mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-11 20:52:09 +02:00
IDE: find/rename identifier: search in used but not listed units too
git-svn-id: trunk@57727 -
This commit is contained in:
parent
9f7177574f
commit
7dd4ef464c
@ -100,6 +100,7 @@ type
|
||||
TUsesGraph = class
|
||||
private
|
||||
FFiles: TAVLTree; // tree of TUGUnit sorted for Filename
|
||||
FIgnoreFiles: TAVLTree; // tree of TUGUnit sorted for Filename
|
||||
FQueuedFiles: TAVLTree; // tree of TUGUnit sorted for Filename
|
||||
FTargetAll: boolean;
|
||||
FTargetFiles: TAVLTree; // tree of TUGUnit sorted for Filename
|
||||
@ -122,6 +123,7 @@ type
|
||||
|
||||
procedure AddStartUnit(ExpFilename: string);
|
||||
procedure AddTargetUnit(ExpFilename: string);
|
||||
procedure AddIgnoreUnit(ExpFilename: string);
|
||||
procedure AddSystemUnitAsTarget;
|
||||
function Parse(IgnoreErrors: boolean; out Completed: boolean;
|
||||
StopAfterMs: integer = -1): boolean;
|
||||
@ -134,6 +136,7 @@ type
|
||||
function InsertMissingLinks(UGUnitList: TFPList): boolean;
|
||||
|
||||
property FilesTree: TAVLTree read FFiles; // tree of TUGUnit sorted for Filename (all parsed)
|
||||
property IgnoreFilesTree: TAVLTree read FIgnoreFiles; // tree of TUGUnit sorted for Filename
|
||||
property QueuedFilesTree: TAVLTree read FQueuedFiles; // tree of TUGUnit sorted for Filename
|
||||
property TargetFilesTree: TAVLTree read FTargetFiles; // tree of TUGUnit sorted for Filename
|
||||
property TargetAll: boolean read FTargetAll write FTargetAll;
|
||||
@ -245,6 +248,7 @@ begin
|
||||
FUnitClass:=TUGUnit;
|
||||
FUsesClass:=TUGUses;
|
||||
FFiles:=TAVLTree.Create(@CompareUGUnitFilenames);
|
||||
FIgnoreFiles:=TAVLTree.Create(@CompareUGUnitFilenames);
|
||||
FQueuedFiles:=TAVLTree.Create(@CompareUGUnitFilenames);
|
||||
FTargetFiles:=TAVLTree.Create(@CompareUGUnitFilenames);
|
||||
end;
|
||||
@ -252,6 +256,7 @@ end;
|
||||
destructor TUsesGraph.Destroy;
|
||||
begin
|
||||
Clear;
|
||||
FreeAndNil(FIgnoreFiles);
|
||||
FreeAndNil(FQueuedFiles);
|
||||
FreeAndNil(FTargetFiles);
|
||||
FreeAndNil(FFiles);
|
||||
@ -333,16 +338,29 @@ begin
|
||||
end;
|
||||
|
||||
procedure TUsesGraph.AddTargetUnit(ExpFilename: string);
|
||||
var
|
||||
NewUnit: TUGUnit;
|
||||
begin
|
||||
if ExpFilename='' then exit;
|
||||
if FQueuedFiles.FindKey(PChar(ExpFilename),@CompareFilenameAndUGUnit)<>nil then
|
||||
exit; // already a start file
|
||||
// add to FFiles and FTargetFiles
|
||||
//debugln(['TUsesGraph.AddTargetUnit ',ExpFilename]);
|
||||
FTargetFiles.Add(GetUnit(ExpFilename,true));
|
||||
NewUnit:=GetUnit(ExpFilename,true);
|
||||
if FTargetFiles.Find(NewUnit)=nil then
|
||||
FTargetFiles.Add(NewUnit);
|
||||
FTargetDirsValid:=false;
|
||||
end;
|
||||
|
||||
procedure TUsesGraph.AddIgnoreUnit(ExpFilename: string);
|
||||
var
|
||||
NewUnit: TUGUnit;
|
||||
begin
|
||||
NewUnit:=GetUnit(ExpFilename,true);
|
||||
if FIgnoreFiles.Find(NewUnit)=nil then
|
||||
FIgnoreFiles.Add(NewUnit);
|
||||
end;
|
||||
|
||||
procedure TUsesGraph.AddSystemUnitAsTarget;
|
||||
begin
|
||||
AddTargetUnit(DirectoryCachePool.FindUnitInUnitSet('','system'));
|
||||
@ -389,6 +407,7 @@ function TUsesGraph.Parse(IgnoreErrors: boolean; out Completed: boolean;
|
||||
ImplementationUsesSection: TStrings;
|
||||
begin
|
||||
Result:=false;
|
||||
//debugln(['ParseUnit ',CurUnit.Filename,' ',Pos('tcfiler',CurUnit.Filename)]);
|
||||
Include(CurUnit.Flags,ugufLoadError);
|
||||
// load file
|
||||
Abort:=false;
|
||||
@ -461,6 +480,7 @@ begin
|
||||
CurUnit:=TUGUnit(AVLNode.Data);
|
||||
FQueuedFiles.Delete(AVLNode);
|
||||
Include(CurUnit.Flags,ugufReached);
|
||||
if FIgnoreFiles.Find(CurUnit)<>nil then continue;
|
||||
//debugln(['TUsesGraph.Parse Unit=',CurUnit.Filename,' UnitCanFindTarget=',UnitCanFindTarget(CurUnit.Filename)]);
|
||||
if UnitCanFindTarget(CurUnit.Filename) then begin
|
||||
ParseUnit(CurUnit);
|
||||
@ -527,7 +547,7 @@ begin
|
||||
end;
|
||||
|
||||
function TUsesGraph.UnitCanFindTarget(ExpFilename: string): boolean;
|
||||
// returns true if units search path allows finding a target unit
|
||||
// returns true if ExpFilename can find one of the targets via the search paths
|
||||
var
|
||||
BaseDir: String;
|
||||
SrcPath: String;
|
||||
@ -561,8 +581,6 @@ var
|
||||
AVLNode: TAVLTreeNode;
|
||||
CurUnit: TUGUnit;
|
||||
Dir: String;
|
||||
p: Integer;
|
||||
TargetDir: String;
|
||||
begin
|
||||
if FTargetFiles.Count=0 then exit(TargetAll);
|
||||
|
||||
@ -585,7 +603,7 @@ begin
|
||||
// in virtual directory
|
||||
if (FTargetDirs='') or (FTargetDirs[1]<>';') then
|
||||
FTargetDirs:=';'+FTargetDirs;
|
||||
end else if not FileIsInPath(Dir,FTargetDirs) then begin
|
||||
end else if FindPathInSearchPath(Dir,FTargetDirs)<1 then begin
|
||||
// normal source directory
|
||||
if FTargetDirs='' then
|
||||
FTargetDirs:=Dir
|
||||
@ -598,15 +616,9 @@ begin
|
||||
|
||||
Result:=true;
|
||||
if TargetAll then exit;
|
||||
if (ExpDir='') and (FTargetDirs[1]=';') then exit;
|
||||
p:=1;
|
||||
repeat
|
||||
TargetDir:=GetNextDelimitedItem(FTargetDirs,';',p);
|
||||
if TargetDir<>'' then begin
|
||||
if CompareFilenames(TargetDir,ExpDir)=0 then exit;
|
||||
end;
|
||||
until p>length(FTargetDirs);
|
||||
Result:=false;
|
||||
if (ExpDir='') and (FTargetDirs[1]=';') then
|
||||
exit; // virtual directory
|
||||
Result:=FindPathInSearchPath(ExpDir,FTargetDirs)>0;
|
||||
end;
|
||||
|
||||
function TUsesGraph.FindShortestPath(StartUnit, EndUnit: TUGUnit): TFPList;
|
||||
|
@ -250,6 +250,13 @@ type
|
||||
);
|
||||
TPkgIntfRequiredFlags = set of TPkgIntfRequiredFlag;
|
||||
|
||||
TPkgIntfGatherUnitType = (
|
||||
piguListed, // unit is in list of given Owner, i.e. in lpi, lpk file, this may contain platform specific units
|
||||
piguUsed, // unit is used directly or indirectly by the start module and no currently open package/project is associated with it
|
||||
piguAllUsed // as pigyUsed, except even units associated with another package/project are returned
|
||||
);
|
||||
TPkgIntfGatherUnitTypes = set of TPkgIntfGatherUnitType;
|
||||
|
||||
{ TPackageEditingInterface }
|
||||
|
||||
TPackageEditingInterface = class(TComponent)
|
||||
@ -273,6 +280,7 @@ type
|
||||
function GetOwnersOfUnit(const UnitFilename: string): TFPList; virtual; abstract;
|
||||
procedure ExtendOwnerListWithUsedByOwners(OwnerList: TFPList); virtual; abstract;
|
||||
function GetSourceFilesOfOwners(OwnerList: TFPList): TStrings; virtual; abstract;
|
||||
function GetUnitsOfOwners(OwnerList: TFPList; Flags: TPkgIntfGatherUnitTypes): TStrings; virtual; abstract;
|
||||
function GetPossibleOwnersOfUnit(const UnitFilename: string;
|
||||
Flags: TPkgIntfOwnerSearchFlags): TFPList; virtual; abstract;
|
||||
function GetPackageOfSourceEditor(out APackage: TIDEPackage; ASrcEdit: TObject): TLazPackageFile; virtual; abstract;
|
||||
|
@ -36,12 +36,13 @@ uses
|
||||
LCLProc, Forms, Controls, Dialogs, StdCtrls, ExtCtrls, ComCtrls, ButtonPanel,
|
||||
LclIntf,
|
||||
// CodeTools
|
||||
FileProcs, CTUnitGraph, CodeTree, CodeCache, CodeToolManager,
|
||||
FileProcs, CTUnitGraph, CodeTree, CodeCache, CodeToolManager, BasicCodeTools,
|
||||
// LazUtils
|
||||
LazFileUtils, LazFileCache, laz2_DOM, AvgLvlTree,
|
||||
// IDE
|
||||
LazarusIDEStrConsts, IDEProcs, IDEWindowIntf, MiscOptions, DialogProcs,
|
||||
LazIDEIntf, IDEDialogs, InputHistory, SearchResultView, CodeHelp;
|
||||
LazIDEIntf, IDEDialogs, SrcEditorIntf, PackageIntf, InputHistory,
|
||||
SearchResultView, CodeHelp, TransferMacros;
|
||||
|
||||
type
|
||||
|
||||
@ -95,6 +96,10 @@ function ShowFindRenameIdentifierDialog(const Filename: string;
|
||||
AllowRename: boolean; // allow user to disable/enable rename
|
||||
SetRenameActive: boolean; // check rename
|
||||
Options: TFindRenameIdentifierOptions): TModalResult;
|
||||
function DoFindRenameIdentifier(
|
||||
AllowRename: boolean; // allow user to disable/enable rename
|
||||
SetRenameActive: boolean; // check rename
|
||||
Options: TFindRenameIdentifierOptions): TModalResult;
|
||||
function GatherIdentifierReferences(Files: TStringList;
|
||||
DeclarationCode: TCodeBuffer; const DeclarationCaretXY: TPoint;
|
||||
SearchInComments: boolean;
|
||||
@ -166,6 +171,256 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function DoFindRenameIdentifier(AllowRename: boolean; SetRenameActive: boolean;
|
||||
Options: TFindRenameIdentifierOptions): TModalResult;
|
||||
|
||||
// TODO: replace Files: TStringsList with a AVL tree
|
||||
|
||||
function AddExtraFiles(Files: TStrings): TModalResult;
|
||||
var
|
||||
i: Integer;
|
||||
CurFileMask: string;
|
||||
FileInfo: TSearchRec;
|
||||
CurDirectory: String;
|
||||
CurFilename: String;
|
||||
OnlyPascalSources: Boolean;
|
||||
begin
|
||||
Result:=mrCancel;
|
||||
if (Options.ExtraFiles<>nil) then begin
|
||||
for i:=0 to Options.ExtraFiles.Count-1 do begin
|
||||
CurFileMask:=Options.ExtraFiles[i];
|
||||
if not GlobalMacroList.SubstituteStr(CurFileMask) then exit;
|
||||
CurFileMask:=ChompPathDelim(CurFileMask);
|
||||
if not FilenameIsAbsolute(CurFileMask) then begin
|
||||
if LazarusIDE.ActiveProject.IsVirtual then continue;
|
||||
CurFileMask:=AppendPathDelim(LazarusIDE.ActiveProject.Directory+CurFileMask);
|
||||
end;
|
||||
CurFileMask:=TrimFilename(CurFileMask);
|
||||
OnlyPascalSources:=false;
|
||||
if DirPathExistsCached(CurFileMask) then begin
|
||||
// a whole directory
|
||||
OnlyPascalSources:=true;
|
||||
CurFileMask:=AppendPathDelim(CurFileMask)+AllFilesMask;
|
||||
end else if FileExistsCached(CurFileMask) then begin
|
||||
// single file
|
||||
Files.Add(CurFileMask);
|
||||
continue;
|
||||
end else begin
|
||||
// a mask
|
||||
end;
|
||||
if FindFirstUTF8(CurFileMask,faAnyFile,FileInfo)=0
|
||||
then begin
|
||||
CurDirectory:=AppendPathDelim(ExtractFilePath(CurFileMask));
|
||||
repeat
|
||||
// check if special file
|
||||
if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='')
|
||||
then
|
||||
continue;
|
||||
if OnlyPascalSources and not FilenameIsPascalSource(FileInfo.Name)
|
||||
then
|
||||
continue;
|
||||
CurFilename:=CurDirectory+FileInfo.Name;
|
||||
//debugln(['AddExtraFiles ',CurFilename]);
|
||||
if FileIsText(CurFilename) then
|
||||
Files.Add(CurFilename);
|
||||
until FindNextUTF8(FileInfo)<>0;
|
||||
end;
|
||||
FindCloseUTF8(FileInfo);
|
||||
end;
|
||||
end;
|
||||
Result:=mrOk;
|
||||
end;
|
||||
|
||||
var
|
||||
StartSrcEdit: TSourceEditorInterface;
|
||||
DeclCode, StartSrcCode: TCodeBuffer;
|
||||
DeclX, DeclY, DeclTopLine, StartTopLine, i: integer;
|
||||
LogCaretXY, DeclarationCaretXY: TPoint;
|
||||
OwnerList: TFPList;
|
||||
ExtraFiles: TStrings;
|
||||
Files: TStringList;
|
||||
Identifier: string;
|
||||
PascalReferences: TAVLTree;
|
||||
ListOfLazFPDocNode: TFPList;
|
||||
CurUnitname: String;
|
||||
OldChange, Completed: Boolean;
|
||||
Graph: TUsesGraph;
|
||||
Node: TAVLTreeNode;
|
||||
UGUnit: TUGUnit;
|
||||
begin
|
||||
Result:=mrCancel;
|
||||
if not LazarusIDE.BeginCodeTools then exit(mrCancel);
|
||||
|
||||
StartSrcEdit:=SourceEditorManagerIntf.ActiveEditor;
|
||||
StartSrcCode:=TCodeBuffer(StartSrcEdit.CodeToolsBuffer);
|
||||
StartTopLine:=StartSrcEdit.TopLine;
|
||||
|
||||
// find the main declaration
|
||||
LogCaretXY:=StartSrcEdit.CursorTextXY;
|
||||
if not CodeToolBoss.FindMainDeclaration(StartSrcCode,
|
||||
LogCaretXY.X,LogCaretXY.Y,
|
||||
DeclCode,DeclX,DeclY,DeclTopLine) then
|
||||
begin
|
||||
LazarusIDE.DoJumpToCodeToolBossError;
|
||||
exit(mrCancel);
|
||||
end;
|
||||
DeclarationCaretXY:=Point(DeclX,DeclY);
|
||||
Result:=LazarusIDE.DoOpenFileAndJumpToPos(DeclCode.Filename, DeclarationCaretXY,
|
||||
DeclTopLine,-1,-1,[ofOnlyIfExists,ofRegularFile,ofDoNotLoadResource]);
|
||||
if Result<>mrOk then
|
||||
exit;
|
||||
|
||||
CodeToolBoss.GetIdentifierAt(DeclCode,DeclarationCaretXY.X,DeclarationCaretXY.Y,Identifier);
|
||||
CurUnitname:=ExtractFileNameOnly(DeclCode.Filename);
|
||||
|
||||
//debugln('TMainIDE.DoFindRenameIdentifier A DeclarationCaretXY=x=',dbgs(DeclarationCaretXY.X),' y=',dbgs(DeclarationCaretXY.Y));
|
||||
|
||||
Files:=nil;
|
||||
OwnerList:=nil;
|
||||
PascalReferences:=nil;
|
||||
ListOfLazFPDocNode:=nil;
|
||||
try
|
||||
// let user choose the search scope
|
||||
Result:=ShowFindRenameIdentifierDialog(DeclCode.Filename,DeclarationCaretXY,
|
||||
AllowRename,SetRenameActive,nil);
|
||||
if Result<>mrOk then begin
|
||||
debugln('Error: (lazarus) DoFindRenameIdentifier failed: user cancelled dialog');
|
||||
exit;
|
||||
end;
|
||||
|
||||
// create the file list
|
||||
Files:=TStringList.Create;
|
||||
Files.Add(DeclCode.Filename);
|
||||
if CompareFilenames(DeclCode.Filename,StartSrcCode.Filename)<>0 then
|
||||
Files.Add(DeclCode.Filename);
|
||||
|
||||
Options:=MiscellaneousOptions.FindRenameIdentifierOptions;
|
||||
|
||||
// add packages, projects
|
||||
case Options.Scope of
|
||||
frProject:
|
||||
begin
|
||||
OwnerList:=TFPList.Create;
|
||||
OwnerList.Add(LazarusIDE.ActiveProject);
|
||||
end;
|
||||
frOwnerProjectPackage,frAllOpenProjectsAndPackages:
|
||||
begin
|
||||
OwnerList:=PackageEditingInterface.GetOwnersOfUnit(StartSrcCode.Filename);
|
||||
if (OwnerList<>nil)
|
||||
and (Options.Scope=frAllOpenProjectsAndPackages) then begin
|
||||
PackageEditingInterface.ExtendOwnerListWithUsedByOwners(OwnerList);
|
||||
ReverseList(OwnerList);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// get source files of packages and projects
|
||||
if OwnerList<>nil then begin
|
||||
// start in all listed files of the package(s)
|
||||
ExtraFiles:=PackageEditingInterface.GetSourceFilesOfOwners(OwnerList);
|
||||
if ExtraFiles<>nil then
|
||||
begin
|
||||
// parse all used units
|
||||
Graph:=CodeToolBoss.CreateUsesGraph;
|
||||
try
|
||||
for i:=0 to ExtraFiles.Count-1 do
|
||||
Graph.AddStartUnit(ExtraFiles[i]);
|
||||
Graph.AddTargetUnit(DeclCode.Filename);
|
||||
Graph.Parse(true,Completed);
|
||||
Node:=Graph.FilesTree.FindLowest;
|
||||
while Node<>nil do begin
|
||||
UGUnit:=TUGUnit(Node.Data);
|
||||
Files.Add(UGUnit.Filename);
|
||||
Node:=Node.Successor;
|
||||
end;
|
||||
finally
|
||||
ExtraFiles.Free;
|
||||
Graph.Free;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
//debugln(['DoFindRenameIdentifier ',Files.Text]);
|
||||
|
||||
// add user defined extra files
|
||||
Result:=AddExtraFiles(Files);
|
||||
if Result<>mrOk then begin
|
||||
debugln('Error: (lazarus) DoFindRenameIdentifier unable to add user defined extra files');
|
||||
exit;
|
||||
end;
|
||||
|
||||
// search pascal source references
|
||||
Result:=GatherIdentifierReferences(Files,DeclCode,
|
||||
DeclarationCaretXY,Options.SearchInComments,PascalReferences);
|
||||
if CodeToolBoss.ErrorMessage<>'' then
|
||||
LazarusIDE.DoJumpToCodeToolBossError;
|
||||
if Result<>mrOk then begin
|
||||
debugln('Error: (lazarus) DoFindRenameIdentifier GatherIdentifierReferences failed');
|
||||
exit;
|
||||
end;
|
||||
|
||||
{$IFDEF EnableFPDocRename}
|
||||
// search fpdoc references
|
||||
Result:=GatherFPDocReferencesForPascalFiles(Files,DeclarationUnitInfo.Source,
|
||||
DeclarationCaretXY,ListOfLazFPDocNode);
|
||||
if Result<>mrOk then begin
|
||||
debugln('Error: (lazarus) DoFindRenameIdentifier GatherFPDocReferences failed');
|
||||
exit;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
// ToDo: search lfm source references
|
||||
// ToDo: search i18n references
|
||||
// ToDo: designer references
|
||||
|
||||
// rename identifier
|
||||
if Options.Rename then begin
|
||||
if CompareIdentifiers(PChar(Identifier),PChar(CurUnitName))=0 then
|
||||
begin
|
||||
IDEMessageDialog(srkmecRenameIdentifier,
|
||||
lisTheIdentifierIsAUnitPleaseUseTheFileSaveAsFunction,
|
||||
mtInformation,[mbCancel],'');
|
||||
exit(mrCancel);
|
||||
end;
|
||||
OldChange:=LazarusIDE.OpenEditorsOnCodeToolChange;
|
||||
LazarusIDE.OpenEditorsOnCodeToolChange:=true;
|
||||
try
|
||||
if not CodeToolBoss.RenameIdentifier(PascalReferences,
|
||||
Identifier,Options.RenameTo, DeclCode, @DeclarationCaretXY)
|
||||
then begin
|
||||
LazarusIDE.DoJumpToCodeToolBossError;
|
||||
debugln('Error: (lazarus) DoFindRenameIdentifier unable to commit');
|
||||
Result:=mrCancel;
|
||||
exit;
|
||||
end;
|
||||
finally
|
||||
LazarusIDE.OpenEditorsOnCodeToolChange:=OldChange;
|
||||
end;
|
||||
if Options.RenameShowResult then
|
||||
Result:=ShowIdentifierReferences(DeclCode,
|
||||
DeclarationCaretXY,PascalReferences);
|
||||
end;
|
||||
|
||||
// show result
|
||||
Result:=mrOk;
|
||||
if (not Options.Rename) or (not SetRenameActive) then begin
|
||||
Result:=ShowIdentifierReferences(DeclCode,
|
||||
DeclarationCaretXY,PascalReferences);
|
||||
if Result<>mrOk then exit;
|
||||
end;
|
||||
|
||||
finally
|
||||
Files.Free;
|
||||
OwnerList.Free;
|
||||
CodeToolBoss.FreeTreeOfPCodeXYPosition(PascalReferences);
|
||||
FreeListObjects(ListOfLazFPDocNode,true);
|
||||
|
||||
// jump back in source editor
|
||||
Result:=LazarusIDE.DoOpenFileAndJumpToPos(StartSrcCode.Filename, LogCaretXY,
|
||||
StartTopLine,-1,-1,[ofOnlyIfExists,ofRegularFile,ofDoNotLoadResource]);
|
||||
end;
|
||||
end;
|
||||
|
||||
function GatherIdentifierReferences(Files: TStringList;
|
||||
DeclarationCode: TCodeBuffer; const DeclarationCaretXY: TPoint;
|
||||
SearchInComments: boolean;
|
||||
|
223
ide/main.pp
223
ide/main.pp
@ -9967,229 +9967,8 @@ begin
|
||||
end;
|
||||
|
||||
function TMainIDE.DoFindRenameIdentifier(Rename: boolean): TModalResult;
|
||||
var
|
||||
Options: TFindRenameIdentifierOptions;
|
||||
|
||||
// TODO: replace Files: TStringsList with a AVL tree
|
||||
|
||||
function AddExtraFiles(Files: TStrings): TModalResult;
|
||||
var
|
||||
i: Integer;
|
||||
CurFileMask: string;
|
||||
FileInfo: TSearchRec;
|
||||
CurDirectory: String;
|
||||
CurFilename: String;
|
||||
OnlyPascalSources: Boolean;
|
||||
begin
|
||||
Result:=mrCancel;
|
||||
if (Options.ExtraFiles<>nil) then begin
|
||||
for i:=0 to Options.ExtraFiles.Count-1 do begin
|
||||
CurFileMask:=Options.ExtraFiles[i];
|
||||
if not GlobalMacroList.SubstituteStr(CurFileMask) then exit;
|
||||
CurFileMask:=ChompPathDelim(CurFileMask);
|
||||
if not FilenameIsAbsolute(CurFileMask) then begin
|
||||
if Project1.IsVirtual then continue;
|
||||
CurFileMask:=AppendPathDelim(Project1.Directory+CurFileMask);
|
||||
end;
|
||||
CurFileMask:=TrimFilename(CurFileMask);
|
||||
OnlyPascalSources:=false;
|
||||
if DirPathExistsCached(CurFileMask) then begin
|
||||
// a whole directory
|
||||
OnlyPascalSources:=true;
|
||||
CurFileMask:=AppendPathDelim(CurFileMask)+GetAllFilesMask;
|
||||
end else if FileExistsCached(CurFileMask) then begin
|
||||
// single file
|
||||
Files.Add(CurFileMask);
|
||||
continue;
|
||||
end else begin
|
||||
// a mask
|
||||
end;
|
||||
if FindFirstUTF8(CurFileMask,faAnyFile,FileInfo)=0
|
||||
then begin
|
||||
CurDirectory:=AppendPathDelim(ExtractFilePath(CurFileMask));
|
||||
repeat
|
||||
// check if special file
|
||||
if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='')
|
||||
then
|
||||
continue;
|
||||
if OnlyPascalSources and not FilenameIsPascalSource(FileInfo.Name)
|
||||
then
|
||||
continue;
|
||||
CurFilename:=CurDirectory+FileInfo.Name;
|
||||
//debugln(['AddExtraFiles ',CurFilename]);
|
||||
if FileIsText(CurFilename) then
|
||||
Files.Add(CurFilename);
|
||||
until FindNextUTF8(FileInfo)<>0;
|
||||
end;
|
||||
FindCloseUTF8(FileInfo);
|
||||
end;
|
||||
end;
|
||||
Result:=mrOk;
|
||||
end;
|
||||
|
||||
var
|
||||
TargetSrcEdit, DeclarationSrcEdit: TSourceEditor;
|
||||
TargetUnitInfo, DeclarationUnitInfo: TUnitInfo;
|
||||
NewSource: TCodeBuffer;
|
||||
NewX, NewY, NewTopLine: integer;
|
||||
LogCaretXY, DeclarationCaretXY: TPoint;
|
||||
OwnerList: TFPList;
|
||||
ExtraFiles: TStrings;
|
||||
Files: TStringList;
|
||||
Identifier: string;
|
||||
PascalReferences: TAVLTree;
|
||||
ListOfLazFPDocNode: TFPList;
|
||||
CurUnitname: String;
|
||||
OldChange: Boolean;
|
||||
begin
|
||||
Result:=mrCancel;
|
||||
TargetSrcEdit:=nil;
|
||||
if not BeginCodeTool(TargetSrcEdit,TargetUnitInfo,[]) then exit;
|
||||
|
||||
// find the main declaration
|
||||
LogCaretXY:=TargetSrcEdit.EditorComponent.LogicalCaretXY;
|
||||
if not CodeToolBoss.FindMainDeclaration(TargetUnitInfo.Source,
|
||||
LogCaretXY.X,LogCaretXY.Y,
|
||||
NewSource,NewX,NewY,NewTopLine) then
|
||||
begin
|
||||
DoJumpToCodeToolBossError;
|
||||
exit;
|
||||
end;
|
||||
DoJumpToCodePosition(TargetSrcEdit, TargetUnitInfo,
|
||||
NewSource, NewX, NewY, NewTopLine, NewTopLine, NewTopLine, [jfFocusEditor]);
|
||||
CodeToolBoss.GetIdentifierAt(NewSource,NewX,NewY,Identifier);
|
||||
CurUnitname:=ExtractFileNameOnly(NewSource.Filename);
|
||||
|
||||
GetCurrentUnit(DeclarationSrcEdit,DeclarationUnitInfo);
|
||||
DeclarationCaretXY:=DeclarationSrcEdit.EditorComponent.LogicalCaretXY;
|
||||
//debugln('TMainIDE.DoFindRenameIdentifier A DeclarationCaretXY=x=',dbgs(DeclarationCaretXY.X),' y=',dbgs(DeclarationCaretXY.Y));
|
||||
|
||||
Files:=nil;
|
||||
OwnerList:=nil;
|
||||
PascalReferences:=nil;
|
||||
ListOfLazFPDocNode:=nil;
|
||||
try
|
||||
// let user choose the search scope
|
||||
Result:=ShowFindRenameIdentifierDialog(DeclarationUnitInfo.Source.Filename,
|
||||
DeclarationCaretXY,true,Rename,nil);
|
||||
if Result<>mrOk then begin
|
||||
debugln('Error: (lazarus) TMainIDE.DoFindRenameIdentifier failed: user cancelled dialog');
|
||||
exit;
|
||||
end;
|
||||
|
||||
// create the file list
|
||||
Files:=TStringList.Create;
|
||||
Files.Add(TargetUnitInfo.Filename);
|
||||
if CompareFilenames(DeclarationUnitInfo.Filename,TargetUnitInfo.Filename)<>0 then
|
||||
Files.Add(DeclarationUnitInfo.Filename);
|
||||
|
||||
Options:=MiscellaneousOptions.FindRenameIdentifierOptions;
|
||||
|
||||
// add packages, projects
|
||||
case Options.Scope of
|
||||
frProject:
|
||||
begin
|
||||
OwnerList:=TFPList.Create;
|
||||
OwnerList.Add(Project1);
|
||||
end;
|
||||
frOwnerProjectPackage,frAllOpenProjectsAndPackages:
|
||||
begin
|
||||
OwnerList:=PkgBoss.GetOwnersOfUnit(TargetUnitInfo.Filename);
|
||||
if (OwnerList<>nil)
|
||||
and (Options.Scope=frAllOpenProjectsAndPackages) then begin
|
||||
PkgBoss.ExtendOwnerListWithUsedByOwners(OwnerList);
|
||||
ReverseList(OwnerList);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// get source files of packages and projects
|
||||
if OwnerList<>nil then begin
|
||||
ExtraFiles:=PkgBoss.GetSourceFilesOfOwners(OwnerList);
|
||||
try
|
||||
if ExtraFiles<>nil then
|
||||
Files.AddStrings(ExtraFiles);
|
||||
finally
|
||||
ExtraFiles.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
// add user defined extra files
|
||||
Result:=AddExtraFiles(Files);
|
||||
if Result<>mrOk then begin
|
||||
debugln('Error: (lazarus) TMainIDE.DoFindRenameIdentifier unable to add user defined extra files');
|
||||
exit;
|
||||
end;
|
||||
|
||||
// search pascal source references
|
||||
Result:=GatherIdentifierReferences(Files,DeclarationUnitInfo.Source,
|
||||
DeclarationCaretXY,Options.SearchInComments,PascalReferences);
|
||||
if CodeToolBoss.ErrorMessage<>'' then
|
||||
DoJumpToCodeToolBossError;
|
||||
if Result<>mrOk then begin
|
||||
debugln('Error: (lazarus) TMainIDE.DoFindRenameIdentifier GatherIdentifierReferences failed');
|
||||
exit;
|
||||
end;
|
||||
|
||||
{$IFDEF EnableFPDocRename}
|
||||
// search fpdoc references
|
||||
Result:=GatherFPDocReferencesForPascalFiles(Files,DeclarationUnitInfo.Source,
|
||||
DeclarationCaretXY,ListOfLazFPDocNode);
|
||||
if Result<>mrOk then begin
|
||||
debugln('Error: (lazarus) TMainIDE.DoFindRenameIdentifier GatherFPDocReferences failed');
|
||||
exit;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
// ToDo: search lfm source references
|
||||
// ToDo: search i18n references
|
||||
// ToDo: designer references
|
||||
|
||||
// rename identifier
|
||||
if Options.Rename then begin
|
||||
if CompareIdentifiers(PChar(Identifier),PChar(CurUnitName))=0 then
|
||||
begin
|
||||
IDEMessageDialog(srkmecRenameIdentifier,
|
||||
lisTheIdentifierIsAUnitPleaseUseTheFileSaveAsFunction,
|
||||
mtInformation,[mbCancel],'');
|
||||
exit(mrCancel);
|
||||
end;
|
||||
OldChange:=OpenEditorsOnCodeToolChange;
|
||||
OpenEditorsOnCodeToolChange:=true;
|
||||
try
|
||||
if not CodeToolBoss.RenameIdentifier(PascalReferences,
|
||||
Identifier,Options.RenameTo, DeclarationUnitInfo.Source, @DeclarationCaretXY)
|
||||
then begin
|
||||
DoJumpToCodeToolBossError;
|
||||
debugln('Error: (lazarus) TMainIDE.DoFindRenameIdentifier unable to commit');
|
||||
Result:=mrCancel;
|
||||
exit;
|
||||
end;
|
||||
finally
|
||||
OpenEditorsOnCodeToolChange:=OldChange;
|
||||
end;
|
||||
if Options.RenameShowResult then
|
||||
Result:=ShowIdentifierReferences(DeclarationUnitInfo.Source,
|
||||
DeclarationCaretXY,PascalReferences);
|
||||
end;
|
||||
|
||||
// show result
|
||||
if (not Options.Rename) or (not Rename) then begin
|
||||
Result:=ShowIdentifierReferences(DeclarationUnitInfo.Source,
|
||||
DeclarationCaretXY,PascalReferences);
|
||||
if Result<>mrOk then exit;
|
||||
end;
|
||||
|
||||
finally
|
||||
Files.Free;
|
||||
OwnerList.Free;
|
||||
CodeToolBoss.FreeTreeOfPCodeXYPosition(PascalReferences);
|
||||
FreeListObjects(ListOfLazFPDocNode,true);
|
||||
|
||||
// jump back in source editor
|
||||
DoJumpToCodePosition(TargetSrcEdit, TargetUnitInfo,
|
||||
TargetUnitInfo.Source, LogCaretXY.X, LogCaretXY.Y, -1, -1, -1, [jfFocusEditor]);
|
||||
end;
|
||||
Result:=FindRenameIdentifier.DoFindRenameIdentifier(true,Rename,nil);
|
||||
end;
|
||||
|
||||
function TMainIDE.DoFindUsedUnitReferences: boolean;
|
||||
|
@ -51,10 +51,10 @@ uses
|
||||
LCLProc, Forms, Controls, Dialogs, Menus, ComCtrls, LResources,
|
||||
// LazUtils
|
||||
LazUTF8, Laz2_XMLCfg, lazutf8classes, LazFileUtils, LazFileCache, StringHashList,
|
||||
Translations, AvgLvlTree,
|
||||
Translations, AvgLvlTree, Laz_AVL_Tree,
|
||||
// Codetools
|
||||
CodeToolsConfig, CodeToolManager, CodeCache, BasicCodeTools,
|
||||
FileProcs, CodeTree,
|
||||
FileProcs, CodeTree, CTUnitGraph,
|
||||
// IDE Interface
|
||||
NewItemIntf, ProjPackIntf, ProjectIntf, PackageIntf, PackageDependencyIntf, PackageLinkIntf,
|
||||
CompOptsIntf, MenuIntf, IDEWindowIntf, IDEExternToolIntf, MacroIntf, LazIDEIntf,
|
||||
@ -230,6 +230,7 @@ type
|
||||
function GetOwnersOfUnit(const UnitFilename: string): TFPList; override;
|
||||
procedure ExtendOwnerListWithUsedByOwners(OwnerList: TFPList); override;
|
||||
function GetSourceFilesOfOwners(OwnerList: TFPList): TStrings; override;
|
||||
function GetUnitsOfOwners(OwnerList: TFPList; Flags: TPkgIntfGatherUnitTypes): TStrings; override;
|
||||
function GetPossibleOwnersOfUnit(const UnitFilename: string;
|
||||
Flags: TPkgIntfOwnerSearchFlags): TFPList; override;
|
||||
function GetPackageOfCurrentSourceEditor(out APackage: TIDEPackage): TPkgFile;
|
||||
@ -4702,6 +4703,128 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TPkgManager.GetUnitsOfOwners(OwnerList: TFPList;
|
||||
Flags: TPkgIntfGatherUnitTypes): TStrings;
|
||||
var
|
||||
Units: TFilenameToPointerTree;
|
||||
Graph: TUsesGraph;
|
||||
|
||||
procedure AddUnit(ExpFilename: string);
|
||||
begin
|
||||
if not FileExistsCached(ExpFilename) then exit;
|
||||
if Units.Contains(ExpFilename) then exit;
|
||||
Units[ExpFilename]:=nil;
|
||||
end;
|
||||
|
||||
procedure AddStartModule(ExpFilename: string);
|
||||
begin
|
||||
AddUnit(ExpFilename);
|
||||
Graph.AddStartUnit(ExpFilename);
|
||||
end;
|
||||
|
||||
var
|
||||
i, j: Integer;
|
||||
CurOwner: TObject;
|
||||
CurProject: TProject;
|
||||
CurPackage: TLazPackage;
|
||||
ProjFile: TLazProjectFile;
|
||||
PkgFile: TPkgFile;
|
||||
Completed: boolean;
|
||||
Node: TAVLTreeNode;
|
||||
UGUnit: TUGUnit;
|
||||
begin
|
||||
debugln(['TPkgManager.GetUnitsOfOwners piguListed=',piguListed in Flags,' piguUsed=',piguUsed in Flags,' piguAllUsed=',piguAllUsed in Flags]);
|
||||
Result:=TStringListUTF8.Create;
|
||||
if (OwnerList=nil) or (OwnerList.Count=0) then exit;
|
||||
|
||||
Units:=TFilenameToPointerTree.Create(false);
|
||||
Graph:=TUsesGraph.Create;
|
||||
try
|
||||
|
||||
for i:=0 to OwnerList.Count-1 do
|
||||
begin
|
||||
CurOwner:=TObject(OwnerList[i]);
|
||||
if CurOwner is TProject then
|
||||
begin
|
||||
CurProject:=TProject(CurOwner);
|
||||
if (pfMainUnitIsPascalSource in CurProject.Flags)
|
||||
and (CurProject.MainUnitInfo<>nil) then
|
||||
AddStartModule(CurProject.MainUnitInfo.GetFullFilename);
|
||||
if piguListed in Flags then
|
||||
begin
|
||||
for j:=0 to CurProject.FileCount-1 do
|
||||
begin
|
||||
ProjFile:=CurProject.Files[j];
|
||||
if not FilenameIsPascalUnit(ProjFile.Filename) then continue;
|
||||
AddStartModule(ProjFile.GetFullFilename);
|
||||
end;
|
||||
end;
|
||||
end else if CurOwner is TLazPackage then
|
||||
begin
|
||||
CurPackage:=TLazPackage(CurOwner);
|
||||
if piguListed in Flags then
|
||||
begin
|
||||
for j:=0 to CurPackage.FileCount-1 do
|
||||
begin
|
||||
PkgFile:=CurPackage.Files[j];
|
||||
if not (PkgFile.FileType in PkgFileRealUnitTypes) then continue;
|
||||
AddStartModule(PkgFile.GetFullFilename);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if Units.Count=0 then
|
||||
begin
|
||||
debugln(['TPkgManager.GetUnitsOfOwners no start modules END']);
|
||||
exit; // no start modules
|
||||
end;
|
||||
|
||||
if [piguUsed,piguAllUsed]*Flags<>[] then
|
||||
begin
|
||||
// parse units recursively
|
||||
Graph.AddSystemUnitAsTarget;
|
||||
if piguAllUsed in Flags then
|
||||
begin
|
||||
// gather all used units
|
||||
end else if piguUsed in Flags then
|
||||
begin
|
||||
// ignore units of other packages
|
||||
for i:=0 to PackageGraph.Count-1 do
|
||||
begin
|
||||
CurPackage:=PackageGraph[i];
|
||||
if OwnerList.IndexOf(CurPackage)>=0 then continue;
|
||||
for j:=0 to CurPackage.FileCount-1 do
|
||||
begin
|
||||
PkgFile:=CurPackage.Files[j];
|
||||
if not (PkgFile.FileType in PkgFileRealUnitTypes) then continue;
|
||||
Graph.AddIgnoreUnit(PkgFile.GetFullFilename);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// parse
|
||||
Graph.Parse(true,Completed);
|
||||
if Completed then ;
|
||||
|
||||
// add parsed units
|
||||
Node:=Graph.FilesTree.FindLowest;
|
||||
while Node<>nil do
|
||||
begin
|
||||
UGUnit:=TUGUnit(Node.Data);
|
||||
if Graph.IgnoreFilesTree.Find(UGUnit)=nil then
|
||||
Units[UGUnit.Filename]:=nil;
|
||||
Node:=Node.Successor;
|
||||
end;
|
||||
end;
|
||||
|
||||
Units.GetNames(Result);
|
||||
|
||||
finally
|
||||
Graph.Free;
|
||||
Units.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TPkgManager.GetPossibleOwnersOfUnit(const UnitFilename: string;
|
||||
Flags: TPkgIntfOwnerSearchFlags): TFPList;
|
||||
var
|
||||
|
Loading…
Reference in New Issue
Block a user