From da6b00918dec62a6ca52be407d66791fcde4995b Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Wed, 10 Nov 2021 17:11:00 -0600 Subject: [PATCH 1/9] Add addons for code search, auto-closing code, active line highlight, and trailing whitespace #1201 #1202 --- scripts/project.json | 10 ++++ shared/naturalcrit/codeEditor/close-tag.js | 48 +++++++++++++++++ shared/naturalcrit/codeEditor/codeEditor.jsx | 52 +++++++++++++------ shared/naturalcrit/codeEditor/codeEditor.less | 8 +++ 4 files changed, 102 insertions(+), 16 deletions(-) create mode 100644 shared/naturalcrit/codeEditor/close-tag.js diff --git a/scripts/project.json b/scripts/project.json index a83b7a0a1..07acdda48 100644 --- a/scripts/project.json +++ b/scripts/project.json @@ -14,6 +14,16 @@ "codemirror/mode/javascript/javascript.js", "codemirror/addon/fold/foldcode.js", "codemirror/addon/fold/foldgutter.js", + "codemirror/addon/fold/xml-fold.js", + "codemirror/addon/search/search.js", + "codemirror/addon/search/searchcursor.js", + "codemirror/addon/search/jump-to-line.js", + "codemirror/addon/search/match-highlighter.js", + "codemirror/addon/search/matchesonscrollbar.js", + "codemirror/addon/dialog/dialog.js", + "codemirror/addon/edit/closetag.js", + "codemirror/addon/edit/trailingspace.js", + "codemirror/addon/selection/active-line.js", "moment", "superagent", "marked" diff --git a/shared/naturalcrit/codeEditor/close-tag.js b/shared/naturalcrit/codeEditor/close-tag.js new file mode 100644 index 000000000..728b63a5c --- /dev/null +++ b/shared/naturalcrit/codeEditor/close-tag.js @@ -0,0 +1,48 @@ +const autoCloseCurlyBraces = function(CodeMirror, cm, typingClosingBrace) { + const ranges = cm.listSelections(), replacements = []; + for (let i = 0; i < ranges.length; i++) { + if(!ranges[i].empty()) return CodeMirror.Pass; + const pos = ranges[i].head, line = cm.getLine(pos.line), tok = cm.getTokenAt(pos); + if(!typingClosingBrace && (tok.type == 'string' || tok.string.charAt(0) != '{' || tok.start != pos.ch - 1)) + return CodeMirror.Pass; + else if(typingClosingBrace) { + let hasUnclosedBraces = false, index = -1; + do { + index = line.indexOf('{{', index + 1); + if(index !== -1 && line.indexOf('}}', index + 1) === -1) { + hasUnclosedBraces = true; + break; + } + } while (index !== -1); + if(!hasUnclosedBraces) return CodeMirror.Pass; + } + + replacements[i] = typingClosingBrace ? { + text : '}}', + newPos : CodeMirror.Pos(pos.line, pos.ch + 2) + } : { + text : '{}}', + newPos : CodeMirror.Pos(pos.line, pos.ch + 1) + }; + } + + for (let i = ranges.length - 1; i >= 0; i--) { + const info = replacements[i]; + cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, '+insert'); + const sel = cm.listSelections().slice(0); + sel[i] = { + head : info.newPos, + anchor : info.newPos + }; + cm.setSelections(sel); + } +}; + +module.exports = { + autoCloseCurlyBraces : function(CodeMirror, codeMirror) { + const map = { name: 'autoCloseCurlyBraces' }; + map[`'{'`] = function(cm) { return autoCloseCurlyBraces(CodeMirror, cm); }; + map[`'}'`] = function(cm) { return autoCloseCurlyBraces(CodeMirror, cm, true); }; + codeMirror.addKeyMap(map); + } +}; \ No newline at end of file diff --git a/shared/naturalcrit/codeEditor/codeEditor.jsx b/shared/naturalcrit/codeEditor/codeEditor.jsx index 3fdfec252..8f23d984c 100644 --- a/shared/naturalcrit/codeEditor/codeEditor.jsx +++ b/shared/naturalcrit/codeEditor/codeEditor.jsx @@ -3,7 +3,7 @@ const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); const cx = require('classnames'); - +const closeTag = require('./close-tag'); let CodeMirror; if(typeof navigator !== 'undefined'){ @@ -17,6 +17,16 @@ if(typeof navigator !== 'undefined'){ //Addons require('codemirror/addon/fold/foldcode.js'); require('codemirror/addon/fold/foldgutter.js'); + require('codemirror/addon/fold/xml-fold.js'); + require('codemirror/addon/search/search.js'); + require('codemirror/addon/search/searchcursor.js'); + require('codemirror/addon/search/jump-to-line.js'); + require('codemirror/addon/search/match-highlighter.js'); + require('codemirror/addon/search/matchesonscrollbar.js'); + require('codemirror/addon/dialog/dialog.js'); + require('codemirror/addon/edit/closetag.js'); + require('codemirror/addon/edit/trailingspace.js'); + require('codemirror/addon/selection/active-line.js'); const foldCode = require('./fold-code'); foldCode.registerHomebreweryHelper(CodeMirror); @@ -74,20 +84,22 @@ const CodeEditor = createClass({ tabSize : 2, historyEventDelay : 250, extraKeys : { - 'Ctrl-B' : this.makeBold, - 'Cmd-B' : this.makeBold, - 'Ctrl-I' : this.makeItalic, - 'Cmd-I' : this.makeItalic, - 'Ctrl-M' : this.makeSpan, - 'Cmd-M' : this.makeSpan, - 'Ctrl-/' : this.makeComment, - 'Cmd-/' : this.makeComment, - 'Ctrl-\\' : this.toggleCodeFolded, - 'Cmd-\\' : this.toggleCodeFolded, - 'Ctrl-[' : this.foldAllCode, - 'Cmd-[' : this.foldAllCode, - 'Ctrl-]' : this.unfoldAllCode, - 'Cmd-]' : this.unfoldAllCode + 'Ctrl-B' : this.makeBold, + 'Cmd-B' : this.makeBold, + 'Ctrl-I' : this.makeItalic, + 'Cmd-I' : this.makeItalic, + 'Ctrl-M' : this.makeSpan, + 'Cmd-M' : this.makeSpan, + 'Ctrl-/' : this.makeComment, + 'Cmd-/' : this.makeComment, + 'Ctrl-\\' : this.toggleCodeFolded, + 'Cmd-\\' : this.toggleCodeFolded, + 'Ctrl-[' : this.foldAllCode, + 'Cmd-[' : this.foldAllCode, + 'Ctrl-]' : this.unfoldAllCode, + 'Cmd-]' : this.unfoldAllCode, + 'Ctrl-Alt-F' : this.findPersistent, + 'Cmd-Opt-F' : this.findPersistent }, foldGutter : true, foldOptions : { @@ -107,8 +119,12 @@ const CodeEditor = createClass({ return `\u21A4${text.substr(0, maxLength)}\u21A6`; } }, - gutters : ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'] + gutters : ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], + showTrailingSpace : true, + autoCloseTags : true, + styleActiveLine : true }); + closeTag.autoCloseCurlyBraces(CodeMirror, this.codeMirror); // Note: codeMirror passes a copy of itself in this callback. cm === this.codeMirror. Either one works. this.codeMirror.on('change', (cm)=>{this.props.onChange(cm.getValue());}); @@ -163,6 +179,10 @@ const CodeEditor = createClass({ this.codeMirror.execCommand('unfoldAll'); }, + findPersistent : function() { + this.codeMirror.execCommand('findPersistent'); + }, + //=-- Externally used -==// setCursorPosition : function(line, char){ setTimeout(()=>{ diff --git a/shared/naturalcrit/codeEditor/codeEditor.less b/shared/naturalcrit/codeEditor/codeEditor.less index 5c0680349..fa00ba750 100644 --- a/shared/naturalcrit/codeEditor/codeEditor.less +++ b/shared/naturalcrit/codeEditor/codeEditor.less @@ -1,8 +1,16 @@ @import (less) 'codemirror/lib/codemirror.css'; @import (less) 'codemirror/addon/fold/foldgutter.css'; +@import (less) 'codemirror/addon/search/matchesonscrollbar.css'; +@import (less) 'codemirror/addon/dialog/dialog.css'; .codeEditor{ .CodeMirror-foldmarker { font-family: inherit; } + + .cm-trailingspace { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; + } } \ No newline at end of file From 278a4d35c717afefd0dd7061cff17458a9802746 Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Thu, 11 Nov 2021 21:47:15 -0600 Subject: [PATCH 2/9] Adjust calling of `removeLineClass` to limit the classes it removes #1201 #1202 --- client/homebrew/editor/editor.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 14038f740..9448404d2 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -114,7 +114,7 @@ const Editor = createClass({ const lineNumbers = _.reduce(this.props.brew.text.split('\n'), (r, line, lineNumber)=>{ //reset custom line styles - codeMirror.removeLineClass(lineNumber, 'background'); + codeMirror.removeLineClass(lineNumber, 'background', 'pageLine'); codeMirror.removeLineClass(lineNumber, 'text'); // Legacy Codemirror styling From 602ff67f3c9c0be496e7e1ae4b061cf739f89ffc Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Thu, 11 Nov 2021 22:38:27 -0600 Subject: [PATCH 3/9] Add style for tabs to show tabs differently from spaces in the code editor #1622 --- shared/naturalcrit/codeEditor/codeEditor.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared/naturalcrit/codeEditor/codeEditor.less b/shared/naturalcrit/codeEditor/codeEditor.less index 4913ff3e5..67beb394b 100644 --- a/shared/naturalcrit/codeEditor/codeEditor.less +++ b/shared/naturalcrit/codeEditor/codeEditor.less @@ -10,6 +10,10 @@ font-weight: 600; } + .cm-tab { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAQAAACOs/baAAAARUlEQVR4nGJgIAG8JkXxUAcCtDWemcGR1lY4MvgzCEKY7jSBjgxBDAG09UEQzAe0AMwMHrSOAwEGRtpaMIwAAAAA//8DAG4ID9EKs6YqAAAAAElFTkSuQmCC) no-repeat right; + } + .cm-trailingspace { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==); background-position: bottom left; From 65c9a2cba038969314019032d11c5c607519a93f Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Fri, 10 Dec 2021 23:04:22 -0600 Subject: [PATCH 4/9] Update CodeMirror library import order and add comments explaining each file --- shared/naturalcrit/codeEditor/codeEditor.jsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shared/naturalcrit/codeEditor/codeEditor.jsx b/shared/naturalcrit/codeEditor/codeEditor.jsx index 1e9445333..3aa4ffbde 100644 --- a/shared/naturalcrit/codeEditor/codeEditor.jsx +++ b/shared/naturalcrit/codeEditor/codeEditor.jsx @@ -16,18 +16,24 @@ if(typeof navigator !== 'undefined'){ require('codemirror/mode/javascript/javascript.js'); //Addons + //Code folding require('codemirror/addon/fold/foldcode.js'); require('codemirror/addon/fold/foldgutter.js'); - require('codemirror/addon/fold/xml-fold.js'); + //Search and replace require('codemirror/addon/search/search.js'); require('codemirror/addon/search/searchcursor.js'); require('codemirror/addon/search/jump-to-line.js'); require('codemirror/addon/search/match-highlighter.js'); require('codemirror/addon/search/matchesonscrollbar.js'); require('codemirror/addon/dialog/dialog.js'); - require('codemirror/addon/edit/closetag.js'); + //Trailing space highlighting require('codemirror/addon/edit/trailingspace.js'); + //Active line highlighting require('codemirror/addon/selection/active-line.js'); + //Auto-closing + //XML code folding is a requirement of the auto-closing tag feature and is not enabled + require('codemirror/addon/fold/xml-fold.js'); + require('codemirror/addon/edit/closetag.js'); const foldCode = require('./fold-code'); foldCode.registerHomebreweryHelper(CodeMirror); From b60bc2996b0a30869fd8e4113ccf9b70f6423a33 Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Fri, 10 Dec 2021 23:05:16 -0600 Subject: [PATCH 5/9] Update search/replace shortcuts and add 'Enter'-based shortcut for navigating backwards --- shared/naturalcrit/codeEditor/codeEditor.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/shared/naturalcrit/codeEditor/codeEditor.jsx b/shared/naturalcrit/codeEditor/codeEditor.jsx index 3aa4ffbde..f2baea264 100644 --- a/shared/naturalcrit/codeEditor/codeEditor.jsx +++ b/shared/naturalcrit/codeEditor/codeEditor.jsx @@ -131,8 +131,9 @@ const CodeEditor = createClass({ 'Shift-Cmd-Enter' : this.newColumn, 'Ctrl-Enter' : this.newPage, 'Cmd-Enter' : this.newPage, - 'Ctrl-Alt-F' : this.findPersistent, - 'Cmd-Opt-F' : this.findPersistent, + 'Ctrl-F' : 'findPersistent', + 'Cmd-F' : 'findPersistent', + 'Shift-Enter' : 'findPersistentPrevious', 'Ctrl-[' : this.foldAllCode, 'Cmd-[' : this.foldAllCode, 'Ctrl-]' : this.unfoldAllCode, From 61cfef445b366fb6760fe76681434a23a77f8938 Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Fri, 10 Dec 2021 23:07:21 -0600 Subject: [PATCH 6/9] Update trailing space background and remove tab background when it is inside a trailing space --- shared/naturalcrit/codeEditor/codeEditor.less | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/shared/naturalcrit/codeEditor/codeEditor.less b/shared/naturalcrit/codeEditor/codeEditor.less index 67beb394b..5b1dc56d7 100644 --- a/shared/naturalcrit/codeEditor/codeEditor.less +++ b/shared/naturalcrit/codeEditor/codeEditor.less @@ -15,8 +15,11 @@ } .cm-trailingspace { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==); - background-position: bottom left; - background-repeat: repeat-x; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQAgMAAABW5NbuAAAACVBMVEVHcEwAAAAAAAAWawmTAAAAA3RSTlMAPBJ6PMxpAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAFUlEQVQI12NgwACcCQysASAEZGAAACMuAX06aCQUAAAAAElFTkSuQmCC) repeat-x left; + background-size: 7.16px 15px; + + .cm-tab { + background: none; + } } } \ No newline at end of file From 84f3519dbe73cbeeca53972b2771086bcaadf0e5 Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Fri, 10 Dec 2021 23:39:26 -0600 Subject: [PATCH 7/9] Remove unnecessary findPersistent method --- shared/naturalcrit/codeEditor/codeEditor.jsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/shared/naturalcrit/codeEditor/codeEditor.jsx b/shared/naturalcrit/codeEditor/codeEditor.jsx index f2baea264..2a1bc8f30 100644 --- a/shared/naturalcrit/codeEditor/codeEditor.jsx +++ b/shared/naturalcrit/codeEditor/codeEditor.jsx @@ -326,10 +326,6 @@ const CodeEditor = createClass({ this.codeMirror.execCommand('unfoldAll'); }, - findPersistent : function() { - this.codeMirror.execCommand('findPersistent'); - }, - //=-- Externally used -==// setCursorPosition : function(line, char){ setTimeout(()=>{ From 53fcdd8d7a7b8a5a1a366e1c0c45958f9c51a1a7 Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Mon, 13 Dec 2021 20:29:28 -0600 Subject: [PATCH 8/9] Prevent activeline class from being removed --- client/homebrew/editor/editor.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 6f9ce517f..6eefc183f 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -117,7 +117,7 @@ const Editor = createClass({ _.forEach(this.props.brew.text.split('\n'), (line, lineNumber)=>{ //reset custom line styles - codeMirror.removeLineClass(lineNumber, 'background'); + codeMirror.removeLineClass(lineNumber, 'background', 'pageLine'); codeMirror.removeLineClass(lineNumber, 'text'); // Styling for \page breaks From 2c2579ae2b6a4edc77d1fd11337f7e93d23bad03 Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Mon, 13 Dec 2021 20:49:32 -0600 Subject: [PATCH 9/9] Update usage of trailing space to include special chars for spaces --- shared/naturalcrit/codeEditor/codeEditor.jsx | 15 +++++++++++---- shared/naturalcrit/codeEditor/codeEditor.less | 7 ++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/shared/naturalcrit/codeEditor/codeEditor.jsx b/shared/naturalcrit/codeEditor/codeEditor.jsx index 2a1bc8f30..0956521f4 100644 --- a/shared/naturalcrit/codeEditor/codeEditor.jsx +++ b/shared/naturalcrit/codeEditor/codeEditor.jsx @@ -161,10 +161,17 @@ const CodeEditor = createClass({ return `\u21A4 ${text} \u21A6`; } }, - gutters : ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], - showTrailingSpace : true, - autoCloseTags : true, - styleActiveLine : true + gutters : ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], + autoCloseTags : true, + styleActiveLine : true, + showTrailingSpace : true, + specialChars : / /, + specialCharPlaceholder : function(char) { + const el = document.createElement('span'); + el.className = 'cm-space'; + el.innerHTML = ' '; + return el; + } }); closeTag.autoCloseCurlyBraces(CodeMirror, this.codeMirror); diff --git a/shared/naturalcrit/codeEditor/codeEditor.less b/shared/naturalcrit/codeEditor/codeEditor.less index 5b1dc56d7..037a326bc 100644 --- a/shared/naturalcrit/codeEditor/codeEditor.less +++ b/shared/naturalcrit/codeEditor/codeEditor.less @@ -15,11 +15,8 @@ } .cm-trailingspace { - background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQAgMAAABW5NbuAAAACVBMVEVHcEwAAAAAAAAWawmTAAAAA3RSTlMAPBJ6PMxpAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAFUlEQVQI12NgwACcCQysASAEZGAAACMuAX06aCQUAAAAAElFTkSuQmCC) repeat-x left; - background-size: 7.16px 15px; - - .cm-tab { - background: none; + .cm-space { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQAgMAAABW5NbuAAAACVBMVEVHcEwAAAAAAAAWawmTAAAAA3RSTlMAPBJ6PMxpAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAFUlEQVQI12NgwACcCQysASAEZGAAACMuAX06aCQUAAAAAElFTkSuQmCC) no-repeat right; } } } \ No newline at end of file