codetools: FindFileAtCursor: unit name, search in comment

git-svn-id: trunk@53311 -
This commit is contained in:
mattias 2016-11-08 12:20:40 +00:00
parent 6e64d8a23d
commit 4eaf02c3a1
4 changed files with 130 additions and 41 deletions

View File

@ -1504,6 +1504,7 @@ end;
function FindCommentEnd(const ASource: string; StartPos: integer; function FindCommentEnd(const ASource: string; StartPos: integer;
NestedComments: boolean): integer; NestedComments: boolean): integer;
// returns position after the comment end, e.g. after } // returns position after the comment end, e.g. after }
// failure: returns length(ASource)+1
var var
CommentLvl: integer; CommentLvl: integer;
p: PChar; p: PChar;
@ -2900,7 +2901,7 @@ begin
else else
if Result>1 then begin if Result>1 then begin
c2:=Source[Result-1]; c2:=Source[Result-1];
// test for double char operators :=, +=, -=, /=, *=, <>, <=, >=, **, ><, .. // test for double char operators :=, +=, -=, /=, *=, <>, <=, >=, **, ><, @@ ..
if ((c2='=') and (IsEqualOperatorStartChar[c])) if ((c2='=') and (IsEqualOperatorStartChar[c]))
or ((c='<') and (c2='>')) or ((c='<') and (c2='>'))
or ((c='>') and (c2='<')) or ((c='>') and (c2='<'))

View File

@ -668,7 +668,8 @@ type
ffatResource, ffatResource,
ffatDisabledResource, ffatDisabledResource,
ffatLiteral, ffatLiteral,
ffatComment ffatComment,
ffatUnit // unit by name
); );
TFindFileAtCursorFlags = set of TFindFileAtCursorFlag; TFindFileAtCursorFlags = set of TFindFileAtCursorFlag;
const const
@ -3560,10 +3561,71 @@ var
end; end;
end; end;
function CheckPlainComments(Source: string; CurAbsPos: integer): boolean;
var
Filename: String;
p, EndPos, FileStartPos, FileEndPos, MinPos, MaxPos: Integer;
begin
// check if cursor in a comment (ignoring directives)
Result:=false;
CursorPos.Code.LineColToPosition(CursorPos.Y,CursorPos.X,CurAbsPos);
Source:=CursorPos.Code.Source;
if (CurAbsPos<1) or (CurAbsPos>length(Source)) then exit;
p:=1;
repeat
p:=FindNextComment(Source,p);
if p>CurAbsPos then break;
EndPos:=FindCommentEnd(Source,p,Scanner.NestedComments);
if EndPos>CurAbsPos then begin
// cursor in comment
MinPos:=p+1;
MaxPos:=EndPos-1;
if Source[p]<>'{' then begin
inc(MinPos);
dec(MaxPos);
end;
FileStartPos:=CurAbsPos;
while (FileStartPos>MinPos) and not (Source[FileStartPos-1] in [#0..#32]) do
dec(FileStartPos);
FileEndPos:=CurAbsPos;
while (FileEndPos<MaxPos) and not (Source[FileEndPos] in [#0..#32]) do
inc(FileEndPos);
Filename:=TrimFilename(copy(Source,FileStartPos,FileEndPos-FileStartPos));
if not FilenameIsAbsolute(Filename) then
Filename:=ResolveDots(ExtractFilePath(MainFilename)+Filename);
if Scanner.OnLoadSource(Scanner,Filename,false)<>nil then begin
Found:=ffatComment;
FoundFilename:=Filename;
exit(true);
end;
exit;
end;
p:=EndPos;
until false;
end;
function CheckUnitByWordAtCursor(Source: string; CurAbsPos: integer): boolean;
// e.g. 'Sy|sUtils.CompareText'
var
AnUnitName: String;
Code: TCodeBuffer;
p: Integer;
begin
Result:=false;
p:=FindStartOfAtom(Source,CurAbsPos);
if p<1 then exit;
AnUnitName:=GetIdentifier(@Source[p]);
Code:=FindUnitSource(AnUnitName,'',false);
if Code=nil then exit;
Found:=ffatUnit;
FoundFilename:=Code.Filename;
Result:=true;
end;
var var
CommentStart, CommentEnd, Col, StartCol: integer; CommentStart, CommentEnd, Col, StartCol, CurAbsPos: integer;
Node: TCodeTreeNode; Node: TCodeTreeNode;
aUnitName, UnitInFilename, Line, Literal: string; aUnitName, UnitInFilename, Line, Literal, aSource: string;
NewCode: TCodeBuffer; NewCode: TCodeBuffer;
p, StartP: PChar; p, StartP: PChar;
begin begin
@ -3571,7 +3633,10 @@ begin
Found:=ffatNone; Found:=ffatNone;
FoundFilename:=''; FoundFilename:='';
if StartPos<>nil then if StartPos<>nil then
StartPos^:=CleanCodeXYPosition; StartPos^:=CleanCodeXYPosition;
if CursorPos.Code.LineColIsOutside(CursorPos.Y,CursorPos.X) then exit;
if CursorPos.Code.LineColIsSpace(CursorPos.Y,CursorPos.X) then exit;
if (CursorPos.Y<1) or (CursorPos.Y>CursorPos.Code.LineCount) then exit;
{$IFDEF VerboseFindFileAtCursor} {$IFDEF VerboseFindFileAtCursor}
debugln(['TFindDeclarationTool.FindFileAtCursor START']); debugln(['TFindDeclarationTool.FindFileAtCursor START']);
{$ENDIF} {$ENDIF}
@ -3663,42 +3728,52 @@ begin
if ffatLiteral in SearchFor then begin if ffatLiteral in SearchFor then begin
// check literal // check literal
p:=PChar(Line); p:=PChar(Line);
Col:=1;
repeat repeat
if p^=#0 then begin case p^ of
#0:
break; break;
end else if p^='''' then begin '''':
StartCol:=Col; begin
inc(Col); StartCol:=p-PChar(Line)+1;
inc(p); inc(p);
StartP:=p; StartP:=p;
repeat repeat
case p^ of case p^ of
#0: break; #0,'''': break;
'''': break; else inc(p);
#9: Col:=(Col+8) and not 7; end;
else inc(p,UTF8CharacterLength(p)); until false;
end; Col:=p-PChar(Line)+1;
until false; writeln('TFindDeclarationTool.FindFileAtCursor Col=',Col,' CursorCol=',CursorPos.X,' Literal=',copy(Line,StartCol+1,p-StartP));
if (CursorPos.X>=StartCol) and (CursorPos.X<=Col) then begin if (p>StartP) and (CursorPos.X>=StartCol) and (CursorPos.X<=Col) then begin
Literal:=copy(Line,Col,p-StartP); Literal:=copy(Line,StartCol+1,p-StartP);
if not FilenameIsAbsolute(Literal) then if not FilenameIsAbsolute(Literal) then
Literal:=TrimFilename(ExtractFilePath(Scanner.MainFilename)+Literal); Literal:=TrimFilename(ExtractFilePath(Scanner.MainFilename)+Literal);
if FilenameIsAbsolute(Literal)
and DirectoryCache.Pool.FileExists(Literal) then begin
Found:=ffatLiteral; Found:=ffatLiteral;
FoundFilename:=Literal; FoundFilename:=Literal;
exit(true); exit(true);
end; end;
if p^=#0 then break;
// p is now on the ending '
end; end;
if p^=#0 then break;
end; end;
inc(p); inc(p);
inc(Col); inc(Col);
until false; until false;
end; end;
// search without node tree with basic tools
CursorPos.Code.LineColToPosition(CursorPos.Y,CursorPos.X,CurAbsPos);
aSource:=CursorPos.Code.Source;
if (CurAbsPos<1) or (CurAbsPos>length(aSource)) then exit;
if ffatComment in SearchFor then begin if ffatComment in SearchFor then begin
// ToDo: check simple // ignore syntax and only read comments
if CheckPlainComments(aSource,CurAbsPos) then exit(true);
end;
if ffatUnit in SearchFor then begin
if CheckUnitByWordAtCursor(aSource,CurAbsPos) then exit(true);
end; end;
end; end;

View File

@ -57,7 +57,6 @@ type
procedure ExtendXmlDocument(Doc: TXMLDocument); override; procedure ExtendXmlDocument(Doc: TXMLDocument); override;
public public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override; destructor Destroy; override;
end; end;
@ -142,16 +141,11 @@ begin
Doc.FirstChild.AppendChild(env); Doc.FirstChild.AppendChild(env);
end; end;
constructor TCTTestRunner.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
DefaultFormat:=fPlain;
DefaultRunAllTests:=true;
end;
var var
App: TCTTestRunner; App: TCTTestRunner;
begin begin
DefaultFormat:=fPlain;
DefaultRunAllTests:=True;
App := TCTTestRunner.Create(nil); App := TCTTestRunner.Create(nil);
App.Initialize; App.Initialize;
App.Title := 'FPCUnit Console runner for the CodeTools Find Declaration Suite.'; App.Title := 'FPCUnit Console runner for the CodeTools Find Declaration Suite.';

View File

@ -402,17 +402,36 @@ begin
AssertEquals('FindFileAtCursor in literal Found',ord(ffatLiteral),ord(Found)); AssertEquals('FindFileAtCursor in literal Found',ord(ffatLiteral),ord(Found));
AssertEquals('FindFileAtCursor in literal FoundFilename','unit2.pas',FoundFilename); AssertEquals('FindFileAtCursor in literal FoundFilename','unit2.pas',FoundFilename);
// --- comment ---
Code.Source:='program test1;'+LineEnding
+'{unit2.pas}'+LineEnding;
if not CodeToolBoss.FindFileAtCursor(Code,3,2,Found,FoundFilename) then
Fail('CodeToolBoss.FindFileAtCursor in comment');
AssertEquals('FindFileAtCursor in comment Found',ord(ffatComment),ord(Found));
AssertEquals('FindFileAtCursor in comment FoundFilename','unit2.pas',FoundFilename);
// --- unit name search in comment ---
Code.Source:='program test1;'+LineEnding
+'{unit2}'+LineEnding;
if not CodeToolBoss.FindFileAtCursor(Code,3,2,Found,FoundFilename) then
Fail('CodeToolBoss.FindFileAtCursor in comment');
AssertEquals('FindFileAtCursor in comment Found',ord(ffatUnit),ord(Found));
AssertEquals('FindFileAtCursor in comment FoundFilename','unit2.pas',FoundFilename);
// --- unit name search in code ---
Code.Source:='program test1;'+LineEnding
+'begin'+LineEnding
+' unit2.Test;'+LineEnding;
if not CodeToolBoss.FindFileAtCursor(Code,3,3,Found,FoundFilename) then
Fail('CodeToolBoss.FindFileAtCursor in comment');
AssertEquals('FindFileAtCursor in comment Found',ord(ffatUnit),ord(Found));
AssertEquals('FindFileAtCursor in comment FoundFilename','unit2.pas',FoundFilename);
finally finally
Code.IsDeleted:=true; Code.IsDeleted:=true;
SubUnit2Code.IsDeleted:=true; SubUnit2Code.IsDeleted:=true;
LFMCode.IsDeleted:=true; LFMCode.IsDeleted:=true;
end; end;
// ToDo: test $i 'file with spaces' in code
// ToDo: test $i in disabled code
// ToDo: test 'readme.txt' in active code
// ToDo: test readme.txt in active code fails
// ToDo: test readme.txt in comment works
end; end;
procedure TTestFindDeclaration.TestFindDeclaration_FPCTests; procedure TTestFindDeclaration.TestFindDeclaration_FPCTests;