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

Commit b4a003c

Browse files
committed
add dfmt on/off parsing
1 parent 89287f7 commit b4a003c

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

source/workspaced/com/dfmt.d

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ import std.conv;
77
import std.getopt;
88
import std.json;
99
import std.stdio : stderr;
10+
import std.string;
1011

1112
import dfmt.config;
1213
import dfmt.editorconfig;
1314
import dfmt.formatter : fmt = format;
1415

16+
import dparse.lexer;
17+
1518
import core.thread;
1619

1720
import painlessjson;
@@ -141,10 +144,96 @@ class DfmtComponent : ComponentWrapper
141144
else
142145
return code.idup;
143146
}
147+
148+
/// Finds dfmt instruction comments (dfmt off, dfmt on)
149+
/// Returns: a list of dfmt instructions, sorted in appearing (source code)
150+
/// order
151+
DfmtInstruction[] findDfmtInstructions(scope const(char)[] code)
152+
{
153+
LexerConfig config;
154+
config.whitespaceBehavior = WhitespaceBehavior.skip;
155+
config.commentBehavior = CommentBehavior.noIntern;
156+
auto lexer = DLexer(code, config, &workspaced.stringCache);
157+
auto ret = appender!(DfmtInstruction[]);
158+
Search: foreach (token; lexer)
159+
{
160+
if (token.type == tok!"comment")
161+
{
162+
auto text = dfmtCommentText(token.text);
163+
DfmtInstruction instruction;
164+
switch (text)
165+
{
166+
case "dfmt on":
167+
instruction.type = DfmtInstruction.Type.dfmtOn;
168+
break;
169+
case "dfmt off":
170+
instruction.type = DfmtInstruction.Type.dfmtOff;
171+
break;
172+
default:
173+
text = text.chompPrefix("/").strip; // make doc comments (///) appear as unknown because only first 2 // are stripped.
174+
if (text.startsWith("dfmt", "dmft", "dftm")) // include some typos
175+
{
176+
instruction.type = DfmtInstruction.Type.unknown;
177+
break;
178+
}
179+
continue Search;
180+
}
181+
instruction.index = token.index;
182+
instruction.line = token.line;
183+
instruction.column = token.column;
184+
instruction.length = token.text.length;
185+
ret.put(instruction);
186+
}
187+
else if (token.type == tok!"__EOF__")
188+
break;
189+
}
190+
return ret.data;
191+
}
192+
}
193+
194+
///
195+
struct DfmtInstruction
196+
{
197+
/// Known instruction types
198+
enum Type
199+
{
200+
/// Instruction to turn off formatting from here
201+
dfmtOff,
202+
/// Instruction to turn on formatting again from here
203+
dfmtOn,
204+
/// Starts with dfmt, but unknown contents
205+
unknown,
206+
}
207+
208+
///
209+
Type type;
210+
/// libdparse Token location (byte based offset)
211+
size_t index;
212+
/// libdparse Token location (byte based, 1-based)
213+
size_t line, column;
214+
/// Comment length in bytes
215+
size_t length;
144216
}
145217

146218
private:
147219

220+
// from dfmt/formatter.d TokenFormatter!T.commentText
221+
string dfmtCommentText(string commentText)
222+
{
223+
import std.string : strip;
224+
225+
if (commentText[0 .. 2] == "//")
226+
commentText = commentText[2 .. $];
227+
else
228+
{
229+
if (commentText.length > 3)
230+
commentText = commentText[2 .. $ - 2];
231+
else
232+
commentText = commentText[2 .. $];
233+
}
234+
return commentText.strip();
235+
}
236+
148237
void tryFetchProperty(T = string)(ref JSONValue json, ref T ret, string name)
149238
{
150239
auto ptr = name in json;
@@ -184,3 +273,35 @@ void tryFetchProperty(T = string)(ref JSONValue json, ref T ret, string name)
184273
static assert(false);
185274
}
186275
}
276+
277+
unittest
278+
{
279+
scope backend = new WorkspaceD();
280+
auto workspace = makeTemporaryTestingWorkspace;
281+
auto instance = backend.addInstance(workspace.directory);
282+
backend.register!DfmtComponent;
283+
DfmtComponent dfmt = instance.get!DfmtComponent;
284+
285+
assert(dfmt.findDfmtInstructions("void main() {}").length == 0);
286+
assert(dfmt.findDfmtInstructions("void main() {\n\t// dfmt off\n}") == [
287+
DfmtInstruction(DfmtInstruction.Type.dfmtOff, 15, 2, 2, 11)
288+
]);
289+
assert(dfmt.findDfmtInstructions(`import std.stdio;
290+
291+
// dfmt on
292+
void main()
293+
{
294+
// dfmt off
295+
writeln("hello");
296+
// dmft off
297+
string[string] x = [
298+
"a": "b"
299+
];
300+
// dfmt on
301+
}`) == [
302+
DfmtInstruction(DfmtInstruction.Type.dfmtOn, 19, 3, 1, 10),
303+
DfmtInstruction(DfmtInstruction.Type.dfmtOff, 45, 6, 2, 11),
304+
DfmtInstruction(DfmtInstruction.Type.unknown, 77, 8, 2, 11),
305+
DfmtInstruction(DfmtInstruction.Type.dfmtOn, 127, 12, 2, 10),
306+
]);
307+
}

0 commit comments

Comments
 (0)