IDE: lazdoc: now reads comments and shows them in hints

git-svn-id: trunk@13021 -
This commit is contained in:
mattias 2007-11-25 13:23:37 +00:00
parent a23d1512a6
commit 688c0a4db0
7 changed files with 227 additions and 12 deletions

View File

@ -45,7 +45,7 @@ function FindCommentEnd(const ASource: string; StartPos: integer;
NestedComments: boolean): integer;
function IsCommentEnd(const ASource: string; EndPos: integer): boolean;
function FindNextComment(const ASource: string;
StartPos: integer; NestedComments: boolean): integer;
StartPos: integer; MaxPos: integer = 0): integer;
function FindNextCompilerDirective(const ASource: string; StartPos: integer;
NestedComments: boolean): integer;
function FindNextCompilerDirectiveWithName(const ASource: string;
@ -59,6 +59,9 @@ function FindNextIDEDirective(const ASource: string; StartPos: integer;
NestedComments: boolean; EndPos: integer = 0): integer;
function CleanCodeFromComments(const DirtyCode: string;
NestedComments: boolean): string;
function ExtractCommentContent(const ASource: string; CommentStart: integer;
NestedComments: boolean;
TrimStart: boolean = false; TrimEnd: boolean = false): string;
function FindMainUnitHint(const ASource: string; var Filename: string): boolean;
// indent
@ -1096,11 +1099,10 @@ begin
end;
function FindNextComment(const ASource: string; StartPos: integer;
NestedComments: boolean): integer;
var
MaxPos: integer;
MaxPos: integer): integer;
begin
MaxPos:=length(ASource);
if (MaxPos>length(ASource)) or (MaxPos<1) then
MaxPos:=length(ASource);
Result:=StartPos;
while (Result<=MaxPos) do begin
case ASource[Result] of
@ -2690,6 +2692,51 @@ begin
SetLength(Result,CleanPos-1);
end;
function ExtractCommentContent(const ASource: string; CommentStart: integer;
NestedComments: boolean; TrimStart: boolean; TrimEnd: boolean): string;
var
CommentEnd: LongInt;
StartPos: LongInt;
EndPos: LongInt;
begin
Result:='';
if (CommentStart<1) or (CommentStart>length(ASource)) then exit;
CommentEnd:=FindCommentEnd(ASource,CommentStart,NestedComments);
StartPos:=CommentStart;
EndPos:=CommentEnd;
if (ASource[StartPos]='/') then begin
inc(StartPos);
if (StartPos<=length(ASource)) and (ASource[StartPos]='/') then
inc(StartPos);
if (EndPos<=length(ASource)) then begin
while (EndPos>StartPos) and (ASource[EndPos-1] in [#10,#13]) do
dec(EndPos);
end;
end else if (ASource[StartPos]='{') then begin
inc(StartPos);
if (EndPos<=length(ASource)) and (ASource[EndPos-1]='}') then
dec(EndPos);
end else if (ASource[StartPos]='(') then begin
inc(StartPos);
if (StartPos<=length(ASource)) and (ASource[StartPos]='*') then
inc(StartPos);
if (EndPos<=length(ASource)) and (ASource[EndPos-1]=')') then begin
dec(EndPos);
if (ASource[EndPos-1]='*') then
dec(EndPos);
end;
end;
if TrimStart then begin
while (StartPos<EndPos) and (ASource[StartPos] in [' ',#9,#10,#13]) do
inc(StartPos);
end;
if TrimEnd then begin
while (StartPos<EndPos) and (ASource[Endpos-1] in [' ',#9,#10,#13]) do
dec(EndPos);
end;
Result:=copy(ASource,StartPos,EndPos-StartPos);
end;
function FindMainUnitHint(const ASource: string; var Filename: string
): boolean;
const

View File

@ -333,6 +333,8 @@ type
// keywords and comments
function IsKeyword(Code: TCodeBuffer; const KeyWord: string): boolean;
function ExtractCodeWithoutComments(Code: TCodeBuffer): string;
function GetPasDocComments(Code: TCodeBuffer; X, Y: integer;
out ListOfPCodeXYPosition: TFPList): boolean;
// blocks (e.g. begin..end, case..end, try..finally..end, repeat..until)
function FindBlockCounterPart(Code: TCodeBuffer; X,Y: integer;
@ -2530,6 +2532,32 @@ begin
GetNestedCommentsFlagForFile(Code.Filename));
end;
function TCodeToolManager.GetPasDocComments(Code: TCodeBuffer; X, Y: integer;
out ListOfPCodeXYPosition: TFPList): boolean;
var
CursorPos: TCodeXYPosition;
begin
Result:=false;
{$IFDEF CTDEBUG}
DebugLn('TCodeToolManager.GetPasDocComments A ',Code.Filename);
{$ENDIF}
if not InitCurCodeTool(Code) then exit;
CursorPos.X:=X;
CursorPos.Y:=Y;
CursorPos.Code:=Code;
{$IFDEF CTDEBUG}
DebugLn('TCodeToolManager.GetPasDocComments B ',dbgs(FCurCodeTool.Scanner<>nil));
{$ENDIF}
try
Result:=FCurCodeTool.GetPasDocComments(CursorPos,true,ListOfPCodeXYPosition);
except
on e: Exception do Result:=HandleException(e);
end;
{$IFDEF CTDEBUG}
DebugLn('TCodeToolManager.GetPasDocComments END ');
{$ENDIF}
end;
function TCodeToolManager.FindBlockCounterPart(Code: TCodeBuffer;
X, Y: integer; var NewCode: TCodeBuffer; var NewX, NewY, NewTopLine: integer
): boolean;

View File

@ -291,6 +291,9 @@ type
out CommentStart, CommentEnd: TCodeXYPosition): boolean;
function CommentCode(const StartPos, EndPos: integer;
SourceChangeCache: TSourceChangeCache; Apply: boolean): boolean;
function GetPasDocComments(const StartPos: TCodeXYPosition;
InvokeBuildTree: boolean;
out ListOfPCodeXYPosition: TFPList): boolean;
end;
@ -3721,6 +3724,98 @@ begin
Result:=true;
end;
function TStandardCodeTool.GetPasDocComments(const StartPos: TCodeXYPosition;
InvokeBuildTree: boolean; out ListOfPCodeXYPosition: TFPList): boolean;
// Comments are normally in front.
// { Description of TMyClass. }
// TMyClass = class
//
// Comments can be behind in the same line
// property Color; // description of Color
//
// Comments can be in the following line if started with <
function CommentBelongsToPrior(CommentStart: integer): boolean;
var
p: Integer;
begin
if (CommentStart<SrcLen) and (Src[CommentStart]='{')
and (Src[CommentStart+1]='<') then
Result:=true
else if (CommentStart+2<=SrcLen) and (Src[CommentStart]='(')
and (Src[CommentStart+1]='*') and (Src[CommentStart+2]='<') then
Result:=true
else if (CommentStart+2<=SrcLen) and (Src[CommentStart]='/')
and (Src[CommentStart+1]='/') and (Src[CommentStart+2]='<') then
Result:=true
else begin
p:=CommentStart-1;
while (p>=1) and (Src[p] in [' ',#9]) do dec(p);
if (p<1) or (Src[p] in [#10,#13]) then
Result:=false
else
Result:=true; // there is code in the same line in front of the comment
end;
end;
procedure Add(CleanPos: integer);
var
CodePos: TCodeXYPosition;
begin
if ListOfPCodeXYPosition=nil then
ListOfPCodeXYPosition:=TFPList.Create;
if not CleanPosToCaret(CleanPos,CodePos) then exit;
AddCodePosition(ListOfPCodeXYPosition,CodePos);
end;
var
CleanCursorPos: integer;
ANode: TCodeTreeNode;
p: LongInt;
NextNode: TCodeTreeNode;
EndPos: LongInt;
begin
ListOfPCodeXYPosition:=nil;
Result:=false;
// parse source and find clean positions
if InvokeBuildTree then
BuildTreeAndGetCleanPos(trAll,StartPos,CleanCursorPos,[])
else
if CaretToCleanPos(StartPos,CleanCursorPos)<>0 then
exit;
// find node
ANode:=FindDeepestNodeAtPos(CleanCursorPos,true);
if (ANode=nil) then exit;
NextNode:=ANode.Next;
if NextNode<>nil then
EndPos:=NextNode.StartPos
else
EndPos:=ANode.EndPos;
// read comments (start in front of node)
p:=FindLineEndOrCodeInFrontOfPosition(ANode.StartPos,true);
while p<EndPos do begin
p:=FindNextComment(Src,p,EndPos);
if p>=EndPos then break;
if (p<ANode.StartPos) then begin
// comment in front of node
if not CommentBelongsToPrior(p) then
Add(p);
end else if (p<ANode.EndPos) then begin
// comment in the middle
Add(p);
end else begin
// comment behind
if CommentBelongsToPrior(p) then
Add(p);
end;
p:=FindCommentEnd(Src,p,Scanner.NestedComments);
end;
Result:=true;
end;
function TStandardCodeTool.GatherResourceStringsWithValue(
const CursorPos: TCodeXYPosition; const StringValue: string;
PositionList: TCodeXYPositions): boolean;

View File

@ -892,6 +892,7 @@ begin
if LazDocBoss.GetHint(Code,CodePos.X,CodePos.Y,true,Hint,CacheWasUsed)=ldprSuccess
then
exit(shrSuccess);
DebugLn(['THelpManager.GetHintForSourcePosition not found']);
Result:=shrHelpNotFound;
end;

View File

@ -32,7 +32,8 @@ interface
uses
Classes, SysUtils, LCLProc, FileUtil,
CodeAtom, CodeTree, CodeToolManager, FindDeclarationTool, CodeCache, CacheCodeTools,
CodeAtom, CodeTree, CodeToolManager, FindDeclarationTool, BasicCodeTools,
CodeCache, CacheCodeTools,
FileProcs, AvgLvlTree,
Laz_DOM, Laz_XMLRead, Laz_XMLWrite,
MacroIntf, PackageIntf, LazHelpIntf, ProjectIntf, LazIDEIntf,
@ -90,6 +91,7 @@ type
TLazDocElement = class
public
CodeContext: TFindContext;
CodeXYPos: TCodeXYPosition;
ElementName: string;
ElementNode: TDOMNode;
FPDocFile: TLazFPDocFile;
@ -262,7 +264,7 @@ begin
Result:=GetFirstElement;
while Result<>nil do begin
if (Result is TDomElement)
and (CompareText(TDomElement(Result).GetAttribute('name'),ElementName)=0)
and (SysUtils.CompareText(TDomElement(Result).GetAttribute('name'),ElementName)=0)
then
exit;
Result:=Result.NextSibling;
@ -688,6 +690,7 @@ begin
// add element
LDElement:=Chain.Add;
LDElement.CodeXYPos:=CodePos^;
LDElement.CodeContext.Tool:=CurTool;
LDElement.CodeContext.Node:=Node;
//DebugLn(['TLazDocManager.GetElementChain i=',i,' CodeContext=',FindContextToString(LDElement.CodeContext)]);
@ -755,12 +758,21 @@ var
Item: TLazDocElement;
NodeValues: TFPDocNode;
f: TFPDocItem;
ListOfPCodeXYPosition: TFPList;
CodeXYPos: PCodeXYPosition;
CommentStart: integer;
NestedComments: Boolean;
CommentStr: String;
ItemAdded: Boolean;
CommentCode: TCodeBuffer;
j: Integer;
begin
//DebugLn(['TLazDocManager.GetHint ',Code.Filename,' ',X,',',Y]);
Hint:=CodeToolBoss.FindSmartHint(Code,X,Y);
CacheWasUsed:=true;
Chain:=nil;
ListOfPCodeXYPosition:=nil;
try
//DebugLn(['TLazDocManager.GetHint GetElementChain...']);
Result:=GetElementChain(Code,X,Y,Complete,Chain,CacheWasUsed);
@ -769,19 +781,53 @@ begin
if Chain<>nil then begin
for i:=0 to Chain.Count-1 do begin
Item:=Chain[i];
ItemAdded:=false;
DebugLn(['TLazDocManager.GetHint ',i,' Element=',Item.ElementName]);
if Item.ElementNode=nil then continue;
NodeValues:=Item.FPDocFile.GetValuesFromNode(Item.ElementNode);
for f:=Low(TFPDocItem) to High(TFPDocItem) do
DebugLn(['TLazDocManager.GetHint ',FPDocItemNames[f],' ',NodeValues[f]]);
if NodeValues[fpdiShort]<>'' then begin
Hint:=Hint+#13#13+Item.ElementName+#13
Hint:=Hint+#13#13
+Item.ElementName+#13
+NodeValues[fpdiShort];
ItemAdded:=true;
end;
// Add comments
if CodeToolBoss.GetPasDocComments(Item.CodeXYPos.Code,
Item.CodeXYPos.X,Item.CodeXYPos.Y,ListOfPCodeXYPosition)
and (ListOfPCodeXYPosition<>nil) then
begin
NestedComments:=CodeToolBoss.GetNestedCommentsFlagForFile(
Item.CodeXYPos.Code.Filename);
for j:=0 to ListOfPCodeXYPosition.Count-1 do begin
CodeXYPos:=PCodeXYPosition(ListOfPCodeXYPosition[j]);
CommentCode:=CodeXYPos^.Code;
CommentCode.LineColToPosition(CodeXYPos^.Y,CodeXYPos^.X,CommentStart);
if (CommentStart<1) or (CommentStart>CommentCode.SourceLength)
then
continue;
CommentStr:=ExtractCommentContent(CommentCode.Source,CommentStart,
NestedComments,true,true);
if CommentStr<>'' then begin
if not ItemAdded then begin
Hint:=Hint+#13#13
+Item.ElementName+#13
+CommentStr;
end else begin
Hint:=Hint+#13
+CommentStr;
end;
ItemAdded:=true;
end;
end;
end;
end;
end;
Result:=ldprSuccess;
finally
FreeListOfPCodeXYPosition(ListOfPCodeXYPosition);
Chain.Free;
end;

View File

@ -11999,10 +11999,8 @@ begin
writeln('[TMainIDE.OnSrcNotebookShowHintForSource] ************ ',ActiveUnitInfo.Source.Filename,' X=',CaretPos.X,' Y=',CaretPos.Y);
{$ENDIF}
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.OnSrcNotebookShowHintForSource A');{$ENDIF}
{$IFDEF EnableLazDocHint}
THelpManager(HelpBoss).GetHintForSourcePosition(ActiveUnitInfo.Filename,
CaretPos,SmartHintStr);
{$ENDIF}
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.OnSrcNotebookShowHintForSource B');{$ENDIF}
end;
itDebugger: begin

View File

@ -564,9 +564,9 @@ begin
try
Src:=Tool.Src;
p:=1;
NestedComment:=true;
NestedComment:=CodeToolBoss.GetNestedCommentsFlagForFile(Code.Filename);
repeat
p:=FindNextComment(Src,p,NestedComment);
p:=FindNextComment(Src,p);
if p>length(Src) then break;
CommentEnd:=FindCommentEnd(Src,p,NestedComment);
Tool.CleanPosToCaret(p,CodeXYPosition);