Skip to content
This repository has been archived by the owner on Mar 1, 2022. It is now read-only.

Commit

Permalink
add dfmt on/off parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
WebFreak001 committed Jun 25, 2021
1 parent 89287f7 commit b4a003c
Showing 1 changed file with 121 additions and 0 deletions.
121 changes: 121 additions & 0 deletions source/workspaced/com/dfmt.d
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import std.conv;
import std.getopt;
import std.json;
import std.stdio : stderr;
import std.string;

import dfmt.config;
import dfmt.editorconfig;
import dfmt.formatter : fmt = format;

import dparse.lexer;

import core.thread;

import painlessjson;
Expand Down Expand Up @@ -141,10 +144,96 @@ class DfmtComponent : ComponentWrapper
else
return code.idup;
}

/// Finds dfmt instruction comments (dfmt off, dfmt on)
/// Returns: a list of dfmt instructions, sorted in appearing (source code)
/// order
DfmtInstruction[] findDfmtInstructions(scope const(char)[] code)
{
LexerConfig config;
config.whitespaceBehavior = WhitespaceBehavior.skip;
config.commentBehavior = CommentBehavior.noIntern;
auto lexer = DLexer(code, config, &workspaced.stringCache);
auto ret = appender!(DfmtInstruction[]);
Search: foreach (token; lexer)
{
if (token.type == tok!"comment")
{
auto text = dfmtCommentText(token.text);
DfmtInstruction instruction;
switch (text)
{
case "dfmt on":
instruction.type = DfmtInstruction.Type.dfmtOn;
break;
case "dfmt off":
instruction.type = DfmtInstruction.Type.dfmtOff;
break;
default:
text = text.chompPrefix("/").strip; // make doc comments (///) appear as unknown because only first 2 // are stripped.
if (text.startsWith("dfmt", "dmft", "dftm")) // include some typos
{
instruction.type = DfmtInstruction.Type.unknown;
break;
}
continue Search;
}
instruction.index = token.index;
instruction.line = token.line;
instruction.column = token.column;
instruction.length = token.text.length;
ret.put(instruction);
}
else if (token.type == tok!"__EOF__")
break;
}
return ret.data;
}
}

///
struct DfmtInstruction
{
/// Known instruction types
enum Type
{
/// Instruction to turn off formatting from here
dfmtOff,
/// Instruction to turn on formatting again from here
dfmtOn,
/// Starts with dfmt, but unknown contents
unknown,
}

///
Type type;
/// libdparse Token location (byte based offset)
size_t index;
/// libdparse Token location (byte based, 1-based)
size_t line, column;
/// Comment length in bytes
size_t length;
}

private:

// from dfmt/formatter.d TokenFormatter!T.commentText
string dfmtCommentText(string commentText)
{
import std.string : strip;

if (commentText[0 .. 2] == "//")
commentText = commentText[2 .. $];
else
{
if (commentText.length > 3)
commentText = commentText[2 .. $ - 2];
else
commentText = commentText[2 .. $];
}
return commentText.strip();
}

void tryFetchProperty(T = string)(ref JSONValue json, ref T ret, string name)
{
auto ptr = name in json;
Expand Down Expand Up @@ -184,3 +273,35 @@ void tryFetchProperty(T = string)(ref JSONValue json, ref T ret, string name)
static assert(false);
}
}

unittest
{
scope backend = new WorkspaceD();
auto workspace = makeTemporaryTestingWorkspace;
auto instance = backend.addInstance(workspace.directory);
backend.register!DfmtComponent;
DfmtComponent dfmt = instance.get!DfmtComponent;

assert(dfmt.findDfmtInstructions("void main() {}").length == 0);
assert(dfmt.findDfmtInstructions("void main() {\n\t// dfmt off\n}") == [
DfmtInstruction(DfmtInstruction.Type.dfmtOff, 15, 2, 2, 11)
]);
assert(dfmt.findDfmtInstructions(`import std.stdio;
// dfmt on
void main()
{
// dfmt off
writeln("hello");
// dmft off
string[string] x = [
"a": "b"
];
// dfmt on
}`) == [
DfmtInstruction(DfmtInstruction.Type.dfmtOn, 19, 3, 1, 10),
DfmtInstruction(DfmtInstruction.Type.dfmtOff, 45, 6, 2, 11),
DfmtInstruction(DfmtInstruction.Type.unknown, 77, 8, 2, 11),
DfmtInstruction(DfmtInstruction.Type.dfmtOn, 127, 12, 2, 10),
]);
}

0 comments on commit b4a003c

Please sign in to comment.