mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-09-06 00:20:13 +02:00
implemented codetools functions to collect search paths and to unitfiles in searchpaths
git-svn-id: trunk@8350 -
This commit is contained in:
parent
46291e2df0
commit
55b7e83e1c
@ -32,11 +32,10 @@ unit BasicCodeTools;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, SourceLog, KeywordFuncLists, FileProcs;
|
||||
Classes, SysUtils, AVL_Tree, SourceLog, KeywordFuncLists, FileProcs;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
{ These functions are used by the codetools
|
||||
}
|
||||
{ These functions are used by the codetools }
|
||||
|
||||
// comments
|
||||
function FindNextNonSpace(const ASource: string; StartPos: integer): integer;
|
||||
@ -136,6 +135,29 @@ function SplitStringConstant(const StringConstant: string;
|
||||
procedure ImproveStringConstantStart(const ACode: string; var StartPos: integer);
|
||||
procedure ImproveStringConstantEnd(const ACode: string; var EndPos: integer);
|
||||
|
||||
// files
|
||||
type
|
||||
|
||||
{ TUnitFileInfo }
|
||||
|
||||
TUnitFileInfo = class
|
||||
private
|
||||
FFilename: string;
|
||||
FUnitName: string;
|
||||
public
|
||||
constructor Create(const TheUnitName, TheFilename: string);
|
||||
property UnitName: string read FUnitName;
|
||||
property Filename: string read FFilename;
|
||||
end;
|
||||
|
||||
function GatherUnitFiles(const BaseDir, SearchPath,
|
||||
Extensions: string; KeepDoubles, CaseInsensitive: boolean;
|
||||
var TreeOfUnitFiles: TAVLTree): boolean;
|
||||
procedure FreeTreeOfUnitFiles(TreeOfUnitFiles: TAVLTree);
|
||||
function CompareUnitFileInfos(Data1, Data2: Pointer): integer;
|
||||
function CompareUnitNameAndUnitFileInfo(UnitnamePAnsiString,
|
||||
UnitFileInfo: Pointer): integer;
|
||||
|
||||
// other useful stuff
|
||||
procedure RaiseCatchableException(const Msg: string);
|
||||
|
||||
@ -3122,6 +3144,206 @@ begin
|
||||
until AtomEndPos>=EndPos;
|
||||
end;
|
||||
|
||||
function GatherUnitFiles(const BaseDir, SearchPath,
|
||||
Extensions: string; KeepDoubles, CaseInsensitive: boolean;
|
||||
var TreeOfUnitFiles: TAVLTree): boolean;
|
||||
// BaseDir: base directory, used when SearchPath is relative
|
||||
// SearchPath: semicolon separated list of directories
|
||||
// Extensions: semicolon separated list of extensions (e.g. 'pas;.pp;ppu')
|
||||
// KeepDoubles: false to return only the first match of each unit
|
||||
// CaseInsensitive: true to ignore case on comparing extensions
|
||||
// TreeOfUnitFiles: tree of TUnitFileInfo
|
||||
var
|
||||
SearchedDirectories: TAVLTree; // tree of PAnsiString
|
||||
|
||||
function DirectoryAlreadySearched(const ADirectory: string): boolean;
|
||||
begin
|
||||
Result:=false;
|
||||
end;
|
||||
|
||||
procedure MarkDirectoryAsSearched(const ADirectory: string);
|
||||
var
|
||||
s: String;
|
||||
begin
|
||||
// increase refcount
|
||||
s:=ADirectory;
|
||||
if SearchedDirectories=nil then
|
||||
SearchedDirectories:=TAVLTree.Create(@ComparePAnsiStringFilenames);
|
||||
SearchedDirectories.Add(@s);
|
||||
Pointer(s):=nil;
|
||||
end;
|
||||
|
||||
procedure FreeSearchedDirectories;
|
||||
var
|
||||
ANode: TAVLTreeNode;
|
||||
s: String;
|
||||
begin
|
||||
if SearchedDirectories=nil then exit;
|
||||
s:='';
|
||||
ANode:=SearchedDirectories.FindLowest;
|
||||
while ANode<>nil do begin
|
||||
Pointer(s):=ANode.Data;
|
||||
s:=''; // decrease refcount
|
||||
ANode:=SearchedDirectories.FindSuccessor(ANode);
|
||||
end;
|
||||
if s='' then ;
|
||||
SearchedDirectories.Free;
|
||||
end;
|
||||
|
||||
function ExtensionFits(const Filename: string): boolean;
|
||||
var
|
||||
ExtStart: Integer;
|
||||
ExtLen: Integer; // length without '.'
|
||||
CurExtStart: Integer;
|
||||
CurExtEnd: LongInt;
|
||||
CompareCaseInsensitive: Boolean;
|
||||
p: Integer;
|
||||
begin
|
||||
CompareCaseInsensitive:=CaseInsensitive;
|
||||
{$IFDEF Win32}
|
||||
CompareCaseInsensitive:=true;
|
||||
{$ENDIF}
|
||||
|
||||
ExtStart:=length(Filename);
|
||||
while (ExtStart>=1) and (not (Filename[ExtStart] in [PathDelim,'.'])) do
|
||||
dec(ExtStart);
|
||||
if (ExtStart>0) and (Filename[ExtStart]='.') then begin
|
||||
// filename has an extension
|
||||
ExtLen:=length(Filename)-ExtStart;
|
||||
inc(ExtStart);
|
||||
CurExtStart:=1;
|
||||
while (CurExtStart<=length(Extensions)) do begin
|
||||
// skip '.'
|
||||
if Extensions[CurExtStart]='.' then inc(CurExtStart);
|
||||
// read till semicolon
|
||||
CurExtEnd:=CurExtStart;
|
||||
while (CurExtEnd<=length(Extensions)) and (Extensions[CurExtEnd]<>';')
|
||||
do
|
||||
inc(CurExtEnd);
|
||||
if (CurExtEnd>CurExtStart) and (CurExtEnd-CurExtStart=ExtLen) then begin
|
||||
// compare extension
|
||||
p:=ExtLen-1;
|
||||
while (p>=0) do begin
|
||||
if CompareCaseInsensitive then begin
|
||||
if UpChars[Filename[ExtStart+p]]
|
||||
<>UpChars[Extensions[CurExtStart+p]]
|
||||
then
|
||||
break;
|
||||
end else begin
|
||||
if Filename[ExtStart+p]<>Extensions[CurExtStart+p] then
|
||||
break;
|
||||
end;
|
||||
dec(p);
|
||||
end;
|
||||
if p<0 then begin
|
||||
// extension fit
|
||||
Result:=true;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
CurExtStart:=CurExtEnd+1;
|
||||
end;
|
||||
end;
|
||||
Result:=false;
|
||||
end;
|
||||
|
||||
procedure AddFilename(const Filename: string);
|
||||
var
|
||||
AnUnitName: String;
|
||||
NewItem: TUnitFileInfo;
|
||||
begin
|
||||
AnUnitName:=ExtractFileNameOnly(Filename);
|
||||
if (not KeepDoubles) then begin
|
||||
if (TreeOfUnitFiles<>nil)
|
||||
and (TreeOfUnitFiles.FindKey(Pointer(AnUnitName),
|
||||
@CompareUnitNameAndUnitFileInfo)<>nil)
|
||||
then begin
|
||||
// an unit with the same name was already found and doubles are not
|
||||
// wanted
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
// add
|
||||
if TreeOfUnitFiles=nil then
|
||||
TreeOfUnitFiles:=TAVLTree.Create(@CompareUnitFileInfos);
|
||||
NewItem:=TUnitFileInfo.Create(AnUnitName,Filename);
|
||||
TreeOfUnitFiles.Add(NewItem);
|
||||
end;
|
||||
|
||||
function SearchDirectory(const ADirectory: string): boolean;
|
||||
var
|
||||
FileInfo: TSearchRec;
|
||||
begin
|
||||
Result:=true;
|
||||
if DirectoryAlreadySearched(ADirectory) then exit;
|
||||
MarkDirectoryAsSearched(ADirectory);
|
||||
|
||||
if not DirPathExists(ADirectory) then exit;
|
||||
if SysUtils.FindFirst(ADirectory+FileMask,faAnyFile,FileInfo)=0 then begin
|
||||
repeat
|
||||
// check if special file
|
||||
if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='')
|
||||
then
|
||||
continue;
|
||||
if ExtensionFits(FileInfo.Name) then begin
|
||||
AddFilename(FileInfo.Name);
|
||||
end;
|
||||
until SysUtils.FindNext(FileInfo)<>0;
|
||||
end;
|
||||
SysUtils.FindClose(FileInfo);
|
||||
end;
|
||||
|
||||
var
|
||||
PathStartPos: Integer;
|
||||
PathEndPos: LongInt;
|
||||
CurDir: String;
|
||||
begin
|
||||
Result:=false;
|
||||
SearchedDirectories:=nil;
|
||||
try
|
||||
// search all paths in SearchPath
|
||||
PathStartPos:=1;
|
||||
while PathStartPos<=length(SearchPath) do begin
|
||||
PathEndPos:=PathStartPos;
|
||||
while (PathEndPos<=length(SearchPath)) and (SearchPath[PathEndPos]<>';')
|
||||
do
|
||||
inc(PathEndPos);
|
||||
if PathEndPos>PathStartPos then begin
|
||||
CurDir:=AppendPathDelim(TrimFilename(
|
||||
copy(SearchPath,PathStartPos,PathEndPos-PathStartPos)));
|
||||
if not FilenameIsAbsolute(CurDir) then
|
||||
CurDir:=AppendPathDelim(BaseDir)+CurDir;
|
||||
if not SearchDirectory(AppendPathDelim(CurDir)) then exit;
|
||||
end;
|
||||
PathStartPos:=PathEndPos;
|
||||
while (PathStartPos<=length(SearchPath))
|
||||
and (SearchPath[PathStartPos]=';') do
|
||||
inc(PathStartPos);
|
||||
end;
|
||||
Result:=true;
|
||||
finally
|
||||
FreeSearchedDirectories;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure FreeTreeOfUnitFiles(TreeOfUnitFiles: TAVLTree);
|
||||
begin
|
||||
TreeOfUnitFiles.FreeAndClear;
|
||||
end;
|
||||
|
||||
function CompareUnitFileInfos(Data1, Data2: Pointer): integer;
|
||||
begin
|
||||
Result:=SysUtils.CompareText(TUnitFileInfo(Data1).UnitName,
|
||||
TUnitFileInfo(Data2).UnitName);
|
||||
end;
|
||||
|
||||
function CompareUnitNameAndUnitFileInfo(UnitnamePAnsiString,
|
||||
UnitFileInfo: Pointer): integer;
|
||||
begin
|
||||
Result:=SysUtils.CompareText(PAnsiString(UnitnamePAnsiString)^,
|
||||
TUnitFileInfo(UnitFileInfo).UnitName);
|
||||
end;
|
||||
|
||||
procedure RaiseCatchableException(const Msg: string);
|
||||
begin
|
||||
{ Raises an exception.
|
||||
@ -3234,6 +3456,14 @@ begin
|
||||
Result:=CompareText(Txt1,Len1,Txt2,Len2,CaseSensitive);
|
||||
end;
|
||||
|
||||
{ TUnitFileInfo }
|
||||
|
||||
constructor TUnitFileInfo.Create(const TheUnitName, TheFilename: string);
|
||||
begin
|
||||
FUnitName:=TheUnitName;
|
||||
FFilename:=TheFilename;
|
||||
end;
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
@ -84,6 +84,8 @@ function ClearFile(const Filename: string; RaiseOnError: boolean): boolean;
|
||||
function GetTempFilename(const Path, Prefix: string): string;
|
||||
function FindDiskFilename(const Filename: string): string;
|
||||
|
||||
function ComparePAnsiStringFilenames(Data1, data2: Pointer): integer;
|
||||
|
||||
type
|
||||
TCTPascalExtType = (petNone, petPAS, petPP, petP);
|
||||
|
||||
@ -364,6 +366,16 @@ begin
|
||||
until StartPos>length(Result);
|
||||
end;
|
||||
|
||||
function ComparePAnsiStringFilenames(Data1, data2: Pointer): integer;
|
||||
var
|
||||
s1: String;
|
||||
s2: String;
|
||||
begin
|
||||
s1:=PAnsiString(Data1)^;
|
||||
s2:=PAnsiString(Data1)^;
|
||||
Result:=CompareFilenames(s1,s2);
|
||||
end;
|
||||
|
||||
function CompareFilenames(const Filename1, Filename2: string): integer;
|
||||
begin
|
||||
{$IFDEF WIN32}
|
||||
|
@ -422,7 +422,7 @@ type
|
||||
IdentifierTool: TFindDeclarationTool;
|
||||
FoundProc: PFoundProc;
|
||||
end;
|
||||
|
||||
|
||||
TFindDeclarationParams = class(TObject)
|
||||
public
|
||||
// input parameters:
|
||||
@ -482,7 +482,6 @@ type
|
||||
const
|
||||
AllFindSmartFlags = [fsfIncludeDirective];
|
||||
|
||||
|
||||
type
|
||||
//----------------------------------------------------------------------------
|
||||
ECodeToolUnitNotFound = class(ECodeToolFileNotFound)
|
||||
@ -659,6 +658,7 @@ type
|
||||
var NewPos: TCodeXYPosition; var NewTopLine: integer): boolean;
|
||||
function FindUnitSource(const AnUnitName,
|
||||
AnUnitInFilename: string; ExceptionOnNotFound: boolean): TCodeBuffer;
|
||||
procedure GatherUnitAndSrcPath(var UnitPath, SrcPath: string);
|
||||
function FindSmartHint(const CursorPos: TCodeXYPosition): string;
|
||||
function BaseTypeOfNodeHasSubIdents(ANode: TCodeTreeNode): boolean;
|
||||
function FindBaseTypeOfNode(Params: TFindDeclarationParams;
|
||||
@ -1503,7 +1503,8 @@ var
|
||||
end;
|
||||
|
||||
function SearchUnitInUnitLinks(const TheUnitName: string): TCodeBuffer;
|
||||
var UnitLinks, CurFilename: string;
|
||||
var
|
||||
UnitLinks, CurFilename: string;
|
||||
UnitLinkStart, UnitLinkEnd, UnitLinkLen: integer;
|
||||
pe: TCTPascalExtType;
|
||||
begin
|
||||
@ -1632,7 +1633,7 @@ begin
|
||||
end;
|
||||
end else begin
|
||||
// normal unit name
|
||||
// first source search in current directory (= where the maincode is)
|
||||
// first search in current directory (= where the maincode is)
|
||||
{$IFDEF ShowTriedFiles}
|
||||
DebugLn('TFindDeclarationTool.FindUnitSource Search in current dir=',CurDir);
|
||||
{$ENDIF}
|
||||
@ -1706,8 +1707,7 @@ begin
|
||||
// there is a compiled unit, only the source was not found
|
||||
RaiseExceptionInstance(
|
||||
ECodeToolUnitNotFound.Create(Self,
|
||||
Format(ctsSourceNotFoundUnit, [CompiledResult.Filename]),
|
||||
AnUnitName));
|
||||
Format(ctsSourceNotFoundUnit, [CompiledResult.Filename]),AnUnitName));
|
||||
end else begin
|
||||
// nothing found
|
||||
RaiseExceptionInstance(
|
||||
@ -1717,6 +1717,71 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFindDeclarationTool.GatherUnitAndSrcPath(var UnitPath,
|
||||
SrcPath: string);
|
||||
var
|
||||
CurDir: String;
|
||||
|
||||
procedure SearchCompiledSrcPaths(const APath: string);
|
||||
var
|
||||
PathStart, PathEnd: integer;
|
||||
ADir: string;
|
||||
CurCompiledSrcPath: string;
|
||||
begin
|
||||
if not Assigned(OnGetSrcPathForCompiledUnit) then begin
|
||||
exit;
|
||||
end;
|
||||
|
||||
PathStart:=1;
|
||||
while PathStart<=length(APath) do begin
|
||||
PathEnd:=PathStart;
|
||||
while (PathEnd<=length(APath)) and (APath[PathEnd]<>';') do inc(PathEnd);
|
||||
if PathEnd>PathStart then begin
|
||||
// extract and expand current search directory
|
||||
ADir:=copy(APath,PathStart,PathEnd-PathStart);
|
||||
if (ADir<>'') and (ADir[length(ADir)]<>PathDelim) then
|
||||
ADir:=ADir+PathDelim;
|
||||
if not FilenameIsAbsolute(ADir) then ADir:=CurDir+ADir;
|
||||
// get CompiledSrcPath for current search directory
|
||||
CurCompiledSrcPath:=OnGetSrcPathForCompiledUnit(Self,ADir);
|
||||
if CurCompiledSrcPath<>'' then begin
|
||||
// this directory is an unit output directory
|
||||
SrcPath:=SrcPath+';'+CurCompiledSrcPath;
|
||||
end;
|
||||
end;
|
||||
PathStart:=PathEnd+1;
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
MainCodeIsVirtual: Boolean;
|
||||
begin
|
||||
UnitPath:='';
|
||||
SrcPath:='';
|
||||
|
||||
MainCodeIsVirtual:=TCodeBuffer(Scanner.MainCode).IsVirtual;
|
||||
if not MainCodeIsVirtual then begin
|
||||
CurDir:=ExtractFilePath(TCodeBuffer(Scanner.MainCode).Filename);
|
||||
end else begin
|
||||
CurDir:='';
|
||||
end;
|
||||
|
||||
// first search in current directory (= where the maincode is)
|
||||
UnitPath:=CurDir;
|
||||
|
||||
// search source in search path
|
||||
if Assigned(OnGetUnitSourceSearchPath) then begin
|
||||
SrcPath:=SrcPath+';'+OnGetUnitSourceSearchPath(Self);
|
||||
end else begin
|
||||
UnitPath:=UnitPath+';'+Scanner.Values[ExternalMacroStart+'UnitPath'];
|
||||
SrcPath:=SrcPath+';'+Scanner.Values[ExternalMacroStart+'SrcPath'];
|
||||
end;
|
||||
|
||||
// search for compiled unit
|
||||
// -> search in every unit path for a CompiledSrcPath and search there
|
||||
SearchCompiledSrcPaths(UnitPath);
|
||||
end;
|
||||
|
||||
function TFindDeclarationTool.FindSmartHint(const CursorPos: TCodeXYPosition
|
||||
): string;
|
||||
var
|
||||
|
@ -226,6 +226,8 @@ type
|
||||
const Context: TFindContext; BeautifyCodeOptions: TBeautifyCodeOptions);
|
||||
procedure GatherUsefulIdentifiers(CleanPos: integer;
|
||||
const Context: TFindContext; BeautifyCodeOptions: TBeautifyCodeOptions);
|
||||
procedure GatherUnitnames(CleanPos: integer;
|
||||
const Context: TFindContext; BeautifyCodeOptions: TBeautifyCodeOptions);
|
||||
public
|
||||
function GatherIdentifiers(const CursorPos: TCodeXYPosition;
|
||||
var IdentifierList: TIdentifierList;
|
||||
@ -938,6 +940,12 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TIdentCompletionTool.GatherUnitnames(CleanPos: integer;
|
||||
const Context: TFindContext; BeautifyCodeOptions: TBeautifyCodeOptions);
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
function TIdentCompletionTool.GatherIdentifiers(
|
||||
const CursorPos: TCodeXYPosition; var IdentifierList: TIdentifierList;
|
||||
BeautifyCodeOptions: TBeautifyCodeOptions): boolean;
|
||||
@ -1007,99 +1015,103 @@ begin
|
||||
' Ident=',copy(Src,IdentStartPos,IdentEndPos-IdentStartPos));
|
||||
{$ENDIF}
|
||||
GatherContext:=CreateFindContext(Self,CursorNode);
|
||||
ContextExprStartPos:=GetContextExprStartPos(IdentStartPos,CursorNode);
|
||||
if GatherContext.Node.Desc=ctnWithVariable then
|
||||
GatherContext.Node:=GatherContext.Node.Parent;
|
||||
if CursorNode.Desc=ctnUsesSection then begin
|
||||
GatherUnitNames(IdentStartPos,GatherContext,BeautifyCodeOptions);
|
||||
end else begin
|
||||
ContextExprStartPos:=GetContextExprStartPos(IdentStartPos,CursorNode);
|
||||
if GatherContext.Node.Desc=ctnWithVariable then
|
||||
GatherContext.Node:=GatherContext.Node.Parent;
|
||||
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers C',
|
||||
' ContextExprStartPos=',dbgs(ContextExprStartPos),
|
||||
' Expr=',StringToPascalConst(copy(Src,ContextExprStartPos,
|
||||
IdentStartPos-ContextExprStartPos)));
|
||||
{$ENDIF}
|
||||
StartInSubContext:=false;
|
||||
if ContextExprStartPos<IdentStartPos then begin
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers C',
|
||||
' ContextExprStartPos=',dbgs(ContextExprStartPos),
|
||||
' Expr=',StringToPascalConst(copy(Src,ContextExprStartPos,
|
||||
IdentStartPos-ContextExprStartPos)));
|
||||
{$ENDIF}
|
||||
StartInSubContext:=false;
|
||||
if ContextExprStartPos<IdentStartPos then begin
|
||||
MoveCursorToCleanPos(IdentStartPos);
|
||||
Params.ContextNode:=CursorNode;
|
||||
Params.SetIdentifier(Self,nil,nil);
|
||||
Params.Flags:=[fdfExceptionOnNotFound,
|
||||
fdfSearchInParentNodes,fdfSearchInAncestors];
|
||||
ExprType:=FindExpressionTypeOfVariable(ContextExprStartPos,IdentStartPos,
|
||||
Params);
|
||||
if (ExprType.Desc=xtContext) then begin
|
||||
GatherContext:=ExprType.Context;
|
||||
StartInSubContext:=true;
|
||||
end;
|
||||
end;
|
||||
|
||||
// search and gather identifiers in context
|
||||
if (GatherContext.Tool<>nil) and (GatherContext.Node<>nil) then begin
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers D CONTEXT: ',
|
||||
GatherContext.Tool.MainFilename,
|
||||
' ',GatherContext.Node.DescAsString,
|
||||
' "',StringToPascalConst(copy(GatherContext.Tool.Src,GatherContext.Node.StartPos,50)),'"');
|
||||
{$ENDIF}
|
||||
// gather all identifiers in context
|
||||
Params.ContextNode:=GatherContext.Node;
|
||||
Params.SetIdentifier(Self,nil,@CollectAllIdentifiers);
|
||||
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable];
|
||||
if not StartInSubContext then
|
||||
Include(Params.Flags,fdfSearchInParentNodes);
|
||||
|
||||
if Params.ContextNode.Desc in [ctnClass,ctnClassInterface] then
|
||||
Exclude(Params.Flags,fdfSearchInParentNodes);
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers F');
|
||||
{$ENDIF}
|
||||
CurrentIdentifierList.Context:=GatherContext;
|
||||
GatherContext.Tool.FindIdentifierInContext(Params);
|
||||
end;
|
||||
|
||||
// add useful identifiers without context
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers G');
|
||||
{$ENDIF}
|
||||
GatherUsefulIdentifiers(IdentStartPos,GatherContext,BeautifyCodeOptions);
|
||||
|
||||
// check for incomplete context
|
||||
// context bracket level
|
||||
CurrentIdentifierList.StartBracketLvl:=
|
||||
GetBracketLvl(Src,CursorNode.StartPos,IdentStartPos,
|
||||
Scanner.NestedComments);
|
||||
// context behind
|
||||
if IdentEndPos<SrcLen then begin
|
||||
MoveCursorToCleanPos(IdentEndPos);
|
||||
ReadNextAtom;
|
||||
CurrentIdentifierList.StartAtomBehind:=CurPos;
|
||||
// check if in statement
|
||||
if CursorNode.Desc in AllPascalStatements then begin
|
||||
CurrentIdentifierList.ContextFlags:=
|
||||
CurrentIdentifierList.ContextFlags+[ilcfStartInStatement];
|
||||
// check if at end of statement
|
||||
if (CurPos.Flag in [cafEnd,cafBegin])
|
||||
or ((not UpAtomIs('ELSE'))
|
||||
and (CurPos.Flag=cafWord)
|
||||
and (not PositionsInSameLine(Src,IdentEndPos,CurPos.StartPos)))
|
||||
then
|
||||
if CurrentIdentifierList.StartBracketLvl=0 then
|
||||
CurrentIdentifierList.ContextFlags:=
|
||||
CurrentIdentifierList.ContextFlags+[ilcfContextNeedsEndSemicolon];
|
||||
end;
|
||||
end;
|
||||
// context in front of
|
||||
MoveCursorToCleanPos(IdentStartPos);
|
||||
Params.ContextNode:=CursorNode;
|
||||
Params.SetIdentifier(Self,nil,nil);
|
||||
Params.Flags:=[fdfExceptionOnNotFound,
|
||||
fdfSearchInParentNodes,fdfSearchInAncestors];
|
||||
ExprType:=FindExpressionTypeOfVariable(ContextExprStartPos,IdentStartPos,
|
||||
Params);
|
||||
if (ExprType.Desc=xtContext) then begin
|
||||
GatherContext:=ExprType.Context;
|
||||
StartInSubContext:=true;
|
||||
end;
|
||||
end;
|
||||
|
||||
// search and gather identifiers in context
|
||||
if (GatherContext.Tool<>nil) and (GatherContext.Node<>nil) then begin
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers D CONTEXT: ',
|
||||
GatherContext.Tool.MainFilename,
|
||||
' ',GatherContext.Node.DescAsString,
|
||||
' "',StringToPascalConst(copy(GatherContext.Tool.Src,GatherContext.Node.StartPos,50)),'"');
|
||||
{$ENDIF}
|
||||
// gather all identifiers in context
|
||||
Params.ContextNode:=GatherContext.Node;
|
||||
Params.SetIdentifier(Self,nil,@CollectAllIdentifiers);
|
||||
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable];
|
||||
if not StartInSubContext then
|
||||
Include(Params.Flags,fdfSearchInParentNodes);
|
||||
|
||||
if Params.ContextNode.Desc in [ctnClass,ctnClassInterface] then
|
||||
Exclude(Params.Flags,fdfSearchInParentNodes);
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers F');
|
||||
{$ENDIF}
|
||||
CurrentIdentifierList.Context:=GatherContext;
|
||||
GatherContext.Tool.FindIdentifierInContext(Params);
|
||||
end;
|
||||
|
||||
// add useful identifiers without context
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers G');
|
||||
{$ENDIF}
|
||||
GatherUsefulIdentifiers(IdentStartPos,GatherContext,BeautifyCodeOptions);
|
||||
|
||||
// check for incomplete context
|
||||
// context bracket level
|
||||
CurrentIdentifierList.StartBracketLvl:=
|
||||
GetBracketLvl(Src,CursorNode.StartPos,IdentStartPos,
|
||||
Scanner.NestedComments);
|
||||
// context behind
|
||||
if IdentEndPos<SrcLen then begin
|
||||
MoveCursorToCleanPos(IdentEndPos);
|
||||
ReadNextAtom;
|
||||
CurrentIdentifierList.StartAtomBehind:=CurPos;
|
||||
// check if in statement
|
||||
if CursorNode.Desc in AllPascalStatements then begin
|
||||
CurrentIdentifierList.ContextFlags:=
|
||||
CurrentIdentifierList.ContextFlags+[ilcfStartInStatement];
|
||||
// check if at end of statement
|
||||
if (CurPos.Flag in [cafEnd,cafBegin])
|
||||
or ((not UpAtomIs('ELSE'))
|
||||
and (CurPos.Flag=cafWord)
|
||||
and (not PositionsInSameLine(Src,IdentEndPos,CurPos.StartPos)))
|
||||
ReadPriorAtom;
|
||||
CurrentIdentifierList.StartAtomInFront:=CurPos;
|
||||
// check if LValue
|
||||
if (ilcfStartInStatement in CurrentIdentifierList.ContextFlags) then begin
|
||||
if (CurPos.Flag in [cafSemicolon,cafBegin,cafEnd])
|
||||
or WordIsBlockKeyWord.DoItUpperCase(UpperSrc,
|
||||
CurPos.StartPos,CurPos.EndPos-CurPos.StartPos)
|
||||
then
|
||||
if CurrentIdentifierList.StartBracketLvl=0 then
|
||||
CurrentIdentifierList.ContextFlags:=
|
||||
CurrentIdentifierList.ContextFlags+[ilcfContextNeedsEndSemicolon];
|
||||
CurrentIdentifierList.ContextFlags:=
|
||||
CurrentIdentifierList.ContextFlags+[ilcfStartIsLValue];
|
||||
end;
|
||||
end;
|
||||
// context in front of
|
||||
MoveCursorToCleanPos(IdentStartPos);
|
||||
ReadPriorAtom;
|
||||
CurrentIdentifierList.StartAtomInFront:=CurPos;
|
||||
// check if LValue
|
||||
if (ilcfStartInStatement in CurrentIdentifierList.ContextFlags) then begin
|
||||
if (CurPos.Flag in [cafSemicolon,cafBegin,cafEnd])
|
||||
or WordIsBlockKeyWord.DoItUpperCase(UpperSrc,
|
||||
CurPos.StartPos,CurPos.EndPos-CurPos.StartPos)
|
||||
then
|
||||
CurrentIdentifierList.ContextFlags:=
|
||||
CurrentIdentifierList.ContextFlags+[ilcfStartIsLValue];
|
||||
end;
|
||||
|
||||
Result:=true;
|
||||
finally
|
||||
|
@ -120,7 +120,8 @@ function TrimSearchPath(const SearchPath, BaseDirectory: string): string;
|
||||
function MergeSearchPaths(const OldSearchPath, AddSearchPath: string): string;
|
||||
function RemoveSearchPaths(const SearchPath, RemoveSearchPath: string): string;
|
||||
function CreateRelativeSearchPath(const SearchPath, BaseDirectory: string): string;
|
||||
function ShortenSearchPath(const SearchPath, BaseDirectory, ChompDirectory: string): string;
|
||||
function ShortenSearchPath(const SearchPath, BaseDirectory,
|
||||
ChompDirectory: string): string;
|
||||
function GetNextDirectoryInSearchPath(const SearchPath: string;
|
||||
var NextStartPos: integer): string;
|
||||
function GetNextUsedDirectoryInSearchPath(const SearchPath,
|
||||
|
Loading…
Reference in New Issue
Block a user