Add auto-completion for procedural operators

Related commit:
- 3e72a47c1f
This commit is contained in:
Raymond Hill 2020-06-16 08:59:55 -04:00
parent de8d217983
commit aa000e282e
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
3 changed files with 64 additions and 33 deletions

View File

@ -127,3 +127,7 @@ div.CodeMirror span.CodeMirror-matchingbracket {
.CodeMirror-merge-gap { .CodeMirror-merge-gap {
vertical-align: top; vertical-align: top;
} }
.CodeMirror-hints {
z-index: 10000;
}

View File

@ -262,8 +262,13 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
const parser = new StaticFilteringParser(); const parser = new StaticFilteringParser();
const redirectNames = new Map(); const redirectNames = new Map();
const scriptletNames = new Map(); const scriptletNames = new Map();
const proceduralOperatorNames = new Map(
Array.from(parser.proceduralOperatorTokens).filter(item => {
return (item[1] & 0b01) !== 0;
})
);
const getNetOptionHint = function(cursor, isNegated, seedLeft, seedRight) { const getNetOptionHints = function(cursor, isNegated, seedLeft, seedRight) {
const assignPos = seedRight.indexOf('='); const assignPos = seedRight.indexOf('=');
if ( assignPos !== -1 ) { seedRight = seedRight.slice(0, assignPos); } if ( assignPos !== -1 ) { seedRight = seedRight.slice(0, assignPos); }
const seed = (seedLeft + seedRight).trim(); const seed = (seedLeft + seedRight).trim();
@ -289,7 +294,7 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
}; };
}; };
const getNetRedirectHint = function(cursor, seedLeft, seedRight) { const getNetRedirectHints = function(cursor, seedLeft, seedRight) {
const seed = (seedLeft + seedRight).trim(); const seed = (seedLeft + seedRight).trim();
const out = []; const out = [];
for ( let text of redirectNames.keys() ) { for ( let text of redirectNames.keys() ) {
@ -303,7 +308,7 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
}; };
}; };
const getNetHint = function(cursor, line) { const getNetHints = function(cursor, line) {
const beg = cursor.ch; const beg = cursor.ch;
if ( beg < parser.optionsSpan ) { return; } if ( beg < parser.optionsSpan ) { return; }
const lineBefore = line.slice(0, beg); const lineBefore = line.slice(0, beg);
@ -313,21 +318,41 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
if ( matchLeft === null || matchRight === null ) { return; } if ( matchLeft === null || matchRight === null ) { return; }
let pos = matchLeft[1].indexOf('='); let pos = matchLeft[1].indexOf('=');
if ( pos === -1 ) { if ( pos === -1 ) {
return getNetOptionHint( return getNetOptionHints(
cursor, cursor,
matchLeft[0].startsWith('~'), matchLeft[0].startsWith('~'),
matchLeft[1], matchLeft[1],
matchRight[1] matchRight[1]
); );
} }
return getNetRedirectHint( return getNetRedirectHints(
cursor, cursor,
matchLeft[1].slice(pos + 1), matchLeft[1].slice(pos + 1),
matchRight[1] matchRight[1]
); );
}; };
const getExtScriptletHint = function(cursor, line) { const getExtSelectorHints = function(cursor, line) {
const beg = cursor.ch;
const matchLeft = /#\^?.*:([^:]*)$/.exec(line.slice(0, beg));
const matchRight = /^([a-z-]*)\(?/.exec(line.slice(beg));
if ( matchLeft === null || matchRight === null ) { return; }
const isStaticDOM = matchLeft[0].indexOf('^') !== -1;
const seed = (matchLeft[1] + matchRight[1]).trim();
const out = [];
for ( let [ text, bits ] of proceduralOperatorNames ) {
if ( text.startsWith(seed) === false ) { continue; }
if ( isStaticDOM && (bits & 0b10) !== 0 ) { continue; }
out.push(text);
}
return {
from: { line: cursor.line, ch: cursor.ch - matchLeft[1].length },
to: { line: cursor.line, ch: cursor.ch + matchRight[1].length },
list: out,
};
};
const getExtScriptletHints = function(cursor, line) {
const beg = cursor.ch; const beg = cursor.ch;
const matchLeft = /#\+\js\(([^,]*)$/.exec(line.slice(0, beg)); const matchLeft = /#\+\js\(([^,]*)$/.exec(line.slice(0, beg));
const matchRight = /^([^,)]*)/.exec(line.slice(beg)); const matchRight = /^([^,)]*)/.exec(line.slice(beg));
@ -353,14 +378,14 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
const cursor = cm.getCursor(); const cursor = cm.getCursor();
const line = cm.getLine(cursor.line); const line = cm.getLine(cursor.line);
parser.analyze(line); parser.analyze(line);
if ( if ( parser.category === parser.CATStaticExtFilter ) {
parser.category === parser.CATStaticExtFilter && if ( parser.hasFlavor(parser.BITFlavorExtScriptlet) ) {
parser.hasFlavor(parser.BITFlavorExtScriptlet) return getExtScriptletHints(cursor, line);
) { }
return getExtScriptletHint(cursor, line); return getExtSelectorHints(cursor, line);
} }
if ( parser.category === parser.CATStaticNetFilter ) { if ( parser.category === parser.CATStaticNetFilter ) {
return getNetHint(cursor, line); return getNetHints(cursor, line);
} }
}; };

View File

@ -1101,27 +1101,7 @@ Parser.prototype.SelectorCompiler = class {
this.rePseudoClass = /:(?::?after|:?before|:[a-z][a-z-]*[a-z])$/; this.rePseudoClass = /:(?::?after|:?before|:[a-z][a-z-]*[a-z])$/;
this.reProceduralOperator = new RegExp([ this.reProceduralOperator = new RegExp([
'^(?:', '^(?:',
[ Array.from(parser.proceduralOperatorTokens.keys()).join('|'),
'-abp-contains',
'-abp-has',
'contains',
'has',
'has-text',
'if',
'if-not',
'matches-css',
'matches-css-after',
'matches-css-before',
'min-text-length',
'not',
'nth-ancestor',
'remove',
'style',
'upward',
'watch-attr',
'watch-attrs',
'xpath'
].join('|'),
')\\(' ')\\('
].join('')); ].join(''));
this.reEatBackslashes = /\\([()])/g; this.reEatBackslashes = /\\([()])/g;
@ -1627,6 +1607,28 @@ Parser.prototype.SelectorCompiler = class {
} }
}; };
Parser.prototype.proceduralOperatorTokens = new Map([
[ '-abp-contains', 0b00 ],
[ '-abp-has', 0b00, ],
[ 'contains', 0b00, ],
[ 'has', 0b01 ],
[ 'has-text', 0b01 ],
[ 'if', 0b00 ],
[ 'if-not', 0b00 ],
[ 'matches-css', 0b11 ],
[ 'matches-css-after', 0b11 ],
[ 'matches-css-before', 0b11 ],
[ 'min-text-length', 0b01 ],
[ 'not', 0b01 ],
[ 'nth-ancestor', 0b00 ],
[ 'remove', 0b11 ],
[ 'style', 0b11 ],
[ 'upward', 0b01 ],
[ 'watch-attr', 0b11 ],
[ 'watch-attrs', 0b00 ],
[ 'xpath', 0b01 ],
]);
/******************************************************************************/ /******************************************************************************/
const hasNoBits = (v, bits) => (v & bits) === 0; const hasNoBits = (v, bits) => (v & bits) === 0;