Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e44a568

Browse files
committed
Add CoreMirror's code-folding ability to list editor/viewer
Related issue: - uBlockOrigin/uBlock-issues#1134 CodeMirror's code folding reference: - https://codemirror.net/doc/manual.html#addon_foldcode This commit adds support for code-folding to the filter list editor/viewer. The following blocks of code are foldable by clicking the corresponding marker in the gutter: - !#if/#endif blocks - !#include blocks Addtionally, the following changes: - The `!#include` line is now preserved when importing a sublist - The `!#if` directives will be syntax-colored according to whether they evaluate to true or false on the current platform - Double-clicking on a foldable line in the gutter will select the content of the foldable block - Minor visual improvement to matching brackets
1 parent f955d50 commit e44a568

File tree

12 files changed

+443
-28
lines changed

12 files changed

+443
-28
lines changed

src/1p-filters.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<title>uBlock — Your filters</title>
77

88
<link rel="stylesheet" href="lib/codemirror/lib/codemirror.css">
9+
<link rel="stylesheet" href="lib/codemirror/addon/fold/foldgutter.css">
910
<link rel="stylesheet" href="lib/codemirror/addon/hint/show-hint.css">
1011
<link rel="stylesheet" href="lib/codemirror/addon/search/matchesonscrollbar.css">
1112

@@ -42,6 +43,8 @@
4243
<script src="lib/codemirror/addon/display/panel.js"></script>
4344
<script src="lib/codemirror/addon/edit/closebrackets.js"></script>
4445
<script src="lib/codemirror/addon/edit/matchbrackets.js"></script>
46+
<script src="lib/codemirror/addon/fold/foldcode.js"></script>
47+
<script src="lib/codemirror/addon/fold/foldgutter.js"></script>
4548
<script src="lib/codemirror/addon/hint/show-hint.js"></script>
4649
<script src="lib/codemirror/addon/scroll/annotatescrollbar.js"></script>
4750
<script src="lib/codemirror/addon/search/matchesonscrollbar.js"></script>

src/asset-viewer.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1">
66
<title data-i18n="assetViewerPageName"></title>
77
<link rel="stylesheet" href="lib/codemirror/lib/codemirror.css">
8+
<link rel="stylesheet" href="lib/codemirror/addon/fold/foldgutter.css">
89
<link rel="stylesheet" href="lib/codemirror/addon/search/matchesonscrollbar.css">
910
<link rel="stylesheet" type="text/css" href="css/themes/default.css">
1011
<link rel="stylesheet" href="css/common.css">
@@ -31,6 +32,8 @@
3132
<script src="lib/codemirror/lib/codemirror.js"></script>
3233
<script src="lib/codemirror/addon/display/panel.js"></script>
3334
<script src="lib/codemirror/addon/edit/matchbrackets.js"></script>
35+
<script src="lib/codemirror/addon/fold/foldcode.js"></script>
36+
<script src="lib/codemirror/addon/fold/foldgutter.js"></script>
3437
<script src="lib/codemirror/addon/scroll/annotatescrollbar.js"></script>
3538
<script src="lib/codemirror/addon/search/matchesonscrollbar.js"></script>
3639
<script src="lib/codemirror/addon/search/searchcursor.js"></script>

src/css/codemirror.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ div.CodeMirror span.CodeMirror-matchingbracket {
5252
color: unset;
5353
}
5454
.CodeMirror-matchingbracket {
55+
background-color: #afa;
5556
color: inherit !important;
5657
font-weight: bold;
5758
}

src/js/1p-filters.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ const cmEditor = new CodeMirror(document.getElementById('userFilters'), {
3636
'Ctrl-Space': 'autocomplete',
3737
'Tab': 'toggleComment',
3838
},
39+
foldGutter: true,
40+
gutters: [ 'CodeMirror-linenumbers', 'CodeMirror-foldgutter' ],
3941
lineNumbers: true,
4042
lineWrapping: true,
4143
matchBrackets: true,

src/js/asset-viewer.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
const cmEditor = new CodeMirror(document.getElementById('content'), {
3434
autofocus: true,
35+
foldGutter: true,
36+
gutters: [ 'CodeMirror-linenumbers', 'CodeMirror-foldgutter' ],
3537
lineNumbers: true,
3638
lineWrapping: true,
3739
matchBrackets: true,

src/js/assets.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ api.fetchFilterList = async function(mainlistURL) {
276276
if ( sublistURLs.has(subURL) ) { continue; }
277277
sublistURLs.add(subURL);
278278
out.push(
279-
slice.slice(lastIndex, match.index),
279+
slice.slice(lastIndex, match.index + match[0].length),
280280
`! >>>>>>>> ${subURL}`,
281281
api.fetchText(subURL),
282282
`! <<<<<<<< ${subURL}`

src/js/codemirror/ubo-static-filtering.js

Lines changed: 80 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
const redirectNames = new Map();
3434
const scriptletNames = new Map();
35-
const preparseDirectiveTokens = new Set();
35+
const preparseDirectiveTokens = new Map();
3636
const preparseDirectiveHints = [];
3737

3838
/******************************************************************************/
@@ -44,8 +44,8 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
4444
if ( StaticFilteringParser instanceof Object === false ) { return; }
4545
const parser = new StaticFilteringParser({ interactive: true });
4646

47-
const rePreparseDirectives = /^!#(?:if|endif|include)\b/;
48-
const rePreparseIfDirective = /^(!#if !?)(.+)$/;
47+
const rePreparseDirectives = /^!#(?:if|endif|include )\b/;
48+
const rePreparseIfDirective = /^(!#if ?)(.*)$/;
4949
let parserSlot = 0;
5050
let netOptionValueMode = false;
5151

@@ -60,17 +60,28 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
6060
return 'variable strong';
6161
}
6262
if ( stream.pos < match[1].length ) {
63-
stream.pos = match[1].length;
63+
stream.pos += match[1].length;
6464
return 'variable strong';
6565
}
6666
stream.skipToEnd();
67-
if (
68-
preparseDirectiveTokens.size === 0 ||
69-
preparseDirectiveTokens.has(match[2].trim())
70-
) {
71-
return 'variable strong';
67+
if ( match[1].endsWith(' ') === false ) {
68+
return 'error strong';
69+
}
70+
if ( preparseDirectiveTokens.size === 0 ) {
71+
return 'positive strong';
72+
}
73+
let token = match[2];
74+
const not = token.startsWith('!');
75+
if ( not ) {
76+
token = token.slice(1);
77+
}
78+
if ( preparseDirectiveTokens.has(token) === false ) {
79+
return 'error strong';
7280
}
73-
return 'error strong';
81+
if ( not !== preparseDirectiveTokens.get(token) ) {
82+
return 'positive strong';
83+
}
84+
return 'negative strong';
7485
};
7586

7687
const colorExtHTMLPatternSpan = function(stream) {
@@ -289,8 +300,8 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
289300
scriptletNames.set(name.slice(0, -3), displayText);
290301
}
291302
}
292-
details.preparseDirectiveTokens.forEach(a => {
293-
preparseDirectiveTokens.add(a);
303+
details.preparseDirectiveTokens.forEach(([ a, b ]) => {
304+
preparseDirectiveTokens.set(a, b);
294305
});
295306
preparseDirectiveHints.push(...details.preparseDirectiveHints);
296307
initHints();
@@ -471,6 +482,63 @@ const initHints = function() {
471482

472483
/******************************************************************************/
473484

485+
CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
486+
487+
const foldIfEndif = function(startLineNo, startLine, cm) {
488+
const lastLineNo = cm.lastLine();
489+
let endLineNo = startLineNo;
490+
let depth = 1;
491+
while ( endLineNo < lastLineNo ) {
492+
endLineNo += 1;
493+
const line = cm.getLine(endLineNo);
494+
if ( line.startsWith('!#endif') ) {
495+
depth -= 1;
496+
if ( depth === 0 ) {
497+
return {
498+
from: CodeMirror.Pos(startLineNo, startLine.length),
499+
to: CodeMirror.Pos(endLineNo, 0)
500+
};
501+
}
502+
}
503+
if ( line.startsWith('!#if') ) {
504+
depth += 1;
505+
}
506+
}
507+
};
508+
509+
const foldInclude = function(startLineNo, startLine, cm) {
510+
const lastLineNo = cm.lastLine();
511+
let endLineNo = startLineNo + 1;
512+
if ( endLineNo >= lastLineNo ) { return; }
513+
if ( cm.getLine(endLineNo).startsWith('! >>>>>>>> ') === false ) {
514+
return;
515+
}
516+
while ( endLineNo < lastLineNo ) {
517+
endLineNo += 1;
518+
const line = cm.getLine(endLineNo);
519+
if ( line.startsWith('! <<<<<<<< ') ) {
520+
return {
521+
from: CodeMirror.Pos(startLineNo, startLine.length),
522+
to: CodeMirror.Pos(endLineNo, line.length)
523+
};
524+
}
525+
}
526+
};
527+
528+
return function(cm, start) {
529+
const startLineNo = start.line;
530+
const startLine = cm.getLine(startLineNo);
531+
if ( startLine.startsWith('!#if') ) {
532+
return foldIfEndif(startLineNo, startLine, cm);
533+
}
534+
if ( startLine.startsWith('!#include ') ) {
535+
return foldInclude(startLineNo, startLine, cm);
536+
}
537+
};
538+
})());
539+
540+
/******************************************************************************/
541+
474542
// <<<<< end of local scope
475543
}
476544

src/js/dashboard-common.js

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -149,24 +149,37 @@ self.uBlockDashboard.patchCodeMirrorEditor = (function() {
149149
let lastGutterClick = 0;
150150
let lastGutterLine = 0;
151151

152-
const onGutterClicked = function(cm, line) {
152+
const onGutterClicked = function(cm, line, gutter) {
153+
if ( gutter !== 'CodeMirror-linenumbers' ) { return; }
154+
grabFocusAsync(cm);
153155
const delta = Date.now() - lastGutterClick;
156+
// Single click
154157
if ( delta >= 500 || line !== lastGutterLine ) {
155158
cm.setSelection(
156-
{ line: line, ch: 0 },
159+
{ line, ch: 0 },
157160
{ line: line + 1, ch: 0 }
158161
);
159162
lastGutterClick = Date.now();
160163
lastGutterLine = line;
161-
} else {
162-
cm.setSelection(
163-
{ line: 0, ch: 0 },
164-
{ line: cm.lineCount(), ch: 0 },
165-
{ scroll: false }
166-
);
167-
lastGutterClick = 0;
164+
return;
168165
}
169-
grabFocusAsync(cm);
166+
// Double click: select fold-able block or all
167+
let lineFrom = 0;
168+
let lineTo = cm.lineCount();
169+
const foldFn = cm.getHelper({ line, ch: 0 }, 'fold');
170+
if ( foldFn instanceof Function ) {
171+
const range = foldFn(cm, { line, ch: 0 });
172+
if ( range !== undefined ) {
173+
lineFrom = range.from.line;
174+
lineTo = range.to.line + 1;
175+
}
176+
}
177+
cm.setSelection(
178+
{ line: lineFrom, ch: 0 },
179+
{ line: lineTo, ch: 0 },
180+
{ scroll: false }
181+
);
182+
lastGutterClick = 0;
170183
};
171184

172185
return function(cm) {

src/js/storage.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
862862
// the content string which should alternatively be parsed and discarded.
863863
split: function(content) {
864864
const reIf = /^!#(if|endif)\b([^\n]*)(?:[\n\r]+|$)/gm;
865+
const soup = vAPI.webextFlavor.soup;
865866
const stack = [];
866867
const shouldDiscard = ( ) => stack.some(v => v);
867868
const parts = [ 0 ];
@@ -878,10 +879,8 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
878879
if ( target ) { expr = expr.slice(1); }
879880
const token = this.tokens.get(expr);
880881
const startDiscard =
881-
token === 'false' &&
882-
target === false ||
883-
token !== undefined &&
884-
vAPI.webextFlavor.soup.has(token) === target;
882+
token === 'false' && target === false ||
883+
token !== undefined && soup.has(token) === target;
885884
if ( discard === false && startDiscard ) {
886885
parts.push(match.index);
887886
discard = true;
@@ -930,7 +929,12 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
930929
},
931930

932931
getTokens: function() {
933-
return Array.from(this.tokens.keys());
932+
const out = new Map();
933+
const soup = vAPI.webextFlavor.soup;
934+
for ( const [ key, val ] of this.tokens ) {
935+
out.set(key, val !== 'false' && soup.has(val));
936+
}
937+
return Array.from(out);
934938
},
935939

936940
tokens: new Map([
@@ -947,6 +951,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
947951
// Compatibility with other blockers
948952
// https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#adguard-specific
949953
[ 'adguard', 'adguard' ],
954+
[ 'adguard_app_windows', 'false' ],
950955
[ 'adguard_ext_chromium', 'chromium' ],
951956
[ 'adguard_ext_edge', 'edge' ],
952957
[ 'adguard_ext_firefox', 'firefox' ],

0 commit comments

Comments
 (0)