wrapped DCD things in a class: allow to save settings and the instance to know docs and projs.

+ fixes the small lag previously happening during first DCD query
This commit is contained in:
Basile Burg 2014-12-11 09:06:16 +01:00
parent d0ca1fbffa
commit 93be81f643
7 changed files with 245 additions and 243 deletions

View File

@ -5,118 +5,206 @@ unit ce_dcd;
interface interface
uses uses
Classes, SysUtils, process, forms, strutils, ce_common; Classes, SysUtils, process, forms, strutils,
ce_common, ce_writableComponent, ce_interfaces, ce_observer, ce_synmemo, ce_project;
type
(** (**
* frees the server: e.g: to remove some bugy imports from the libman. * Wrap the dcd-server and dcd-clients processes.
*) *
procedure freeServer; * Projects folder are automatically imported: ICEProjectObserver.
* Completion, hints and declaration finder automatically work on the current
(** * document: ICEMultiDocObserver.
* recreates the server. *)
*) TCEDcdWrapper = class(TWritableComponent, ICEProjectObserver, ICEMultiDocObserver)
procedure createServer; private
fTempLines: TStringList;
(** //fPortNum: Word;
* Adds a folder of d sources for DCD. fClient, fServer: TProcess;
*) fAvailable: boolean;
procedure addDcdImport(const aFilename: string); fDoc: TCESynMemo;
fProj: TCEProject;
(** procedure killServer;
* gets a list of propositions for the identifier at aPosition in aFilename. //
*) procedure projNew(aProject: TCEProject);
procedure getCompletion(const aFilename: string; aPosition: Integer; const list: TStrings); procedure projChanged(aProject: TCEProject);
procedure projClosing(aProject: TCEProject);
(** procedure projFocused(aProject: TCEProject);
* tries to get the DDoc comment for the identifier at aPosition in aFilename. //
*) procedure docNew(aDoc: TCESynMemo);
procedure getHint(const aFilename: string; aPosition: Integer; const list: TStrings); procedure docFocused(aDoc: TCESynMemo);
procedure docChanged(aDoc: TCESynMemo);
(** procedure docClosing(aDoc: TCESynMemo);
* tries to get the symbol location of the identifier at aPosition in aFilename. public
* after the call aFilename and aPosition contains the location filename and position. constructor create(aOwner: TComponent); override;
*) destructor destroy; override;
procedure getSymbolLoc(var aFilename: string; var aPosition: Integer); //
procedure restartServer;
procedure addImportFolder(const aFolder: string);
procedure getComplAtCursor(aList: TStrings);
procedure getDdocFromCursor(out aComment: string);
procedure getDeclFromCursor(out aFilename: string; out aPosition: Integer);
//
property available: boolean read fAvailable;
end;
var var
dcdOn: boolean; DcdWrapper: TCEDcdWrapper;
implementation implementation
var {$REGION Standard Comp/Obj------------------------------------------------------}
DCD_server: TProcess = nil; constructor TCEDcdWrapper.create(aOwner: TComponent);
DCD_client: TProcess = nil; const
lines: TStringList; clientName = 'dcd-client' + exeExt;
serverName = 'dcd-server' + exeExt;
procedure lazyServerStart;
begin begin
if not DCD_server.Running then inherited;
DCD_server.Execute;
end;
procedure freeServer;
begin
while DCD_client.Running do;
DCD_client.Parameters.Clear;
DCD_client.Parameters.Add('--shutdown');
DCD_client.Execute;
if DCD_server <> nil then
FreeAndNil(DCD_server);
end;
procedure createServer;
begin
if DCD_server <> nil then
FreeAndNil(DCD_server);
DCD_server := TProcess.Create(nil);
DCD_server.Executable := 'dcd-server' + exeExt;
DCD_server.Options := [poUsePipes{$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
DCD_server.ShowWindow := swoHIDE;
end;
procedure addDcdImport(const aFilename: string);
begin
if not dcdOn then exit;
// //
if not DCD_server.Running then fAvailable := exeInSysPath(clientName) and exeInSysPath(serverName);
DCD_server.Parameters.Add('-I' + aFilename) if not fAvailable then
else if DCD_client <> nil then begin exit;
DCD_client.Parameters.Clear; //
DCD_client.Parameters.Add('-I' + aFilename); fClient := TProcess.Create(self);
DCD_client.Execute; fClient.Executable := clientName;
end; fClient.Options := [poUsePipes{$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
{$IFNDEF DEBUG}
fClient.ShowWindow := swoHIDE;
{$ENDIF}
//
fServer := TProcess.Create(self);
fServer.Executable := serverName;
fServer.Options := [poUsePipes{$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
{$IFNDEF DEBUG}
fServer.ShowWindow := swoHIDE;
{$ENDIF}
fTempLines := TStringList.Create;
fServer.Execute;
//
EntitiesConnector.addObserver(self);
end; end;
procedure getCompletion(const aFilename: string; aPosition: Integer; const list: TStrings); destructor TCEDcdWrapper.destroy;
begin
EntitiesConnector.removeObserver(self);
if fTempLines <> nil then
fTempLines.Free;
killServer;
inherited;
end;
{$ENDREGION}
{$REGION ICEProjectObserver ----------------------------------------------------}
procedure TCEDcdWrapper.projNew(aProject: TCEProject);
begin
fProj := aProject;
end;
procedure TCEDcdWrapper.projChanged(aProject: TCEProject);
var
i: Integer;
begin
if fProj <> aProject then
exit;
if fProj = nil then
exit;
//
for i:= 0 to fProj.Sources.Count-1 do
addImportFolder(extractFilePath(fProj.Sources.Strings[i]));
end;
procedure TCEDcdWrapper.projClosing(aProject: TCEProject);
begin
if fProj <> aProject then exit;
fProj := nil;
end;
procedure TCEDcdWrapper.projFocused(aProject: TCEProject);
begin
fProj := aProject;
end;
{$ENDREGION}
{$REGION ICEMultiDocObserver ---------------------------------------------------}
procedure TCEDcdWrapper.docNew(aDoc: TCESynMemo);
begin
fDoc := aDoc;
end;
procedure TCEDcdWrapper.docFocused(aDoc: TCESynMemo);
begin
fDoc := aDoc;
end;
procedure TCEDcdWrapper.docChanged(aDoc: TCESynMemo);
begin
if fDoc <> aDoc then exit;
end;
procedure TCEDcdWrapper.docClosing(aDoc: TCESynMemo);
begin
if fDoc <> aDoc then exit;
fDoc := nil;
end;
{$ENDREGION}
{$REGION DCD things ------------------------------------------------------------}
procedure TCEDcdWrapper.killServer;
begin
if not fAvailable then exit;
//
while fClient.Running do;
fClient.Parameters.Clear;
fClient.Parameters.Add('--shutdown');
fClient.Execute;
end;
procedure TCEDcdWrapper.restartServer;
begin
if not fAvailable then exit;
//
end;
procedure TCEDcdWrapper.addImportFolder(const aFolder: string);
begin
if not fAvailable then exit;
//
fClient.Parameters.Clear;
fClient.Parameters.Add('-I' + aFolder);
fClient.Execute;
end;
procedure TCEDcdWrapper.getComplAtCursor(aList: TStrings);
var var
i, j: NativeInt; i, j: NativeInt;
kind: Char; kind: Char;
item: string; item: string;
asComp, asTips: boolean; asComp, asTips: boolean;
begin begin
if not dcdOn then if not fAvailable then exit;
exit; if fDoc = nil then exit;
lazyServerStart;
// //
DCD_client.Parameters.Clear; fTempLines.Assign(fDoc.Lines);
DCD_client.Parameters.Add('-c'); fTempLines.SaveToFile(fDoc.tempFilename);
DCD_client.Parameters.Add(intToStr(aPosition)); //
DCD_client.Parameters.Add(aFilename); fClient.Parameters.Clear;
DCD_client.Execute; fClient.Parameters.Add('-c');
fClient.Parameters.Add(intToStr(fDoc.SelStart - 1));
fClient.Parameters.Add(fDoc.tempFilename);
fClient.Execute;
//
fTempLines.LoadFromStream(fClient.Output);
if fTempLines.Count = 0 then exit;
//
asComp := fTempLines.Strings[0] = 'identifiers';
asTips := fTempLines.Strings[0] = 'calltips';
if asTips then exit;
// //
lines.LoadFromStream(DCD_client.Output);
if lines.Count = 0 then
exit;
asComp := lines.Strings[0] = 'identifiers';
asTips := lines.Strings[0] = 'calltips';
if asTips then
exit;
if asComp then j := 1 else j := 0; if asComp then j := 1 else j := 0;
list.Clear; aList.Clear;
for i := j to lines.Count-1 do for i := j to fTempLines.Count-1 do
begin begin
item := lines.Strings[i]; item := fTempLines.Strings[i];
kind := item[length(item)]; kind := item[length(item)];
setLength(item, length(item)-2); setLength(item, length(item)-2);
case kind of case kind of
@ -138,57 +226,55 @@ begin
't': item += ' (template) '; 't': item += ' (template) ';
'T': item += ' (mixin) '; 'T': item += ' (mixin) ';
end; end;
list.Add(item); aList.Add(item);
end; end;
end; end;
procedure getHint(const aFilename: string; aPosition: Integer; const list: TStrings); procedure TCEDcdWrapper.getDdocFromCursor(out aComment: string);
var var
i: Integer; i: Integer;
str: string;
begin begin
if not dcdOn then if not fAvailable then exit;
exit; if fDoc = nil then exit;
lazyServerStart;
if DCD_client.Running then
exit;
// //
DCD_client.Parameters.Clear; fTempLines.Assign(fDoc.Lines);
DCD_client.Parameters.Add('-c'); fTempLines.SaveToFile(fDoc.tempFilename);
DCD_client.Parameters.Add(intToStr(aPosition));
DCD_client.Parameters.Add('-d');
DCD_client.Parameters.Add(aFilename);
DCD_client.Execute;
// //
list.LoadFromStream(DCD_client.Output); fClient.Parameters.Clear;
for i := 0 to list.Count-1 do fClient.Parameters.Add('-d');
begin fClient.Parameters.Add('-c');
str := list.Strings[i]; fClient.Parameters.Add(intToStr(fDoc.SelStart-1));
list.Strings[i] := ReplaceStr(str, '\n', ''); fClient.Parameters.Add(fDoc.tempFilename);
end; fClient.Execute;
//
aComment := '';
fTempLines.LoadFromStream(fClient.Output);
for i := 0 to fTempLines.Count-1 do
aComment += ReplaceStr(fTempLines.Strings[i], '\n', LineEnding);
end; end;
procedure getSymbolLoc(var aFilename: string; var aPosition: Integer); procedure TCEDcdWrapper.getDeclFromCursor(out aFilename: string; out aPosition: Integer);
var var
i: Integer; i: Integer;
str, loc: string; str, loc: string;
begin begin
if not dcdOn then if not fAvailable then exit;
exit; if fDoc = nil then exit;
lazyServerStart;
if DCD_client.Running then
exit;
// //
DCD_client.Parameters.Clear; fTempLines.Assign(fDoc.Lines);
DCD_client.Parameters.Add('-l'); fTempLines.SaveToFile(fDoc.tempFilename);
DCD_client.Parameters.Add('-c'); //
DCD_client.Parameters.Add(intToStr(aPosition)); fClient.Parameters.Clear;
DCD_client.Parameters.Add(aFilename); fClient.Parameters.Add('-l');
DCD_client.Execute; fClient.Parameters.Add('-c');
fClient.Parameters.Add(intToStr(fDoc.SelStart - 1));
fClient.Parameters.Add(fDoc.tempFilename);
fClient.Execute;
// //
str := 'a'; str := 'a';
setlength(str, 256); setlength(str, 256);
i := DCD_client.Output.Read(str[1], 256); i := fClient.Output.Read(str[1], 256);
setLength(str, i); setLength(str, i);
if str <> '' then if str <> '' then
begin begin
@ -196,25 +282,15 @@ begin
if i = -1 then if i = -1 then
exit; exit;
loc := str[i+1..length(str)]; loc := str[i+1..length(str)];
str := str[1..i-1]; aFilename := str[1..i-1];
aFilename := str;
loc := ReplaceStr(loc, LineEnding, ''); loc := ReplaceStr(loc, LineEnding, '');
aPosition := strToIntDef(loc, -1); aPosition := strToIntDef(loc, -1);
end; end;
end; end;
{$ENDREGION}
initialization initialization
createServer; DcdWrapper := TCEDcdWrapper.create(nil);
DCD_client := TProcess.Create(nil);
DCD_client.Executable := 'dcd-client' + exeExt;
DCD_client.Options := [poUsePipes{$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
DCD_client.ShowWindow := swoHIDE;
dcdOn := exeInSysPath(DCD_server.Executable) and exeInSysPath(DCD_client.Executable);
lines := TStringList.Create;
finalization finalization
DCD_server.Active := false; DcdWrapper.Free;
DCD_client.Active := false;
DCD_server.Free;
DCD_client.Free;
lines.Free;
end. end.

View File

@ -52,7 +52,6 @@ type
procedure addEditor; procedure addEditor;
procedure removeEditor(const aIndex: NativeInt); procedure removeEditor(const aIndex: NativeInt);
procedure focusedEditorChanged; procedure focusedEditorChanged;
function getEditorHint: string;
// //
procedure docNew(aDoc: TCESynMemo); procedure docNew(aDoc: TCESynMemo);
procedure docClosing(aDoc: TCESynMemo); procedure docClosing(aDoc: TCESynMemo);
@ -249,85 +248,27 @@ end;
procedure TCEEditorWidget.getSymbolLoc; procedure TCEEditorWidget.getSymbolLoc;
var var
str: TMemoryStream;
srcpos: Integer; srcpos: Integer;
ftempname, fname: string; fname: string;
begin begin
if not dcdOn then exit; if not DcdWrapper.available then exit;
if fDoc = nil then exit;
// //
str := TMemoryStream.Create; DcdWrapper.getDeclFromCursor(fname, srcpos);
try if fname <> fDoc.fileName then if fileExists(fname) then
ftempname := fDoc.tempFilename; CEMainForm.openFile(fname);
fDoc.Lines.SaveToStream(str); if srcpos <> -1 then begin
str.SaveToFile(ftempname); fDoc.SelStart := srcpos;
fname := ftempname; fDoc.SelectWord;
srcpos := fDoc.SelStart;
if srcpos > 0 then srcpos += -1;
if fDoc.GetWordAtRowCol(fDoc.LogicalCaretXY) <> '' then
ce_dcd.getSymbolLoc(fname, srcpos);
if fname <> ftempname then if fileExists(fname) then
CEMainForm.openFile(fname);
if srcpos <> -1 then
begin
fDoc.SelStart := srcpos;
fDoc.SelectWord;
end;
finally
str.Free;
end; end;
end; end;
procedure TCEEditorWidget.getCompletionList; procedure TCEEditorWidget.getCompletionList;
var
str: TMemoryStream;
srcpos: NativeInt;
fname: string;
begin begin
if not dcdOn then exit; if not DcdWrapper.available then exit;
if fDoc = nil then exit;
// //
str := TMemoryStream.Create; completion.Position := 0;
try completion.ItemList.Clear;
completion.Position := 0; // previous index could cause an error here. DcdWrapper.getComplAtCursor(completion.ItemList);
fname := fDoc.tempFilename;
fDoc.Lines.SaveToStream(str);
str.SaveToFile(fname);
srcpos := fDoc.SelStart;
if srcpos > 0 then srcpos += -1;
completion.ItemList.Clear;
ce_dcd.getCompletion(fname, srcpos, completion.ItemList);
finally
str.Free;
end;
end;
function TCEEditorWidget.getEditorHint: string;
var
str: TMemoryStream;
lst: TStringList;
srcpos: NativeInt;
fname: string;
begin
result := '';
if not dcdOn then exit;
if fDoc = nil then exit;
//
str := TMemoryStream.Create;
lst := TStringList.Create;
try
fname := fDoc.tempFilename;
fDoc.Lines.SaveToStream(str);
str.SaveToFile(fname);
srcpos := fDoc.SelStart;
if srcpos > 0 then srcpos += -1;
if fDoc.GetWordAtRowCol(fDoc.LogicalCaretXY) <> '' then
ce_dcd.getHint(fname, srcpos, lst);
result := lst.Text;
finally
str.Free;
lst.Free;
end;
end; end;
procedure TCEEditorWidget.UpdateByEvent; procedure TCEEditorWidget.UpdateByEvent;

View File

@ -81,14 +81,12 @@ var
itm: TLibraryItem; itm: TLibraryItem;
i: NativeInt; i: NativeInt;
begin begin
if not dcdOn then exit; if not DcdWrapper.available then exit;
// // note: new items are directly handled but removed ones still in cache until next cession.
ce_dcd.freeServer;
ce_dcd.createServer;
for i := 0 to fCol.Count-1 do for i := 0 to fCol.Count-1 do
begin begin
itm := TLibraryItem(fCol.Items[i]); itm := TLibraryItem(fCol.Items[i]);
ce_dcd.addDcdImport(itm.libSourcePath); DcdWrapper.addImportFolder(itm.libSourcePath);
end; end;
end; end;

View File

@ -929,12 +929,11 @@ procedure TCEMainForm.ApplicationProperties1ShowHint(var HintStr: string;
var CanShow: Boolean; var HintInfo: THintInfo); var CanShow: Boolean; var HintInfo: THintInfo);
begin begin
CanShow := true; CanShow := true;
{if fDoc <> nil then //if fDoc <> nil then if fDoc.Focused then
if fDoc.Focused then //begin
begin // DcdWrapper.getDdocFromCursor(HintStr);
HintStr := fEditWidg.getEditorHint; // CanShow := HintStr <> '';
CanShow := HintStr <> ''; //end;
end;}
end; end;
{$ENDREGION} {$ENDREGION}

View File

@ -39,7 +39,6 @@ type
fCanBeRun: boolean; fCanBeRun: boolean;
procedure updateOutFilename; procedure updateOutFilename;
procedure doChanged; procedure doChanged;
procedure updateDcd;
procedure setLibAliases(const aValue: TStringList); procedure setLibAliases(const aValue: TStringList);
procedure subMemberChanged(sender : TObject); procedure subMemberChanged(sender : TObject);
procedure setOptsColl(const aValue: TCollection); procedure setOptsColl(const aValue: TCollection);
@ -144,14 +143,6 @@ begin
Configuration[i].onChanged := @subMemberChanged; Configuration[i].onChanged := @subMemberChanged;
end; end;
procedure TCEProject.updateDcd;
var
fname: string;
begin
for fname in fSrcs do
ce_dcd.addDcdImport(extractfilePath(getAbsoluteFilename(fname)));
end;
procedure TCEProject.addSource(const aFilename: string); procedure TCEProject.addSource(const aFilename: string);
var var
relSrc, absSrc: string; relSrc, absSrc: string;
@ -162,7 +153,6 @@ begin
if aFilename = absSrc then exit; if aFilename = absSrc then exit;
end; end;
fSrcs.Add(ExtractRelativepath(fBasePath,aFilename)); fSrcs.Add(ExtractRelativepath(fBasePath,aFilename));
updateDcd;
end; end;
procedure TCEProject.setRoot(const aValue: string); procedure TCEProject.setRoot(const aValue: string);
@ -208,7 +198,6 @@ begin
beforeChanged; beforeChanged;
fSrcs.Assign(aValue); fSrcs.Assign(aValue);
patchPlateformPaths(fSrcs); patchPlateformPaths(fSrcs);
updateDcd;
afterChanged; afterChanged;
end; end;
@ -363,7 +352,6 @@ var
hasPatched: Boolean; hasPatched: Boolean;
begin begin
patchPlateformPaths(fSrcs); patchPlateformPaths(fSrcs);
updateDcd;
doChanged; doChanged;
fModified := false; fModified := false;
hasPatched := false; hasPatched := false;

View File

@ -54,12 +54,12 @@ const
macFname = 'staticMacros.txt'; macFname = 'staticMacros.txt';
defMacros: array[0..5] of string = ( defMacros: array[0..5] of string = (
'$a=auto', '$a=auto',
'$c=class {}', '$c=class {}',
'$s=struct {}', '$s=struct {}',
'$ut=unittest{}', '$ut=unittest{}',
'$fo=for(auto i = 0; ; )', '$fo=for(auto i = 0; ; )',
'$fe=foreach(elem; )' '$fe=foreach(elem; )'
); );
var var

View File

@ -7,7 +7,7 @@ interface
uses uses
Classes, SysUtils, SynEdit, ce_d2syn, ce_txtsyn ,SynEditHighlighter, Classes, SysUtils, SynEdit, ce_d2syn, ce_txtsyn ,SynEditHighlighter,
controls, lcltype, LazSynEditText, SynEditKeyCmds, SynHighlighterLFM, SynEditMouseCmds, controls, lcltype, LazSynEditText, SynEditKeyCmds, SynHighlighterLFM, SynEditMouseCmds,
ce_common, ce_observer, ce_dcd; ce_common, ce_observer;
type type
@ -76,7 +76,7 @@ var
implementation implementation
uses uses
graphics, ce_interfaces, ce_staticmacro; graphics, ce_interfaces, ce_staticmacro, ce_dcd;
{$REGION TCESynMemoPositions ---------------------------------------------------} {$REGION TCESynMemoPositions ---------------------------------------------------}
constructor TCESynMemoPositions.create(aMemo: TCustomSynEdit); constructor TCESynMemoPositions.create(aMemo: TCustomSynEdit);