Add syntax highlighting/auto-completion for preparsing directives · gorhill/uBlock@83c01fb (original) (raw)
`@@ -25,17 +25,53 @@
`
25
25
``
26
26
`/******************************************************************************/
`
27
27
``
``
28
`+
{
`
``
29
`+
// >>>>> start of local scope
`
``
30
+
``
31
`+
/******************************************************************************/
`
``
32
+
``
33
`+
const redirectNames = new Map();
`
``
34
`+
const scriptletNames = new Map();
`
``
35
`+
const preparseDirectiveNames = new Set();
`
``
36
+
``
37
`+
/******************************************************************************/
`
``
38
+
28
39
`CodeMirror.defineMode('ubo-static-filtering', function() {
`
29
40
`const StaticFilteringParser = typeof vAPI === 'object'
`
30
41
` ? vAPI.StaticFilteringParser
`
31
42
` : self.StaticFilteringParser;
`
32
43
`if ( StaticFilteringParser instanceof Object === false ) { return; }
`
33
44
`const parser = new StaticFilteringParser({ interactive: true });
`
34
45
``
35
``
`-
const reDirective = /^!#(?:if|endif|include)\b/;
`
``
46
`+
const rePreparseDirectives = /^!#(?:if|endif|include)\b/;
`
``
47
`+
const rePreparseIfDirective = /^(!#if !?)(.+)$/;
`
36
48
`let parserSlot = 0;
`
37
49
`let netOptionValueMode = false;
`
38
50
``
``
51
`+
const colorCommentSpan = function(stream) {
`
``
52
`+
if ( rePreparseDirectives.test(stream.string) === false ) {
`
``
53
`+
stream.skipToEnd();
`
``
54
`+
return 'comment';
`
``
55
`+
}
`
``
56
`+
const match = rePreparseIfDirective.exec(stream.string);
`
``
57
`+
if ( match === null ) {
`
``
58
`+
stream.skipToEnd();
`
``
59
`+
return 'variable strong';
`
``
60
`+
}
`
``
61
`+
if ( stream.pos < match[1].length ) {
`
``
62
`+
stream.pos = match[1].length;
`
``
63
`+
return 'variable strong';
`
``
64
`+
}
`
``
65
`+
stream.skipToEnd();
`
``
66
`+
if (
`
``
67
`+
preparseDirectiveNames.size === 0 ||
`
``
68
`+
preparseDirectiveNames.has(match[2].trim())
`
``
69
`+
) {
`
``
70
`+
return 'variable strong';
`
``
71
`+
}
`
``
72
`+
return 'error strong';
`
``
73
`+
};
`
``
74
+
39
75
`const colorExtHTMLPatternSpan = function(stream) {
`
40
76
`const { i } = parser.patternSpan;
`
41
77
`if ( stream.pos === parser.slices[i+1] ) {
`
`@@ -202,10 +238,7 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
`
202
238
`return 'comment';
`
203
239
`}
`
204
240
`if ( parser.category === parser.CATComment ) {
`
205
``
`-
stream.skipToEnd();
`
206
``
`-
return reDirective.test(stream.string)
`
207
``
`-
? 'variable strong'
`
208
``
`-
: 'comment';
`
``
241
`+
return colorCommentSpan(stream);
`
209
242
`}
`
210
243
`if ( (parser.slices[parserSlot] & parser.BITIgnore) !== 0 ) {
`
211
244
`stream.pos += parser.slices[parserSlot+2];
`
`@@ -243,6 +276,23 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
`
243
276
`style = style.trim();
`
244
277
`return style !== '' ? style : null;
`
245
278
`},
`
``
279
`+
setHints: function(details) {
`
``
280
`+
for ( const [ name, desc ] of details.redirectResources ) {
`
``
281
`+
const displayText = desc.aliasOf !== ''
`
``
282
`` +
? ${name} (${desc.aliasOf})
``
``
283
`+
: '';
`
``
284
`+
if ( desc.canRedirect ) {
`
``
285
`+
redirectNames.set(name, displayText);
`
``
286
`+
}
`
``
287
`+
if ( desc.canInject && name.endsWith('.js') ) {
`
``
288
`+
scriptletNames.set(name.slice(0, -3), displayText);
`
``
289
`+
}
`
``
290
`+
}
`
``
291
`+
details.preparseDirectives.forEach(a => {
`
``
292
`+
preparseDirectiveNames.add(a);
`
``
293
`+
});
`
``
294
`+
initHints();
`
``
295
`+
},
`
246
296
`};
`
247
297
`});
`
248
298
``
`@@ -251,17 +301,13 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
`
251
301
`// Following code is for auto-completion. Reference:
`
252
302
`// https://codemirror.net/demo/complete.html
`
253
303
``
254
``
`-
(( ) => {
`
255
``
`-
if ( typeof vAPI !== 'object' ) { return; }
`
256
``
-
``
304
`+
const initHints = function() {
`
257
305
`const StaticFilteringParser = typeof vAPI === 'object'
`
258
306
` ? vAPI.StaticFilteringParser
`
259
307
` : self.StaticFilteringParser;
`
260
308
`if ( StaticFilteringParser instanceof Object === false ) { return; }
`
261
309
``
262
310
`const parser = new StaticFilteringParser();
`
263
``
`-
const redirectNames = new Map();
`
264
``
`-
const scriptletNames = new Map();
`
265
311
`const proceduralOperatorNames = new Map(
`
266
312
`Array.from(parser.proceduralOperatorTokens).filter(item => {
`
267
313
`return (item[1] & 0b01) !== 0;
`
`@@ -380,7 +426,28 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
`
380
426
`return pickBestHints(cursor, matchLeft[1], matchRight[1], hints);
`
381
427
`};
`
382
428
``
383
``
`-
const getHints = function(cm) {
`
``
429
`+
const getCommentHints = function(cursor, line) {
`
``
430
`+
const beg = cursor.ch;
`
``
431
`+
if ( line.startsWith('!#if ') ) {
`
``
432
`+
const matchLeft = /^!#if !?(\w*)$/.exec(line.slice(0, beg));
`
``
433
`+
const matchRight = /^\w*/.exec(line.slice(beg));
`
``
434
`+
if ( matchLeft === null || matchRight === null ) { return; }
`
``
435
`+
const hints = [];
`
``
436
`+
for ( const hint of preparseDirectiveNames ) {
`
``
437
`+
hints.push(hint);
`
``
438
`+
}
`
``
439
`+
return pickBestHints(cursor, matchLeft[1], matchRight[0], hints);
`
``
440
`+
}
`
``
441
`+
if ( line.startsWith('!#') && line !== '!#endif' ) {
`
``
442
`+
const matchLeft = /^!#(\w*)$/.exec(line.slice(0, beg));
`
``
443
`+
const matchRight = /^\w*/.exec(line.slice(beg));
`
``
444
`+
if ( matchLeft === null || matchRight === null ) { return; }
`
``
445
`+
const hints = [ 'if ', 'endif\n', 'include ' ];
`
``
446
`+
return pickBestHints(cursor, matchLeft[1], matchRight[0], hints);
`
``
447
`+
}
`
``
448
`+
};
`
``
449
+
``
450
`+
CodeMirror.registerHelper('hint', 'ubo-static-filtering', function(cm) {
`
384
451
`const cursor = cm.getCursor();
`
385
452
`const line = cm.getLine(cursor.line);
`
386
453
`parser.analyze(line);
`
`@@ -393,25 +460,15 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
`
393
460
`if ( parser.category === parser.CATStaticNetFilter ) {
`
394
461
`return getNetHints(cursor, line);
`
395
462
`}
`
396
``
`-
};
`
397
``
-
398
``
`-
vAPI.messaging.send('dashboard', {
`
399
``
`-
what: 'getResourceDetails'
`
400
``
`-
}).then(response => {
`
401
``
`-
if ( Array.isArray(response) === false ) { return; }
`
402
``
`-
for ( const [ name, details ] of response ) {
`
403
``
`-
const displayText = details.aliasOf !== ''
`
404
``
`` -
? ${name} (${details.aliasOf})
``
405
``
`-
: '';
`
406
``
`-
if ( details.canRedirect ) {
`
407
``
`-
redirectNames.set(name, displayText);
`
408
``
`-
}
`
409
``
`-
if ( details.canInject && name.endsWith('.js') ) {
`
410
``
`-
scriptletNames.set(name.slice(0, -3), displayText);
`
411
``
`-
}
`
``
463
`+
if ( parser.category === parser.CATComment ) {
`
``
464
`+
return getCommentHints(cursor, line);
`
412
465
`}
`
413
``
`-
CodeMirror.registerHelper('hint', 'ubo-static-filtering', getHints);
`
414
466
`});
`
415
``
`-
})();
`
``
467
`+
};
`
``
468
+
``
469
`+
/******************************************************************************/
`
``
470
+
``
471
`+
// <<<<< end of local scope
`
``
472
`+
}
`
416
473
``
417
474
`/******************************************************************************/
`