From b23f72dedacc7c68e2840c5709eef33f8d2e868e Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Wed, 25 Feb 2015 09:22:16 +0100 Subject: [PATCH 1/3] added procedure to accumulate process output in a stream --- src/ce_common.pas | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/ce_common.pas b/src/ce_common.pas index a6102353..7c830c45 100644 --- a/src/ce_common.pas +++ b/src/ce_common.pas @@ -213,6 +213,11 @@ type *) procedure processOutputToStrings(aProcess: TProcess; var aList: TStringList); + (** + * Copy available process output to a stream. + *) + procedure processOutputToStream(aProcess: TProcess; output: TMemoryStream); + (** * Terminates and frees aProcess; *) @@ -810,6 +815,25 @@ begin end; end; +procedure processOutputToStream(aProcess: TProcess; output: TMemoryStream); +var + sum, cnt: Integer; +const + buffSz = 2048; +begin + if not (poUsePipes in aProcess.Options) then + exit; + // + sum := output.Size; + while aProcess.Output.NumBytesAvailable <> 0 do begin + output.SetSize(sum + buffSz); + cnt := aProcess.Output.Read((output.Memory + sum)^, buffSz); + sum += cnt; + end; + output.SetSize(sum); + output.Position := sum; +end; + procedure killProcess(var aProcess: TAsyncProcess); begin if aProcess = nil then From ac5c8e1ad41fa812ff3e9241cb9179ced942b308 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Wed, 25 Feb 2015 09:23:02 +0100 Subject: [PATCH 2/3] fix, in asyncprocess output has to be accumulated in the two events --- cetodo/cetodo.d | 1 + src/ce_todolist.pas | 82 ++++++++++++++++++++------------------------- 2 files changed, 37 insertions(+), 46 deletions(-) diff --git a/cetodo/cetodo.d b/cetodo/cetodo.d index 2859858e..6b46b1e5 100644 --- a/cetodo/cetodo.d +++ b/cetodo/cetodo.d @@ -225,6 +225,7 @@ void main(string[] args) // samples for testing the program as a runnable ('Compile and runfile ...') with '' +// fixme-p8: èuèuuè``u`èuùè // fixme-p8: fixme also handled // TODO-cINVALID_because_no_content: // TODO: set this property as const() to set it read only. diff --git a/src/ce_todolist.pas b/src/ce_todolist.pas index 03f5c3d6..e2f654ee 100644 --- a/src/ce_todolist.pas +++ b/src/ce_todolist.pas @@ -79,11 +79,12 @@ type procedure handleListClick(Sender: TObject); procedure mnuAutoRefreshClick(Sender: TObject); private + fToolOutput: TMemoryStream; fAutoRefresh: Boolean; fSingleClick: Boolean; fProj: TCEProject; fDoc: TCESynMemo; - fToolProcess: TCheckedAsyncProcess; + fToolProc: TCheckedAsyncProcess; fTodos: TTodoItems; fMsgs: ICEMessagesDisplay; fOptions: TCETodoOptions; @@ -107,7 +108,8 @@ type function getContext: TTodoContext; procedure killToolProcess; procedure callToolProcess; - procedure procOutput(sender: TObject); + procedure toolTerminated(sender: TObject); + procedure toolOutputData(sender: TObject); procedure procOutputDbg(sender: TObject); procedure clearTodoList; procedure fillTodoList; @@ -193,6 +195,7 @@ var begin inherited; // + fToolOutput := TMemoryStream.Create; fOptions := TCETodoOptions.Create(self); fOptions.autoRefresh := true; fOptions.Name := 'todolistOptions'; @@ -230,6 +233,7 @@ destructor TCETodoListWidget.destroy; begin fOptions.saveToFile(getCoeditDocPath + OptFname); killToolProcess; + fToolOutput.Free; inherited; end; @@ -364,11 +368,11 @@ end; procedure TCETodoListWidget.killToolProcess; begin - if fToolProcess = nil then exit; + if fToolProc = nil then exit; // - fToolProcess.Terminate(0); - fToolProcess.Free; - fToolProcess := nil; + fToolProc.Terminate(0); + fToolProc.Free; + fToolProc := nil; end; procedure TCETodoListWidget.callToolProcess; @@ -382,26 +386,19 @@ begin // killToolProcess; // process parameter - fToolProcess := TCheckedAsyncProcess.Create(nil); - fToolProcess.Executable := ToolExeName; - fToolProcess.Options := [poUsePipes]; - fToolProcess.ShowWindow := swoHIDE; - fToolProcess.CurrentDirectory := ExtractFileDir(Application.ExeName); - - // Something not quite clear: - // -------------------------- - // actually the two events can be called, depending - // on the amount of data in the output. - // many: OnReadData is called. - // few: OnTerminate is called. - fToolProcess.OnTerminate := @procOutput; - fToolProcess.OnReadData := @procOutput; + fToolProc := TCheckedAsyncProcess.Create(nil); + fToolProc.Executable := ToolExeName; + fToolProc.Options := [poUsePipes]; + fToolProc.ShowWindow := swoHIDE; + fToolProc.CurrentDirectory := ExtractFileDir(Application.ExeName); + fToolProc.OnTerminate := @toolTerminated; + fToolProc.OnReadData := @toolOutputData; // files passed to the tool argument - if ctxt = tcProject then fToolProcess.Parameters.AddText(symbolExpander.get('')) - else fToolProcess.Parameters.Add(symbolExpander.get('')); + if ctxt = tcProject then fToolProc.Parameters.AddText(symbolExpander.get('')) + else fToolProc.Parameters.Add(symbolExpander.get('')); // - fToolProcess.Execute; + fToolProc.Execute; end; procedure TCETodoListWidget.procOutputDbg(sender: TObject); @@ -413,7 +410,7 @@ begin getMessageDisplay(fMsgs); str := TStringList.Create; try - processOutputToStrings(fToolProcess, str); + processOutputToStrings(fToolProc, str); ctxt := getContext; for msg in str do case ctxt of tcNone: fMsgs.message(msg, nil, amcMisc, amkAuto); @@ -425,29 +422,22 @@ begin end; end; -procedure TCETodoListWidget.procOutput(sender: TObject); -var - str: TMemoryStream; - cnt: Integer; - sum: Integer; -const - buffSz = 1024; +procedure TCETodoListWidget.toolOutputData(sender: TObject); begin - sum := 0; - str := TMemoryStream.Create; - try - while fToolProcess.Output.NumBytesAvailable <> 0 do begin - str.SetSize(sum + buffSz); - cnt := fToolProcess.Output.Read((str.Memory + sum)^, buffSz); - sum += cnt; - end; - str.SetSize(sum); - str.Position := 0; - fTodos.loadFromTxtStream(str); - fillTodoList; - finally - str.Free; - end; + processOutputToStream(fToolProc, fToolOutput); +end; + +procedure TCETodoListWidget.toolTerminated(sender: TObject); +begin + processOutputToStream(fToolProc, fToolOutput); + fToolOutput.Position := 0; + //TODO-cbugfix: UTF chars in TODO comments bug either in the widget or the tool, symptom: empty todo list, conditions: to determine. + //fToolOutput.SaveToFile('C:\cetodo_widgetside.txt'); + fTodos.loadFromTxtStream(fToolOutput); + fillTodoList; + fToolProc.OnTerminate := nil; + fToolProc.OnReadData := nil; + fToolOutput.Clear; end; procedure TCETodoListWidget.clearTodoList; From 2c8182223f4fb22c07c99a20df1a677ed22f0349 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Wed, 25 Feb 2015 09:23:29 +0100 Subject: [PATCH 3/3] fix, in asyncprocess, output has to be accumulated in the two events --- cesyms/cesyms.d | 96 +++++++++++++++------------------------------- src/ce_symlist.pas | 40 ++++++++----------- 2 files changed, 48 insertions(+), 88 deletions(-) diff --git a/cesyms/cesyms.d b/cesyms/cesyms.d index 63d54085..d3ebd8e9 100644 --- a/cesyms/cesyms.d +++ b/cesyms/cesyms.d @@ -2,36 +2,6 @@ module cesyms; import std.stdio, std.path, std.file, std.array, std.string; import std.d.lexer, std.d.ast, std.d.parser; -static import std.conv; - -interface I{} - -alias Int32 = int; -//alias long Int64; - -enum E -{ - e1, - e2, - e3, -} - -enum {opt1,opt2} - -class A -{ - class AA - { - class AA1{} - class AA2{} - } - - class BB - { - class BB1{} - class BB2{} - } -} enum SymbolType { @@ -58,18 +28,18 @@ struct Symbol void serialize(ref Appender!string lfmApp) { - lfmApp.put(" \r item\r"); + lfmApp.put("\ritem\r"); - lfmApp.put(format(" line = %d\r", line)); - lfmApp.put(format(" col = %d\r", col)); - lfmApp.put(format(" name = '%s'\r", name)); - lfmApp.put(format(" symType = %s\r", type)); + lfmApp.put(format("line = %d\r", line)); + lfmApp.put(format("col = %d\r", col)); + lfmApp.put(format("name = '%s'\r", name)); + lfmApp.put(format("symType = %s\r", type)); - lfmApp.put(" subs = <"); + lfmApp.put("subs = <"); if (subs.length) foreach(Symbol * sub; subs) sub.serialize(lfmApp); lfmApp.put(">\r"); - lfmApp.put(" end\r"); + lfmApp.put("end\r"); } } @@ -91,30 +61,27 @@ void main(string[] args) { slb.resetRoot; slb.visit(decl); - } - - - // TODO-cfeature: Outputs the symbol tree in a format handlable by a Coedit widget - - int level = -1; - void print(Symbol * s) - { - foreach(i; 0 .. level) write("."); - level++; - write(s.name, '\r'); - foreach(ss; s.subs) - print(ss); - - level--; } - //print(&slb.root); + + version(none) + { + int level = -1; + void print(Symbol * s) + { + foreach(i; 0 .. level) write("."); + level++; + write(s.name, '\r'); + foreach(ss; s.subs) + print(ss); + + level--; + } + print(&slb.root); + } auto str = slb.serialize; - - //std.file.write(r"C:\too.txt",cast(ubyte[])str); - + //std.file.write(r"C:\tool.txt",cast(ubyte[])str); write(str); - stdout.flush; } class SymbolListBuilder : ASTVisitor @@ -134,12 +101,11 @@ class SymbolListBuilder : ASTVisitor Appender!string lfmApp; lfmApp.reserve(count * 64); - lfmApp.put("object TSymbolList\r symbols = <"); + lfmApp.put("object TSymbolList\rsymbols = <"); foreach(Symbol * sym; root.subs) sym.serialize(lfmApp); lfmApp.put(">\rend\r\n"); - return lfmApp.data; - + return lfmApp.data; } /// returns a new symbol if the declarator is based on a Token named "name". @@ -161,7 +127,7 @@ class SymbolListBuilder : ASTVisitor { count++; auto result = new Symbol; - result.name = adt.name.text.idup; + result.name = adt.name.text; result.line = adt.name.line; result.col = adt.name.column; parent.subs ~= result; @@ -185,7 +151,7 @@ class SymbolListBuilder : ASTVisitor dt.accept(this); } } - + final override void visit(const AliasDeclaration decl) { // old alias syntax not supported by this. @@ -201,7 +167,7 @@ class SymbolListBuilder : ASTVisitor final override void visit(const EnumDeclaration decl) { - // TODO-ctest: try to see if what dmd outputs as , "enum member" is handled. + //TODO-ctest: try to see if what dmd outputs as , "enum member" is handled. namedVisitorImpl!(EnumDeclaration, SymbolType._class)(decl); } @@ -241,8 +207,8 @@ class SymbolListBuilder : ASTVisitor final override void visit(const MixinDeclaration decl) { - // TODO-cfeature: MixinDeclaration, just display the name of the mixed template. - // the template might be implemented in another module so their ùeùbrs cant be displayed. + // TODO-cfeature: MixinDeclaration, just display the name of the mixed template. + // the template might be implemented in another module so their cant be displayed. } final override void visit(const StructDeclaration decl) diff --git a/src/ce_symlist.pas b/src/ce_symlist.pas index a8f14d8f..b1f9b79e 100644 --- a/src/ce_symlist.pas +++ b/src/ce_symlist.pas @@ -94,6 +94,7 @@ type fAutoRefresh: boolean; fRefreshOnChange: boolean; fRefreshOnFocus: boolean; + fToolOutput: TMemoryStream; ndAlias, ndClass, ndEnum, ndFunc, ndUni: TTreeNode; ndImp, ndIntf, ndMix, ndStruct, ndTmp, ndVar: TTreeNode; procedure TreeDblClick(Sender: TObject); @@ -106,7 +107,8 @@ type procedure clearTree; // procedure callToolProc; - procedure symbolListProduced(sender: TObject); + procedure toolOutputData(sender: TObject); + procedure toolTerminated(sender: TObject); // procedure optget_AutoRefresh(aWriter: TWriter); procedure optset_AutoRefresh(aReader: TReader); @@ -239,6 +241,7 @@ begin inherited; // allow empty name if owner is nil fSyms := TSymbolList.create(nil); + fToolOutput := TMemoryStream.create; // ndAlias := Tree.Items[0]; ndClass := Tree.Items[1]; @@ -271,6 +274,7 @@ begin EntitiesConnector.removeObserver(self); // killProcess(fToolProc); + fToolOutput.free; fSyms.Free; inherited; end; @@ -517,8 +521,8 @@ begin fToolProc.ShowWindow := swoHIDE; fToolProc.Options := [poUsePipes]; fToolProc.Executable := 'cesyms'; - fToolProc.OnTerminate := @symbolListProduced; - fToolProc.OnReadData := @symbolListProduced; + fToolProc.OnTerminate := @toolTerminated; + fToolProc.OnReadData := @toolOutputData; fToolProc.CurrentDirectory := ExtractFileDir(Application.ExeName); // focused source @@ -531,13 +535,14 @@ begin fToolProc.Execute; end; -procedure TCESymbolListWidget.symbolListProduced(sender: TObject); +procedure TCESymbolListWidget.toolOutputData(sender: TObject); +begin + processOutputToStream(TProcess(sender), fToolOutput); +end; + +procedure TCESymbolListWidget.toolTerminated(sender: TObject); var - cnt, sum: Integer; - str: TmemoryStream; i: Integer; -const - buffSz = 1024; // procedure symbolToTreeNode(sym: TSymbol); var @@ -573,23 +578,12 @@ begin updateVisibleCat; if fDoc = nil then exit; // - sum := 0; - str := TMemoryStream.Create; - try - while fToolProc.Output.NumBytesAvailable <> 0 do begin - str.SetSize(sum + buffSz); - cnt := fToolProc.Output.Read((str.Memory + sum)^, buffSz); - sum += cnt; - end; - str.SetSize(sum); - str.Position := 0; - //str.SaveToFile('C:\symlist.txt'); - fSyms.LoadFromTool(str); - finally - str.Free; - end; + processOutputToStream(TProcess(sender), fToolOutput); + fToolOutput.Position := 0; + fSyms.LoadFromTool(fToolOutput); fToolProc.OnTerminate := nil; fToolProc.OnReadData := nil; + fToolOutput.Clear; // tree.BeginUpdate; for i := 0 to fSyms.symbols.Count-1 do