diff --git a/src/1p-filters.html b/src/1p-filters.html
index 7d5cb9664..fa153ba56 100644
--- a/src/1p-filters.html
+++ b/src/1p-filters.html
@@ -6,7 +6,6 @@
uBlock — Your filters
-
@@ -44,7 +43,6 @@
-
diff --git a/src/asset-viewer.html b/src/asset-viewer.html
index 70858725a..9bda40011 100644
--- a/src/asset-viewer.html
+++ b/src/asset-viewer.html
@@ -5,7 +5,6 @@
-
@@ -29,7 +28,6 @@
-
diff --git a/src/css/codemirror.css b/src/css/codemirror.css
index b1b6d70f8..0e3516249 100644
--- a/src/css/codemirror.css
+++ b/src/css/codemirror.css
@@ -23,8 +23,9 @@
}
.CodeMirror-foldmarker {
color: var(--cm-foldmarker-ink);
- font-size: large;
- text-shadow: none;
+ cursor: pointer;
+ font-family: sans-serif;
+ font-weight: bold;
}
.CodeMirror-foldgutter-folded::after {
content: '\25B6';
@@ -213,7 +214,7 @@
display: none;
flex-grow: 1;
}
-.cm-linter-widget.hasErrors {
+.cm-linter-widget:not([data-lint="0"]) {
display: inline-flex;
}
.cm-linter-widget .cm-linter-widget-count {
@@ -273,25 +274,44 @@
}
.CodeMirror-lintmarker {
- background-color: var(--sf-error-ink);
height: calc(var(--font-size) - 2px);
margin-top: 1px;
position: relative;
}
-.CodeMirror-lintmarker > span {
+.CodeMirror-lintmarker > * {
+ position: absolute;
+ }
+.CodeMirror-lintmarker[data-lint="error"] {
+ background-color: var(--sf-error-ink);
+ }
+.CodeMirror-lintmarker[data-lint="error"] .msg {
display: none;
}
-.CodeMirror-lintmarker > span {
+.CodeMirror-lintmarker[data-lint="error"] .msg {
background-color: var(--surface-0);
border: 1px solid var(--sf-error-ink);
color: var(--ink-1);
left: 100%;
padding: var(--default-gap-xsmall);
- position: absolute;
top: -2px;
white-space: pre;
}
-.CodeMirror-lintmarker:hover > span,
-.CodeMirror-lintmarker > span:hover {
+.CodeMirror-lintmarker svg {
+ height: 70%;
+ left: 15%;
+ top: 15%;
+ width: 70%;
+ }
+.CodeMirror-lintmarker[data-fold="start"] {
+ fill: var(--cm-foldmarker-ink);
+ }
+.CodeMirror-lintmarker[data-fold="start"].folded svg {
+ transform: rotate(-90deg);
+ }
+.CodeMirror-lintmarker[data-fold="end"] {
+ fill: var(--border-2);
+ }
+.CodeMirror-lintmarker[data-lint="error"]:hover > span,
+.CodeMirror-lintmarker[data-lint="error"] > span:hover {
display: initial;
}
diff --git a/src/css/popup-fenix.css b/src/css/popup-fenix.css
index 7800d0d26..28672bc53 100644
--- a/src/css/popup-fenix.css
+++ b/src/css/popup-fenix.css
@@ -320,6 +320,9 @@ body.mobile.no-tooltips .toolRibbon .tool {
border-bottom: 1px dotted #ddd;
padding: 0.25em;
}
+#firewall > section .filterExpressions div:last-of-type {
+ border-bottom: 0;
+ }
#firewall > section .filterExpressions span {
cursor: default;
display: inline-flex;
diff --git a/src/js/1p-filters.js b/src/js/1p-filters.js
index c33acfd32..4a31ace32 100644
--- a/src/js/1p-filters.js
+++ b/src/js/1p-filters.js
@@ -38,9 +38,8 @@ const cmEditor = new CodeMirror(qs$('#userFilters'), {
},
foldGutter: true,
gutters: [
- 'CodeMirror-foldgutter',
'CodeMirror-linenumbers',
- { className: 'CodeMirror-lintgutter', style: 'width: 10px' },
+ { className: 'CodeMirror-lintgutter', style: 'width: 11px' },
],
lineNumbers: true,
lineWrapping: true,
diff --git a/src/js/asset-viewer.js b/src/js/asset-viewer.js
index 20f1cff66..060ea20a3 100644
--- a/src/js/asset-viewer.js
+++ b/src/js/asset-viewer.js
@@ -53,9 +53,8 @@ import './codemirror/ubo-static-filtering.js';
autofocus: true,
foldGutter: true,
gutters: [
- 'CodeMirror-foldgutter',
'CodeMirror-linenumbers',
- { className: 'CodeMirror-lintgutter', style: 'width: 10px' },
+ { className: 'CodeMirror-lintgutter', style: 'width: 11px' },
],
lineNumbers: true,
lineWrapping: true,
diff --git a/src/js/codemirror/search.js b/src/js/codemirror/search.js
index 7f42b1f1b..882e7afd4 100644
--- a/src/js/codemirror/search.js
+++ b/src/js/codemirror/search.js
@@ -27,7 +27,7 @@
'use strict';
-import { dom } from '../dom.js';
+import { dom, qs$ } from '../dom.js';
import { i18n$ } from '../i18n.js';
{
@@ -382,7 +382,9 @@ import { i18n$ } from '../i18n.js';
doc.eachLine(start, end, lineHandle => {
const markers = lineHandle.gutterMarkers || null;
if ( markers === null ) { return; }
- if ( markers['CodeMirror-lintgutter'] === undefined ) { return; }
+ const marker = markers['CodeMirror-lintgutter'];
+ if ( marker === undefined ) { return; }
+ if ( marker.dataset.lint !== 'error' ) { return; }
const line = lineHandle.lineNo();
if ( dir < 0 ) {
found = line;
@@ -476,7 +478,7 @@ import { i18n$ } from '../i18n.js';
'angle-up ' +
'' +
'' +
- '' +
+ '' +
' ' +
'angle-up ' +
'angle-up ' +
@@ -497,10 +499,12 @@ import { i18n$ } from '../i18n.js';
CodeMirror.defineInitHook(function(cm) {
getSearchState(cm);
cm.on('linterDone', details => {
+ const linterWidget = qs$('.cm-linter-widget');
const count = details.errorCount;
- dom.cl.toggle('.cm-linter-widget', 'hasErrors', count !== 0);
+ if ( linterWidget.dataset.lint === `${count}` ) { return; }
+ linterWidget.dataset.lint = `${count}`;
dom.text(
- '.cm-linter-widget .cm-linter-widget-count',
+ qs$(linterWidget, '.cm-linter-widget-count'),
i18n$('linterMainReport').replace('{{count}}', count.toLocaleString())
);
});
diff --git a/src/js/codemirror/ubo-static-filtering.js b/src/js/codemirror/ubo-static-filtering.js
index 5f647b748..9811a5c26 100644
--- a/src/js/codemirror/ubo-static-filtering.js
+++ b/src/js/codemirror/ubo-static-filtering.js
@@ -26,6 +26,7 @@
/******************************************************************************/
import * as sfp from '../static-filtering-parser.js';
+import { dom, qs$ } from '../dom.js';
/******************************************************************************/
@@ -670,91 +671,189 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
const changeset = [];
let changesetTimer;
+
+ const includeset = new Set();
let errorCount = 0;
- const addChange = (doc, change) => {
- changeset.push(change);
- processChangesetAsync(doc);
- };
-
- const processChangesetAsync = doc => {
- if ( changesetTimer !== undefined ) { return; }
- changesetTimer = self.requestIdleCallback(deadline => {
- changesetTimer = undefined;
- processChangeset(doc, deadline);
- });
- };
-
- const extractError = ( ) => {
- if ( astParser.hasError() === false ) { return; }
- const error = 'Invalid filter';
- switch ( astParser.astError ) {
- case sfp.AST_ERROR_REGEX:
- return `${error}: Bad regular expression`;
- case sfp.AST_ERROR_PATTERN:
- return `${error}: Bad pattern`;
- case sfp.AST_ERROR_DOMAIN_NAME:
- return `${error}: Bad domain name`;
- case sfp.AST_ERROR_OPTION_DUPLICATE:
- return `${error}: Duplicate filter option`;
- case sfp.AST_ERROR_OPTION_UNKNOWN:
- return `${error}: Unsupported filter option`;
- case sfp.AST_ERROR_IF_TOKEN_UNKNOWN:
- return `${error}: Unknown preparsing token`;
- default:
- break;
+ const extractMarkerDetails = (doc, lineHandle) => {
+ if ( astParser.isUnsupported() ) {
+ return { value: 'error', msg: 'Unsupported filter syntax' };
}
- if ( astParser.isCosmeticFilter() && astParser.result.error ) {
- return `${error}: ${astParser.result.error}`;
+ if ( astParser.hasError() ) {
+ let msg = 'Invalid filter';
+ switch ( astParser.astError ) {
+ case sfp.AST_ERROR_UNSUPPORTED:
+ msg = `${msg}: Unsupported filter syntax`;
+ break;
+ case sfp.AST_ERROR_REGEX:
+ msg = `${msg}: Bad regular expression`;
+ break;
+ case sfp.AST_ERROR_PATTERN:
+ msg = `${msg}: Bad pattern`;
+ break;
+ case sfp.AST_ERROR_DOMAIN_NAME:
+ msg = `${msg}: Bad domain name`;
+ break;
+ case sfp.AST_ERROR_OPTION_DUPLICATE:
+ msg = `${msg}: Duplicate filter option`;
+ break;
+ case sfp.AST_ERROR_OPTION_UNKNOWN:
+ msg = `${msg}: Unsupported filter option`;
+ break;
+ case sfp.AST_ERROR_IF_TOKEN_UNKNOWN:
+ msg = `${msg}: Unknown preparsing token`;
+ break;
+ default:
+ if ( astParser.isCosmeticFilter() && astParser.result.error ) {
+ msg = `${msg}: ${astParser.result.error}`;
+ }
+ break;
+ }
+ return { value: 'error', msg };
}
- return error;
+ if ( astParser.astType !== sfp.AST_TYPE_COMMENT ) { return; }
+ if ( astParser.astTypeFlavor !== sfp.AST_TYPE_COMMENT_PREPARSER ) {
+ if ( astParser.raw.startsWith('! <<<<<<<< ') === false ) { return; }
+ for ( const include of includeset ) {
+ if ( astParser.raw.endsWith(include) === false ) { continue; }
+ includeset.delete(include);
+ return { value: 'include-end' };
+ }
+ return;
+ }
+ if ( /^\s*!#if \S+/.test(astParser.raw) ) {
+ return { value: 'if-start' };
+ }
+ if ( /^\s*!#endif\b/.test(astParser.raw) ) {
+ return { value: 'if-end' };
+ }
+ const match = /^\s*!#include\s*(\S+)/.exec(astParser.raw);
+ if ( match === null ) { return; }
+ const nextLineHandle = doc.getLineHandle(lineHandle.lineNo() + 1);
+ if ( nextLineHandle === undefined ) { return; }
+ if ( nextLineHandle.text.startsWith('! >>>>>>>> ') === false ) { return; }
+ const includeToken = `/${match[1]}`;
+ if ( nextLineHandle.text.endsWith(includeToken) === false ) { return; }
+ includeset.add(includeToken);
+ return { value: 'include-start' };
};
const extractMarker = lineHandle => {
const markers = lineHandle.gutterMarkers || null;
- if ( markers === null ) { return; }
- return markers['CodeMirror-lintgutter'] || undefined;
+ return markers !== null
+ ? markers['CodeMirror-lintgutter'] || null
+ : null;
};
- const markerTemplate = (( ) => {
- const marker = document.createElement('div');
- marker.classList.add('CodeMirror-lintmarker');
- marker.textContent = '\xA0';
- const info = document.createElement('span');
- marker.append(info);
- return marker;
- })();
+ const markerTemplates = {
+ 'error': {
+ node: null,
+ html: [
+ ' ',
+ '',
+ '
',
+ ],
+ },
+ 'if-start': {
+ node: null,
+ html: [
+ '',
+ ],
+ },
+ 'if-end': {
+ node: null,
+ html: [
+ '',
+ ],
+ },
+ 'include-start': {
+ node: null,
+ html: [
+ '',
+ ],
+ },
+ 'include-end': {
+ node: null,
+ html: [
+ '',
+ ],
+ },
+ };
- const makeMarker = (doc, lineHandle, marker, error) => {
- if ( marker === undefined ) {
- marker = addMarker(doc, lineHandle);
+ const markerFromTemplate = which => {
+ const template = markerTemplates[which];
+ if ( template.node === null ) {
+ const domParser = new DOMParser();
+ const doc = domParser.parseFromString(template.html.join(''), 'text/html');
+ template.node = document.adoptNode(qs$(doc, '.CodeMirror-lintmarker'));
}
- marker.children[0].textContent = error;
+ return template.node.cloneNode(true);
};
- const addMarker = (doc, lineHandle) => {
- const marker = markerTemplate.cloneNode(true);
- doc.setGutterMarker(lineHandle, 'CodeMirror-lintgutter', marker);
- lineHandle.on('delete', deleteMarker);
- errorCount += 1;
- return marker;
+ const addMarker = (doc, lineHandle, marker, details) => {
+ if ( marker !== null && marker.dataset.lint !== details.value ) {
+ doc.setGutterMarker(lineHandle, 'CodeMirror-lintgutter', null);
+ if ( marker.dataset.lint === 'error' ) {
+ errorCount -= 1;
+ }
+ marker = null;
+ }
+ if ( marker === null ) {
+ marker = markerFromTemplate(details.value);
+ doc.setGutterMarker(lineHandle, 'CodeMirror-lintgutter', marker);
+ if ( details.value === 'error' ) {
+ errorCount += 1;
+ }
+ }
+ const msgElem = qs$(marker, '.msg');
+ if ( msgElem === null ) { return; }
+ msgElem.textContent = details.msg || '';
};
- const deleteMarker = ( ) => {
- errorCount -= 1;
+ const removeMarker = (doc, lineHandle, marker) => {
+ doc.setGutterMarker(lineHandle, 'CodeMirror-lintgutter', null);
+ if ( marker.dataset.lint === 'error' ) {
+ errorCount -= 1;
+ }
};
- const processChange = (doc, deadline, change) => {
+ const processDeletion = (doc, change) => {
+ let { from, to } = change;
+ doc.eachLine(from.line, to.line, lineHandle => {
+ const marker = extractMarker(lineHandle);
+ if ( marker === null ) { return; }
+ if ( marker.dataset.lint === 'error' ) {
+ errorCount -= 1;
+ }
+ });
+ };
+
+ const processInsertion = (doc, deadline, change) => {
let { from, to } = change;
doc.eachLine(from, to, lineHandle => {
astParser.parse(lineHandle.text);
- const error = extractError();
+ const markerDetails = extractMarkerDetails(doc, lineHandle);
const marker = extractMarker(lineHandle);
- if ( error === undefined && marker ) {
- doc.setGutterMarker(lineHandle, 'CodeMirror-lintgutter', null);
- deleteMarker();
- } else if ( error !== undefined ) {
- makeMarker(doc, lineHandle, marker, error);
+ if ( markerDetails === undefined && marker !== null ) {
+ removeMarker(doc, lineHandle, marker);
+ } else if ( markerDetails !== undefined ) {
+ addMarker(doc, lineHandle, marker, markerDetails);
}
from += 1;
if ( (from & 0x0F) !== 0 ) { return; }
@@ -770,7 +869,7 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
const cm = doc.getEditor();
cm.startOperation();
while ( changeset.length !== 0 ) {
- const change = processChange(doc, deadline, changeset.shift());
+ const change = processInsertion(doc, deadline, changeset.shift());
if ( change === undefined ) { continue; }
changeset.unshift(change);
break;
@@ -779,17 +878,120 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
if ( changeset.length !== 0 ) {
return processChangesetAsync(doc);
}
+ includeset.clear();
CodeMirror.signal(doc.getEditor(), 'linterDone', { errorCount });
};
- CodeMirror.defineInitHook(cm => {
- cm.on('changes', function(cm, changes) {
- const doc = cm.getDoc();
- for ( const change of changes ) {
- const from = change.from.line;
- const to = from + change.text.length;
- addChange(doc, { from, to });
+ const processChangesetAsync = doc => {
+ if ( changesetTimer !== undefined ) { return; }
+ changesetTimer = self.requestIdleCallback(deadline => {
+ changesetTimer = undefined;
+ processChangeset(doc, deadline);
+ });
+ };
+
+ const onChanges = (cm, changes) => {
+ const doc = cm.getDoc();
+ for ( const change of changes ) {
+ const from = change.from.line;
+ const to = from + change.text.length;
+ changeset.push({ from, to });
+ processChangesetAsync(doc);
+ }
+ };
+
+ const onBeforeChanges = (cm, change) => {
+ const doc = cm.getDoc();
+ processDeletion(doc, change);
+ };
+
+ const foldRangeFinder = (cm, from) => {
+ const lineNo = from.line;
+ const lineHandle = cm.getDoc().getLineHandle(lineNo);
+ const marker = extractMarker(lineHandle);
+ if ( marker === null ) { return; }
+ if ( marker.dataset.fold === undefined ) { return; }
+ const foldName = marker.dataset.lint;
+ from.ch = lineHandle.text.length;
+ const to = { line: 0, ch: 0 };
+ const doc = cm.getDoc();
+ let depth = 0;
+ doc.eachLine(from.line, doc.lineCount(), lineHandle => {
+ const marker = extractMarker(lineHandle);
+ if ( marker === null ) { return; }
+ if ( marker.dataset.lint === foldName && marker.dataset.fold === 'start' ) {
+ depth += 1;
+ return;
}
+ if ( marker.dataset.lint !== foldName ) { return; }
+ if ( marker.dataset.fold !== 'end' ) { return; }
+ depth -= 1;
+ if ( depth !== 0 ) { return; }
+ to.line = lineHandle.lineNo();
+ return true;
+ });
+ return { from, to };
+ };
+
+ const onGutterClick = (cm, lineNo, gutterId, ev) => {
+ if ( ev.button !== 0 ) { return; }
+ if ( gutterId !== 'CodeMirror-lintgutter' ) { return; }
+ const doc = cm.getDoc();
+ const lineHandle = doc.getLineHandle(lineNo);
+ const marker = extractMarker(lineHandle);
+ if ( marker === null ) { return; }
+ if ( marker.dataset.fold === 'start' ) {
+ if ( ev.ctrlKey ) {
+ if ( dom.cl.has(marker, 'folded') ) {
+ CodeMirror.commands.unfoldAll(cm);
+ } else {
+ CodeMirror.commands.foldAll(cm);
+ }
+ doc.setCursor(lineNo);
+ return;
+ }
+ cm.foldCode(lineNo, {
+ widget: '\u00A0\u22EF\u00A0',
+ rangeFinder: foldRangeFinder,
+ });
+ return;
+ }
+ if ( marker.dataset.fold === 'end' ) {
+ let depth = 1;
+ let lineNo = lineHandle.lineNo();
+ while ( lineNo-- ) {
+ const prevLineHandle = doc.getLineHandle(lineNo);
+ const markerFrom = extractMarker(prevLineHandle);
+ if ( markerFrom === null ) { continue; }
+ if ( markerFrom.dataset.fold === 'end' ) {
+ depth += 1;
+ } else if ( markerFrom.dataset.fold === 'start' ) {
+ depth -= 1;
+ if ( depth === 0 ) {
+ doc.setCursor(lineNo);
+ break;
+ }
+ }
+ }
+ return;
+ }
+ };
+
+ CodeMirror.defineInitHook(cm => {
+ cm.on('changes', onChanges);
+ cm.on('beforeChange', onBeforeChanges);
+ cm.on('gutterClick', onGutterClick);
+ cm.on('fold', function(cm, from) {
+ const doc = cm.getDoc();
+ const lineHandle = doc.getLineHandle(from.line);
+ const marker = extractMarker(lineHandle);
+ dom.cl.add(marker, 'folded');
+ });
+ cm.on('unfold', function(cm, from) {
+ const doc = cm.getDoc();
+ const lineHandle = doc.getLineHandle(from.line);
+ const marker = extractMarker(lineHandle);
+ dom.cl.remove(marker, 'folded');
});
});
}
diff --git a/src/js/static-filtering-parser.js b/src/js/static-filtering-parser.js
index 39258e9cb..1f2cbbe69 100644
--- a/src/js/static-filtering-parser.js
+++ b/src/js/static-filtering-parser.js
@@ -727,6 +727,7 @@ export class AstFilterParser {
this.astType = AST_TYPE_NONE;
this.astTypeFlavor = AST_TYPE_NONE;
this.astFlags = 0;
+ this.astError = 0;
this.nodeTypeRegister = [];
this.nodeTypeRegisterPtr = 0;
this.nodeTypeLookupTable = new Uint32Array(NODE_TYPE_COUNT);
@@ -1068,7 +1069,7 @@ export class AstFilterParser {
const head = this.allocTypedNode(NODE_TYPE_NET_RAW, parentBeg, tailStart);
if ( this.linkDown(head, this.parseNet(head)) === 0 ) {
this.astType = AST_TYPE_UNKNOWN;
- this.addFlags(AST_FLAG_UNSUPPORTED);
+ this.addFlags(AST_FLAG_UNSUPPORTED | AST_FLAG_HAS_ERROR);
}
if ( tail !== 0 ) {
this.linkRight(head, tail);
@@ -2085,7 +2086,7 @@ export class AstFilterParser {
if ( c === 0x40 /* @ */ ) {
return AST_FLAG_IS_EXCEPTION | this.extFlagsFromAnchor(anchorBeg+1);
}
- return AST_FLAG_UNSUPPORTED;
+ return AST_FLAG_UNSUPPORTED | AST_FLAG_HAS_ERROR;
}
validateExt() {
@@ -2395,6 +2396,10 @@ export class AstFilterParser {
return (this.astFlags & AST_FLAG_HAS_ERROR) !== 0;
}
+ isUnsupported() {
+ return (this.astFlags & AST_FLAG_UNSUPPORTED) !== 0;
+ }
+
hasOptions() {
return (this.astFlags & AST_FLAG_HAS_OPTIONS) !== 0;
}
@@ -3015,7 +3020,7 @@ class ExtSelectorCompiler {
this.reIsRelativeSelector = /^\s*[+>~]/;
this.reExtendedSyntax = /\[-(?:abp|ext)-[a-z-]+=(['"])(?:.+?)(?:\1)\]/;
this.reExtendedSyntaxReplacer = /\[-(?:abp|ext)-([a-z-]+)=(['"])(.+?)\2\]/g;
- this.abpProceduralOpReplacer = /:-abp-(?:contains|has)\(/g;
+ this.abpProceduralOpReplacer = /:-abp-(?:[a-z]+)\(/g;
this.nativeCssHas = instanceOptions.nativeCssHas === true;
// https://www.w3.org/TR/css-syntax-3/#typedef-ident-token
this.reInvalidIdentifier = /^\d/;
@@ -3048,15 +3053,14 @@ class ExtSelectorCompiler {
return `:${op}(${a3})`;
});
} else {
+ let asProcedural = false;
raw = raw.replace(this.abpProceduralOpReplacer, match => {
- if ( match === ':-abp-contains(' ) {
- return ':has-text(';
- } else if ( match === ':-abp-has(' ) {
- this.asProcedural = false;
- return ':has(';
- }
+ if ( match === ':-abp-contains(' ) { return ':has-text('; }
+ if ( match === ':-abp-has(' ) { return ':has('; }
+ asProcedural = true;
return match;
});
+ this.asProcedural = asProcedural;
}
}
@@ -3068,9 +3072,10 @@ class ExtSelectorCompiler {
return true;
}
+ this.error = undefined;
out.compiled = this.compileSelector(raw);
if ( out.compiled === undefined ) {
- out.error = this.error || undefined;
+ out.error = this.error;
return false;
}
@@ -3116,7 +3121,13 @@ class ExtSelectorCompiler {
parseValue: false,
});
} catch(reason) {
- this.error = reason && reason.message || undefined;
+ const lines = [ reason.message ];
+ const extra = reason.sourceFragment().split('\n');
+ if ( extra.length !== 0 ) { lines.push(''); }
+ const match = /^[^|]+\|/.exec(extra[0]);
+ const beg = match !== null ? match[0].length : 0;
+ lines.push(...extra.map(a => a.slice(beg)));
+ this.error = lines.join('\n');
return;
}
const parts = [];
@@ -3177,6 +3188,7 @@ class ExtSelectorCompiler {
}
if ( data.type !== 'PseudoClassSelector' ) { return; }
if ( data.name.startsWith('-abp-') && this.asProcedural === false ) {
+ this.error = `${data.name} requires '#?#' separator syntax`;
return;
}
// Post-analysis, mind:
@@ -3189,6 +3201,7 @@ class ExtSelectorCompiler {
data.type = 'ActionSelector';
} else if ( data.name.startsWith('-abp-') ) {
data.type = 'Error';
+ this.error = `${data.name} is not supported`;
return;
}
if ( this.maybeProceduralOperatorNames.has(data.name) === false ) {
@@ -3196,6 +3209,7 @@ class ExtSelectorCompiler {
}
if ( this.astHasType(args, 'ActionSelector') ) {
data.type = 'Error';
+ this.error = 'invalid use of action operator';
return;
}
if ( this.astHasType(args, 'ProceduralSelector') ) {
diff --git a/src/js/support.js b/src/js/support.js
index 3b878b035..c144d6383 100644
--- a/src/js/support.js
+++ b/src/js/support.js
@@ -152,12 +152,12 @@ function showData() {
if ( reportedPage !== null ) {
shownData.popupPanel = reportedPage.popupPanel;
}
- const text = JSON.stringify(shownData, null, 2)
+ const text = JSON.stringify(shownData, null, 1)
.split('\n')
.slice(1, -1)
.map(v => {
return v
- .replace(/^( *?) "/, '$1')
+ .replace(/^( *?) "/, '$1')
.replace(/^( *.*[^\\])(?:": "|": \{$|": \[$|": )/, '$1: ')
.replace(/(?:",?|\},?|\],?|,)$/, '');
})