mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-29 23:50:25 +02:00
codetools: FindFileAtCursor: unit name, search in comment
git-svn-id: trunk@53311 -
This commit is contained in:
parent
6e64d8a23d
commit
4eaf02c3a1
@ -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='<'))
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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.';
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user