From e905e4e07906ecfe22eb8e6d6d7d3ceae911fe4a Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 3 Dec 2017 21:34:01 +0300 Subject: [PATCH] properly escape/unescape regexp in applies-to widgets --- _locales/en/messages.json | 4 ++++ edit/applies-to-line-widget.js | 8 +++++++- edit/edit.css | 6 ++++++ edit/regexp-tester.js | 8 +++++++- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index e7f5877e..697c870e 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -742,6 +742,10 @@ "message": "Invalid regexps skipped", "description": "RegExp test report: label for the invalid expressions" }, + "styleRegexpTestNote": { + "message": "Note: use a single \\ for escaping in the regexp input field, which will be automatically converted to \\\\ in the style code as per specification for quoted strings in CSS.", + "description": "RegExp test report: a note displayed at the bottom of the dialog" + }, "styleRegexpPartialExplanation": { "message": "This style uses partially matching regexps in violation of CSS4 @document specification which requires a full URL match. The affected CSS sections were not applied to the page. This style was probably created in Stylish-for-Chrome which incorrectly checks 'regexp()' rules since the very first version (known bug)." }, diff --git a/edit/applies-to-line-widget.js b/edit/applies-to-line-widget.js index d23668bc..34340626 100644 --- a/edit/applies-to-line-widget.js +++ b/edit/applies-to-line-widget.js @@ -435,9 +435,13 @@ function createAppliesToLineWidget(cm) { } function changeItem(apply, part, newText) { + if (!apply) { + return; + } part = apply[part]; const range = part.mark.find(); part.mark.clear(); + newText = newText.replace(/\\/g, '\\\\'); cm.replaceRange(newText, range.from, range.to, 'appliesTo'); part.mark = cm.markText( range.from, @@ -467,12 +471,14 @@ function createAppliesToLineWidget(cm) { } function createApply(pos, typeText, valueText, isQuoted = false) { + typeText = typeText.toLowerCase(); const start = pos; const typeStart = start; const typeEnd = typeStart + typeText.length; const valueStart = typeEnd + 1 + Number(isQuoted); const valueEnd = valueStart + valueText.length; const end = valueEnd + Number(isQuoted) + 1; + const hasSingleEscapes = /([^\\]|^)\\([^\\]|$)/.test(valueText); return { start, type: { @@ -481,7 +487,7 @@ function createAppliesToLineWidget(cm) { end: typeEnd, }, value: { - text: valueText, + text: hasSingleEscapes ? valueText : valueText.replace(/\\\\/g, '\\'), start: valueStart, end: valueEnd, }, diff --git a/edit/edit.css b/edit/edit.css index 299b1ec4..4a892adb 100644 --- a/edit/edit.css +++ b/edit/edit.css @@ -385,6 +385,12 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar margin-left: -20px; margin-top: -1px; } +.regexp-report-note { + font-size: 90%; + margin: 1em 1em .5em; + color: #999; +} + /************ help popup ************/ #help-popup { top: 3rem; diff --git a/edit/regexp-tester.js b/edit/regexp-tester.js index 80ad7a70..a11527c1 100644 --- a/edit/regexp-tester.js +++ b/edit/regexp-tester.js @@ -165,9 +165,15 @@ var regExpTester = (() => { } } } + report.appendChild($element({ + tag: 'p', + className: 'regexp-report-note', + appendChild: t('styleRegexpTestNote').split(/(\\+)/) + .map(s => s.startsWith('\\') ? $element({tag: 'code', textContent: s}) : s), + })); showHelp(t('styleRegexpTestTitle'), report); - $('.regexp-report').onclick = event => { + report.onclick = event => { const target = event.target.closest('a, .regexp-report div'); if (target) { openURL({