CodeCompletion.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. {
  2. TIGCC IDE
  3. Copyright (C) 2004 Fréderic Bour
  4. Copyright (C) 2004 Sebastian Reichelt
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software Foundation,
  15. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  16. }
  17. unit CodeCompletion;
  18. interface
  19. uses SysUtils, SourceFileUnit, Dialogs, Classes, MainUnit;
  20. const
  21. DefautDesc = '';
  22. CCFVersion: Byte = 2;
  23. // Zero: Cardinal = 0;
  24. type
  25. TOnNeedFile = procedure(const FileName: string; out CCFData: string) of object;
  26. TCompletionItem = class(TObject)
  27. public
  28. Left, Right: string;
  29. Description: string;
  30. Line: Cardinal;
  31. // Not Saved
  32. SourceFileName: string;
  33. procedure ReadFromStream(F: TStream);
  34. procedure WriteToStream(F: TStream);
  35. end;
  36. TCompletionList = class(TStringList)
  37. protected
  38. FIncluded: TStringList;
  39. FOnNeed: TOnNeedFile;
  40. function aGetObject(Index: Integer): TCompletionItem;
  41. procedure aSetObject(Index: Integer; const Value: TCompletionItem);
  42. public
  43. constructor Create; reintroduce;
  44. destructor Destroy; override;
  45. function AddObject(const Symbol: string; Info: TCompletionItem): Integer; reintroduce;
  46. procedure Clear; override;
  47. property Completion[Index: Integer]: TCompletionItem read aGetObject write aSetObject;
  48. procedure AddCompletion(CCFData: TStream); overload;
  49. procedure AddCompletion(const CCFData: string); overload;
  50. // Completion state
  51. property IncludedFiles: TStringList read FIncluded;
  52. // When a file is needed
  53. property OnNeedFile: TOnNeedFile read FOnNeed write FOnNeed;
  54. end;
  55. function ReadString(F: TStream; var S: string): Boolean;
  56. function WriteString(F: TStream; const S: string): Boolean;
  57. function FileToString(const FileName: string): string;
  58. // Remove comments from a C Source
  59. function GetIdent(const S: string; var aPos: Integer): string;
  60. procedure FilterComment(Src, Dst: TStrings);
  61. // Parse a C Source
  62. function MakeCCF_C(const UnitName: string; Src: TSourceTextSourceFile): string;
  63. // Parse an Header Source
  64. function MakeCCF_H(const UnitName: string; Lines: TStrings; FilterTo: TStrings = nil): string;
  65. implementation
  66. uses StrUtils, UtilsDos;
  67. // Routines
  68. function GetIdent(const S: string; var aPos: Integer): string;
  69. var
  70. i, l: Integer;
  71. begin
  72. i := aPos;
  73. l := Length(S);
  74. while (i <= l) and (S[i] = ' ') do
  75. Inc(i);
  76. while (i <= l) and (S[i] in ['a'..'z', 'A'..'Z', '0'..'9', '_', '#']) do
  77. Inc(i);
  78. Result := Copy(S, aPos, i - aPos);
  79. aPos := i;
  80. end;
  81. function ReadString(F: TStream; var S: string): Boolean;
  82. var
  83. B: Byte;
  84. begin
  85. if F.Read(B, 1) = 1 then
  86. begin
  87. Setlength(S, B);
  88. Result := F.Read(S[1], B) = B;
  89. end
  90. else
  91. begin
  92. Result := False;
  93. S := '';
  94. end;
  95. end;
  96. function WriteString(F: TStream; const S: string): Boolean;
  97. var
  98. B: Byte;
  99. begin
  100. B := Length(S);
  101. Result := False;
  102. if F.Write(B, 1) = 1 then
  103. Result := F.Write(S[1], B) = B;
  104. end;
  105. function FileToString(const FileName: string): string;
  106. var
  107. F: TFileStream;
  108. c1, c2: Integer;
  109. begin
  110. Result := '';
  111. try
  112. F := TFileStream.Create(FileName, fmOpenRead);
  113. try
  114. c1 := F.Size;
  115. SetLength(Result, c1);
  116. c2 := F.Read(Result[1], c1);
  117. if c1 <> c2 then
  118. SetLength(Result, c2);
  119. finally
  120. F.Free;
  121. end;
  122. except
  123. end;
  124. end;
  125. procedure FilterComment(Src, Dst: TStrings);
  126. var
  127. S, S2: string;
  128. i, p: Integer;
  129. InComment: Boolean;
  130. begin
  131. InComment := False;
  132. for i := 0 to Src.Count - 1 do
  133. begin
  134. S := Trim(Src[i]);
  135. // Check end of comment
  136. if InComment then
  137. begin
  138. p := Pos('*/', S);
  139. if p = 0 then
  140. begin
  141. Dst.Add('');
  142. Continue;
  143. end
  144. else
  145. begin
  146. InComment := False;
  147. S := Copy(S, p + 2, MaxInt);
  148. end;
  149. end;
  150. // Check line comment
  151. p := Pos('//', S);
  152. if p = 1 then
  153. begin
  154. Dst.Add('');
  155. Continue;
  156. end
  157. else if p <> 0 then
  158. S := Copy(S, 1, p - 1);
  159. // Check start of comment
  160. p := Pos('/*', S);
  161. if p <> 0 then
  162. begin
  163. S2 := S;
  164. S := Copy(S, 1, p - 1);
  165. p := PosEx('*/', S2, p + 2);
  166. InComment := p = 0;
  167. if not InComment then
  168. begin
  169. InComment := False;
  170. S := S + Copy(S2, p + 2, MaxInt);
  171. end;
  172. end;
  173. // Add result
  174. Dst.Add(S);
  175. end;
  176. end;
  177. procedure ParseIncludes(Src, Dst: TStrings);
  178. var
  179. i, p: Integer;
  180. Line: string;
  181. begin
  182. // find line which starts with '#include'
  183. for i := 0 to Src.Count - 1 do
  184. begin
  185. Line := Trim(Src[i]);
  186. if AnsiStartsText('#include', Line) then
  187. begin
  188. p := Pos('"', Line);
  189. if P <> 0 then
  190. begin
  191. Line := Copy(Line, p + 1, MaxInt);
  192. Line := Copy(Line, 1, Pos('"', Line) - 1);
  193. Dst.Add(Trim(Line));
  194. end
  195. else
  196. begin
  197. p := Pos('<', Line);
  198. if P <> 0 then
  199. begin
  200. Line := Copy(Line, p + 1, MaxInt);
  201. Line := Copy(Line, 1, Pos('>', Line) - 1);
  202. Dst.Add(Trim(Line));
  203. end;
  204. end;
  205. end;
  206. end;
  207. end;
  208. function MakeCCF_C(const UnitName: string; Src: TSourceTextSourceFile): string;
  209. var
  210. Dst: TMemoryStream;
  211. // Parse files included in the Source unit
  212. procedure ParseInc;
  213. var
  214. Included: TStringList;
  215. w: Word;
  216. i: Integer;
  217. Source: TStrings;
  218. begin
  219. Source := TStringList.Create;
  220. FilterComment(Src.SourceEditor.Lines, Source);
  221. Included := TStringList.Create;
  222. Included.Sorted := True;
  223. Included.Duplicates := dupIgnore;
  224. ParseIncludes(Source, Included);
  225. w := Included.Count;
  226. // write result to stream
  227. Dst.Write(w, 2);
  228. for i := 0 to Included.Count - 1 do
  229. WriteString(Dst, Included[i]);
  230. Included.Free;
  231. Source.Free;
  232. end;
  233. // Parse Functions
  234. procedure ParseFuncs;
  235. var
  236. Funcs: TSourceFileFunctions;
  237. Func: TSourceFileFunction;
  238. i, p, c, l: Integer;
  239. S: string;
  240. Source: TStrings;
  241. begin
  242. Source := Src.SourceEditor.Lines;
  243. Funcs := Src.GetFunctions;
  244. c := Source.Count;
  245. for i := 0 to Length(Funcs) - 1 do
  246. begin
  247. Func := Funcs[i];
  248. if Func.Name <> '' then
  249. begin
  250. if (Func.ImplementationLine > 0) and (Func.ImplementationLine <= c) then
  251. l := Func.ImplementationLine - 1
  252. else if (Func.PrototypeLine > 0) and (Func.PrototypeLine <= c) then
  253. l := Func.PrototypeLine - 1
  254. else
  255. l := -1;
  256. if l > -1 then
  257. S := Source[l];
  258. if S <> '' then
  259. begin
  260. p := Pos(Func.Name, S);
  261. WriteString(Dst, Func.Name);
  262. Dst.Write(l, 4);
  263. WriteString(Dst, '<c:Teal>func <c:Blue>' + Trim(Copy(S, 1, p - 1)));
  264. WriteString(Dst, Trim(Copy(S, p + Length(Func.Name), MaxInt)));
  265. WriteString(Dst, DefautDesc);
  266. end;
  267. end;
  268. end;
  269. end;
  270. begin
  271. Dst := TMemoryStream.Create;
  272. Dst.Write(CCFVersion, SizeOf(CCFVersion));
  273. WriteString(Dst, UnitName);
  274. ParseInc;
  275. ParseFuncs;
  276. SetString(Result, PChar(Dst.Memory), Dst.Size);
  277. Dst.Free;
  278. end;
  279. function MakeCCF_H(const UnitName: string; Lines: TStrings; FilterTo: TStrings = nil): string;
  280. var
  281. Dst: TMemoryStream;
  282. Source: TStrings;
  283. // Parse files included in the Source unit
  284. procedure ParseInc;
  285. var
  286. Included: TStringList;
  287. w: Word;
  288. i: Integer;
  289. begin
  290. Included := TStringList.Create;
  291. Included.Sorted := True;
  292. Included.Duplicates := dupIgnore;
  293. ParseIncludes(Source, Included);
  294. w := Included.Count;
  295. // write result to stream
  296. Dst.Write(w, 2);
  297. for i := 0 to Included.Count - 1 do
  298. WriteString(Dst, Included[i]);
  299. Included.Free;
  300. end;
  301. procedure ParseHeader;
  302. var
  303. i, p, c: Integer;
  304. S, S2, Ident: string;
  305. begin
  306. c := Source.Count;
  307. i := 0;
  308. while i < c do
  309. begin
  310. S := Source[i];
  311. if AnsiStartsText('#define', S) then
  312. begin
  313. p := 9;
  314. Ident := GetIdent(S, p);
  315. S2 := Trim(Copy(S, p, MaxInt));
  316. if S2 <> '' then
  317. begin
  318. WriteString(Dst, Ident);
  319. Dst.Write(i, 4);
  320. WriteString(Dst, '<c:Green>macro');
  321. WriteString(Dst, S2);
  322. WriteString(Dst, '');
  323. end
  324. end
  325. else
  326. begin
  327. // terminer cette partie du code :)
  328. end;
  329. Inc(i);
  330. end;
  331. end;
  332. begin
  333. Dst := TMemoryStream.Create;
  334. Dst.Write(CCFVersion, SizeOf(CCFVersion));
  335. if Assigned(FilterTo) then
  336. Source := FilterTo
  337. else
  338. Source := TStringList.Create;
  339. Source.Clear;
  340. FilterComment(Lines, Source);
  341. WriteString(Dst, UnitName);
  342. ParseInc;
  343. ParseHeader;
  344. SetString(Result, PChar(Dst.Memory), Dst.Size);
  345. if FilterTo = nil then
  346. Source.Free;
  347. Dst.Free;
  348. end;
  349. { TCompletionList }
  350. constructor TCompletionList.Create;
  351. begin
  352. inherited;
  353. CaseSensitive := True;
  354. Sorted := True;
  355. Duplicates := dupAccept;
  356. FIncluded := TStringList.Create;
  357. FIncluded.Sorted := True;
  358. FIncluded.Duplicates := dupIgnore;
  359. end;
  360. destructor TCompletionList.Destroy;
  361. begin
  362. Clear;
  363. inherited;
  364. end;
  365. function TCompletionList.AddObject(const Symbol: string;
  366. Info: TCompletionItem): Integer;
  367. begin
  368. Result := inherited AddObject(Symbol, Info);
  369. end;
  370. procedure TCompletionList.Clear;
  371. var
  372. i: Integer;
  373. begin
  374. IncludedFiles.Clear;
  375. for i := 0 to Count - 1 do
  376. Objects[i].Free;
  377. inherited;
  378. end;
  379. function TCompletionList.aGetObject(Index: Integer): TCompletionItem;
  380. begin
  381. Result := TCompletionItem(Objects[Index]);
  382. end;
  383. procedure TCompletionList.aSetObject(Index: Integer;
  384. const Value: TCompletionItem);
  385. begin
  386. Objects[Index] := Value;
  387. end;
  388. procedure TCompletionList.AddCompletion(CCFData: TStream);
  389. var
  390. aStream: TStream;
  391. UnitName, S1, S2: string;
  392. i, w: Word;
  393. C: TCompletionItem;
  394. B: Byte;
  395. begin
  396. if (CCFData.Read(B, 1) <> 1) or (B <> CCFVersion) then
  397. Exit; // Wrong Version
  398. if ReadString(CCFData, UnitName) and (IncludedFiles.IndexOf(UnitName) = -1) and (CCFData.Read(w, 2) = 2) then
  399. begin
  400. IncludedFiles.Add(UnitName);
  401. // Check for included files
  402. for i := 1 to w do
  403. begin
  404. if ReadString(CCFData, S1) then
  405. begin
  406. if (IncludedFiles.IndexOf(S1) = -1) and Assigned(OnNeedFile) then
  407. begin
  408. OnNeedFile(S1, S2);
  409. if S2 <> '' then
  410. begin
  411. aStream := TStringStream.Create(S2);
  412. AddCompletion(aStream);
  413. aStream.Free;
  414. end;
  415. end;
  416. end
  417. else
  418. Exit;
  419. end;
  420. // Add completion info
  421. while ReadString(CCFData, S1) do
  422. begin
  423. C := TCompletionItem.Create;
  424. C.ReadFromStream(CCFData);
  425. C.SourceFileName := UnitName;
  426. if S1 <> '' then
  427. AddObject(S1, C)
  428. else
  429. C.Free;
  430. end;
  431. end;
  432. end;
  433. procedure TCompletionList.AddCompletion(const CCFData: string);
  434. var
  435. S: TStringStream;
  436. begin
  437. S := TStringStream.Create(CCFData);
  438. AddCompletion(S);
  439. S.Free;
  440. end;
  441. { TCompletionItem }
  442. procedure TCompletionItem.ReadFromStream(F: TStream);
  443. begin
  444. F.Read(Line, SizeOf(Line));
  445. ReadString(F, Left);
  446. ReadString(F, Right);
  447. ReadString(F, Description);
  448. end;
  449. procedure TCompletionItem.WriteToStream(F: TStream);
  450. begin
  451. F.Write(Line, SizeOf(Line));
  452. WriteString(F, Left);
  453. WriteString(F, Right);
  454. WriteString(F, Description);
  455. end;
  456. end.