From b2eac666e510a4a5938c35cc3044ca1754bcd5e4 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 26 Aug 2013 21:41:18 +0400 Subject: [PATCH 1/9] allow removing listener while event is dispatched --- lib/ace/lib/event_emitter.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ace/lib/event_emitter.js b/lib/ace/lib/event_emitter.js index 482ae0d4..b9860145 100644 --- a/lib/ace/lib/event_emitter.js +++ b/lib/ace/lib/event_emitter.js @@ -55,6 +55,7 @@ EventEmitter._dispatchEvent = function(eventName, e) { if (!e.preventDefault) e.preventDefault = preventDefault; + listeners = listeners.slice(); for (var i=0; i Date: Mon, 26 Aug 2013 21:44:30 +0400 Subject: [PATCH 2/9] provide oldSize in resize event --- lib/ace/virtual_renderer.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index ab529919..b73f96aa 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -344,7 +344,7 @@ var VirtualRenderer = function(container, theme) { if (force) this.$renderChanges(changes, true); else - this.$loop.schedule(changes || this.$changes); + this.$loop.schedule(changes | this.$changes); if (this.resizing) this.resizing = 0; @@ -353,6 +353,12 @@ var VirtualRenderer = function(container, theme) { this.$updateCachedSize = function(force, gutterWidth, width, height) { var changes = 0; var size = this.$size; + var oldSize = { + width: size.width, + height: size.height, + scrollerHeight: size.scrollerHeight, + scrollerWidth: size.scrollerWidth + }; if (height && (force || size.height != height)) { size.height = height; changes = this.CHANGE_SIZE; @@ -394,7 +400,7 @@ var VirtualRenderer = function(container, theme) { } if (changes) - this._signal("resize"); + this._signal("resize", oldSize); return changes; }; @@ -402,7 +408,7 @@ var VirtualRenderer = function(container, theme) { this.onGutterResize = function() { var gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; if (gutterWidth != this.gutterWidth) - this.$changes != this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height); + this.$changes |= this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height); if (this.session.getUseWrapMode() && this.adjustWrapLimit()) this.$loop.schedule(this.CHANGE_FULL); From 79c0f83e2c988f17c76ffc7605c0f19945f1db34 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 26 Aug 2013 21:52:38 +0400 Subject: [PATCH 3/9] add input event, make doing multiple changes in one turn much faster --- lib/ace/background_tokenizer.js | 6 ++++-- lib/ace/editor.js | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index 2fe9dceb..1eb28794 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -170,6 +170,10 @@ var BackgroundTokenizer = function(tokenizer, editor) { // pretty long delay to prevent the tokenizer from interfering with the user this.running = setTimeout(this.$worker, 700); }; + + this.scheduleStart = function() { + this.running = setTimeout(this.$worker, 700); + } this.$updateOnChange = function(delta) { var range = delta.range; @@ -191,8 +195,6 @@ var BackgroundTokenizer = function(tokenizer, editor) { this.currentLine = Math.min(startRow, this.currentLine, this.doc.getLength()); this.stop(); - // pretty long delay to prevent the tokenizer from interfering with the user - this.running = setTimeout(this.$worker, 700); }; /** diff --git a/lib/ace/editor.js b/lib/ace/editor.js index afd98874..e22875d5 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -90,6 +90,15 @@ var Editor = function(renderer, session) { this.commands.on("exec", this.$historyTracker); this.$initOperationListeners(); + + this._$emitInputEvent = lang.delayedCall(function() { + this._signal("input", {}); + this.session.bgTokenizer && this.session.bgTokenizer.scheduleStart(); + }.bind(this)); + + this.on("change", function(_, _self) { + _self._$emitInputEvent.schedule(31); + }); this.setSession(session || new EditSession("")); config.resetOptions(this); From 3eef5f0a637be4bbc6d9a042c3566c79d887bfdb Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 26 Aug 2013 21:55:14 +0400 Subject: [PATCH 4/9] allow clicking through invisible mac scrollbars --- lib/ace/css/editor.css | 14 +++++--------- lib/ace/mouse/mouse_handler.js | 2 ++ lib/ace/scrollbar.js | 4 ++++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/ace/css/editor.css b/lib/ace/css/editor.css index 0063ba2d..3413f99c 100644 --- a/lib/ace/css/editor.css +++ b/lib/ace/css/editor.css @@ -71,17 +71,19 @@ .ace_scrollbar { position: absolute; - overflow: hidden; + overflow-x: hidden; overflow-y: auto; right: 0; top: 0; bottom: 0; + z-index: 6; } .ace_scrollbar-inner { position: absolute; - width: 1px; + cursor: text; left: 0; + top: 0; } .ace_scrollbar-h { @@ -91,15 +93,9 @@ right: 0; left: 0; bottom: 0; + z-index: 6; } -.ace_scrollbar-inner { - position: absolute; - height: 1px; - left: 0; -} - - .ace_print-margin { position: absolute; height: 100%; diff --git a/lib/ace/mouse/mouse_handler.js b/lib/ace/mouse/mouse_handler.js index 76fedc3c..a0afd3b4 100644 --- a/lib/ace/mouse/mouse_handler.js +++ b/lib/ace/mouse/mouse_handler.js @@ -50,6 +50,8 @@ var MouseHandler = function(editor) { event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click")); event.addListener(mouseTarget, "mousemove", this.onMouseMove.bind(this, "mousemove")); event.addMultiMouseDownListener(mouseTarget, [300, 300, 250], this, "onMouseEvent"); + event.addMultiMouseDownListener(editor.renderer.scrollBarV.inner, [300, 300, 250], this, "onMouseEvent"); + event.addMultiMouseDownListener(editor.renderer.scrollBarH.inner, [300, 300, 250], this, "onMouseEvent"); event.addMouseWheelListener(editor.container, this.onMouseWheel.bind(this, "mousewheel")); var gutterEl = editor.renderer.$gutter; diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index 83e6c467..6d72979b 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -64,7 +64,10 @@ var ScrollBarV = function(parent, renderer) { // make element a little bit wider to retain scrollbar when page is zoomed renderer.$scrollbarWidth = this.width = dom.scrollbarWidth(parent.ownerDocument); + renderer.$scrollbarWidth = + this.width = dom.scrollbarWidth(parent.ownerDocument); this.fullWidth = this.width; + this.inner.style.width = this.element.style.width = (this.width || 15) + 5 + "px"; this.setVisible(false); this.element.style.overflowY = "scroll"; @@ -89,6 +92,7 @@ var ScrollBarH = function(parent, renderer) { // make element a little bit wider to retain scrollbar when page is zoomed this.height = renderer.$scrollbarWidth; this.fullHeight = this.height; + this.inner.style.height = this.element.style.height = (this.height || 15) + 5 + "px"; this.setVisible(false); this.element.style.overflowX = "scroll"; From 3a23eacda282ec2d08115c1987c0e62b110c48f0 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 26 Aug 2013 21:55:34 +0400 Subject: [PATCH 5/9] fix foldAll --- lib/ace/edit_session/folding.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index b36857c6..1735e6f9 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -272,7 +272,8 @@ function Folding() { var endColumn = fold.end.column; // --- Some checking --- - if (startRow == endRow && endColumn - startColumn < 2) + if (!(startRow < endRow || + startRow == endRow && startColumn < endColumn - 2)) throw "The range has to be at least 2 characters width"; var startFold = this.getFoldAt(startRow, startColumn, 1); @@ -627,19 +628,25 @@ function Folding() { depth = 100000; // JSON.stringify doesn't hanle Infinity var foldWidgets = this.foldWidgets; endRow = endRow || this.getLength(); - for (var row = startRow || 0; row < endRow; row++) { + startRow = startRow || 0; + for (var row = startRow; row < endRow; row++) { if (foldWidgets[row] == null) foldWidgets[row] = this.getFoldWidget(row); if (foldWidgets[row] != "start") continue; var range = this.getFoldWidgetRange(row); + var rangeEndRow = range.end.row; // sometimes range can be incompatible with existing fold // TODO change addFold to return null istead of throwing - if (range && range.end.row <= endRow) try { + if (range && range.isMultiLine() + && rangeEndRow <= endRow + && range.start.row >= startRow + ) try { var fold = this.addFold("...", range); fold.collapseChildren = depth; - row = range.end.row; + // addFold can change the range + row = rangeEndRow; } catch(e) {} } }; From 79fbec43b08fe933e093bb2cc760859b520b5a25 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 26 Aug 2013 21:57:22 +0400 Subject: [PATCH 6/9] misc fixes --- lib/ace/keyboard/hash_handler.js | 3 +++ lib/ace/keyboard/keybinding.js | 5 ++++- lib/ace/mode/logiql_highlight_rules.js | 2 +- lib/ace/theme/tomorrow_night_bright.css | 4 ++++ lib/ace/theme/tomorrow_night_eighties.css | 4 ++++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/ace/keyboard/hash_handler.js b/lib/ace/keyboard/hash_handler.js index 2ef110da..f56532ee 100644 --- a/lib/ace/keyboard/hash_handler.js +++ b/lib/ace/keyboard/hash_handler.js @@ -89,6 +89,9 @@ function HashHandler(config, platform) { this.addCommands = function(commands) { commands && Object.keys(commands).forEach(function(name) { var command = commands[name]; + if (!command) + return; + if (typeof command === "string") return this.bindKey(command, name); diff --git a/lib/ace/keyboard/keybinding.js b/lib/ace/keyboard/keybinding.js index 9c54a947..2a1a2230 100644 --- a/lib/ace/keyboard/keybinding.js +++ b/lib/ace/keyboard/keybinding.js @@ -108,8 +108,11 @@ var KeyBinding = function(editor) { success = commands.exec(toExecute.command, this.$editor, toExecute.args, e); } // do not stop input events to not break repeating - if (success && e && hashId != -1 && toExecute.passEvent != true) + if (success && e && hashId != -1 && + toExecute.passEvent != true && toExecute.command.passEvent != true + ) { event.stopEvent(e); + } if (success) break; } diff --git a/lib/ace/mode/logiql_highlight_rules.js b/lib/ace/mode/logiql_highlight_rules.js index 17ceab0c..f4e505d8 100644 --- a/lib/ace/mode/logiql_highlight_rules.js +++ b/lib/ace/mode/logiql_highlight_rules.js @@ -53,7 +53,7 @@ var LogiQLHighlightRules = function() { //A single line comment. }, { token: 'constant.numeric', - regex: '\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?', + regex: '\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?[fd]?', //An integer constant. //Or a Real number. }, diff --git a/lib/ace/theme/tomorrow_night_bright.css b/lib/ace/theme/tomorrow_night_bright.css index 065d9783..a4c182dc 100644 --- a/lib/ace/theme/tomorrow_night_bright.css +++ b/lib/ace/theme/tomorrow_night_bright.css @@ -48,6 +48,10 @@ background-color: #2A2A2A } +.ace-tomorrow-night-bright .ace_stack { + background-color: rgb(66, 90, 44); +} + .ace-tomorrow-night-bright .ace_marker-layer .ace_selected-word { border: 1px solid #424242 } diff --git a/lib/ace/theme/tomorrow_night_eighties.css b/lib/ace/theme/tomorrow_night_eighties.css index 613fd9a0..fc3e532f 100644 --- a/lib/ace/theme/tomorrow_night_eighties.css +++ b/lib/ace/theme/tomorrow_night_eighties.css @@ -44,6 +44,10 @@ border: 1px solid #6A6A6A } +.ace-tomorrow-night-bright .ace_stack { + background: rgb(66, 90, 44) +} + .ace-tomorrow-night-eighties .ace_marker-layer .ace_active-line { background: #393939 } From c62e0d30621a17185b05a8a3c64bba96968c6184 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 26 Aug 2013 21:58:31 +0400 Subject: [PATCH 7/9] add trimEmpty options to trimTrailingSpace, cleanup --- lib/ace/ext/whitespace.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/ace/ext/whitespace.js b/lib/ace/ext/whitespace.js index 234a9579..83486fb0 100644 --- a/lib/ace/ext/whitespace.js +++ b/lib/ace/ext/whitespace.js @@ -63,7 +63,7 @@ exports.$detectIndentation = function(lines, fallback) { // ignore lines ending with backslash while (line[line.length - 1] == "\\") line = lines[i++]; - }; + } function getScore(indent) { var score = 0; @@ -113,15 +113,17 @@ exports.detectIndentation = function(session) { return indent; }; -exports.trimTrailingSpace = function(session) { +exports.trimTrailingSpace = function(session, trimEmpty) { var doc = session.getDocument(); var lines = doc.getAllLines(); + + var min = trimEmpty ? -1 : 0; for (var i = 0, l=lines.length; i < l; i++) { var line = lines[i]; var index = line.search(/\s+$/); - if (index !== -1) + if (index > min) doc.removeInLine(i, index, line.length); } }; @@ -160,14 +162,14 @@ exports.convertIndentation = function(session, ch, len) { }; exports.$parseStringArg = function(text) { - var indent = {} + var indent = {}; if (/t/.test(text)) indent.ch = "\t"; else if (/s/.test(text)) indent.ch = " "; var m = text.match(/\d+/); if (m) - indent.length = parseInt(m[0]); + indent.length = parseInt(m[0], 10); return indent; }; @@ -179,7 +181,7 @@ exports.$parseArg = function(arg) { if (typeof arg.text == "string") return exports.$parseStringArg(arg.text); return arg; -} +}; exports.commands = [{ name: "detectIndentation", @@ -196,7 +198,7 @@ exports.commands = [{ name: "convertIndentation", exec: function(editor, arg) { var indent = exports.$parseArg(arg); - exports.convertIndentation(editor.session, arg.ch, arg.length); + exports.convertIndentation(editor.session, indent.ch, indent.length); } }, { name: "setIndentation", @@ -205,6 +207,6 @@ exports.commands = [{ indent.length && editor.session.setTabSize(indent.length); indent.ch && editor.session.setUseSoftTabs(indent.ch == " "); } -}] +}]; }); From 449bbfe406802d919be26400505c909cf837c56e Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 26 Aug 2013 21:59:17 +0400 Subject: [PATCH 8/9] improve batch highlighting --- lib/ace/mode/batchfile_highlight_rules.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ace/mode/batchfile_highlight_rules.js b/lib/ace/mode/batchfile_highlight_rules.js index 488edbb9..be0380d8 100644 --- a/lib/ace/mode/batchfile_highlight_rules.js +++ b/lib/ace/mode/batchfile_highlight_rules.js @@ -78,7 +78,8 @@ var BatchFileHighlightRules = function() { { token: 'keyword.operator.redirect.shell', regex: '&>|\\d*>&\\d*|\\d*(?:>>|>|<)|\\d*<&|\\d*<>' } ], variable: [ - { token: 'constant.numeric', regex: '%%\\w+'}, + { token: 'constant.numeric', regex: '%%\\w+|%[*\\d]|%\\w+%'}, + { token: 'constant.numeric', regex: '%~\\d+'}, { token: ['markup.list', 'constant.other', 'markup.list'], regex: '(%)(\\w+)(%?)' }]} From e2b2f08c248e14619ded8cc64069e3b9bd2c63d1 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 26 Aug 2013 22:41:29 +0400 Subject: [PATCH 9/9] fix tests --- lib/ace/edit_session/folding.js | 2 +- lib/ace/mode/_test/tokens_batchfile.json | 18 ++++-------------- lib/ace/mouse/mouse_handler.js | 6 ++++-- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index 1735e6f9..3aefea84 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -273,7 +273,7 @@ function Folding() { // --- Some checking --- if (!(startRow < endRow || - startRow == endRow && startColumn < endColumn - 2)) + startRow == endRow && startColumn <= endColumn - 2)) throw "The range has to be at least 2 characters width"; var startFold = this.getFoldAt(startRow, startColumn, 1); diff --git a/lib/ace/mode/_test/tokens_batchfile.json b/lib/ace/mode/_test/tokens_batchfile.json index d685d835..0f1f138c 100644 --- a/lib/ace/mode/_test/tokens_batchfile.json +++ b/lib/ace/mode/_test/tokens_batchfile.json @@ -14,16 +14,12 @@ ["text"," "], ["keyword.command.dosbatch","set"], ["text"," var1="], - ["markup.list","%"], - ["constant.other","cd"], - ["markup.list","%"] + ["constant.numeric","%cd%"] ],[ "start", ["keyword.command.dosbatch","echo"], ["text"," unhide everything in "], - ["markup.list","%"], - ["constant.other","var1"], - ["markup.list","%"], + ["constant.numeric","%var1%"], ["text","!"] ],[ "start" @@ -46,19 +42,13 @@ "start", ["keyword.command.dosbatch","echo"], ["text"," "], - ["markup.list","%"], - ["constant.other","var1"], - ["markup.list","%"], - ["constant.numeric","%%G"] + ["constant.numeric","%var1%%%G"] ],[ "start", ["keyword.command.dosbatch","attrib"], ["text"," -r -a -h -s "], ["punctuation.definition.string.begin.shell","\""], - ["markup.list","%"], - ["constant.other","var1"], - ["markup.list","%"], - ["constant.numeric","%%G"], + ["constant.numeric","%var1%%%G"], ["punctuation.definition.string.end.shell","\""], ["text"," /D /S"] ],[ diff --git a/lib/ace/mouse/mouse_handler.js b/lib/ace/mouse/mouse_handler.js index a0afd3b4..a30fe76b 100644 --- a/lib/ace/mouse/mouse_handler.js +++ b/lib/ace/mouse/mouse_handler.js @@ -50,8 +50,10 @@ var MouseHandler = function(editor) { event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click")); event.addListener(mouseTarget, "mousemove", this.onMouseMove.bind(this, "mousemove")); event.addMultiMouseDownListener(mouseTarget, [300, 300, 250], this, "onMouseEvent"); - event.addMultiMouseDownListener(editor.renderer.scrollBarV.inner, [300, 300, 250], this, "onMouseEvent"); - event.addMultiMouseDownListener(editor.renderer.scrollBarH.inner, [300, 300, 250], this, "onMouseEvent"); + if (editor.renderer.scrollBarV) { + event.addMultiMouseDownListener(editor.renderer.scrollBarV.inner, [300, 300, 250], this, "onMouseEvent"); + event.addMultiMouseDownListener(editor.renderer.scrollBarH.inner, [300, 300, 250], this, "onMouseEvent"); + } event.addMouseWheelListener(editor.container, this.onMouseWheel.bind(this, "mousewheel")); var gutterEl = editor.renderer.$gutter;