diff --git a/src/serverprotocol/PasLS.CodeUtils.pas b/src/serverprotocol/PasLS.CodeUtils.pas index a2abdb1..e2d493a 100644 --- a/src/serverprotocol/PasLS.CodeUtils.pas +++ b/src/serverprotocol/PasLS.CodeUtils.pas @@ -29,7 +29,7 @@ interface SysUtils, Classes, FPJSON, { CodeTools } CodeCache, CodeTree, PascalReaderTool, PascalParserTool, IdentCompletionTool, BasicCodeTools, - CodeToolManager, + CodeToolManager, CodeAtom, { LazUtils } FileUtil, { Pasls } @@ -68,6 +68,7 @@ TJSONSerializedArray = class (TJSONString) end; { Functions } +function IsIdentifier(CodeBuffer: TCodeBuffer; X, Y: Integer): Boolean; function GetIdentifierAtPos(Tool: TPascalReaderTool; StartPos: Longint; aSkipAmp: Boolean = true; IncludeDot: Boolean = false; IncludeOps: Boolean = false): String; function GetIdentifierRangeAtPos(Code: TCodeBuffer; X, Y: Integer): TRange; function FindIdentifierClass(Identifier: TIdentifierListItem): ShortString; @@ -86,6 +87,46 @@ procedure GetProjectUnits(const MainFilename: String; Files: TStrings; PreLoad: implementation +function IsIdentifier(CodeBuffer: TCodeBuffer; X, Y: Integer): Boolean; +var + IsString, IsComment, isKeyword: Boolean; + CursorPos: TCodeXYPosition; + CodeTool: TCodeTool; + SameArea: TAtomPosition; + CleanPos: integer; +begin + IsString := False; + IsComment := False; + isKeyword := False; + + CursorPos.Code := CodeBuffer; + CursorPos.X := X; + CursorPos.Y := Y; + CodeTool:=TCodeTool(CodeToolBoss.FindCodeToolForSource(CodeBuffer)); + + if CodeTool.CaretToCleanPos(CursorPos, CleanPos) <> 0 then + exit; + + CodeTool.BuildTreeAndGetCleanPos(CursorPos, CleanPos); + CodeTool.GetCleanPosInfo(-1, CleanPos, false, SameArea); + + if SameArea.Flag = cafNone then + IsComment := (SameArea.StartPos <= CleanPos) and (CleanPos < SameArea.EndPos); + + if not IsComment then + begin + CodeTool.MoveCursorToCleanPos(SameArea.StartPos); + CodeTool.ReadNextAtom; + + if CodeTool.AtomIsStringConstant then + IsString := True + else if CodeTool.StringIsKeyWord(CodeTool.GetAtom) then + isKeyword := True; + end; + + Result := not (IsString or isKeyword or IsComment); +end; + function GetIdentifierRangeAtPos(Code: TCodeBuffer; X, Y: Integer): TRange; var Line: String; diff --git a/src/serverprotocol/PasLS.GotoDefinition.pas b/src/serverprotocol/PasLS.GotoDefinition.pas index 7e6aaf9..e701e65 100644 --- a/src/serverprotocol/PasLS.GotoDefinition.pas +++ b/src/serverprotocol/PasLS.GotoDefinition.pas @@ -25,9 +25,9 @@ interface uses { RTL } - Classes, + Classes, sysutils, { Code Tools } - CodeToolManager, CodeCache, + CodeToolManager, CodeCache, BasicCodeTools, CodeTree, { Protocol } LSP.Base, LSP.Basic; @@ -48,13 +48,15 @@ function TGotoDefinition.Process(var Params: TTextDocumentPositionParams): TLoca var Code: TCodeBuffer; NewCode: TCodeBuffer; - X, Y: Integer; + X, Y, AbsPos: Integer; NewX, NewY, NewTopLine: integer; + begin with Params do begin Code := CodeToolBoss.FindFile(textDocument.localPath); X := position.character; Y := position.line; + { NOTE: Use FindMainDeclaration to skip forward declarations and find the main/complete declaration. This is the correct behavior for @@ -70,11 +72,19 @@ function TGotoDefinition.Process(var Params: TTextDocumentPositionParams): TLoca FindMainDeclaration returns the main declaration location. } - if CodeToolBoss.FindMainDeclaration(Code, X + 1, Y + 1, NewCode, NewX, NewY, NewTopLine) then + if IsIdentifier(Code, X + 1, Y + 1) then begin - Result := TLocation.Create; - Result.uri := PathToURI(NewCode.Filename); - Result.range := GetIdentifierRangeAtPos(NewCode, NewX, NewY - 1); + if CodeToolBoss.FindMainDeclaration(Code, X + 1, Y + 1, NewCode, NewX, NewY, NewTopLine) then + begin + Result := TLocation.Create; + Result.uri := PathToURI(NewCode.Filename); + Result.range := GetIdentifierRangeAtPos(NewCode, NewX, NewY - 1); + end + else + begin + Result := nil; + PublishCodeToolsError(Transport,''); + end; end else begin