fpdocmanager heavily refactored.

git-svn-id: trunk@34675 -
This commit is contained in:
dodi 2012-01-09 11:10:32 +00:00
parent 10c51b2e9e
commit 3066c21737
11 changed files with 789 additions and 461 deletions

1
.gitattributes vendored
View File

@ -3711,7 +3711,6 @@ examples/fpdocmanager/fmain.pas svneol=native#text/pascal
examples/fpdocmanager/fpdocengine.lpk svneol=native#text/plain
examples/fpdocmanager/fupdateview.lfm svneol=native#text/plain
examples/fpdocmanager/fupdateview.pas svneol=native#text/pascal
examples/fpdocmanager/ucmdline.pas svneol=native#text/pascal
examples/fpdocmanager/ulpk.pp svneol=native#text/pascal
examples/fpdocmanager/umakeskel.pas svneol=native#text/pascal
examples/fpdocmanager/umanager.pas svneol=native#text/pascal

View File

@ -11,6 +11,7 @@
<UseXPManifest Value="True"/>
<Icon Value="0"/>
</General>
<LazDoc Paths="docs"/>
<i18n>
<EnableI18N LFM="False"/>
</i18n>
@ -42,7 +43,7 @@
<PackageName Value="LCL"/>
</Item3>
</RequiredPackages>
<Units Count="10">
<Units Count="9">
<Unit0>
<Filename Value="FPDocManager.lpr"/>
<IsPartOfProject Value="True"/>
@ -63,44 +64,39 @@
<UnitName Value="fConfig"/>
</Unit2>
<Unit3>
<Filename Value="ucmdline.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="uCmdLine"/>
</Unit3>
<Unit4>
<Filename Value="umakeskel.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="umakeskel"/>
</Unit4>
<Unit5>
</Unit3>
<Unit4>
<Filename Value="umanager.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="uManager"/>
</Unit5>
<Unit6>
</Unit4>
<Unit5>
<Filename Value="flogview.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="LogView"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="fLogView"/>
</Unit6>
<Unit7>
</Unit5>
<Unit6>
<Filename Value="fupdateview.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="UpdateView"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="fUpdateView"/>
</Unit7>
<Unit8>
</Unit6>
<Unit7>
<Filename Value="ulpk.pp"/>
<IsPartOfProject Value="True"/>
<UnitName Value="uLpk"/>
</Unit8>
<Unit9>
</Unit7>
<Unit8>
<Filename Value="$(FPCDir)\utils\fpdoc\dw_html.pp"/>
<IsPartOfProject Value="True"/>
<UnitName Value="dw_HTML"/>
</Unit9>
</Unit8>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -7,7 +7,7 @@ uses
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, dw_HTML, umakeskel, fMain, fConfig, uCmdLine, uManager, fLogView,
Forms, dw_HTML, umakeskel, fMain, fConfig, uManager, fLogView,
fUpdateView, ulpk;
{$R *.res}

View File

@ -9,6 +9,11 @@ A package FPDocEngine is supplied for use in commandline or GUI applications.
uMakeSkel is a copy of parts of the FPDoc and MakeSkel programs, modified
with workarounds for known problems with these FPC tools.
Organization
------------
A dedicated directory contains all package specifications and documentation.
INI files are created for the manager itself and every package.
Release notes 1.0
-----------------

View File

@ -50,8 +50,8 @@ object CfgWizard: TCfgWizard
end
object SelFPDir: TTabSheet
Caption = 'FPC'
ClientHeight = 195
ClientWidth = 312
ClientHeight = 213
ClientWidth = 310
OnShow = SelFPDirShow
object Label2: TLabel
Left = 10
@ -83,7 +83,7 @@ object CfgWizard: TCfgWizard
Left = 100
Height = 23
Top = 144
Width = 200
Width = 198
Anchors = [akTop, akLeft, akRight]
OnChange = edFpcDirChange
TabOrder = 2
@ -102,6 +102,7 @@ object CfgWizard: TCfgWizard
Caption = 'RTL'
ClientHeight = 213
ClientWidth = 310
OnShow = MkRTLShow
object Label3: TLabel
Left = 10
Height = 136

View File

@ -48,10 +48,11 @@ type
procedure edRootChange(Sender: TObject);
procedure edRtlBatChange(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure MkRTLShow(Sender: TObject);
procedure SelFPDirShow(Sender: TObject);
procedure SelRootShow(Sender: TObject);
private
{ private declarations }
NoRun: boolean;
public
{ public declarations }
end;
@ -62,7 +63,7 @@ var
implementation
uses
uManager, uCmdLine;
uManager;
{$R *.lfm}
@ -95,6 +96,14 @@ begin
Steps.ActivePage := SelRoot;
end;
procedure TCfgWizard.MkRTLShow(Sender: TObject);
begin
NoRun:=True; //lock updates!
edRtlBat.Text := Manager.Packages.Values['rtl'];
edFclBat.Text := Manager.Packages.Values['fcl'];
NoRun:=False;
end;
procedure TCfgWizard.SelFPDirShow(Sender: TObject);
begin
edFpcDir.Text := Manager.FpcDocDir;
@ -120,7 +129,9 @@ begin
fn := ed.Text;
if fn = '' then
exit;
uCmdLine.CmdToPrj(fn);
//uCmdLine.CmdToPrj(fn);
if not NoRun then
Manager.ImportCmd(fn);
end;
procedure TCfgWizard.buFclBatClick(Sender: TObject);

View File

@ -129,6 +129,7 @@ begin
end;
end;
end;
//UpdateDocs; //package objects seem to be missing?
end;
procedure TMain.FormResize(Sender: TObject);
@ -255,8 +256,10 @@ var
i: integer;
begin
lbPackages.Clear;
for i := 0 to Manager.Projects.Count - 1 do begin
lbPackages.AddItem(Manager.Projects.Names[i], Manager.Projects.Objects[i]);
for i := 0 to Manager.Packages.Count - 1 do begin
if (Manager.Packages.ValueFromIndex[i] <> '')
and (Manager.Packages.Objects[i] <> nil) then
lbPackages.AddItem(Manager.Packages.Names[i], Manager.Packages.Objects[i]);
end;
end;

View File

@ -1,57 +0,0 @@
unit uCmdLine;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
function CmdToPrj(const AFileName: string): boolean;
implementation
uses
uManager, umakeskel;
(* Create an project file from an FPDoc commandline
*)
function CmdToPrj(const AFileName: string): boolean;
var
lst: TStringList;
l, w: string;
prj: TFPDocMaker;
begin
(* Need a temporary project, that only includes the given files etc.
*)
Result := False; //in case of errors
lst := TStringList.Create;
prj := TFPDocMaker.Create(nil);
//prj.OnLog := @prj.LogToStdOut; -->ShowMsg???
try
lst.LoadFromFile(AFileName);
l := lst[0];
w := GetNextWord(l);
if w <> 'fpdoc' then
exit; //expected fpdoc command
while l <> '' do begin
w := GetNextWord(l);
prj.ParseFPDocOption(w);
end;
w := prj.SelectedPackage.Name;
if w = '' then
exit; //no project name???
l := ChangeFileExt(AFileName, '_prj.xml'); //same directory!!!
Result := prj.CreateProject(l, prj.SelectedPackage);
//now load the project into the manager
if Result then
//add package/project to the manager
Manager.AddProject(w, l, True); //.Packages.Add(w + '=' + l);
finally
prj.Free;
lst.Free;
end;
end;
end.

View File

@ -20,22 +20,22 @@ uses
Classes, SysUtils,
uManager;
//function ImportLpk(const AFile: string): boolean;
function ImportLpk(const AFile: string): TDocPackage;
//function ImportCompiled(const LpkFile: string): boolean;
implementation
//uses
type
eKey = (kvEof, kvName, kvIncl, kvOther, kvFilename, kvDocPaths, kvReq
eKey = (kvEof, kvName, kvIncl, kvOther, kvFilename, kvDocPaths, kvReq, kvTitle
);
const
aKey: array[eKey] of string = (
'', 'Name', 'IncludeFiles', 'OtherUnitFiles',
'Filename', 'LazDoc' ,'PackageName'
'Filename', 'LazDoc' ,'PackageName', 'Title'
);
FirstKeys = 'NIOFLP';
FirstKeys = 'NIOFLPT';
var
f: TextFile;
@ -59,6 +59,7 @@ begin
//parse
ReadLn(f, ln);
//todo...
//ImportCommandline (CmdToPrj?)
finally
CloseFile(f);
end;
@ -79,8 +80,10 @@ begin
if i < 1 then
continue;
key := eKey(i);
if Copy(ln, lt+1, Length(aKey[key])) <> aKey[key] then
continue;
if CompareText(Copy(ln, lt+1, Length(aKey[key])), aKey[key]) <> 0 then
continue; //diff. case in "FileName", "Filename"
if key = kvTitle then
key := kvName; //LPR
//check value
eq := Pos('=', ln);
if (eq <= lt) or (ln[eq+1] <> '"') then
@ -97,6 +100,7 @@ end;
function ImportLpk(const AFile: string): TDocPackage;
var
pkg: TDocPackage;
dir: string;
begin
Result := Nil; // False; //assume fail
AssignFile(f, AFile);
@ -112,7 +116,8 @@ begin
value := 'lcl';
pkg := Manager.AddPackage(value);
pkg.LazPkg := AFile;
//Manager.Package := pkg; //!DocPkg
dir := ExtractFilePath(AFile);
pkg.ProjectDir := dir; //ChDir on exec
//remaining keys
while GetLine do begin
case key of
@ -121,18 +126,14 @@ begin
kvOther: pkg.UnitPath := value;
kvFilename:
begin
if not FileExists(dir + value) then
continue;
ext := ExtractFileExt(value);
if (ext = '.pas') or (ext = '.pp') then
pkg.Units.Add(value); //!!! no dupes!?
end;
kvDocPaths: pkg.DescrDir := value;
kvReq: pkg.Requires.Add(LowerCase(value));
{
begin
ext := Manager.RootDir + '/' + value + ',../' + value;
pkg.Imports.Add(ext);
end;
}
end;
end;
Result := pkg; // True;

View File

@ -65,10 +65,17 @@ resourcestring
SCreatingNewNode = 'Creating documentation for new node : %s';
SNodeNotReferenced = 'Documentation node "%s" no longer used';
SDone = 'Done.';
//from fpdocxmlopts
SErrInvalidRootNode = 'Invalid options root node: Got "%s", expected "docproject"';
SErrNoPackagesNode = 'No "packages" node found in docproject';
type
TCmdLineAction = (actionHelp, actionConvert);
(* EngineOptions plus MakeSkel options.
Used in the commandline parsers, passed to the Engine.
Project.Options are ignored by TFDocMaker.(?)
*)
TCmdOptions = class(TEngineOptions)
public
WriteDeclaration,
@ -157,7 +164,6 @@ type
destructor Destroy; override;
procedure AddDirToFileList(List: TStrings; const ADirName, AMask: String);
procedure AddToFileList(List: TStrings; const FileName: String);
function UnitName(AList: TStrings; AIndex: integer): string;
function UnitSpec(AUnit: string): string;
function ImportName(AIndex: integer): string;
procedure LogToStdOut(Sender: TObject; const msg: string);
@ -166,8 +172,10 @@ type
function ParseFPDocOption(const S: string): TCreatorAction;
function ParseUpdateOption(const S: string): TCreatorAction;
function CheckSkelOptions: string;
function CreateProject(const AFileName: string; APackage: TFPDocPackage): boolean; virtual;
function CleanXML(const FileName: string): boolean;
{$IFDEF v0}
function CreateProject(const AFileName: string; APackage: TFPDocPackage): boolean; virtual;
procedure LoadXMLProject(const AFileName: string);
function ParseOption(const S: string): TCreatorAction;
function Exec: string;
{$ELSE}
@ -201,81 +209,27 @@ var
{$ELSE}
{$ENDIF}
//Extract next commandline option from a string
Function GetNextWord(Var s : string) : String;
//Get package name from Imports spec
function ExtractImportName(const s: string): string;
//Get Unit filename from Inputs or Descriptions
function UnitFile(AList: TStrings; AIndex: integer): string;
//Get Unit name from Inputs or Descriptions
function ExtractUnitName(AList: TStrings; AIndex: integer): string;
function ExtractUnitName(s: string): string;
implementation
uses
dom,
dWriter, fpdocxmlopts;
dWriter;
type
(* special save/load options
(* Extract (remove!) next commandline option from a string.
Handle quoted arguments, but do not unquote.
Option may be partially quoted, e.g. -opt="arg with blanks"
*)
{ TXMLPackageOptions }
TXMLPackageOptions = class(TXMLFPDocOptions)
public
Pkg: TFPDocPackage;
procedure SaveOptionsToFile(AProject: TFPDocProject; const AFileName: String; APackage: TFPDocPackage);
procedure SaveToXML(AProject: TFPDocProject; ADoc: TXMLDocument); override;
end;
TNodePair = Class(TObject)
Private
FEl : TPasElement;
FNode : TDocNode;
Public
Constructor Create(AnElement : TPasElement; ADocNode : TDocNode);
Property Element : TPasElement Read FEl;
Property DocNode : TDocNode Read FNode;
end;
{ TXMLPackageOptions }
procedure TXMLPackageOptions.SaveOptionsToFile(AProject: TFPDocProject;
const AFileName: String; APackage: TFPDocPackage);
begin
Pkg := APackage; //for use in SaveXML
inherited SaveOptionsToFile(AProject, AFileName);
end;
procedure TXMLPackageOptions.SaveToXML(AProject: TFPDocProject;
ADoc: TXMLDocument);
var
i: integer;
E,PE: TDOMElement;
begin
if false then inherited SaveToXML(AProject, ADoc);
E:=ADoc.CreateElement('docproject');
ADoc.AppendChild(E);
E:=ADoc.CreateElement('options');
ADoc.DocumentElement.AppendChild(E);
SaveEngineOptions(AProject.Options,ADoc,E);
E:=ADoc.CreateElement('packages');
ADoc.DocumentElement.AppendChild(E);
if assigned(Pkg) then begin
PE:=ADoc.CreateElement('package');
E.AppendChild(PE);
SavePackage(Pkg,ADoc,PE);
end else begin
for i := 0 to AProject.Packages.Count - 1 do
begin
PE:=ADoc.CreateElement('package');
E.AppendChild(PE);
SavePackage(AProject.Packages[i],ADoc,PE);
end;
end;
end;
Constructor TNodePair.Create(AnElement : TPasElement; ADocNode : TDocNode);
begin
Fel:=Anelement;
FNode:=ADocNode;
end;
Function GetNextWord(Var s : string) : String;
Const
WhiteSpace = [' ',#9,#10,#13];
@ -306,6 +260,69 @@ begin
Delete(S,1,J);
end;
function ExtractImportName(const s: string): string;
var
i: integer;
begin
Result := s;
i := Pos(',', Result);
if i > 1 then
SetLength(Result, i-1);
Result := ChangeFileExt(ExtractFileName(Result), '');
end;
function ExtractUnitName(s: string): string;
begin
Result := ChangeFileExt(ExtractFileName(s), '');
end;
(* Unit name from Inputs[i] or Descriptions[i]
Package name from Imports?
*)
function ExtractUnitName(AList: TStrings; AIndex: integer): string;
begin
Result := UnitFile(AList, AIndex);
if Result <> '' then
Result := ChangeFileExt(ExtractFileName(Result), '');
end;
(* Extract a file reference from Inputs or Descriptions list.
Check for existing list and item.
*)
function UnitFile(AList: TStrings; AIndex: integer): string;
var
s: string;
begin
if assigned(AList) and (AIndex < AList.Count) then begin
s := AList[AIndex];
while s <> '' do begin
Result := GetNextWord(s);
if (Result <> '') and (Result[1] <> '-') then
exit; //found a non-option
end;
end;
Result := ''; //should never happen!
end;
type
TNodePair = Class(TObject)
Private
FEl : TPasElement;
FNode : TDocNode;
Public
Constructor Create(AnElement : TPasElement; ADocNode : TDocNode);
Property Element : TPasElement Read FEl;
Property DocNode : TDocNode Read FNode;
end;
Constructor TNodePair.Create(AnElement : TPasElement; ADocNode : TDocNode);
begin
Fel:=Anelement;
FNode:=ADocNode;
end;
function TSkelEngine.FindModule(const AName: String): TPasModule;
Var
@ -636,30 +653,13 @@ begin
Result := FDescrDir;
end;
(* Unit name from Inputs[i] or Descriptions[i]
Package name from Imports?
*)
function TFPDocMaker.UnitName(AList: TStrings; AIndex: integer): string;
var
w: string;
begin
Result := AList[AIndex];
while Result <> '' do begin
w := GetNextWord(Result);
if (w <> '') and (w[1] <> '-') then begin
Result := ChangeFileExt(ExtractFileName(w), '');
break;
end;
end;
end;
function TFPDocMaker.UnitSpec(AUnit: string): string;
var
i: integer;
s, w: string;
begin
for i := 0 to SelectedPackage.Inputs.Count - 1 do begin
w := UnitName(FPackage.Inputs, i);
w := ExtractUnitName(FPackage.Inputs, i);
if CompareText(w, AUnit) = 0 then begin
Result := FPackage.Inputs[i];
exit;
@ -669,15 +669,8 @@ begin
end;
function TFPDocMaker.ImportName(AIndex: integer): string;
var
i: integer;
begin
Result := SelectedPackage.Imports[AIndex];
i := Pos(',', Result);
if i > 1 then
SetLength(Result, i-1);
Result := ExtractFileName(Result);
Result := ChangeFileExt(Result, '');
Result := ExtractImportName(SelectedPackage.Imports[AIndex]);
end;
function TFPDocMaker.GetInputDir: string;
@ -752,12 +745,13 @@ begin
end;
end;
{$IFDEF v0}
function TFPDocMaker.CreateProject(const AFileName: string; APackage: TFPDocPackage): boolean;
var
f: TXMLPackageOptions;
f: TXMLPackageProject;
begin
try
f := TXMLPackageOptions.Create(nil);
f := TXMLPackageProject.Create(nil);
try
f.SaveOptionsToFile(Project, AFileName, APackage);
Result := True;
@ -769,6 +763,21 @@ begin
end;
end;
procedure TFPDocMaker.LoadXMLProject(const AFileName: string);
var
f: TXMLPackageProject;
begin
//LoadProjectFile();
f := TXMLPackageProject.Create(self);
try
f.LoadOptionsFromFile(Project, AFileName);
finally
f.Free;
end;
end;
{$ELSE}
{$ENDIF}
procedure TFPDocMaker.SetCmdAction(AValue: TCreatorAction);
begin
if FCmdAction=AValue then Exit;
@ -1057,6 +1066,32 @@ begin
end;
end;
(* Return True and (try) kill file if no "<element" found.
*)
function TFPDocMaker.CleanXML(const FileName: string): boolean;
var
f: TextFile;
s: string;
begin
AssignFile(f, FileName);
Reset(f);
try
while not EOF(f) do begin
ReadLn(f, s);
if Pos('<element ', s) > 0 then
exit(False); //file not empty
end;
finally
CloseFile(f);
end;
//nothing found, delete the file
if DeleteFile(FileName) then
DoLog('File ' + FileName + ' has no elements. Deleted.')
else
DoLog('File ' + FileName + ' has no elements. Delete failed.');
Result := True;
end;
function TFPDocMaker.ParseUpdateOption(const s: String): TCreatorAction;
//procedure ParseOption(const s: String; Options: TEngineOptions);

File diff suppressed because it is too large Load Diff