From 6be3267993949cf557cae7e1f60d7723443a8ee9 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Thu, 27 Apr 2017 11:43:16 +0200 Subject: [PATCH] add an editor command to insert ddoc templates, close #135 --- dastworx/dastworx.ce | 1 + dastworx/src/ddoc_template.d | 193 +++++++++++++++++++++++++++++++++++ dastworx/src/main.d | 22 +++- src/ce_dastworx.pas | 27 +++++ src/ce_editor.lfm | 4 + src/ce_editor.pas | 8 ++ src/ce_synmemo.pas | 45 +++++++- 7 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 dastworx/src/ddoc_template.d diff --git a/dastworx/dastworx.ce b/dastworx/dastworx.ce index 8e761316..86b1c885 100644 --- a/dastworx/dastworx.ce +++ b/dastworx/dastworx.ce @@ -42,6 +42,7 @@ object CurrentProject: TCENativeProject 'src/mainfun.d' 'src/common.d' 'src/halstead.d' + 'src/ddoc_template.d' ) ConfigurationIndex = 1 end diff --git a/dastworx/src/ddoc_template.d b/dastworx/src/ddoc_template.d new file mode 100644 index 00000000..20a34b53 --- /dev/null +++ b/dastworx/src/ddoc_template.d @@ -0,0 +1,193 @@ +module ddoc_template; + +import + std.stdio; +import + iz.memory; +import + dparse.ast, dparse.lexer, dparse.parser, dparse.rollback_allocator; + +/** + * Finds the declaration at caretLine and write its ddoc template + * in the standard output. + */ +void getDdocTemplate(const(Module) mod, int caretLine) +{ + DDocTemplateGenerator dtg = construct!DDocTemplateGenerator(caretLine); + dtg.visit(mod); +} + +final class DDocTemplateGenerator: ASTVisitor +{ + alias visit = ASTVisitor.visit; + +private: + + int _caretline; + +public: + + this(int caretline) + { + _caretline = caretline; + } + + override void visit(const(FunctionDeclaration) decl) + { + if (decl.name.line == _caretline) + { + writeln("/**\n * \n * \n * \n *"); + + if (decl.templateParameters || decl.parameters) + { + writeln(" * Params:"); + + if (decl.templateParameters && decl.templateParameters.templateParameterList) + { + foreach(const TemplateParameter p; decl.templateParameters + .templateParameterList.items) + { + if (p.templateAliasParameter) + writeln(" * ", p.templateAliasParameter.identifier.text, " = "); + else if (p.templateTupleParameter) + writeln(" * ", p.templateTupleParameter.identifier.text, " = "); + else if (p.templateTypeParameter) + writeln(" * ", p.templateTypeParameter.identifier.text, " = "); + else if (p.templateValueParameter) + writeln(" * ", p.templateValueParameter.identifier.text, " = "); + } + } + if (decl.parameters) + { + foreach(i, const Parameter p; decl.parameters.parameters) + { + if (p.name.text != "") + writeln(" * ", p.name.text, " = "); + else + writeln(" * __param", i, " = "); + } + } + } + + if (decl.returnType) + { + if (decl.returnType.type2 && decl.returnType.type2 + && decl.returnType.type2.builtinType != tok!"void") + writeln(" * \n * Returns: "); + } + + writeln(" */"); + + } + else if (decl.name.line > _caretline) + return; + decl.accept(this); + } + + override void visit(const(TemplateDeclaration) decl) + { + visitTemplateOrAggregate(decl); + } + + override void visit(const(ClassDeclaration) decl) + { + visitTemplateOrAggregate(decl); + } + + override void visit(const(StructDeclaration) decl) + { + visitTemplateOrAggregate(decl); + } + + override void visit(const(UnionDeclaration) decl) + { + visitTemplateOrAggregate(decl); + } + + private void visitTemplateOrAggregate(T)(const(T) decl) + { + if (decl.name.line == _caretline) + { + writeln("/**\n * \n * \n * \n *"); + + if (decl.templateParameters) + { + writeln(" * Params:"); + + if (decl.templateParameters && decl.templateParameters.templateParameterList) + { + foreach(const TemplateParameter p; decl.templateParameters + .templateParameterList.items) + { + if (p.templateAliasParameter) + writeln(" * ", p.templateAliasParameter.identifier.text, " = "); + else if (p.templateTupleParameter) + writeln(" * ", p.templateTupleParameter.identifier.text, " = "); + else if (p.templateTypeParameter) + writeln(" * ", p.templateTypeParameter.identifier.text, " = "); + else if (p.templateValueParameter) + writeln(" * ", p.templateValueParameter.identifier.text, " = "); + } + } + + } + writeln(" */"); + + } + else if (decl.name.line > _caretline) + return; + decl.accept(this); + } +} + +version(unittest) +{ + DDocTemplateGenerator parseAndVisit(const(char)[] source, int caretLine) + { + writeln; + RollbackAllocator allocator; + LexerConfig config = LexerConfig("", StringBehavior.source, WhitespaceBehavior.skip); + StringCache cache = StringCache(StringCache.defaultBucketCount); + const(Token)[] tokens = getTokensForParser(cast(ubyte[]) source, config, &cache); + Module mod = parseModule(tokens, "", &allocator); + DDocTemplateGenerator result = construct!(DDocTemplateGenerator)(caretLine); + result.visit(mod); + return result; + } +} + +unittest +{ + q{ module a; + void foo(A...)(A a){} + }.parseAndVisit(2); +} + +unittest +{ + q{ module a; + void foo()(){} + }.parseAndVisit(2); +} + +unittest +{ + q{ module a; + int foo(int){} + }.parseAndVisit(2); +} + +unittest +{ + q{ module a; + class Foo(T, A...){} + }.parseAndVisit(2); +} + +unittest +{ + q{ module a; + struct Foo(alias Fun, A...){} + }.parseAndVisit(2); +} + diff --git a/dastworx/src/main.d b/dastworx/src/main.d index ff19ff7f..827c9656 100644 --- a/dastworx/src/main.d +++ b/dastworx/src/main.d @@ -9,9 +9,10 @@ import import dparse.lexer, dparse.parser, dparse.ast, dparse.rollback_allocator; import - common, todos, symlist, imports, mainfun, halstead; + common, todos, symlist, imports, mainfun, halstead, ddoc_template; +private __gshared int caretLine; private __gshared bool deepSymList; private __gshared static Appender!(ubyte[]) source; private __gshared static Appender!(AstErrors) errors; @@ -50,7 +51,8 @@ void main(string[] args) // options for the work getopt(args, std.getopt.config.passThrough, - "d", &deepSymList + "d", &deepSymList, + "l", &caretLine ); // launch directly a work @@ -60,6 +62,7 @@ void main(string[] args) "s", &handleSymListOption, "t", &handleTodosOption, "H", &handleHalsteadOption, + "K", &handleDdocTemplateOption, ); } @@ -137,6 +140,21 @@ void handleHalsteadOption() .performHalsteadMetrics; } +/// Handles the "-D" option: write the ddoc template for a given declaration +void handleDdocTemplateOption() +{ + mixin(logCall); + + RollbackAllocator alloc; + StringCache cache = StringCache(StringCache.defaultBucketCount); + LexerConfig config = LexerConfig("", StringBehavior.source); + + source.data + .getTokensForParser(config, &cache) + .parseModule("", &alloc, &ignoreErrors) + .getDdocTemplate(caretLine); +} + private void handleErrors(string fname, size_t line, size_t col, string message, bool err) { diff --git a/src/ce_dastworx.pas b/src/ce_dastworx.pas index aeb49610..31566807 100644 --- a/src/ce_dastworx.pas +++ b/src/ce_dastworx.pas @@ -22,6 +22,8 @@ procedure getModulesImports(const files: string; results: TStrings); procedure getHalsteadMetrics(source: TStrings; out jsn: TJSONObject); +procedure getDdocTemplate(source, res: TStrings;caretLine: integer); + implementation var @@ -125,5 +127,30 @@ begin end; end; +procedure getDdocTemplate(source, res: TStrings; caretLine: integer); +var + prc: TProcess; + str: string; +begin + str := getToolName; + if str.isEmpty then + exit; + prc := TProcess.Create(nil); + try + prc.Executable := str; + prc.Parameters.Add('-K'); + prc.Parameters.Add('-l' + caretLine.ToString); + prc.Options := [poUsePipes {$IFDEF WINDOWS}, poNewConsole{$ENDIF}]; + prc.ShowWindow := swoHIDE; + prc.Execute; + str := source.Text; + prc.Input.Write(str[1], str.length); + prc.CloseInput; + processOutputToStrings(prc, res); + finally + prc.Free; + end; +end; + end. diff --git a/src/ce_editor.lfm b/src/ce_editor.lfm index b751dad4..39ce91ce 100644 --- a/src/ce_editor.lfm +++ b/src/ce_editor.lfm @@ -155,6 +155,10 @@ inherited CEEditorWidget: TCEEditorWidget object MenuItem12: TMenuItem Caption = '-' end + object mnuedDdocTmp: TMenuItem + Caption = 'Insert DDOC template' + OnClick = mnuedDdocTmpClick + end object mnuedRename: TMenuItem Caption = 'Rename identifier' OnClick = mnuedRenameClick diff --git a/src/ce_editor.pas b/src/ce_editor.pas index 21a4cc3e..7368eb0d 100644 --- a/src/ce_editor.pas +++ b/src/ce_editor.pas @@ -58,6 +58,7 @@ type MenuItem10: TMenuItem; MenuItem11: TMenuItem; MenuItem12: TMenuItem; + mnuedDdocTmp: TMenuItem; mnuedPrevProtGrp: TMenuItem; mnuedNextProtGrp: TMenuItem; MenuItem2: TMenuItem; @@ -89,6 +90,7 @@ type macRecorder: TSynMacroRecorder; editorStatus: TStatusBar; mnuEditor: TPopupMenu; + procedure mnuedDdocTmpClick(Sender: TObject); procedure mnuedPrevProtGrpClick(Sender: TObject); procedure mnuedNextProtGrpClick(Sender: TObject); procedure mnuedNextCareaClick(Sender: TObject); @@ -900,6 +902,12 @@ begin fDoc.previousProtectionGroup; end; +procedure TCEEditorWidget.mnuedDdocTmpClick(Sender: TObject); +begin + if fDoc.isNotNil then + fDoc.insertDdocTemplate; +end; + procedure TCEEditorWidget.mnuedNextProtGrpClick(Sender: TObject); begin if fDoc.isNotNil then diff --git a/src/ce_synmemo.pas b/src/ce_synmemo.pas index b1551d80..91f4c1c3 100644 --- a/src/ce_synmemo.pas +++ b/src/ce_synmemo.pas @@ -12,7 +12,7 @@ uses md5, //SynEditMarkupFoldColoring, Clipbrd, fpjson, jsonparser, LazUTF8, LazUTF8Classes, Buttons, StdCtrls, - ce_common, ce_writableComponent, ce_d2syn, ce_txtsyn, ce_dialogs, + ce_common, ce_writableComponent, ce_d2syn, ce_txtsyn, ce_dialogs, ce_dastworx, ce_sharedres, ce_dlang, ce_stringrange, ce_dbgitf, ce_observer, ce_diff; type @@ -272,6 +272,7 @@ type procedure addCurLineBreakPoint; procedure removeCurLineBreakPoint; procedure toggleCurLineBreakpoint; + procedure insertDdocTemplate; function implementMain: THasMain; procedure replaceUndoableContent(const value: string); // @@ -346,6 +347,7 @@ const ecAddBreakpoint = ecUserFirst + 22; ecRemoveBreakpoint = ecUserFirst + 23; ecToggleBreakpoint = ecUserFirst + 24; + ecInsertDdocTemplate = ecUserFirst + 25; var D2Syn: TSynD2Syn; // used as model to set the options when no editor exists. @@ -989,6 +991,7 @@ begin AddKey(ecAddBreakpoint, 0, [], 0, []); AddKey(ecRemoveBreakpoint, 0, [], 0, []); AddKey(ecToggleBreakpoint, 0, [], 0, []); + AddKey(ecInsertDdocTemplate, 0, [], 0, []); end; end; @@ -1019,6 +1022,7 @@ begin 'ecAddBreakpoint': begin Int := ecAddBreakpoint; exit(true); end; 'ecRemoveBreakpoint': begin Int := ecRemoveBreakpoint; exit(true); end; 'ecToggleBreakpoint': begin Int := ecToggleBreakpoint; exit(true); end; + 'ecInsertDdocTemplate': begin Int := ecInsertDdocTemplate; exit(true); end; else exit(false); end; end; @@ -1050,6 +1054,7 @@ begin ecAddBreakpoint: begin Ident := 'ecAddBreakpoint'; exit(true); end; ecRemoveBreakpoint: begin Ident := 'ecRemoveBreakpoint'; exit(true); end; ecToggleBreakpoint: begin Ident := 'ecToggleBreakpoint'; exit(true); end; + ecInsertDdocTemplate: begin Ident := 'ecInsertDdocTemplate'; exit(true); end; else exit(false); end; end; @@ -1120,6 +1125,8 @@ begin removeCurLineBreakPoint; ecToggleBreakpoint: toggleCurLineBreakpoint; + ecInsertDdocTemplate: + insertDdocTemplate; end; if fOverrideColMode and not SelAvail then begin @@ -1839,6 +1846,42 @@ begin else removeBreakPoint(CaretY); end; + +procedure TCESynMemo.insertDdocTemplate; +var + d: TStringList; + i: integer; + j: integer; + k: integer; + s: string; + p: TPoint; +begin + d := TStringList.Create; + try + getDdocTemplate(lines, d, CaretY); + if d.Text.isNotEmpty then + begin + BeginUndoBlock; + ExecuteCommand(ecLineStart, #0, nil); + k := CaretX; + p.y:= CaretY -1 ; + p.x:= 1 ; + ExecuteCommand(ecGotoXY, #0, @p); + for i := 0 to d.Count-1 do + begin + s := d[i]; + ExecuteCommand(ecLineBreak, #0, nil); + while caretX < k do + ExecuteCommand(ecTab, #0, nil); + for j := 1 to s.length do + ExecuteCommand(ecChar, s[j], nil); + end; + EndUndoBlock; + end; + finally + d.Free; + end; +end; {$ENDREGION} {$REGION DDoc & CallTip --------------------------------------------------------}