mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-09-11 11:39:19 +02:00
IDE: lazdoc: now reads comments and shows them in hints
git-svn-id: trunk@13021 -
This commit is contained in:
parent
a23d1512a6
commit
688c0a4db0
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user