diff --git a/src/ce_dcd.pas b/src/ce_dcd.pas index b248f215..93bd54d8 100644 --- a/src/ce_dcd.pas +++ b/src/ce_dcd.pas @@ -5,118 +5,206 @@ unit ce_dcd; interface 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; - -(** - * frees the server: e.g: to remove some bugy imports from the libman. - *) -procedure freeServer; - -(** - * recreates the server. - *) -procedure createServer; - -(** - * Adds a folder of d sources for DCD. - *) -procedure addDcdImport(const aFilename: string); - -(** - * gets a list of propositions for the identifier at aPosition in aFilename. - *) -procedure getCompletion(const aFilename: string; aPosition: Integer; const list: TStrings); - -(** - * tries to get the DDoc comment for the identifier at aPosition in aFilename. - *) -procedure getHint(const aFilename: string; aPosition: Integer; const list: TStrings); - -(** - * tries to get the symbol location of the identifier at aPosition in aFilename. - * after the call aFilename and aPosition contains the location filename and position. - *) -procedure getSymbolLoc(var aFilename: string; var aPosition: Integer); +type + (** + * Wrap the dcd-server and dcd-clients processes. + * + * Projects folder are automatically imported: ICEProjectObserver. + * Completion, hints and declaration finder automatically work on the current + * document: ICEMultiDocObserver. + *) + TCEDcdWrapper = class(TWritableComponent, ICEProjectObserver, ICEMultiDocObserver) + private + fTempLines: TStringList; + //fPortNum: Word; + fClient, fServer: TProcess; + fAvailable: boolean; + fDoc: TCESynMemo; + fProj: TCEProject; + procedure killServer; + // + procedure projNew(aProject: TCEProject); + procedure projChanged(aProject: TCEProject); + procedure projClosing(aProject: TCEProject); + procedure projFocused(aProject: TCEProject); + // + procedure docNew(aDoc: TCESynMemo); + procedure docFocused(aDoc: TCESynMemo); + procedure docChanged(aDoc: TCESynMemo); + procedure docClosing(aDoc: TCESynMemo); + public + constructor create(aOwner: TComponent); override; + destructor destroy; override; + // + 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 - dcdOn: boolean; + DcdWrapper: TCEDcdWrapper; implementation -var - DCD_server: TProcess = nil; - DCD_client: TProcess = nil; - lines: TStringList; - -procedure lazyServerStart; +{$REGION Standard Comp/Obj------------------------------------------------------} +constructor TCEDcdWrapper.create(aOwner: TComponent); +const + clientName = 'dcd-client' + exeExt; + serverName = 'dcd-server' + exeExt; begin - if not DCD_server.Running then - 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; + inherited; // - if not DCD_server.Running then - DCD_server.Parameters.Add('-I' + aFilename) - else if DCD_client <> nil then begin - DCD_client.Parameters.Clear; - DCD_client.Parameters.Add('-I' + aFilename); - DCD_client.Execute; - end; + fAvailable := exeInSysPath(clientName) and exeInSysPath(serverName); + if not fAvailable then + exit; + // + fClient := TProcess.Create(self); + fClient.Executable := clientName; + 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; -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 i, j: NativeInt; kind: Char; item: string; asComp, asTips: boolean; begin - if not dcdOn then - exit; - lazyServerStart; + if not fAvailable then exit; + if fDoc = nil then exit; // - DCD_client.Parameters.Clear; - DCD_client.Parameters.Add('-c'); - DCD_client.Parameters.Add(intToStr(aPosition)); - DCD_client.Parameters.Add(aFilename); - DCD_client.Execute; + fTempLines.Assign(fDoc.Lines); + fTempLines.SaveToFile(fDoc.tempFilename); + // + fClient.Parameters.Clear; + 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; - list.Clear; - for i := j to lines.Count-1 do + aList.Clear; + for i := j to fTempLines.Count-1 do begin - item := lines.Strings[i]; + item := fTempLines.Strings[i]; kind := item[length(item)]; setLength(item, length(item)-2); case kind of @@ -138,57 +226,55 @@ begin 't': item += ' (template) '; 'T': item += ' (mixin) '; end; - list.Add(item); + aList.Add(item); end; end; -procedure getHint(const aFilename: string; aPosition: Integer; const list: TStrings); +procedure TCEDcdWrapper.getDdocFromCursor(out aComment: string); var i: Integer; - str: string; begin - if not dcdOn then - exit; - lazyServerStart; - if DCD_client.Running then - exit; + if not fAvailable then exit; + if fDoc = nil then exit; // - DCD_client.Parameters.Clear; - DCD_client.Parameters.Add('-c'); - DCD_client.Parameters.Add(intToStr(aPosition)); - DCD_client.Parameters.Add('-d'); - DCD_client.Parameters.Add(aFilename); - DCD_client.Execute; + fTempLines.Assign(fDoc.Lines); + fTempLines.SaveToFile(fDoc.tempFilename); // - list.LoadFromStream(DCD_client.Output); - for i := 0 to list.Count-1 do - begin - str := list.Strings[i]; - list.Strings[i] := ReplaceStr(str, '\n', ''); - end; + fClient.Parameters.Clear; + fClient.Parameters.Add('-d'); + fClient.Parameters.Add('-c'); + fClient.Parameters.Add(intToStr(fDoc.SelStart-1)); + fClient.Parameters.Add(fDoc.tempFilename); + fClient.Execute; + // + aComment := ''; + fTempLines.LoadFromStream(fClient.Output); + for i := 0 to fTempLines.Count-1 do + aComment += ReplaceStr(fTempLines.Strings[i], '\n', LineEnding); + end; -procedure getSymbolLoc(var aFilename: string; var aPosition: Integer); +procedure TCEDcdWrapper.getDeclFromCursor(out aFilename: string; out aPosition: Integer); var - i: Integer; - str, loc: string; + i: Integer; + str, loc: string; begin - if not dcdOn then - exit; - lazyServerStart; - if DCD_client.Running then - exit; + if not fAvailable then exit; + if fDoc = nil then exit; // - DCD_client.Parameters.Clear; - DCD_client.Parameters.Add('-l'); - DCD_client.Parameters.Add('-c'); - DCD_client.Parameters.Add(intToStr(aPosition)); - DCD_client.Parameters.Add(aFilename); - DCD_client.Execute; + fTempLines.Assign(fDoc.Lines); + fTempLines.SaveToFile(fDoc.tempFilename); + // + fClient.Parameters.Clear; + fClient.Parameters.Add('-l'); + fClient.Parameters.Add('-c'); + fClient.Parameters.Add(intToStr(fDoc.SelStart - 1)); + fClient.Parameters.Add(fDoc.tempFilename); + fClient.Execute; // str := 'a'; setlength(str, 256); - i := DCD_client.Output.Read(str[1], 256); + i := fClient.Output.Read(str[1], 256); setLength(str, i); if str <> '' then begin @@ -196,25 +282,15 @@ begin if i = -1 then exit; loc := str[i+1..length(str)]; - str := str[1..i-1]; - aFilename := str; + aFilename := str[1..i-1]; loc := ReplaceStr(loc, LineEnding, ''); aPosition := strToIntDef(loc, -1); end; end; +{$ENDREGION} initialization - createServer; - 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; + DcdWrapper := TCEDcdWrapper.create(nil); finalization - DCD_server.Active := false; - DCD_client.Active := false; - DCD_server.Free; - DCD_client.Free; - lines.Free; + DcdWrapper.Free; end. diff --git a/src/ce_editor.pas b/src/ce_editor.pas index dea831b2..ca16e732 100644 --- a/src/ce_editor.pas +++ b/src/ce_editor.pas @@ -52,7 +52,6 @@ type procedure addEditor; procedure removeEditor(const aIndex: NativeInt); procedure focusedEditorChanged; - function getEditorHint: string; // procedure docNew(aDoc: TCESynMemo); procedure docClosing(aDoc: TCESynMemo); @@ -249,85 +248,27 @@ end; procedure TCEEditorWidget.getSymbolLoc; var - str: TMemoryStream; srcpos: Integer; - ftempname, fname: string; + fname: string; begin - if not dcdOn then exit; - if fDoc = nil then exit; + if not DcdWrapper.available then exit; // - str := TMemoryStream.Create; - try - ftempname := fDoc.tempFilename; - fDoc.Lines.SaveToStream(str); - str.SaveToFile(ftempname); - fname := ftempname; - 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; + DcdWrapper.getDeclFromCursor(fname, srcpos); + if fname <> fDoc.fileName then if fileExists(fname) then + CEMainForm.openFile(fname); + if srcpos <> -1 then begin + fDoc.SelStart := srcpos; + fDoc.SelectWord; end; end; procedure TCEEditorWidget.getCompletionList; -var - str: TMemoryStream; - srcpos: NativeInt; - fname: string; begin - if not dcdOn then exit; - if fDoc = nil then exit; + if not DcdWrapper.available then exit; // - str := TMemoryStream.Create; - try - completion.Position := 0; // previous index could cause an error here. - 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; + completion.Position := 0; + completion.ItemList.Clear; + DcdWrapper.getComplAtCursor(completion.ItemList); end; procedure TCEEditorWidget.UpdateByEvent; diff --git a/src/ce_libman.pas b/src/ce_libman.pas index 2297410c..16286f08 100644 --- a/src/ce_libman.pas +++ b/src/ce_libman.pas @@ -81,14 +81,12 @@ var itm: TLibraryItem; i: NativeInt; begin - if not dcdOn then exit; - // - ce_dcd.freeServer; - ce_dcd.createServer; + if not DcdWrapper.available then exit; + // note: new items are directly handled but removed ones still in cache until next cession. for i := 0 to fCol.Count-1 do begin itm := TLibraryItem(fCol.Items[i]); - ce_dcd.addDcdImport(itm.libSourcePath); + DcdWrapper.addImportFolder(itm.libSourcePath); end; end; diff --git a/src/ce_main.pas b/src/ce_main.pas index 7f831020..6eadb82b 100644 --- a/src/ce_main.pas +++ b/src/ce_main.pas @@ -929,12 +929,11 @@ procedure TCEMainForm.ApplicationProperties1ShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo); begin CanShow := true; - {if fDoc <> nil then - if fDoc.Focused then - begin - HintStr := fEditWidg.getEditorHint; - CanShow := HintStr <> ''; - end;} + //if fDoc <> nil then if fDoc.Focused then + //begin + // DcdWrapper.getDdocFromCursor(HintStr); + // CanShow := HintStr <> ''; + //end; end; {$ENDREGION} diff --git a/src/ce_project.pas b/src/ce_project.pas index b2542ef6..59dafa70 100644 --- a/src/ce_project.pas +++ b/src/ce_project.pas @@ -39,7 +39,6 @@ type fCanBeRun: boolean; procedure updateOutFilename; procedure doChanged; - procedure updateDcd; procedure setLibAliases(const aValue: TStringList); procedure subMemberChanged(sender : TObject); procedure setOptsColl(const aValue: TCollection); @@ -144,14 +143,6 @@ begin Configuration[i].onChanged := @subMemberChanged; 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); var relSrc, absSrc: string; @@ -162,7 +153,6 @@ begin if aFilename = absSrc then exit; end; fSrcs.Add(ExtractRelativepath(fBasePath,aFilename)); - updateDcd; end; procedure TCEProject.setRoot(const aValue: string); @@ -208,7 +198,6 @@ begin beforeChanged; fSrcs.Assign(aValue); patchPlateformPaths(fSrcs); - updateDcd; afterChanged; end; @@ -363,7 +352,6 @@ var hasPatched: Boolean; begin patchPlateformPaths(fSrcs); - updateDcd; doChanged; fModified := false; hasPatched := false; diff --git a/src/ce_staticmacro.pas b/src/ce_staticmacro.pas index 57841196..647b7e7a 100644 --- a/src/ce_staticmacro.pas +++ b/src/ce_staticmacro.pas @@ -54,12 +54,12 @@ const macFname = 'staticMacros.txt'; defMacros: array[0..5] of string = ( - '$a=auto', - '$c=class {}', - '$s=struct {}', - '$ut=unittest{}', - '$fo=for(auto i = 0; ; )', - '$fe=foreach(elem; )' + '$a=auto', + '$c=class {}', + '$s=struct {}', + '$ut=unittest{}', + '$fo=for(auto i = 0; ; )', + '$fe=foreach(elem; )' ); var diff --git a/src/ce_synmemo.pas b/src/ce_synmemo.pas index 4616d3d0..a40770ce 100644 --- a/src/ce_synmemo.pas +++ b/src/ce_synmemo.pas @@ -7,7 +7,7 @@ interface uses Classes, SysUtils, SynEdit, ce_d2syn, ce_txtsyn ,SynEditHighlighter, controls, lcltype, LazSynEditText, SynEditKeyCmds, SynHighlighterLFM, SynEditMouseCmds, - ce_common, ce_observer, ce_dcd; + ce_common, ce_observer; type @@ -76,7 +76,7 @@ var implementation uses - graphics, ce_interfaces, ce_staticmacro; + graphics, ce_interfaces, ce_staticmacro, ce_dcd; {$REGION TCESynMemoPositions ---------------------------------------------------} constructor TCESynMemoPositions.create(aMemo: TCustomSynEdit);