add an editor command to insert ddoc templates, close #135

This commit is contained in:
Basile Burg 2017-04-27 11:43:16 +02:00
parent 260323080f
commit 6be3267993
No known key found for this signature in database
GPG Key ID: 1868039F415CB8CF
7 changed files with 297 additions and 3 deletions

View File

@ -42,6 +42,7 @@ object CurrentProject: TCENativeProject
'src/mainfun.d' 'src/mainfun.d'
'src/common.d' 'src/common.d'
'src/halstead.d' 'src/halstead.d'
'src/ddoc_template.d'
) )
ConfigurationIndex = 1 ConfigurationIndex = 1
end end

View File

@ -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 * <short description> \n * \n * <detailed description>\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, " = <description>");
else if (p.templateTupleParameter)
writeln(" * ", p.templateTupleParameter.identifier.text, " = <description>");
else if (p.templateTypeParameter)
writeln(" * ", p.templateTypeParameter.identifier.text, " = <description>");
else if (p.templateValueParameter)
writeln(" * ", p.templateValueParameter.identifier.text, " = <description>");
}
}
if (decl.parameters)
{
foreach(i, const Parameter p; decl.parameters.parameters)
{
if (p.name.text != "")
writeln(" * ", p.name.text, " = <description>");
else
writeln(" * __param", i, " = <description>");
}
}
}
if (decl.returnType)
{
if (decl.returnType.type2 && decl.returnType.type2
&& decl.returnType.type2.builtinType != tok!"void")
writeln(" * \n * Returns: <return description>");
}
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 * <short description> \n * \n * <detailed description>\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, " = <description>");
else if (p.templateTupleParameter)
writeln(" * ", p.templateTupleParameter.identifier.text, " = <description>");
else if (p.templateTypeParameter)
writeln(" * ", p.templateTypeParameter.identifier.text, " = <description>");
else if (p.templateValueParameter)
writeln(" * ", p.templateValueParameter.identifier.text, " = <description>");
}
}
}
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);
}

View File

@ -9,9 +9,10 @@ import
import import
dparse.lexer, dparse.parser, dparse.ast, dparse.rollback_allocator; dparse.lexer, dparse.parser, dparse.ast, dparse.rollback_allocator;
import 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 bool deepSymList;
private __gshared static Appender!(ubyte[]) source; private __gshared static Appender!(ubyte[]) source;
private __gshared static Appender!(AstErrors) errors; private __gshared static Appender!(AstErrors) errors;
@ -50,7 +51,8 @@ void main(string[] args)
// options for the work // options for the work
getopt(args, std.getopt.config.passThrough, getopt(args, std.getopt.config.passThrough,
"d", &deepSymList "d", &deepSymList,
"l", &caretLine
); );
// launch directly a work // launch directly a work
@ -60,6 +62,7 @@ void main(string[] args)
"s", &handleSymListOption, "s", &handleSymListOption,
"t", &handleTodosOption, "t", &handleTodosOption,
"H", &handleHalsteadOption, "H", &handleHalsteadOption,
"K", &handleDdocTemplateOption,
); );
} }
@ -137,6 +140,21 @@ void handleHalsteadOption()
.performHalsteadMetrics; .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, private void handleErrors(string fname, size_t line, size_t col, string message,
bool err) bool err)
{ {

View File

@ -22,6 +22,8 @@ procedure getModulesImports(const files: string; results: TStrings);
procedure getHalsteadMetrics(source: TStrings; out jsn: TJSONObject); procedure getHalsteadMetrics(source: TStrings; out jsn: TJSONObject);
procedure getDdocTemplate(source, res: TStrings;caretLine: integer);
implementation implementation
var var
@ -125,5 +127,30 @@ begin
end; end;
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. end.

View File

@ -155,6 +155,10 @@ inherited CEEditorWidget: TCEEditorWidget
object MenuItem12: TMenuItem object MenuItem12: TMenuItem
Caption = '-' Caption = '-'
end end
object mnuedDdocTmp: TMenuItem
Caption = 'Insert DDOC template'
OnClick = mnuedDdocTmpClick
end
object mnuedRename: TMenuItem object mnuedRename: TMenuItem
Caption = 'Rename identifier' Caption = 'Rename identifier'
OnClick = mnuedRenameClick OnClick = mnuedRenameClick

View File

@ -58,6 +58,7 @@ type
MenuItem10: TMenuItem; MenuItem10: TMenuItem;
MenuItem11: TMenuItem; MenuItem11: TMenuItem;
MenuItem12: TMenuItem; MenuItem12: TMenuItem;
mnuedDdocTmp: TMenuItem;
mnuedPrevProtGrp: TMenuItem; mnuedPrevProtGrp: TMenuItem;
mnuedNextProtGrp: TMenuItem; mnuedNextProtGrp: TMenuItem;
MenuItem2: TMenuItem; MenuItem2: TMenuItem;
@ -89,6 +90,7 @@ type
macRecorder: TSynMacroRecorder; macRecorder: TSynMacroRecorder;
editorStatus: TStatusBar; editorStatus: TStatusBar;
mnuEditor: TPopupMenu; mnuEditor: TPopupMenu;
procedure mnuedDdocTmpClick(Sender: TObject);
procedure mnuedPrevProtGrpClick(Sender: TObject); procedure mnuedPrevProtGrpClick(Sender: TObject);
procedure mnuedNextProtGrpClick(Sender: TObject); procedure mnuedNextProtGrpClick(Sender: TObject);
procedure mnuedNextCareaClick(Sender: TObject); procedure mnuedNextCareaClick(Sender: TObject);
@ -900,6 +902,12 @@ begin
fDoc.previousProtectionGroup; fDoc.previousProtectionGroup;
end; end;
procedure TCEEditorWidget.mnuedDdocTmpClick(Sender: TObject);
begin
if fDoc.isNotNil then
fDoc.insertDdocTemplate;
end;
procedure TCEEditorWidget.mnuedNextProtGrpClick(Sender: TObject); procedure TCEEditorWidget.mnuedNextProtGrpClick(Sender: TObject);
begin begin
if fDoc.isNotNil then if fDoc.isNotNil then

View File

@ -12,7 +12,7 @@ uses
md5, md5,
//SynEditMarkupFoldColoring, //SynEditMarkupFoldColoring,
Clipbrd, fpjson, jsonparser, LazUTF8, LazUTF8Classes, Buttons, StdCtrls, 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; ce_sharedres, ce_dlang, ce_stringrange, ce_dbgitf, ce_observer, ce_diff;
type type
@ -272,6 +272,7 @@ type
procedure addCurLineBreakPoint; procedure addCurLineBreakPoint;
procedure removeCurLineBreakPoint; procedure removeCurLineBreakPoint;
procedure toggleCurLineBreakpoint; procedure toggleCurLineBreakpoint;
procedure insertDdocTemplate;
function implementMain: THasMain; function implementMain: THasMain;
procedure replaceUndoableContent(const value: string); procedure replaceUndoableContent(const value: string);
// //
@ -346,6 +347,7 @@ const
ecAddBreakpoint = ecUserFirst + 22; ecAddBreakpoint = ecUserFirst + 22;
ecRemoveBreakpoint = ecUserFirst + 23; ecRemoveBreakpoint = ecUserFirst + 23;
ecToggleBreakpoint = ecUserFirst + 24; ecToggleBreakpoint = ecUserFirst + 24;
ecInsertDdocTemplate = ecUserFirst + 25;
var var
D2Syn: TSynD2Syn; // used as model to set the options when no editor exists. D2Syn: TSynD2Syn; // used as model to set the options when no editor exists.
@ -989,6 +991,7 @@ begin
AddKey(ecAddBreakpoint, 0, [], 0, []); AddKey(ecAddBreakpoint, 0, [], 0, []);
AddKey(ecRemoveBreakpoint, 0, [], 0, []); AddKey(ecRemoveBreakpoint, 0, [], 0, []);
AddKey(ecToggleBreakpoint, 0, [], 0, []); AddKey(ecToggleBreakpoint, 0, [], 0, []);
AddKey(ecInsertDdocTemplate, 0, [], 0, []);
end; end;
end; end;
@ -1019,6 +1022,7 @@ begin
'ecAddBreakpoint': begin Int := ecAddBreakpoint; exit(true); end; 'ecAddBreakpoint': begin Int := ecAddBreakpoint; exit(true); end;
'ecRemoveBreakpoint': begin Int := ecRemoveBreakpoint; exit(true); end; 'ecRemoveBreakpoint': begin Int := ecRemoveBreakpoint; exit(true); end;
'ecToggleBreakpoint': begin Int := ecToggleBreakpoint; exit(true); end; 'ecToggleBreakpoint': begin Int := ecToggleBreakpoint; exit(true); end;
'ecInsertDdocTemplate': begin Int := ecInsertDdocTemplate; exit(true); end;
else exit(false); else exit(false);
end; end;
end; end;
@ -1050,6 +1054,7 @@ begin
ecAddBreakpoint: begin Ident := 'ecAddBreakpoint'; exit(true); end; ecAddBreakpoint: begin Ident := 'ecAddBreakpoint'; exit(true); end;
ecRemoveBreakpoint: begin Ident := 'ecRemoveBreakpoint'; exit(true); end; ecRemoveBreakpoint: begin Ident := 'ecRemoveBreakpoint'; exit(true); end;
ecToggleBreakpoint: begin Ident := 'ecToggleBreakpoint'; exit(true); end; ecToggleBreakpoint: begin Ident := 'ecToggleBreakpoint'; exit(true); end;
ecInsertDdocTemplate: begin Ident := 'ecInsertDdocTemplate'; exit(true); end;
else exit(false); else exit(false);
end; end;
end; end;
@ -1120,6 +1125,8 @@ begin
removeCurLineBreakPoint; removeCurLineBreakPoint;
ecToggleBreakpoint: ecToggleBreakpoint:
toggleCurLineBreakpoint; toggleCurLineBreakpoint;
ecInsertDdocTemplate:
insertDdocTemplate;
end; end;
if fOverrideColMode and not SelAvail then if fOverrideColMode and not SelAvail then
begin begin
@ -1839,6 +1846,42 @@ begin
else else
removeBreakPoint(CaretY); removeBreakPoint(CaretY);
end; 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} {$ENDREGION}
{$REGION DDoc & CallTip --------------------------------------------------------} {$REGION DDoc & CallTip --------------------------------------------------------}