@@ -7,11 +7,14 @@ import std.conv;
7
7
import std.getopt ;
8
8
import std.json ;
9
9
import std.stdio : stderr;
10
+ import std.string ;
10
11
11
12
import dfmt.config;
12
13
import dfmt.editorconfig;
13
14
import dfmt.formatter : fmt = format;
14
15
16
+ import dparse.lexer;
17
+
15
18
import core.thread ;
16
19
17
20
import painlessjson;
@@ -141,10 +144,96 @@ class DfmtComponent : ComponentWrapper
141
144
else
142
145
return code.idup;
143
146
}
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;
144
216
}
145
217
146
218
private :
147
219
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
+
148
237
void tryFetchProperty (T = string )(ref JSONValue json, ref T ret, string name)
149
238
{
150
239
auto ptr = name in json;
@@ -184,3 +273,35 @@ void tryFetchProperty(T = string)(ref JSONValue json, ref T ret, string name)
184
273
static assert (false );
185
274
}
186
275
}
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