1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
|
unit ChmProg;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
Dialogs, FileUtil, LazFileUtils, LazUTF8, LazLogger,
LazHelpIntf, HelpIntfs,
IDEHelpIntf, MacroIntf;
const
sFPCCompilerDirectives = 'FreePascal Compiler directives';
type
{ TFPCDirectivesHelpDatabase }
TFPCDirectivesHelpDatabase = class(THelpDatabase)
private
FCHMSearchPath: string;
FDirectiveNodes: TFPList;
function SearchForDirective(ADirective: string;
var ListOfNodes: THelpNodeQueryList): Boolean;
procedure ClearDirectiveNodes;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
function GetNodesForDirective(const HelpDirective: string;
var ListOfNodes: THelpNodeQueryList;
var ErrMsg: string): TShowHelpResult; override;
function ShowHelp(Query: THelpQuery; {%H-}BaseNode, NewNode: THelpNode;
{%H-}QueryItem: THelpQueryItem;
var ErrMsg: string): TShowHelpResult; override;
function GetCHMSearchPath: string;
property CHMSearchPath: string read FCHMSearchPath write FCHMSearchPath;
function FindCHMFile: string;
end;
procedure RegisterFPCDirectivesHelpDatabase;
var
FPCDirectivesHelpDatabase: TFPCDirectivesHelpDatabase = nil;
implementation
uses chmreader, chmFiftiMain;
procedure RegisterFPCDirectivesHelpDatabase;
begin
if not Assigned(FPCDirectivesHelpDatabase) then
FPCDirectivesHelpDatabase :=
TFPCDirectivesHelpDatabase(HelpDatabases.CreateHelpDatabase(
sFPCCompilerDirectives, TFPCDirectivesHelpDatabase, true));
end;
{ TFPCDirectivesHelpDatabase }
function TFPCDirectivesHelpDatabase.SearchForDirective(ADirective: string;
var ListOfNodes: THelpNodeQueryList): Boolean;
var
chm: TChmFileList;
fchm: TChmReader;
DocTitle, URL: string;
ms: TMemoryStream;
SearchReader: TChmSearchReader;
TitleResults: TChmWLCTopicArray;
i, k: Integer;
DirectiveNode: THelpNode;
Filename: String;
begin
ADirective := UpperCase(ADirective);
Result := False;
Filename:=FindCHMFile;
if Filename='' then exit;
chm := TChmFileList.Create(Utf8ToSys(Filename));
try
if chm.Count = 0 then Exit;
fchm := chm.Chm[0];
if fchm.SearchReader = nil then
begin
ms := fchm.GetObject('/$FIftiMain');
if ms = nil then Exit;
SearchReader := TChmSearchReader.Create(ms, True); //frees the stream when done
fchm.SearchReader := SearchReader;
end
else
SearchReader := fchm.SearchReader;
SearchReader.LookupWord(Copy(ADirective, 2, MaxInt), TitleResults);
for k := 0 to High(TitleResults) do
begin
URL := fchm.LookupTopicByID(TitleResults[k].TopicIndex, DocTitle);
i := Pos(ADirective, DocTitle);
if (i = 0) or (Length(DocTitle) >= i + Length(ADirective))
and (upCase(DocTitle[i + Length(ADirective)]) in ['A'..'Z','0'..'9']) then Continue;
if (Length(URL) > 0) and (URL[1] = '/') then
Delete(URL, 1, 1);
if URL = '' then Continue;
DirectiveNode := THelpNode.CreateURL(Self, ADirective, 'prog.chm://' + URL);
DirectiveNode.Title := 'FPC directives: ' + DocTitle;
CreateNodeQueryListAndAdd(DirectiveNode, nil, ListOfNodes, True);
FDirectiveNodes.Add(DirectiveNode);
Result := True;
end;
fchm.Free;
finally
chm.Free;
end;
end;
procedure TFPCDirectivesHelpDatabase.ClearDirectiveNodes;
var i: Integer;
begin
for i := 0 to FDirectiveNodes.Count - 1 do
TObject(FDirectiveNodes[i]).Free;
FDirectiveNodes.Clear;
end;
constructor TFPCDirectivesHelpDatabase.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
FDirectiveNodes := TFPList.Create;
end;
destructor TFPCDirectivesHelpDatabase.Destroy;
begin
ClearDirectiveNodes;
FDirectiveNodes.Free;
inherited Destroy;
end;
function TFPCDirectivesHelpDatabase.GetNodesForDirective(
const HelpDirective: string; var ListOfNodes: THelpNodeQueryList;
var ErrMsg: string): TShowHelpResult;
var
Directive: String;
Filename: String;
begin
Result := shrHelpNotFound;
if (csDesigning in ComponentState) then Exit;
if (FPCDirectiveHelpPrefix<>'') and
(LeftStr(HelpDirective, Length(FPCDirectiveHelpPrefix)) = FPCDirectiveHelpPrefix) then
begin
Filename:=FindCHMFile;
debugln(['TFPCDirectivesHelpDatabase.GetNodesForDirective ',Filename]);
if (Filename='') then
begin
Result := shrDatabaseNotFound;
ErrMsg := Format('prog.chm not found. Please put prog.chm help file in '+ LineEnding
+ '%s' + LineEnding
+'or set the path to it with "HelpFilesPath" in '
+' Environment Options -> Help -> Help Options ->' + LineEnding
+'under Viewers - CHM Help Viewer', [FCHMSearchPath]);
Exit;
end;
// HelpDirective starts with DirectivePrefix
Directive := Copy(HelpDirective, Length(FPCDirectiveHelpPrefix) + 1, Length(HelpDirective));
ClearDirectiveNodes;
if SearchForDirective(Directive, ListOfNodes) then
Result := shrSuccess;
end;
end;
function TFPCDirectivesHelpDatabase.ShowHelp(Query: THelpQuery; BaseNode,
NewNode: THelpNode; QueryItem: THelpQueryItem; var ErrMsg: string
): TShowHelpResult;
var
Viewer: THelpViewer;
begin
Result:=shrHelpNotFound;
if not (Query is THelpQueryDirective) then exit;
Result := FindViewer('text/html', ErrMsg, Viewer);
if Result <> shrSuccess then Exit;
Result := Viewer.ShowNode(NewNode, ErrMsg);
end;
function TFPCDirectivesHelpDatabase.GetCHMSearchPath: string;
begin
Result:=FCHMSearchPath;
if Result='' then
begin
Result := '$(LazarusDir)/docs/chm;$(LazarusDir)/docs/html';
IDEMacros.SubstituteMacros(Result);
Result:=MinimizeSearchPath(GetForcedPathDelims(Result));
end;
end;
function TFPCDirectivesHelpDatabase.FindCHMFile: string;
begin
Result:=SearchFileInPath('prog.chm','',GetCHMSearchPath,';',[]);
end;
end.
|