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/common.d'
'src/halstead.d'
'src/ddoc_template.d'
)
ConfigurationIndex = 1
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
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)
{

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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 --------------------------------------------------------}