IDE: fpdoc editor: started resolving links

git-svn-id: trunk@21041 -
This commit is contained in:
mattias 2009-08-01 06:58:53 +00:00
parent 40768a5fa9
commit 9951b2d70c
2 changed files with 315 additions and 74 deletions

View File

@ -242,11 +242,16 @@ type
out CacheWasUsed: boolean;
out AnOwner: TObject;// package or project
CreateIfNotExists: boolean = false): string;
function GetFPDocFilenameForPkgFile(PkgFile: TPkgFile;
ResolveIncludeFiles: Boolean;
out CacheWasUsed: boolean;
CreateIfNotExists: boolean = false): string;
procedure GetFPDocFilenamesForSources(SrcFilenames: TStringToStringTree;
ResolveIncludeFiles: boolean;
var FPDocFilenames: TStringToStringTree // Names=Filename, Values=ModuleName
);
function FindModuleOwner(const Modulename: string): TObject;
function FindModuleOwner(FPDocFile: TLazFPDocFile): TObject;
function GetModuleOwnerName(TheOwner: TObject): string;
function ExpandFPDocLinkID(const LinkID, DefaultUnitName,
DefaultOwnerName: string): string;
@ -257,6 +262,13 @@ type
function GetFPDocNode(Tool: TCodeTool; CodeNode: TCodeTreeNode; Complete: boolean;
out FPDocFile: TLazFPDocFile; out DOMNode: TDOMNode;
out CacheWasUsed: boolean): TCodeHelpParseResult;
function GetLinkedFPDocNode(StartFPDocFile: TLazFPDocFile;
StartDOMNode: TDOMNode;
const Path: string;
Flags: TCodeHelpOpenFileFlags;
out ModuleOwner: TObject;
out FPDocFile: TLazFPDocFile; out DOMNode: TDOMNode;
out CacheWasUsed: boolean): TCodeHelpParseResult;
function GetDeclarationChain(Code: TCodeBuffer; X, Y: integer;
out ListOfPCodeXYPosition: TFPList;
out CacheWasUsed: boolean): TCodeHelpParseResult;
@ -1387,6 +1399,40 @@ begin
{$endif}
end;
function TCodeHelpManager.GetFPDocFilenameForPkgFile(PkgFile: TPkgFile;
ResolveIncludeFiles: Boolean; out CacheWasUsed: boolean;
CreateIfNotExists: boolean): string;
var
APackage: TLazPackage;
BaseDir: String;
SrcFilename: String;
CodeBuf: TCodeBuffer;
begin
Result:='';
CacheWasUsed:=false;
APackage:=TLazPackage(PkgFile.LazPackage);
if APackage.LazDocPaths='' then exit;
BaseDir:=APackage.Directory;
if BaseDir='' then exit;
SrcFilename:=PkgFile.Filename;
if ResolveIncludeFiles then begin
CodeBuf:=CodeToolBoss.FindFile(SrcFilename);
if CodeBuf<>nil then begin
CodeBuf:=CodeToolBoss.GetMainCode(CodeBuf);
if CodeBuf<>nil then begin
SrcFilename:=CodeBuf.Filename;
end;
end;
end;
if not FilenameIsPascalUnit(SrcFilename) then exit;
SrcFilename:=ExtractFileNameOnly(SrcFilename)+'.xml';
Result:=SearchFileInPath(SrcFilename,BaseDir,APackage.LazDocPaths,';',
ctsfcDefault);
end;
procedure TCodeHelpManager.GetFPDocFilenamesForSources(
SrcFilenames: TStringToStringTree; ResolveIncludeFiles: boolean;
var FPDocFilenames: TStringToStringTree);
@ -1430,6 +1476,69 @@ begin
Result:=nil;
end;
function TCodeHelpManager.FindModuleOwner(FPDocFile: TLazFPDocFile): TObject;
var
AProject: TLazProject;
Path: String;
p: PChar;
PkgName: String;
function InPackage(Pkg: TLazPackage): boolean;
var
SearchPath: String;
begin
Result:=false;
if (Pkg=nil) or (Pkg.LazDocPaths='') then exit;
// check if the file is in the search path
Path:=ExtractFilePath(FPDocFile.Filename);
SearchPath:=Pkg.LazDocPaths;
p:=FindPathInSearchPath(PChar(Path),length(Path),
PChar(SearchPath),length(SearchPath));
if p<>nil then begin
FindModuleOwner:=Pkg;
Result:=true;
end;
end;
var
Pkg: TLazPackage;
SearchPath: String;
i: Integer;
begin
Result:=nil;
if FPDocFile=nil then exit;
AProject:=LazarusIDE.ActiveProject;
// virtual files belong to the project
if not FilenameIsAbsolute(FPDocFile.Filename) then begin
Result:=AProject;
exit;
end;
// check if in the doc path of the project
if (AProject<>nil) and (AProject.LazDocPaths<>'') then begin
Path:=ExtractFilePath(FPDocFile.Filename);
SearchPath:=AProject.LazDocPaths;
p:=FindPathInSearchPath(PChar(Path),length(Path),
PChar(SearchPath),length(SearchPath));
if p<>nil then begin
Result:=AProject;
exit;
end;
end;
// check the packagename in the fpdoc file
PkgName:=FPDocFile.GetPackageName;
if PkgName<>'' then begin
Pkg:=PackageGraph.FindAPackageWithName(PkgName,nil);
if InPackage(Pkg) then exit;
end;
// search in all packages
for i:=0 to PackageGraph.Count-1 do
if InPackage(PackageGraph.Packages[i]) then exit;
end;
function TCodeHelpManager.GetModuleOwnerName(TheOwner: TObject): string;
begin
if TheOwner is TLazPackage then
@ -1576,6 +1685,108 @@ begin
Result:=chprSuccess;
end;
function TCodeHelpManager.GetLinkedFPDocNode(StartFPDocFile: TLazFPDocFile;
StartDOMNode: TDOMNode; const Path: string; Flags: TCodeHelpOpenFileFlags;
out ModuleOwner: TObject; out FPDocFile: TLazFPDocFile; out DOMNode: TDOMNode;
out CacheWasUsed: boolean): TCodeHelpParseResult;
function FindFPDocFilename(BaseDir, SearchPath, UnitName: string): string;
begin
if FilenameIsAbsolute(BaseDir) then
Result:=SearchFileInPath(UnitName+'.xml',BaseDir,SearchPath,';',ctsfcDefault)
else
Result:='';
end;
var
StartPos, p: LongInt;
PkgName: String;
Pkg: TLazPackage;
UnitName: String;
AProject: TLazProject;
ElementName: String;
FPDocFilename: String;
BaseDir: String;
begin
ModuleOwner:=nil;
FPDocFile:=nil;
DOMNode:=nil;
CacheWasUsed:=false;
Result:=chprFailed;
if Path='' then exit;
if StartDOMNode=nil then ; // for future use
StartPos:=1;
p:=1;
if Path[1]='#' then begin
// switch package
while (p<=length(Path)) and (Path[p]<>'.') do inc(p);
PkgName:=copy(Path,2,p-2);
if PkgName='' then exit;
Pkg:=PackageGraph.FindAPackageWithName(PkgName,nil);
if Pkg=nil then exit;
ModuleOwner:=Pkg;
if p>length(Path) then begin
// link to the module, no unit
Result:=chprSuccess;
exit;
end;
StartPos:=p+1;
end else begin
// relative link (either in the same fpdoc file or of the same module)
// use same package
ModuleOwner:=FindModuleOwner(FPDocFile);
if ModuleOwner=nil then exit;
// try in the same fpdoc file
DOMNode:=FPDocFile.GetElementWithName(Path);
if DOMNode<>nil then begin
// target is in same file
FPDocFile:=StartFPDocFile;
exit(chprSuccess);
end;
end;
// search in another unit
while (p<=length(Path)) and (Path[p]<>'.') do inc(p);
UnitName:=copy(Path,StartPos,p-StartPos);
if UnitName='' then exit;
FPDocFilename:='';
if ModuleOwner is TLazProject then begin
AProject:=TLazProject(ModuleOwner);
if AProject.LazDocPaths<>'' then begin
BaseDir:=ExtractFilePath(AProject.ProjectInfoFile);
FPDocFilename:=FindFPDocFilename(BaseDir,AProject.LazDocPaths,UnitName);
end;
end else if ModuleOwner is TLazPackage then begin
Pkg:=TLazPackage(ModuleOwner);
if Pkg.LazDocPaths<>'' then begin
BaseDir:=Pkg.Directory;
FPDocFilename:=FindFPDocFilename(BaseDir,Pkg.LazDocPaths,UnitName);
end;
end;
if FPDocFilename='' then exit;
// load FPDocFile
Result:=LoadFPDocFile(FPDocFilename,Flags,FPDocFile,CacheWasUsed);
if Result<>chprSuccess then exit;
if p>length(Path) then begin
// link to a unit, no element
Result:=chprSuccess;
exit;
end;
StartPos:=p+1;
while (p<=length(Path)) and (Path[p]<>'.') do inc(p);
// find element
ElementName:=copy(Path,p+1,length(Path));
DOMNode:=FPDocFile.GetElementWithName(ElementName);
if DOMNode<>nil then
Result:=chprSuccess
else
Result:=chprFailed;
end;
function TCodeHelpManager.GetDeclarationChain(Code: TCodeBuffer; X, Y: integer;
out ListOfPCodeXYPosition: TFPList; out CacheWasUsed: boolean
): TCodeHelpParseResult;

View File

@ -88,38 +88,42 @@ type
procedure LinkEditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState
);
private
FDocFile: TLazFPDocFile;
FStartFPDocFile: TLazFPDocFile;
fItems: TFPDocLinkCompletionList;
FSourceFilename: string;
fSourceOwner: TObject;
FStartModuleOwner: TObject;
function GetLink: string;
function GetLinkTitle: string;
procedure SetDocFile(const AValue: TLazFPDocFile);
procedure SetStartFPDocFile(const AValue: TLazFPDocFile);
procedure SetLink(const AValue: string);
procedure SetLinkTitle(const AValue: string);
procedure SetSourceFilename(const AValue: string);
procedure SetStartModuleOwner(const AValue: TObject);
procedure UpdateCompletionBox;
procedure AddPackagesToCompletion(Prefix: string);
procedure AddSiblingUnits(Prefix: string);
procedure AddModuleUnits(ModuleOwner: TObject; Prefix: string);
procedure AddProjectUnits(AProject: TLazProject; Prefix: string);
procedure AddPackageUnits(APackage: TLazPackage; Prefix: string);
procedure AddIdentifiers(Prefix: string);
procedure AddIdentifiers(ModuleOwner: TObject; FPDocFile: TLazFPDocFile;
Prefix: string);
procedure AddSubIdentifiers(Path: string);
public
procedure SetLink(const ASrcFilename, ATitle, ALink: string;
procedure SetLinkAndContext(const ASrcFilename, ATitle, ALink: string;
ADocFile: TLazFPDocFile);
property SourceFilename: string read FSourceFilename write SetSourceFilename;
property LinkTitle: string read GetLinkTitle write SetLinkTitle;
property Link: string read GetLink write SetLink;
property DocFile: TLazFPDocFile read FDocFile write SetDocFile;
property StartFPDocFile: TLazFPDocFile read FStartFPDocFile write SetStartFPDocFile;
property StartModuleOwner: TObject read FStartModuleOwner write SetStartModuleOwner;
end;
function ShowFPDocLinkEditorDialog(SrcFilename: string; DocFile: TLazFPDocFile;
out Link, LinkTitle: string): TModalResult;
function ShowFPDocLinkEditorDialog(SrcFilename: string;
StartFPDocFile: TLazFPDocFile; out Link, LinkTitle: string): TModalResult;
implementation
function ShowFPDocLinkEditorDialog(SrcFilename: string; DocFile: TLazFPDocFile;
out Link, LinkTitle: string): TModalResult;
function ShowFPDocLinkEditorDialog(SrcFilename: string;
StartFPDocFile: TLazFPDocFile; out Link, LinkTitle: string): TModalResult;
var
FPDocLinkEditorDlg: TFPDocLinkEditorDlg;
begin
@ -127,7 +131,7 @@ begin
LinkTitle:='';
FPDocLinkEditorDlg:=TFPDocLinkEditorDlg.Create(nil);
try
FPDocLinkEditorDlg.SetLink(SrcFilename,LinkTitle,Link,DocFile);
FPDocLinkEditorDlg.SetLinkAndContext(SrcFilename,LinkTitle,Link,StartFPDocFile);
Result:=FPDocLinkEditorDlg.ShowModal;
if Result=mrOk then begin
Link:=FPDocLinkEditorDlg.Link;
@ -169,7 +173,7 @@ end;
procedure TFPDocLinkEditorDlg.LinkEditChange(Sender: TObject);
begin
Link:=LinkEdit.Text;
end;
procedure TFPDocLinkEditorDlg.LinkEditKeyDown(Sender: TObject; var Key: Word;
@ -185,17 +189,17 @@ var
begin
if FSourceFilename=AValue then exit;
FSourceFilename:=AValue;
fSourceOwner:=nil;
FStartModuleOwner:=nil;
Owners:=PackageEditingInterface.GetPossibleOwnersOfUnit(FSourceFilename,
[piosfIncludeSourceDirectories]);
if Owners=nil then exit;
try
for i:=0 to Owners.Count-1 do begin
if TObject(Owners[i]) is TLazProject then begin
fSourceOwner:=TLazProject(Owners[i]);
FStartModuleOwner:=TLazProject(Owners[i]);
end else if TObject(Owners[i]) is TLazPackage then begin
if fSourceOwner=nil then
fSourceOwner:=TLazPackage(Owners[i]);
if FStartModuleOwner=nil then
FStartModuleOwner:=TLazPackage(Owners[i]);
end;
end;
finally
@ -203,6 +207,12 @@ begin
end;
end;
procedure TFPDocLinkEditorDlg.SetStartModuleOwner(const AValue: TObject);
begin
if FStartModuleOwner=AValue then exit;
FStartModuleOwner:=AValue;
end;
procedure TFPDocLinkEditorDlg.UpdateCompletionBox;
{
ToDo:
@ -240,31 +250,39 @@ begin
end;
end;
procedure TFPDocLinkEditorDlg.AddSiblingUnits(Prefix: string);
procedure TFPDocLinkEditorDlg.AddModuleUnits(ModuleOwner: TObject;
Prefix: string);
var
AProject: TLazProject;
i: Integer;
ProjFile: TLazProjectFile;
APackage: TLazPackage;
Filename: String;
begin
if fSourceOwner=nil then exit;
if fSourceOwner is TLazProject then begin
AProject:=TLazProject(fSourceOwner);
for i:=0 to AProject.FileCount-1 do begin
ProjFile:=AProject.Files[i];
if ProjFile.IsPartOfProject then begin
Filename:=ProjFile.Filename;
if FilenameIsPascalUnit(Filename) then begin
Filename:=ExtractFileNameOnly(Filename);
if (CompareFilenames(Prefix,copy(Filename,1,length(Prefix)))=0) then
fItems.AddProjectFile(ProjFile);
end;
if ModuleOwner=nil then exit;
if ModuleOwner is TLazProject then begin
AProject:=TLazProject(ModuleOwner);
AddProjectUnits(AProject,Prefix);
end else if ModuleOwner is TLazPackage then begin
APackage:=TLazPackage(ModuleOwner);
AddPackageUnits(APackage,Prefix);
end;
end;
procedure TFPDocLinkEditorDlg.AddProjectUnits(AProject: TLazProject;
Prefix: string);
var
i: Integer;
Filename: String;
ProjFile: TLazProjectFile;
begin
for i:=0 to AProject.FileCount-1 do begin
ProjFile:=AProject.Files[i];
if ProjFile.IsPartOfProject then begin
Filename:=ProjFile.Filename;
if FilenameIsPascalUnit(Filename) then begin
Filename:=ExtractFileNameOnly(Filename);
if (CompareFilenames(Prefix,copy(Filename,1,length(Prefix)))=0) then
fItems.AddProjectFile(ProjFile);
end;
end;
end else if fSourceOwner is TLazPackage then begin
APackage:=TLazPackage(fSourceOwner);
AddPackageUnits(APackage,Prefix);
end;
end;
@ -288,20 +306,30 @@ begin
end;
end;
procedure TFPDocLinkEditorDlg.AddIdentifiers(Prefix: string);
procedure TFPDocLinkEditorDlg.AddIdentifiers(ModuleOwner: TObject;
FPDocFile: TLazFPDocFile; Prefix: string);
var
DOMNode: TDOMNode;
ElementName: String;
begin
if fDocFile=nil then exit;
DOMNode:=FDocFile.GetFirstElement;
if FPDocFile=nil then exit;
DOMNode:=FPDocFile.GetFirstElement;
while DOMNode<>nil do begin
if (DOMNode is TDomElement) then begin
ElementName:=TDomElement(DOMNode).GetAttribute('name');
if (System.Pos('.',ElementName)<1)
and (SysUtils.CompareText(Prefix,copy(ElementName,1,length(Prefix)))=0)
then
then begin
if (FPDocFile<>nil) and (FPDocFile<>StartFPDocFile) then begin
// different unit
ElementName:=ExtractFileNameOnly(FPDocFile.Filename)+'.'+ElementName;
end;
if (ModuleOwner<>nil) and (ModuleOwner<>StartModuleOwner) then begin
// different unit
//ElementName:=ExtractFileNameOnly(FPDocFile.Filename)+'.'+ElementName;
end;
FItems.AddIdentifier(ElementName);
end;
end;
DOMNode:=DOMNode.NextSibling;
end;
@ -310,11 +338,18 @@ end;
procedure TFPDocLinkEditorDlg.AddSubIdentifiers(Path: string);
var
p: LongInt;
PrePath: String;
Pkg: TLazPackage;
PkgFile: TPkgFile;
Prefix: String;
HelpResult: TCodeHelpParseResult;
ModuleOwner: TObject;
FPDocFile: TLazFPDocFile;
DOMNode: TDOMNode;
CacheWasUsed: boolean;
DOMElement: TDOMElement;
begin
p:=System.Pos('.',Path);
p:=length(Path);
while (p>0) and (Path[p]<>'.') do dec(p);
Prefix:=copy(Path,p+1,length(Path));
Path:=copy(Path,1,p-1);
if p<1 then begin
// empty : show all packages, all units of current project/package and all identifiers of unit
// #l : show all packages beginning with the letter l
@ -322,41 +357,33 @@ begin
if (Path='') or (Path[1]='#') then
AddPackagesToCompletion(copy(Path,2,length(Path)));
if (Path='') or (Path[1]<>'#') then begin
AddSiblingUnits(Path);
AddIdentifiers(Path);
AddModuleUnits(StartModuleOwner,Path);
AddIdentifiers(StartModuleOwner,StartFPDocFile,Path);
end;
end else begin
// sub identifier
// #lcl.f : show all units of package lcl
// forms.f : show all identifiers of unit forms and all sub identifiers of identifier forms
PrePath:=copy(Path,1,p-1);
Path:=copy(Path,p+1,length(Path));
if PrePath='' then exit;
if PrePath[1]='#' then begin
// package
Pkg:=PackageGraph.FindAPackageWithName(PrePath,nil);
if Pkg=nil then exit;
p:=System.Pos('.',Path);
if p<1 then begin
AddPackageUnits(Pkg,PrePath);
end else begin
// unit
PrePath:=copy(Path,1,p-1);
Path:=copy(Path,p+1,length(Path));
if PrePath='' then exit;
PkgFile:=Pkg.FindUnit(PrePath);
if PkgFile=nil then exit;
end;
HelpResult:=CodeHelpBoss.GetLinkedFPDocNode(StartFPDocFile,nil,Path,
[chofUpdateFromDisk,chofQuiet],ModuleOwner,FPDocFile,DOMNode,CacheWasUsed);
if HelpResult<>chprSuccess then exit;
if DOMNode is TDomElement then begin
DOMElement:=TDomElement(DOMNode);
AddIdentifiers(ModuleOwner,FPDocFile,DOMElement.GetAttribute('name')+'.'+Prefix);
end else if FPDocFile<>nil then begin
AddIdentifiers(ModuleOwner,FPDocFile,Prefix);
end else if ModuleOwner<>nil then begin
if ModuleOwner is TLazPackage then
AddPackageUnits(TLazPackage(ModuleOwner),Prefix)
else if ModuleOwner is TLazProject then
AddProjectUnits(TLazProject(ModuleOwner),Prefix)
end;
end;
end;
procedure TFPDocLinkEditorDlg.SetLink(const ASrcFilename, ATitle, ALink: string;
ADocFile: TLazFPDocFile);
procedure TFPDocLinkEditorDlg.SetLinkAndContext(const ASrcFilename, ATitle,
ALink: string; ADocFile: TLazFPDocFile);
begin
SourceFilename:=ASrcFilename;
DocFile:=ADocFile;
StartFPDocFile:=ADocFile;
fSourceFilename:=ASrcFilename;
LinkTitle:=ATitle;
Link:=ALink;
UpdateCompletionBox;
@ -367,10 +394,11 @@ begin
Result:=TitleEdit.Text;
end;
procedure TFPDocLinkEditorDlg.SetDocFile(const AValue: TLazFPDocFile);
procedure TFPDocLinkEditorDlg.SetStartFPDocFile(const AValue: TLazFPDocFile);
begin
if FDocFile=AValue then exit;
FDocFile:=AValue;
if FStartFPDocFile=AValue then exit;
FStartFPDocFile:=AValue;
FStartModuleOwner:=CodeHelpBoss.FindModuleOwner(FStartFPDocFile);
end;
function TFPDocLinkEditorDlg.GetLink: string;
@ -380,7 +408,9 @@ end;
procedure TFPDocLinkEditorDlg.SetLink(const AValue: string);
begin
if Link=AValue then exit;
LinkEdit.Text:=AValue;
UpdateCompletionBox;
end;
procedure TFPDocLinkEditorDlg.SetLinkTitle(const AValue: string);