123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- {
- TIGCC IDE
- Copyright (C) 2004 Fréderic Bour
- Copyright (C) 2004 Sebastian Reichelt
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- }
- unit CodeCompletion;
- interface
- uses SysUtils, SourceFileUnit, Dialogs, Classes, MainUnit;
- const
- DefautDesc = '';
- CCFVersion: Byte = 2;
- // Zero: Cardinal = 0;
- type
- TOnNeedFile = procedure(const FileName: string; out CCFData: string) of object;
- TCompletionItem = class(TObject)
- public
- Left, Right: string;
- Description: string;
- Line: Cardinal;
- // Not Saved
- SourceFileName: string;
- procedure ReadFromStream(F: TStream);
- procedure WriteToStream(F: TStream);
- end;
- TCompletionList = class(TStringList)
- protected
- FIncluded: TStringList;
- FOnNeed: TOnNeedFile;
- function aGetObject(Index: Integer): TCompletionItem;
- procedure aSetObject(Index: Integer; const Value: TCompletionItem);
- public
- constructor Create; reintroduce;
- destructor Destroy; override;
- function AddObject(const Symbol: string; Info: TCompletionItem): Integer; reintroduce;
- procedure Clear; override;
- property Completion[Index: Integer]: TCompletionItem read aGetObject write aSetObject;
- procedure AddCompletion(CCFData: TStream); overload;
- procedure AddCompletion(const CCFData: string); overload;
- // Completion state
- property IncludedFiles: TStringList read FIncluded;
- // When a file is needed
- property OnNeedFile: TOnNeedFile read FOnNeed write FOnNeed;
- end;
- function ReadString(F: TStream; var S: string): Boolean;
- function WriteString(F: TStream; const S: string): Boolean;
- function FileToString(const FileName: string): string;
- // Remove comments from a C Source
- function GetIdent(const S: string; var aPos: Integer): string;
- procedure FilterComment(Src, Dst: TStrings);
- // Parse a C Source
- function MakeCCF_C(const UnitName: string; Src: TSourceTextSourceFile): string;
- // Parse an Header Source
- function MakeCCF_H(const UnitName: string; Lines: TStrings; FilterTo: TStrings = nil): string;
- implementation
- uses StrUtils, UtilsDos;
- // Routines
- function GetIdent(const S: string; var aPos: Integer): string;
- var
- i, l: Integer;
- begin
- i := aPos;
- l := Length(S);
- while (i <= l) and (S[i] = ' ') do
- Inc(i);
- while (i <= l) and (S[i] in ['a'..'z', 'A'..'Z', '0'..'9', '_', '#']) do
- Inc(i);
- Result := Copy(S, aPos, i - aPos);
- aPos := i;
- end;
- function ReadString(F: TStream; var S: string): Boolean;
- var
- B: Byte;
- begin
- if F.Read(B, 1) = 1 then
- begin
- Setlength(S, B);
- Result := F.Read(S[1], B) = B;
- end
- else
- begin
- Result := False;
- S := '';
- end;
- end;
- function WriteString(F: TStream; const S: string): Boolean;
- var
- B: Byte;
- begin
- B := Length(S);
- Result := False;
- if F.Write(B, 1) = 1 then
- Result := F.Write(S[1], B) = B;
- end;
- function FileToString(const FileName: string): string;
- var
- F: TFileStream;
- c1, c2: Integer;
- begin
- Result := '';
- try
- F := TFileStream.Create(FileName, fmOpenRead);
- try
- c1 := F.Size;
- SetLength(Result, c1);
- c2 := F.Read(Result[1], c1);
- if c1 <> c2 then
- SetLength(Result, c2);
- finally
- F.Free;
- end;
- except
- end;
- end;
- procedure FilterComment(Src, Dst: TStrings);
- var
- S, S2: string;
- i, p: Integer;
- InComment: Boolean;
- begin
- InComment := False;
- for i := 0 to Src.Count - 1 do
- begin
- S := Trim(Src[i]);
- // Check end of comment
- if InComment then
- begin
- p := Pos('*/', S);
- if p = 0 then
- begin
- Dst.Add('');
- Continue;
- end
- else
- begin
- InComment := False;
- S := Copy(S, p + 2, MaxInt);
- end;
- end;
- // Check line comment
- p := Pos('//', S);
- if p = 1 then
- begin
- Dst.Add('');
- Continue;
- end
- else if p <> 0 then
- S := Copy(S, 1, p - 1);
- // Check start of comment
- p := Pos('/*', S);
- if p <> 0 then
- begin
- S2 := S;
- S := Copy(S, 1, p - 1);
- p := PosEx('*/', S2, p + 2);
- InComment := p = 0;
- if not InComment then
- begin
- InComment := False;
- S := S + Copy(S2, p + 2, MaxInt);
- end;
- end;
- // Add result
- Dst.Add(S);
- end;
- end;
- procedure ParseIncludes(Src, Dst: TStrings);
- var
- i, p: Integer;
- Line: string;
- begin
- // find line which starts with '#include'
- for i := 0 to Src.Count - 1 do
- begin
- Line := Trim(Src[i]);
- if AnsiStartsText('#include', Line) then
- begin
- p := Pos('"', Line);
- if P <> 0 then
- begin
- Line := Copy(Line, p + 1, MaxInt);
- Line := Copy(Line, 1, Pos('"', Line) - 1);
- Dst.Add(Trim(Line));
- end
- else
- begin
- p := Pos('<', Line);
- if P <> 0 then
- begin
- Line := Copy(Line, p + 1, MaxInt);
- Line := Copy(Line, 1, Pos('>', Line) - 1);
- Dst.Add(Trim(Line));
- end;
- end;
- end;
- end;
- end;
- function MakeCCF_C(const UnitName: string; Src: TSourceTextSourceFile): string;
- var
- Dst: TMemoryStream;
- // Parse files included in the Source unit
- procedure ParseInc;
- var
- Included: TStringList;
- w: Word;
- i: Integer;
- Source: TStrings;
- begin
- Source := TStringList.Create;
- FilterComment(Src.SourceEditor.Lines, Source);
- Included := TStringList.Create;
- Included.Sorted := True;
- Included.Duplicates := dupIgnore;
- ParseIncludes(Source, Included);
- w := Included.Count;
- // write result to stream
- Dst.Write(w, 2);
- for i := 0 to Included.Count - 1 do
- WriteString(Dst, Included[i]);
- Included.Free;
- Source.Free;
- end;
- // Parse Functions
- procedure ParseFuncs;
- var
- Funcs: TSourceFileFunctions;
- Func: TSourceFileFunction;
- i, p, c, l: Integer;
- S: string;
- Source: TStrings;
- begin
- Source := Src.SourceEditor.Lines;
- Funcs := Src.GetFunctions;
- c := Source.Count;
- for i := 0 to Length(Funcs) - 1 do
- begin
- Func := Funcs[i];
- if Func.Name <> '' then
- begin
- if (Func.ImplementationLine > 0) and (Func.ImplementationLine <= c) then
- l := Func.ImplementationLine - 1
- else if (Func.PrototypeLine > 0) and (Func.PrototypeLine <= c) then
- l := Func.PrototypeLine - 1
- else
- l := -1;
- if l > -1 then
- S := Source[l];
- if S <> '' then
- begin
- p := Pos(Func.Name, S);
- WriteString(Dst, Func.Name);
- Dst.Write(l, 4);
- WriteString(Dst, '<c:Teal>func <c:Blue>' + Trim(Copy(S, 1, p - 1)));
- WriteString(Dst, Trim(Copy(S, p + Length(Func.Name), MaxInt)));
- WriteString(Dst, DefautDesc);
- end;
- end;
- end;
- end;
- begin
- Dst := TMemoryStream.Create;
- Dst.Write(CCFVersion, SizeOf(CCFVersion));
- WriteString(Dst, UnitName);
- ParseInc;
- ParseFuncs;
- SetString(Result, PChar(Dst.Memory), Dst.Size);
- Dst.Free;
- end;
- function MakeCCF_H(const UnitName: string; Lines: TStrings; FilterTo: TStrings = nil): string;
- var
- Dst: TMemoryStream;
- Source: TStrings;
- // Parse files included in the Source unit
- procedure ParseInc;
- var
- Included: TStringList;
- w: Word;
- i: Integer;
- begin
- Included := TStringList.Create;
- Included.Sorted := True;
- Included.Duplicates := dupIgnore;
- ParseIncludes(Source, Included);
- w := Included.Count;
- // write result to stream
- Dst.Write(w, 2);
- for i := 0 to Included.Count - 1 do
- WriteString(Dst, Included[i]);
- Included.Free;
- end;
- procedure ParseHeader;
- var
- i, p, c: Integer;
- S, S2, Ident: string;
- begin
- c := Source.Count;
- i := 0;
- while i < c do
- begin
- S := Source[i];
- if AnsiStartsText('#define', S) then
- begin
- p := 9;
- Ident := GetIdent(S, p);
- S2 := Trim(Copy(S, p, MaxInt));
- if S2 <> '' then
- begin
- WriteString(Dst, Ident);
- Dst.Write(i, 4);
- WriteString(Dst, '<c:Green>macro');
- WriteString(Dst, S2);
- WriteString(Dst, '');
- end
- end
- else
- begin
- // terminer cette partie du code :)
- end;
- Inc(i);
- end;
- end;
- begin
- Dst := TMemoryStream.Create;
- Dst.Write(CCFVersion, SizeOf(CCFVersion));
- if Assigned(FilterTo) then
- Source := FilterTo
- else
- Source := TStringList.Create;
- Source.Clear;
- FilterComment(Lines, Source);
- WriteString(Dst, UnitName);
- ParseInc;
- ParseHeader;
- SetString(Result, PChar(Dst.Memory), Dst.Size);
- if FilterTo = nil then
- Source.Free;
- Dst.Free;
- end;
- { TCompletionList }
- constructor TCompletionList.Create;
- begin
- inherited;
- CaseSensitive := True;
- Sorted := True;
- Duplicates := dupAccept;
- FIncluded := TStringList.Create;
- FIncluded.Sorted := True;
- FIncluded.Duplicates := dupIgnore;
- end;
- destructor TCompletionList.Destroy;
- begin
- Clear;
- inherited;
- end;
- function TCompletionList.AddObject(const Symbol: string;
- Info: TCompletionItem): Integer;
- begin
- Result := inherited AddObject(Symbol, Info);
- end;
- procedure TCompletionList.Clear;
- var
- i: Integer;
- begin
- IncludedFiles.Clear;
- for i := 0 to Count - 1 do
- Objects[i].Free;
- inherited;
- end;
- function TCompletionList.aGetObject(Index: Integer): TCompletionItem;
- begin
- Result := TCompletionItem(Objects[Index]);
- end;
- procedure TCompletionList.aSetObject(Index: Integer;
- const Value: TCompletionItem);
- begin
- Objects[Index] := Value;
- end;
- procedure TCompletionList.AddCompletion(CCFData: TStream);
- var
- aStream: TStream;
- UnitName, S1, S2: string;
- i, w: Word;
- C: TCompletionItem;
- B: Byte;
- begin
- if (CCFData.Read(B, 1) <> 1) or (B <> CCFVersion) then
- Exit; // Wrong Version
- if ReadString(CCFData, UnitName) and (IncludedFiles.IndexOf(UnitName) = -1) and (CCFData.Read(w, 2) = 2) then
- begin
- IncludedFiles.Add(UnitName);
- // Check for included files
- for i := 1 to w do
- begin
- if ReadString(CCFData, S1) then
- begin
- if (IncludedFiles.IndexOf(S1) = -1) and Assigned(OnNeedFile) then
- begin
- OnNeedFile(S1, S2);
- if S2 <> '' then
- begin
- aStream := TStringStream.Create(S2);
- AddCompletion(aStream);
- aStream.Free;
- end;
- end;
- end
- else
- Exit;
- end;
- // Add completion info
- while ReadString(CCFData, S1) do
- begin
- C := TCompletionItem.Create;
- C.ReadFromStream(CCFData);
- C.SourceFileName := UnitName;
- if S1 <> '' then
- AddObject(S1, C)
- else
- C.Free;
- end;
- end;
- end;
- procedure TCompletionList.AddCompletion(const CCFData: string);
- var
- S: TStringStream;
- begin
- S := TStringStream.Create(CCFData);
- AddCompletion(S);
- S.Free;
- end;
- { TCompletionItem }
- procedure TCompletionItem.ReadFromStream(F: TStream);
- begin
- F.Read(Line, SizeOf(Line));
- ReadString(F, Left);
- ReadString(F, Right);
- ReadString(F, Description);
- end;
- procedure TCompletionItem.WriteToStream(F: TStream);
- begin
- F.Write(Line, SizeOf(Line));
- WriteString(F, Left);
- WriteString(F, Right);
- WriteString(F, Description);
- end;
- end.
|