mirror of
https://github.com/gorhill/uBlock.git
synced 2026-03-11 09:04:36 +00:00
[mv3] Add support for code-folding and use custom stream parser
This commit is contained in:
parent
837451c17a
commit
fad39c6ce5
4 changed files with 135 additions and 11 deletions
|
|
@ -36,7 +36,7 @@ section[data-pane="develop"] > div > * {
|
|||
border-top: 1px dotted transparent;
|
||||
}
|
||||
|
||||
#cm-dnrRules .cm-editor .cm-line:has(.ͼ5) {
|
||||
#cm-dnrRules .cm-editor .cm-line:has(.ͼc) {
|
||||
border-bottom: 1px dotted var(--border-1);
|
||||
border-top: 1px dotted var(--border-1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -356,9 +356,10 @@ function setEditorText(text) {
|
|||
cmRules.dispatch({
|
||||
changes: {
|
||||
from: 0, to: cmRules.state.doc.length,
|
||||
insert: text
|
||||
insert: text,
|
||||
},
|
||||
});
|
||||
cmRules.focus();
|
||||
}
|
||||
|
||||
function getEditorText() {
|
||||
|
|
@ -529,6 +530,7 @@ function importRulesFromFile() {
|
|||
prepend = `${prepend}---\n`;
|
||||
}
|
||||
cmRules.dispatch({ changes: { from, insert: `${prepend}${text}` } });
|
||||
self.cm6.foldAll(cmRules);
|
||||
cmRules.focus();
|
||||
};
|
||||
fr.readAsText(file);
|
||||
|
|
@ -568,25 +570,57 @@ function importRulesFromPaste(transaction) {
|
|||
const { from, to } = rangeFromTransaction(transaction);
|
||||
if ( from === undefined || to === undefined ) { return; }
|
||||
// Paste position must match start of a line
|
||||
const { doc } = transaction.newDoc;
|
||||
const lineFrom = doc.lineAt(from);
|
||||
const { newDoc } = transaction;
|
||||
const lineFrom = newDoc.lineAt(from);
|
||||
if ( lineFrom.from !== from ) { return; }
|
||||
// Paste position must match a rule boundary
|
||||
if ( lineFrom.number !== 1 ) {
|
||||
const lineBefore = doc.line(lineFrom.number-1);
|
||||
const lineBefore = newDoc.line(lineFrom.number-1);
|
||||
if ( /^---\s*$/.test(lineBefore.text) === false ) { return; }
|
||||
}
|
||||
const pastedText = doc.sliceString(from, to);
|
||||
const pastedText = newDoc.sliceString(from, to);
|
||||
const rules = rulesFromJSON(pastedText);
|
||||
if ( rules === undefined ) { return; }
|
||||
const yamlText = textFromRules(rules);
|
||||
if ( yamlText === undefined ) { return; }
|
||||
cmRules.dispatch({ changes: { from, to, insert: yamlText } });
|
||||
self.cm6.foldAll(cmRules);
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function foldService(state, from) {
|
||||
const { doc } = state;
|
||||
const lineFrom = doc.lineAt(from);
|
||||
if ( reFoldable.test(lineFrom.text) === false ) { return null; }
|
||||
if ( lineFrom.number <= 5 ) { return null ; }
|
||||
const lineBlockStart = doc.line(lineFrom.number - 5);
|
||||
if ( reFoldCandidates.test(lineBlockStart.text) === false ) { return null; }
|
||||
for ( let i = lineFrom.number-4; i < lineFrom.number; i++ ) {
|
||||
const line = doc.line(i);
|
||||
if ( reFoldable.test(line.text) === false ) { return null; }
|
||||
}
|
||||
for ( let i = lineFrom.number; i < doc.lines; i++ ) {
|
||||
const lineNext = doc.line(i+1);
|
||||
if ( reFoldable.test(lineNext.text) ) { continue; }
|
||||
if ( i === lineFrom.number ) { return null; }
|
||||
const lineFoldEnd = doc.line(i);
|
||||
return { from: lineFrom.from+6, to: lineFoldEnd.to };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const reFoldable = /^ {4}- \S/;
|
||||
const reFoldCandidates = new RegExp(`^(?: {2})+${[
|
||||
'initiatorDomains',
|
||||
'excludedInitiatorDomains',
|
||||
'requestDomains',
|
||||
'excludedRequestDomains',
|
||||
].join('|')}:$`);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function smartBackspace(transaction) {
|
||||
const { from, to } = rangeFromTransaction(transaction);
|
||||
if ( from === undefined || to === undefined ) { return; }
|
||||
|
|
@ -655,18 +689,104 @@ function smartSpacebar(transaction) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const dnryamlStreamParser = {
|
||||
name: 'dnryaml',
|
||||
startState() {
|
||||
return {
|
||||
scope: 0,
|
||||
reKeywords: new RegExp(`\\b(${[
|
||||
'block',
|
||||
'redirect',
|
||||
'allow',
|
||||
'modifyHeaders',
|
||||
'upgradeScheme',
|
||||
'allowAllRequest',
|
||||
'append',
|
||||
'set',
|
||||
'remove',
|
||||
'firstParty',
|
||||
'thirdParty',
|
||||
'true',
|
||||
'false',
|
||||
'connect',
|
||||
'delete',
|
||||
'get',
|
||||
'head',
|
||||
'options',
|
||||
'patch',
|
||||
'post',
|
||||
'put',
|
||||
'other',
|
||||
'main_frame',
|
||||
'sub_frame',
|
||||
'stylesheet',
|
||||
'script',
|
||||
'image',
|
||||
'font',
|
||||
'object',
|
||||
'xmlhttprequest',
|
||||
'ping',
|
||||
'csp_report',
|
||||
'media',
|
||||
'websocket',
|
||||
'webtransport',
|
||||
'webbundle',
|
||||
'other',
|
||||
].join('|')})\\b`),
|
||||
};
|
||||
},
|
||||
token(stream, state) {
|
||||
const c = stream.peek();
|
||||
if ( c === '#' ) {
|
||||
if ( (stream.pos === 0 || /\s/.test(stream.string.charAt(stream.pos - 1))) ) {
|
||||
stream.skipToEnd();
|
||||
return 'comment';
|
||||
}
|
||||
}
|
||||
if ( stream.sol() ) {
|
||||
if ( stream.match('---') ) { return 'contentSeparator'; }
|
||||
if ( stream.match('...') ) { return 'contentSeparator'; }
|
||||
}
|
||||
if ( stream.eatSpace() ) {
|
||||
return null;
|
||||
}
|
||||
const { scope } = state;
|
||||
state.scope = 0;
|
||||
if ( scope === 0 && stream.match(/^[^:]+(?=:)/) ) {
|
||||
state.scope = 1;
|
||||
return 'keyword';
|
||||
}
|
||||
if ( scope === 1 && stream.match(/^:(?: |$)/) ) {
|
||||
return 'meta';
|
||||
}
|
||||
if ( stream.match(/^- /) ) {
|
||||
return 'meta';
|
||||
}
|
||||
if ( stream.match(state.reKeywords) ) {
|
||||
return 'literal';
|
||||
}
|
||||
if ( stream.match(/^\S+/) ) {
|
||||
return null;
|
||||
}
|
||||
stream.next();
|
||||
return null;
|
||||
},
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function cmUpdateListener(info) {
|
||||
if ( info.docChanged === false ) { return; }
|
||||
for ( const transaction of info.transactions ) {
|
||||
if ( transaction.docChanged === false ) { continue; }
|
||||
addToModifiedRange(transaction);
|
||||
if ( transaction.isUserEvent('delete.backward') ) {
|
||||
if ( smartBackspace(transaction) ) { break; }
|
||||
smartBackspace(transaction);
|
||||
} else if ( transaction.isUserEvent('input.paste') ) {
|
||||
if ( importRulesFromPaste(transaction) ) { break; }
|
||||
importRulesFromPaste(transaction);
|
||||
} else if ( transaction.isUserEvent('input') ) {
|
||||
if ( smartReturn(transaction) ) { break; }
|
||||
if ( smartSpacebar(transaction) ) { break; }
|
||||
if ( smartReturn(transaction) ) { continue; }
|
||||
smartSpacebar(transaction);
|
||||
}
|
||||
}
|
||||
updateViewAsync();
|
||||
|
|
@ -743,6 +863,8 @@ const cmRules = (( ) => {
|
|||
},
|
||||
gutterClick,
|
||||
hoverTooltip,
|
||||
streamParser: dnryamlStreamParser,
|
||||
foldService,
|
||||
}, qs$('#cm-dnrRules'));
|
||||
})();
|
||||
|
||||
|
|
@ -754,6 +876,7 @@ localRead('userDnrRules').then(text => {
|
|||
text ||= '';
|
||||
setEditorText(text);
|
||||
lastSavedText = text;
|
||||
self.cm6.foldAll(cmRules);
|
||||
self.cm6.resetUndoRedo(cmRules);
|
||||
|
||||
dom.on('#dnrRulesApply', 'click', ( ) => {
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ function changeTrustedSites() {
|
|||
function getStagedTrustedSites() {
|
||||
const text = cmTrustedSites.state.doc.toString();
|
||||
return text.split(/\s/).map(hn => {
|
||||
if ( hn === '' ) { return ''; }
|
||||
try {
|
||||
return punycode.toASCII(
|
||||
(new URL(`https://${hn}/`)).hostname
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 1d352d4489fea6f4aa10a32417eba4abd67db5c9
|
||||
Subproject commit 58a4bae6af82358754da665d3056d7af295bbb7b
|
||||
Loading…
Reference in a new issue