View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0038141 | FPC | Utilities | public | 2020-11-27 20:09 | 2020-12-26 21:41 |
Reporter | Andrey Sobol | Assigned To | Michael Van Canneyt | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Platform | i386 | OS | Windows | ||
Fixed in Version | 3.3.1 | ||||
Summary | 0038141: The fpdoc generates docs with a hierarchy problems. | ||||
Description | 1. All classes without a parent are showed as TObject ancestors. For example #rtl.TThread , #rtl.TThreadList, #rtl.TCharacter and many other. 2. All unresolved and undocumented classes also are showed as TObject ancestors ( with mark "?"), may be that is Ok for class discription but the class hierarchy page Looks bad. 3. For the chm files which was produced from rtl.xct - class hierarchy page does not have of links to the #rtl packet classes. The picture is attached. 4. For many classes even of rtl.chm we do not have of links on TObject, For that classes also have been lost methods from TObject on page Class.methods. The picture applied I want to write a patch for that. I am testing first version now. | ||||
Additional Information | related issue https://bugs.freepascal.org/view.php?id=38028 | ||||
Tags | No tags attached. | ||||
Fixed in Revision | 47719 | ||||
FPCOldBugId | |||||
FPCTarget | 3.2.2 | ||||
Attached Files |
|
related to | 0038250 | new | Patches | Redone of lHelp |
|
|
|
I can click through the rom eiostreamerror to tobject by clickling the links in the class() and exception() lines. So tracking is possible. I suspect the tree code doesn't trace very well through the fcl->rtl separation |
|
Yes the xct files have wrong data also. |
|
Well, xct works at least partially since clicking through class() and exception() links works |
|
My guess the problem has to do with dw_html:2425-2435: if (M<>Nil) then EN:=Package.Name+'.'+UTF8Encode(M.Name)+'.'+UTF8Encode(E.Element.Name) else EN:=UTF8Encode(E.Element.Name); J:=AList.IndexOf(EN); If J<>-1 then P:=AList.Objects[J] as TPasElement else P:=Engine.FindElement(EN); PushClassElement; |
|
What is the problem with point 1 ? That is how it is supposed to be ? Similar for point 2. If fpdoc works with incomplete information, There is nothing you can do except attach 'unknown' objects to TObject. (every object descends from TObject) I don't understand what the pictures are supposed to demonstrate ? For point 4, the documentation does not show methods from inherited classes, this is by design. That you cannot click through to some ancestors ? This is possible if the xct files are missing or incomplete. |
|
All the links in the pictures are clickable if you navigate the inheritence by repeatedly clicking on the ancestor in the class(ancestor) declaration verified with 3.2.0 html (on site) and chm |
|
Picture 1. [All the links in the pictures are clickable if you navigate the inheritence by repeatedly clicking on the ancestor in the class(ancestor) declaration] - The links work if you is into rtl.chm, but when you into fcl.chm then the links from class hierarchy page to rtl.chm do not work. - At the same time the links from the class overview page work. - The TObject link does not work always (from fcl.chm to rtl.chm) [For point 4, the documentation does not show methods from inherited classes, this is by design.] - When I have fixed crosslink into cxt files, the method and property pages show all ancestor items. Picture 2. - For all chm which use rtl.xct and other xct. When I'll have the LCL.chm sample then you decide to do so or not. |
|
OK, so the point is that the .xct info is not always correctly processed (or generated) ? That can be. As it happens, I am working on the documentation engine (for other things). I alread noticed that the makefile first generated the fcl and then only the rtl documentation. This is of course wrong and must be corrected, I still need to check why this happens. The method/property pages I never use, so quite possibly I didn't notice they're supposed to have all methods... If you find bugs in the xct handling and have a patch, I will gladly apply it. Thank you for looking into this ! |
|
I suspect it is the findelement in dw_html.inc:2434 (createclasshierarcypage), and think it should be a resolve variant (that also checks between packages). |
|
Hello, Marco - attached patch - attached description - link to test files https://drive.google.com/file/d/1f08ONIZ-lJFadOWG8tk_gLPIwLdEE-WG/view?usp=sharing Andrey. patch_fpdoc_01.patch (48,435 bytes)
Index: packages/chm/src/chmwriter.pas =================================================================== --- packages/chm/src/chmwriter.pas (revision 47408) +++ packages/chm/src/chmwriter.pas (working copy) @@ -1664,14 +1664,15 @@ procedure TChmWriter.CheckFileMakeSearchable(AStream: TStream; AFileEntry: TFileEntryRec); var - TopicEntry: TTopicEntry; - ATitle: String; + TopicEntry: TTopicEntry; + ATitle: String; begin - if Pos('.ht', AFileEntry.Name) > 0 then + // Exclude Full text index for files starting from the dot + if (Pos('.', AFileEntry.Name) <> 1) and (Pos('.ht', AFileEntry.Name) > 0) then begin ATitle := FIndexedFiles.IndexFile(AStream, NextTopicIndex, FSearchTitlesOnly); AddTopic(ATitle,AFileEntry.Path+AFileEntry.Name,-1); - end; + end; end; function TChmWriter.AddTopic(ATitle,AnUrl:AnsiString;code:integer=-1):integer; @@ -1690,7 +1691,7 @@ TopicEntry.URLTableOffset := AddURL(AnUrl, Result); if code=-1 then begin - if ATitle<>'' then + if Trim(ATitle) <> '' then TopicEntry.InContents := 6 else TopicEntry.InContents := 2; @@ -1720,8 +1721,8 @@ ATitle :=StringReplace(Atitle, '&x27;', '', [rfReplaceAll]); // adhoc subsitutions. Replace with real code if exact behaviour is known. -{ Atitle:=StringReplace(atitle, '&x27;', '''', [rfReplaceAll]); - if length(atitle)>0 then +{ Atitle:=StringReplace(Atitle, '&x27;', '''', [rfReplaceAll]); + if length(Trim(Atitle))>0 then atitle[1]:=uppercase(atitle[1])[1];} {$ifdef binindex} writeln('Enter ',ATitle,' ',AnUrl); @@ -1732,11 +1733,11 @@ writeln('found:',result); {$endif} end - else - begin - result:=addtopic(atitle,anurl); - FDictTopicsUrlInd.add(anurl,result); - end; + else if Trim(ATitle) <> '' then + begin + result:=addtopic(ATitle,AnUrl); + FDictTopicsUrlInd.add(AnUrl,result); + end; end; procedure TChmWriter.ScanSitemap(asitemap:TCHMSiteMap); Index: utils/fpdoc/dglobals.pp =================================================================== --- utils/fpdoc/dglobals.pp (revision 47408) +++ utils/fpdoc/dglobals.pp (working copy) @@ -36,9 +36,12 @@ resourcestring // Output strings SDocPackageTitle = 'Reference for package ''%s'''; + SDocPackageMenuTitle = 'Menu for package ''%s'''; + SDocPackageLinkTitle = 'Package'; SDocPrograms = 'Programs'; SDocUnits = 'Units'; SDocUnitTitle = 'Reference for unit ''%s'''; + SDocUnitMenuTitle = 'Menu for unit ''%s'''; SDocInheritanceHierarchy = 'Inheritance Hierarchy'; SDocInterfaceSection = 'Interface section'; SDocImplementationSection = 'Implementation section'; @@ -52,7 +55,9 @@ SDocProceduresAndFunctions = 'Procedures and functions'; SDocVariables = 'Variables'; SDocIdentifierIndex = 'Index'; - SDocPackageClassHierarchy = 'Class hierarchy'; + SDocPackageClassHierarchy = 'Classes hierarchy'; + SDocPackageTObjectHierarchy = 'Hierarchy of TObject classes'; + SDocPackageSimpleHierarchy = 'Hierarchy of simple classes'; SDocModuleIndex = 'Index of all identifiers in unit ''%s'''; SDocPackageIndex = 'Index of all identifiers in package ''%s'''; SDocUnitOverview = 'Overview of unit ''%s'''; @@ -317,9 +322,9 @@ FAlwaysVisible : TStringList; DescrDocs: TObjectList; // List of XML documents DescrDocNames: TStringList; // Names of the XML documents - FRootLinkNode: TLinkNode; - FRootDocNode: TDocNode; - FPackages: TFPList; // List of TFPPackage objects + FRootLinkNode: TLinkNode; // Global tree of TlinkNode from the imported .xct files + FRootDocNode: TDocNode; // Global tree of TDocNode from the .xml documentation files + FPackages: TFPList; // Global list of TPasPackage objects and full tree of sources CurModule: TPasModule; CurPackageDocNode: TDocNode; function ParseUsedUnit(AName, AInputLine,AOSTarget,ACPUTarget: String): TPasModule; virtual; @@ -336,7 +341,9 @@ constructor Create; destructor Destroy; override; procedure SetPackageName(const APackageName: String); + // process the import objects from external .xct file procedure ReadContentFile(const AFilename, ALinkPrefix: String); + // creation of an own .xct output file procedure WriteContentFile(const AFilename: String); function CreateElement(AClass: TPTreeElement; const AName: String; @@ -343,6 +350,7 @@ AParent: TPasElement; AVisibility: TPasMemberVisibility; const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement; override; + function FindInModule(const AName: String ; AModule: TPasModule): TPasElement; function FindElement(const AName: String): TPasElement; override; function FindModule(const AName: String): TPasModule; override; Function HintsToStr(Hints : TPasMemberHints) : String; @@ -658,7 +666,9 @@ procedure TFPDocEngine.ReadContentFile(const AFilename, ALinkPrefix: String); var f: Text; - inheritanceinfo : TStringlist; + inheritanceinfo : TStringlist; // contents list of TPasClass with inheritance info + // like this #PackageName.ModuleName.ClassName + tmpLinkPrefix : string; procedure ReadLinkTree; var @@ -706,8 +716,10 @@ i := ThisSpaces + 1; while s[i] <> ' ' do Inc(i); + if ALinkPrefix <> '' then + tmpLinkPrefix := ExcludeTrailingPathDelimiter(ALinkPrefix)+'/'; NewNode := TLinkNode.Create(Copy(s, ThisSpaces + 1, i - ThisSpaces - 1), - ALinkPrefix + Copy(s, i + 1, Length(s))); + tmpLinkPrefix + Copy(s, i + 1, Length(s))); if pos(' ',newnode.link)>0 then writeln(stderr,'Bad format imported node: name="',newnode.name,'" link="',newnode.link,'"'); if Assigned(PrevSibling) then @@ -719,56 +731,56 @@ end; function ResolvePackageModule(AName:String;out pkg:TPasPackage;out module:TPasModule;createnew:boolean):String; - var - DotPos, DotPos2, i: Integer; - s: String; - HPackage: TPasPackage; + var + DotPos, DotPos2, i: Integer; + s: String; + HPackage: TPasPackage; - begin - pkg:=nil; module:=nil; result:=''; + begin + pkg:=nil; module:=nil; result:=''; - // Find or create package - DotPos := Pos('.', AName); - s := Copy(AName, 1, DotPos - 1); - HPackage := nil; - for i := 0 to FPackages.Count - 1 do - if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then - begin - HPackage := TPasPackage(FPackages[i]); - break; - end; - if not Assigned(HPackage) then + // Find or create package + DotPos := Pos('.', AName); + s := Copy(AName, 1, DotPos - 1); + HPackage := nil; + for i := 0 to FPackages.Count - 1 do + if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then begin - if not CreateNew then - exit; - HPackage := TPasPackage(inherited CreateElement(TPasPackage, s, nil, - '', 0)); - FPackages.Add(HPackage); + HPackage := TPasPackage(FPackages[i]); + break; end; + if not Assigned(HPackage) then + begin + if not CreateNew then + exit; + HPackage := TPasPackage(inherited CreateElement(TPasPackage, s, nil, + '', 0)); + FPackages.Add(HPackage); + end; - // Find or create module - DotPos2 := DotPos; - repeat - Inc(DotPos2); - until AName[DotPos2] = '.'; - s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1); - Module := nil; - for i := 0 to HPackage.Modules.Count - 1 do - if CompareText(TPasModule(HPackage.Modules[i]).Name, s) = 0 then - begin - Module := TPasModule(HPackage.Modules[i]); - break; - end; - if not Assigned(Module) then + // Find or create module + DotPos2 := DotPos; + repeat + Inc(DotPos2); + until AName[DotPos2] = '.'; + s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1); + Module := nil; + for i := 0 to HPackage.Modules.Count - 1 do + if CompareText(TPasModule(HPackage.Modules[i]).Name, s) = 0 then begin - if not CreateNew then - exit; - Module := TPasExternalModule.Create(s, HPackage); - Module.InterfaceSection := TInterfaceSection.Create('', Module); - HPackage.Modules.Add(Module); + Module := TPasModule(HPackage.Modules[i]); + break; end; - pkg:=hpackage; - result:=Copy(AName, DotPos2 + 1, length(AName)-dotpos2); + if not Assigned(Module) then + begin + if not CreateNew then + exit; + Module := TPasExternalModule.Create(s, HPackage); + Module.InterfaceSection := TInterfaceSection.Create('', Module); + HPackage.Modules.Add(Module); + end; + pkg:=hpackage; + result:=Copy(AName, DotPos2 + 1, length(AName)-dotpos2); end; function SearchInList(clslist:TFPList;s:string):TPasElement; @@ -832,9 +844,9 @@ InheritanceInfo.AddObject(Inheritancestr,result); end; - procedure splitalias(var instr:string;out outstr:string); - var i,j:integer; - begin + procedure splitalias(var instr:string;out outstr:string); + var i,j:integer; + begin if length(instr)=0 then exit; instr:=trim(instr); i:=pos('(',instr); @@ -846,10 +858,10 @@ outstr:=copy(instr,i+1,j); delete(instr,i,j+2); end - end; + end; - Function ResolveAndLinkClass(clname:String;IsClass:boolean;cls:TPasClassType):TPasClassType; - begin + Function ResolveAndLinkClass(clname:String;IsClass:boolean;cls:TPasClassType):TPasClassType; + begin result:=TPasClassType(ResolveClassType(clname)); if assigned(result) and not (cls=result) then // save from tobject=implicit tobject begin @@ -868,47 +880,47 @@ else if cls<>result then DoLog('Warning : ancestor class %s of class %s could not be resolved',[clname,cls.name]); -end; + end; -function CreateAliasType (alname,clname : string;parentclass:TPasClassType; out cl2 :TPasClassType):TPasAliasType; -// create alias clname = alname -var - pkg : TPasPackage; - module : TPasModule; - s : string; -begin - Result:=nil; - s:=ResolvePackageModule(Alname,pkg,module,True); - if not assigned(module) then - exit; - cl2:=TPasClassType(ResolveClassType(alname)); - if assigned( cl2) and not (parentclass=cl2) then - begin - result:=ResolveAliasType(clname); - if assigned(result) then + function CreateAliasType (alname,clname : string;parentclass:TPasClassType; out cl2 :TPasClassType):TPasAliasType; + // create alias clname = alname + var + pkg : TPasPackage; + module : TPasModule; + s : string; + begin + Result:=nil; + s:=ResolvePackageModule(Alname,pkg,module,True); + if not assigned(module) then + exit; + cl2:=TPasClassType(ResolveClassType(alname)); + if assigned( cl2) and not (parentclass=cl2) then begin -// writeln('found alias ',clname,' (',s,') ',result.classname); + result:=ResolveAliasType(clname); + if assigned(result) then + begin + // writeln('found alias ',clname,' (',s,') ',result.classname); + end + else + begin + // writeln('new alias ',clname,' (',s,') '); + cl2.addref; + Result := TPasAliasType(CreateElement(TPasAliasType,s,module.interfacesection,vispublic,'',0)); + module.interfacesection.Declarations.Add(Result); + TPasAliasType(Result).DestType := cl2; + end end - else - begin -// writeln('new alias ',clname,' (',s,') '); - cl2.addref; - Result := TPasAliasType(CreateElement(TPasAliasType,s,module.interfacesection,vispublic,'',0)); - module.interfacesection.Declarations.Add(Result); - TPasAliasType(Result).DestType := cl2; - end - end -end; + end; - procedure ProcessInheritanceStrings(inhInfo:TStringList); + procedure ProcessInheritanceStrings(inhInfo:TStringList); - var i,j : integer; - cls : TPasClassType; + var i,j : integer; + cls : TPasClassType; cls2: TPasClassType; clname, alname : string; inhclass : TStringList; - begin + begin inhclass:=TStringList.Create; inhclass.delimiter:=','; if InhInfo.Count>0 then @@ -920,12 +932,12 @@ for j:= 0 to inhclass.count-1 do begin - //writeln('processing',inhclass[j]); + // writeln('processing',inhclass[j]); clname:=inhclass[j]; - splitalias(clname,alname); + splitalias(clname,alname); if alname<>'' then // the class//interface we refered to is an alias begin - // writeln('Found alias pair ',clname,' = ',alname); + // writeln('Found alias pair ',clname,' = ',alname); if not assigned(CreateAliasType(alname,clname,cls,cls2)) then DoLog('Warning: creating alias %s for %s failed!',[alname,clname]); end @@ -934,7 +946,7 @@ end; end; inhclass.free; - end; + end; var s, Name: String; @@ -991,10 +1003,10 @@ CurClass.Members.Add(Member); end; end; - ProcessInheritanceStrings(Inheritanceinfo); + ProcessInheritanceStrings(Inheritanceinfo); finally - inheritanceinfo.Free; - end; + inheritanceinfo.Free; + end; end; var @@ -1042,11 +1054,13 @@ end; end; - function CheckImplicitInterfaceLink(const s : String):String; + function CheckImplicitLink(const s : String):String; begin - if uppercase(s)='IUNKNOWN' then + if uppercase(s)='IUNKNOWN' then Result:='#rtl.System.IUnknown' - else + else if uppercase(s)='TOBJECT' then + Result:='#rtl.System.TObject' + else Result:=s; end; var @@ -1089,11 +1103,11 @@ for j := 0 to Module.InterfaceSection.Classes.Count - 1 do begin ClassDecl := TPasClassType(Module.InterfaceSection.Classes[j]); - Write(ContentFile, CheckImplicitInterfaceLink(ClassDecl.PathName), ' '); - if Assigned(ClassDecl.AncestorType) then + Write(ContentFile, CheckImplicitLink(ClassDecl.PathName), ' '); + if Assigned(ClassDecl.AncestorType) then // and (ClassDecl.ObjKind <> okClass) then begin // simple aliases to class types are coded as "alias(classtype)" - Write(ContentFile, CheckImplicitInterfaceLink(ClassDecl.AncestorType.PathName)); + Write(ContentFile, CheckImplicitLink(ClassDecl.AncestorType.PathName)); if ClassDecl.AncestorType is TPasAliasType then begin alias:= TPasAliasType(ClassDecl.AncestorType); @@ -1102,19 +1116,20 @@ end; end else if ClassDecl.ObjKind = okClass then - Write(ContentFile, '#rtl.System.TObject') + //Write(ContentFile, '@NO_ANCESTOR_CLASS') else if ClassDecl.ObjKind = okInterface then - Write(ContentFile, '#rtl.System.IUnknown'); + //Write(ContentFile, '@NO_ANCESTOR_INTERFACE') + ; if ClassDecl.Interfaces.Count>0 then begin for k:=0 to ClassDecl.Interfaces.count-1 do begin - write(contentfile,',',CheckImplicitInterfaceLink(TPasClassType(ClassDecl.Interfaces[k]).PathName)); + write(contentfile,',',CheckImplicitLink(TPasClassType(ClassDecl.Interfaces[k]).PathName)); if TPasElement(ClassDecl.Interfaces[k]) is TPasAliasType then begin alias:= TPasAliasType(ClassDecl.Interfaces[k]); if assigned(alias.desttype) and (alias.desttype is TPasClassType) then - write(ContentFile,'(',CheckImplicitInterfaceLink(alias.desttype.PathName),')'); + write(ContentFile,'(',CheckImplicitLink(alias.desttype.PathName),')'); end; end; end; @@ -1163,34 +1178,34 @@ Result.SourceLinenumber := ASourceLinenumber; end; -function TFPDocEngine.FindElement(const AName: String): TPasElement; +function TFPDocEngine.FindInModule ( const AName: String; AModule: TPasModule + ) : TPasElement; +var + l: TFPList; + i: Integer; - function FindInModule(AModule: TPasModule; const LocalName: String): TPasElement; - - var - l: TFPList; - i: Integer; - - begin - If assigned(AModule.InterfaceSection) and - Assigned(AModule.InterfaceSection.Declarations) then +begin + If Assigned(AModule) and Assigned(AModule.InterfaceSection) and + Assigned(AModule.InterfaceSection.Declarations) then + begin + l:=AModule.InterfaceSection.Declarations; + for i := 0 to l.Count - 1 do begin - l:=AModule.InterfaceSection.Declarations; - for i := 0 to l.Count - 1 do - begin - Result := TPasElement(l[i]); - if CompareText(Result.Name, LocalName) = 0 then - exit; - end; - end; - Result := nil; - end; + Result := TPasElement(l[i]); + if CompareText(Result.Name, AName) = 0 then + exit; + end; + end; + Result := nil; +end; +function TFPDocEngine.FindElement(const AName: String): TPasElement; + var i: Integer; Module: TPasElement; begin - Result := FindInModule(CurModule, AName); + Result := FindInModule( AName, CurModule ); if not Assigned(Result) and assigned (CurModule.InterfaceSection) then for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do begin @@ -1197,7 +1212,7 @@ Module := TPasElement(CurModule.InterfaceSection.UsesList[i]); if Module.ClassType.InheritsFrom(TPasModule) then begin - Result := FindInModule(TPasModule(Module), AName); + Result := FindInModule(AName, TPasModule(Module)); if Assigned(Result) then exit; end; Index: utils/fpdoc/dw_html.pp =================================================================== --- utils/fpdoc/dw_html.pp (revision 47408) +++ utils/fpdoc/dw_html.pp (working copy) @@ -231,7 +231,8 @@ procedure CreatePackagePageBody; procedure CreatePackageIndex; procedure CreatePackageClassHierarchy; - procedure CreateClassHierarchyPage(AList: TStringList; AddUnit : Boolean); + procedure CreateClassHierarchyPage(AList:TStringList ; ClassTree :TDOMElement; + ShowRoot : Boolean); procedure AddModuleIdentifiers(AModule : TPasModule; L : TStrings); Procedure CreateTopicPageBody(AElement : TTopicElement); procedure CreateModulePageBody(AModule: TPasModule; ASubpageIndex: Integer); @@ -245,6 +246,7 @@ procedure AddElementsFromList(L: TStrings; List: TFPList; UsePathName : Boolean = False); procedure AppendTypeDecl(AType: TPasType; TableEl, CodeEl: TDomElement); public + // Creating all module hierarchy classes is here !!!! constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override; destructor Destroy; override; @@ -252,7 +254,7 @@ function CreateHTMLPage(AElement: TPasElement; ASubpageIndex: Integer): TXMLDocument; function CreateXHTMLPage(AElement: TPasElement; ASubpageIndex: Integer): TXMLDocument; - // For producing complete package documentation + // Start producing html complete package documentation procedure WriteHTMLPages; virtual; procedure WriteXHTMLPages; function ModuleForElement(AnElement:TPasElement):TPasModule; @@ -282,6 +284,7 @@ implementation uses SysUtils, XMLRead, HTMWrite, sh_pas, fpdocclasstree, +// XMLWrite, chmsitemap; {$i css.inc} @@ -324,13 +327,20 @@ var n,s: String; i: Integer; - + excl: Boolean; //search begin Result:=''; + excl := False; if AElement.ClassType = TPasPackage then - Result := 'index' + begin + Result := 'index'; + excl := True; + end else if AElement.ClassType = TPasModule then - Result := LowerCase(AElement.Name) + PathDelim + 'index' + begin + Result := LowerCase(AElement.Name) + PathDelim + 'index'; + excl := True; + end else begin if AElement is TPasOperator then @@ -359,8 +369,12 @@ if (N<>'') and (N[1]=':') then Delete(N,1,1); Result:=Result + '-'+ s + '-' + N; - end else + end + else + begin Result := LowerCase(AElement.PathName); + excl := (ASubindex > 0); + end; // searching for TPasModule - it is on the 2nd level if Assigned(AElement.Parent) then while Assigned(AElement.Parent.Parent) do @@ -373,6 +387,14 @@ Inc(i); if (i <= Length(Result)) and (i > 0) then Result[i] := PathDelim; + if excl or (Length(Result)=0) then + begin + // exclude the from full text search index + s:= '.'+ExtractFileName(Result + '.'); + n:= ExtractFileDir(Result); + Result := n + DirectorySeparator + s; + Result := Copy(Result, 1, Length(Result)-1); + end; end; if ASubindex > 0 then @@ -769,6 +791,7 @@ Filename := Engine.Output + Allocator.GetFilename(Element, SubpageIndex); try CreatePath(Filename); + //writeln('Element: ',Element.PathName, ' FileName: ', Filename); WriteHTMLFile(PageDoc, Filename); except on E: Exception do @@ -1532,7 +1555,8 @@ end; end; -Procedure THTMLWriter.AppendShortDescr(AContext: TPasElement; Parent: TDOMNode; DocNode : TDocNode); +procedure THTMLWriter.AppendShortDescr ( AContext: TPasElement; + Parent: TDOMNode; DocNode: TDocNode ) ; Var N : TDocNode; @@ -2081,7 +2105,7 @@ procedure THTMLWriter.AppendMenuBar(ASubpageIndex: Integer); var - TableEl, TREl, ParaEl, TitleEl: TDOMElement; + TableEl, TREl, TRE2, ParaEl, TitleEl: TDOMElement; procedure AddLink(ALinkSubpageIndex: Integer; const AName: String); begin @@ -2118,9 +2142,34 @@ TableEl['border'] := '0'; TableEl['width'] := '100%'; TableEl['class'] := 'bar'; + // Title Row TREl := CreateTR(TableEl); - ParaEl := CreateEl(CreateTD(TREl), 'b'); + // Menu title + ParaEl := CreateTD(TREl); + ParaEl['align'] := 'left'; + TitleEl := CreateEl(ParaEl, 'span'); + TitleEl['class'] := 'bartitle'; + if Assigned(Module) then + AppendText(TitleEl, Format(SDocUnitMenuTitle, [Module.Name])) + else + AppendText(TitleEl, Format(SDocPackageMenuTitle, [Package.Name])); + // Package link title + ParaEl := CreateTD(TREl); + ParaEl['align'] := 'right'; + TitleEl := CreateEl(ParaEl, 'span'); + TitleEl['class'] := 'bartitle'; + if Assigned(Module) and Assigned(Package) then // Displays a Package page + begin + AppendText(TitleEl, SDocPackageLinkTitle); + end; + + // Links Row + TRE2 := CreateTR(TableEl); + ParaEl := CreateTD(TRE2); + ParaEl['align'] := 'left'; + ParaEl := CreateEl(ParaEl, 'b'); + if Assigned(Module) then begin AddLink(0, SDocOverview); @@ -2140,7 +2189,13 @@ end else begin + // Overview + AppendText(ParaEl, '['); + AppendHyperlink(ParaEl, Package).TextContent:= UTF8Decode(SDocOverview); + AppendText(ParaEl, ']'); + //Index AddPackageLink(IndexSubIndex, SDocIdentifierIndex); + // Class TObject tree AddPackageLink(ClassHierarchySubIndex, SDocPackageClassHierarchy); end; @@ -2152,18 +2207,17 @@ if FUseMenuBrackets then AppendText(ParaEl, ']'); end; - ParaEl := CreateTD(TREl); + + ParaEl := CreateTD(TRE2); ParaEl['align'] := 'right'; - TitleEl := CreateEl(ParaEl, 'span'); - TitleEl['class'] := 'bartitle'; - if Assigned(Module) then - AppendText(TitleEl, Format(SDocUnitTitle, [Module.Name])); - if Assigned(Package) then + ParaEl := CreateEl(ParaEl, 'b'); + if Assigned(Module) and Assigned(Package) then // Displays a Package page begin - AppendText(TitleEl, ' ('); - AppendHyperlink(TitleEl, Package); - AppendText(TitleEl, ')'); + AppendText(ParaEl, '['); + AppendHyperlink(ParaEl, Package); + AppendText(ParaEl, ']'); end; + end; procedure THTMLWriter.AppendSourceRef(AElement: TPasElement); @@ -2172,7 +2226,8 @@ [ExtractFileName(AElement.SourceFilename), AElement.SourceLinenumber])); end; -Procedure THTMLWriter.AppendSeeAlsoSection(AElement : TPasElement;DocNode : TDocNode); +procedure THTMLWriter.AppendSeeAlsoSection ( AElement: TPasElement; + DocNode: TDocNode ) ; var Node: TDOMNode; @@ -2246,7 +2301,8 @@ end; // While end; -Procedure THTMLWriter.AppendExampleSection(AElement : TPasElement;DocNode : TDocNode); +procedure THTMLWriter.AppendExampleSection ( AElement: TPasElement; + DocNode: TDocNode ) ; var Node: TDOMNode; @@ -2367,7 +2423,8 @@ end; end; -procedure THTMLWriter.CreateClassHierarchyPage(AList : TStringList; AddUnit : Boolean); +procedure THTMLWriter.CreateClassHierarchyPage ( AList: TStringList; + ClassTree: TDOMElement; ShowRoot: Boolean ) ; Procedure PushClassElement; @@ -2395,7 +2452,7 @@ PushOutputNode(h); end; - Procedure AppendClass(E : TDomElement); + Procedure AppendClass(E : TDomElement; Level: Integer); Var N : TDomNode; @@ -2405,27 +2462,34 @@ I,J : Integer; begin + if not Assigned(E) then exit; + //WriteLn('>> AppendClass NodeName = ',E.NodeName); EN:=Package.Name+'.'+UTF8Encode(E['unit'])+'.'+UTF8Encode(E.NodeName); J:=AList.IndexOf(EN); If J<>-1 then P:=AList.Objects[J] as TPasElement else - P:=Engine.FindElement(EN); - PushClassElement; + P:=Engine.FindInModule(UTF8Encode(E.NodeName), + Engine.FindModule(UTF8Encode(E['unit']))); try - if (P<>Nil) then + inc(Level); + if Level > 0 then begin - AppendHyperLink(CurOutputNode,P); - PM:=ModuleForElement(P); - if (PM<>Nil) then - begin - AppendText(CurOutputNode,' ('); - AppendHyperLink(CurOutputNode,PM); - AppendText(CurOutputNode,')'); - end - end - else - AppendText(CurOutputNode,E.Nodename); + PushClassElement; + if (P<>Nil) then + begin + AppendHyperLink(CurOutputNode,P); + PM:=ModuleForElement(P); + if (PM<>Nil) then + begin + AppendText(CurOutputNode,' ('); + AppendHyperLink(CurOutputNode,PM); + AppendText(CurOutputNode,')'); + end + end + else + AppendText(CurOutputNode,E.Nodename); + end; LL:=TStringList.Create; try N:=E.FirstChild; @@ -2436,48 +2500,39 @@ N:=N.NextSibling; end; if (LL.Count>0) then - begin + begin LL.Sorted:=true; PushClassList; try For I:=0 to LL.Count-1 do - AppendClass(LL.Objects[i] as TDomElement); + AppendClass(LL.Objects[i] as TDomElement, Level); finally - PopOutputNode; + PopOutputNode; // classlist end; - end; + end; finally LL.Free; end; Finally - PopOutputNode; + if Level > 0 then PopOutputNode; // classelement + Dec(Level); end; + //WriteLn('<< AppendClass NodeName = ',E.NodeName); end; - -Var - B : TClassTreeBuilder; - E : TDomElement; +var + lev: Integer; begin - PushOutputNode(BodyElement); + lev:= -1; + if ShowRoot then lev:= 0; try - B:=TClassTreeBuilder.Create(Package,okClass); + if lev = 0 then PushClassList; try - B.BuildTree(AList); - // Classes - // WriteXMLFile(B.ClassTree,'tree.xml'); - // Dummy TObject - E:=B.ClassTree.DocumentElement; - PushClassList; - try - AppendClass(E); - finally - PopOutputNode; - end; + AppendClass(ClassTree, lev); finally - B.Free; + //PopOutputNode; end; finally - PopOutputNode; + if lev = 0 then PopOutputNode; //classlist end; end; @@ -2496,6 +2551,8 @@ M : TPasModule; S : String; SE : THTMLElement; + B : TClassTreeBuilder; + E : TDomElement; begin SE := Doc.CreateElement('script'); @@ -2514,8 +2571,30 @@ S:=Package.Name; If Length(S)>0 then Delete(S,1,1); - AppendTitle(UTF8Decode(Format(SDocPackageClassHierarchy, [S]))); - CreateClassHierarchyPage(L,True); + try + B:=TClassTreeBuilder.Create(Package,okClass); + try + PushOutputNode(BodyElement); + B.BuildTree(L); + // Classes + //WriteXMLFile(B.ClassTree,'tree.xml'); + // Dummy TObject + //AppendTitle(UTF8Decode(Format(SDocPackageClassHierarchy, [S]))); + AppendTitle(UTF8Decode(SDocPackageTObjectHierarchy)); + E:=B.ClassTreeTObject; + // TObject Tree + CreateClassHierarchyPage(L,E, True); + // Simple Tree + //AppendTitle(UTF8Decode(Format(SDocPackageSimpleHierarchy, [S]))); + AppendTitle(UTF8Decode(SDocPackageSimpleHierarchy)); + E:=B.ClassTreeSimple; + CreateClassHierarchyPage(L,E, False); + finally + PopOutputNode; + end; + finally + B.Free; + end; Finally L.Free; end; @@ -2664,7 +2743,8 @@ end; end; -Procedure THTMLWriter.AddElementsFromList(L : TStrings; List : TFPList; UsePathName : Boolean = False); +procedure THTMLWriter.AddElementsFromList ( L: TStrings; List: TFPList; + UsePathName: Boolean ) ; Var I : Integer; @@ -2774,7 +2854,8 @@ end; end; -Procedure THTMLWriter.CreateTopicLinks(Node : TDocNode; PasElement : TPasElement); +procedure THTMLWriter.CreateTopicLinks ( Node: TDocNode; + PasElement: TPasElement ) ; var DocNode: TDocNode; @@ -3342,10 +3423,12 @@ i: Integer; ThisInterface, ThisClass: TPasClassType; - HaveSeenTObject: Boolean; + SeenFullTree: Boolean; LName : String; + LastClassName: String; ThisNode : TPasUnresolvedTypeRef; begin + //WriteLn('@ClassPageBody.CreateMainPage Class=', AClass.Name); AppendMenuBar(-1); AppendTitle(UTF8Decode(AClass.Name),AClass.Hints); @@ -3389,14 +3472,12 @@ end; CreateMemberDeclarations(AClass, AClass.Members,TableEl, not AClass.IsShortDefinition); - - AppendText(CreateH2(BodyElement), UTF8Decode(SDocInheritance)); TableEl := CreateTable(BodyElement); - HaveSeenTObject := AClass.ObjKind <> okClass; + SeenFullTree := AClass.ObjKind <> okClass; // we try to track classes. But imported classes // are TLinkNode's not the TPasClassType generated by the parser. - ThisClass := AClass; ThisNode := Nil; + ThisClass := AClass; ThisNode := Nil; LastClassName := ''; while True do begin TREl := CreateTR(TableEl); @@ -3407,10 +3488,12 @@ LName:=ThisClass.Name Else LName:=ThisNode.Name; + // add link to class hierarchy if Assigned(ThisClass) Then AppendHyperlink(CodeEl, ThisClass) else AppendHyperlink(CodeEl, ThisNode); + // link to class interfaces if Assigned(ThisClass) and (ThisClass.Interfaces.count>0) then begin for i:=0 to ThisClass.interfaces.count-1 do @@ -3420,48 +3503,73 @@ AppendHyperlink(CodeEl, ThisInterface); end; end; - AppendShortDescrCell(TREl, ThisClass); - if HaveSeenTObject or (CompareText(LName, 'TObject') = 0) then - HaveSeenTObject := True - else - begin - TDEl := CreateTD(CreateTR(TableEl)); - TDEl['align'] := 'center'; - AppendText(TDEl, '|'); - end; + // short class description + if Assigned(ThisClass) then + AppendShortDescrCell(TREl, ThisClass); - if Assigned(ThisClass.AncestorType) then - begin - if ThisClass.AncestorType.InheritsFrom(TPasClassType) then - ThisClass := TPasClassType(ThisClass.AncestorType) - else + if Assigned(ThisClass) then begin - if thisclass.ancestortype is TPasUnresolvedTypeRef then - thisnode:=TPasUnresolvedTypeRef(ThisClass.ancestortype); - TDEl := CreateTD(CreateTR(TableEl)); - TDEl['align'] := 'center'; - AppendText(CreateCode(CreatePara(TDEl)), UTF8Decode(ThisClass.AncestorType.Name)); - if CompareText(ThisClass.AncestorType.Name, 'TObject') = 0 then - HaveSeenTObject := True - else + if Assigned(ThisClass.AncestorType) then begin TDEl := CreateTD(CreateTR(TableEl)); TDEl['align'] := 'center'; - AppendText(TDEl, '?'); + AppendText(TDEl, '|'); + if ThisClass.AncestorType.InheritsFrom(TPasClassType) then + begin + ThisClass := TPasClassType(ThisClass.AncestorType); + ThisNode := nil; + end + else if ThisClass.ancestortype is TPasUnresolvedTypeRef then + begin + ThisNode:=TPasUnresolvedTypeRef(ThisClass.ancestortype); + ThisClass := nil; + end + else if ThisClass.ancestortype is TPasAliasType then + begin + LastClassName := TPasAliasType(ThisClass.AncestorType).ElementTypeName; + SeenFullTree := false; + break; // end class tree + end + else + begin + LastClassName := 'UNRESOLVED CLASS'; + SeenFullTree := false; + break; // end class tree + end; + end + else + begin + SeenFullTree := true; + break; // end class tree end; - break; end - end else - break; + else if Assigned(ThisNode) then + begin + if Assigned(ThisNode.Parent) then + begin + ThisNode := TPasUnresolvedTypeRef(ThisNode.Parent); + ThisClass := nil; + end + else + begin + SeenFullTree := Pos(UpperCase(ThisNode.Name), 'TOBJECT') = 1; // last ClassName was TObject + break; // end class node + end; + end; end; - - if not HaveSeenTObject then - begin + if not SeenFullTree then + begin // we suggest that last parent is TObject TDEl := CreateTD(CreateTR(TableEl)); TDEl['align'] := 'center'; - AppendText(CreateCode(CreatePara(TDEl)), 'TObject'); + if Length(LastClassName)=0 then + AppendText(TDEl, '?'); + TDEl := CreateTD(CreateTR(TableEl)); + TDEl['align'] := 'center'; + if Length(LastClassName)>0 then + AppendText(CreateCode(CreatePara(TDEl)),LastClassName) + else + AppendText(CreateCode(CreatePara(TDEl)), 'TObject'); end; - FinishElementPage(AClass); end; @@ -3838,7 +3946,7 @@ FinishElementPage(AProc); end; -Function THTMLWriter.InterPretOption(Const Cmd,Arg : String) : boolean; +function THTMLWriter.InterPretOption ( const Cmd, Arg: String ) : boolean; begin Result:=True; @@ -3907,7 +4015,7 @@ end; end; -Class Function THTMLWriter.FileNameExtension : String; +class function THTMLWriter.FileNameExtension: String; begin result:=''; end; Index: utils/fpdoc/dw_txt.pp =================================================================== --- utils/fpdoc/dw_txt.pp (revision 47408) +++ utils/fpdoc/dw_txt.pp (working copy) @@ -158,18 +158,19 @@ Var I,L : Integer; - + SP: set of char; begin Result:=0; + SP := [#10,#13,' ',#9]; I:=P; L:=Length(S); - While (I>0) and (I<=L) and not (S[i] in [#10,#13,' ',#9]) do - Dec(i); + While (I>0) and (I<=L) and not (S[i] in SP) do + Dec(I); If (I=0) then begin - I:=P; - While (I<=L) and not (S[i] in [#10,#13,' ',#9]) do - Inc(i); + Inc(I); + While (I<=L) and not (S[I] in SP) do + Inc(I); end; Result:=I; end; @@ -186,7 +187,7 @@ exit; N:=S; Repeat - If ((FCurrentPos+Length(N))>LineWidth) then + If ((FCurrentPos+Length(N)+1)>LineWidth) then begin L:=FindSpace(N,LineWidth-FCurrentPos+1); inherited Write(Copy(N,1,L-1)); @@ -195,8 +196,8 @@ end else begin - L:=Length(N)+1; - inherited Write(Copy(N,1,L-1)); + L:=Length(N); + inherited Write(Copy(N,1,L)); Inc(FCurrentPos,L); If FCheckEOL then If (L>=LEOL) then Index: utils/fpdoc/fpdoc.pp =================================================================== --- utils/fpdoc/fpdoc.pp (revision 47408) +++ utils/fpdoc/fpdoc.pp (working copy) @@ -428,6 +428,8 @@ end; begin + //AssignFile(Output, 'fpdoc.log'); + //rewrite(Output); With TFPDocApplication.Create(Nil) do try Run; Index: utils/fpdoc/fpdocclasstree.pp =================================================================== --- utils/fpdoc/fpdocclasstree.pp (revision 47408) +++ utils/fpdoc/fpdocclasstree.pp (working copy) @@ -11,7 +11,9 @@ TClassTreeBuilder = Class Private FClassTree : TXMLDocument; - FTreeStart : TDomElement; + FXmlRoot: TDomElement; + FClassTObjectRoot : TDomElement; // for TObject or IInterface childs + FClassSimpleRoot : TDomElement; // for Classes without parent or undocumented parents FObjectKind : TPasObjKind; FPackage: TPasPackage; FParentObject : TPasClassType; @@ -24,6 +26,8 @@ Destructor Destroy; override; Function BuildTree(AObjects : TStringList) : Integer; Property ClassTree : TXMLDocument Read FClassTree; + Property ClassTreeTObject: TDomElement read FClassTObjectRoot; + Property ClassTreeSimple: TDomElement read FClassSimpleRoot; end; implementation @@ -30,20 +34,31 @@ constructor TClassTreeBuilder.Create(APackage : TPasPackage; AObjectKind: TPasObjKind); - begin FCLassTree:=TXMLDocument.Create; FPackage:=APAckage; FObjectKind:=AObjectKind; Case FObjectkind of - okObject : FParentObject:=TPasClassType.Create('System.TObject',FPackage); - okClass : FParentObject:=TPasClassType.Create('System.TObject',FPackage); - okInterface : FParentObject:=TPasClassType.Create('System.IInterface',FPackage); + okObject, okClass: + begin + FParentObject:=TPasClassType.Create('System.TObject',FPackage); + FClassTObjectRoot:=FClassTree.CreateElement('TObject'); + FClassTObjectRoot['unit']:='System'; + end; + okInterface : + begin + FParentObject:=TPasClassType.Create('System.IInterface',FPackage); + FClassTObjectRoot:=FClassTree.CreateElement('IInterface'); + FClassTObjectRoot['unit']:='System'; + end; end; + FXmlRoot:=FClassTree.CreateElement('ClassHierarchy'); + ClassTree.AppendChild(FXmlRoot); FParentObject.ObjKind:=FObjectKind; - FTreeStart:=FClassTree.CreateElement('TObject'); - FTreeStart['unit']:='System'; - ClassTree.AppendChild(FTreeStart); + FXmlRoot.AppendChild(FClassTObjectRoot); + //FClassSimpleRoot := FXmlRoot; + FClassSimpleRoot:=FClassTree.CreateElement('SimpleClasses'); + FXmlRoot.AppendChild(FClassSimpleRoot); end; destructor TClassTreeBuilder.Destroy; @@ -65,6 +80,7 @@ begin PC:=AObjects.Objects[i] as TPasClassType; If (PC.ObjKind=FObjectKind) and Not PC.IsForward then + // Each our Pascal class inserted into tree AddToClassTree(PC,Result); end; end; @@ -72,7 +88,7 @@ Function TClassTreeBuilder.NodeMatch(N : TDomNode; AElement : TPasElement; NoPath : Boolean) : Boolean; Var - PN,S,EN : String; + PN,S,EN, EP : String; begin EN:=AELement.Name; @@ -86,13 +102,24 @@ end else begin - IF Assigned(Aelement.GetModule) then - PN:=Aelement.GetModule.PackageName + if Assigned(AElement.GetModule) then + PN:=AElement.GetModule.PackageName else PN:=FPackage.Name; - S:=PN+'.'+UTF8Encode(TDomElement(N)['unit'])+'.'+S; - Result:=(CompareText(S,AElement.PathName)=0); + if PN <> '' then + begin + S:=PN+'.'+UTF8Encode(TDomElement(N)['unit'])+'.'+S; + EP:=AElement.PathName; + end + else + begin + S:=UTF8Encode(TDomElement(N)['unit'])+'.'+S; + EP:=AElement.PathName; + if EP[1] = '#' then + EP := Copy(EP, Pos('.', EP)+1, Length(EP)); end; + Result:=(CompareText(S,EP)=0); + end; end; end; @@ -102,7 +129,7 @@ N : TDomNode; begin -// Writeln('Enter TClassTreeBuilderLookForElement'); +// Write('>> TClassTreeBuilder.LookForElement'); Result:=PE; While (Result<>Nil) and Not NodeMatch(Result,AElement,NoPath) do Result:=Result.NextSibling; @@ -119,7 +146,7 @@ N:=N.NextSibling; end; end; -// Writeln('Exit TClassTreeBuilderLookForElement'); +// Write('<< TClassTreeBuilder.LookForElement'); end; Function TClassTreeBuilder.AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement; @@ -127,62 +154,67 @@ // I initialized them to nil to at least make failures deterministic. Var PC : TPasClassType; - PE : TDomElement; + PE : TDomElement; // Parent Node elemet M : TPasModule; N : TDomNode; begin -// Writeln('Enter TClassTreeBuilder.AddToClassTree'); + //Write('>> TClassTreeBuilder.AddToClassTree'); //if Assigned(AElement) then - //Writeln('Addtoclasstree : ',aElement.Name); + // WriteLn(' Addtoclasstree=', aElement.Name, ' cnt=', IntToStr(ACount)) + //else + // WriteLn(''); Result:=Nil; M:=Nil; N:=Nil;PE:=NIL;PC:=Nil; If (AElement=Nil) then - begin - Result:=FTreeStart; - Exit; - end + Exit else If (AElement is TPasUnresolvedTypeRef) then - begin - N:=LookForElement(FTreeStart,AElement,True); + begin // Search into NodeTree + N:=LookForElement(FClassTObjectRoot,AElement,True); If (N=Nil) then - PE:=FTreeStart; + PE:=FClassSimpleRoot; end else If (AElement is TPasClassType) then begin - if (AElement=FParentObject) then - Result:=FTreeStart + if (AElement=FParentObject) then // Input Object is RootTObject + Result:=FClassTObjectRoot else - begin - PC:=AElement as TPasClassType; - PE:=AddToClassTree(PC.AncestorType,ACount); - if PE=Nil then - PE:=FTreeStart; - N:=LookForElement(PE,PC,False); + begin // Need Add ancestor + PC:=AElement as TPasClassType; + PE:=AddToClassTree(PC.AncestorType,ACount); // try add Ancestor + if PE=nil then + begin + N:=LookForElement(FClassTObjectRoot,PC,False); // Seek into root TObject classes + if N=Nil then + N:=LookForElement(FClassSimpleRoot,PC,False); // Seek into free classes + end; end - end; - If (N<>Nil) then - begin + end; // if + If (N <> Nil) then // Class node was found Result:=N as TDomElement - end - else if AElement.Name<>'' then + else if AElement.Name <> '' then begin // N=NIL, PE might be nil. - Inc(ACount); - Result:=FClassTree.CreateElement(UTF8Decode(AElement.Name)); - If Not (AElement is TPasUnresolvedTypeRef) then - begin + if Not (AElement is TPasUnresolvedTypeRef) then + begin + Inc(ACount); + if PE=Nil then + PE:=FClassSimpleRoot; + end; + Result:=FClassTree.CreateElement(UTF8Decode(AElement.Name)); // Create new NodeElement M:=AElement.GetModule; - if Assigned(M) then - Result['unit']:=UTF8Decode(M.Name); - end; - if PE=Nil then - begin - PE:=FTreeStart - end; - // if not assigned, probably needs to be assigned to something else. - if assigned(PE) then - PE.AppendChild(Result); + if Assigned(Result) then + begin + if Assigned(M) then + Result['unit']:=UTF8Decode(M.Name); // module name + if Assigned(PE)then + PE.AppendChild(Result); + end; end; + //Writeln('<< TClassTreeBuilder.AddToClassTree'); + //if Assigned(AElement) then + // WriteLn(' Addtoclasstree=', aElement.Name, ' cnt=', IntToStr(ACount)) + //else + // WriteLn(''); end; end. Index: utils/fpdoc/mkfpdoc.pp =================================================================== --- utils/fpdoc/mkfpdoc.pp (revision 47408) +++ utils/fpdoc/mkfpdoc.pp (working copy) @@ -42,6 +42,8 @@ procedure SetVerbose(AValue: Boolean); virtual; Procedure DoLog(Const Msg : String); procedure DoLog(Const Fmt : String; Args : Array of Const); + Procedure DoLogSender(Sender : TObject; Const Msg : String); + // Create documetation by specified Writer class procedure CreateOutput(APackage: TFPDocPackage; Engine: TFPDocEngine); virtual; Public Constructor Create(AOwner : TComponent); override; @@ -96,6 +98,14 @@ DoLog(Format(Fmt,Args)); end; +procedure TFPDocCreator.DoLogSender ( Sender: TObject; const Msg: String ) ; +begin + if Assigned(Sender) then + DoLog(Format('%s - Sender: %s', [Msg, Sender.ClassName])) + else + DoLog(Msg); +end; + procedure TFPDocCreator.HandleOnParseUnit(Sender: TObject; const AUnitName: String; out AInputFile, OSTarget, CPUTarget: String); @@ -208,7 +218,9 @@ Cmd,Arg : String; begin + // Now is used the specified writer WriterClass:=GetWriterClass(Options.Backend); + // ALL CONTENT CREATED HERE Writer:=WriterClass.Create(Engine.Package,Engine); With Writer do Try @@ -225,10 +237,12 @@ If not InterPretOption(Cmd,Arg) then DoLog(SCmdLineInvalidOption,[Cmd+'='+Arg]); end; + // Output created Documentation WriteDoc; Finally Free; end; + // Output content files Writeln('Content file : ',APackage.ContentFile); if Length(APackage.ContentFile) > 0 then Engine.WriteContentFile(APackage.ContentFile); @@ -247,16 +261,21 @@ Cmd:=''; FCurPackage:=APackage; Engine:=TFPDocEngine.Create; + Engine.OnLog:= @DoLogSender; try + // get documentation Writer html, latex, and other WriterClass:=GetWriterClass(Options.Backend); For J:=0 to Apackage.Imports.Count-1 do begin Arg:=Apackage.Imports[j]; + // conversion import FilePathes WriterClass.SplitImport(Arg,Cmd); + // create tree of imported objects Engine.ReadContentFile(Arg, Cmd); end; for i := 0 to APackage.Descriptions.Count - 1 do Engine.AddDocFile(FixDescrFile(APackage.Descriptions[i]),Options.donttrim); + // set engine options Engine.SetPackageName(APackage.Name); Engine.Output:=APackage.Output; Engine.OnLog:=Self.OnLog; @@ -268,13 +287,18 @@ Engine.WarnNoNode:=Options.WarnNoNode; if Length(Options.Language) > 0 then TranslateDocStrings(Options.Language); + // scan the input source files for i := 0 to APackage.Inputs.Count - 1 do try + // get options from input packages SplitInputFileOption(APackage.Inputs[i],Cmd,Arg); + // make absolute filepath Cmd:=FixInputFile(Cmd); if FProcessedUnits.IndexOf(Cmd)=-1 then begin FProcessedUnits.Add(Cmd); + // Parce sources for OS Target + //WriteLn(Format('Parcing unit: %s', [ExtractFilenameOnly(Cmd)])); ParseSource(Engine,Cmd+' '+Arg, Options.OSTarget, Options.CPUTarget,[poUseStreams]); end; except @@ -290,6 +314,7 @@ if Not ParseOnly then begin Engine.StartDocumenting; + // Create documentation CreateOutput(APackage,Engine); end; finally patch_fpdoc_description_01_en.txt (3,416 bytes)
Fix Description. I apologize that I was placed a lot in this patch, but almost everything does not work separately. If you say that you need to divide on the parts, then I will do it. But I did not have the opportunity to make intermediate fixations in repo. Changes: 1. Correction of the generation of XCT files. Unit dGlobal.pp. Now all classes have only full FilePath with the package name. FUNSTION - TFPDOCENGINE.WRIPECONTENTFILE() 2. Small fixing of the assembly link to the internal pages FUNCTION - TFPDOCENGINE.REDCONTENTFILE LINES 719 - 720. 3. Remake the classes tree for the pages of the classes hierarchy. Here are great changes. Unit Fpdocclasstree. In this file, the XML document received two separate branches. One branch for TObject classes ancestors, the second branch for classes without ancestor and for unresolved classes. An example of a tree for my test is attached. (test.xml) The output of this file can be enabled in the DW_HTML.PP Line 2580 string 4. Remake the page with the display hierarchy of classes for the entire package. Here you can see the two sections "Hierarchy of tobject Classes" and "Hierarchy of Simple Classes". It is better visible on the test.chm file. 5. Remake the main page of the class display page, so that there were no passages of the hierarchy. What is done no longer remember. DW_HTML.PP Procedure CreatemainPage; 6. Fix small exception ino dw_txt.pas 7. As I have already written that after fixing the XCT file and some functions, all methods and properties of the ancestors appeared in all pages of Class-Functions Class-Properties Class-Events. After it, the chm file and the full-text index grew very much. Also began to load Lhelp for a long time. These pages not have a title and are useless for the index, so I tried to turn them off from full-text search. But in Packages / CHM / SRC / CHMWRITER.PAS, there is no possibility to remove some files from full-text search, you can only turn off all files. Here I apologize, I made a hack, you decide. But if this is not done, then everything made will be useless. I added to Packages/CHM/SRC/CHMWRITER.PAS the hack code. Exception of files from a full-text index if they start from the point. That in general logical and then it will be possible to exclude other index pages. As a result, full-text search became beautiful. Under another, I don`t know how to do that another. I didn`t want use external index for that. 8. From beautiful, I only made a change in the upper bar, because it was very difficult to understande where I am now. Now I obviously signed when I displays the data of the unit or package. DW_HTML.PP - Thtmlwriter.APPendMenubar 9. Misc - The situation with the RTF format is incomprehensible, it does not open with me. - Also attached the generated tree objects for the classes hierarchy (test.xml) - An XML mode produces exception when I start without created before an output directory (need to add the directory creation before output). Attached: - The test files TXT, IPF, MAN, CHTM, HTML modes, and a new LCL.CHM as an example. - I have no opportunity to check LATEX on Windows, but the machine with Linux has already collected. - New rtl.xct fcl.xct Files: https://drive.google.com/file/d/1f08ONIZ-lJFadOWG8tk_gLPIwLdEE-WG/view?usp=sharing I hope that you can allocate time to work with this FIX. Andrey Sobol. |
|
Hello, I looked at your patch. I will apply what I can. The menu bar change seems nice to me. Unfortunately, there are some remarks: * You will need to redo the complete class tree work with current trunk. If you look at the current sources, you'll see that there is no more XML used in that unit. None of your code is usable. * Classes without explicit parent always descend from TObject. Putting them in a separate tree is simply wrong. I can understand you want to put the 'unknown' ones in a separate tree, but the one without explict parents must go in the normal tree. |
|
Sadly ... :( I will see... Classes I agree also, I forgot that. |
|
What are you think about exclusion of files from a full text index per the dot prefix? |
|
A list of files to exclude seems the best way to me. It could contain wildchars. |
|
You can't put the . hack in CHMwriter anyway, that unit is for more applications than just fpdoc |
|
But I don`t need this, I don`t include that files into full text index. You can see it into my fix, package/chm/chmwriter |
|
Hello - attached the new patch version - attached description - link to test files https://drive.google.com/file/d/1myUOZGsGTl42aaji68WC6G0XczUZaT19/view?usp=sharing To do - add a tree output for xmlwriter. - show unresolved sign '?' at ClassTree for classes without documentation. - can be add an using TClassTreeBuilder for another pages. patch_fpdoc_02.patch (52,198 bytes)
Index: packages/chm/src/chmwriter.pas =================================================================== --- packages/chm/src/chmwriter.pas (revision 47408) +++ packages/chm/src/chmwriter.pas (working copy) @@ -1664,14 +1664,15 @@ procedure TChmWriter.CheckFileMakeSearchable(AStream: TStream; AFileEntry: TFileEntryRec); var - TopicEntry: TTopicEntry; - ATitle: String; + TopicEntry: TTopicEntry; + ATitle: String; begin - if Pos('.ht', AFileEntry.Name) > 0 then + // Exclude Full text index for files starting from the dot + if (Pos('.', AFileEntry.Name) <> 1) and (Pos('.ht', AFileEntry.Name) > 0) then begin ATitle := FIndexedFiles.IndexFile(AStream, NextTopicIndex, FSearchTitlesOnly); AddTopic(ATitle,AFileEntry.Path+AFileEntry.Name,-1); - end; + end; end; function TChmWriter.AddTopic(ATitle,AnUrl:AnsiString;code:integer=-1):integer; @@ -1690,7 +1691,7 @@ TopicEntry.URLTableOffset := AddURL(AnUrl, Result); if code=-1 then begin - if ATitle<>'' then + if Trim(ATitle) <> '' then TopicEntry.InContents := 6 else TopicEntry.InContents := 2; @@ -1720,8 +1721,8 @@ ATitle :=StringReplace(Atitle, '&x27;', '', [rfReplaceAll]); // adhoc subsitutions. Replace with real code if exact behaviour is known. -{ Atitle:=StringReplace(atitle, '&x27;', '''', [rfReplaceAll]); - if length(atitle)>0 then +{ Atitle:=StringReplace(Atitle, '&x27;', '''', [rfReplaceAll]); + if length(Trim(Atitle))>0 then atitle[1]:=uppercase(atitle[1])[1];} {$ifdef binindex} writeln('Enter ',ATitle,' ',AnUrl); @@ -1732,11 +1733,11 @@ writeln('found:',result); {$endif} end - else - begin - result:=addtopic(atitle,anurl); - FDictTopicsUrlInd.add(anurl,result); - end; + else if Trim(ATitle) <> '' then + begin + result:=addtopic(ATitle,AnUrl); + FDictTopicsUrlInd.add(AnUrl,result); + end; end; procedure TChmWriter.ScanSitemap(asitemap:TCHMSiteMap); Index: utils/fpdoc/dglobals.pp =================================================================== --- utils/fpdoc/dglobals.pp (revision 47648) +++ utils/fpdoc/dglobals.pp (working copy) @@ -36,9 +36,12 @@ resourcestring // Output strings SDocPackageTitle = 'Reference for package ''%s'''; + SDocPackageMenuTitle = 'Menu for package ''%s'''; + SDocPackageLinkTitle = 'Package'; SDocPrograms = 'Programs'; SDocUnits = 'Units'; SDocUnitTitle = 'Reference for unit ''%s'''; + SDocUnitMenuTitle = 'Menu for unit ''%s'''; SDocInheritanceHierarchy = 'Inheritance Hierarchy'; SDocInterfaceSection = 'Interface section'; SDocImplementationSection = 'Implementation section'; @@ -205,7 +208,7 @@ Const SVisibility: array[TPasMemberVisibility] of string = ('Default', 'Private', 'Protected', 'Public', - 'Published', 'Automated','Strict Private','Strict Protected','Required','Optional'); + 'Published', 'Automated','Strict Private','Strict Protected'); type TBufType = Array[1..ContentBufSize-1] of byte; @@ -319,9 +322,9 @@ FAlwaysVisible : TStringList; DescrDocs: TObjectList; // List of XML documents DescrDocNames: TStringList; // Names of the XML documents - FRootLinkNode: TLinkNode; - FRootDocNode: TDocNode; - FPackages: TFPList; // List of TFPPackage objects + FRootLinkNode: TLinkNode; // Global tree of TlinkNode from the imported .xct files + FRootDocNode: TDocNode; // Global tree of TDocNode from the .xml documentation files + FPackages: TFPList; // Global list of TPasPackage objects and full tree of sources CurModule: TPasModule; CurPackageDocNode: TDocNode; function ParseUsedUnit(AName, AInputLine,AOSTarget,ACPUTarget: String): TPasModule; virtual; @@ -338,7 +341,9 @@ constructor Create; destructor Destroy; override; procedure SetPackageName(const APackageName: String); + // process the import objects from external .xct file procedure ReadContentFile(const AFilename, ALinkPrefix: String); + // creation of an own .xct output file procedure WriteContentFile(const AFilename: String); function CreateElement(AClass: TPTreeElement; const AName: String; @@ -345,6 +350,7 @@ AParent: TPasElement; AVisibility: TPasMemberVisibility; const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement; override; + function FindInModule(const AName: String ; AModule: TPasModule): TPasElement; function FindElement(const AName: String): TPasElement; override; function FindModule(const AName: String): TPasModule; override; Function HintsToStr(Hints : TPasMemberHints) : String; @@ -660,7 +666,9 @@ procedure TFPDocEngine.ReadContentFile(const AFilename, ALinkPrefix: String); var f: Text; - inheritanceinfo : TStringlist; + inheritanceinfo : TStringlist; // contents list of TPasClass with inheritance info + // like this #PackageName.ModuleName.ClassName + tmpLinkPrefix : string; procedure ReadLinkTree; var @@ -708,8 +716,10 @@ i := ThisSpaces + 1; while s[i] <> ' ' do Inc(i); + if ALinkPrefix <> '' then + tmpLinkPrefix := ExcludeTrailingPathDelimiter(ALinkPrefix)+'/'; NewNode := TLinkNode.Create(Copy(s, ThisSpaces + 1, i - ThisSpaces - 1), - ALinkPrefix + Copy(s, i + 1, Length(s))); + tmpLinkPrefix + Copy(s, i + 1, Length(s))); if pos(' ',newnode.link)>0 then writeln(stderr,'Bad format imported node: name="',newnode.name,'" link="',newnode.link,'"'); if Assigned(PrevSibling) then @@ -721,56 +731,57 @@ end; function ResolvePackageModule(AName:String;out pkg:TPasPackage;out module:TPasModule;createnew:boolean):String; - var - DotPos, DotPos2, i: Integer; - s: String; - HPackage: TPasPackage; + var + DotPos, DotPos2, i: Integer; + s: String; + HPackage: TPasPackage; - begin - pkg:=nil; module:=nil; result:=''; + begin + pkg:=nil; module:=nil; result:=''; - // Find or create package - DotPos := Pos('.', AName); - s := Copy(AName, 1, DotPos - 1); - HPackage := nil; - for i := 0 to FPackages.Count - 1 do - if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then - begin - HPackage := TPasPackage(FPackages[i]); - break; - end; - if not Assigned(HPackage) then + // Find or create package + DotPos := Pos('.', AName); + s := Copy(AName, 1, DotPos - 1); + HPackage := nil; + for i := 0 to FPackages.Count - 1 do + if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then begin - if not CreateNew then - exit; - HPackage := TPasPackage(inherited CreateElement(TPasPackage, s, nil, - '', 0)); - FPackages.Add(HPackage); + HPackage := TPasPackage(FPackages[i]); + break; end; + if not Assigned(HPackage) then + begin + if not CreateNew then + exit; + HPackage := TPasPackage(inherited CreateElement(TPasPackage, s, nil, + '', 0)); + FPackages.Add(HPackage); + end; - // Find or create module - DotPos2 := DotPos; - repeat - Inc(DotPos2); - until AName[DotPos2] = '.'; - s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1); - Module := nil; - for i := 0 to HPackage.Modules.Count - 1 do - if CompareText(TPasModule(HPackage.Modules[i]).Name, s) = 0 then - begin - Module := TPasModule(HPackage.Modules[i]); - break; - end; - if not Assigned(Module) then + // Find or create module + DotPos2 := DotPos; + repeat + Inc(DotPos2); + until AName[DotPos2] = '.'; + s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1); + Module := nil; + for i := 0 to HPackage.Modules.Count - 1 do + if CompareText(TPasModule(HPackage.Modules[i]).Name, s) = 0 then begin - if not CreateNew then - exit; - Module := TPasExternalModule.Create(s, HPackage); - Module.InterfaceSection := TInterfaceSection.Create('', Module); - HPackage.Modules.Add(Module); + Module := TPasModule(HPackage.Modules[i]); + break; end; - pkg:=hpackage; - result:=Copy(AName, DotPos2 + 1, length(AName)-dotpos2); + if not Assigned(Module) then + begin + if not CreateNew then + exit; + Module := TPasExternalModule.Create(s, HPackage); + Module.InterfaceSection := TInterfaceSection.Create('', Module); + Module.PackageName:= HPackage.Name; + HPackage.Modules.Add(Module); + end; + pkg:=hpackage; + result:=Copy(AName, DotPos2 + 1, length(AName)-dotpos2); end; function SearchInList(clslist:TFPList;s:string):TPasElement; @@ -834,9 +845,9 @@ InheritanceInfo.AddObject(Inheritancestr,result); end; - procedure splitalias(var instr:string;out outstr:string); - var i,j:integer; - begin + procedure splitalias(var instr:string;out outstr:string); + var i,j:integer; + begin if length(instr)=0 then exit; instr:=trim(instr); i:=pos('(',instr); @@ -848,10 +859,10 @@ outstr:=copy(instr,i+1,j); delete(instr,i,j+2); end - end; + end; - Function ResolveAndLinkClass(clname:String;IsClass:boolean;cls:TPasClassType):TPasClassType; - begin + Function ResolveAndLinkClass(clname:String;IsClass:boolean;cls:TPasClassType):TPasClassType; + begin result:=TPasClassType(ResolveClassType(clname)); if assigned(result) and not (cls=result) then // save from tobject=implicit tobject begin @@ -870,47 +881,47 @@ else if cls<>result then DoLog('Warning : ancestor class %s of class %s could not be resolved',[clname,cls.name]); -end; + end; -function CreateAliasType (alname,clname : string;parentclass:TPasClassType; out cl2 :TPasClassType):TPasAliasType; -// create alias clname = alname -var - pkg : TPasPackage; - module : TPasModule; - s : string; -begin - Result:=nil; - s:=ResolvePackageModule(Alname,pkg,module,True); - if not assigned(module) then - exit; - cl2:=TPasClassType(ResolveClassType(alname)); - if assigned( cl2) and not (parentclass=cl2) then - begin - result:=ResolveAliasType(clname); - if assigned(result) then + function CreateAliasType (alname,clname : string;parentclass:TPasClassType; out cl2 :TPasClassType):TPasAliasType; + // create alias clname = alname + var + pkg : TPasPackage; + module : TPasModule; + s : string; + begin + Result:=nil; + s:=ResolvePackageModule(Alname,pkg,module,True); + if not assigned(module) then + exit; + cl2:=TPasClassType(ResolveClassType(alname)); + if assigned( cl2) and not (parentclass=cl2) then begin -// writeln('found alias ',clname,' (',s,') ',result.classname); + result:=ResolveAliasType(clname); + if assigned(result) then + begin + // writeln('found alias ',clname,' (',s,') ',result.classname); + end + else + begin + // writeln('new alias ',clname,' (',s,') '); + cl2.addref; + Result := TPasAliasType(CreateElement(TPasAliasType,s,module.interfacesection,vispublic,'',0)); + module.interfacesection.Declarations.Add(Result); + TPasAliasType(Result).DestType := cl2; + end end - else - begin -// writeln('new alias ',clname,' (',s,') '); - cl2.addref; - Result := TPasAliasType(CreateElement(TPasAliasType,s,module.interfacesection,vispublic,'',0)); - module.interfacesection.Declarations.Add(Result); - TPasAliasType(Result).DestType := cl2; - end - end -end; + end; - procedure ProcessInheritanceStrings(inhInfo:TStringList); + procedure ProcessInheritanceStrings(inhInfo:TStringList); - var i,j : integer; - cls : TPasClassType; + var i,j : integer; + cls : TPasClassType; cls2: TPasClassType; clname, alname : string; inhclass : TStringList; - begin + begin inhclass:=TStringList.Create; inhclass.delimiter:=','; if InhInfo.Count>0 then @@ -922,12 +933,12 @@ for j:= 0 to inhclass.count-1 do begin - //writeln('processing',inhclass[j]); + // writeln('processing',inhclass[j]); clname:=inhclass[j]; - splitalias(clname,alname); + splitalias(clname,alname); if alname<>'' then // the class//interface we refered to is an alias begin - // writeln('Found alias pair ',clname,' = ',alname); + // writeln('Found alias pair ',clname,' = ',alname); if not assigned(CreateAliasType(alname,clname,cls,cls2)) then DoLog('Warning: creating alias %s for %s failed!',[alname,clname]); end @@ -936,7 +947,7 @@ end; end; inhclass.free; - end; + end; var s, Name: String; @@ -993,10 +1004,10 @@ CurClass.Members.Add(Member); end; end; - ProcessInheritanceStrings(Inheritanceinfo); + ProcessInheritanceStrings(Inheritanceinfo); finally - inheritanceinfo.Free; - end; + inheritanceinfo.Free; + end; end; var @@ -1044,11 +1055,13 @@ end; end; - function CheckImplicitInterfaceLink(const s : String):String; + function CheckImplicitLink(const s : String):String; begin - if uppercase(s)='IUNKNOWN' then + if uppercase(s)='IUNKNOWN' then Result:='#rtl.System.IUnknown' - else + else if uppercase(s)='TOBJECT' then + Result:='#rtl.System.TObject' + else Result:=s; end; var @@ -1096,13 +1109,13 @@ ClassLikeDecl:=MemberDecl as TPasClassType else ClassLikeDecl:=nil; - Write(ContentFile, CheckImplicitInterfaceLink(MemberDecl.PathName), ' '); + Write(ContentFile, CheckImplicitLink(MemberDecl.PathName), ' '); if Assigned(ClassLikeDecl) then begin if Assigned(ClassLikeDecl.AncestorType) then begin // simple aliases to class types are coded as "alias(classtype)" - Write(ContentFile, CheckImplicitInterfaceLink(ClassLikeDecl.AncestorType.PathName)); + Write(ContentFile, CheckImplicitLink(ClassLikeDecl.AncestorType.PathName)); if ClassLikeDecl.AncestorType is TPasAliasType then begin alias:= TPasAliasType(ClassLikeDecl.AncestorType); @@ -1118,12 +1131,12 @@ begin for k:=0 to ClassLikeDecl.Interfaces.count-1 do begin - write(contentfile,',',CheckImplicitInterfaceLink(TPasClassType(ClassLikeDecl.Interfaces[k]).PathName)); + write(contentfile,',',CheckImplicitLink(TPasClassType(ClassLikeDecl.Interfaces[k]).PathName)); if TPasElement(ClassLikeDecl.Interfaces[k]) is TPasAliasType then begin alias:= TPasAliasType(ClassLikeDecl.Interfaces[k]); if assigned(alias.desttype) and (alias.desttype is TPasClassType) then - write(ContentFile,'(',CheckImplicitInterfaceLink(alias.desttype.PathName),')'); + write(ContentFile,'(',CheckImplicitLink(alias.desttype.PathName),')'); end; end; end; @@ -1173,34 +1186,34 @@ Result.SourceLinenumber := ASourceLinenumber; end; -function TFPDocEngine.FindElement(const AName: String): TPasElement; +function TFPDocEngine.FindInModule ( const AName: String; AModule: TPasModule + ) : TPasElement; +var + l: TFPList; + i: Integer; - function FindInModule(AModule: TPasModule; const LocalName: String): TPasElement; - - var - l: TFPList; - i: Integer; - - begin - If assigned(AModule.InterfaceSection) and - Assigned(AModule.InterfaceSection.Declarations) then +begin + If Assigned(AModule) and Assigned(AModule.InterfaceSection) and + Assigned(AModule.InterfaceSection.Declarations) then + begin + l:=AModule.InterfaceSection.Declarations; + for i := 0 to l.Count - 1 do begin - l:=AModule.InterfaceSection.Declarations; - for i := 0 to l.Count - 1 do - begin - Result := TPasElement(l[i]); - if CompareText(Result.Name, LocalName) = 0 then - exit; - end; - end; - Result := nil; - end; + Result := TPasElement(l[i]); + if CompareText(Result.Name, AName) = 0 then + exit; + end; + end; + Result := nil; +end; +function TFPDocEngine.FindElement(const AName: String): TPasElement; + var i: Integer; Module: TPasElement; begin - Result := FindInModule(CurModule, AName); + Result := FindInModule( AName, CurModule ); if not Assigned(Result) and assigned (CurModule.InterfaceSection) then for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do begin @@ -1207,7 +1220,7 @@ Module := TPasElement(CurModule.InterfaceSection.UsesList[i]); if Module.ClassType.InheritsFrom(TPasModule) then begin - Result := FindInModule(TPasModule(Module), AName); + Result := FindInModule(AName, TPasModule(Module)); if Assigned(Result) then exit; end; Index: utils/fpdoc/dw_html.pp =================================================================== --- utils/fpdoc/dw_html.pp (revision 47648) +++ utils/fpdoc/dw_html.pp (working copy) @@ -15,7 +15,7 @@ {$mode objfpc} {$H+} -unit dw_HTML; +unit dw_html; {$WARN 5024 off : Parameter "$1" not used} interface @@ -75,9 +75,7 @@ THTMLWriter = class(TFPDocWriter) private FImageFileList: TStrings; - FOnTest: TNotifyEvent; - FPackage: TPasPackage; FCharSet : String; procedure CreateMinusImage; procedure CreatePlusImage; @@ -233,7 +231,7 @@ procedure CreatePackagePageBody; procedure CreatePackageIndex; procedure CreatePackageClassHierarchy; - procedure CreateClassHierarchyPage(AList: TStringList; AddUnit : Boolean); + procedure CreateClassHierarchyPage(AddUnit : Boolean); procedure AddModuleIdentifiers(AModule : TPasModule; L : TStrings); Procedure CreateTopicPageBody(AElement : TTopicElement); procedure CreateModulePageBody(AModule: TPasModule; ASubpageIndex: Integer); @@ -244,9 +242,9 @@ procedure CreateVarPageBody(AVar: TPasVariable); procedure CreateProcPageBody(AProc: TPasProcedureBase); Procedure CreateTopicLinks(Node : TDocNode; PasElement : TPasElement); - procedure AddElementsFromList(L: TStrings; List: TFPList; UsePathName : Boolean = False); procedure AppendTypeDecl(AType: TPasType; TableEl, CodeEl: TDomElement); public + // Creating all module hierarchy classes is here !!!! constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override; destructor Destroy; override; @@ -254,7 +252,7 @@ function CreateHTMLPage(AElement: TPasElement; ASubpageIndex: Integer): TXMLDocument; function CreateXHTMLPage(AElement: TPasElement; ASubpageIndex: Integer): TXMLDocument; - // For producing complete package documentation + // Start producing html complete package documentation procedure WriteHTMLPages; virtual; procedure WriteXHTMLPages; function ModuleForElement(AnElement:TPasElement):TPasModule; @@ -266,7 +264,7 @@ Class procedure SplitImport(var AFilename, ALinkPrefix: String); override; Property SearchPage: String Read FSearchPage Write FSearchPage; property Allocator: TFileAllocator read FAllocator; - property Package: TPasPackage read FPackage; + property PageCount: Integer read GetPageCount; Property IncludeDateInFooter : Boolean Read FIDF Write FIDF; Property DateFormat : String Read FDateFormat Write FDateFormat; @@ -326,13 +324,20 @@ var n,s: String; i: Integer; - + excl: Boolean; //search begin Result:=''; + excl := False; if AElement.ClassType = TPasPackage then - Result := 'index' + begin + Result := 'index'; + excl := True; + end else if AElement.ClassType = TPasModule then - Result := LowerCase(AElement.Name) + PathDelim + 'index' + begin + Result := LowerCase(AElement.Name) + PathDelim + 'index'; + excl := True; + end else begin if AElement is TPasOperator then @@ -361,8 +366,12 @@ if (N<>'') and (N[1]=':') then Delete(N,1,1); Result:=Result + '-'+ s + '-' + N; - end else + end + else + begin Result := LowerCase(AElement.PathName); + excl := (ASubindex > 0); + end; // searching for TPasModule - it is on the 2nd level if Assigned(AElement.Parent) then while Assigned(AElement.Parent.Parent) do @@ -375,6 +384,14 @@ Inc(i); if (i <= Length(Result)) and (i > 0) then Result[i] := PathDelim; + if excl or (Length(Result)=0) then + begin + // exclude the from full text search index + s:= '.'+ExtractFileName(Result + '.'); + n:= ExtractFileDir(Result); + Result := n + DirectorySeparator + s; + Result := Copy(Result, 1, Length(Result)-1); + end; end; if ASubindex > 0 then @@ -632,7 +649,7 @@ H : Boolean; begin - inherited ; + inherited Create(APackage, AEngine); // should default to true since this is the old behavior UseMenuBrackets:=True; @@ -640,7 +657,6 @@ IndexColCount:=3; Charset:='iso-8859-1'; CreateAllocator; - FPackage := APackage; OutputNodeStack := TList.Create; PageInfos := TObjectList.Create; @@ -716,6 +732,7 @@ HTMLEl.AppendChild(BodyElement); CreatePageBody(AElement, ASubpageIndex); + AppendFooter; HeadEl.AppendChild(El); @@ -771,6 +788,7 @@ Filename := Engine.Output + Allocator.GetFilename(Element, SubpageIndex); try CreatePath(Filename); + //writeln('Element: ',Element.PathName, ' FileName: ', Filename); WriteHTMLFile(PageDoc, Filename); except on E: Exception do @@ -1534,7 +1552,8 @@ end; end; -Procedure THTMLWriter.AppendShortDescr(AContext: TPasElement; Parent: TDOMNode; DocNode : TDocNode); +procedure THTMLWriter.AppendShortDescr ( AContext: TPasElement; + Parent: TDOMNode; DocNode: TDocNode ) ; Var N : TDocNode; @@ -2093,7 +2112,7 @@ procedure THTMLWriter.AppendMenuBar(ASubpageIndex: Integer); var - TableEl, TREl, ParaEl, TitleEl: TDOMElement; + TableEl, TREl, TRE2, ParaEl, TitleEl: TDOMElement; procedure AddLink(ALinkSubpageIndex: Integer; const AName: String); begin @@ -2132,9 +2151,35 @@ TableEl['border'] := '0'; TableEl['width'] := '100%'; TableEl['class'] := 'bar'; + // Title Row TREl := CreateTR(TableEl); - ParaEl := CreateEl(CreateTD(TREl), 'b'); + // Menu title + ParaEl := CreateTD(TREl); + ParaEl['align'] := 'left'; + TitleEl := CreateEl(ParaEl, 'span'); + TitleEl['class'] := 'bartitle'; + if Assigned(Module) then + AppendText(TitleEl, Format(SDocUnitMenuTitle, [Module.Name])) + else + AppendText(TitleEl, Format(SDocPackageMenuTitle, [Package.Name])); + // Package link title + ParaEl := CreateTD(TREl); + ParaEl['align'] := 'right'; + TitleEl := CreateEl(ParaEl, 'span'); + TitleEl['class'] := 'bartitle'; + if Assigned(Module) and Assigned(Package) then // Displays a Package page + begin + AppendText(TitleEl, SDocPackageLinkTitle); + end; + + // Links Row + TRE2 := CreateTR(TableEl); + ParaEl := CreateTD(TRE2); + ParaEl['align'] := 'left'; + ParaEl := CreateEl(ParaEl, 'span'); + ParaEl['class']:= 'bartitle'; + if Assigned(Module) then begin AddLink(0, SDocOverview); @@ -2150,12 +2195,18 @@ AddLink(ProcsSubindex, SDocProceduresAndFunctions); if Module.InterfaceSection.Variables.Count > 0 then AddLink(VarsSubindex, SDocVariables); - AddLink(IndexSubIndex,SDocIdentifierIndex); + AddLink(IndexSubIndex,SDocIdentifierIndex); AppendFragment(ParaEl, NavigatorHTML); end else begin + // Overview + AppendText(ParaEl, '['); + AppendHyperlink(ParaEl, Package).TextContent:= UTF8Decode(SDocOverview); + AppendText(ParaEl, ']'); + //Index AddPackageLink(IndexSubIndex, SDocIdentifierIndex); + // Class TObject tree AddPackageLink(ClassHierarchySubIndex, SDocPackageClassHierarchy); AppendFragment(ParaEl, NavigatorHTML) end; @@ -2168,17 +2219,16 @@ if FUseMenuBrackets then AppendText(ParaEl, ']'); end; - ParaEl := CreateTD(TREl); + + ParaEl := CreateTD(TRE2); ParaEl['align'] := 'right'; - TitleEl := CreateEl(ParaEl, 'span'); - TitleEl['class'] := 'bartitle'; - if Assigned(Module) then - AppendText(TitleEl, Format(SDocUnitTitle, [Module.Name])); - if Assigned(Package) then + ParaEl := CreateEl(ParaEl, 'span'); + ParaEl['class']:= 'bartitle'; + if Assigned(Module) and Assigned(Package) then // Displays a Package page begin - AppendText(TitleEl, ' ('); - AppendHyperlink(TitleEl, Package); - AppendText(TitleEl, ')'); + AppendText(ParaEl, '['); + AppendHyperlink(ParaEl, Package); + AppendText(ParaEl, ']'); end; AppendFragment(BodyElement,HeaderHTML); end; @@ -2189,7 +2239,8 @@ [ExtractFileName(AElement.SourceFilename), AElement.SourceLinenumber])); end; -Procedure THTMLWriter.AppendSeeAlsoSection(AElement : TPasElement;DocNode : TDocNode); +procedure THTMLWriter.AppendSeeAlsoSection ( AElement: TPasElement; + DocNode: TDocNode ) ; var Node: TDOMNode; @@ -2263,7 +2314,8 @@ end; // While end; -Procedure THTMLWriter.AppendExampleSection(AElement : TPasElement;DocNode : TDocNode); +procedure THTMLWriter.AppendExampleSection ( AElement: TPasElement; + DocNode: TDocNode ) ; var Node: TDOMNode; @@ -2384,10 +2436,11 @@ end; end; -procedure THTMLWriter.CreateClassHierarchyPage(AList : TStringList; AddUnit : Boolean); +procedure THTMLWriter.CreateClassHierarchyPage(AddUnit : Boolean); +type + TypeEN = (NPackage, NModule, NName); Procedure PushClassElement; - Var H : THTMLElement; begin @@ -2403,7 +2456,6 @@ end; Procedure PushClassList; - Var H : THTMLElement; begin @@ -2412,32 +2464,39 @@ PushOutputNode(h); end; - Procedure AppendClass(E : TPasElementNode); + function ExtractName(APathName: String; Tp: TypeEN):String; + var + l:TStringList; + begin + Result:= Trim(APathName); + if Result = '' then exit; + l:=TStringList.Create; + try + l.AddDelimitedText(Result, '.', True); + if l.Count=3 then + Result:= l.Strings[Integer(Tp)] + else + Result:=''; + finally + l.free; + end; + end; + Procedure AppendClass(EN : TPasElementNode); + Var - N : TDomNode; - P,PM,M : TPasElement; - EN : String; - LL : TstringList; - I,J : Integer; + PE,PM : TPasElement; + I : Integer; begin - M:=E.Element.GetModule; - if (M<>Nil) then - EN:=Package.Name+'.'+UTF8Encode(M.Name)+'.'+UTF8Encode(E.Element.Name) - else - EN:=UTF8Encode(E.Element.Name); - J:=AList.IndexOf(EN); - If J<>-1 then - P:=AList.Objects[J] as TPasElement - else - P:=Engine.FindElement(EN); + if not Assigned(EN) then exit; + PE:=EN.Element; PushClassElement; try - if (P<>Nil) then + if (PE<>Nil) then begin - AppendHyperLink(CurOutputNode,P); - PM:=ModuleForElement(P); + AppendHyperLink(CurOutputNode,PE); + PM:=ModuleForElement(PE); if (PM<>Nil) then begin AppendText(CurOutputNode,' ('); @@ -2446,13 +2505,13 @@ end end else - AppendText(CurOutputNode,E.Element.Name); - if E.ChildCount>0 then + AppendText(CurOutputNode,EN.Element.Name); + if EN.ChildCount>0 then begin PushClassList; try - For I:=0 to E.ChildCount-1 do - AppendClass(E.Children[i] as TPasElementNode); + For I:=0 to EN.ChildCount-1 do + AppendClass(EN.Children[i] as TPasElementNode); finally PopOutputNode; end; @@ -2462,29 +2521,12 @@ end; end; -Var - B : TClassTreeBuilder; - E : TPasElementNode; - begin PushOutputNode(BodyElement); try - B:=TClassTreeBuilder.Create(Package,okClass); - try - B.BuildTree(AList); - // Classes - // WriteXMLFile(B.ClassTree,'tree.xml'); - // Dummy TObject - E:=B.RootNode; - PushClassList; - try - AppendClass(E); - finally - PopOutputNode; - end; - finally - B.Free; - end; + PushClassList; + AppendClass(TreeClass.RootNode); + //PopOutputNode; finally PopOutputNode; end; @@ -2500,9 +2542,6 @@ '}'; Var - L : TStringList; - I : Integer; - M : TPasModule; S : String; SE : THTMLElement; @@ -2510,24 +2549,12 @@ SE := Doc.CreateElement('script'); AppendText(SE,SFunc); HeadElement.AppendChild(SE); - L:=TStringList.Create; - try - L.Capacity:=PageInfos.Count; // Too much, but that doesn't hurt. - For I:=0 to Package.Modules.Count-1 do - begin - M:=TPasModule(Package.Modules[i]); - if Not (M is TPasExternalModule) and assigned(M.InterfaceSection) then - Self.AddElementsFromList(L,M.InterfaceSection.Classes,True) - end; - AppendMenuBar(ClassHierarchySubIndex); - S:=Package.Name; - If Length(S)>0 then - Delete(S,1,1); - AppendTitle(UTF8Decode(Format(SDocPackageClassHierarchy, [S]))); - CreateClassHierarchyPage(L,True); - Finally - L.Free; - end; + AppendMenuBar(ClassHierarchySubIndex); + S:=Package.Name; + If Length(S)>0 then + Delete(S,1,1); + AppendTitle(UTF8Decode(Format(SDocPackageClassHierarchy, [S]))); + CreateClassHierarchyPage(True); end; procedure THTMLWriter.CreatePageBody(AElement: TPasElement; @@ -2673,30 +2700,7 @@ end; end; -Procedure THTMLWriter.AddElementsFromList(L : TStrings; List : TFPList; UsePathName : Boolean = False); -Var - I : Integer; - El : TPasElement; - N : TDocNode; - -begin - For I:=0 to List.Count-1 do - begin - El:=TPasElement(List[I]); - N:=Engine.FindDocNode(El); - if (N=Nil) or (not N.IsSkipped) then - begin - if UsePathName then - L.AddObject(El.PathName,El) - else - L.AddObject(El.Name,El); - If el is TPasEnumType then - AddElementsFromList(L,TPasEnumType(el).Values); - end; - end; -end; - procedure THTMLWriter.AddModuleIdentifiers(AModule : TPasModule; L : TStrings); begin @@ -2783,7 +2787,8 @@ end; end; -Procedure THTMLWriter.CreateTopicLinks(Node : TDocNode; PasElement : TPasElement); +procedure THTMLWriter.CreateTopicLinks ( Node: TDocNode; + PasElement: TPasElement ) ; var DocNode: TDocNode; @@ -3351,10 +3356,9 @@ i: Integer; ThisInterface, ThisClass: TPasClassType; - HaveSeenTObject: Boolean; - LName : String; - ThisNode : TPasUnresolvedTypeRef; + ThisTreeNode: TPasElementNode; begin + //WriteLn('@ClassPageBody.CreateMainPage Class=', AClass.Name); AppendMenuBar(-1); AppendTitle(UTF8Decode(AClass.Name),AClass.Hints); @@ -3398,14 +3402,16 @@ end; CreateMemberDeclarations(AClass, AClass.Members,TableEl, not AClass.IsShortDefinition); + AppendText(CreateH2(BodyElement), UTF8Decode(SDocInheritance)); + TableEl := CreateTable(BodyElement); + // Now we are using only TreeClass for show inheritance - AppendText(CreateH2(BodyElement), UTF8Decode(SDocInheritance)); - TableEl := CreateTable(BodyElement); - HaveSeenTObject := AClass.ObjKind <> okClass; - // we try to track classes. But imported classes - // are TLinkNode's not the TPasClassType generated by the parser. - ThisClass := AClass; ThisNode := Nil; + ThisClass := AClass; ThisTreeNode := Nil; + if AClass.ObjKind = okInterface then + ThisTreeNode := TreeInterface.GetPasElNode(AClass) + else + ThisTreeNode := TreeClass.GetPasElNode(AClass); while True do begin TREl := CreateTR(TableEl); @@ -3412,14 +3418,13 @@ TDEl := CreateTD_vtop(TREl); TDEl['align'] := 'center'; CodeEl := CreateCode(CreatePara(TDEl)); - if Assigned(ThisClass) then - LName:=ThisClass.Name - Else - LName:=ThisNode.Name; + + // Show class item if Assigned(ThisClass) Then - AppendHyperlink(CodeEl, ThisClass) - else - AppendHyperlink(CodeEl, ThisNode); + AppendHyperlink(CodeEl, ThisClass); + //else + // AppendHyperlink(CodeEl, ThisTreeNode); + // Show links to class interfaces if Assigned(ThisClass) and (ThisClass.Interfaces.count>0) then begin for i:=0 to ThisClass.interfaces.count-1 do @@ -3429,48 +3434,28 @@ AppendHyperlink(CodeEl, ThisInterface); end; end; - AppendShortDescrCell(TREl, ThisClass); - if HaveSeenTObject or (CompareText(LName, 'TObject') = 0) then - HaveSeenTObject := True - else - begin - TDEl := CreateTD(CreateTR(TableEl)); - TDEl['align'] := 'center'; - AppendText(TDEl, '|'); - end; + // short class description + if Assigned(ThisClass) then + AppendShortDescrCell(TREl, ThisClass); - if Assigned(ThisClass.AncestorType) then - begin - if ThisClass.AncestorType.InheritsFrom(TPasClassType) then - ThisClass := TPasClassType(ThisClass.AncestorType) - else + if Assigned(ThisTreeNode) then + if Assigned(ThisTreeNode.ParentNode) then begin - if thisclass.ancestortype is TPasUnresolvedTypeRef then - thisnode:=TPasUnresolvedTypeRef(ThisClass.ancestortype); TDEl := CreateTD(CreateTR(TableEl)); TDEl['align'] := 'center'; - AppendText(CreateCode(CreatePara(TDEl)), UTF8Decode(ThisClass.AncestorType.Name)); - if CompareText(ThisClass.AncestorType.Name, 'TObject') = 0 then - HaveSeenTObject := True + AppendText(TDEl, '|'); + ThisClass := ThisTreeNode.ParentNode.Element; + ThisTreeNode := ThisTreeNode.ParentNode; + end else - begin - TDEl := CreateTD(CreateTR(TableEl)); - TDEl['align'] := 'center'; - AppendText(TDEl, '?'); - end; + begin + ThisClass := nil; + ThisTreeNode:= nil; break; end - end else + else break; end; - - if not HaveSeenTObject then - begin - TDEl := CreateTD(CreateTR(TableEl)); - TDEl['align'] := 'center'; - AppendText(CreateCode(CreatePara(TDEl)), 'TObject'); - end; - FinishElementPage(AClass); end; @@ -3847,11 +3832,12 @@ FinishElementPage(AProc); end; -Function THTMLWriter.InterPretOption(Const Cmd,Arg : String) : boolean; +function THTMLWriter.InterPretOption ( const Cmd, Arg: String ) : boolean; Function ReadFile(aFileName : string) : TstringStream; begin + aFileName:= SetDirSeparators(aFileName); try if copy(aFileName,1,1)<>'@' then Result:=TStringStream.Create(aFileName) @@ -3942,7 +3928,7 @@ end; end; -Class Function THTMLWriter.FileNameExtension : String; +class function THTMLWriter.FileNameExtension: String; begin result:=''; end; Index: utils/fpdoc/dw_txt.pp =================================================================== --- utils/fpdoc/dw_txt.pp (revision 47648) +++ utils/fpdoc/dw_txt.pp (working copy) @@ -158,18 +158,19 @@ Var I,L : Integer; - + SP: set of char; begin Result:=0; + SP := [#10,#13,' ',#9]; I:=P; L:=Length(S); - While (I>0) and (I<=L) and not (S[i] in [#10,#13,' ',#9]) do - Dec(i); + While (I>0) and (I<=L) and not (S[i] in SP) do + Dec(I); If (I=0) then begin - I:=P; - While (I<=L) and not (S[i] in [#10,#13,' ',#9]) do - Inc(i); + Inc(I); + While (I<=L) and not (S[I] in SP) do + Inc(I); end; Result:=I; end; @@ -186,7 +187,7 @@ exit; N:=S; Repeat - If ((FCurrentPos+Length(N))>LineWidth) then + If ((FCurrentPos+Length(N)+1)>LineWidth) then begin L:=FindSpace(N,LineWidth-FCurrentPos+1); inherited Write(Copy(N,1,L-1)); @@ -195,8 +196,8 @@ end else begin - L:=Length(N)+1; - inherited Write(Copy(N,1,L-1)); + L:=Length(N); + inherited Write(Copy(N,1,L)); Inc(FCurrentPos,L); If FCheckEOL then If (L>=LEOL) then Index: utils/fpdoc/dwriter.pp =================================================================== --- utils/fpdoc/dwriter.pp (revision 47648) +++ utils/fpdoc/dwriter.pp (working copy) @@ -25,7 +25,7 @@ {$WARN 5024 off : Parameter "$1" not used} interface -uses Classes, DOM, dGlobals, PasTree, SysUtils; +uses Classes, DOM, dGlobals, PasTree, SysUtils, fpdocclasstree; resourcestring SErrFileWriting = 'An error occurred during writing of file "%s": %s'; @@ -80,8 +80,12 @@ FImgExt : String; FBeforeEmitNote : TWriterNoteEvent; procedure ConvertURL(AContext: TPasElement; El: TDOMElement); - + procedure CreateClassTree; protected + TreeClass: TClassTreeBuilder; // Global class tree + TreeInterface: TClassTreeBuilder; // Global interface tree + + procedure AddElementsFromList(L: TStrings; List: TFPList; UsePathName : Boolean = False); Procedure DoLog(Const Msg : String); Procedure DoLog(Const Fmt : String; Args : Array of const); procedure Warning(AContext: TPasElement; const AMsg: String); @@ -339,7 +343,8 @@ } -Constructor TFPDocWriter.Create(APackage: TPasPackage; AEngine: TFPDocEngine); +constructor TFPDocWriter.Create ( APackage: TPasPackage; AEngine: TFPDocEngine + ) ; begin inherited Create; @@ -347,6 +352,9 @@ FPackage := APackage; FTopics:=Tlist.Create; FImgExt:='.png'; + TreeClass:= TClassTreeBuilder.Create(FEngine, FPackage, okClass); + TreeInterface:= TClassTreeBuilder.Create(FEngine, FPackage, okInterface); + CreateClassTree; end; destructor TFPDocWriter.Destroy; @@ -358,6 +366,8 @@ For I:=0 to FTopics.Count-1 do TTopicElement(FTopics[i]).Free; FTopics.Free; + TreeClass.free; + TreeInterface.Free; Inherited; end; @@ -390,7 +400,7 @@ end; end; -Function TFPDocWriter.FindTopicElement(Node : TDocNode): TTopicElement; +function TFPDocWriter.FindTopicElement ( Node: TDocNode ) : TTopicElement; Var I : Integer; @@ -713,6 +723,55 @@ DescrEndURL; end; +procedure TFPDocWriter.AddElementsFromList ( L: TStrings; List: TFPList; + UsePathName: Boolean ) ; +Var + I : Integer; + El : TPasElement; + N : TDocNode; + +begin + For I:=0 to List.Count-1 do + begin + El:=TPasElement(List[I]); + N:=Engine.FindDocNode(El); + if (N=Nil) or (not N.IsSkipped) then + begin + if UsePathName then + L.AddObject(El.PathName,El) + else + L.AddObject(El.Name,El); + If el is TPasEnumType then + AddElementsFromList(L,TPasEnumType(el).Values); + end; + end; +end; + +procedure TFPDocWriter.CreateClassTree; +var + L: TStringList; + M: TPasModule; + I:Integer; +begin + L:=TStringList.Create; + try + For I:=0 to Package.Modules.Count-1 do + begin + M:=TPasModule(Package.Modules[i]); + if Not (M is TPasExternalModule) and assigned(M.InterfaceSection) then + Self.AddElementsFromList(L,M.InterfaceSection.Classes,True) + end; + TreeClass.BuildTree(L); + TreeInterface.BuildTree(L); + {$IFDEF TREE_TEST} + TreeClass.SaveToXml('TreeClass.xml'); + TreeInterface.SaveToXml('TreeInterface.xml'); + {$ENDIF} + Finally + L.Free; + end; +end; + procedure TFPDocWriter.DoLog(const Msg: String); begin If Assigned(FEngine.OnLog) then @@ -1126,7 +1185,7 @@ Result := False; end; -Procedure TFPDocWriter.ConvertImage(El : TDomElement); +procedure TFPDocWriter.ConvertImage ( El: TDomElement ) ; Var FN,Cap,LinkName : DOMString; @@ -1169,7 +1228,7 @@ Inherited; end; -Function TFPDocWriter.WriteDescr(Element: TPasElement) : TDocNode; +function TFPDocWriter.WriteDescr ( Element: TPasElement ) : TDocNode; begin Result:=Engine.FindDocNode(Element); @@ -1211,7 +1270,8 @@ Result:=Not ((M.Visibility=visProtected) and Engine.HideProtected) end; -Procedure TFPDocWriter.GetMethodList(ClassDecl: TPasClassType; List : TStringList); +procedure TFPDocWriter.GetMethodList ( ClassDecl: TPasClassType; + List: TStringList ) ; Var I : Integer; Index: utils/fpdoc/fpdoc.pp =================================================================== --- utils/fpdoc/fpdoc.pp (revision 47648) +++ utils/fpdoc/fpdoc.pp (working copy) @@ -428,6 +428,8 @@ end; begin + //AssignFile(Output, 'fpdoc.log'); + //rewrite(Output); With TFPDocApplication.Create(Nil) do try Run; Index: utils/fpdoc/fpdocclasstree.pp =================================================================== --- utils/fpdoc/fpdocclasstree.pp (revision 47648) +++ utils/fpdoc/fpdocclasstree.pp (working copy) @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, DOM, pastree, contnrs; + Classes, SysUtils, dGlobals, pastree, contnrs, DOM ,XMLWrite; Type @@ -13,16 +13,18 @@ TPasElementNode = Class Private - FElement : TPasElement; + FElement : TPasClassType; + FParentNode: TPasElementNode; FChildren : TFPObjectList; function GetChild(aIndex : Integer): TPasElementNode; function GetChildCount: Integer; Public - Constructor Create (aElement : TPaselement); + Constructor Create (aElement : TPasClassType); Destructor Destroy; override; Procedure AddChild(C : TPasElementNode); Procedure SortChildren; - Property Element : TPasElement Read FElement; + Property Element : TPasClassType Read FElement; + Property ParentNode : TPasElementNode read FParentNode; Property Children [aIndex : Integer] : TPasElementNode Read GetChild; Property ChildCount : Integer Read GetChildCount; end; @@ -31,7 +33,7 @@ TClassTreeBuilder = Class Private - // Full name -> TDomElement; + FEngine:TFPDocEngine; FElementList : TFPObjectHashTable; FObjectKind : TPasObjKind; FPackage: TPasPackage; @@ -38,13 +40,20 @@ FParentObject : TPasClassType; FRootNode : TPasElementNode; FRootObjectName : string; + FRootObjectPathName : string; Protected function AddToList(aElement: TPasClassType): TPasElementNode; Public - Constructor Create(APackage : TPasPackage; AObjectKind : TPasObjKind = okClass); + Constructor Create(AEngine:TFPDocEngine; APackage : TPasPackage; + AObjectKind : TPasObjKind = okClass); Destructor Destroy; override; Function BuildTree(AObjects : TStringList) : Integer; +{$IFDEF TREE_TEST} + Procedure SaveToXml(AFileName: String); +{$ENDIF} Property RootNode : TPasElementNode Read FRootNode; + Property PasElToNodes: TFPObjectHashTable read FElementList; + function GetPasElNode (APasEl: TPasElement) : TPasElementNode; end; implementation @@ -72,7 +81,7 @@ Result:=0 end; -constructor TPasElementNode.Create(aElement: TPaselement); +constructor TPasElementNode.Create(aElement: TPasClassType); begin FElement:=aElement; end; @@ -96,24 +105,38 @@ FChildren.Sort(@SortOnElementName); end; -constructor TClassTreeBuilder.Create(APackage : TPasPackage; +constructor TClassTreeBuilder.Create(AEngine:TFPDocEngine; APackage : TPasPackage; AObjectKind: TPasObjKind); begin - FPackage:=APAckage; + FEngine:= AEngine; + FPackage:= APAckage; FObjectKind:=AObjectKind; Case FObjectkind of - okInterface : FRootObjectName:='#rtl.System.IInterface'; - okObject, - okClass : FRootObjectName:='#rtl.System.TObject'; + okInterface : + begin + FRootObjectPathName:='#rtl.System.IInterface'; + FRootObjectName:= 'IInterface'; + end; + okObject, okClass : + begin + FRootObjectPathName:='#rtl.System.TObject'; + FRootObjectName:= 'TObject'; + end else - FRootObjectName:='#rtl.System.TObject'; + begin + FRootObjectPathName:='#rtl.System.TObject'; + FRootObjectName:= 'TObject'; + end; end; - FParentObject:=TPasClassType.Create(FRootObjectName,FPackage); + FParentObject:=TPasClassType.Create(FRootObjectName,FEngine.FindModule('System')); + if not Assigned(FParentObject) then + FParentObject:=TPasClassType.Create(FRootObjectName,FPackage); FParentObject.ObjKind:=FObjectKind; FRootNode:=TPasElementNode.Create(FParentObject); + FRootNode.FParentNode := nil; FElementList:=TFPObjectHashTable.Create(False); - FElementList.Add(FRootObjectName,FRootNode); + FElementList.Add(FRootObjectPathName,FRootNode); end; destructor TClassTreeBuilder.Destroy; @@ -124,7 +147,8 @@ Inherited; end; -Function TClassTreeBuilder.AddToList(aElement : TPasClassType) : TPasElementNode; +function TClassTreeBuilder.AddToList ( aElement: TPasClassType + ) : TPasElementNode; Var aParentNode : TPasElementNode; @@ -131,27 +155,29 @@ aName : String; begin + Result:= nil; + if (aElement.ObjKind <> FObjectKind) then exit; + aParentNode:= nil; if aElement=Nil then aName:=FRootObjectName else - begin aName:=aElement.PathName; - end; Result:=TPasElementNode(FElementList.Items[aName]); if (Result=Nil) then - begin + begin if aElement.AncestorType is TPasClassType then - aParentNode:=AddToList(aElement.AncestorType as TPasClassType) - else + aParentNode:=AddToList(aElement.AncestorType as TPasClassType); + if not Assigned(aParentNode) then aParentNode:=FRootNode; Result:=TPasElementNode.Create(aElement); aParentNode.AddChild(Result); + Result.FParentNode := aParentNode; FElementList.Add(aName,Result); - end; + end; end; -Function TClassTreeBuilder.BuildTree(AObjects : TStringList) : Integer; +function TClassTreeBuilder.BuildTree ( AObjects: TStringList ) : Integer; (* Procedure DumpNode(Prefix : String; N : TPasElementNode); @@ -182,7 +208,63 @@ end; end; +function TClassTreeBuilder.GetPasElNode ( APasEl: TPasElement + ) : TPasElementNode; +begin + Result:= TPasElementNode(FElementList.Items[APasEl.PathName]); +end; +procedure TClassTreeBuilder.SaveToXml ( AFileName: String ) ; + procedure AddPasElChildsToXml (ParentxmlEl : TDOMElement ; ParentPasEl: TPasElementNode ) ; + var + CounterVar: Integer; + PasElNode: TPasElementNode; + AXmlDoc: TDOMDocument; + xmlEl: TDOMElement; + M: TPasModule; + begin + if not Assigned(ParentPasEl) or (ParentPasEl.ChildCount = 0) then exit; + AXmlDoc:= ParentxmlEl.OwnerDocument; + for CounterVar := 0 to ParentPasEl.ChildCount-1 do + begin + PasElNode:= ParentPasEl.Children[CounterVar]; + xmlEl:= AXmlDoc.CreateElement(UnicodeString(PasElNode.Element.Name)); + M:= PasElNode.Element.GetModule; + xmlEl['unit'] := UnicodeString(M.Name); + xmlEl['package'] := UnicodeString(M.PackageName); + ParentxmlEl.AppendChild(xmlEl); + AddPasElChildsToXml(xmlEl, PasElNode); + end; + end; + +var + XmlDoc: TXMLDocument; + XmlRootEl: TDOMElement; + M: TPasModule; +begin + XmlDoc:= TXMLDocument.Create; + try + XmlRootEl:= XmlDoc.CreateElement(UnicodeString(FRootNode.Element.Name)); + M:= FRootNode.Element.GetModule; + if Assigned(M) then + begin + XmlRootEl['unit'] := UnicodeString(M.Name); + XmlRootEl['package'] := UnicodeString(M.PackageName); + end + else + begin + XmlRootEl['unit'] := 'system'; + XmlRootEl['package'] := 'rtl'; + end; + XmlDoc.AppendChild(XmlRootEl); + AddPasElChildsToXml(XmlRootEl, FRootNode); + WriteXMLFile(XmlDoc, AFileName); + finally + XmlDoc.Free; + end; +end; + + end. Index: utils/fpdoc/mkfpdoc.pp =================================================================== --- utils/fpdoc/mkfpdoc.pp (revision 47648) +++ utils/fpdoc/mkfpdoc.pp (working copy) @@ -42,6 +42,8 @@ procedure SetVerbose(AValue: Boolean); virtual; Procedure DoLog(Const Msg : String); procedure DoLog(Const Fmt : String; Args : Array of Const); + Procedure DoLogSender(Sender : TObject; Const Msg : String); + // Create documetation by specified Writer class procedure CreateOutput(APackage: TFPDocPackage; Engine: TFPDocEngine); virtual; Public Constructor Create(AOwner : TComponent); override; @@ -96,6 +98,14 @@ DoLog(Format(Fmt,Args)); end; +procedure TFPDocCreator.DoLogSender ( Sender: TObject; const Msg: String ) ; +begin + if Assigned(Sender) then + DoLog(Format('%s - Sender: %s', [Msg, Sender.ClassName])) + else + DoLog(Msg); +end; + procedure TFPDocCreator.HandleOnParseUnit(Sender: TObject; const AUnitName: String; out AInputFile, OSTarget, CPUTarget: String); @@ -208,7 +218,9 @@ Cmd,Arg : String; begin + // Now is used the specified writer WriterClass:=GetWriterClass(Options.Backend); + // ALL CONTENT CREATED HERE Writer:=WriterClass.Create(Engine.Package,Engine); With Writer do Try @@ -225,10 +237,12 @@ If not InterPretOption(Cmd,Arg) then DoLog(SCmdLineInvalidOption,[Cmd+'='+Arg]); end; + // Output created Documentation WriteDoc; Finally Free; end; + // Output content files Writeln('Content file : ',APackage.ContentFile); if Length(APackage.ContentFile) > 0 then Engine.WriteContentFile(APackage.ContentFile); @@ -247,16 +261,21 @@ Cmd:=''; FCurPackage:=APackage; Engine:=TFPDocEngine.Create; + Engine.OnLog:= @DoLogSender; try + // get documentation Writer html, latex, and other WriterClass:=GetWriterClass(Options.Backend); For J:=0 to Apackage.Imports.Count-1 do begin Arg:=Apackage.Imports[j]; + // conversion import FilePathes WriterClass.SplitImport(Arg,Cmd); + // create tree of imported objects Engine.ReadContentFile(Arg, Cmd); end; for i := 0 to APackage.Descriptions.Count - 1 do Engine.AddDocFile(FixDescrFile(APackage.Descriptions[i]),Options.donttrim); + // set engine options Engine.SetPackageName(APackage.Name); Engine.Output:=APackage.Output; Engine.OnLog:=Self.OnLog; @@ -268,13 +287,18 @@ Engine.WarnNoNode:=Options.WarnNoNode; if Length(Options.Language) > 0 then TranslateDocStrings(Options.Language); + // scan the input source files for i := 0 to APackage.Inputs.Count - 1 do try + // get options from input packages SplitInputFileOption(APackage.Inputs[i],Cmd,Arg); + // make absolute filepath Cmd:=FixInputFile(Cmd); if FProcessedUnits.IndexOf(Cmd)=-1 then begin FProcessedUnits.Add(Cmd); + // Parce sources for OS Target + //WriteLn(Format('Parcing unit: %s', [ExtractFilenameOnly(Cmd)])); ParseSource(Engine,Cmd+' '+Arg, Options.OSTarget, Options.CPUTarget,[poUseStreams]); end; except @@ -290,6 +314,7 @@ if Not ParseOnly then begin Engine.StartDocumenting; + // Create documentation CreateOutput(APackage,Engine); end; finally patch_fpdoc_description_02_en.txt (3,231 bytes)
Fix Description. I apologize that I was placed a lot in this patch, but almost everything does not work separately. If you say that you need to divide on the parts, then I will do it. But I did not have the opportunity to make intermediate fixations in repo. Changes: 1. Correction of the generation of XCT files. Unit dGlobal.pp. Now all classes have only full FilePath with the package name. FUNSTION - TFPDOCENGINE.WRIPECONTENTFILE() 2. Small fixing of the assembly link to the internal pages FUNCTION - TFPDOCENGINE.REDCONTENTFILE LINES 719 - 720. 3. Remake the classes tree for the pages of the classes hierarchy. Here are great changes. Unit Fpdocclasstree. Now this class is used for building the class pages. Two Instance of this class are created in TFPDocWriter. Now trees (TreeClasse, TreeInterface) is available for another writer classes. An example of a tree for my test is attached. (TreeClass.xml, TreeInterface.xml) OutPut of that class will be used by TXMLWriter. 4. Remake the page with the display hierarchy of classes for the entire package. 5. Remake the main page of the class display page, so that there were no passages of the hierarchy. Use the Fpdocclasstree classe. DW_HTML.PP Procedure CreatemainPage; 6. Fix small exception ino dw_txt.pas 7. After fixing the XCT file and some functions, all methods and properties of the ancestors appeared in all pages of Class-Functions Class-Properties Class-Events. After it, the chm file and the full-text index grew very much. Also began to load Lhelp for a long time. These pages not have a title and are useless for the index, so I tried to turn them off from full-text search. But in Packages / CHM / SRC / CHMWRITER.PAS, there is no possibility to remove some files from full-text search, you can only turn off all files. Here I apologize, I made a hack, you decide. But if this is not done, then everything made will be useless. I added to Packages/CHM/SRC/CHMWRITER.PAS the hack code. The exclution of files from a full-text index if they start from the point. That in general logical and then it will be possible to exclude other index pages. As a result, full-text search became beautiful. I don`t know how to do that another. I didn`t want use external index for that. 8. Change in the upper bar, because it was very difficult to understande where I am now. Now I obviously signed when I displays the data of the unit or package. DW_HTML.PP - Thtmlwriter.APPendMenubar 9. Misc - The situation with the RTF format is incomprehensible, it does not open with me. - Also attached the generated tree objects for the classes hierarchy (TreeClass.xml, TreeInterface.xml) - An XML mode produces exception when I start without created before an output directory (need to add the directory creation before output). Attached: - The test files TXT, IPF, MAN, CHTM, HTML modes, and a new LCL.CHM as an example. - I have no opportunity to check LATEX on Windows, but the machine with Linux has already collected. - New rtl.xct fcl.xct Files: https://drive.google.com/file/d/1myUOZGsGTl42aaji68WC6G0XczUZaT19/view?usp=sharing I hope that you can allocate time to work with this FIX. Andrey Sobol. |
|
Again: the "." search modification is not necessary in chmwriter, which is general code. chmwriter.fileadd can be overriden in a fpdoc dependent derived class if need be. |
|
Ok, I will change that. |
|
Applied what could be applied in rev 47710. Your code did not compile: * fpclasschart didn't compile, you added an engine argument to class tree builder constructor * visibility names missed 2 elements (required, optional) * missing IFDEF TEST_TREE around SaveToXML method implementation. After fixing that and a cosmetic change in output, all seems to work for html. Thank you for your efforts ! I'm not closing this yet, so you can create a proper patch for the chm writer. |
|
I will watch yours changes. Thank you for yours spent time. |
|
The patch for exclude the chmWriter dependency. I want check the docs more thoroughly when I will have a linux machine and full build of docs. How is better to send changes. By issue only? In advance thank for answer. Andrey. patch_fpdoc_03.patch (1,905 bytes)
Index: dw_html.pp =================================================================== --- dw_html.pp (revision 47710) +++ dw_html.pp (working copy) @@ -19,7 +19,7 @@ {$WARN 5024 off : Parameter "$1" not used} interface -uses Classes, DOM, DOM_HTML, dGlobals, PasTree, dWriter, ChmWriter; +uses Classes, DOM, DOM_HTML, dGlobals, PasTree, dWriter, ChmWriter, chmtypes; const // Subpage indices for modules Index: dw_htmlchm.inc =================================================================== --- dw_htmlchm.inc (revision 47710) +++ dw_htmlchm.inc (working copy) @@ -2,12 +2,19 @@ {$IFDEF chmInterface} type + { TFpDocChmWriter } + + TFpDocChmWriter = class (TChmWriter) + protected + procedure FileAdded(AStream: TStream; const AEntry: TFileEntryRec); override; + end; + { TCHMHTMLWriter } TCHMHTMLWriter = class(THTMLWriter) private FOutChm: TStream; - FChm: TChmWriter; + FChm: TFpDocChmWriter; FTempUncompressed: TStream; FTempUncompressedName: String; FChmTitle: String; @@ -37,6 +44,17 @@ end; {$ELSE} // implementation +{ TFpDocChmWriter } + +procedure TFpDocChmWriter.FileAdded ( AStream: TStream; + const AEntry: TFileEntryRec ) ; +begin + // Exclude Full text index for files starting from the dot + if Pos('.', AEntry.Name) <> 1 then + inherited FileAdded(AStream, AEntry); + +end; + { TCHMHTMLWriter } function TCHMHTMLWriter.ResolveLinkIDAbs(const Name: String; Level : Integer = 0): DOMString; @@ -466,7 +484,7 @@ FTempUncompressedName := GetTempFileName+IntToStr(GetProcessID) +'.raw'; FTempUncompressed := TFileStream.Create(FTempUncompressedName, fmOpenReadWrite or fmCreate); - FChm := TChmWriter.Create(FOutChm, False); + FChm := TFpDocChmWriter.Create(FOutChm, False); FChm.Title := FChmTitle; FChm.TempRawStream := FTempUncompressed; FChm.OnGetFileData := @RetrieveOtherFiles; |
|
Updated chms and object tree dependencies looks fine: http://www.stack.nl/~marcov/doc-chm.zip |
|
Send me please xct files also |
|
We will have a clean search result when you apply the last patch. |
|
Andrey they are in the http://www.stack.nl/~marcov/doc-chmbeta.zip archive, which also contains lazutils/lcl |
|
User guide (user.chm) Contents page <meta content="text/html; charset=iso8859-1" http-equiv="Content-Type"> <div class="author"><span class="cmss-12">Micha</span><span class="cmss-12">?l Van Canneyt</span><br class="newline"><span class="cmss-12">Florian Kl</span><span class="cmss-12">?mpfl</span></div> <br class="newline">____________________________________________________________________________ Non-ASCII characters missed, and replaced by SPAN tag. |
|
How is it joined to this issue? It was and before. You can change it or open new issue. |
|
serbod I think that is the latex->html conversion, and not the archiving of the result. But I can have a look, please file a separate issue. |
|
Submitted as 0038184 |
|
Applied your latest patch. Please test and close if OK. Thank you for your efforts, it is a real improvement ! |
|
That is fine :) Index includes only usefull info. Thank you for spent your time. |
Date Modified | Username | Field | Change |
---|---|---|---|
2020-11-27 20:09 | Andrey Sobol | New Issue | |
2020-11-27 20:09 | Andrey Sobol | File Added: 2020-11-03 16_22_17-LHelp - (FCL) Free Component Library [(FCL) Free Pascal Resources support, FPDoc.jpg | |
2020-11-27 20:09 | Andrey Sobol | File Added: 2020-11-27 21_28_39-(RTL) Runtime Library.jpg | |
2020-11-27 20:09 | Andrey Sobol | File Added: 2020-11-27 21_43_34-mk_@MSITStore_M__lazarus_docs_chm_fcl.chm___iostream_eiostreamerror-3.html - Int.jpg | |
2020-11-27 21:31 | Marco van de Voort | Note Added: 0127215 | |
2020-11-27 21:38 | Andrey Sobol | Note Added: 0127216 | |
2020-11-27 21:44 | Marco van de Voort | Note Added: 0127217 | |
2020-11-27 23:11 | Marco van de Voort | Note Added: 0127218 | |
2020-11-28 00:55 | Michael Van Canneyt | Assigned To | => Michael Van Canneyt |
2020-11-28 00:55 | Michael Van Canneyt | Status | new => assigned |
2020-11-28 01:03 | Michael Van Canneyt | Note Added: 0127221 | |
2020-11-28 05:14 | Marco van de Voort | Note Added: 0127222 | |
2020-11-28 09:37 | Andrey Sobol | Note Added: 0127225 | |
2020-11-28 10:04 | Andrey Sobol | Note Edited: 0127225 | View Revisions |
2020-11-28 10:42 | Michael Van Canneyt | Note Added: 0127229 | |
2020-11-28 10:43 | Michael Van Canneyt | Note Edited: 0127229 | View Revisions |
2020-11-29 13:05 | Marco van de Voort | Note Added: 0127255 | |
2020-11-30 19:14 | Andrey Sobol | Note Added: 0127272 | |
2020-11-30 19:14 | Andrey Sobol | File Added: patch_fpdoc_01.patch | |
2020-11-30 19:14 | Andrey Sobol | File Added: patch_fpdoc_description_01_en.txt | |
2020-11-30 19:34 | Michael Van Canneyt | Note Added: 0127273 | |
2020-11-30 19:34 | Michael Van Canneyt | Status | assigned => feedback |
2020-11-30 19:34 | Michael Van Canneyt | FPCTarget | => - |
2020-11-30 20:32 | Andrey Sobol | Note Added: 0127277 | |
2020-11-30 20:32 | Andrey Sobol | Status | feedback => assigned |
2020-11-30 20:35 | Andrey Sobol | Note Added: 0127278 | |
2020-11-30 21:04 | Andrey Sobol | Note Edited: 0127278 | View Revisions |
2020-12-01 10:06 | Michael Van Canneyt | Note Added: 0127287 | |
2020-12-01 17:10 | Marco van de Voort | Note Added: 0127304 | |
2020-12-01 17:19 | Andrey Sobol | Note Added: 0127305 | |
2020-12-02 18:52 | Andrey Sobol | Note Added: 0127322 | |
2020-12-02 18:52 | Andrey Sobol | File Added: patch_fpdoc_02.patch | |
2020-12-02 18:52 | Andrey Sobol | File Added: patch_fpdoc_description_02_en.txt | |
2020-12-02 18:59 | Andrey Sobol | Note Edited: 0127322 | View Revisions |
2020-12-02 19:00 | Andrey Sobol | Note Edited: 0127322 | View Revisions |
2020-12-03 10:41 | Andrey Sobol | Note Edited: 0127322 | View Revisions |
2020-12-06 21:30 | Marco van de Voort | Note Added: 0127384 | |
2020-12-07 05:11 | Andrey Sobol | Note Added: 0127390 | |
2020-12-07 13:01 | Michael Van Canneyt | Note Added: 0127414 | |
2020-12-07 14:31 | Andrey Sobol | Note Added: 0127420 | |
2020-12-07 14:32 | Andrey Sobol | Note Edited: 0127420 | View Revisions |
2020-12-07 14:38 | Andrey Sobol | Note Edited: 0127420 | View Revisions |
2020-12-07 14:39 | Andrey Sobol | Note Edited: 0127420 | View Revisions |
2020-12-07 19:08 | Andrey Sobol | Note Added: 0127429 | |
2020-12-07 19:08 | Andrey Sobol | File Added: patch_fpdoc_03.patch | |
2020-12-07 21:28 | Marco van de Voort | Note Added: 0127435 | |
2020-12-07 21:38 | Andrey Sobol | Note Added: 0127436 | |
2020-12-07 21:50 | Andrey Sobol | Note Added: 0127438 | |
2020-12-07 21:50 | Andrey Sobol | File Added: 2020-12-07 23_41_52-LHelp - test [(FCL) Free Component Library, My FCL-image, (FCL) Free Pascal Reso-2.jpg | |
2020-12-07 23:09 | Marco van de Voort | Note Added: 0127439 | |
2020-12-08 08:11 | serbod | Note Added: 0127442 | |
2020-12-08 08:47 | Andrey Sobol | Note Added: 0127444 | |
2020-12-08 09:39 | Marco van de Voort | Note Added: 0127446 | |
2020-12-08 10:07 | serbod | Note Added: 0127447 | |
2020-12-08 10:50 | Michael Van Canneyt | Status | assigned => resolved |
2020-12-08 10:50 | Michael Van Canneyt | Resolution | open => fixed |
2020-12-08 10:50 | Michael Van Canneyt | Fixed in Version | => 3.3.1 |
2020-12-08 10:50 | Michael Van Canneyt | Fixed in Revision | => 47719 |
2020-12-08 10:50 | Michael Van Canneyt | FPCTarget | - => 3.2.2 |
2020-12-08 10:50 | Michael Van Canneyt | Note Added: 0127450 | |
2020-12-08 14:14 | Andrey Sobol | Note Added: 0127456 | |
2020-12-08 14:14 | Andrey Sobol | File Added: 2020-12-08 16_11_32-Lazarus IDE v2.0.11 - FPDoc Documentation generator.jpg | |
2020-12-08 14:14 | Andrey Sobol | File Added: 2020-12-08 16_10_39-Lazarus IDE v2.0.11 - FPDoc Documentation generator.jpg | |
2020-12-26 21:41 | Juha Manninen | Relationship added | related to 0038250 |