From cde392b565fb50980f2f585b8db78ab7c4b7b515 Mon Sep 17 00:00:00 2001 From: Adam Jimenez Date: Sun, 4 Mar 2018 19:50:04 +0000 Subject: [PATCH 0001/1293] unused var --- lib/ace/ext/beautify.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ace/ext/beautify.js b/lib/ace/ext/beautify.js index ba2b511f55e..83da2a59926 100644 --- a/lib/ace/ext/beautify.js +++ b/lib/ace/ext/beautify.js @@ -63,7 +63,6 @@ exports.beautify = function(session) { var indent = 0; var unindent = 0; var roundDepth = 0; - var onCaseLine = false; var row; var curRow = 0; var rowsToAdd = 0; From d4d6ef3b28a1c88bac514a83ddddc86b671bd1e9 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 26 Apr 2018 02:02:30 +0400 Subject: [PATCH 0002/1293] Squashed commit of the following: commit 0caba832dec65f7917b4d7f512a54849656173ec Author: Alex Shensis Date: Wed Oct 25 15:51:50 2017 +0300 fix test error commit 968d7e9397728a21e08d559bcc29b5e7bf0669b4 Author: Alex Shensis Date: Sun Oct 22 20:54:19 2017 +0300 fix syntax checks commit 942b4ebce6b3b114661c13552f4c949b8a303e68 Merge: 40ccc5c6f 485cd3568 Author: Alex Shensis Date: Sun Oct 22 20:11:14 2017 +0300 merge with upstream changes commit 40ccc5c6f00602eb89993f458c9e5403d6e114f0 Author: Alex Shensis Date: Fri Oct 20 17:28:21 2017 +0300 attend reviewer comments 2 commit 268da25ff3b601c2362163661f8b14fa6bc02ebe Author: Alex Shensis Date: Thu Sep 7 21:10:29 2017 +0300 right-to-left text direction support --- lib/ace/bidihandler.js | 210 ++++++++++++++++++++------- lib/ace/commands/default_commands.js | 16 ++ lib/ace/edit_session.js | 4 - lib/ace/editor.js | 5 +- lib/ace/lib/bidiutil.js | 9 +- lib/ace/virtual_renderer.js | 1 + 6 files changed, 186 insertions(+), 59 deletions(-) diff --git a/lib/ace/bidihandler.js b/lib/ace/bidihandler.js index 374e0bfe884..0524a899d67 100644 --- a/lib/ace/bidihandler.js +++ b/lib/ace/bidihandler.js @@ -33,8 +33,7 @@ define(function(require, exports, module) { var bidiUtil = require("./lib/bidiutil"); var lang = require("./lib/lang"); -var useragent = require("./lib/useragent"); -var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; +var config = require("./config"); /** * This object is used to ensure Bi-Directional support (for languages with text flowing from right to left, like Arabic or Hebrew) @@ -48,8 +47,8 @@ var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; * * @constructor **/ -var BidiHandler = function(session) { - this.session = session; +var BidiHandler = function(editor) { + this.session = editor.session; this.bidiMap = {}; /* current screen row */ this.currentRow = null; @@ -61,9 +60,39 @@ var BidiHandler = function(session) { this.isRtlDir = false; this.line = ""; this.wrapIndent = 0; - this.isLastRow = false; this.EOF = "\xB6"; - this.seenBidi = false; + this.RLE = '\u202B'; + this.contentWidth = 0; + this.fontMetrics = null; + this.rtlLineOffset = 0; + this.wrapOffset = 0; + this.isRtlSupported = /text$/i.test(this.session.getMode().$id); + this.isMoveLeftOperation = false; + + if (this.isRtlSupported) { + editor.on("changeSelection", this.onChangeSelection); + editor.commands.on("exec", this.onCommandEmitted); + } + + editor.session.on("change", this.onChange); + + editor.session.on("changeWrapMode", function(e, session) { + session.$bidiHandler.currentRow = null; + }); + + editor.on("changeMode", function(e, editor) { + var isRtlSupported = /text$/i.test(editor.session.getMode().$id); + if (isRtlSupported ^ editor.session.$bidiHandler.isRtlSupported) { + editor.session.$bidiHandler.isRtlSupported = isRtlSupported; + if (isRtlSupported) { + editor.on("changeSelection", editor.session.$bidiHandler.onChangeSelection); + editor.commands.on("exec", editor.session.$bidiHandler.onCommandEmitted); + } else { + editor.off("changeSelection", editor.session.$bidiHandler.onChangeSelection); + editor.commands.off("exec", editor.session.$bidiHandler.onCommandEmitted); + } + } + }); }; (function() { @@ -76,8 +105,6 @@ var BidiHandler = function(session) { * @param {Number} the wrapped screen line index [ optional] **/ this.isBidiRow = function(screenRow, docRow, splitIndex) { - if (!this.seenBidi) - return false; if (screenRow !== this.currentRow) { this.currentRow = screenRow; this.updateRowLine(docRow, splitIndex); @@ -86,18 +113,6 @@ var BidiHandler = function(session) { return this.bidiMap.bidiLevels; }; - this.onChange = function(delta) { - if (!this.seenBidi) { - if (delta.action == "insert" && bidiRE.test(delta.lines.join("\n"))) { - this.seenBidi = true; - this.currentRow = null; - } - } - else { - this.currentRow = null; - } - }; - this.getDocumentRow = function() { var docRow = 0; var rowCache = this.session.$screenRowCache; @@ -123,6 +138,8 @@ var BidiHandler = function(session) { prevIndex = currentIndex; splitIndex++; } + } else { + splitIndex = this.currentRow; } return splitIndex; @@ -132,9 +149,12 @@ var BidiHandler = function(session) { if (docRow === undefined) docRow = this.getDocumentRow(); + var isLastRow = (docRow === this.session.getLength() - 1), + endOfLine = isLastRow ? this.EOF : this.EOL; + this.wrapIndent = 0; - this.isLastRow = (docRow === this.session.getLength() - 1); this.line = this.session.getLine(docRow); + this.isRtlDir = this.isRtlSupported && (this.line.charAt(0) === this.RLE); if (this.session.$useWrapMode) { var splits = this.session.$wrapData[docRow]; if (splits) { @@ -143,13 +163,18 @@ var BidiHandler = function(session) { if(splitIndex > 0 && splits.length) { this.wrapIndent = splits.indent; + this.wrapOffset = this.wrapIndent * this.charWidths[bidiUtil.L]; this.line = (splitIndex < splits.length) ? - this.line.substring(splits[splitIndex - 1], splits[splits.length - 1]) : + this.line.substring(splits[splitIndex - 1], splits[splitIndex]) : this.line.substring(splits[splits.length - 1]); } else { this.line = this.line.substring(0, splits[splitIndex]); } } + if (splitIndex == splits.length) + this.line += (this.showInvisibles) ? endOfLine : bidiUtil.DOT; + } else { + this.line += this.showInvisibles ? endOfLine : bidiUtil.DOT; } /* replace tab and wide characters by commensurate spaces */ @@ -162,24 +187,22 @@ var BidiHandler = function(session) { } return ch; }); + + if(this.isRtlDir) { + this.fontMetrics.$main.innerHTML = (this.line.charAt(this.line.length - 1) == bidiUtil.DOT) ? this.line.substr(0, this.line.length - 1) : this.line; + this.rtlLineOffset = this.contentWidth - this.fontMetrics.$main.getBoundingClientRect().width; + } }; this.updateBidiMap = function() { - var textCharTypes = [], endOfLine = this.isLastRow ? this.EOF : this.EOL; - var line = this.line + (this.showInvisibles ? endOfLine : bidiUtil.DOT); - if (bidiUtil.hasBidiCharacters(line, textCharTypes)) { - this.bidiMap = bidiUtil.doBidiReorder(line, textCharTypes, this.isRtlDir); + var textCharTypes = []; + if (bidiUtil.hasBidiCharacters(this.line, textCharTypes) || this.isRtlDir) { + this.bidiMap = bidiUtil.doBidiReorder(this.line, textCharTypes, this.isRtlDir); } else { this.bidiMap = {}; } }; - /** - * Resets stored info related to current screen row - **/ - this.markAsDirty = function() { - this.currentRow = null; - }; /** * Updates array of character widths @@ -187,26 +210,21 @@ var BidiHandler = function(session) { * **/ this.updateCharacterWidths = function(fontMetrics) { - if (!this.seenBidi) - return; if (this.characterWidth === fontMetrics.$characterSize.width) return; + this.fontMetrics = fontMetrics; var characterWidth = this.characterWidth = fontMetrics.$characterSize.width; var bidiCharWidth = fontMetrics.$measureCharWidth("\u05d4"); this.charWidths[bidiUtil.L] = this.charWidths[bidiUtil.EN] = this.charWidths[bidiUtil.ON_R] = characterWidth; this.charWidths[bidiUtil.R] = this.charWidths[bidiUtil.AN] = bidiCharWidth; - this.charWidths[bidiUtil.R_H] = useragent.isChrome ? bidiCharWidth : bidiCharWidth * 0.45; - this.charWidths[bidiUtil.B] = 0; + this.charWidths[bidiUtil.R_H] = bidiCharWidth * 0.45; + this.charWidths[bidiUtil.B] = this.charWidths[bidiUtil.RLE] = 0; this.currentRow = null; }; - this.getShowInvisibles = function() { - return this.showInvisibles; - }; - this.setShowInvisibles = function(showInvisibles) { this.showInvisibles = showInvisibles; this.currentRow = null; @@ -216,8 +234,78 @@ var BidiHandler = function(session) { this.EOL = eolChar; }; - this.setTextDir = function(isRtlDir) { - this.isRtlDir = isRtlDir; + this.hasRtlSupport = function() { + return this.isRtlSupported; + }; + + this.setContentWidth = function(width) { + this.contentWidth = width; + }; + + this.isRtlLine = function(row) { + if (row != undefined) + return (this.session.getLine(row).charAt(0) == this.RLE); + else + return this.isRtlDir; + }; + + this.toggleRtlDirection = function(editor, isRtlDir) { + var cursor = editor.getCursorPosition(); + for (var row = editor.selection.getSelectionAnchor().row; row <= cursor.row; row++) { + if (!isRtlDir && editor.session.getLine(row).charAt(0) === editor.session.$bidiHandler.RLE) + editor.session.doc.removeInLine(row, 0, 1); + else if (isRtlDir && editor.session.getLine(row).charAt(0) !== editor.session.$bidiHandler.RLE) + editor.session.doc.insert({column: 0, row: row}, editor.session.$bidiHandler.RLE); + } + }; + + /** + * Whenever the selection is changed, prevent cursor (lead) to be positioned at + * position 0 of right-to-left line in order to maintain the RLE marker at this position. + * When cursor reaches position 0, either advance it to position 1 of current line (default) + * or to last position of previous line (if it comes from position 1 as the result of commands + * mentioned in 'onCommandEmitted' event handler). + * This serves few purposes: + * - ensures cursor visual movement as if RLE mark doesn't exist. + * - prevents character insertion before RLE mark. + * - prevents RLE mark removal when 'delete' is pressed when cursot stays at position 0. + * - ensures RLE mark removal on line merge, when 'delete' is pressed and cursor stays + * at last position of previous line and when 'backspace' is pressed and cursor stays at + * first position of current line. This is achived by hacking range boundaries on 'remove' operation. + **/ + this.onChangeSelection = function(e, editor) { + var lead = editor.getSelection().lead; + if (editor.session.$bidiHandler.isRtlLine(lead.row)) { + if (lead.column === 0) { + if (editor.session.$bidiHandler.isMoveLeftOperation && lead.row > 0) { + editor.getSelection().moveCursorTo(lead.row - 1, editor.session.getLine(lead.row - 1).length); + } else { + if (editor.getSelection().isEmpty()) + lead.column += 1; + else + lead.setPosition(lead.row, lead.column + 1); + } + } + } + }; + + this.onCommandEmitted = function(commadEvent) { + commadEvent.editor.session.$bidiHandler.isMoveLeftOperation = /gotoleft|selectleft|backspace|removewordleft/.test(commadEvent.command.name); + }; + + /** + * Whenever the document is changed make sure that line break operatin + * on right-to-left line (like pressing Enter or pasting multi-line text) + * produces new right-to-left lines + **/ + this.onChange = function(delta, session) { + session.$bidiHandler.currentRow = null; + if (session.$bidiHandler.isRtlLine(delta.start.row) && delta.action === 'insert' && delta.lines.length > 1) { + for (var row = delta.start.row; row < delta.end.row; row++) { + if (session.getLine(row + 1).charAt(0) !== session.$bidiHandler.RLE) + session.getDocument().$lines[row + 1] = session.$bidiHandler.RLE + session.getLine(row + 1); + } + } }; /** @@ -228,21 +316,26 @@ var BidiHandler = function(session) { **/ this.getPosLeft = function(col) { col -= this.wrapIndent; - var visualIdx = bidiUtil.getVisualFromLogicalIdx(col > 0 ? col - 1 : 0, this.bidiMap), + var leftBoundary = (this.line.charAt(0) === this.RLE) ? 1 : 0; + var logicalIdx = (col > leftBoundary) ? (this.session.getOverwrite() ? col : col - 1) : leftBoundary; + var visualIdx = bidiUtil.getVisualFromLogicalIdx(logicalIdx, this.bidiMap), levels = this.bidiMap.bidiLevels, left = 0; - if (col === 0 && levels[visualIdx] % 2 !== 0) - visualIdx++; - + if (!this.session.getOverwrite() && col <= leftBoundary && levels[visualIdx] % 2 !== 0) + visualIdx++; + for (var i = 0; i < visualIdx; i++) { left += this.charWidths[levels[i]]; } - if (col !== 0 && levels[visualIdx] % 2 === 0) + if (!this.session.getOverwrite() && (col > leftBoundary) && (levels[visualIdx] % 2 === 0)) left += this.charWidths[levels[visualIdx]]; if (this.wrapIndent) - left += this.wrapIndent * this.charWidths[bidiUtil.L]; + left += this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset; + + if (this.isRtlDir) + left += this.rtlLineOffset; return left; }; @@ -255,9 +348,12 @@ var BidiHandler = function(session) { * @return {Array of Objects} Each object contains 'left' and 'width' values defining selection rectangle. **/ this.getSelections = function(startCol, endCol) { - var map = this.bidiMap, levels = map.bidiLevels, level, offset = this.wrapIndent * this.charWidths[bidiUtil.L], selections = [], + var map = this.bidiMap, levels = map.bidiLevels, level, selections = [], offset = 0, selColMin = Math.min(startCol, endCol) - this.wrapIndent, selColMax = Math.max(startCol, endCol) - this.wrapIndent, isSelected = false, isSelectedPrev = false, selectionStart = 0; + + if (this.wrapIndent) + offset += this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset; for (var logIdx, visIdx = 0; visIdx < levels.length; visIdx++) { logIdx = map.logicalFromVisual[visIdx]; @@ -276,6 +372,11 @@ var BidiHandler = function(session) { selections.push({left: selectionStart, width: offset - selectionStart}); } + if(this.isRtlDir) { + for (var i = 0; i < selections.length; i++) { + selections[i].left += this.rtlLineOffset; + } + } return selections; }; @@ -286,13 +387,15 @@ var BidiHandler = function(session) { * @return {Number} screen column number corresponding to given pixel offset **/ this.offsetToCol = function(posX) { + if(this.isRtlDir) + posX -= this.rtlLineOffset; + var logicalIdx = 0, posX = Math.max(posX, 0), offset = 0, visualIdx = 0, levels = this.bidiMap.bidiLevels, charWidth = this.charWidths[levels[visualIdx]]; - if (this.wrapIndent) { - posX -= this.wrapIndent * this.charWidths[bidiUtil.L]; - } + if (this.wrapIndent) + posX -= this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset; while(posX > offset + charWidth/2) { offset += charWidth; @@ -329,6 +432,9 @@ var BidiHandler = function(session) { logicalIdx = this.bidiMap.logicalFromVisual[visualIdx]; } + if (logicalIdx === 0 && this.isRtlDir) + logicalIdx++; + return (logicalIdx + this.wrapIndent); }; diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 527bebe874a..b813c9c1c0f 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -712,6 +712,22 @@ exports.commands = [{ }, multiSelectAction: "forEach", readOnly: true +}, { + name: "leftToRight", + bindKey: bindKey("Ctrl-Alt-Shift-L", "Command-Alt-Shift-L"), + exec: function(editor) { + if (editor.session.$bidiHandler.hasRtlSupport()) + editor.session.$bidiHandler.toggleRtlDirection(editor, false); + }, + readOnly: true +}, { + name: "rightToLeft", + bindKey: bindKey("Ctrl-Alt-Shift-R", "Command-Alt-Shift-R"), + exec: function(editor) { + if (editor.session.$bidiHandler.hasRtlSupport()) + editor.session.$bidiHandler.toggleRtlDirection(editor, true); + }, + readOnly: true }, { name: "invertSelection", bindKey: bindKey(null, null), diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 3d20309e425..12276abadc8 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -33,7 +33,6 @@ define(function(require, exports, module) { var oop = require("./lib/oop"); var lang = require("./lib/lang"); -var BidiHandler = require("./bidihandler").BidiHandler; var config = require("./config"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Selection = require("./selection").Selection; @@ -159,7 +158,6 @@ var EditSession = function(text, mode) { if (typeof text != "object" || !text.getLine) text = new Document(text); - this.$bidiHandler = new BidiHandler(this); this.setDocument(text); this.selection = new Selection(this); @@ -255,7 +253,6 @@ EditSession.$uid = 0; this.onChange = function(delta) { this.$modified = true; - this.$bidiHandler.onChange(delta); this.$resetRowCache(delta.start.row); var removedFolds = this.$updateInternalDataOnChange(delta); @@ -1536,7 +1533,6 @@ EditSession.$uid = 0; if (this.$wrapLimitRange.min !== min || this.$wrapLimitRange.max !== max) { this.$wrapLimitRange = { min: min, max: max }; this.$modified = true; - this.$bidiHandler.markAsDirty(); // This will force a recalculation of the wrap limit if (this.$useWrapMode) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index e7fec475eb8..992f0285a94 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -49,6 +49,7 @@ var CommandManager = require("./commands/command_manager").CommandManager; var defaultCommands = require("./commands/default_commands").commands; var config = require("./config"); var TokenIterator = require("./token_iterator").TokenIterator; +var BidiHandler = require("./bidihandler").BidiHandler; var clipboard = require("./clipboard"); @@ -321,6 +322,8 @@ Editor.$uid = 0; this.session = session; if (session) { + session.$bidiHandler = new BidiHandler(this); + this.$onDocumentChange = this.onDocumentChange.bind(this); session.on("change", this.$onDocumentChange); this.renderer.setSession(session); @@ -1005,7 +1008,7 @@ Editor.$uid = 0; } } - + if (text == "\t") text = this.session.getTabString(); diff --git a/lib/ace/lib/bidiutil.js b/lib/ace/lib/bidiutil.js index 522a8df5a9f..ec6fbcd192a 100644 --- a/lib/ace/lib/bidiutil.js +++ b/lib/ace/lib/bidiutil.js @@ -320,6 +320,8 @@ exports.AN = 4; exports.R_H = 5; /* invisible EOL (6 - even), zero width */ exports.B = 6; +/* invisible RLE (7 - odd), zero width */ +exports.RLE = 7; exports.DOT = "\xB7"; @@ -363,6 +365,9 @@ exports.doBidiReorder = function(text, textCharTypes, isRtl) { if (chars[chars.length - 1] === exports.DOT) levels[chars.length - 1] = exports.B; + if (chars[0] === '\u202B') + levels[0] = exports.RLE; + for (var i = 0; i < logicalFromVisual.length; i++) { bidiLevels[i] = levels[logicalFromVisual[i]]; } @@ -375,13 +380,13 @@ exports.doBidiReorder = function(text, textCharTypes, isRtl) { * @param {String} text string to be reordered * @param {Array} unicode character types (to be filled by this method) * - * @return {Boolean} 'true' if text contains Bidi characters, otherwise 'false' + * @return {Boolean} 'true' if text contains Bidi characters, otherwise 'false' **/ exports.hasBidiCharacters = function(text, textCharTypes){ var ret = false; for (var i = 0; i < text.length; i++){ textCharTypes[i] = _getCharacterType(text.charAt(i)); - if (!ret && (textCharTypes[i] == R || textCharTypes[i] == AL)) + if (!ret && (textCharTypes[i] == R || textCharTypes[i] == AL || textCharTypes[i] == AN)) ret = true; } return ret; diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 973a9bc93e3..1cd8bec9491 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -1040,6 +1040,7 @@ var VirtualRenderer = function(container, theme) { height : this.$size.scrollerHeight }; + this.session.$bidiHandler.setContentWidth(longestLine); // For debugging. // console.log(JSON.stringify(this.layerConfig)); From bbc7323a74d3e5da15cf1c7b2023479496a65155 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 29 Apr 2018 00:53:23 +0400 Subject: [PATCH 0003/1293] move rtl related code into extension --- demo/kitchen-sink/demo.js | 6 ++ lib/ace/bidihandler.js | 125 ++++++++------------------- lib/ace/commands/default_commands.js | 16 ---- lib/ace/edit_session.js | 4 + lib/ace/editor.js | 5 +- lib/ace/ext/rtl.js | 124 ++++++++++++++++++++++++++ lib/ace/virtual_renderer.js | 3 +- 7 files changed, 171 insertions(+), 112 deletions(-) create mode 100644 lib/ace/ext/rtl.js diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 9040f642151..829d0941739 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -34,6 +34,8 @@ define(function(require, exports, module) { require("ace/lib/fixoldbrowsers"); +require("ace/ext/rtl"); + require("ace/multi_select"); require("ace/ext/spellcheck"); require("./inline_editor"); @@ -368,6 +370,10 @@ optionsPanel.add({ } }, More: { + "Rtl Text": { + path: "rtlText", + position: 900 + }, "Show token info": { path: "showTokenInfo", position: 1000 diff --git a/lib/ace/bidihandler.js b/lib/ace/bidihandler.js index 0524a899d67..b955f5faebf 100644 --- a/lib/ace/bidihandler.js +++ b/lib/ace/bidihandler.js @@ -33,7 +33,7 @@ define(function(require, exports, module) { var bidiUtil = require("./lib/bidiutil"); var lang = require("./lib/lang"); -var config = require("./config"); +var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\u202B]/; /** * This object is used to ensure Bi-Directional support (for languages with text flowing from right to left, like Arabic or Hebrew) @@ -47,8 +47,8 @@ var config = require("./config"); * * @constructor **/ -var BidiHandler = function(editor) { - this.session = editor.session; +var BidiHandler = function(session) { + this.session = session; this.bidiMap = {}; /* current screen row */ this.currentRow = null; @@ -61,38 +61,13 @@ var BidiHandler = function(editor) { this.line = ""; this.wrapIndent = 0; this.EOF = "\xB6"; - this.RLE = '\u202B'; + this.RLE = "\u202B"; this.contentWidth = 0; this.fontMetrics = null; this.rtlLineOffset = 0; this.wrapOffset = 0; - this.isRtlSupported = /text$/i.test(this.session.getMode().$id); - this.isMoveLeftOperation = false; - - if (this.isRtlSupported) { - editor.on("changeSelection", this.onChangeSelection); - editor.commands.on("exec", this.onCommandEmitted); - } - - editor.session.on("change", this.onChange); - - editor.session.on("changeWrapMode", function(e, session) { - session.$bidiHandler.currentRow = null; - }); - - editor.on("changeMode", function(e, editor) { - var isRtlSupported = /text$/i.test(editor.session.getMode().$id); - if (isRtlSupported ^ editor.session.$bidiHandler.isRtlSupported) { - editor.session.$bidiHandler.isRtlSupported = isRtlSupported; - if (isRtlSupported) { - editor.on("changeSelection", editor.session.$bidiHandler.onChangeSelection); - editor.commands.on("exec", editor.session.$bidiHandler.onCommandEmitted); - } else { - editor.off("changeSelection", editor.session.$bidiHandler.onChangeSelection); - editor.commands.off("exec", editor.session.$bidiHandler.onCommandEmitted); - } - } - }); + this.isMoveLeftOperation = false; + this.seenBidi = null; }; (function() { @@ -105,6 +80,8 @@ var BidiHandler = function(editor) { * @param {Number} the wrapped screen line index [ optional] **/ this.isBidiRow = function(screenRow, docRow, splitIndex) { + if (this.seenBidi == false) + return false; if (screenRow !== this.currentRow) { this.currentRow = screenRow; this.updateRowLine(docRow, splitIndex); @@ -113,6 +90,18 @@ var BidiHandler = function(editor) { return this.bidiMap.bidiLevels; }; + this.onChange = function(delta) { + if (!this.seenBidi) { + if (delta.action == "insert" && bidiRE.test(delta.lines.join("\n"))) { + this.seenBidi = true; + this.currentRow = null; + } + } + else { + this.currentRow = null; + } + }; + this.getDocumentRow = function() { var docRow = 0; var rowCache = this.session.$screenRowCache; @@ -139,7 +128,7 @@ var BidiHandler = function(editor) { splitIndex++; } } else { - splitIndex = this.currentRow; + splitIndex = this.currentRow; } return splitIndex; @@ -154,7 +143,7 @@ var BidiHandler = function(editor) { this.wrapIndent = 0; this.line = this.session.getLine(docRow); - this.isRtlDir = this.isRtlSupported && (this.line.charAt(0) === this.RLE); + this.isRtlDir = this.line.charAt(0) === this.RLE; if (this.session.$useWrapMode) { var splits = this.session.$wrapData[docRow]; if (splits) { @@ -188,7 +177,7 @@ var BidiHandler = function(editor) { return ch; }); - if(this.isRtlDir) { + if (this.isRtlDir) { this.fontMetrics.$main.innerHTML = (this.line.charAt(this.line.length - 1) == bidiUtil.DOT) ? this.line.substr(0, this.line.length - 1) : this.line; this.rtlLineOffset = this.contentWidth - this.fontMetrics.$main.getBoundingClientRect().width; } @@ -203,6 +192,12 @@ var BidiHandler = function(editor) { } }; + /** + * Resets stored info related to current screen row + **/ + this.markAsDirty = function() { + this.currentRow = null; + }; /** * Updates array of character widths @@ -234,10 +229,6 @@ var BidiHandler = function(editor) { this.EOL = eolChar; }; - this.hasRtlSupport = function() { - return this.isRtlSupported; - }; - this.setContentWidth = function(width) { this.contentWidth = width; }; @@ -249,8 +240,8 @@ var BidiHandler = function(editor) { return this.isRtlDir; }; - this.toggleRtlDirection = function(editor, isRtlDir) { - var cursor = editor.getCursorPosition(); + this.setRtlDirection = function(editor, isRtlDir) { + var cursor = editor.getCursorPosition(); for (var row = editor.selection.getSelectionAnchor().row; row <= cursor.row; row++) { if (!isRtlDir && editor.session.getLine(row).charAt(0) === editor.session.$bidiHandler.RLE) editor.session.doc.removeInLine(row, 0, 1); @@ -259,54 +250,6 @@ var BidiHandler = function(editor) { } }; - /** - * Whenever the selection is changed, prevent cursor (lead) to be positioned at - * position 0 of right-to-left line in order to maintain the RLE marker at this position. - * When cursor reaches position 0, either advance it to position 1 of current line (default) - * or to last position of previous line (if it comes from position 1 as the result of commands - * mentioned in 'onCommandEmitted' event handler). - * This serves few purposes: - * - ensures cursor visual movement as if RLE mark doesn't exist. - * - prevents character insertion before RLE mark. - * - prevents RLE mark removal when 'delete' is pressed when cursot stays at position 0. - * - ensures RLE mark removal on line merge, when 'delete' is pressed and cursor stays - * at last position of previous line and when 'backspace' is pressed and cursor stays at - * first position of current line. This is achived by hacking range boundaries on 'remove' operation. - **/ - this.onChangeSelection = function(e, editor) { - var lead = editor.getSelection().lead; - if (editor.session.$bidiHandler.isRtlLine(lead.row)) { - if (lead.column === 0) { - if (editor.session.$bidiHandler.isMoveLeftOperation && lead.row > 0) { - editor.getSelection().moveCursorTo(lead.row - 1, editor.session.getLine(lead.row - 1).length); - } else { - if (editor.getSelection().isEmpty()) - lead.column += 1; - else - lead.setPosition(lead.row, lead.column + 1); - } - } - } - }; - - this.onCommandEmitted = function(commadEvent) { - commadEvent.editor.session.$bidiHandler.isMoveLeftOperation = /gotoleft|selectleft|backspace|removewordleft/.test(commadEvent.command.name); - }; - - /** - * Whenever the document is changed make sure that line break operatin - * on right-to-left line (like pressing Enter or pasting multi-line text) - * produces new right-to-left lines - **/ - this.onChange = function(delta, session) { - session.$bidiHandler.currentRow = null; - if (session.$bidiHandler.isRtlLine(delta.start.row) && delta.action === 'insert' && delta.lines.length > 1) { - for (var row = delta.start.row; row < delta.end.row; row++) { - if (session.getLine(row + 1).charAt(0) !== session.$bidiHandler.RLE) - session.getDocument().$lines[row + 1] = session.$bidiHandler.RLE + session.getLine(row + 1); - } - } - }; /** * Returns offset of character at position defined by column. @@ -322,8 +265,8 @@ var BidiHandler = function(editor) { levels = this.bidiMap.bidiLevels, left = 0; if (!this.session.getOverwrite() && col <= leftBoundary && levels[visualIdx] % 2 !== 0) - visualIdx++; - + visualIdx++; + for (var i = 0; i < visualIdx; i++) { left += this.charWidths[levels[i]]; } @@ -351,7 +294,7 @@ var BidiHandler = function(editor) { var map = this.bidiMap, levels = map.bidiLevels, level, selections = [], offset = 0, selColMin = Math.min(startCol, endCol) - this.wrapIndent, selColMax = Math.max(startCol, endCol) - this.wrapIndent, isSelected = false, isSelectedPrev = false, selectionStart = 0; - + if (this.wrapIndent) offset += this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset; diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index b813c9c1c0f..527bebe874a 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -712,22 +712,6 @@ exports.commands = [{ }, multiSelectAction: "forEach", readOnly: true -}, { - name: "leftToRight", - bindKey: bindKey("Ctrl-Alt-Shift-L", "Command-Alt-Shift-L"), - exec: function(editor) { - if (editor.session.$bidiHandler.hasRtlSupport()) - editor.session.$bidiHandler.toggleRtlDirection(editor, false); - }, - readOnly: true -}, { - name: "rightToLeft", - bindKey: bindKey("Ctrl-Alt-Shift-R", "Command-Alt-Shift-R"), - exec: function(editor) { - if (editor.session.$bidiHandler.hasRtlSupport()) - editor.session.$bidiHandler.toggleRtlDirection(editor, true); - }, - readOnly: true }, { name: "invertSelection", bindKey: bindKey(null, null), diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 12276abadc8..3d20309e425 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -33,6 +33,7 @@ define(function(require, exports, module) { var oop = require("./lib/oop"); var lang = require("./lib/lang"); +var BidiHandler = require("./bidihandler").BidiHandler; var config = require("./config"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Selection = require("./selection").Selection; @@ -158,6 +159,7 @@ var EditSession = function(text, mode) { if (typeof text != "object" || !text.getLine) text = new Document(text); + this.$bidiHandler = new BidiHandler(this); this.setDocument(text); this.selection = new Selection(this); @@ -253,6 +255,7 @@ EditSession.$uid = 0; this.onChange = function(delta) { this.$modified = true; + this.$bidiHandler.onChange(delta); this.$resetRowCache(delta.start.row); var removedFolds = this.$updateInternalDataOnChange(delta); @@ -1533,6 +1536,7 @@ EditSession.$uid = 0; if (this.$wrapLimitRange.min !== min || this.$wrapLimitRange.max !== max) { this.$wrapLimitRange = { min: min, max: max }; this.$modified = true; + this.$bidiHandler.markAsDirty(); // This will force a recalculation of the wrap limit if (this.$useWrapMode) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 992f0285a94..e7fec475eb8 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -49,7 +49,6 @@ var CommandManager = require("./commands/command_manager").CommandManager; var defaultCommands = require("./commands/default_commands").commands; var config = require("./config"); var TokenIterator = require("./token_iterator").TokenIterator; -var BidiHandler = require("./bidihandler").BidiHandler; var clipboard = require("./clipboard"); @@ -322,8 +321,6 @@ Editor.$uid = 0; this.session = session; if (session) { - session.$bidiHandler = new BidiHandler(this); - this.$onDocumentChange = this.onDocumentChange.bind(this); session.on("change", this.$onDocumentChange); this.renderer.setSession(session); @@ -1008,7 +1005,7 @@ Editor.$uid = 0; } } - + if (text == "\t") text = this.session.getTabString(); diff --git a/lib/ace/ext/rtl.js b/lib/ace/ext/rtl.js new file mode 100644 index 00000000000..0db8c99b6f0 --- /dev/null +++ b/lib/ace/ext/rtl.js @@ -0,0 +1,124 @@ +define(function(require, exports, module) { +"use strict"; +/** simple statusbar **/ +var dom = require("ace/lib/dom"); +var lang = require("ace/lib/lang"); + +var commands = [{ + name: "leftToRight", + bindKey: { win: "Ctrl-Alt-Shift-L", mac: "Command-Alt-Shift-L" }, + exec: function(editor) { + editor.session.$bidiHandler.setRtlDirection(editor, false); + }, + readOnly: true +}, { + name: "rightToLeft", + bindKey: { win: "Ctrl-Alt-Shift-R", mac: "Command-Alt-Shift-R" }, + exec: function(editor) { + editor.session.$bidiHandler.setRtlDirection(editor, true); + }, + readOnly: true +}]; + +var Editor = require("../editor").Editor; +require("../config").defineOptions(Editor.prototype, "editor", { + rtlText: { + set: function(val) { + if (val) { + this.on("session", onChange); + this.on("changeSelection", onChangeSelection); + this.renderer.on("afterRender", updateLineDirection); + this.commands.on("exec", onCommandEmitted); + this.commands.addCommands(commands); + } else { + this.off("session", onChange); + this.off("changeSelection", onChangeSelection); + this.renderer.off("afterRender", updateLineDirection); + this.commands.off("exec", onCommandEmitted); + this.commands.removeCommands(commands); + clearTextLayer(this.renderer); + } + this.renderer.updateFull(); + } + } +}); + +/** + * Whenever the selection is changed, prevent cursor (lead) to be positioned at + * position 0 of right-to-left line in order to maintain the RLE marker at this position. + * When cursor reaches position 0, either advance it to position 1 of current line (default) + * or to last position of previous line (if it comes from position 1 as the result of commands + * mentioned in 'onCommandEmitted' event handler). + * This serves few purposes: + * - ensures cursor visual movement as if RLE mark doesn't exist. + * - prevents character insertion before RLE mark. + * - prevents RLE mark removal when 'delete' is pressed when cursot stays at position 0. + * - ensures RLE mark removal on line merge, when 'delete' is pressed and cursor stays + * at last position of previous line and when 'backspace' is pressed and cursor stays at + * first position of current line. This is achived by hacking range boundaries on 'remove' operation. + **/ +function onChangeSelection(e, editor) { + var lead = editor.getSelection().lead; + if (editor.session.$bidiHandler.isRtlLine(lead.row)) { + if (lead.column === 0) { + if (editor.session.$bidiHandler.isMoveLeftOperation && lead.row > 0) { + editor.getSelection().moveCursorTo(lead.row - 1, editor.session.getLine(lead.row - 1).length); + } else { + if (editor.getSelection().isEmpty()) + lead.column += 1; + else + lead.setPosition(lead.row, lead.column + 1); + } + } + } +} + +function onCommandEmitted(commadEvent) { + commadEvent.editor.session.$bidiHandler.isMoveLeftOperation = /gotoleft|selectleft|backspace|removewordleft/.test(commadEvent.command.name); +} + +/** + * Whenever the document is changed make sure that line break operatin + * on right-to-left line (like pressing Enter or pasting multi-line text) + * produces new right-to-left lines + **/ +function onChange(delta, session) { + session.$bidiHandler.currentRow = null; + if (session.$bidiHandler.isRtlLine(delta.start.row) && delta.action === 'insert' && delta.lines.length > 1) { + for (var row = delta.start.row; row < delta.end.row; row++) { + if (session.getLine(row + 1).charAt(0) !== session.$bidiHandler.RLE) + session.getDocument().$lines[row + 1] = session.$bidiHandler.RLE + session.getLine(row + 1); + } + } +} + +function updateLineDirection(e, renderer) { + var session = renderer.session; + var $bidiHandler = session.$bidiHandler; + var cells = renderer.$textLayer.$lines.cells; + var width = renderer.layerConfig.width - renderer.layerConfig.padding + "px"; + cells.forEach(function(cell) { + var style = cell.element.style; + if ($bidiHandler && $bidiHandler.isRtlLine(cell.row)) { + style.direction = "rtl"; + style.textAlign = "right"; + style.width = width; + } else { + style.direction = ""; + style.textAlign = ""; + style.width = ""; + } + }); +} + +function clearTextLayer(renderer) { + var lines = renderer.$textLayer.$lines; + lines.cells.forEach(clear); + lines.cellCache.forEach(clear); + function clear(cell) { + var style = cell.element.style; + style.direction = style.textAlign = style.width = ""; + } +} + +}); diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 1cd8bec9491..7231a8d5da3 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -1040,7 +1040,8 @@ var VirtualRenderer = function(container, theme) { height : this.$size.scrollerHeight }; - this.session.$bidiHandler.setContentWidth(longestLine); + if (this.session.$bidiHandler) + this.session.$bidiHandler.setContentWidth(longestLine - this.$padding); // For debugging. // console.log(JSON.stringify(this.layerConfig)); From ecd19f0ceec11628063180da34b41b72d0d40169 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 29 Apr 2018 00:53:50 +0400 Subject: [PATCH 0004/1293] restore bidi support in marker layer --- lib/ace/bidihandler.js | 4 +-- lib/ace/edit_session.js | 2 +- lib/ace/layer/marker.js | 60 ++++++++++++++++++++++++++++++----------- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/lib/ace/bidihandler.js b/lib/ace/bidihandler.js index b955f5faebf..cb8df42b12a 100644 --- a/lib/ace/bidihandler.js +++ b/lib/ace/bidihandler.js @@ -67,7 +67,7 @@ var BidiHandler = function(session) { this.rtlLineOffset = 0; this.wrapOffset = 0; this.isMoveLeftOperation = false; - this.seenBidi = null; + this.seenBidi = bidiRE.test(session.getValue()); }; (function() { @@ -80,7 +80,7 @@ var BidiHandler = function(session) { * @param {Number} the wrapped screen line index [ optional] **/ this.isBidiRow = function(screenRow, docRow, splitIndex) { - if (this.seenBidi == false) + if (!this.seenBidi) return false; if (screenRow !== this.currentRow) { this.currentRow = screenRow; diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 3d20309e425..740d85a31d0 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -159,9 +159,9 @@ var EditSession = function(text, mode) { if (typeof text != "object" || !text.getLine) text = new Document(text); - this.$bidiHandler = new BidiHandler(this); this.setDocument(text); this.selection = new Selection(this); + this.$bidiHandler = new BidiHandler(this); config.resetOptions(this); this.setMode(mode); diff --git a/lib/ace/layer/marker.js b/lib/ace/layer/marker.js index 17ee2f673c1..4a9bf4278e1 100644 --- a/lib/ace/layer/marker.js +++ b/lib/ace/layer/marker.js @@ -150,23 +150,35 @@ var Marker = function(parentEl) { var left = padding + range.start.column * config.characterWidth; extraStyle = extraStyle || ""; - this.elt( - clazz + " ace_br1 ace_start", - "height:"+ height+ "px;"+ "right:0;"+ "top:"+top+ "px;left:"+ left+ "px;" + (extraStyle || "") - ); - + if (this.session.$bidiHandler.isBidiRow(range.start.row)) { + var range1 = range.clone(); + range1.end.row = range1.start.row; + range1.end.column = this.session.getLine(range1.start.row).length; + this.drawBidiSingleLineMarker(stringBuilder, range1, clazz + " ace_br1 ace_start", config, null, extraStyle); + } else { + this.elt( + clazz + " ace_br1 ace_start", + "height:"+ height+ "px;"+ "right:0;"+ "top:"+top+ "px;left:"+ left+ "px;" + (extraStyle || "") + ); + } // from start of the last line to the selection end - top = this.$getTop(range.end.row, config); - var width = range.end.column * config.characterWidth; - - this.elt( - clazz + " ace_br12", - "height:"+ height+ "px;"+ - "width:"+ width+ "px;"+ - "top:"+ top+ "px;"+ - "left:"+ padding+ "px;"+ (extraStyle || "") - ); + if (this.session.$bidiHandler.isBidiRow(range.end.row)) { + var range1 = range.clone(); + range1.start.row = range1.end.row; + range1.start.column = 0; + this.drawBidiSingleLineMarker(stringBuilder, range1, clazz + " ace_br12", config, null, extraStyle); + } else { + top = this.$getTop(range.end.row, config); + var width = range.end.column * config.characterWidth; + this.elt( + clazz + " ace_br12", + "height:"+ height+ "px;"+ + "width:"+ width+ "px;"+ + "top:"+ top+ "px;"+ + "left:"+ padding+ "px;"+ (extraStyle || "") + ); + } // all the complete lines height = (range.end.row - range.start.row - 1) * config.lineHeight; if (height <= 0) @@ -186,6 +198,8 @@ var Marker = function(parentEl) { // Draws a marker which covers part or whole width of a single screen line this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) { + if (this.session.$bidiHandler.isBidiRow(range.start.row)) + return this.drawBidiSingleLineMarker(stringBuilder, range, clazz, config, extraLength, extraStyle); var height = config.lineHeight; var width = (range.end.column + (extraLength || 0) - range.start.column) * config.characterWidth; @@ -201,6 +215,22 @@ var Marker = function(parentEl) { ); }; + // Draws Bidi marker which covers part or whole width of a single screen line + this.drawBidiSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) { + var height = config.lineHeight, top = this.$getTop(range.start.row, config), padding = this.$padding; + var selections = this.session.$bidiHandler.getSelections(range.start.column, range.end.column); + + selections.forEach(function(selection) { + this.elt( + clazz, + "height:" + height + "px;" + + "width:" + selection.width + (extraLength || 0) + "px;" + + "top:" + top + "px;" + + "left:" + (padding + selection.left) + "px;" + (extraStyle || "") + ); + }, this); + }; + this.drawFullLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { var top = this.$getTop(range.start.row, config); var height = config.lineHeight; From ced10ce34e15c6cf0e29a571473a31ea38e3f135 Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Sat, 5 May 2018 16:25:56 +0100 Subject: [PATCH 0005/1293] lucene: improve highlight rules --- lib/ace/mode/_test/text_lucene.txt | 53 +++-- lib/ace/mode/_test/tokens_lucene.json | 257 ++++++++++++++++++++----- lib/ace/mode/lucene_highlight_rules.js | 87 +++++---- 3 files changed, 295 insertions(+), 102 deletions(-) diff --git a/lib/ace/mode/_test/text_lucene.txt b/lib/ace/mode/_test/text_lucene.txt index c71f2680d1a..739c3b4d65e 100644 --- a/lib/ace/mode/_test/text_lucene.txt +++ b/lib/ace/mode/_test/text_lucene.txt @@ -1,16 +1,39 @@ -test: recognises AND as keyword -test: recognises OR as keyword -test: recognises NOT as keyword -test: recognises "hello this is dog" as string -test: recognises -"hello this is dog" as negation with string -test: recognises ~100 as text with proximity -test: recognises "hello this is dog"~100 as string with proximity -test: recognises raw:"hello this is dog" as keyword -test: recognises raw:foo as"keyword' -test: recognises "(" as opening parenthesis -test: recognises ")" as closing parenthesis -test: recognises foo* as text with asterisk -test: recognises foo? as text with interro -test: recognises single word as text foo - \ No newline at end of file +foo: foo AND bar +foo AND bar +foo OR bar +foo NOT bar +"foo bar" +bar "foo bar" +bar -foo +bar -"foo bar" +-foo +-"foo bar" +bar foo~100 +foo~100 +foo~100 bar +"foo bar"~10 +foo~ +bar foo~ +foo~ bar +foo~0.8 +field:foo +field:foo bar +field:"foo bar" +(foo AND bar) +(field:foo AND field:"bar baz") +foo* +f?o +f*o ++foo ++"foo bar" +foo? +?oo +foo +field:(-foo +bar +"foo bar") +field:{foo TO bar} +field:[foo TO bar] +field:["a b c" TO def] +field:{"a b c" TO def} +field:{foo TO "bar"} +field:{20180101 TO 20190202} diff --git a/lib/ace/mode/_test/tokens_lucene.json b/lib/ace/mode/_test/tokens_lucene.json index 1f6d2985e20..08bb1dc1747 100644 --- a/lib/ace/mode/_test/tokens_lucene.json +++ b/lib/ace/mode/_test/tokens_lucene.json @@ -1,92 +1,245 @@ [[ "start", - ["keyword","test:"], - ["text"," recognises "], + ["text"," "], + ["string.unquoted","foo"] +],[ + "start", + ["keyword","foo:"], + ["text"," "], + ["string.unquoted","foo"], + ["text"," "], ["keyword.operator","AND"], - ["text"," as keyword"] + ["text"," "], + ["string.unquoted","bar"] ],[ "start", - ["keyword","test:"], - ["text"," recognises "], + ["string.unquoted","foo"], + ["text"," "], + ["keyword.operator","AND"], + ["text"," "], + ["string.unquoted","bar"] +],[ + "start", + ["string.unquoted","foo"], + ["text"," "], ["keyword.operator","OR"], - ["text"," as keyword"] + ["text"," "], + ["string.unquoted","bar"] ],[ "start", - ["keyword","test:"], - ["text"," recognises "], + ["string.unquoted","foo"], + ["text"," "], ["keyword.operator","NOT"], - ["text"," as keyword"] + ["text"," "], + ["string.unquoted","bar"] +],[ + "start", + ["string","\"foo bar\""] ],[ "start", - ["keyword","test:"], - ["text"," recognises "], - ["string","\"hello this is dog\""], - ["text"," as string"] + ["string.unquoted","bar"], + ["text"," "], + ["string","\"foo bar\""] ],[ "start", - ["keyword","test:"], - ["text"," recognises "], + ["string.unquoted","bar"], + ["text"," "], ["constant.character.negation","-"], - ["string","\"hello this is dog\""], - ["text"," as negation with string"] + ["string.unquoted","foo"] ],[ "start", - ["keyword","test:"], - ["text"," recognises "], - ["constant.character.proximity","~100"], - ["text"," as text with proximity"] + ["string.unquoted","bar"], + ["text"," "], + ["constant.character.negation","-"], + ["string","\"foo bar\""] +],[ + "start", + ["constant.character.negation","-"], + ["string.unquoted","foo"] +],[ + "start", + ["constant.character.negation","-"], + ["string","\"foo bar\""] +],[ + "start", + ["string.unquoted","bar"], + ["text"," "], + ["string.unquoted","foo"], + ["constant.character.proximity","~100"] ],[ "start", - ["keyword","test:"], - ["text"," recognises "], - ["string","\"hello this is dog\""], + ["string.unquoted","foo"], + ["constant.character.proximity","~100"] +],[ + "start", + ["string.unquoted","foo"], ["constant.character.proximity","~100"], - ["text"," as string with proximity"] + ["text"," "], + ["string.unquoted","bar"] +],[ + "start", + ["string","\"foo bar\""], + ["constant.character.proximity","~10"] +],[ + "start", + ["string.unquoted","foo"], + ["constant.character.proximity","~"] +],[ + "start", + ["string.unquoted","bar"], + ["text"," "], + ["string.unquoted","foo"], + ["constant.character.proximity","~"] +],[ + "start", + ["string.unquoted","foo"], + ["constant.character.proximity","~"], + ["text"," "], + ["string.unquoted","bar"] +],[ + "start", + ["string.unquoted","foo"], + ["constant.character.proximity","~0.8"] +],[ + "start", + ["keyword","field:"], + ["string.unquoted","foo"] +],[ + "start", + ["keyword","field:"], + ["string.unquoted","foo"], + ["text"," "], + ["string.unquoted","bar"] +],[ + "start", + ["keyword","field:"], + ["string","\"foo bar\""] ],[ "start", - ["keyword","test:"], - ["text"," recognises "], - ["keyword","raw:"], - ["string","\"hello this is dog\""], - ["text"," as keyword"] + ["paren.lparen","("], + ["string.unquoted","foo"], + ["text"," "], + ["keyword.operator","AND"], + ["text"," "], + ["string.unquoted","bar"], + ["paren.rparen",")"] ],[ "start", - ["keyword","test:"], - ["text"," recognises "], - ["keyword","raw:"], - ["text","foo as\"keyword'"] + ["paren.lparen","("], + ["keyword","field:"], + ["string.unquoted","foo"], + ["text"," "], + ["keyword.operator","AND"], + ["text"," "], + ["keyword","field:"], + ["string","\"bar baz\""], + ["paren.rparen",")"] ],[ "start", - ["keyword","test:"], - ["text"," recognises "], - ["string","\"(\""], - ["text"," as opening parenthesis"] + ["string.unquoted","foo"], + ["constant.character.asterisk","*"] ],[ "start", - ["keyword","test:"], - ["text"," recognises "], - ["string","\")\""], - ["text"," as closing parenthesis"] + ["string.unquoted","f"], + ["constant.character.interro","?"], + ["string.unquoted","o"] ],[ "start", - ["keyword","test:"], - ["text"," recognises foo"], + ["string.unquoted","f"], ["constant.character.asterisk","*"], - ["text"," as text with asterisk"] + ["string.unquoted","o"] +],[ + "start", + ["constant.character.required","+"], + ["string.unquoted","foo"] +],[ + "start", + ["constant.character.required","+"], + ["string","\"foo bar\""] +],[ + "start", + ["string.unquoted","foo"], + ["constant.character.interro","?"] ],[ "start", - ["keyword","test:"], - ["text"," recognises foo"], ["constant.character.interro","?"], - ["text"," as text with interro"] + ["string.unquoted","oo"] +],[ + "start", + ["string.unquoted","foo"] +],[ + "start", + ["keyword","field:"], + ["paren.lparen","("], + ["constant.character.negation","-"], + ["string.unquoted","foo"], + ["text"," "], + ["constant.character.required","+"], + ["string.unquoted","bar"], + ["text"," "], + ["constant.character.required","+"], + ["string","\"foo bar\""], + ["paren.rparen",")"] ],[ "start", - ["keyword","test:"], - ["text"," recognises single word as text"] + ["keyword","field:"], + ["paren.lparen","{"], + ["string.unquoted","foo"], + ["text"," "], + ["keyword.operator","TO"], + ["text"," "], + ["string.unquoted","bar"], + ["paren.rparen","}"] ],[ "start", - ["text"," foo"] + ["keyword","field:"], + ["paren.lparen","["], + ["string.unquoted","foo"], + ["text"," "], + ["keyword.operator","TO"], + ["text"," "], + ["string.unquoted","bar"], + ["paren.rparen","]"] ],[ "start", - ["text"," "] + ["keyword","field:"], + ["paren.lparen","["], + ["string","\"a b c\""], + ["text"," "], + ["keyword.operator","TO"], + ["text"," "], + ["string.unquoted","def"], + ["paren.rparen","]"] +],[ + "start", + ["keyword","field:"], + ["paren.lparen","{"], + ["string","\"a b c\""], + ["text"," "], + ["keyword.operator","TO"], + ["text"," "], + ["string.unquoted","def"], + ["paren.rparen","}"] +],[ + "start", + ["keyword","field:"], + ["paren.lparen","{"], + ["string.unquoted","foo"], + ["text"," "], + ["keyword.operator","TO"], + ["text"," "], + ["string","\"bar\""], + ["paren.rparen","}"] +],[ + "start", + ["keyword","field:"], + ["paren.lparen","{"], + ["string.unquoted","20180101"], + ["text"," "], + ["keyword.operator","TO"], + ["text"," "], + ["string.unquoted","20190202"], + ["paren.rparen","}"] +],[ + "start" ]] \ No newline at end of file diff --git a/lib/ace/mode/lucene_highlight_rules.js b/lib/ace/mode/lucene_highlight_rules.js index 536aa1d30f0..12d1c738e97 100644 --- a/lib/ace/mode/lucene_highlight_rules.js +++ b/lib/ace/mode/lucene_highlight_rules.js @@ -6,41 +6,58 @@ var lang = require("../lib/lang"); var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var LuceneHighlightRules = function() { - this.$rules = { - "start" : [ - { - token : "constant.character.negation", - regex : "[\\-]" - }, { - token : "constant.character.interro", - regex : "[\\?]" - }, { - token : "constant.character.asterisk", - regex : "[\\*]" - }, { - token: 'constant.character.proximity', - regex: '~[0-9]+\\b' - }, { - token : 'keyword.operator', - regex: '(?:AND|OR|NOT)\\b' - }, { - token : "paren.lparen", - regex : "[\\(]" - }, { - token : "paren.rparen", - regex : "[\\)]" - }, { - token : "keyword", - regex : "[\\S]+:" - }, { - token : "string", // " string - regex : '".*?"' - }, { - token : "text", - regex : "\\s+" - } - ] - }; + this.$rules = { + "start" : [ + { + token: "constant.character.negation", + regex: "\\-" + }, + { + token: "constant.character.interro", + regex: "\\?" + }, + { + token: "constant.character.required", + regex: "\\+" + }, + { + token: "constant.character.asterisk", + regex: "\\*" + }, + { + token: 'constant.character.proximity', + regex: '~(?:0\\.[0-9]+|[0-9]+)?' + }, + { + token: 'keyword.operator', + regex: '(AND|OR|NOT|TO)\\b' + }, + { + token: "paren.lparen", + regex: "[\\(\\{\\[]" + }, + { + token: "paren.rparen", + regex: "[\\)\\}\\]]" + }, + { + token: "keyword", + regex: "\\S+:" + }, + { + token: "string", // " string + regex: '"[^"]*"' + }, + { + token: "string.unquoted", + regex: "\\w+" + }, + { + token: "text", + regex: "\\s+" + } + ] + }; }; oop.inherits(LuceneHighlightRules, TextHighlightRules); From d96a63eb57fb4388a9748786f7afa731e7aa648e Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Wed, 9 May 2018 21:44:16 +0100 Subject: [PATCH 0006/1293] lucene: whitespace revert --- lib/ace/mode/lucene_highlight_rules.js | 93 ++++++++++++-------------- 1 file changed, 41 insertions(+), 52 deletions(-) diff --git a/lib/ace/mode/lucene_highlight_rules.js b/lib/ace/mode/lucene_highlight_rules.js index 12d1c738e97..59b134ddebf 100644 --- a/lib/ace/mode/lucene_highlight_rules.js +++ b/lib/ace/mode/lucene_highlight_rules.js @@ -6,58 +6,47 @@ var lang = require("../lib/lang"); var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var LuceneHighlightRules = function() { - this.$rules = { - "start" : [ - { - token: "constant.character.negation", - regex: "\\-" - }, - { - token: "constant.character.interro", - regex: "\\?" - }, - { - token: "constant.character.required", - regex: "\\+" - }, - { - token: "constant.character.asterisk", - regex: "\\*" - }, - { - token: 'constant.character.proximity', - regex: '~(?:0\\.[0-9]+|[0-9]+)?' - }, - { - token: 'keyword.operator', - regex: '(AND|OR|NOT|TO)\\b' - }, - { - token: "paren.lparen", - regex: "[\\(\\{\\[]" - }, - { - token: "paren.rparen", - regex: "[\\)\\}\\]]" - }, - { - token: "keyword", - regex: "\\S+:" - }, - { - token: "string", // " string - regex: '"[^"]*"' - }, - { - token: "string.unquoted", - regex: "\\w+" - }, - { - token: "text", - regex: "\\s+" - } - ] - }; + this.$rules = { + "start" : [ + { + token: "constant.character.negation", + regex: "\\-" + }, { + token: "constant.character.interro", + regex: "\\?" + }, { + token: "constant.character.required", + regex: "\\+" + }, { + token: "constant.character.asterisk", + regex: "\\*" + }, { + token: 'constant.character.proximity', + regex: '~(?:0\\.[0-9]+|[0-9]+)?' + }, { + token: 'keyword.operator', + regex: '(AND|OR|NOT|TO)\\b' + }, { + token: "paren.lparen", + regex: "[\\(\\{\\[]" + }, { + token: "paren.rparen", + regex: "[\\)\\}\\]]" + }, { + token: "keyword", + regex: "\\S+:" + }, { + token: "string", // " string + regex: '"[^"]*"' + }, { + token: "string.unquoted", + regex: "\\w+" + }, { + token: "text", + regex: "\\s+" + } + ] + }; }; oop.inherits(LuceneHighlightRules, TextHighlightRules); From 02a0522518088a40bb3799fa224c97517d7422c8 Mon Sep 17 00:00:00 2001 From: Cigery <150526401@qq.com> Date: Fri, 11 May 2018 12:38:55 +0800 Subject: [PATCH 0007/1293] missed a "." in L677 --- api/resources/csses/ace_api.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/resources/csses/ace_api.css b/api/resources/csses/ace_api.css index 7a90b4c3f7a..3ef8b391618 100644 --- a/api/resources/csses/ace_api.css +++ b/api/resources/csses/ace_api.css @@ -674,7 +674,7 @@ li.signature { #documentation .alias a:hover, #documentation .related-to a:hover { text-decoration: none; } -.#documentation alias:hover, #documentation .related-to:hover { +.#documentation .alias:hover, #documentation .related-to:hover { opacity: 0.8; cursor: pointer; } From ff449b75b548b4019cf363e571f0a29d8b42dd82 Mon Sep 17 00:00:00 2001 From: Nathan Whetsell Date: Fri, 11 May 2018 09:59:58 -0400 Subject: [PATCH 0008/1293] Update for Csound 6.11.0 --- .../mode/csound_orchestra_highlight_rules.js | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/lib/ace/mode/csound_orchestra_highlight_rules.js b/lib/ace/mode/csound_orchestra_highlight_rules.js index b775a021165..346bd565440 100644 --- a/lib/ace/mode/csound_orchestra_highlight_rules.js +++ b/lib/ace/mode/csound_orchestra_highlight_rules.js @@ -122,9 +122,11 @@ var CsoundOrchestraHighlightRules = function() { "MixerSetLevel", "MixerSetLevel_i", "OSCinit", + "OSCinitM", "OSClisten", "OSCraw", "OSCsend", + "OSCsend_lo", "S", "STKBandedWG", "STKBeeThree", @@ -174,6 +176,7 @@ var CsoundOrchestraHighlightRules = function() { "atonex", "babo", "balance", + "balance2", "bamboo", "barmodel", "bbcutm", @@ -734,6 +737,8 @@ var CsoundOrchestraHighlightRules = function() { "lorenz", "loscil", "loscil3", + "loscil3phs", + "loscilphs", "loscilx", "lowpass2", "lowres", @@ -1033,7 +1038,6 @@ var CsoundOrchestraHighlightRules = function() { "pvsftw", "pvsfwrite", "pvsgain", - "pvsgendy", "pvshift", "pvsifd", "pvsin", @@ -1271,7 +1275,6 @@ var CsoundOrchestraHighlightRules = function() { "sockrecv", "sockrecvs", "socksend", - "socksend_k", "socksends", "sorta", "sortd", @@ -1372,38 +1375,6 @@ var CsoundOrchestraHighlightRules = function() { "tanh", "taninv", "taninv2", - "tb0", - "tb0_init", - "tb1", - "tb10", - "tb10_init", - "tb11", - "tb11_init", - "tb12", - "tb12_init", - "tb13", - "tb13_init", - "tb14", - "tb14_init", - "tb15", - "tb15_init", - "tb1_init", - "tb2", - "tb2_init", - "tb3", - "tb3_init", - "tb4", - "tb4_init", - "tb5", - "tb5_init", - "tb6", - "tb6_init", - "tb7", - "tb7_init", - "tb8", - "tb8_init", - "tb9", - "tb9_init", "tbvcf", "tempest", "tempo", @@ -1589,6 +1560,10 @@ var CsoundOrchestraHighlightRules = function() { "lentab", "maxtab", "mintab", + "pop", + "pop_f", + "push", + "push_f", "scalet", "sndload", "soundout", @@ -1602,11 +1577,44 @@ var CsoundOrchestraHighlightRules = function() { "specscal", "specsum", "spectrum", + "stack", "sumtab", "tabgen", "tabmap", "tabmap_i", "tabslice", + "tb0", + "tb0_init", + "tb1", + "tb10", + "tb10_init", + "tb11", + "tb11_init", + "tb12", + "tb12_init", + "tb13", + "tb13_init", + "tb14", + "tb14_init", + "tb15", + "tb15_init", + "tb1_init", + "tb2", + "tb2_init", + "tb3", + "tb3_init", + "tb4", + "tb4_init", + "tb5", + "tb5_init", + "tb6", + "tb6_init", + "tb7", + "tb7_init", + "tb8", + "tb8_init", + "tb9", + "tb9_init", "vbap16", "vbap4", "vbap4move", From a8471e59b1c54cb0a5367286286c4c2414ffd503 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 13 May 2018 22:44:43 +0400 Subject: [PATCH 0009/1293] add Terraform and Puppet modes --- demo/kitchen-sink/docs/puppet.epp | 51 ++++++ demo/kitchen-sink/docs/terraform.tf | 94 ++++++++++ lib/ace/ext/modelist.js | 2 + lib/ace/mode/puppet.js | 57 ++++++ lib/ace/mode/puppet_highlight_rules.js | 184 +++++++++++++++++++ lib/ace/mode/terraform.js | 57 ++++++ lib/ace/mode/terraform_highlight_rules.js | 212 ++++++++++++++++++++++ lib/ace/snippets/puppet.js | 7 + lib/ace/snippets/puppet.snippets | 0 lib/ace/snippets/terraform.js | 7 + lib/ace/snippets/terraform.snippets | 0 11 files changed, 671 insertions(+) create mode 100644 demo/kitchen-sink/docs/puppet.epp create mode 100644 demo/kitchen-sink/docs/terraform.tf create mode 100644 lib/ace/mode/puppet.js create mode 100644 lib/ace/mode/puppet_highlight_rules.js create mode 100644 lib/ace/mode/terraform.js create mode 100644 lib/ace/mode/terraform_highlight_rules.js create mode 100644 lib/ace/snippets/puppet.js create mode 100644 lib/ace/snippets/puppet.snippets create mode 100644 lib/ace/snippets/terraform.js create mode 100644 lib/ace/snippets/terraform.snippets diff --git a/demo/kitchen-sink/docs/puppet.epp b/demo/kitchen-sink/docs/puppet.epp new file mode 100644 index 00000000000..bc070681a2a --- /dev/null +++ b/demo/kitchen-sink/docs/puppet.epp @@ -0,0 +1,51 @@ +define apache::vhost ($port, $docroot, $servername = $title, $vhost_name = '*') { + include apache + include apache::params + $vhost_dir = $apache::params::vhost_dir + file { "${vhost_dir}/${servername}.conf": + content => template('apache/vhost-default.conf.erb'), + owner => 'www', + group => 'www', + mode => '644', + require => Package['httpd'], + notify => Service['httpd'], + } +} + +type MyModule::Tree = Array[Variant[Data, Tree]] + +function apache::bool2http(Variant[String, Boolean] $arg) >> String { + case $arg { + false, undef, /(?i:false)/ : { 'Off' } + true, /(?i:true)/ : { 'On' } + default : { "$arg" } + } +} + +# A class with parameters +class apache (String $version = 'latest') { + package {'httpd': + ensure => $version, # Using the class parameter from above + before => File['/etc/httpd.conf'], + } + file {'/etc/httpd.conf': + ensure => file, + owner => 'httpd', + content => template('apache/httpd.conf.erb'), # Template from a module + } + service {'httpd': + ensure => running, + enable => true, + subscribe => File['/etc/httpd.conf'], + } +} + + +if $is_virtual { + warning( 'Tried to include class ntp on virtual machine; this node might be misclassified.' ) +} +elsif $operatingsystem == 'Darwin' { + warning( 'This NTP module does not yet work on our Mac laptops.' ) +else { + include ntp +} \ No newline at end of file diff --git a/demo/kitchen-sink/docs/terraform.tf b/demo/kitchen-sink/docs/terraform.tf new file mode 100644 index 00000000000..f63d7746436 --- /dev/null +++ b/demo/kitchen-sink/docs/terraform.tf @@ -0,0 +1,94 @@ +export TF_LOG=TRACE + +# An AMI +variable "ami" { + description = "the AMI to use" +} + +/* A multi + line comment. */ +resource "aws_instance" "web" { + ami = "${var.ami}" + count = 2 + source_dest_check = false + + connection { + user = "root" + } +} + +resource "aws_instance" "web" { + subnet = "${var.env == "production" ? var.prod_subnet : var.dev_subnet}" +} + +variable "count" { + default = 2 +} + +variable "hostnames" { + default = { + "0" = "example1.org" + "1" = "example2.net" + } +} + +data "template_file" "web_init" { + # Render the template once for each instance + count = "${length(var.hostnames)}" + template = "${file("templates/web_init.tpl")}" + vars { + # count.index tells us the index of the instance we are rendering + hostname = "${var.hostnames[count.index]}" + } +} + +resource "aws_instance" "web" { + # Create one instance for each hostname + count = "${length(var.hostnames)}" + + # Pass each instance its corresponding template_file + user_data = "${data.template_file.web_init.*.rendered[count.index]}" +} + +variable "count" { + default = 2 +} + +# Define the common tags for all resources +locals { + common_tags = { + Component = "awesome-app" + Environment = "production" + } +} + +# Create a resource that blends the common tags with instance-specific tags. +resource "aws_instance" "server" { + ami = "ami-123456" + instance_type = "t2.micro" + + tags = "${merge( + local.common_tags, + map( + "Name", "awesome-app-server", + "Role", "server" + ) + )}" +} + +$ terraform apply -var foo=bar -var foo=baz +$ terraform apply -var 'foo={quux="bar"}' -var 'foo={bar="baz"}' + +$ terraform apply -var-file=foo.tfvars -var-file=bar.tfvars +$ TF_VAR_somemap='{foo = "bar", baz = "qux"}' terraform plan + +resource "aws_instance" "web" { + # ... + + count = "${var.count}" + + # Tag the instance with a counter starting at 1, ie. web-001 + tags { + Name = "${format("web-%03d", count.index + 1)}" + } +} \ No newline at end of file diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 202ddcdad42..b4558ea38a4 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -141,6 +141,7 @@ var supportedModes = { pgSQL: ["pgsql"], PHP_Laravel_blade: ["blade.php"], PHP: ["php|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"], + Puppet: ["epp|pp"], Pig: ["pig"], Powershell: ["ps1"], Praat: ["praat|praatscript|psc|proc"], @@ -174,6 +175,7 @@ var supportedModes = { SVG: ["svg"], Swift: ["swift"], Tcl: ["tcl"], + Terraform: ["tf", "tfvars", "terragrunt"], Tex: ["tex"], Text: ["txt"], Textile: ["textile"], diff --git a/lib/ace/mode/puppet.js b/lib/ace/mode/puppet.js new file mode 100644 index 00000000000..0f038beca51 --- /dev/null +++ b/lib/ace/mode/puppet.js @@ -0,0 +1,57 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function (require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var PuppetHighlightRules = require("./puppet_highlight_rules").PuppetHighlightRules; +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; + +var Mode = function () { + TextMode.call(this); + this.HighlightRules = PuppetHighlightRules; + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CstyleBehaviour(); + this.foldingRules = new CStyleFoldMode(); +}; + +oop.inherits(Mode, TextMode); + + +(function () { + this.$id = "ace/mode/puppet"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/puppet_highlight_rules.js b/lib/ace/mode/puppet_highlight_rules.js new file mode 100644 index 00000000000..7179648ec40 --- /dev/null +++ b/lib/ace/mode/puppet_highlight_rules.js @@ -0,0 +1,184 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function (require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; +var PuppetHighlightRules = function () { + this.$rules = { + "start": [ + { + token: ['keyword.type.puppet', 'constant.class.puppet', 'keyword.inherits.puppet', 'constant.class.puppet'], + regex: "^\\s*(class)(\\s+(?:[-_A-Za-z0-9\".]+::)*[-_A-Za-z0-9\".]+\\s*)(?:(inherits\\s*)(\\s+(?:[-_A-Za-z0-9\".]+::)*[-_A-Za-z0-9\".]+\\s*))?" + }, + { + token: ['storage.function.puppet', 'name.function.puppet', 'punctuation.lpar'], + regex: "(^\\s*define)(\\s+[a-zA-Z0-9_:]+\\s*)(\\()", + push: + [{ + token: 'punctuation.rpar.puppet', + regex: "\\)", + next: 'pop' + }, + {include: "constants"}, + {include: "variable"}, + {include: "strings"}, + {include: "operators"}, + {defaultToken: 'string'}] + }, + { + token: ["language.support.class", "keyword.operator"], + regex: "\\b([a-zA-Z_]+)(\\s+=>)" + }, + { + token: ["exported.resource.puppet", "keyword.name.resource.puppet", "paren.lpar"], + regex: "(\\@\\@)?(\\s*[a-zA-Z_]*)(\\s*\\{)" + }, + { + token: "qualified.variable.puppet", + regex: "(\\$([a-z][a-z0-9_]*)?(::[a-z][a-z0-9_]*)*::[a-z0-9_][a-zA-Z0-9_]*)" + }, + + { + token: "singleline.comment.puppet", + regex: '#(.)*$' + }, + { + token: "multiline.comment.begin.puppet", + regex: '^\\s*\\/\\*\\s*$', + push: "blockComment" + }, + { + token: "keyword.control.puppet", + regex: "\\b(case|if|unless|else|elsif|in|default:|and|or)\\s+(?!::)" + }, + { + token: "keyword.control.puppet", + regex: "\\b(import|default|inherits|include|require|contain|node|application|consumes|environment|site|function|produces)\\b" + }, + { + token: "support.function.puppet", + regex: "\\b(lest|str2bool|escape|gsub|Timestamp|Timespan|with|alert|crit|debug|notice|sprintf|split|step|strftime|slice|shellquote|type|sha1|defined|scanf|reverse_each|regsubst|return|emerg|reduce|err|failed|fail|versioncmp|file|generate|then|info|realize|search|tag|tagged|template|epp|warning|hiera_include|each|assert_type|binary_file|create_resources|dig|digest|filter|lookup|find_file|fqdn_rand|hiera_array|hiera_hash|inline_epp|inline_template|map|match|md5|new|next)\\b" + }, + { + token: "constant.types.puppet", + regex: "\\b(String|File|Package|Service|Class|Integer|Array|Catalogentry|Variant|Boolean|Undef|Number|Hash|Float|Numeric|NotUndef|Callable|Optional|Any|Regexp|Sensitive|Sensitive.new|Type|Resource|Default|Enum|Scalar|Collection|Data|Pattern|Tuple|Struct)\\b" + }, + + { + token: "paren.lpar", + regex: "[[({]" + }, + { + token: "paren.rpar", + regex: "[\\])}]" + }, + {include: "variable"}, + {include: "constants"}, + {include: "strings"}, + {include: "operators"}, + { + token: "regexp.begin.string.puppet", + regex: "\\s*(\\/(\\S)+)\\/" + } + ], + blockComment: [{ + regex: "^\\s*\\/\\*\\s*$", + token: "multiline.comment.begin.puppet", + push: "blockComment" + }, { + regex: "^\\s*\\*\\/\\s*$", + token: "multiline.comment.end.puppet", + next: "pop" + }, { + defaultToken: "comment" + }], + "constants": [ + { + token: "constant.language.puppet", + regex: "\\b(false|true|running|stopped|installed|purged|latest|file|directory|held|undef|present|absent|link|mounted|unmounted)\\b" + } + ], + "variable": [ + { + token: "variable.puppet", + regex: "(\\$[a-z0-9_\{][a-zA-Z0-9_]*)" + } + ], + "strings": [ + { + token: "punctuation.quote.puppet", + regex: "'", + push: + [{ + token: 'punctuation.quote.puppet', + regex: "'", + next: 'pop' + }, + {include: "escaped_chars"}, + {defaultToken: 'string'}] + }, + { + token: "punctuation.quote.puppet", + regex: '"', + push: + [{ + token: 'punctuation.quote.puppet', + regex: '"', + next: 'pop' + }, + {include: "escaped_chars"}, + {include: "variable"}, + {defaultToken: 'string'}] + } + ], + "escaped_chars": [ + { + token: "constant.escaped_char.puppet", + regex: "\\\\." + } + ], + "operators": [ + { + token: "keyword.operator", + regex: "\\+\\.|\\-\\.|\\*\\.|\\/\\.|#|;;|\\+|\\-|\\*|\\*\\*\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|<-|=|::|," + } + ] + }; + this.normalizeRules(); +}; + + +oop.inherits(PuppetHighlightRules, TextHighlightRules); + +exports.PuppetHighlightRules = PuppetHighlightRules; +}); diff --git a/lib/ace/mode/terraform.js b/lib/ace/mode/terraform.js new file mode 100644 index 00000000000..6b495147dba --- /dev/null +++ b/lib/ace/mode/terraform.js @@ -0,0 +1,57 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function (require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var TerraformHighlightRules = require("./terraform_highlight_rules").TerraformHighlightRules; +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; + +var Mode = function () { + TextMode.call(this); + this.HighlightRules = TerraformHighlightRules; + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CstyleBehaviour(); + this.foldingRules = new CStyleFoldMode(); +}; + +oop.inherits(Mode, TextMode); + + +(function () { + this.$id = "ace/mode/terraform"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/terraform_highlight_rules.js b/lib/ace/mode/terraform_highlight_rules.js new file mode 100644 index 00000000000..0d8587acce2 --- /dev/null +++ b/lib/ace/mode/terraform_highlight_rules.js @@ -0,0 +1,212 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function (require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; +var TerraformHighlightRules = function () { + + + this.$rules = { + "start": [ + { + token: ['storage.function.terraform'], + regex: '\\b(output|resource|data|variable|module|export)\\b' + }, + { + token: "variable.terraform", + regex: "\\$\\s", + push: [ + { + token: "keyword.terraform", + regex: "(-var-file|-var)" + }, + { + token: "variable.terraform", + regex: "\\n|$", + next: "pop" + }, + + {include: "strings"}, + {include: "variables"}, + {include: "operators"}, + + {defaultToken: "text"} + ] + }, + { + token: "language.support.class", + regex: "\\b(timeouts|provider|connection|provisioner|lifecycleprovider|atlas)\\b" + }, + + { + token: "singleline.comment.terraform", + regex: '#(.)*$' + }, + { + token: "multiline.comment.begin.terraform", + regex: '^\\s*\\/\\*', + push: "blockComment" + }, + { + token: "storage.function.terraform", + regex: "^\\s*(locals|terraform)\\s*{" + }, + { + token: "paren.lpar", + regex: "[[({]" + }, + + { + token: "paren.rpar", + regex: "[\\])}]" + }, + {include: "constants"}, + {include: "strings"}, + {include: "operators"}, + {include: "variables"} + ], + blockComment: [{ + regex: "^\\s*\\/\\*", + token: "multiline.comment.begin.terraform", + push: "blockComment" + }, { + regex: "\\*\\/\\s*$", + token: "multiline.comment.end.terraform", + next: "pop" + }, { + defaultToken: "comment" + }], + "constants": [ + { + token: "constant.language.terraform", + regex: "\\b(true|false|yes|no|on|off|EOF)\\b" + }, + { + token: "constant.numeric.terraform", + regex: "(\\b([0-9]+)([kKmMgG]b?)?\\b)|(\\b(0x[0-9A-Fa-f]+)([kKmMgG]b?)?\\b)" + } + ], + "variables": [ + { + token: ["variable.assignment.terraform", "keyword.operator"], + regex: "\\b([a-zA-Z_]+)(\\s*=)" + } + ], + "interpolated_variables": [ + { + token: "variable.terraform", + regex: "\\b(var|self|count|path|local)\\b(?:\\.*[a-zA-Z_-]*)?" + } + ], + "strings": [ + { + token: "punctuation.quote.terraform", + regex: "'", + push: + [{ + token: 'punctuation.quote.terraform', + regex: "'", + next: 'pop' + }, + {include: "escaped_chars"}, + {defaultToken: 'string'}] + }, + { + token: "punctuation.quote.terraform", + regex: '"', + push: + [{ + token: 'punctuation.quote.terraform', + regex: '"', + next: 'pop' + }, + {include: "interpolation"}, + {include: "escaped_chars"}, + {defaultToken: 'string'}] + } + ], + "escaped_chars": [ + { + token: "constant.escaped_char.terraform", + regex: "\\\\." + } + ], + "operators": [ + { + token: "keyword.operator", + regex: "\\?|:|==|!=|>|<|>=|<=|&&|\\|\\\||!|%|&|\\*|\\+|\\-|/|=" + } + ], + "interpolation": [ + {// TODO: double $ + token: "punctuation.interpolated.begin.terraform", + regex: "\\$?\\$\\{", + push: [{ + token: "punctuation.interpolated.end.terraform", + regex: "\\}", + next: "pop" + }, + {include: "interpolated_variables"}, + {include: "operators"}, + {include: "constants"}, + {include: "strings"}, + {include: "functions"}, + {include: "parenthesis"}, + {defaultToken: "punctuation"} + ] + } + ], + "functions": [ + { + token: "keyword.function.terraform", + regex: "\\b(abs|basename|base64decode|base64encode|base64gzip|base64sha256|base64sha512|bcrypt|ceil|chomp|chunklist|cidrhost|cidrnetmask|cidrsubnet|coalesce|coalescelist|compact|concat|contains|dirname|distinct|element|file|floor|flatten|format|formatlist|indent|index|join|jsonencode|keys|length|list|log|lookup|lower|map|matchkeys|max|merge|min|md5|pathexpand|pow|replace|rsadecrypt|sha1|sha256|sha512|signum|slice|sort|split|substr|timestamp|timeadd|title|transpose|trimspace|upper|urlencode|uuid|values|zipmap)\\b" + } + ], + "parenthesis": [ + { + token: "paren.lpar", + regex: "\\[" + }, + { + token: "paren.rpar", + regex: "\\]" + } + ] + }; + this.normalizeRules(); +}; + +oop.inherits(TerraformHighlightRules, TextHighlightRules); + +exports.TerraformHighlightRules = TerraformHighlightRules; +}); diff --git a/lib/ace/snippets/puppet.js b/lib/ace/snippets/puppet.js new file mode 100644 index 00000000000..61d1a67081f --- /dev/null +++ b/lib/ace/snippets/puppet.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./puppet.snippets"); +exports.scope = "puppet"; + +}); diff --git a/lib/ace/snippets/puppet.snippets b/lib/ace/snippets/puppet.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/terraform.js b/lib/ace/snippets/terraform.js new file mode 100644 index 00000000000..d681d4e5278 --- /dev/null +++ b/lib/ace/snippets/terraform.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./terraform.snippets"); +exports.scope = "terraform"; + +}); diff --git a/lib/ace/snippets/terraform.snippets b/lib/ace/snippets/terraform.snippets new file mode 100644 index 00000000000..e69de29bb2d From bb8d406417d29c7254a343027bd1804a238ac90a Mon Sep 17 00:00:00 2001 From: Rick Strahl Date: Mon, 14 May 2018 11:00:18 -0700 Subject: [PATCH 0010/1293] Add image link parsing to the Markdown link parsing RegEx. --- lib/ace/mode/markdown_highlight_rules.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ace/mode/markdown_highlight_rules.js b/lib/ace/mode/markdown_highlight_rules.js index 8f4887f13dd..4502a058edf 100644 --- a/lib/ace/mode/markdown_highlight_rules.js +++ b/lib/ace/mode/markdown_highlight_rules.js @@ -137,10 +137,10 @@ var MarkdownHighlightRules = function() { regex : "(\\[)(" + escaped("]") + ")(\\]\\s*\\[)("+ escaped("]") + ")(\\])" }, { // link by url token : ["text", "string", "text", "markup.underline", "string", "text"], - regex : "(\\[)(" + // [ - escaped("]") + // link text + regex : "(\\!?\\[)(" + // [ + escaped("]") + // link text or alt text ")(\\]\\()"+ // ]( - '((?:[^\\)\\s\\\\]|\\\\.|\\s(?=[^"]))*)' + // href + '((?:[^\\)\\s\\\\]|\\\\.|\\s(?=[^"]))*)' + // href or image '(\\s*"' + escaped('"') + '"\\s*)?' + // "title" "(\\))" // ) }, { // strong ** __ From 6c3a7bf33222f348e6f8e3780a2688dcd7042cc2 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Fri, 18 May 2018 16:57:20 -0700 Subject: [PATCH 0011/1293] Delete CNAME --- CNAME | 1 - 1 file changed, 1 deletion(-) delete mode 100644 CNAME diff --git a/CNAME b/CNAME deleted file mode 100644 index cb9e1ae2c39..00000000000 --- a/CNAME +++ /dev/null @@ -1 +0,0 @@ -ace.c9.io \ No newline at end of file From 51c0625e138687257d0f943442d17056849086fb Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Fri, 18 May 2018 16:57:34 -0700 Subject: [PATCH 0012/1293] Create CNAME --- CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 CNAME diff --git a/CNAME b/CNAME new file mode 100644 index 00000000000..cb9e1ae2c39 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +ace.c9.io \ No newline at end of file From f03ae9d3f5a76e12d3fbbdff41cbb1c070530c27 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 24 May 2018 12:30:41 +0100 Subject: [PATCH 0013/1293] Added two tmthemes gruvbox dark (hard contrast) and light (hard contrast) --- lib/ace/theme/gruvbox_dark_hard.css | 159 +++ lib/ace/theme/gruvbox_dark_hard.js | 39 + lib/ace/theme/gruvbox_light_hard.css | 159 +++ lib/ace/theme/gruvbox_light_hard.js | 39 + tool/tmtheme.js | 2 + tool/tmthemes/gruvboxDarkHard.tmTheme | 1509 ++++++++++++++++++++++++ tool/tmthemes/gruvboxLightHard.tmTheme | 1509 ++++++++++++++++++++++++ 7 files changed, 3416 insertions(+) create mode 100644 lib/ace/theme/gruvbox_dark_hard.css create mode 100644 lib/ace/theme/gruvbox_dark_hard.js create mode 100644 lib/ace/theme/gruvbox_light_hard.css create mode 100644 lib/ace/theme/gruvbox_light_hard.js create mode 100644 tool/tmthemes/gruvboxDarkHard.tmTheme create mode 100644 tool/tmthemes/gruvboxLightHard.tmTheme diff --git a/lib/ace/theme/gruvbox_dark_hard.css b/lib/ace/theme/gruvbox_dark_hard.css new file mode 100644 index 00000000000..a0f30186b1a --- /dev/null +++ b/lib/ace/theme/gruvbox_dark_hard.css @@ -0,0 +1,159 @@ +.ace-gruvbox-dark-hard .ace_gutter { + background: #1d2021; + color: rgb(132,126,106) +} + +.ace-gruvbox-dark-hard .ace_print-margin { + width: 1px; + background: #e8e8e8 +} + +.ace-gruvbox-dark-hard { + background-color: #1d2021; + color: rgba(235, 219, 178, 0.50) +} + +.ace-gruvbox-dark-hard .ace_cursor { + color: #a89984 +} + +.ace-gruvbox-dark-hard .ace_marker-layer .ace_selection { + background: #3c3836 +} + +.ace-gruvbox-dark-hard.ace_multiselect .ace_selection.ace_start { + box-shadow: 0 0 3px 0px #1d2021; + border-radius: 2px +} + +.ace-gruvbox-dark-hard .ace_marker-layer .ace_step { + background: rgb(198, 219, 174) +} + +.ace-gruvbox-dark-hard .ace_marker-layer .ace_bracket { + margin: -1px 0 0 -1px; + border: 1px solid rgba(235, 219, 178, 0.15) +} + +.ace-gruvbox-dark-hard .ace_marker-layer .ace_active-line { + background: #3c3836 +} + +.ace-gruvbox-dark-hard .ace_gutter-active-line { + background-color: #3c3836 +} + +.ace-gruvbox-dark-hard .ace_marker-layer .ace_selected-word { + border: 1px solid #3c3836 +} + +.ace-gruvbox-dark-hard .ace_fold { + background-color: #b8bb26; + border-color: rgba(235, 219, 178, 0.50) +} + +.ace-gruvbox-dark-hard .ace_keyword { + color: #fb4934 +} + +.ace-gruvbox-dark-hard .ace_keyword.ace_operator { + color: #8ec07c +} + +.ace-gruvbox-dark-hard .ace_keyword.ace_other.ace_unit { + color: #b16286 +} + +.ace-gruvbox-dark-hard .ace_constant { + color: #d3869b +} + +.ace-gruvbox-dark-hard .ace_constant.ace_numeric { + color: #d3869b +} + +.ace-gruvbox-dark-hard .ace_constant.ace_character.ace_escape { + color: #fb4934 +} + +.ace-gruvbox-dark-hard .ace_constant.ace_other { + color: #d3869b +} + +.ace-gruvbox-dark-hard .ace_support.ace_function { + color: #8ec07c +} + +.ace-gruvbox-dark-hard .ace_support.ace_constant { + color: #d3869b +} + +.ace-gruvbox-dark-hard .ace_support.ace_constant.ace_property-value { + color: #f9f5d7 +} + +.ace-gruvbox-dark-hard .ace_support.ace_class { + color: #fabd2f +} + +.ace-gruvbox-dark-hard .ace_support.ace_type { + color: #fabd2f +} + +.ace-gruvbox-dark-hard .ace_storage { + color: #fb4934 +} + +.ace-gruvbox-dark-hard .ace_invalid { + color: #f9f5d7; + background-color: #fb4934 +} + +.ace-gruvbox-dark-hard .ace_string { + color: #b8bb26 +} + +.ace-gruvbox-dark-hard .ace_string.ace_regexp { + color: #b8bb26 +} + +.ace-gruvbox-dark-hard .ace_comment { + font-style: italic; + color: #928374 +} + +.ace-gruvbox-dark-hard .ace_variable { + color: #83a598 +} + +.ace-gruvbox-dark-hard .ace_variable.ace_language { + color: #d3869b +} + +.ace-gruvbox-dark-hard .ace_variable.ace_parameter { + color: #f9f5d7 +} + +.ace-gruvbox-dark-hard .ace_meta.ace_tag { + color: #f9f5d7 +} + +.ace-gruvbox-dark-hard .ace_entity.ace_other.ace_attribute-name { + color: #fabd2f +} + +.ace-gruvbox-dark-hard .ace_entity.ace_name.ace_function { + color: #b8bb26 +} + +.ace-gruvbox-dark-hard .ace_entity.ace_name.ace_tag { + color: #83a598 +} + +.ace-gruvbox-dark-hard .ace_markup.ace_heading { + color: #b8bb26 +} + +.ace-gruvbox-dark-hard .ace_markup.ace_list { + color: #83a598 +} \ No newline at end of file diff --git a/lib/ace/theme/gruvbox_dark_hard.js b/lib/ace/theme/gruvbox_dark_hard.js new file mode 100644 index 00000000000..2cd402ab9b9 --- /dev/null +++ b/lib/ace/theme/gruvbox_dark_hard.js @@ -0,0 +1,39 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-gruvbox-dark-hard"; +exports.cssText = require("../requirejs/text!./gruvbox_dark_hard.css"); + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/lib/ace/theme/gruvbox_light_hard.css b/lib/ace/theme/gruvbox_light_hard.css new file mode 100644 index 00000000000..8a106cadd77 --- /dev/null +++ b/lib/ace/theme/gruvbox_light_hard.css @@ -0,0 +1,159 @@ +.ace-gruvbox-light-hard .ace_gutter { + background: #f9f5d7; + color: rgb(155,151,135) +} + +.ace-gruvbox-light-hard .ace_print-margin { + width: 1px; + background: #e8e8e8 +} + +.ace-gruvbox-light-hard { + background-color: #f9f5d7; + color: rgba(60, 56, 54, 0.50) +} + +.ace-gruvbox-light-hard .ace_cursor { + color: #7c6f64 +} + +.ace-gruvbox-light-hard .ace_marker-layer .ace_selection { + background: #ebdbb2 +} + +.ace-gruvbox-light-hard.ace_multiselect .ace_selection.ace_start { + box-shadow: 0 0 3px 0px #f9f5d7; + border-radius: 2px +} + +.ace-gruvbox-light-hard .ace_marker-layer .ace_step { + background: rgb(198, 219, 174) +} + +.ace-gruvbox-light-hard .ace_marker-layer .ace_bracket { + margin: -1px 0 0 -1px; + border: 1px solid rgba(60, 56, 54, 0.15) +} + +.ace-gruvbox-light-hard .ace_marker-layer .ace_active-line { + background: #ebdbb2 +} + +.ace-gruvbox-light-hard .ace_gutter-active-line { + background-color: #ebdbb2 +} + +.ace-gruvbox-light-hard .ace_marker-layer .ace_selected-word { + border: 1px solid #ebdbb2 +} + +.ace-gruvbox-light-hard .ace_fold { + background-color: #79740e; + border-color: rgba(60, 56, 54, 0.50) +} + +.ace-gruvbox-light-hard .ace_keyword { + color: #9d0006 +} + +.ace-gruvbox-light-hard .ace_keyword.ace_operator { + color: #427b58 +} + +.ace-gruvbox-light-hard .ace_keyword.ace_other.ace_unit { + color: #b16286 +} + +.ace-gruvbox-light-hard .ace_constant { + color: #8f3f71 +} + +.ace-gruvbox-light-hard .ace_constant.ace_numeric { + color: #8f3f71 +} + +.ace-gruvbox-light-hard .ace_constant.ace_character.ace_escape { + color: #9d0006 +} + +.ace-gruvbox-light-hard .ace_constant.ace_other { + color: #8f3f71 +} + +.ace-gruvbox-light-hard .ace_support.ace_function { + color: #427b58 +} + +.ace-gruvbox-light-hard .ace_support.ace_constant { + color: #8f3f71 +} + +.ace-gruvbox-light-hard .ace_support.ace_constant.ace_property-value { + color: #1d2021 +} + +.ace-gruvbox-light-hard .ace_support.ace_class { + color: #b57614 +} + +.ace-gruvbox-light-hard .ace_support.ace_type { + color: #b57614 +} + +.ace-gruvbox-light-hard .ace_storage { + color: #9d0006 +} + +.ace-gruvbox-light-hard .ace_invalid { + color: #1d2021; + background-color: #9d0006 +} + +.ace-gruvbox-light-hard .ace_string { + color: #79740e +} + +.ace-gruvbox-light-hard .ace_string.ace_regexp { + color: #79740e +} + +.ace-gruvbox-light-hard .ace_comment { + font-style: italic; + color: #928374 +} + +.ace-gruvbox-light-hard .ace_variable { + color: #076678 +} + +.ace-gruvbox-light-hard .ace_variable.ace_language { + color: #8f3f71 +} + +.ace-gruvbox-light-hard .ace_variable.ace_parameter { + color: #1d2021 +} + +.ace-gruvbox-light-hard .ace_meta.ace_tag { + color: #1d2021 +} + +.ace-gruvbox-light-hard .ace_entity.ace_other.ace_attribute-name { + color: #b57614 +} + +.ace-gruvbox-light-hard .ace_entity.ace_name.ace_function { + color: #79740e +} + +.ace-gruvbox-light-hard .ace_entity.ace_name.ace_tag { + color: #076678 +} + +.ace-gruvbox-light-hard .ace_markup.ace_heading { + color: #79740e +} + +.ace-gruvbox-light-hard .ace_markup.ace_list { + color: #076678 +} \ No newline at end of file diff --git a/lib/ace/theme/gruvbox_light_hard.js b/lib/ace/theme/gruvbox_light_hard.js new file mode 100644 index 00000000000..e33217c61b4 --- /dev/null +++ b/lib/ace/theme/gruvbox_light_hard.js @@ -0,0 +1,39 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-gruvbox-light-hard"; +exports.cssText = require("../requirejs/text!./gruvbox_light_hard.css"); + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/tool/tmtheme.js b/tool/tmtheme.js index c3b5ef16443..397951b1477 100755 --- a/tool/tmtheme.js +++ b/tool/tmtheme.js @@ -288,6 +288,8 @@ var themes = { "solarized_light": "Solarized-light", "katzenmilch": "Katzenmilch", "kuroir": "Kuroir Theme", + "gruvbox_dark_hard": "gruvboxDarkHard", + "gruvbox_light_hard": "gruvboxLightHard", //"textmate": "Textmate (Mac Classic)", "tomorrow": "Tomorrow", "tomorrow_night": "Tomorrow-Night", diff --git a/tool/tmthemes/gruvboxDarkHard.tmTheme b/tool/tmthemes/gruvboxDarkHard.tmTheme new file mode 100644 index 00000000000..64c80d32a27 --- /dev/null +++ b/tool/tmthemes/gruvboxDarkHard.tmTheme @@ -0,0 +1,1509 @@ + + + + + comment + Based on gruvbox for Vim (https://github.com/morhetz/gruvbox) + originalAuthor + Pavel Pertsev (https://github.com/morhetz) + author + Brian Reilly (https://github.com/Briles/gruvbox) + name + gruvbox (Dark) (Hard) + colorSpaceName + sRGB + settings + + + settings + + background + #1d2021 + caret + #a89984 + foreground + #ebdbb280 + invisibles + #ebdbb226 + lineHighlight + #3c3836 + selection + #3c3836 + inactiveSelection + #3c3836 + guide + #ebdbb226 + activeGuide + #ebdbb280 + stackGuide + #ebdbb240 + bracketContentsOptions + underline + bracketContentsForeground + #bdae93 + bracketsOptions + underline + bracketsForeground + #bdae93 + gutterForeground + #928374 + highlight + #f9f5d7 + highlightForeground + #f9f5d7 + findHighlight + #d79921 + findHighlightForeground + #1d2021 + tagsOptions + underline + selectionBorder + #3c3836 + popupCss + + html { + background-color: #111313; + color: #f9f5d7; + padding: 12px; + } + + a { + color: #8ec07c; + } + + .error, .deleted { + color: #fb4934; + } + + .success, .inserted, .name { + color: #b8bb26; + } + + .warning, .modified { + color: #fabd2f; + } + + .type { + color: #fabd2f; + font-style: italic; + } + + .param { + color: #f9f5d7; + } + + .current { + text-decoration: underline; + } + + + + + name + Text and Source Base Colors + scope + meta.group, meta.method-call.source.cs, meta.method.attribute.source.cs, meta.method.body.java, meta.method.body.source.cs, meta.method.source.cs, none, source, text + settings + + foreground + #f9f5d7 + + + + name + Punctuation + scope + entity.quasi.element meta.group.braces, keyword.operator keyword.operator.neon, keyword.operator operator.neon, keyword.operator.accessor, keyword.other.accessor, meta.attribute-selector keyword.operator.stylus, meta.brace, meta.delimiter, meta.group.braces, meta.punctuation.separator, meta.separator, punctuation + settings + + foreground + #f9f5d7 + + + + name + Comments + scope + comment, comment text, markup.strikethrough, punctuation.definition.comment, punctuation.whitespace.comment, string.comment, text.cancelled + settings + + fontStyle + italic + foreground + #928374 + + + + name + Keywords Inside Comments + scope + comment.keyword, comment.keyword.punctuation + settings + + foreground + #d5c4a1 + + + + name + DocBlockr & Other Keywords Inside Comments + scope + comment.parameter, comment.punctuation, comment.string, comment.type, keyword.other.phpdoc.php, punctuation.definition.keyword.javadoc, source.groovy keyword.other.documentation, source.java keyword.other.documentation, storage.type.annotation.coffeescript, storage.type.class.jsdoc + settings + + foreground + #bdae93 + + + + name + Entity + scope + constant.language.name, entity.name.type, entity.other.inherited-class + settings + + foreground + #fabd2f + + + + name + Template String Punctuation + scope + constant.other.placeholder, entity.name.tag.mustache, entity.tag.tagbraces, punctuation.definition.string.template, punctuation.definition.template-expression, punctuation.quasi, punctuation.section.embedded, string.interpolated, variable.other.interpolation.scss + settings + + foreground + #8ec07c + + + + name + Keywords + scope + js.embedded.control.flow keyword.operator.js, keyword, keyword.control, keyword.operator.logical.python, meta.at-rule.media support.function.misc, meta.prolog.haml, meta.tag.sgml.doctype.html, storage.type.function.jade, storage.type.function.pug, storage.type.import.haxe, storage.type.import.include.jade, storage.type.import.include.pug, support.keyword.timing-direction, variable.documentroot + settings + + foreground + #fb4934 + + + + name + CSS At-Rule Punctuation (@) & At-Rule Vendor Prefixes + scope + keyword.control.at-rule support.type.property-vendor, punctuation.definition.keyword + settings + + foreground + #cc241d + + + + name + Operators + scope + keyword.control.new, keyword.control.operator, keyword.operator, keyword.other.arrow, keyword.other.double-colon, punctuation.operator + settings + + foreground + #8ec07c + + + + name + Constants Punctuation + scope + constant.other.color punctuation.definition.constant, constant.other.symbol punctuation.definition.constant, constant.other.unit, keyword.other.unit, punctuation.section.flowtype, support.constant.unicode-range.prefix + settings + + foreground + #b16286 + + + + name + Storage + scope + storage, storage.type.annotation, storage.type.primitive + settings + + foreground + #fb4934 + + + + scope + storage.modifier.import, storage.modifier.package, storage.type.import, variable.import, variable.package + settings + + foreground + #f9f5d7 + + + + name + Function Keyword + scope + entity.quasi.tag.name, meta.function storage.type.matlab, storage.type.function + settings + + foreground + #8ec07c + + + + name + Variables + scope + entity.name.val.declaration, entity.name.variable, meta.definition.variable, storage.type.variable, support.type.custom-property, support.type.variable-name, variable, variable.interpolation variable, variable.other.interpolation variable, variable.parameter.dosbatch, variable.parameter.output.function.matlab, variable.parameter.sass + settings + + foreground + #83a598 + + + + name + Variable - Punctuation + scope + keyword.other.custom-property.prefix, punctuation.definition.custom-property, punctuation.definition.variable, support.constant.custom-property-name.prefix, variable.interpolation, variable.other.dollar punctuation.dollar, variable.other.object.dollar punctuation.dollar + settings + + foreground + #458588 + + + + name + Function Declaration - Punctuation + scope + entity.name.function punctuation.dollar + settings + + foreground + #98971a + + + + name + Object Properties + scope + meta.property.object + settings + + foreground + #f9f5d7 + + + + name + Object Literal Properties + scope + constant.other.object.key string, meta.object-literal.key + settings + + foreground + #f9f5d7 + + + + name + Parameters + scope + meta.parameters, variable.parameter + settings + + foreground + #f9f5d7 + + + + name + SASS Import URL + scope + variable.parameter.url + settings + + foreground + #b8bb26 + + + + name + Language Constants + scope + constant, constant.numeric, constant.other, constant.other.color, constant.other.symbol, support.constant, support.constant.color, support.constant.font-name, support.constant.media, support.constant.prototype, variable.language + settings + + foreground + #d3869b + + + + name + Language Constants Punctuation + scope + variable.language punctuation.definition.variable + settings + + foreground + #b16286 + + + + name + User-Defined Constants + scope + entity.name.constant, variable.other.constant + settings + + foreground + #fabd2f + + + + name + Escaped Characters + scope + constant.character.escape, constant.character.escaped, constant.character.quoted, constant.other.character-class.escape + settings + + foreground + #fb4934 + + + + name + Invalids and Illegals + scope + invalid + settings + + foreground + #f9f5d7 + background + #fb4934 + + + + name + Inner Scopes of Invalids and Illegals + scope + invalid keyword.other.custom-property.prefix, invalid support.type.custom-property.name + settings + + foreground + #f9f5d7 + + + + name + Errors + scope + message.error + settings + + foreground + #fb4934 + + + + name + Strings + scope + meta.object-literal.key string, string + settings + + foreground + #b8bb26 + + + + name + JSON Keys + scope + meta.structure.dictionary.key.json string + settings + + foreground + #83a598 + + + + name + Regular Expressions Text + scope + source.regexp, string.regexp + settings + + foreground + #b8bb26 + + + + name + Regular Expressions Start & End Punctuation + scope + string.regexp punctuation.definition.string + settings + + foreground + #bdae93 + + + + name + Regular Expressions Character Class Punctuation ([]) + scope + keyword.control.set.regexp, punctuation.definition.character-class, string.regexp.character-class.ruby + settings + + foreground + #d3869b + + + + name + Regular Expressions Capturing Group + scope + string.regexp.group + settings + + foreground + #f9f5d7 + + + + name + Regular Expressions Assertions + scope + constant.other.assertion.regexp, punctuation.definition.group.assertion.regexp, punctuation.definition.group.capture.regexp + settings + + foreground + #83a598 + + + + name + Regular Expressions Character Class + scope + constant.other.character-class.escape.backslash.regexp, keyword.control.character-class.regexp, string.regexp.character-class constant.character.escape + settings + + foreground + #fabd2f + + + + name + Regular Expressions Quantifiers & Operators + scope + string.regexp.arbitrary-repetition, string.regexp.arbitrary-repetition punctuation + settings + + foreground + #8ec07c + + + + name + Hyperlinks + scope + constant.other.reference.link, string.other.link + settings + + foreground + #8ec07c + + + + name + Hyperlink Punctuation + scope + meta.image.inline punctuation.definition.string, meta.link.inline punctuation.definition.string, meta.link.reference punctuation.definition.constant, meta.link.reference.literal punctuation.definition.constant, meta.link.reference.literal punctuation.definition.string + settings + + foreground + #689d6a + + + + name + Markup Tag Punctuation + scope + punctuation.definition.tag + settings + + foreground + #83a598 + + + + name + Markdown Heading + scope + markup.heading + settings + + foreground + #b8bb26 + + + + name + Markdown Heading Punctuation + scope + punctuation.definition.heading, punctuation.definition.identity + settings + + foreground + #98971a + + + + name + Markdown Bold Text + scope + markup.bold + settings + + foreground + #fe8019 + fontStyle + bold + + + + name + Markdown Bold Text Punctuation + scope + punctuation.definition.bold + settings + + foreground + #d65d0e + fontStyle + bold + + + + name + Markdown Italic Text + scope + markup.italic + settings + + foreground + #fb4934 + fontStyle + italic + + + + name + Markdown Italic Text Punctuation + scope + punctuation.definition.italic + settings + + foreground + #cc241d + fontStyle + italic + + + + name + Markdown Inline Code + scope + markup.raw.inline + settings + + foreground + #fabd2f + + + + name + Markdown Inline Code Punctuation + scope + markup.raw.inline punctuation.definition.raw + settings + + foreground + #d79921 + + + + name + Markdown Quoted + scope + markup.quote + settings + + foreground + #d3869b + + + + name + Markdown Quoted Punctuation + scope + markup.quote punctuation.definition.blockquote + settings + + foreground + #b16286 + + + + name + Markdown List + scope + markup.list + settings + + foreground + #83a598 + + + + name + Markdown List Punctuation + scope + markup.list punctuation.definition.list_item + settings + + foreground + #458588 + + + + name + Markdown Separators + scope + meta.separator.markdown + settings + + foreground + #928374 + + + + name + Support + scope + meta.function-call.constructor variable.type, support.class, support.type, variable.other.class + settings + + foreground + #fabd2f + + + + name + Supporting Type - Dollar Punctuation + scope + support.class punctuation.dollar + settings + + foreground + #d79921 + + + + name + Function Calls + scope + entity.name.function.jade, entity.name.function.pug, keyword.other.special-method, meta.function-call variable.function, meta.function-call variable.other.dollar.only punctuation.dollar, support.function + settings + + foreground + #8ec07c + + + + name + Method Calls + scope + meta.function-call.method support.function, meta.function-call.method variable.function, meta.function-call.static variable.function, meta.method-call, meta.method-call support.function, meta.method-call variable.function, support.function.mutator + settings + + foreground + #689d6a + + + + name + Special Variables + scope + support.module + settings + + foreground + #d3869b + + + + name + Entities + scope + entity.name.accessor, entity.name.function, entity.name.label, entity.name.section + settings + + foreground + #b8bb26 + + + + name + Modules + scope + entity.name.module + settings + + foreground + #fe8019 + + + + name + HTML & CSS ID + scope + constant.id.tag, entity.name.tag.id, entity.other.attribute-name.id + settings + + foreground + #fe8019 + + + + name + HTML & CSS ID Punctuation (#) + scope + entity.other.attribute-name.id punctuation.definition.entity + settings + + foreground + #d65d0e + + + + name + HTML & CSS Class + scope + entity.name.tag.class, entity.other.attribute-name.class + settings + + foreground + #fabd2f + + + + name + HTML & CSS Class Punctuation (.) + scope + entity.other.attribute-name.class punctuation.definition.entity + settings + + foreground + #d79921 + + + + name + CSS Attribute Selector Attribute Name + scope + meta.attribute-selector entity.other.attribute-name + settings + + foreground + #d79921 + + + + name + HTML & XML Entity Punctuation + scope + constant.character.entity punctuation.definition.constant, constant.character.entity punctuation.definition.entity + settings + + foreground + #b16286 + + + + scope + entity.name.class, entity.name.type.class + settings + + foreground + #fabd2f + + + + name + Markup Tag + scope + entity.name.function.neon, entity.name.namespace.wildcard, entity.name.tag, entity.tag, keyword.control.untitled, keyword.doctype.xml, keyword.operator support.other.neon, punctuation.definition.prolog.haml, source.less keyword.control.html.elements + settings + + foreground + #83a598 + + + + name + HTML Attribute Names + scope + entity.name.attribute-name, entity.other.attribute-name, meta.section.attributes.haml constant.other.symbol.ruby + settings + + foreground + #fabd2f + + + + name + CSS Pseudo Elements/Classes & Vendor Prefixes + scope + entity.other.attribute-name.placeholder punctuation.definition.entity, entity.other.attribute-name.pseudo-class, entity.other.attribute-name.pseudo-element, entity.other.attribute-name.tag.pseudo-class, entity.other.attribute-name.tag.pseudo-element, entity.other.pseudo-class, entity.other.pseudo-element, support.type.vendor-prefix + settings + + foreground + #d79921 + + + + name + CSS Animations / Keyframes + scope + entity.function-name.stylus, entity.other.animation-keyframe.stylus, entity.other.animation-name, keyword.language.function.misc.stylus, meta.at-rule.keyframes entity.name.function, variable.other.animation-name + settings + + foreground + #8ec07c + + + + name + Author-Defined Names + scope + entity.other.namespace-prefix + settings + + foreground + #8ec07c + + + + scope + meta.class.body, meta.tag + settings + + foreground + #f9f5d7 + + + + name + Markdown Image & Hyperlink + scope + meta.image, meta.link + settings + + foreground + #d3869b + + + + name + Markdown Image & Hyperlink Punctuation + scope + meta.image punctuation.definition.metadata, meta.link punctuation.definition.metadata + settings + + foreground + #b16286 + + + + scope + meta.require + settings + + foreground + #b8bb26 + + + + name + Function Call Braces + scope + constant.name.attribute.tag.jade, constant.name.attribute.tag.pug, meta.brace.round, meta.function-call meta.group punctuation.definition.group, punctuation.definition.method-parameters, punctuation.definition.parameters + settings + + foreground + #bdae93 + + + + name + CSS Property Names + scope + meta.property-name, support.type.property-name, support.type.shape.definition support.constant.property-value + settings + + foreground + #b8bb26 + + + + name + CSS Property Name Vendor Prefixes + scope + meta.property-name support.type.vendor-prefix, support.type.property-name.media support.type.vendor-prefix + settings + + foreground + #98971a + + + + name + CSS Property Values + scope + constant.string.sass, meta.property-value, support.constant.property-value + settings + + foreground + #f9f5d7 + + + + name + CSS Property Value Vendor Prefixes + scope + meta.property-value support.type.vendor-prefix + settings + + foreground + #bdae93 + + + + name + Diff Foreground Text + scope + source.diff + settings + + foreground + #a89984 + + + + name + Diff Header Text From + scope + meta.diff.header.from-file + settings + + foreground + #83a598 + + + + name + Diff Header Text From Punctuation + scope + punctuation.definition.from-file + settings + + foreground + #458588 + + + + name + Diff Header Text To + scope + meta.diff.header.to-file + settings + + foreground + #d3869b + + + + name + Diff Header Text To Punctuation + scope + punctuation.definition.to-file + settings + + foreground + #b16286 + + + + name + Diff Additions & Deletions Stats + scope + meta.diff.range, meta.toc-list.line-number + settings + + foreground + #fabd2f + + + + name + Diff Additions & Deletions Stats Punctuation + scope + punctuation.definition.range.diff + settings + + foreground + #d79921 + + + + name + FiF Line Number + scope + constant.numeric.line-number + settings + + foreground + #928374 + + + + name + FiF Line Number Matched + scope + constant.numeric.line-number.match + settings + + foreground + #8ec07c + + + + name + FiF Filename + scope + entity.name.filename + settings + + foreground + #b8bb26 + + + + name + GitGutter & Diff Deleted + scope + markup.deleted, punctuation.definition.deleted + settings + + foreground + #fb4934 + + + + name + GitGutter & Diff Inserted + scope + markup.inserted, punctuation.definition.inserted + settings + + foreground + #b8bb26 + + + + name + GitGutter & Diff Changed + scope + markup.changed, punctuation.definition.changed + settings + + foreground + #fabd2f + + + + name + GitGutter ignored + scope + markup.ignored + settings + + foreground + #928374 + + + + name + GitGutter untracked + scope + markup.untracked + settings + + foreground + #928374 + + + + name + Bracket Tag + scope + brackethighlighter.tag + settings + + foreground + #bdae93 + + + + name + Bracket Curly + scope + brackethighlighter.curly + settings + + foreground + #bdae93 + + + + name + Bracket Round + scope + brackethighlighter.round + settings + + foreground + #bdae93 + + + + name + Bracket Square + scope + brackethighlighter.square + settings + + foreground + #bdae93 + + + + name + Bracket Angle + scope + brackethighlighter.angle + settings + + foreground + #bdae93 + + + + name + Bracket Quote + scope + brackethighlighter.quote + settings + + foreground + #bdae93 + + + + name + Bracket Unmatched + scope + brackethighlighter.unmatched + settings + + foreground + #fb4934 + + + + name + SublimeLinter Error + scope + sublimelinter.mark.error + settings + + foreground + #fb4934 + + + + name + SublimeLinter Gutter Mark + scope + sublimelinter.gutter-mark + settings + + foreground + #928374 + + + + name + SublimeLinter Warning + scope + sublimelinter.mark.warning + settings + + foreground + #fabd2f + + + + name + HexViewer Upper Byte Nibble + scope + raw.nibble.upper + settings + + foreground + #f9f5d7 + + + + name + HexViewer Lower Byte Nibble + scope + raw.nibble.lower + settings + + foreground + #f9f5d7 + + + + name + HexViewer Highlight + scope + hexviewer.highlight + settings + + foreground + #1d2021 + background + #fabd2f + + + + name + HexViewer Edited Highlight + scope + hexviewer.highlight.edited + settings + + foreground + #1d2021 + background + #fe8019 + + + + name + Raw New Line: Carriage Return + scope + glyph.carriage-return + settings + + foreground + #ebdbb226 + + + + name + Raw New Line: New Line Glyph + scope + glyph.new-line + settings + + foreground + #ebdbb226 + + + + name + PlainTasks: Header + scope + keyword.control.header.todo + settings + + foreground + #b8bb26 + background + #2e3234 + + + + name + PlainTasks: Notes + scope + notes.todo + settings + + foreground + #bdae93 + + + + name + PlainTasks: Punctuation + scope + text.todo punctuation.definition.bold, text.todo punctuation.definition.italic + settings + + foreground + #7c6f64 + + + + name + PlainTasks: Task Pending + scope + meta.item.todo.pending + settings + + foreground + #f9f5d7 + + + + name + PlainTasks: Task Pending Punctuation + scope + punctuation.definition.bullet.pending.todo + settings + + foreground + #928374 + + + + name + PlainTasks: Task Completed Punctuation + scope + punctuation.definition.bullet.completed.todo + settings + + foreground + #8ec07c + + + + name + PlainTasks: Task Cancelled Punctuation + scope + punctuation.definition.bullet.cancelled.todo + settings + + foreground + #fb4934 + + + + name + PlainTasks: Tag Critical + scope + string.other.tag.todo.critical + settings + + foreground + #fb4934 + fontStyle + bold + + + + name + PlainTasks: Tag High + scope + string.other.tag.todo.high + settings + + foreground + #fe8019 + fontStyle + bold + + + + name + PlainTasks: Tag Low + scope + string.other.tag.todo.low + settings + + foreground + #83a598 + fontStyle + bold + + + + name + PlainTasks: Tag Today + scope + string.other.tag.todo.today + settings + + foreground + #fabd2f + fontStyle + bold + + + + name + PlainTasks: Tag + scope + meta.tag.todo + settings + + foreground + #d3869b + + + + name + PlainTasks: URL + scope + punctuation.definition.url, todo.url + settings + + foreground + #83a598 + + + + name + PlainTasks: Separator + scope + meta.punctuation.archive.todo, meta.punctuation.separator.todo + settings + + fontStyle + italic + foreground + #928374 + + + + + \ No newline at end of file diff --git a/tool/tmthemes/gruvboxLightHard.tmTheme b/tool/tmthemes/gruvboxLightHard.tmTheme new file mode 100644 index 00000000000..c75d15f7689 --- /dev/null +++ b/tool/tmthemes/gruvboxLightHard.tmTheme @@ -0,0 +1,1509 @@ + + + + + comment + Based on gruvbox for Vim (https://github.com/morhetz/gruvbox) + originalAuthor + Pavel Pertsev (https://github.com/morhetz) + author + Brian Reilly (https://github.com/Briles/gruvbox) + name + gruvbox (Light) (Hard) + colorSpaceName + sRGB + settings + + + settings + + background + #f9f5d7 + caret + #7c6f64 + foreground + #3c383680 + invisibles + #3c383626 + lineHighlight + #ebdbb2 + selection + #ebdbb2 + inactiveSelection + #ebdbb2 + guide + #3c383626 + activeGuide + #3c383680 + stackGuide + #3c383640 + bracketContentsOptions + underline + bracketContentsForeground + #665c54 + bracketsOptions + underline + bracketsForeground + #665c54 + gutterForeground + #928374 + highlight + #1d2021 + highlightForeground + #1d2021 + findHighlight + #d79921 + findHighlightForeground + #f9f5d7 + tagsOptions + underline + selectionBorder + #ebdbb2 + popupCss + + html { + background-color: #f6efc1; + color: #1d2021; + padding: 12px; + } + + a { + color: #427b58; + } + + .error, .deleted { + color: #9d0006; + } + + .success, .inserted, .name { + color: #79740e; + } + + .warning, .modified { + color: #b57614; + } + + .type { + color: #b57614; + font-style: italic; + } + + .param { + color: #1d2021; + } + + .current { + text-decoration: underline; + } + + + + + name + Text and Source Base Colors + scope + meta.group, meta.method-call.source.cs, meta.method.attribute.source.cs, meta.method.body.java, meta.method.body.source.cs, meta.method.source.cs, none, source, text + settings + + foreground + #1d2021 + + + + name + Punctuation + scope + entity.quasi.element meta.group.braces, keyword.operator keyword.operator.neon, keyword.operator operator.neon, keyword.operator.accessor, keyword.other.accessor, meta.attribute-selector keyword.operator.stylus, meta.brace, meta.delimiter, meta.group.braces, meta.punctuation.separator, meta.separator, punctuation + settings + + foreground + #1d2021 + + + + name + Comments + scope + comment, comment text, markup.strikethrough, punctuation.definition.comment, punctuation.whitespace.comment, string.comment, text.cancelled + settings + + fontStyle + italic + foreground + #928374 + + + + name + Keywords Inside Comments + scope + comment.keyword, comment.keyword.punctuation + settings + + foreground + #504945 + + + + name + DocBlockr & Other Keywords Inside Comments + scope + comment.parameter, comment.punctuation, comment.string, comment.type, keyword.other.phpdoc.php, punctuation.definition.keyword.javadoc, source.groovy keyword.other.documentation, source.java keyword.other.documentation, storage.type.annotation.coffeescript, storage.type.class.jsdoc + settings + + foreground + #665c54 + + + + name + Entity + scope + constant.language.name, entity.name.type, entity.other.inherited-class + settings + + foreground + #b57614 + + + + name + Template String Punctuation + scope + constant.other.placeholder, entity.name.tag.mustache, entity.tag.tagbraces, punctuation.definition.string.template, punctuation.definition.template-expression, punctuation.quasi, punctuation.section.embedded, string.interpolated, variable.other.interpolation.scss + settings + + foreground + #427b58 + + + + name + Keywords + scope + js.embedded.control.flow keyword.operator.js, keyword, keyword.control, keyword.operator.logical.python, meta.at-rule.media support.function.misc, meta.prolog.haml, meta.tag.sgml.doctype.html, storage.type.function.jade, storage.type.function.pug, storage.type.import.haxe, storage.type.import.include.jade, storage.type.import.include.pug, support.keyword.timing-direction, variable.documentroot + settings + + foreground + #9d0006 + + + + name + CSS At-Rule Punctuation (@) & At-Rule Vendor Prefixes + scope + keyword.control.at-rule support.type.property-vendor, punctuation.definition.keyword + settings + + foreground + #cc241d + + + + name + Operators + scope + keyword.control.new, keyword.control.operator, keyword.operator, keyword.other.arrow, keyword.other.double-colon, punctuation.operator + settings + + foreground + #427b58 + + + + name + Constants Punctuation + scope + constant.other.color punctuation.definition.constant, constant.other.symbol punctuation.definition.constant, constant.other.unit, keyword.other.unit, punctuation.section.flowtype, support.constant.unicode-range.prefix + settings + + foreground + #b16286 + + + + name + Storage + scope + storage, storage.type.annotation, storage.type.primitive + settings + + foreground + #9d0006 + + + + scope + storage.modifier.import, storage.modifier.package, storage.type.import, variable.import, variable.package + settings + + foreground + #1d2021 + + + + name + Function Keyword + scope + entity.quasi.tag.name, meta.function storage.type.matlab, storage.type.function + settings + + foreground + #427b58 + + + + name + Variables + scope + entity.name.val.declaration, entity.name.variable, meta.definition.variable, storage.type.variable, support.type.custom-property, support.type.variable-name, variable, variable.interpolation variable, variable.other.interpolation variable, variable.parameter.dosbatch, variable.parameter.output.function.matlab, variable.parameter.sass + settings + + foreground + #076678 + + + + name + Variable - Punctuation + scope + keyword.other.custom-property.prefix, punctuation.definition.custom-property, punctuation.definition.variable, support.constant.custom-property-name.prefix, variable.interpolation, variable.other.dollar punctuation.dollar, variable.other.object.dollar punctuation.dollar + settings + + foreground + #458588 + + + + name + Function Declaration - Punctuation + scope + entity.name.function punctuation.dollar + settings + + foreground + #98971a + + + + name + Object Properties + scope + meta.property.object + settings + + foreground + #1d2021 + + + + name + Object Literal Properties + scope + constant.other.object.key string, meta.object-literal.key + settings + + foreground + #1d2021 + + + + name + Parameters + scope + meta.parameters, variable.parameter + settings + + foreground + #1d2021 + + + + name + SASS Import URL + scope + variable.parameter.url + settings + + foreground + #79740e + + + + name + Language Constants + scope + constant, constant.numeric, constant.other, constant.other.color, constant.other.symbol, support.constant, support.constant.color, support.constant.font-name, support.constant.media, support.constant.prototype, variable.language + settings + + foreground + #8f3f71 + + + + name + Language Constants Punctuation + scope + variable.language punctuation.definition.variable + settings + + foreground + #b16286 + + + + name + User-Defined Constants + scope + entity.name.constant, variable.other.constant + settings + + foreground + #b57614 + + + + name + Escaped Characters + scope + constant.character.escape, constant.character.escaped, constant.character.quoted, constant.other.character-class.escape + settings + + foreground + #9d0006 + + + + name + Invalids and Illegals + scope + invalid + settings + + foreground + #1d2021 + background + #9d0006 + + + + name + Inner Scopes of Invalids and Illegals + scope + invalid keyword.other.custom-property.prefix, invalid support.type.custom-property.name + settings + + foreground + #1d2021 + + + + name + Errors + scope + message.error + settings + + foreground + #9d0006 + + + + name + Strings + scope + meta.object-literal.key string, string + settings + + foreground + #79740e + + + + name + JSON Keys + scope + meta.structure.dictionary.key.json string + settings + + foreground + #076678 + + + + name + Regular Expressions Text + scope + source.regexp, string.regexp + settings + + foreground + #79740e + + + + name + Regular Expressions Start & End Punctuation + scope + string.regexp punctuation.definition.string + settings + + foreground + #665c54 + + + + name + Regular Expressions Character Class Punctuation ([]) + scope + keyword.control.set.regexp, punctuation.definition.character-class, string.regexp.character-class.ruby + settings + + foreground + #8f3f71 + + + + name + Regular Expressions Capturing Group + scope + string.regexp.group + settings + + foreground + #1d2021 + + + + name + Regular Expressions Assertions + scope + constant.other.assertion.regexp, punctuation.definition.group.assertion.regexp, punctuation.definition.group.capture.regexp + settings + + foreground + #076678 + + + + name + Regular Expressions Character Class + scope + constant.other.character-class.escape.backslash.regexp, keyword.control.character-class.regexp, string.regexp.character-class constant.character.escape + settings + + foreground + #b57614 + + + + name + Regular Expressions Quantifiers & Operators + scope + string.regexp.arbitrary-repetition, string.regexp.arbitrary-repetition punctuation + settings + + foreground + #427b58 + + + + name + Hyperlinks + scope + constant.other.reference.link, string.other.link + settings + + foreground + #427b58 + + + + name + Hyperlink Punctuation + scope + meta.image.inline punctuation.definition.string, meta.link.inline punctuation.definition.string, meta.link.reference punctuation.definition.constant, meta.link.reference.literal punctuation.definition.constant, meta.link.reference.literal punctuation.definition.string + settings + + foreground + #689d6a + + + + name + Markup Tag Punctuation + scope + punctuation.definition.tag + settings + + foreground + #076678 + + + + name + Markdown Heading + scope + markup.heading + settings + + foreground + #79740e + + + + name + Markdown Heading Punctuation + scope + punctuation.definition.heading, punctuation.definition.identity + settings + + foreground + #98971a + + + + name + Markdown Bold Text + scope + markup.bold + settings + + foreground + #af3a03 + fontStyle + bold + + + + name + Markdown Bold Text Punctuation + scope + punctuation.definition.bold + settings + + foreground + #d65d0e + fontStyle + bold + + + + name + Markdown Italic Text + scope + markup.italic + settings + + foreground + #9d0006 + fontStyle + italic + + + + name + Markdown Italic Text Punctuation + scope + punctuation.definition.italic + settings + + foreground + #cc241d + fontStyle + italic + + + + name + Markdown Inline Code + scope + markup.raw.inline + settings + + foreground + #b57614 + + + + name + Markdown Inline Code Punctuation + scope + markup.raw.inline punctuation.definition.raw + settings + + foreground + #d79921 + + + + name + Markdown Quoted + scope + markup.quote + settings + + foreground + #8f3f71 + + + + name + Markdown Quoted Punctuation + scope + markup.quote punctuation.definition.blockquote + settings + + foreground + #b16286 + + + + name + Markdown List + scope + markup.list + settings + + foreground + #076678 + + + + name + Markdown List Punctuation + scope + markup.list punctuation.definition.list_item + settings + + foreground + #458588 + + + + name + Markdown Separators + scope + meta.separator.markdown + settings + + foreground + #928374 + + + + name + Support + scope + meta.function-call.constructor variable.type, support.class, support.type, variable.other.class + settings + + foreground + #b57614 + + + + name + Supporting Type - Dollar Punctuation + scope + support.class punctuation.dollar + settings + + foreground + #d79921 + + + + name + Function Calls + scope + entity.name.function.jade, entity.name.function.pug, keyword.other.special-method, meta.function-call variable.function, meta.function-call variable.other.dollar.only punctuation.dollar, support.function + settings + + foreground + #427b58 + + + + name + Method Calls + scope + meta.function-call.method support.function, meta.function-call.method variable.function, meta.function-call.static variable.function, meta.method-call, meta.method-call support.function, meta.method-call variable.function, support.function.mutator + settings + + foreground + #689d6a + + + + name + Special Variables + scope + support.module + settings + + foreground + #8f3f71 + + + + name + Entities + scope + entity.name.accessor, entity.name.function, entity.name.label, entity.name.section + settings + + foreground + #79740e + + + + name + Modules + scope + entity.name.module + settings + + foreground + #af3a03 + + + + name + HTML & CSS ID + scope + constant.id.tag, entity.name.tag.id, entity.other.attribute-name.id + settings + + foreground + #af3a03 + + + + name + HTML & CSS ID Punctuation (#) + scope + entity.other.attribute-name.id punctuation.definition.entity + settings + + foreground + #d65d0e + + + + name + HTML & CSS Class + scope + entity.name.tag.class, entity.other.attribute-name.class + settings + + foreground + #b57614 + + + + name + HTML & CSS Class Punctuation (.) + scope + entity.other.attribute-name.class punctuation.definition.entity + settings + + foreground + #d79921 + + + + name + CSS Attribute Selector Attribute Name + scope + meta.attribute-selector entity.other.attribute-name + settings + + foreground + #d79921 + + + + name + HTML & XML Entity Punctuation + scope + constant.character.entity punctuation.definition.constant, constant.character.entity punctuation.definition.entity + settings + + foreground + #b16286 + + + + scope + entity.name.class, entity.name.type.class + settings + + foreground + #b57614 + + + + name + Markup Tag + scope + entity.name.function.neon, entity.name.namespace.wildcard, entity.name.tag, entity.tag, keyword.control.untitled, keyword.doctype.xml, keyword.operator support.other.neon, punctuation.definition.prolog.haml, source.less keyword.control.html.elements + settings + + foreground + #076678 + + + + name + HTML Attribute Names + scope + entity.name.attribute-name, entity.other.attribute-name, meta.section.attributes.haml constant.other.symbol.ruby + settings + + foreground + #b57614 + + + + name + CSS Pseudo Elements/Classes & Vendor Prefixes + scope + entity.other.attribute-name.placeholder punctuation.definition.entity, entity.other.attribute-name.pseudo-class, entity.other.attribute-name.pseudo-element, entity.other.attribute-name.tag.pseudo-class, entity.other.attribute-name.tag.pseudo-element, entity.other.pseudo-class, entity.other.pseudo-element, support.type.vendor-prefix + settings + + foreground + #d79921 + + + + name + CSS Animations / Keyframes + scope + entity.function-name.stylus, entity.other.animation-keyframe.stylus, entity.other.animation-name, keyword.language.function.misc.stylus, meta.at-rule.keyframes entity.name.function, variable.other.animation-name + settings + + foreground + #427b58 + + + + name + Author-Defined Names + scope + entity.other.namespace-prefix + settings + + foreground + #427b58 + + + + scope + meta.class.body, meta.tag + settings + + foreground + #1d2021 + + + + name + Markdown Image & Hyperlink + scope + meta.image, meta.link + settings + + foreground + #8f3f71 + + + + name + Markdown Image & Hyperlink Punctuation + scope + meta.image punctuation.definition.metadata, meta.link punctuation.definition.metadata + settings + + foreground + #b16286 + + + + scope + meta.require + settings + + foreground + #79740e + + + + name + Function Call Braces + scope + constant.name.attribute.tag.jade, constant.name.attribute.tag.pug, meta.brace.round, meta.function-call meta.group punctuation.definition.group, punctuation.definition.method-parameters, punctuation.definition.parameters + settings + + foreground + #665c54 + + + + name + CSS Property Names + scope + meta.property-name, support.type.property-name, support.type.shape.definition support.constant.property-value + settings + + foreground + #79740e + + + + name + CSS Property Name Vendor Prefixes + scope + meta.property-name support.type.vendor-prefix, support.type.property-name.media support.type.vendor-prefix + settings + + foreground + #98971a + + + + name + CSS Property Values + scope + constant.string.sass, meta.property-value, support.constant.property-value + settings + + foreground + #1d2021 + + + + name + CSS Property Value Vendor Prefixes + scope + meta.property-value support.type.vendor-prefix + settings + + foreground + #665c54 + + + + name + Diff Foreground Text + scope + source.diff + settings + + foreground + #7c6f64 + + + + name + Diff Header Text From + scope + meta.diff.header.from-file + settings + + foreground + #076678 + + + + name + Diff Header Text From Punctuation + scope + punctuation.definition.from-file + settings + + foreground + #458588 + + + + name + Diff Header Text To + scope + meta.diff.header.to-file + settings + + foreground + #8f3f71 + + + + name + Diff Header Text To Punctuation + scope + punctuation.definition.to-file + settings + + foreground + #b16286 + + + + name + Diff Additions & Deletions Stats + scope + meta.diff.range, meta.toc-list.line-number + settings + + foreground + #b57614 + + + + name + Diff Additions & Deletions Stats Punctuation + scope + punctuation.definition.range.diff + settings + + foreground + #d79921 + + + + name + FiF Line Number + scope + constant.numeric.line-number + settings + + foreground + #928374 + + + + name + FiF Line Number Matched + scope + constant.numeric.line-number.match + settings + + foreground + #427b58 + + + + name + FiF Filename + scope + entity.name.filename + settings + + foreground + #79740e + + + + name + GitGutter & Diff Deleted + scope + markup.deleted, punctuation.definition.deleted + settings + + foreground + #9d0006 + + + + name + GitGutter & Diff Inserted + scope + markup.inserted, punctuation.definition.inserted + settings + + foreground + #79740e + + + + name + GitGutter & Diff Changed + scope + markup.changed, punctuation.definition.changed + settings + + foreground + #b57614 + + + + name + GitGutter ignored + scope + markup.ignored + settings + + foreground + #928374 + + + + name + GitGutter untracked + scope + markup.untracked + settings + + foreground + #928374 + + + + name + Bracket Tag + scope + brackethighlighter.tag + settings + + foreground + #665c54 + + + + name + Bracket Curly + scope + brackethighlighter.curly + settings + + foreground + #665c54 + + + + name + Bracket Round + scope + brackethighlighter.round + settings + + foreground + #665c54 + + + + name + Bracket Square + scope + brackethighlighter.square + settings + + foreground + #665c54 + + + + name + Bracket Angle + scope + brackethighlighter.angle + settings + + foreground + #665c54 + + + + name + Bracket Quote + scope + brackethighlighter.quote + settings + + foreground + #665c54 + + + + name + Bracket Unmatched + scope + brackethighlighter.unmatched + settings + + foreground + #9d0006 + + + + name + SublimeLinter Error + scope + sublimelinter.mark.error + settings + + foreground + #9d0006 + + + + name + SublimeLinter Gutter Mark + scope + sublimelinter.gutter-mark + settings + + foreground + #928374 + + + + name + SublimeLinter Warning + scope + sublimelinter.mark.warning + settings + + foreground + #b57614 + + + + name + HexViewer Upper Byte Nibble + scope + raw.nibble.upper + settings + + foreground + #1d2021 + + + + name + HexViewer Lower Byte Nibble + scope + raw.nibble.lower + settings + + foreground + #1d2021 + + + + name + HexViewer Highlight + scope + hexviewer.highlight + settings + + foreground + #f9f5d7 + background + #b57614 + + + + name + HexViewer Edited Highlight + scope + hexviewer.highlight.edited + settings + + foreground + #f9f5d7 + background + #af3a03 + + + + name + Raw New Line: Carriage Return + scope + glyph.carriage-return + settings + + foreground + #3c383626 + + + + name + Raw New Line: New Line Glyph + scope + glyph.new-line + settings + + foreground + #3c383626 + + + + name + PlainTasks: Header + scope + keyword.control.header.todo + settings + + foreground + #79740e + background + #fefdf6 + + + + name + PlainTasks: Notes + scope + notes.todo + settings + + foreground + #665c54 + + + + name + PlainTasks: Punctuation + scope + text.todo punctuation.definition.bold, text.todo punctuation.definition.italic + settings + + foreground + #a89984 + + + + name + PlainTasks: Task Pending + scope + meta.item.todo.pending + settings + + foreground + #1d2021 + + + + name + PlainTasks: Task Pending Punctuation + scope + punctuation.definition.bullet.pending.todo + settings + + foreground + #928374 + + + + name + PlainTasks: Task Completed Punctuation + scope + punctuation.definition.bullet.completed.todo + settings + + foreground + #427b58 + + + + name + PlainTasks: Task Cancelled Punctuation + scope + punctuation.definition.bullet.cancelled.todo + settings + + foreground + #9d0006 + + + + name + PlainTasks: Tag Critical + scope + string.other.tag.todo.critical + settings + + foreground + #9d0006 + fontStyle + bold + + + + name + PlainTasks: Tag High + scope + string.other.tag.todo.high + settings + + foreground + #af3a03 + fontStyle + bold + + + + name + PlainTasks: Tag Low + scope + string.other.tag.todo.low + settings + + foreground + #076678 + fontStyle + bold + + + + name + PlainTasks: Tag Today + scope + string.other.tag.todo.today + settings + + foreground + #b57614 + fontStyle + bold + + + + name + PlainTasks: Tag + scope + meta.tag.todo + settings + + foreground + #8f3f71 + + + + name + PlainTasks: URL + scope + punctuation.definition.url, todo.url + settings + + foreground + #076678 + + + + name + PlainTasks: Separator + scope + meta.punctuation.archive.todo, meta.punctuation.separator.todo + settings + + fontStyle + italic + foreground + #928374 + + + + + \ No newline at end of file From 7531cc13ecfe4c25ba7d1efffa7c998bf8177d87 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Wed, 30 May 2018 09:26:05 +0100 Subject: [PATCH 0014/1293] re-order caption/value selection --- lib/ace/autocomplete.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index 3b99f03c409..59077385846 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -479,7 +479,7 @@ var FilteredList = function(array, filterText) { var upper = needle.toUpperCase(); var lower = needle.toLowerCase(); loop: for (var i = 0, item; item = items[i]; i++) { - var caption = item.value || item.caption || item.snippet; + var caption = item.snippet || item.caption || item.value; if (!caption) continue; var lastIndex = -1; var matchMask = 0; From 300cb544593d4a2bd22c69e31d687e19843e7afb Mon Sep 17 00:00:00 2001 From: "Lennart C. L. Kats" Date: Fri, 1 Jun 2018 13:12:23 +0200 Subject: [PATCH 0015/1293] Fix err object causing exception with postMessage --- lib/ace/worker/worker_client.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ace/worker/worker_client.js b/lib/ace/worker/worker_client.js index b3a610bba89..5e667b69fb3 100644 --- a/lib/ace/worker/worker_client.js +++ b/lib/ace/worker/worker_client.js @@ -159,6 +159,8 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl, impor try { // firefox refuses to clone objects which have function properties // TODO: cleanup event + if (data.data && data.data.err) + data.data.err = {message: data.data.err.message, stack: data.data.err.stack, code: data.data.err.code}; this.$worker.postMessage({event: event, data: {data: data.data}}); } catch(ex) { From d005e6823684e81c84da7ed0bd96722c1285079b Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Tue, 5 Jun 2018 15:15:39 +0100 Subject: [PATCH 0016/1293] lucene: add escaping and stricter keywords --- lib/ace/mode/_test/text_lucene.txt | 17 +++ lib/ace/mode/_test/tokens_lucene.json | 188 ++++++++++++++++++------- lib/ace/mode/lucene_highlight_rules.js | 7 +- 3 files changed, 159 insertions(+), 53 deletions(-) diff --git a/lib/ace/mode/_test/text_lucene.txt b/lib/ace/mode/_test/text_lucene.txt index 739c3b4d65e..9721e98d6b5 100644 --- a/lib/ace/mode/_test/text_lucene.txt +++ b/lib/ace/mode/_test/text_lucene.txt @@ -37,3 +37,20 @@ field:["a b c" TO def] field:{"a b c" TO def} field:{foo TO "bar"} field:{20180101 TO 20190202} +field:{"2018-01-01" TO "2019-02-02"} +\+escaped +\-escaped +esc\&aped +esc\|aped +\!escaped +\(escaped\) +\{escaped\} +\[escaped\] +escaped\^4 +\"escaped\" +escaped\~0.4 +escaped\* +escaped\? +esc\:aped +esc\\aped +esc\ aped:foo diff --git a/lib/ace/mode/_test/tokens_lucene.json b/lib/ace/mode/_test/tokens_lucene.json index 08bb1dc1747..3a569c2e43c 100644 --- a/lib/ace/mode/_test/tokens_lucene.json +++ b/lib/ace/mode/_test/tokens_lucene.json @@ -1,115 +1,115 @@ [[ "start", ["text"," "], - ["string.unquoted","foo"] + ["term","foo"] ],[ "start", ["keyword","foo:"], ["text"," "], - ["string.unquoted","foo"], + ["term","foo"], ["text"," "], ["keyword.operator","AND"], ["text"," "], - ["string.unquoted","bar"] + ["term","bar"] ],[ "start", - ["string.unquoted","foo"], + ["term","foo"], ["text"," "], ["keyword.operator","AND"], ["text"," "], - ["string.unquoted","bar"] + ["term","bar"] ],[ "start", - ["string.unquoted","foo"], + ["term","foo"], ["text"," "], ["keyword.operator","OR"], ["text"," "], - ["string.unquoted","bar"] + ["term","bar"] ],[ "start", - ["string.unquoted","foo"], + ["term","foo"], ["text"," "], ["keyword.operator","NOT"], ["text"," "], - ["string.unquoted","bar"] + ["term","bar"] ],[ "start", ["string","\"foo bar\""] ],[ "start", - ["string.unquoted","bar"], + ["term","bar"], ["text"," "], ["string","\"foo bar\""] ],[ "start", - ["string.unquoted","bar"], + ["term","bar"], ["text"," "], ["constant.character.negation","-"], - ["string.unquoted","foo"] + ["term","foo"] ],[ "start", - ["string.unquoted","bar"], + ["term","bar"], ["text"," "], ["constant.character.negation","-"], ["string","\"foo bar\""] ],[ "start", ["constant.character.negation","-"], - ["string.unquoted","foo"] + ["term","foo"] ],[ "start", ["constant.character.negation","-"], ["string","\"foo bar\""] ],[ "start", - ["string.unquoted","bar"], + ["term","bar"], ["text"," "], - ["string.unquoted","foo"], + ["term","foo"], ["constant.character.proximity","~100"] ],[ "start", - ["string.unquoted","foo"], + ["term","foo"], ["constant.character.proximity","~100"] ],[ "start", - ["string.unquoted","foo"], + ["term","foo"], ["constant.character.proximity","~100"], ["text"," "], - ["string.unquoted","bar"] + ["term","bar"] ],[ "start", ["string","\"foo bar\""], ["constant.character.proximity","~10"] ],[ "start", - ["string.unquoted","foo"], + ["term","foo"], ["constant.character.proximity","~"] ],[ "start", - ["string.unquoted","bar"], + ["term","bar"], ["text"," "], - ["string.unquoted","foo"], + ["term","foo"], ["constant.character.proximity","~"] ],[ "start", - ["string.unquoted","foo"], + ["term","foo"], ["constant.character.proximity","~"], ["text"," "], - ["string.unquoted","bar"] + ["term","bar"] ],[ "start", - ["string.unquoted","foo"], + ["term","foo"], ["constant.character.proximity","~0.8"] ],[ "start", ["keyword","field:"], - ["string.unquoted","foo"] + ["term","foo"] ],[ "start", ["keyword","field:"], - ["string.unquoted","foo"], + ["term","foo"], ["text"," "], - ["string.unquoted","bar"] + ["term","bar"] ],[ "start", ["keyword","field:"], @@ -117,17 +117,17 @@ ],[ "start", ["paren.lparen","("], - ["string.unquoted","foo"], + ["term","foo"], ["text"," "], ["keyword.operator","AND"], ["text"," "], - ["string.unquoted","bar"], + ["term","bar"], ["paren.rparen",")"] ],[ "start", ["paren.lparen","("], ["keyword","field:"], - ["string.unquoted","foo"], + ["term","foo"], ["text"," "], ["keyword.operator","AND"], ["text"," "], @@ -136,46 +136,46 @@ ["paren.rparen",")"] ],[ "start", - ["string.unquoted","foo"], + ["term","foo"], ["constant.character.asterisk","*"] ],[ "start", - ["string.unquoted","f"], + ["term","f"], ["constant.character.interro","?"], - ["string.unquoted","o"] + ["term","o"] ],[ "start", - ["string.unquoted","f"], + ["term","f"], ["constant.character.asterisk","*"], - ["string.unquoted","o"] + ["term","o"] ],[ "start", ["constant.character.required","+"], - ["string.unquoted","foo"] + ["term","foo"] ],[ "start", ["constant.character.required","+"], ["string","\"foo bar\""] ],[ "start", - ["string.unquoted","foo"], + ["term","foo"], ["constant.character.interro","?"] ],[ "start", ["constant.character.interro","?"], - ["string.unquoted","oo"] + ["term","oo"] ],[ "start", - ["string.unquoted","foo"] + ["term","foo"] ],[ "start", ["keyword","field:"], ["paren.lparen","("], ["constant.character.negation","-"], - ["string.unquoted","foo"], + ["term","foo"], ["text"," "], ["constant.character.required","+"], - ["string.unquoted","bar"], + ["term","bar"], ["text"," "], ["constant.character.required","+"], ["string","\"foo bar\""], @@ -184,21 +184,21 @@ "start", ["keyword","field:"], ["paren.lparen","{"], - ["string.unquoted","foo"], + ["term","foo"], ["text"," "], ["keyword.operator","TO"], ["text"," "], - ["string.unquoted","bar"], + ["term","bar"], ["paren.rparen","}"] ],[ "start", ["keyword","field:"], ["paren.lparen","["], - ["string.unquoted","foo"], + ["term","foo"], ["text"," "], ["keyword.operator","TO"], ["text"," "], - ["string.unquoted","bar"], + ["term","bar"], ["paren.rparen","]"] ],[ "start", @@ -208,7 +208,7 @@ ["text"," "], ["keyword.operator","TO"], ["text"," "], - ["string.unquoted","def"], + ["term","def"], ["paren.rparen","]"] ],[ "start", @@ -218,13 +218,13 @@ ["text"," "], ["keyword.operator","TO"], ["text"," "], - ["string.unquoted","def"], + ["term","def"], ["paren.rparen","}"] ],[ "start", ["keyword","field:"], ["paren.lparen","{"], - ["string.unquoted","foo"], + ["term","foo"], ["text"," "], ["keyword.operator","TO"], ["text"," "], @@ -234,12 +234,98 @@ "start", ["keyword","field:"], ["paren.lparen","{"], - ["string.unquoted","20180101"], + ["term","20180101"], ["text"," "], ["keyword.operator","TO"], ["text"," "], - ["string.unquoted","20190202"], + ["term","20190202"], ["paren.rparen","}"] +],[ + "start", + ["keyword","field:"], + ["paren.lparen","{"], + ["string","\"2018-01-01\""], + ["text"," "], + ["keyword.operator","TO"], + ["text"," "], + ["string","\"2019-02-02\""], + ["paren.rparen","}"] +],[ + "start", + ["constant.language.escape","\\+"], + ["term","escaped"] +],[ + "start", + ["constant.language.escape","\\-"], + ["term","escaped"] +],[ + "start", + ["term","esc"], + ["constant.language.escape","\\&"], + ["term","aped"] +],[ + "start", + ["term","esc"], + ["constant.language.escape","\\|"], + ["term","aped"] +],[ + "start", + ["constant.language.escape","\\!"], + ["term","escaped"] +],[ + "start", + ["constant.language.escape","\\("], + ["term","escaped"], + ["constant.language.escape","\\)"] +],[ + "start", + ["constant.language.escape","\\{"], + ["term","escaped"], + ["constant.language.escape","\\}"] +],[ + "start", + ["constant.language.escape","\\["], + ["term","escaped"], + ["constant.language.escape","\\]"] +],[ + "start", + ["term","escaped"], + ["constant.language.escape","\\^"], + ["term","4"] +],[ + "start", + ["constant.language.escape","\\\""], + ["term","escaped"], + ["constant.language.escape","\\\""] +],[ + "start", + ["term","escaped"], + ["constant.language.escape","\\~"], + ["term","0"], + ["text","."], + ["term","4"] +],[ + "start", + ["term","escaped"], + ["constant.language.escape","\\*"] +],[ + "start", + ["term","escaped"], + ["constant.language.escape","\\?"] +],[ + "start", + ["term","esc"], + ["constant.language.escape","\\:"], + ["term","aped"] +],[ + "start", + ["term","esc"], + ["constant.language.escape","\\\\"], + ["term","aped"] +],[ + "start", + ["keyword","esc\\ aped:"], + ["term","foo"] ],[ "start" ]] \ No newline at end of file diff --git a/lib/ace/mode/lucene_highlight_rules.js b/lib/ace/mode/lucene_highlight_rules.js index 59b134ddebf..600706f6237 100644 --- a/lib/ace/mode/lucene_highlight_rules.js +++ b/lib/ace/mode/lucene_highlight_rules.js @@ -9,6 +9,9 @@ var LuceneHighlightRules = function() { this.$rules = { "start" : [ { + token: "constant.language.escape", + regex: /\\[\+\-&\|!\(\)\{\}\[\]^"~\*\?:\\]/ + }, { token: "constant.character.negation", regex: "\\-" }, { @@ -34,12 +37,12 @@ var LuceneHighlightRules = function() { regex: "[\\)\\}\\]]" }, { token: "keyword", - regex: "\\S+:" + regex: "(?:[^\\s:]+|\\\\ )*[^\\\\]:" }, { token: "string", // " string regex: '"[^"]*"' }, { - token: "string.unquoted", + token: "term", regex: "\\w+" }, { token: "text", From f0bb9ac8b69f0d7cbafd88f4cbfc9d05fb26fe01 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Tue, 5 Jun 2018 15:21:10 +0100 Subject: [PATCH 0017/1293] lucene: handle escaped quotes --- lib/ace/mode/_test/text_lucene.txt | 1 + lib/ace/mode/_test/tokens_lucene.json | 3 +++ lib/ace/mode/lucene_highlight_rules.js | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/ace/mode/_test/text_lucene.txt b/lib/ace/mode/_test/text_lucene.txt index 9721e98d6b5..66669423109 100644 --- a/lib/ace/mode/_test/text_lucene.txt +++ b/lib/ace/mode/_test/text_lucene.txt @@ -54,3 +54,4 @@ escaped\? esc\:aped esc\\aped esc\ aped:foo +"foo\"bar" diff --git a/lib/ace/mode/_test/tokens_lucene.json b/lib/ace/mode/_test/tokens_lucene.json index 3a569c2e43c..abc9ce52661 100644 --- a/lib/ace/mode/_test/tokens_lucene.json +++ b/lib/ace/mode/_test/tokens_lucene.json @@ -326,6 +326,9 @@ "start", ["keyword","esc\\ aped:"], ["term","foo"] +],[ + "start", + ["string","\"foo\\\"bar\""] ],[ "start" ]] \ No newline at end of file diff --git a/lib/ace/mode/lucene_highlight_rules.js b/lib/ace/mode/lucene_highlight_rules.js index 600706f6237..606b305d831 100644 --- a/lib/ace/mode/lucene_highlight_rules.js +++ b/lib/ace/mode/lucene_highlight_rules.js @@ -40,7 +40,7 @@ var LuceneHighlightRules = function() { regex: "(?:[^\\s:]+|\\\\ )*[^\\\\]:" }, { token: "string", // " string - regex: '"[^"]*"' + regex: '"(?:\\\\"|[^"])*"' }, { token: "term", regex: "\\w+" From 00bdafeba644bd4909e7688c04fb9c0a2b446dff Mon Sep 17 00:00:00 2001 From: Henri Yandell Date: Thu, 21 Jun 2018 11:56:15 -0700 Subject: [PATCH 0018/1293] Adding standard files --- CODE_OF_CONDUCT.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..3b64466870c --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,4 @@ +## Code of Conduct +This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +opensource-codeofconduct@amazon.com with any additional questions or comments. From aee2fda5231493677a0ed11f1055c638fc4d0d30 Mon Sep 17 00:00:00 2001 From: Henri Yandell Date: Thu, 21 Jun 2018 11:59:27 -0700 Subject: [PATCH 0019/1293] Adding .github as an exception in gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0e5c2abaab0..bf0ce1f131c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ # Project files that should not be in the repo .* \#* +!/.github !/.gitignore .*.gz *.tmTheme.js From a6b3de2175824758fef25b389bb65c9dd013acc1 Mon Sep 17 00:00:00 2001 From: Henri Yandell Date: Thu, 21 Jun 2018 11:59:40 -0700 Subject: [PATCH 0020/1293] Adding standard PR template --- .github/PULL_REQUEST_TEMPLATE.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000..6bdaa999fc4 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,6 @@ +*Issue #, if available:* + +*Description of changes:* + + +By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. From 87ff0b3eb722f76d8aead47ab97fe64061a86aee Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 16 Jun 2018 00:00:53 +0400 Subject: [PATCH 0021/1293] fix styling of dialog in vim mode --- lib/ace/keyboard/vim.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index 3ecf0d9fff5..fe2a932ee0e 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -192,6 +192,8 @@ define(function(require, exports, module) { this.curOp.force = force; var result = fn(); if (this.ace.curOp && this.ace.curOp.command.name == "vim") { + if (this.state.dialog) + this.ace.curOp.command.scrollIntoView = false; this.ace.endOperation(); if (!curOp.cursorActivity && !curOp.lastChange && prevOp) this.ace.prevOp = prevOp; @@ -715,18 +717,18 @@ dom.importCssString(".normal-mode .ace_cursor{\ .ace_dialog {\ position: absolute;\ left: 0; right: 0;\ - background: white;\ + background: inherit;\ z-index: 15;\ padding: .1em .8em;\ overflow: hidden;\ - color: #333;\ + color: inherit;\ }\ .ace_dialog-top {\ - border-bottom: 1px solid #eee;\ + border-bottom: 1px solid #444;\ top: 0;\ }\ .ace_dialog-bottom {\ - border-top: 1px solid #eee;\ + border-top: 1px solid #444;\ bottom: 0;\ }\ .ace_dialog input {\ @@ -769,11 +771,19 @@ dom.importCssString(".normal-mode .ace_cursor{\ var dialog = dialogDiv(this, template, options.bottom); var closed = false, me = this; + this.state.dialog = dialog; function close(newVal) { if (typeof newVal == 'string') { inp.value = newVal; } else { if (closed) return; + + if (newVal && newVal.type == "blur") { + if (document.activeElement === inp) + return; + } + + me.state.dialog = null; closed = true; dialog.parentNode.removeChild(dialog); me.focus(); From ff450e04a7b5f229438a54e53b0cb2fc98821dc5 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 16 Jun 2018 00:01:23 +0400 Subject: [PATCH 0022/1293] fix gutter --- lib/ace/layer/gutter.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js index 4d11eb30888..b3ca6138a66 100644 --- a/lib/ace/layer/gutter.js +++ b/lib/ace/layer/gutter.js @@ -139,8 +139,6 @@ var Gutter = function(parentEl) { var index = -1; var row = firstRow; - var cells = Array.prototype.slice.call(this.element.childNodes, 0); - while (true) { if (row > foldStart) { row = fold.end.row + 1; @@ -155,7 +153,9 @@ var Gutter = function(parentEl) { } cell = this.$lines.get(++index); - if (!cell) { + if (cell) { + cell.row = row; + } else { cell = this.$lines.createCell(row, config, this.session, onCreateCell); this.$lines.push(cell); } @@ -164,6 +164,7 @@ var Gutter = function(parentEl) { row++; } + this._signal("afterRender"); this.$updateGutterWidth(config); }; @@ -271,6 +272,7 @@ var Gutter = function(parentEl) { this.updateLineHighlight(); + this._signal("afterRender"); this.$updateGutterWidth(config); }; @@ -308,7 +310,6 @@ var Gutter = function(parentEl) { var firstLineNumber = session.$firstLineNumber; - var session = this.session; var breakpoints = session.$breakpoints; var decorations = session.$decorations; var gutterRenderer = session.gutterRenderer || this.$renderer; @@ -417,8 +418,10 @@ var Gutter = function(parentEl) { return {left: 0, right: 0}; var style = dom.computedStyle(this.element.firstChild); this.$padding = {}; - this.$padding.left = parseInt(style.paddingLeft) + 1 || 0; - this.$padding.right = parseInt(style.paddingRight) || 0; + this.$padding.left = (parseInt(style.borderLeftWidth) || 0) + + (parseInt(style.paddingLeft) || 0) + 1; + this.$padding.right = (parseInt(style.borderRightWidth) || 0) + + (parseInt(style.paddingRight) || 0); return this.$padding; }; From 965f49e3d1cb9eab29a615289dfc4d782f516db9 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 16 Jun 2018 00:03:47 +0400 Subject: [PATCH 0023/1293] add support for margin --- lib/ace/virtual_renderer.js | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 7231a8d5da3..e307c8527b4 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -160,6 +160,15 @@ var VirtualRenderer = function(container, theme) { v: 0, h: 0 }; + + this.margin = { + left: 0, + right: 0, + top: 0, + bottom: 0, + v: 0, + h: 0 + }; this.$loop = new RenderLoop( this.$renderChanges.bind(this), @@ -407,8 +416,9 @@ var VirtualRenderer = function(container, theme) { this.gutterWidth = gutterWidth; dom.setStyle(this.scrollBarH.element.style, "left", gutterWidth + "px"); - dom.setStyle(this.scroller.style, "left", gutterWidth + "px"); - size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBarV.getWidth()); + dom.setStyle(this.scroller.style, "left", gutterWidth + this.margin.left + "px"); + size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBarV.getWidth() - this.margin.h); + dom.setStyle(this.$gutter.style, "left", this.margin.left + "px"); var right = this.scrollBarV.getWidth() + "px"; dom.setStyle(this.scrollBarH.element.style, "right", right); @@ -640,7 +650,7 @@ var VirtualRenderer = function(container, theme) { if (posLeft > this.$size.scrollerWidth - w) posLeft = this.$size.scrollerWidth - w; - posLeft += this.gutterWidth; + posLeft += this.gutterWidth + this.margin.left; dom.setStyle(style, "height", h + "px"); dom.setStyle(style, "width", w + "px"); dom.translate(this.textarea, Math.min(posLeft, this.$size.scrollerWidth - w), Math.min(posTop, this.$size.height - h)); @@ -715,6 +725,18 @@ var VirtualRenderer = function(container, theme) { this.session.setScrollTop(-sm.top); this.updateFull(); }; + + this.setMargin = function(top, bottom, left, right) { + var sm = this.margin; + sm.top = top|0; + sm.bottom = bottom|0; + sm.right = right|0; + sm.left = left|0; + sm.v = sm.top + sm.bottom; + sm.h = sm.left + sm.right; + this.$updateCachedSize(true, this.gutterWidth, this.$size.width, this.$size.height); + this.updateFull(); + }; /** * Returns whether the horizontal scrollbar is set to be always visible. @@ -1416,7 +1438,7 @@ var VirtualRenderer = function(container, theme) { if (this.$hasCssTransforms) { canvasPos = {top:0, left: 0}; var p = this.$fontMetrics.transformCoordinates([x, y]); - x = p[1] - this.gutterWidth; + x = p[1] - this.gutterWidth - this.margin.left; y = p[0]; } else { canvasPos = this.scroller.getBoundingClientRect(); @@ -1435,7 +1457,7 @@ var VirtualRenderer = function(container, theme) { if (this.$hasCssTransforms) { canvasPos = {top:0, left: 0}; var p = this.$fontMetrics.transformCoordinates([x, y]); - x = p[1] - this.gutterWidth; + x = p[1] - this.gutterWidth - this.margin.left; y = p[0]; } else { canvasPos = this.scroller.getBoundingClientRect(); @@ -1687,7 +1709,10 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { initialValue: false }, showFoldWidgets: { - set: function(show) {this.$gutterLayer.setShowFoldWidgets(show);}, + set: function(show) { + this.$gutterLayer.setShowFoldWidgets(show); + this.$loop.schedule(this.CHANGE_GUTTER); + }, initialValue: true }, displayIndentGuides: { From 4dcb9d40ff05a0ef62998c3c28f89605be1c9a95 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 15 May 2018 17:43:41 +0400 Subject: [PATCH 0024/1293] add basic support for toggle word --- lib/ace/editor.js | 78 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index e7fec475eb8..971ebabe56b 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -1656,6 +1656,84 @@ Editor.$uid = 0; this.moveCursorTo(row, Math.max(nr.start +1, column + nnr.length - nr.value.length)); } + } else { + this.toggleWord(); + } + }; + + this.$toggleWordPairs = [ + ["first", "last"], + ["true", "false"], + ["yes", "no"], + ["width", "height"], + ["top", "bottom"], + ["right", "left"], + ["on", "off"], + ["x", "y"], + ["get", "set"], + ["max", "min"], + ["horizontal", "vertical"], + ["show", "hide"], + ["add", "remove"], + ["up", "down"], + ["before", "after"], + ["even", "odd"], + ["inside", "outside"], + ["next", "previous"], + ["increase", "decrease"], + ["attach", "detach"], + ["&&", "||"], + ["==", "!="] + ]; + + this.toggleWord = function () { + var row = this.selection.getCursor().row; + var column = this.selection.getCursor().column; + this.selection.selectWord(); + var currentState = this.getSelectedText(); + var currWordStart = this.selection.getWordRange().start.column; + var wordParts = currentState.replace(/([a-z]+|[A-Z]+)(?=[A-Z_]|$)/g, '$1 ').split(/\s/); + var delta = column - currWordStart - 1; + if (delta < 0) delta = 0; + var curLength = 0, itLength = 0; + var that = this; + if (currentState.match(/[A-Za-z0-9_]+/)) { + wordParts.forEach(function (item, i) { + itLength = curLength + item.length; + if (delta >= curLength && delta <= itLength) { + currentState = item; + that.selection.clearSelection(); + that.moveCursorTo(row, curLength + currWordStart); + that.selection.selectTo(row, itLength + currWordStart); + } + curLength = itLength; + }); + } + + var wordPairs = this.$toggleWordPairs; + var reg; + for (var i = 0; i < wordPairs.length; i++) { + var item = wordPairs[i]; + for (var j = 0; j <= 1; j++) { + var negate = +!j; + var firstCondition = currentState.match(new RegExp('^\\s?_?(' + lang.escapeRegExp(item[j]) + ')\\s?$', 'i')); + if (firstCondition) { + var secondCondition = currentState.match(new RegExp('([_]|^|\\s)(' + lang.escapeRegExp(firstCondition[1]) + ')($|\\s)', 'g')); + if (secondCondition) { + reg = currentState.replace(new RegExp(lang.escapeRegExp(item[j]), 'i'), function (result) { + var res = item[negate]; + if (result.toUpperCase() == result) { + res = res.toUpperCase(); + } else if (result.charAt(0).toUpperCase() == result.charAt(0)) { + res = res.substr(0, 0) + item[negate].charAt(0).toUpperCase() + res.substr(1); + } + return res; + }); + this.insert(reg); + reg = ""; + } + } + } } }; From 6e989d6b2b6d97a6c056f38342c76649dea1c5b4 Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Tue, 26 Jun 2018 11:05:52 +0100 Subject: [PATCH 0025/1293] fall back to matching on snippets last --- lib/ace/autocomplete.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index 59077385846..bed4cbb10cb 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -479,7 +479,7 @@ var FilteredList = function(array, filterText) { var upper = needle.toUpperCase(); var lower = needle.toLowerCase(); loop: for (var i = 0, item; item = items[i]; i++) { - var caption = item.snippet || item.caption || item.value; + var caption = item.caption || item.value || item.snippet; if (!caption) continue; var lastIndex = -1; var matchMask = 0; From e483456da9398939219dd8f6763380c1657e5ce9 Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Thu, 28 Jun 2018 10:51:19 +0100 Subject: [PATCH 0026/1293] separate TS module declarations Fixes ajaxorg/ace-builds#133. --- Makefile.dryice.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 2556766137e..6f49b607320 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -112,9 +112,9 @@ function ace() { } function buildTypes() { - copy.file(ACE_HOME + "/ace.d.ts", BUILD_DIR + "/ace.d.ts"); - + var definitions = fs.readFileSync(ACE_HOME + '/ace.d.ts', 'utf8'); var paths = fs.readdirSync(BUILD_DIR + '/src-noconflict'); + var moduleRef = '/// '; var pathModules = paths.map(function(path) { if (/^(mode|theme|ext|keybinding)-/.test(path)) { @@ -124,7 +124,8 @@ function buildTypes() { }).filter(Boolean).join('\n') + "\ndeclare module 'ace-builds/webpack-resolver';\n"; - fs.appendFileSync(BUILD_DIR + '/ace.d.ts', '\n' + pathModules); + fs.writeFileSync(BUILD_DIR + '/ace.d.ts', moduleRef + '\n' + definitions); + fs.writeFileSync(BUILD_DIR + '/ace-modules.d.ts', pathModules); var loader = paths.map(function(path) { if (/\.js$/.test(path) && !/^ace\.js$/.test(path)) { From 90fb9977a31c81b7756da4a3c24950388d23b78c Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 15 Jul 2018 17:32:02 +0400 Subject: [PATCH 0027/1293] fix deletion of autoinserted backquote in javascript mode --- lib/ace/mode/behaviour/behaviour_test.js | 7 +++++++ lib/ace/mode/behaviour/cstyle.js | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/ace/mode/behaviour/behaviour_test.js b/lib/ace/mode/behaviour/behaviour_test.js index 500f3971d41..6c8580f7818 100644 --- a/lib/ace/mode/behaviour/behaviour_test.js +++ b/lib/ace/mode/behaviour/behaviour_test.js @@ -158,6 +158,13 @@ module.exports = { exec("insertstring", 1, '"'); assert.equal(editor.getValue(), '"\\n"'); + editor.setValue(""); + exec("insertstring", 1, '`'); + assert.equal(editor.getValue(), '``'); + exec("insertstring", 1, 'n'); + assert.equal(editor.getValue(), '`n`'); + exec("backspace", 2); + assert.equal(editor.getValue(), ''); }, "test: xml": function() { editor = new Editor(new MockRenderer()); diff --git a/lib/ace/mode/behaviour/cstyle.js b/lib/ace/mode/behaviour/cstyle.js index 317c52c656f..af2d937eeea 100644 --- a/lib/ace/mode/behaviour/cstyle.js +++ b/lib/ace/mode/behaviour/cstyle.js @@ -307,8 +307,10 @@ var CstyleBehaviour = function(options) { }); this.add("string_dquotes", "deletion", function(state, action, editor, session, range) { + var quotes = session.$mode.$quotes || defaultQuotes; + var selected = session.doc.getTextRange(range); - if (!range.isMultiLine() && (selected == '"' || selected == "'")) { + if (!range.isMultiLine() && quotes.hasOwnProperty(selected)) { initContext(editor); var line = session.doc.getLine(range.start.row); var rightChar = line.substring(range.start.column + 1, range.start.column + 2); From fc4746b8f222cf33bd396d56509c4118cb152cd4 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 15 Jul 2018 18:08:35 +0400 Subject: [PATCH 0028/1293] fix #3699: tsx highlighting issues --- lib/ace/mode/javascript_highlight_rules.js | 3 +- lib/ace/mode/typescript_highlight_rules.js | 45 ++++++++-------------- 2 files changed, 17 insertions(+), 31 deletions(-) diff --git a/lib/ace/mode/javascript_highlight_rules.js b/lib/ace/mode/javascript_highlight_rules.js index a26af6e9f3b..7f766d23706 100644 --- a/lib/ace/mode/javascript_highlight_rules.js +++ b/lib/ace/mode/javascript_highlight_rules.js @@ -177,7 +177,8 @@ var JavaScriptHighlightRules = function(options) { next : "property" }, { token : "storage.type", - regex : /=>/ + regex : /=>/, + next : "start" }, { token : "keyword.operator", regex : /--|\+\+|\.{3}|===|==|=|!=|!==|<+=?|>+=?|!|&&|\|\||\?:|[!$%&*+\-~\/^]=?/, diff --git a/lib/ace/mode/typescript_highlight_rules.js b/lib/ace/mode/typescript_highlight_rules.js index 82c9fb4e9d6..0eb82458aaa 100644 --- a/lib/ace/mode/typescript_highlight_rules.js +++ b/lib/ace/mode/typescript_highlight_rules.js @@ -39,56 +39,41 @@ THIS FILE WAS AUTOGENERATED BY mode_highlight_rules.tmpl.js (UUID: 21e323af-f665-4161-96e7-5087d262557e) */ -define(function(require, exports, module) { +define(function (require, exports, module) { "use strict"; var oop = require("../lib/oop"); var JavaScriptHighlightRules = require("./javascript_highlight_rules").JavaScriptHighlightRules; -var TypeScriptHighlightRules = function(options) { +var TypeScriptHighlightRules = function (options) { - var tsRules = [ - // Match stuff like: module name {...} + var tsRules = [ + // Match stuff like: function name: return type) { - token: ["keyword.operator.ts", "text", "variable.parameter.function.ts", "text"], - regex: "\\b(module)(\\s*)([a-zA-Z0-9_?.$][\\w?.$]*)(\\s*\\{)" - }, - // Match stuff like: super(argument, list) - { - token: ["storage.type.variable.ts", "text", "keyword.other.ts", "text"], - regex: "(super)(\\s*\\()([a-zA-Z0-9,_?.$\\s]+\\s*)(\\))" + token: ["storage.type", "text", "entity.name.function.ts"], + regex: "(function)(\\s+)([a-zA-Z0-9\$_\u00a1-\uffff][a-zA-Z0-9\d\$_\u00a1-\uffff]*)", }, - // Match stuff like: function() {...} { - token: ["entity.name.function.ts","paren.lparen", "paren.rparen"], - regex: "([a-zA-Z_?.$][\\w?.$]*)(\\()(\\))" + token: "keyword", + regex: "(?:\\b(constructor|declare|interface|as|AS|public|private|extends|export|super|readonly|module|namespace|abstract|implements)\\b)" }, - // Match stuff like: (function: return type) { - token: ["variable.parameter.function.ts", "text", "variable.parameter.function.ts"], - regex: "([a-zA-Z0-9_?.$][\\w?.$]*)(\\s*:\\s*)([a-zA-Z0-9_?.$][\\w?.$]*)" - }, + token: ["keyword", "storage.type.variable.ts"], + regex: "(class|type)(\\s+[a-zA-Z0-9_?.$][\\w?.$]*)", + }, { - token: ["keyword.operator.ts"], - regex: "(?:\\b(constructor|declare|interface|as|AS|public|private|class|extends|export|super)\\b)" + token: "keyword", + regex: "\\b(?:super|export|import|keyof|infer)\\b" }, { token: ["storage.type.variable.ts"], - regex: "(?:\\b(this\\.|string\\b|bool\\b|number)\\b)" - }, - { - token: ["keyword.operator.ts", "storage.type.variable.ts", "keyword.operator.ts", "storage.type.variable.ts"], - regex: "(class)(\\s+[a-zA-Z0-9_?.$][\\w?.$]*\\s+)(extends)(\\s+[a-zA-Z0-9_?.$][\\w?.$]*\\s+)?" - }, - { - token: "keyword", - regex: "(?:super|export|class|extends|import)\\b" + regex: "(?:\\b(this\\.|string\\b|bool\\b|boolean\\b|number\\b|true\\b|false\\b|undefined\\b|any\\b|null\\b|(?:unique )?symbol\\b|object\\b|never\\b|enum\\b))" } ]; var JSRules = new JavaScriptHighlightRules({jsx: (options && options.jsx) == true}).getRules(); - JSRules.start = tsRules.concat(JSRules.start); + JSRules.no_regex = tsRules.concat(JSRules.no_regex); this.$rules = JSRules; }; From 8e33ff510b535f85fd1d9786726ec0a4da9a1e47 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 16 Jul 2018 00:42:23 +0400 Subject: [PATCH 0029/1293] add documentation about basePath --- index.html | 9 +++++++++ lib/ace/config.js | 17 +++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/index.html b/index.html index 145b727b3f4..6c6741bffee 100644 --- a/index.html +++ b/index.html @@ -348,6 +348,15 @@

Adding New Commands and Keybindings

}, readOnly: true // false if this command should not apply in readOnly mode }); +

Configure dynamic loading of modes and themes

+

By default ace detcts the url for dynamic loading by finding the script node for ace.js. + This doesn't work if ace.js is not loaded with a separate script tag, and in this case it is required to set url explicitely

+
ace.config.set("basePath", "https://url.to.a/folder/that/contains-ace-modes");
+

Path for one module alone can be configured with:

+
ace.config.setModuleUrl("ace/theme/textmate", "url for textmate.js");
+

When using ace with webpack, it is possible to configure paths for all submodules using

+
require("ace-builds/webpack-resolver");
+

which depends on file-loader

Creating a Syntax Highlighter for Ace

diff --git a/lib/ace/config.js b/lib/ace/config.js index 53ce5dce824..2bbc34df3fe 100644 --- a/lib/ace/config.js +++ b/lib/ace/config.js @@ -141,7 +141,24 @@ exports.loadModule = function(moduleName, onLoad) { if (!exports.get("packaged")) return afterLoad(); + net.loadScript(exports.moduleUrl(moduleName, moduleType), afterLoad); + reportErrorIfPathIsNotConfigured(); +}; + +var reportErrorIfPathIsNotConfigured = function() { + if ( + !options.basePath && !options.workerPath + && !options.modePath && !options.themePath + && !Object.keys(options.$moduleUrls).length + ) { + console.error( + "Unable to infer path to ace from script src,", + "use ace.config.set('basePath', 'path') to enable dynamic loading of modes and themes", + "or with webpack use ace/webpack-resolver" + ); + reportErrorIfPathIsNotConfigured = function() {}; + } }; // initialization From 1e8e5486537a9f860b447fce514171338b9b4c01 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 17 Jul 2018 00:20:27 +0400 Subject: [PATCH 0030/1293] fix static-highlight extension --- demo/static-highlighter/server.js | 2 + lib/ace/ext/static_highlight.js | 109 ++++++++++++--------------- lib/ace/ext/static_highlight_test.js | 17 +++-- 3 files changed, 60 insertions(+), 68 deletions(-) diff --git a/demo/static-highlighter/server.js b/demo/static-highlighter/server.js index ea8361d4062..80301d9a809 100644 --- a/demo/static-highlighter/server.js +++ b/demo/static-highlighter/server.js @@ -27,7 +27,9 @@ http.createServer(function(req, res) { res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"}); fs.readFile(path, "utf8", function(err, data) { if (err) data = err.message; + var t = Date.now(); var highlighted = highlighter.render(data, new JavaScriptMode(), theme); + console.log("Rendered " + (data.length/1000) + "kb in " + (Date.now() - t) + "ms"); res.end( '\n' + ' +snippet sub + ${1} +snippet summary + + ${1} + +snippet sup + ${1} +snippet table + + ${2} +
+snippet table. + + ${3} +
+snippet table# + + ${3} +
+snippet tbody + + ${1} + +snippet td + ${1} +snippet td. + ${2} +snippet td# + ${2} +snippet td+ + ${1} + td+${2} +snippet textarea + ${6} +snippet tfoot + + ${1} + +snippet th + ${1} +snippet th. + ${2} +snippet th# + ${2} +snippet th+ + ${1} + th+${2} +snippet thead + + ${1} + +snippet time +
") != -1); + assert.ok(result.html.indexOf("$'$1$2$$$&\n") != -1); next(); }, @@ -107,7 +109,7 @@ module.exports = { var mode = new TextMode(); var result = highlighter.render(snippet, mode, theme); - assert.ok(result.html.indexOf("&<>'"") != -1); + assert.ok(result.html.indexOf("&<>'"\n") != -1); var mode = new JavaScriptMode(); var result = highlighter.render("/*" + snippet, mode, theme); From 69da3f3a6b1caf7c971b9f425562fb5124d49ac2 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 12 Nov 2018 01:31:19 +0400 Subject: [PATCH 0099/1293] fix textinput issues on ios --- lib/ace/css/editor.css | 7 - lib/ace/keyboard/textinput.js | 122 ++++++- lib/ace/keyboard/textinput_ios.js | 527 ------------------------------ lib/ace/virtual_renderer.js | 2 +- 4 files changed, 117 insertions(+), 541 deletions(-) delete mode 100644 lib/ace/keyboard/textinput_ios.js diff --git a/lib/ace/css/editor.css b/lib/ace/css/editor.css index a23a6a27644..573cb86a1cb 100644 --- a/lib/ace/css/editor.css +++ b/lib/ace/css/editor.css @@ -528,10 +528,3 @@ styles.join("\n") position: absolute; z-index: 8; } - - -.ace_text-input-ios { - position: absolute !important; - top: -100000px !important; - left: -100000px !important; -} diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 58ff7472203..405a73b4e45 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -40,11 +40,12 @@ var USE_IE_MIME_TYPE = useragent.isIE; var HAS_FOCUS_ARGS = useragent.isChrome > 63; var MAX_LINE_LENGTH = 400; -var TextInputIOS = require("./textinput_ios").TextInput; +var KEYS = require("../lib/keys"); +var MODS = KEYS.KEY_MODS; +var isIOS = useragent.isIOS; +var valueResetRegex = isIOS ? /\s/ : /\n/; + var TextInput = function(parentNode, host) { - if (useragent.isIOS) - return TextInputIOS.call(this, parentNode, host); - var text = dom.createElement("textarea"); text.className = "ace_text-input"; @@ -156,7 +157,25 @@ var TextInput = function(parentNode, host) { resetSelection(); }); - function resetSelection() { + var resetSelection = isIOS + ? function(value) { + if (!isFocused || (copied && !value)) return; + if (!value) + value = ""; + var newValue = "\n ab" + value + "cde fg\n"; + if (newValue != text.value) + text.value = lastValue = newValue; + + var selectionStart = 4; + var selectionEnd = 4 + (value.length || (host.selection.isEmpty() ? 0 : 1)); + + if (lastSelectionStart != selectionStart || lastSelectionEnd != selectionEnd) { + text.setSelectionRange(selectionStart, selectionEnd); + } + lastSelectionStart = selectionStart; + lastSelectionEnd = selectionEnd; + } + : function() { if (inComposition || sendingText) return; // modifying selection of blured textarea can focus it (chrome mac/linux) @@ -311,7 +330,7 @@ var TextInput = function(parentNode, host) { return onCompositionUpdate(); var data = text.value; var inserted = sendText(data, true); - if (data.length > MAX_LINE_LENGTH + 100 || /\n/.test(inserted)) + if (data.length > MAX_LINE_LENGTH + 100 || valueResetRegex.test(inserted)) resetSelection(); }; @@ -340,6 +359,13 @@ var TextInput = function(parentNode, host) { return event.preventDefault(e); if (handleClipboardData(e, data)) { + if (isIOS) { + resetSelection(data); + copied = data; + setTimeout(function () { + copied = false; + }, 10); + } isCut ? host.onCut() : host.onCopy(); event.preventDefault(e); } else { @@ -587,6 +613,90 @@ var TextInput = function(parentNode, host) { }); event.addListener(host.renderer.scroller, "contextmenu", onContextMenu); event.addListener(text, "contextmenu", onContextMenu); + + if (isIOS) + addIosSelectionHandler(parentNode, host, text); + + function addIosSelectionHandler(parentNode, host, text) { + var typingResetTimeout = null; + var typing = false; + + text.addEventListener("keydown", function (e) { + if (typingResetTimeout) clearTimeout(typingResetTimeout); + typing = true; + }, true); + + text.addEventListener("keyup", function (e) { + typingResetTimeout = setTimeout(function () { + typing = false; + }, 100); + }, true); + + // IOS doesn't fire events for arrow keys, but this unique hack changes everything! + var detectArrowKeys = function(e) { + if (document.activeElement !== text) return; + if (typing || inComposition) return; + + if (copied) { + return; + } + var selectionStart = text.selectionStart; + var selectionEnd = text.selectionEnd; + + var key = null; + var modifier = 0; + console.log(selectionStart, selectionEnd) + if (selectionStart == 0) { + key = KEYS.up; + } else if (selectionStart == 1) { + key = KEYS.home; + } else if (selectionEnd > lastSelectionEnd && lastValue[selectionEnd] == "\n") { + key = KEYS.end; + } else if (selectionStart < lastSelectionStart && lastValue[selectionStart - 1] == " ") { + key = KEYS.left + modifier = MODS.option; + } else if ( + selectionStart < lastSelectionStart + || ( + selectionStart == lastSelectionStart + && lastSelectionEnd != lastSelectionStart + && selectionStart == selectionEnd + ) + ) { + key = KEYS.left; + } else if (selectionEnd > lastSelectionEnd && lastValue.slice(0, selectionEnd).split("\n").length > 2) { + key = KEYS.down; + } else if (selectionEnd > lastSelectionEnd && lastValue[selectionEnd - 1] == " ") { + key = KEYS.right + modifier = MODS.option; + } else if ( + selectionEnd > lastSelectionEnd + || ( + selectionEnd == lastSelectionEnd + && lastSelectionEnd != lastSelectionStart + && selectionStart == selectionEnd + ) + ) { + key = KEYS.right; + } + + if (selectionStart !== selectionEnd) + modifier |= MODS.shift; + + if (key) { + host.onCommandKey(null, modifier, key); + lastSelectionStart = selectionStart; + lastSelectionEnd = selectionEnd; + resetSelection("") + } + }; + // On iOS, "selectionchange" can only be attached to the document object... + document.addEventListener("selectionchange", detectArrowKeys); + host.on("destroy", function() { + document.removeEventListener("selectionchange", detectArrowKeys); + }); + } + }; exports.TextInput = TextInput; diff --git a/lib/ace/keyboard/textinput_ios.js b/lib/ace/keyboard/textinput_ios.js deleted file mode 100644 index 12f6acebd2b..00000000000 --- a/lib/ace/keyboard/textinput_ios.js +++ /dev/null @@ -1,527 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Distributed under the BSD license: - * - * Copyright (c) 2010, Ajax.org B.V. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Ajax.org B.V. nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -define(function(require, exports, module) { -"use strict"; - -var event = require("../lib/event"); -var useragent = require("../lib/useragent"); -var dom = require("../lib/dom"); -var lang = require("../lib/lang"); -var KEYS = require("../lib/keys"); -var MODS = KEYS.KEY_MODS; -var BROKEN_SETDATA = useragent.isChrome < 18; -var USE_IE_MIME_TYPE = useragent.isIE; - -var TextInput = function(parentNode, host) { - var self = this; - var text = dom.createElement("textarea"); - text.className = useragent.isIOS ? "ace_text-input ace_text-input-ios" : "ace_text-input"; - - if (useragent.isTouchPad) - text.setAttribute("x-palm-disable-auto-cap", true); - - text.setAttribute("wrap", "off"); - text.setAttribute("autocorrect", "off"); - text.setAttribute("autocapitalize", "off"); - text.setAttribute("spellcheck", false); - - text.style.opacity = "0"; - parentNode.insertBefore(text, parentNode.firstChild); - - var PLACEHOLDER = "\n aaaa a\n"; - - var copied = false; - var cut = false; - var pasted = false; - var inComposition = false; - var tempStyle = ''; - var isSelectionEmpty = true; - - // FOCUS - // ie9 throws error if document.activeElement is accessed too soon - try { var isFocused = document.activeElement === text; } catch(e) {} - - event.addListener(text, "blur", function(e) { - host.onBlur(e); - isFocused = false; - }); - event.addListener(text, "focus", function(e) { - isFocused = true; - host.onFocus(e); - resetSelection(); - }); - this.focus = function() { - if (tempStyle) return text.focus(); - text.style.position = "fixed"; - text.focus(); - }; - this.blur = function() { - text.blur(); - }; - this.isFocused = function() { - return isFocused; - }; - - // modifying selection of blured textarea can focus it (chrome mac/linux) - var syncSelection = lang.delayedCall(function() { - isFocused && resetSelection(isSelectionEmpty); - }); - var syncValue = lang.delayedCall(function() { - if (!inComposition) { - text.value = PLACEHOLDER; - isFocused && resetSelection(); - } - }); - - function resetSelection(isEmpty) { - if (inComposition) - return; - - // this prevents infinite recursion on safari 8 - // see https://github.com/ajaxorg/ace/issues/2114 - inComposition = true; - - if (inputHandler) { - selectionStart = 0; - selectionEnd = isEmpty ? 0 : text.value.length - 1; - } else { - var selectionStart = 4; - var selectionEnd = 5; - } - // on firefox this throws if textarea is hidden - try { - text.setSelectionRange(selectionStart, selectionEnd); - } catch(e) {} - - inComposition = false; - } - - function resetValue() { - if (inComposition) - return; - text.value = PLACEHOLDER; - //http://code.google.com/p/chromium/issues/detail?id=76516 - if (useragent.isWebKit) - syncValue.schedule(); - } - - useragent.isWebKit || host.addEventListener('changeSelection', function() { - if (host.selection.isEmpty() != isSelectionEmpty) { - isSelectionEmpty = !isSelectionEmpty; - syncSelection.schedule(); - } - }); - - resetValue(); - if (isFocused) - host.onFocus(); - - - var isAllSelected = function(text) { - return text.selectionStart === 0 && text.selectionEnd === text.value.length; - }; - - var onSelect = function(e) { - if (isAllSelected(text)) { - host.selectAll(); - resetSelection(); - } else if (inputHandler) { - resetSelection(host.selection.isEmpty()); - } - }; - - var inputHandler = null; - this.setInputHandler = function(cb) {inputHandler = cb;}; - this.getInputHandler = function() {return inputHandler;}; - var afterContextMenu = false; - - var sendText = function(data) { - if (text.selectionStart === 4 && text.selectionEnd === 5) { - return; - } - if (inputHandler) { - data = inputHandler(data); - inputHandler = null; - } - if (pasted) { - resetSelection(); - if (data) - host.onPaste(data); - pasted = false; - } else if (data == PLACEHOLDER.substr(0) && text.selectionStart === 4) { - if (afterContextMenu) - host.execCommand("del", {source: "ace"}); - else // some versions of android do not fire keydown when pressing backspace - host.execCommand("backspace", {source: "ace"}); - } else if (!copied) { - if (data.substring(0, 9) == PLACEHOLDER && data.length > PLACEHOLDER.length) - data = data.substr(9); - else if (data.substr(0, 4) == PLACEHOLDER.substr(0, 4)) - data = data.substr(4, data.length - PLACEHOLDER.length + 1); - else if (data.charAt(data.length - 1) == PLACEHOLDER.charAt(0)) - data = data.slice(0, -1); - // can happen if undo in textarea isn't stopped - if (data == PLACEHOLDER.charAt(0)) { - // Do nothing - } else if (data.charAt(data.length - 1) == PLACEHOLDER.charAt(0)) - data = data.slice(0, -1); - - if (data) - host.onTextInput(data); - } - if (copied) { - copied = false; - } - if (afterContextMenu) - afterContextMenu = false; - }; - var onInput = function(e) { - // console.log("onInput", inComposition) - if (inComposition) - return; - var data = text.value; - sendText(data); - resetValue(); - }; - - var handleClipboardData = function(e, data, forceIEMime) { - var clipboardData = e.clipboardData || window.clipboardData; - if (!clipboardData || BROKEN_SETDATA) - return; - // using "Text" doesn't work on old webkit but ie needs it - var mime = USE_IE_MIME_TYPE || forceIEMime ? "Text" : "text/plain"; - try { - if (data) { - // Safari 5 has clipboardData object, but does not handle setData() - return clipboardData.setData(mime, data) !== false; - } else { - return clipboardData.getData(mime); - } - } catch(e) { - if (!forceIEMime) - return handleClipboardData(e, data, true); - } - }; - - var doCopy = function(e, isCut) { - var data = host.getCopyText(); - if (!data) - return event.preventDefault(e); - - if (handleClipboardData(e, data)) { - if (useragent.isIOS) { - cut = isCut; - text.value = "\n aa" + data + "a a\n"; - text.setSelectionRange(4, 4 + data.length); - copied = { - value: data - }; - } - isCut ? host.onCut() : host.onCopy(); - if (!useragent.isIOS) event.preventDefault(e); - } else { - copied = true; - text.value = data; - text.select(); - setTimeout(function(){ - copied = false; - resetValue(); - resetSelection(); - isCut ? host.onCut() : host.onCopy(); - }); - } - }; - - var onCut = function(e) { - doCopy(e, true); - }; - - var onCopy = function(e) { - doCopy(e, false); - }; - - var onPaste = function(e) { - var data = handleClipboardData(e); - if (typeof data == "string") { - if (data) - host.onPaste(data, e); - if (useragent.isIE) - setTimeout(resetSelection); - event.preventDefault(e); - } - else { - text.value = ""; - pasted = true; - } - }; - - event.addCommandKeyListener(text, host.onCommandKey.bind(host)); - - event.addListener(text, "select", onSelect); - - event.addListener(text, "input", onInput); - - event.addListener(text, "cut", onCut); - event.addListener(text, "copy", onCopy); - event.addListener(text, "paste", onPaste); - - - // COMPOSITION - var onCompositionStart = function(e) { - if (inComposition || !host.onCompositionStart || host.$readOnly) - return; - // console.log("onCompositionStart", inComposition) - inComposition = {}; - inComposition.canUndo = host.session.$undoManager; - host.onCompositionStart(); - setTimeout(onCompositionUpdate, 0); - host.on("mousedown", onCompositionEnd); - if (inComposition.canUndo && !host.selection.isEmpty()) { - host.insert(""); - host.session.markUndoGroup(); - host.selection.clearSelection(); - } - host.session.markUndoGroup(); - }; - - var onCompositionUpdate = function() { - // console.log("onCompositionUpdate", inComposition && JSON.stringify(text.value)) - if (!inComposition || !host.onCompositionUpdate || host.$readOnly) - return; - var val = text.value.replace(/\x01/g, ""); - if (inComposition.lastValue === val) return; - - host.onCompositionUpdate(val); - if (inComposition.lastValue) - host.undo(); - if (inComposition.canUndo) - inComposition.lastValue = val; - if (inComposition.lastValue) { - var r = host.selection.getRange(); - host.insert(inComposition.lastValue); - host.session.markUndoGroup(); - inComposition.range = host.selection.getRange(); - host.selection.setRange(r); - host.selection.clearSelection(); - } - }; - - var onCompositionEnd = function(e) { - if (!host.onCompositionEnd || host.$readOnly) return; - // console.log("onCompositionEnd", inComposition &&inComposition.lastValue) - var c = inComposition; - inComposition = false; - var timer = setTimeout(function() { - timer = null; - var str = text.value.replace(/\x01/g, ""); - // console.log(str, c.lastValue) - if (inComposition) - return; - else if (str == c.lastValue) - resetValue(); - else if (!c.lastValue && str) { - resetValue(); - sendText(str); - } - }); - inputHandler = function compositionInputHandler(str) { - // console.log("onCompositionEnd", str, c.lastValue) - if (timer) - clearTimeout(timer); - str = str.replace(/\x01/g, ""); - if (str == c.lastValue) - return ""; - if (c.lastValue && timer) - host.undo(); - return str; - }; - host.onCompositionEnd(); - host.removeListener("mousedown", onCompositionEnd); - if (e.type == "compositionend" && c.range) { - host.selection.setRange(c.range); - } - // Workaround for #3027, #3045, #3097, #3100, #3249 - var needsOnInput = - (!!useragent.isChrome && useragent.isChrome >= 53) || - (!!useragent.isWebKit && useragent.isWebKit >= 603); - - if (needsOnInput) { - onInput(); - } - }; - - - - var syncComposition = lang.delayedCall(onCompositionUpdate, 50); - - event.addListener(text, "compositionstart", onCompositionStart); - event.addListener(text, "compositionupdate", function(){syncComposition.schedule();}); - event.addListener(text, "keyup", function(){syncComposition.schedule();}); - event.addListener(text, "keydown", function(){syncComposition.schedule();}); - event.addListener(text, "compositionend", onCompositionEnd); - - this.getElement = function() { - return text; - }; - - this.setReadOnly = function(readOnly) { - text.readOnly = readOnly; - }; - - this.onContextMenu = function(e) { - afterContextMenu = true; - resetSelection(host.selection.isEmpty()); - host._emit("nativecontextmenu", {target: host, domEvent: e}); - this.moveToMouse(e, true); - }; - - this.moveToMouse = function(e, bringToFront) { - if (!tempStyle) - tempStyle = text.style.cssText; - text.style.cssText = (bringToFront ? "z-index:100000;" : "") - + "height:" + text.style.height + ";" - + (useragent.isIE ? "opacity:0.1;" : ""); - - var rect = host.container.getBoundingClientRect(); - var style = dom.computedStyle(host.container); - var top = rect.top + (parseInt(style.borderTopWidth) || 0); - var left = rect.left + (parseInt(rect.borderLeftWidth) || 0); - var maxTop = rect.bottom - top - text.clientHeight -2; - var move = function(e) { - text.style.left = e.clientX - left - 2 + "px"; - text.style.top = Math.min(e.clientY - top - 2, maxTop) + "px"; - }; - move(e); - - if (e.type != "mousedown") - return; - - if (host.renderer.$keepTextAreaAtCursor) - host.renderer.$keepTextAreaAtCursor = null; - - clearTimeout(closeTimeout); - // on windows context menu is opened after mouseup - if (useragent.isWin) - event.capture(host.container, move, onContextMenuClose); - }; - - this.onContextMenuClose = onContextMenuClose; - var closeTimeout; - function onContextMenuClose() { - clearTimeout(closeTimeout); - closeTimeout = setTimeout(function () { - if (tempStyle) { - text.style.cssText = tempStyle; - tempStyle = ''; - } - if (host.renderer.$keepTextAreaAtCursor == null) { - host.renderer.$keepTextAreaAtCursor = true; - host.renderer.$moveTextAreaToCursor(); - } - }, 0); - } - - var onContextMenu = function(e) { - host.textInput.onContextMenu(e); - onContextMenuClose(); - }; - event.addListener(text, "mouseup", onContextMenu); - event.addListener(text, "mousedown", function(e) { - e.preventDefault(); - onContextMenuClose(); - }); - event.addListener(host.renderer.scroller, "contextmenu", onContextMenu); - event.addListener(text, "contextmenu", onContextMenu); - - if (useragent.isIOS) { - var typingResetTimeout = null; - var typing = false; - - parentNode.addEventListener("keydown", function (e) { - if (typingResetTimeout) clearTimeout(typingResetTimeout); - typing = true; - }); - - parentNode.addEventListener("keyup", function (e) { - typingResetTimeout = setTimeout(function () { - typing = false; - }, 100); - }); - - // IOS doesn't fire events for arrow keys, but this unique hack changes everything! - var detectArrowKeys = function(e) { - if (document.activeElement !== text) return; - if (typing) return; - - if (cut) { - return setTimeout(function () { - cut = false; - }, 100); - } - var selectionStart = text.selectionStart; - var selectionEnd = text.selectionEnd; - text.setSelectionRange(4, 5); - if (selectionStart == selectionEnd) { - switch (selectionStart) { - case 0: host.onCommandKey(null, 0, KEYS.up); break; - case 1: host.onCommandKey(null, 0, KEYS.home); break; - case 2: host.onCommandKey(null, MODS.option, KEYS.left); break; - case 4: host.onCommandKey(null, 0, KEYS.left); break; - case 5: host.onCommandKey(null, 0, KEYS.right); break; - case 7: host.onCommandKey(null, MODS.option, KEYS.right); break; - case 8: host.onCommandKey(null, 0, KEYS.end); break; - case 9: host.onCommandKey(null, 0, KEYS.down); break; - } - } else { - switch (selectionEnd) { - case 6: host.onCommandKey(null, MODS.shift, KEYS.right); break; - case 7: host.onCommandKey(null, MODS.shift | MODS.option, KEYS.right); break; - case 8: host.onCommandKey(null, MODS.shift, KEYS.end); break; - case 9: host.onCommandKey(null, MODS.shift, KEYS.down); break; - } - switch (selectionStart) { - case 0: host.onCommandKey(null, MODS.shift, KEYS.up); break; - case 1: host.onCommandKey(null, MODS.shift, KEYS.home); break; - case 2: host.onCommandKey(null, MODS.shift | MODS.option, KEYS.left); break; - case 3: host.onCommandKey(null, MODS.shift, KEYS.left); break; - } - } - }; - // On iOS, "selectionchange" can only be attached to the document object... - document.addEventListener("selectionchange", detectArrowKeys); - host.on("destroy", function() { - document.removeEventListener("selectionchange", detectArrowKeys); - }); - } -}; - -exports.TextInput = TextInput; -}); diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index a30e6f68081..7f5eebcad3b 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -173,7 +173,7 @@ var VirtualRenderer = function(container, theme) { h: 0 }; - this.$keepTextAreaAtCursor = true; + this.$keepTextAreaAtCursor = !useragent.isIOS; this.$loop = new RenderLoop( this.$renderChanges.bind(this), From ff226cf69da5b56a6f5987065cd26f758d7db182 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 12 Nov 2018 01:59:22 +0400 Subject: [PATCH 0100/1293] include snippets in webpack resolver --- .travis.yml | 2 +- Makefile.dryice.js | 16 ++++++++++------ lib/ace/keyboard/textinput.js | 10 +++++----- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index c8f52807fba..0bf282193fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ install: cmp --silent package.json node_modules/package.json || install; script: - - changes=$(git diff --name-only origin/HEAD); + - changes=$(git diff --name-only origin/HEAD --no-renames --diff-filter=ACMR); if [ "$changes" == "" ]; then echo "checking all files"; node node_modules/eslint/bin/eslint "lib/ace/**/*.js"; diff --git a/Makefile.dryice.js b/Makefile.dryice.js index e4faa4dfa9f..d7d5e33b6a9 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -116,8 +116,12 @@ function buildTypes() { var paths = fs.readdirSync(BUILD_DIR + '/src-noconflict'); var moduleRef = '/// '; + fs.readdirSync(BUILD_DIR + '/src-noconflict/snippets').forEach(function(path) { + paths.push("snippets/" + path); + }); + var pathModules = paths.map(function(path) { - if (/^(mode|theme|ext|keybinding)-/.test(path)) { + if (/^(mode|theme|ext|keybinding)-|^snippets\//.test(path)) { var moduleName = path.split('.')[0]; return "declare module 'ace-builds/src-noconflict/" + moduleName + "';"; } @@ -184,8 +188,8 @@ function demo() { removeRequireJS = true; var scripts = m.split(/,\s*/); var result = []; - function comment(str) {result.push("")} - function script(str) {result.push('')} + function comment(str) {result.push("");} + function script(str) {result.push('');} scripts.forEach(function(s) { s = s.replace(/"/g, ""); if (s == "ace/ace") { @@ -422,7 +426,7 @@ function buildAce(options, callback) { // function addCb() { addCb.count = (addCb.count || 0) + 1; - return done + return done; } function done() { if (--addCb.count > 0) @@ -434,7 +438,7 @@ function buildAce(options, callback) { if (callback) return callback(); - console.log("Finished building " + getTargetDir(options)) + console.log("Finished building " + getTargetDir(options)); } } @@ -616,7 +620,7 @@ function addSnippetFile(modeName) { function compress(text) { var uglify = require("dryice").copy.filter.uglifyjs; uglify.options.mangle_toplevel = {except: ["ACE_NAMESPACE", "requirejs"]}; - uglify.options.beautify = {ascii_only: true, inline_script: true} + uglify.options.beautify = {ascii_only: true, inline_script: true}; return asciify(uglify(text)); // copy.filter.uglifyjs.options.ascii_only = true; doesn't work with some uglify.js versions function asciify(text) { diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 405a73b4e45..321f4575ed9 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -239,7 +239,7 @@ var TextInput = function(parentNode, host) { } catch(e){} } inComposition = false; - } + }; if (isFocused) host.onFocus(); @@ -645,7 +645,7 @@ var TextInput = function(parentNode, host) { var key = null; var modifier = 0; - console.log(selectionStart, selectionEnd) + console.log(selectionStart, selectionEnd); if (selectionStart == 0) { key = KEYS.up; } else if (selectionStart == 1) { @@ -653,7 +653,7 @@ var TextInput = function(parentNode, host) { } else if (selectionEnd > lastSelectionEnd && lastValue[selectionEnd] == "\n") { key = KEYS.end; } else if (selectionStart < lastSelectionStart && lastValue[selectionStart - 1] == " ") { - key = KEYS.left + key = KEYS.left; modifier = MODS.option; } else if ( selectionStart < lastSelectionStart @@ -667,7 +667,7 @@ var TextInput = function(parentNode, host) { } else if (selectionEnd > lastSelectionEnd && lastValue.slice(0, selectionEnd).split("\n").length > 2) { key = KEYS.down; } else if (selectionEnd > lastSelectionEnd && lastValue[selectionEnd - 1] == " ") { - key = KEYS.right + key = KEYS.right; modifier = MODS.option; } else if ( selectionEnd > lastSelectionEnd @@ -687,7 +687,7 @@ var TextInput = function(parentNode, host) { host.onCommandKey(null, modifier, key); lastSelectionStart = selectionStart; lastSelectionEnd = selectionEnd; - resetSelection("") + resetSelection(""); } }; // On iOS, "selectionchange" can only be attached to the document object... From bb91e50945c63f0c2afa56310983ecae722d18f8 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 13 Nov 2018 19:50:09 +0400 Subject: [PATCH 0101/1293] fix text blinking when scrolling up at the top --- lib/ace/renderloop.js | 17 +++++++++++++++-- lib/ace/virtual_renderer.js | 6 +++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/ace/renderloop.js b/lib/ace/renderloop.js index 93d8de6e9c6..805df36ce75 100644 --- a/lib/ace/renderloop.js +++ b/lib/ace/renderloop.js @@ -45,9 +45,11 @@ var RenderLoop = function(onRender, win) { this.onRender = onRender; this.pending = false; this.changes = 0; + this.$recursionLimit = 2; this.window = win || window; var _self = this; this._flush = function(ts) { + _self.pending = false; var changes = _self.changes; if (changes) { @@ -56,8 +58,12 @@ var RenderLoop = function(onRender, win) { _self.onRender(changes); } - if (_self.changes) + if (_self.changes) { + if (_self.$recursionLimit-- < 0) return; _self.schedule(); + } else { + _self.$recursionLimit = 2; + } }; }; @@ -65,11 +71,18 @@ var RenderLoop = function(onRender, win) { this.schedule = function(change) { this.changes = this.changes | change; - if (this.changes) { + if (this.changes && !this.pending) { event.nextFrame(this._flush); + this.pending = true; } }; + this.clear = function(change) { + var changes = this.changes; + this.changes = 0; + return changes; + }; + }).call(RenderLoop.prototype); exports.RenderLoop = RenderLoop; diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 7f5eebcad3b..9dd767554d4 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -848,7 +848,7 @@ var VirtualRenderer = function(container, theme) { changes & this.CHANGE_SCROLL || changes & this.CHANGE_H_SCROLL ) { - changes |= this.$computeLayerConfig(); + changes |= this.$computeLayerConfig() | this.$loop.clear(); // If a change is made offscreen and wrapMode is on, then the onscreen // lines may have been pushed down. If so, the first screen row will not // have changed, but the first actual row will. In that case, adjust @@ -860,7 +860,7 @@ var VirtualRenderer = function(container, theme) { // this check is needed as a workaround for the documentToScreenRow returning -1 if document.length == 0 this.scrollTop = st; changes = changes | this.CHANGE_SCROLL; - changes |= this.$computeLayerConfig(); + changes |= this.$computeLayerConfig() | this.$loop.clear(); } } config = this.layerConfig; @@ -1007,7 +1007,6 @@ var VirtualRenderer = function(container, theme) { if (this.$maxLines && this.lineHeight > 1) this.$autosize(); - var offset = this.scrollTop % this.lineHeight; var minHeight = size.scrollerHeight + this.lineHeight; var scrollPastEnd = !this.$maxLines && this.$scrollPastEnd @@ -1030,6 +1029,7 @@ var VirtualRenderer = function(container, theme) { this.scrollBarV.setVisible(vScroll); } + var offset = this.scrollTop % this.lineHeight; var lineCount = Math.ceil(minHeight / this.lineHeight) - 1; var firstRow = Math.max(0, Math.round((this.scrollTop - offset) / this.lineHeight)); var lastRow = firstRow + lineCount; From 53ab0f5620827dc8b804edb144c3920e06c18dd9 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 13 Nov 2018 19:50:50 +0400 Subject: [PATCH 0102/1293] cleanup --- index.html | 56 ++++++++---------------------------------------------- 1 file changed, 8 insertions(+), 48 deletions(-) diff --git a/index.html b/index.html index f28a1b5c07e..d61b015c7d1 100644 --- a/index.html +++ b/index.html @@ -826,11 +826,6 @@

Projects Using Ace

style="left: 10px; top: -4px; width:80px" /> Codiad -
  • - - Plunker -
  • @@ -864,11 +859,6 @@

    Projects Using Ace

    style="left: 18px; top: 6px;"> MODX
  • -
  • - - Chrome Dev Editor -
  • @@ -878,15 +868,13 @@

    Projects Using Ace

    Code Combat
  • -
  • - - Repl.it + + ShareLaTeX +
  • +
  • + + Papeeria
  • Projects Using Ace Dillinger
  • -
  • - - Evaluzio -
  • CodeHelper @@ -941,10 +925,6 @@

    Projects Using Ace

    style="width: 106px; left: -4px; top: 26px;"> Simply Text
  • -
  • - - ShareLaTeX -
  • ACEView @@ -962,22 +942,11 @@

    Projects Using Ace

    Debuggex
  • -
  • -
    S
    - Slim Text -
  • Decor
  • -
  • - - Papeeria -
  • "); + next(); + }, + + "test beautify js object": function(next) { + var s = new EditSession([ + '' + ], new PHPMode()); + s.setUseSoftTabs(false); + + beautify.beautify(s); + assert.equal(s.getValue(), ""); + next(); } }; From 340260b4f9ebcad31d6f88fd36eabfb7dec32e47 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 17 Dec 2018 14:14:00 +0400 Subject: [PATCH 0119/1293] remove unnecessary use of innerHTML --- lib/ace/bidihandler.js | 2 +- lib/ace/ext/searchbox.js | 48 +++++++++++++++---------------- lib/ace/theme/solarized_light.css | 2 +- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/lib/ace/bidihandler.js b/lib/ace/bidihandler.js index cb8df42b12a..4d8adc3c9ac 100644 --- a/lib/ace/bidihandler.js +++ b/lib/ace/bidihandler.js @@ -178,7 +178,7 @@ var BidiHandler = function(session) { }); if (this.isRtlDir) { - this.fontMetrics.$main.innerHTML = (this.line.charAt(this.line.length - 1) == bidiUtil.DOT) ? this.line.substr(0, this.line.length - 1) : this.line; + this.fontMetrics.$main.textContent = (this.line.charAt(this.line.length - 1) == bidiUtil.DOT) ? this.line.substr(0, this.line.length - 1) : this.line; this.rtlLineOffset = this.contentWidth - this.fontMetrics.$main.getBoundingClientRect().width; } }; diff --git a/lib/ace/ext/searchbox.js b/lib/ace/ext/searchbox.js index 16910b68356..9812c8d614a 100644 --- a/lib/ace/ext/searchbox.js +++ b/lib/ace/ext/searchbox.js @@ -42,33 +42,31 @@ var MAX_COUNT = 999; dom.importCssString(searchboxCss, "ace_searchbox"); -var html = ''.replace(/> +/g, ">"); - var SearchBox = function(editor, range, showReplaceForm) { var div = dom.createElement("div"); - div.innerHTML = html; + dom.buildDom(["div", {class:"ace_search right"}, + ["span", {action: "hide", class: "ace_searchbtn_close"}], + ["div", {class: "ace_search_form"}, + ["input", {class: "ace_search_field", placeholder: "Search for", spellcheck: "false"}], + ["span", {action: "findPrev", class: "ace_searchbtn prev"}], + ["span", {action: "findNext", class: "ace_searchbtn next"}], + ["span", {action: "findAll", class: "ace_searchbtn", title: "Alt-Enter"}, "All"] + ], + ["div", {class: "ace_replace_form"}, + ["input", {class: "ace_search_field", placeholder: "Replace with", spellcheck: "false"}], + ["span", {action: "replaceAndFindNext", class: "ace_searchbtn"}, "Replace"], + ["span", {action: "replaceAll", class: "ace_searchbtn"}, "All"] + ], + ["div", {class: "ace_search_options"}, + ["span", {action: "toggleReplace", class: "ace_button", title: "Toggle Replace mode", + style: "float:left;margin-top:-2px;padding:0 5px;"}, "+"], + ["span", {class: "ace_search_counter"}], + ["span", {action: "toggleRegexpMode", class: "ace_button", title: "RegExp Search"}, ".*"], + ["span", {action: "toggleCaseSensitive", class: "ace_button", title: "CaseSensitive Search"}, "Aa"], + ["span", {action: "toggleWholeWords", class: "ace_button", title: "Whole Word Search"}, "\\b"], + ["span", {action: "searchInSelection", class: "ace_button", title: "Search In Selection"}, "S"] + ] + ], div); this.element = div.firstChild; this.setSession = this.setSession.bind(this); diff --git a/lib/ace/theme/solarized_light.css b/lib/ace/theme/solarized_light.css index 65399fdaa7b..9e48e4f4499 100644 --- a/lib/ace/theme/solarized_light.css +++ b/lib/ace/theme/solarized_light.css @@ -43,7 +43,7 @@ } .ace-solarized-light .ace_marker-layer .ace_selected-word { - border: 1px solid #073642 + border: 1px solid #7f9390 } .ace-solarized-light .ace_invisible { From 87ce087ed1cf20eeabe56fb0894e048d9bc9c481 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 17 Dec 2018 14:32:17 +0400 Subject: [PATCH 0120/1293] fix exception in markdown mode --- lib/ace/mode/behaviour/behaviour_test.js | 8 +++++++- lib/ace/mode/text.js | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/ace/mode/behaviour/behaviour_test.js b/lib/ace/mode/behaviour/behaviour_test.js index 6c8580f7818..7b8ca79e6d3 100644 --- a/lib/ace/mode/behaviour/behaviour_test.js +++ b/lib/ace/mode/behaviour/behaviour_test.js @@ -48,6 +48,7 @@ var RustMode = require("../rust").Mode; var XMLMode = require("../xml").Mode; var HTMLMode = require("../html").Mode; var CSSMode = require("../css").Mode; +var MarkdownMode = require("../markdown").Mode; var editor; var exec = function(name, times, args) { do { @@ -388,8 +389,13 @@ module.exports = { editor.selection.moveTo(0, 3); exec("insertstring", 1, "!"); assert.equal(editor.getValue(), "a {!padding:10px!important;}"); + }, + "test: markdown": function() { + editor.session.setMode(new MarkdownMode()); + editor.setValue("```html", 1); + exec("insertstring", 1, "\n"); + assert.equal(editor.getValue(), "```html\n"); } - }; }); diff --git a/lib/ace/mode/text.js b/lib/ace/mode/text.js index ec9bdc61c37..152f884ac0e 100644 --- a/lib/ace/mode/text.js +++ b/lib/ace/mode/text.js @@ -296,7 +296,7 @@ var Mode = function() { }; this.$delegator = function(method, args, defaultHandler) { - var state = args[0]; + var state = args[0] || "start"; if (typeof state != "string") { if (Array.isArray(state[2])) { var language = state[2][state[2].length - 1]; @@ -304,7 +304,7 @@ var Mode = function() { if (mode) return mode[method].apply(mode, [state[1]].concat([].slice.call(args, 1))); } - state = state[0]; + state = state[0] || "start"; } for (var i = 0; i < this.$embeds.length; i++) { From 8a588da6063c085c5c55da42918d23925cd2bf08 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 18 Dec 2018 18:40:29 +0400 Subject: [PATCH 0121/1293] fix highlighting of (*) in fsharp mode --- demo/kitchen-sink/docs/fsharp.fsi | 1 + lib/ace/mode/fsharp_highlight_rules.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/demo/kitchen-sink/docs/fsharp.fsi b/demo/kitchen-sink/docs/fsharp.fsi index 6be8a8a099c..43d6cf6547e 100644 --- a/demo/kitchen-sink/docs/fsharp.fsi +++ b/demo/kitchen-sink/docs/fsharp.fsi @@ -1,5 +1,6 @@ (* fsharp (* example *) *) module Test = + let (*) x y = (x + y) let func1 x = if x < 100 then x*x diff --git a/lib/ace/mode/fsharp_highlight_rules.js b/lib/ace/mode/fsharp_highlight_rules.js index 9291d93a418..a968f2a9414 100644 --- a/lib/ace/mode/fsharp_highlight_rules.js +++ b/lib/ace/mode/fsharp_highlight_rules.js @@ -61,7 +61,7 @@ var FSharpHighlightRules = function () { }, { token: "comment.start", - regex: /\(\*/, + regex: /\(\*(?!\))/, push: "blockComment" }, { @@ -135,7 +135,7 @@ var FSharpHighlightRules = function () { }, { token: "keyword.operator", - regex: "\\+\\.|\\-\\.|\\*\\.|\\/\\.|#|;;|\\+|\\-|\\*|\\*\\*\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|<-|=" + regex: "\\+\\.|\\-\\.|\\*\\.|\\/\\.|#|;;|\\+|\\-|\\*|\\*\\*\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|<-|=|\\(\\*\\)" }, { token: "paren.lpar", From e2c3b79ce6158362957e604a9bd105857bba0eaa Mon Sep 17 00:00:00 2001 From: "Burt.K" Date: Sun, 23 Dec 2018 00:46:48 +0900 Subject: [PATCH 0122/1293] Add open, internal and fileprivate access level keywords --- lib/ace/mode/swift_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/swift_highlight_rules.js b/lib/ace/mode/swift_highlight_rules.js index 86c0fecf9fb..55b49cd3fcb 100644 --- a/lib/ace/mode/swift_highlight_rules.js +++ b/lib/ace/mode/swift_highlight_rules.js @@ -50,7 +50,7 @@ var SwiftHighlightRules = function() { + "|convenience|dynamic|final|infix|lazy|mutating|nonmutating|optional|override|postfix" + "|prefix|required|static|guard|defer", "storage.type": "bool|double|Double" - + "|extension|float|Float|int|Int|private|public|string|String", + + "|extension|float|Float|int|Int|open|internal|fileprivate|private|public|string|String", "constant.language": "false|Infinity|NaN|nil|no|null|null|off|on|super|this|true|undefined|yes", "support.function": From 30522154a1d7fe37744def3fae4bc3d0a74319bc Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 24 Dec 2018 20:15:03 +0400 Subject: [PATCH 0123/1293] add option to allow loading worker directly --- lib/ace/config.js | 3 ++- lib/ace/keyboard/vim.js | 2 +- lib/ace/worker/worker_client.js | 15 +++++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/ace/config.js b/lib/ace/config.js index 2bbc34df3fe..bfbd83f44fc 100644 --- a/lib/ace/config.js +++ b/lib/ace/config.js @@ -49,7 +49,8 @@ var options = { themePath: null, basePath: "", suffix: ".js", - $moduleUrls: {} + $moduleUrls: {}, + loadWorkerFromBlob: true }; exports.get = function(key) { diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index ec5965f79b3..5842aea46b1 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -497,7 +497,7 @@ define(function(require, exports, module) { return this.ace.textInput.getElement(); }; this.getWrapperElement = function() { - return this.ace.containter; + return this.ace.container; }; var optMap = { indentWithTabs: "useSoftTabs", diff --git a/lib/ace/worker/worker_client.js b/lib/ace/worker/worker_client.js index 5e667b69fb3..d28ee255a92 100644 --- a/lib/ace/worker/worker_client.js +++ b/lib/ace/worker/worker_client.js @@ -53,11 +53,14 @@ function $workerBlob(workerUrl) { function createWorker(workerUrl) { if (typeof Worker == "undefined") return { postMessage: function() {}, terminate: function() {} }; - var blob = $workerBlob(workerUrl); - var URL = window.URL || window.webkitURL; - var blobURL = URL.createObjectURL(blob); - // calling URL.revokeObjectURL before worker is terminated breaks it on IE Edge - return new Worker(blobURL); + if (config.get("loadWorkerFromBlob")) { + var blob = $workerBlob(workerUrl); + var URL = window.URL || window.webkitURL; + var blobURL = URL.createObjectURL(blob); + // calling URL.revokeObjectURL before worker is terminated breaks it on IE Edge + return new Worker(blobURL); + } + return new Worker(workerUrl); } var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl, importScripts) { @@ -81,7 +84,7 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl, impor }); } - this.$worker = createWorker(workerUrl); + this.$worker = exports.createWorker(workerUrl); if (importScripts) { this.send("importScripts", importScripts); } From 8fb88ea6f8711ab63ba9b9c6e2d4a12d571edf49 Mon Sep 17 00:00:00 2001 From: JQ Zhu Date: Tue, 25 Dec 2018 13:45:05 +0800 Subject: [PATCH 0124/1293] nameOverrides AutoHotKey to "AutoHotkey / AutoIt" --- lib/ace/ext/modelist.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index d45a4dd5df1..f4ea2fde9a4 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -213,7 +213,8 @@ var nameOverrides = { HTML_Elixir: "HTML (Elixir)", FTL: "FreeMarker", PHP_Laravel_blade: "PHP (Blade Template)", - Perl6: "Perl 6" + Perl6: "Perl 6", + AutoHotKey: "AutoHotkey / AutoIt" }; var modesByName = {}; for (var name in supportedModes) { From 0d95ca3c06230b5504f77c9d9cd01f4a9e9a6cd5 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 29 Jan 2019 00:28:27 +0400 Subject: [PATCH 0125/1293] add option to switch text direction for the whole editor --- demo/kitchen-sink/demo.js | 6 +++++- lib/ace/bidihandler.js | 4 +++- lib/ace/ext/rtl.js | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index da9704b7896..d8909ff1c26 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -369,7 +369,11 @@ optionsPanel.add({ } }, More: { - "Rtl Text": { + "RTL": { + path: "rtl", + position: 900 + }, + "Line based RTL switching": { path: "rtlText", position: 900 }, diff --git a/lib/ace/bidihandler.js b/lib/ace/bidihandler.js index 4d8adc3c9ac..097babdd8f2 100644 --- a/lib/ace/bidihandler.js +++ b/lib/ace/bidihandler.js @@ -58,6 +58,7 @@ var BidiHandler = function(session) { this.EOL = "\xAC"; this.showInvisibles = true; this.isRtlDir = false; + this.$isRtl = false; this.line = ""; this.wrapIndent = 0; this.EOF = "\xB6"; @@ -143,7 +144,7 @@ var BidiHandler = function(session) { this.wrapIndent = 0; this.line = this.session.getLine(docRow); - this.isRtlDir = this.line.charAt(0) === this.RLE; + this.isRtlDir = this.$isRtl || this.line.charAt(0) === this.RLE; if (this.session.$useWrapMode) { var splits = this.session.$wrapData[docRow]; if (splits) { @@ -234,6 +235,7 @@ var BidiHandler = function(session) { }; this.isRtlLine = function(row) { + if (this.$isRtl) return true; if (row != undefined) return (this.session.getLine(row).charAt(0) == this.RLE); else diff --git a/lib/ace/ext/rtl.js b/lib/ace/ext/rtl.js index 4ab2f140b4d..07405c5d6e1 100644 --- a/lib/ace/ext/rtl.js +++ b/lib/ace/ext/rtl.js @@ -40,6 +40,20 @@ require("../config").defineOptions(Editor.prototype, "editor", { } this.renderer.updateFull(); } + }, + rtl: { + set: function(val) { + this.session.$bidiHandler.$isRtl = val; + if (val) { + this.setOption("rtlText", false); + this.renderer.on("afterRender", updateLineDirection); + this.session.$bidiHandler.seenBidi = true; + } else { + this.renderer.off("afterRender", updateLineDirection); + clearTextLayer(this.renderer); + } + this.renderer.updateFull(); + } } }); From 548af1e3e2e0df88ec2c5d4db36cd17a49fd05fd Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 29 Jan 2019 00:31:27 +0400 Subject: [PATCH 0126/1293] fix #3878: F# (*) operator within block comments --- lib/ace/mode/fsharp_highlight_rules.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ace/mode/fsharp_highlight_rules.js b/lib/ace/mode/fsharp_highlight_rules.js index a968f2a9414..98345f82702 100644 --- a/lib/ace/mode/fsharp_highlight_rules.js +++ b/lib/ace/mode/fsharp_highlight_rules.js @@ -147,7 +147,10 @@ var FSharpHighlightRules = function () { } ], blockComment: [{ - regex: /\(\*/, + regex: /\(\*\)/, + token: "comment" + }, { + regex: /\(\*(?!\))/, token: "comment.start", push: "blockComment" }, { From d09968e6206a52d3e60b73e55f1fe6144e04d8f4 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 29 Jan 2019 00:32:04 +0400 Subject: [PATCH 0127/1293] fix searchbox rendering in quirks mode --- lib/ace/ext/searchbox.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/ext/searchbox.js b/lib/ace/ext/searchbox.js index 9812c8d614a..76d1b28352f 100644 --- a/lib/ace/ext/searchbox.js +++ b/lib/ace/ext/searchbox.js @@ -48,8 +48,8 @@ var SearchBox = function(editor, range, showReplaceForm) { ["span", {action: "hide", class: "ace_searchbtn_close"}], ["div", {class: "ace_search_form"}, ["input", {class: "ace_search_field", placeholder: "Search for", spellcheck: "false"}], - ["span", {action: "findPrev", class: "ace_searchbtn prev"}], - ["span", {action: "findNext", class: "ace_searchbtn next"}], + ["span", {action: "findPrev", class: "ace_searchbtn prev"}, "\u200b"], + ["span", {action: "findNext", class: "ace_searchbtn next"}, "\u200b"], ["span", {action: "findAll", class: "ace_searchbtn", title: "Alt-Enter"}, "All"] ], ["div", {class: "ace_replace_form"}, From 3f4ec206a54ed35c8fa214525a608b885fcc9c51 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 29 Jan 2019 01:08:08 +0400 Subject: [PATCH 0128/1293] do not allow invalid value of tabsize to break the editor fixes #3879 --- lib/ace/edit_session.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 740d85a31d0..ba0167702f9 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -2529,6 +2529,7 @@ config.defineOptions(EditSession.prototype, "session", { useSoftTabs: {initialValue: true}, tabSize: { set: function(tabSize) { + tabSize = parseInt(tabSize); if (isNaN(tabSize) || this.$tabSize === tabSize) return; this.$modified = true; From c6ea9f0b22e6f43f199c2be6f5cba4751db810ab Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 29 Jan 2019 01:03:18 +0400 Subject: [PATCH 0129/1293] implement ` and < text objects in vim --- lib/ace/edit_session/bracket_match.js | 4 +++- lib/ace/keyboard/vim.js | 16 ++++++++++------ lib/ace/keyboard/vim_test.js | 4 ++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/ace/edit_session/bracket_match.js b/lib/ace/edit_session/bracket_match.js index 62a8499ca5e..ebd2aa94ce6 100644 --- a/lib/ace/edit_session/bracket_match.js +++ b/lib/ace/edit_session/bracket_match.js @@ -99,7 +99,9 @@ function BracketMatch() { "]": "[", "[": "]", "{": "}", - "}": "{" + "}": "{", + "<": ">", + ">": "<" }; this.$findOpeningBracket = function(bracket, position, typeRe) { diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index ec5965f79b3..7f641f4dd59 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -613,10 +613,11 @@ define(function(require, exports, module) { }; this.scanForBracket = function(pos, dir, _, options) { var re = options.bracketRegex.source; + var tokenRe = /paren|text|operator|tag/; if (dir == 1) { - var m = this.ace.session.$findClosingBracket(re.slice(1, 2), toAcePos(pos), /paren|text/); + var m = this.ace.session.$findClosingBracket(re.slice(1, 2), toAcePos(pos), tokenRe); } else { - var m = this.ace.session.$findOpeningBracket(re.slice(-2, -1), {row: pos.line, column: pos.ch + 1}, /paren|text/); + var m = this.ace.session.$findOpeningBracket(re.slice(-2, -1), {row: pos.line, column: pos.ch + 1}, tokenRe); } return m && {pos: toCmPos(m)}; }; @@ -2695,8 +2696,9 @@ dom.importCssString(".normal-mode .ace_cursor{\ // they're operators var mirroredPairs = {'(': ')', ')': '(', '{': '}', '}': '{', - '[': ']', ']': '['}; - var selfPaired = {'\'': true, '"': true}; + '[': ']', ']': '[', + '<': '>', '>': '<'}; + var selfPaired = {'\'': true, '"': true, '`': true}; var character = motionArgs.selectedCharacter; // 'b' refers to '()' block. @@ -4332,11 +4334,13 @@ dom.importCssString(".normal-mode .ace_cursor{\ var bracketRegexp = ({ '(': /[()]/, ')': /[()]/, '[': /[[\]]/, ']': /[[\]]/, - '{': /[{}]/, '}': /[{}]/})[symb]; + '{': /[{}]/, '}': /[{}]/, + '<': /[<>]/, '>': /[<>]/})[symb]; var openSym = ({ '(': '(', ')': '(', '[': '[', ']': '[', - '{': '{', '}': '{'})[symb]; + '{': '{', '}': '{', + '<': '<', '>': '<'})[symb]; var curChar = cm.getLine(cur.line).charAt(cur.ch); // Due to the behavior of scanForBracket, we need to add an offset if the // cursor is on a matching open bracket. diff --git a/lib/ace/keyboard/vim_test.js b/lib/ace/keyboard/vim_test.js index c64e17f8af8..cbe92ab1686 100644 --- a/lib/ace/keyboard/vim_test.js +++ b/lib/ace/keyboard/vim_test.js @@ -1353,6 +1353,10 @@ testEdit('di)_close_spc', 'foo (bAr) baz', /\)/, 'di)', 'foo () baz'); testEdit('da(_close_spc', 'foo (bAr) baz', /\)/, 'da(', 'foo baz'); testEdit('da)_close_spc', 'foo (bAr) baz', /\)/, 'da)', 'foo baz'); +testEdit('di`', 'foo `bAr` baz', /`/, 'di`', 'foo `` baz'); +testEdit('di>', 'foo baz', /', 'foo <> baz'); +testEdit('da<', 'foo baz', / Date: Fri, 8 Feb 2019 22:52:40 +0400 Subject: [PATCH 0130/1293] fix removeToLineStart at the start of the line --- lib/ace/editor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 1724765ea27..4c3e4f020ae 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -1426,7 +1426,8 @@ Editor.$uid = 0; this.removeToLineStart = function() { if (this.selection.isEmpty()) this.selection.selectLineStart(); - + if (this.selection.isEmpty()) + this.selection.selectLeft(); this.session.remove(this.getSelectionRange()); this.clearSelection(); }; From 23cd324d06609bddbd03810bdef44fd979f00589 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 27 Jul 2018 23:06:04 +0400 Subject: [PATCH 0131/1293] add sublime keybinding --- lib/ace/ext/options.js | 4 +- lib/ace/keyboard/state_handler.js | 249 ----------------- lib/ace/keyboard/sublime.js | 425 ++++++++++++++++++++++++++++++ lib/ace/keyboard/sublime_test.js | 75 ++++++ lib/ace/test/all_browser.js | 1 + 5 files changed, 503 insertions(+), 251 deletions(-) delete mode 100644 lib/ace/keyboard/state_handler.js create mode 100644 lib/ace/keyboard/sublime.js create mode 100644 lib/ace/keyboard/sublime_test.js diff --git a/lib/ace/ext/options.js b/lib/ace/ext/options.js index 21d2116a345..dafe40387c8 100644 --- a/lib/ace/ext/options.js +++ b/lib/ace/ext/options.js @@ -39,8 +39,8 @@ var optionGroups = { items: [ { caption : "Ace", value : null }, { caption : "Vim", value : "ace/keyboard/vim" }, - { caption : "Emacs", value : "ace/keyboard/emacs" } - // { caption : "Sublime", value : "ace/keyboard/sublime" } + { caption : "Emacs", value : "ace/keyboard/emacs" }, + { caption : "Sublime", value : "ace/keyboard/sublime" } ] }, "Font Size": { diff --git a/lib/ace/keyboard/state_handler.js b/lib/ace/keyboard/state_handler.js deleted file mode 100644 index 6859e743bd9..00000000000 --- a/lib/ace/keyboard/state_handler.js +++ /dev/null @@ -1,249 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Distributed under the BSD license: - * - * Copyright (c) 2010, Ajax.org B.V. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Ajax.org B.V. nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -define(function(require, exports, module) { -"use strict"; - -// If you're developing a new keymapping and want to get an idea what's going -// on, then enable debugging. -var DEBUG = false; - -function StateHandler(keymapping) { - this.keymapping = this.$buildKeymappingRegex(keymapping); -} - -StateHandler.prototype = { - /* - * Build the RegExp from the keymapping as RegExp can't stored directly - * in the metadata JSON and as the RegExp used to match the keys/buffer - * need to be adapted. - */ - $buildKeymappingRegex: function(keymapping) { - for (var state in keymapping) { - this.$buildBindingsRegex(keymapping[state]); - } - return keymapping; - }, - - $buildBindingsRegex: function(bindings) { - // Escape a given Regex string. - bindings.forEach(function(binding) { - if (binding.key) { - binding.key = new RegExp('^' + binding.key + '$'); - } else if (Array.isArray(binding.regex)) { - if (!('key' in binding)) - binding.key = new RegExp('^' + binding.regex[1] + '$'); - binding.regex = new RegExp(binding.regex.join('') + '$'); - } else if (binding.regex) { - binding.regex = new RegExp(binding.regex + '$'); - } - }); - }, - - $composeBuffer: function(data, hashId, key, e) { - // Initialize the data object. - if (data.state == null || data.buffer == null) { - data.state = "start"; - data.buffer = ""; - } - - var keyArray = []; - if (hashId & 1) keyArray.push("ctrl"); - if (hashId & 8) keyArray.push("command"); - if (hashId & 2) keyArray.push("option"); - if (hashId & 4) keyArray.push("shift"); - if (key) keyArray.push(key); - - var symbolicName = keyArray.join("-"); - var bufferToUse = data.buffer + symbolicName; - - // Don't add the symbolic name to the key buffer if the alt_ key is - // part of the symbolic name. If it starts with alt_, this means - // that the user hit an alt keycombo and there will be a single, - // new character detected after this event, which then will be - // added to the buffer (e.g. alt_j will result in ∆). - // - // We test for 2 and not for & 2 as we only want to exclude the case where - // the option key is pressed alone. - if (hashId != 2) { - data.buffer = bufferToUse; - } - - var bufferObj = { - bufferToUse: bufferToUse, - symbolicName: symbolicName - }; - - if (e) { - bufferObj.keyIdentifier = e.keyIdentifier; - } - - return bufferObj; - }, - - $find: function(data, buffer, symbolicName, hashId, key, keyIdentifier) { - // Holds the command to execute and the args if a command matched. - var result = {}; - - // Loop over all the bindings of the keymap until a match is found. - this.keymapping[data.state].some(function(binding) { - var match; - - // Check if the key matches. - if (binding.key && !binding.key.test(symbolicName)) { - return false; - } - - // Check if the regex matches. - if (binding.regex && !(match = binding.regex.exec(buffer))) { - return false; - } - - // Check if the match function matches. - if (binding.match && !binding.match(buffer, hashId, key, symbolicName, keyIdentifier)) { - return false; - } - - // Check for disallowed matches. - if (binding.disallowMatches) { - for (var i = 0; i < binding.disallowMatches.length; i++) { - if (!!match[binding.disallowMatches[i]]) { - return false; - } - } - } - - // If there is a command to execute, then figure out the - // command and the arguments. - if (binding.exec) { - result.command = binding.exec; - - // Build the arguments. - if (binding.params) { - var value; - result.args = {}; - binding.params.forEach(function(param) { - if (param.match != null && match != null) { - value = match[param.match] || param.defaultValue; - } else { - value = param.defaultValue; - } - - if (param.type === 'number') { - value = parseInt(value); - } - - result.args[param.name] = value; - }); - } - data.buffer = ""; - } - - // Handle the 'then' property. - if (binding.then) { - data.state = binding.then; - data.buffer = ""; - } - - // If no command is set, then execute the "null" fake command. - if (result.command == null) { - result.command = "null"; - } - - if (DEBUG) { - console.log("KeyboardStateMapper#find", binding); - } - return true; - }); - - if (result.command) { - return result; - } else { - data.buffer = ""; - return false; - } - }, - - /* - * This function is called by keyBinding. - */ - handleKeyboard: function(data, hashId, key, keyCode, e) { - if (hashId == -1) - hashId = 0; - // If we pressed any command key but no other key, then ignore the input. - // Otherwise "shift-" is added to the buffer, and later on "shift-g" - // which results in "shift-shift-g" which doesn't make sense. - if (hashId != 0 && (key == "" || key == String.fromCharCode(0))) { - return null; - } - - // Compute the current value of the keyboard input buffer. - var r = this.$composeBuffer(data, hashId, key, e); - var buffer = r.bufferToUse; - var symbolicName = r.symbolicName; - var keyId = r.keyIdentifier; - - r = this.$find(data, buffer, symbolicName, hashId, key, keyId); - if (DEBUG) { - console.log("KeyboardStateMapper#match", buffer, symbolicName, r); - } - - return r; - } -}; - -/* - * This is a useful matching function and therefore is defined here so that - * users of KeyboardStateMapper can use it. - * - * @return {Boolean} If no command key (Command|Option|Shift|Ctrl) is pressed, it - * returns true. If the only the Shift key is pressed + a character - * true is returned as well. Otherwise, false is returned. - * Summing up, the function returns true whenever the user typed - * a normal character on the keyboard and no shortcut. - */ -exports.matchCharacterOnly = function(buffer, hashId, key, symbolicName) { - // If no command keys are pressed, then catch the input. - if (hashId == 0) { - return true; - } - // If only the shift key is pressed and a character key, then - // catch that input as well. - else if ((hashId == 4) && key.length == 1) { - return true; - } - // Otherwise, we let the input got through. - else { - return false; - } -}; - -exports.StateHandler = StateHandler; -}); diff --git a/lib/ace/keyboard/sublime.js b/lib/ace/keyboard/sublime.js new file mode 100644 index 00000000000..0e6237bc632 --- /dev/null +++ b/lib/ace/keyboard/sublime.js @@ -0,0 +1,425 @@ +define(function(require, exports, module) { +"use strict"; + +var keyUtil = require("../lib/keys"); +var oop = require("../lib/oop"); +var useragent = require("../lib/useragent"); +var HashHandler = require("../keyboard/hash_handler").HashHandler; + +function moveBySubWords(editor, direction, extend) { + var selection = editor.selection; + var row = selection.lead.row; + var column = selection.lead.column; + + var line = editor.session.getLine(row); + if (!line[column + direction]) { + var method = (extend ? "selectWord" : "moveCursorShortWord") + + (direction == 1 ? "Right" : "Left"); + return editor.selection[method](); + } + if (direction == -1) column--; + while (line[column]) { + var type = getType(line[column]) + getType(line[column + direction]); + column += direction; + if (direction == 1) { + if (type == "WW" && getType(line[column + 1]) == "w") + break; + } + else { + if (type == "wW") { + if (getType(line[column - 1]) == "W") { + column -= 1; + break; + } else { + continue; + } + } + if (type == "Ww") + break; + } + if (/w[s_oW]|_[sWo]|o[s_wW]|s[W]|W[so]/.test(type)) + break; + } + if (direction == -1) column++; + if (extend) + editor.selection.moveCursorTo(row, column); + else + editor.selection.moveTo(row, column); + + function getType(x) { + if (!x) return "-"; + if (/\s/.test(x)) return "s"; + if (x == "_") return "_"; + if (x.toUpperCase() == x && x.toLowerCase() != x) return "W"; + if (x.toUpperCase() != x && x.toLowerCase() == x) return "w"; + return "o"; + } +} + +exports.handler = new HashHandler(); + +exports.handler.addCommands([{ + name: "find_all_under", + exec: function(editor) { + if (editor.selection.isEmpty()) + editor.selection.selectWord(); + editor.findAll(); + }, + readOnly: true +}, { + name: "find_under", + exec: function(editor) { + if (editor.selection.isEmpty()) + editor.selection.selectWord(); + editor.findNext(); + }, + readOnly: true +}, { + name: "find_under_prev", + exec: function(editor) { + if (editor.selection.isEmpty()) + editor.selection.selectWord(); + editor.findPrevious(); + }, + readOnly: true +}, { + name: "find_under_expand", + exec: function(editor) { + editor.selectMore(1, false, true); + }, + scrollIntoView: "animate", + readOnly: true +}, { + name: "find_under_expand_skip", + exec: function(editor) { + editor.selectMore(1, true, true); + }, + scrollIntoView: "animate", + readOnly: true +}, { + name: "delete_to_hard_bol", + exec: function(editor) { + var pos = editor.selection.getCursor(); + editor.session.remove({ + start: { row: pos.row, column: 0 }, + end: pos + }); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "delete_to_hard_eol", + exec: function(editor) { + var pos = editor.selection.getCursor(); + editor.session.remove({ + start: pos, + end: { row: pos.row, column: Infinity } + }); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "moveToWordStartLeft", + exec: function(editor) { + editor.selection.moveCursorLongWordLeft(); + editor.clearSelection(); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "moveToWordEndRight", + exec: function(editor) { + editor.selection.moveCursorLongWordRight(); + editor.clearSelection(); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "selectToWordStartLeft", + exec: function(editor) { + var sel = editor.selection; + sel.$moveSelection(sel.moveCursorLongWordLeft); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "selectToWordEndRight", + exec: function(editor) { + var sel = editor.selection; + sel.$moveSelection(sel.moveCursorLongWordRight); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "selectSubWordRight", + exec: function(editor) { + moveBySubWords(editor, 1, true); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectSubWordLeft", + exec: function(editor) { + moveBySubWords(editor, -1, true); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "moveSubWordRight", + exec: function(editor) { + moveBySubWords(editor, 1); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "moveSubWordLeft", + exec: function(editor) { + moveBySubWords(editor, -1); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}]); + + +[{ + bindKey: { mac: "cmd-k cmd-backspace|cmd-backspace", win: "ctrl-shift-backspace|ctrl-k ctrl-backspace" }, + name: "removetolinestarthard" +}, { + bindKey: { mac: "cmd-k cmd-k|cmd-delete|ctrl-k", win: "ctrl-shift-delete|ctrl-k ctrl-k" }, + name: "removetolineendhard" +}, { + bindKey: { mac: "cmd-shift-d", win: "ctrl-shift-d" }, + name: "duplicateSelection" +}, { + bindKey: { mac: "cmd-l", win: "ctrl-l" }, + name: "expandtoline" +}, +{ + bindKey: {mac: "cmd-shift-a", win: "ctrl-shift-a"}, + name: "expandSelection", + args: {to: "tag"} +}, { + bindKey: {mac: "cmd-shift-j", win: "ctrl-shift-j"}, + name: "expandSelection", + args: {to: "indentation"} +}, { + bindKey: {mac: "ctrl-shift-m", win: "ctrl-shift-m"}, + name: "expandSelection", + args: {to: "brackets"} +}, { + bindKey: {mac: "cmd-shift-space", win: "ctrl-shift-space"}, + name: "expandSelection", + args: {to: "scope"} +}, +{ + bindKey: { mac: "ctrl-cmd-g", win: "alt-f3" }, + name: "find_all_under" +}, { + bindKey: { mac: "alt-cmd-g", win: "ctrl-f3" }, + name: "find_under" +}, { + bindKey: { mac: "shift-alt-cmd-g", win: "ctrl-shift-f3" }, + name: "find_under_prev" +}, { + bindKey: { mac: "cmd-g", win: "f3" }, + name: "findnext" +}, { + bindKey: { mac: "shift-cmd-g", win: "shift-f3" }, + name: "findprevious" +}, { + bindKey: { mac: "cmd-d", win: "ctrl-d" }, + name: "find_under_expand" +}, { + bindKey: { mac: "cmd-k cmd-d", win: "ctrl-k ctrl-d" }, + name: "find_under_expand_skip" +}, + +/* fold */ +{ + bindKey: { mac: "cmd-alt-[", win: "ctrl-shift-[" }, + name: "toggleFoldWidget" +}, { + bindKey: { mac: "cmd-alt-]", win: "ctrl-shift-]" }, + name: "unfold" +}, { + bindKey: { mac: "cmd-k cmd-0|cmd-k cmd-j", win: "ctrl-k ctrl-0|ctrl-k ctrl-j" }, + name: "unfoldall" +}, { + bindKey: { mac: "cmd-k cmd-1", win: "ctrl-k ctrl-1" }, + name: "foldOther", + args: { level: 1 } +}, + + +/* move */ +{ + bindKey: { win: "ctrl-left", mac: "alt-left" }, + name: "moveToWordStartLeft" +}, { + bindKey: { win: "ctrl-right", mac: "alt-right" }, + name: "moveToWordEndRight" +}, { + bindKey: { win: "ctrl-shift-left", mac: "alt-shift-left" }, + name: "selectToWordStartLeft" +}, { + bindKey: { win: "ctrl-shift-right", mac: "alt-shift-right" }, + name: "selectToWordEndRight" +}, + +// subwords +{ + bindKey: {mac: "ctrl-alt-shift-right|ctrl-shift-right", win: "alt-shift-right"}, + name: "selectSubWordRight" +}, { + bindKey: {mac: "ctrl-alt-shift-left|ctrl-shift-left", win: "alt-shift-left"}, + name: "selectSubWordLeft" +}, { + bindKey: {mac: "ctrl-alt-right|ctrl-right", win: "alt-right"}, + name: "moveSubWordRight" +}, { + bindKey: {mac: "ctrl-alt-left|ctrl-left", win: "alt-left"}, + name: "moveSubWordLeft" +}, +{ + bindKey: { mac: "ctrl-m", win: "ctrl-m" }, + name: "jumptomatching", + args: { to: "brackets" } +}, +{ + bindKey: { mac: "ctrl-f6", win: "ctrl-f6" }, + name: "goToNextError" +}, { + bindKey: { mac: "ctrl-shift-f6", win: "ctrl-shift-f6" }, + name: "goToPreviousError" +}, + +{ + bindKey: { mac: "ctrl-o" }, + name: "splitline" +}, +{ + bindKey: {mac: "ctrl-shift-w", win: "alt-shift-w"}, + name: "surrowndWithTag" +},{ + bindKey: {mac: "cmd-alt-.", win: "alt-."}, + name: "close_tag" +}, +{ + bindKey: { mac: "cmd-j", win: "ctrl-j" }, + name: "joinlines" +}, + +{ + bindKey: {mac: "ctrl--", win: "alt--"}, + name: "jumpBack" +}, { + bindKey: {mac: "ctrl-shift--", win: "alt-shift--"}, + name: "jumpForward" +}, + +{ + bindKey: { mac: "cmd-k cmd-l", win: "ctrl-k ctrl-l" }, + name: "tolowercase" +}, { + bindKey: { mac: "cmd-k cmd-u", win: "ctrl-k ctrl-u" }, + name: "touppercase" +}, + +{ + bindKey: {mac: "cmd-shift-v", win: "ctrl-shift-v"}, + name: "paste_and_indent" +}, { + bindKey: {mac: "cmd-k cmd-v|cmd-alt-v", win: "ctrl-k ctrl-v"}, + name: "paste_from_history" +}, + +{ + bindKey: { mac: "cmd-shift-enter", win: "ctrl-shift-enter" }, + name: "addLineBefore" +}, { + bindKey: { mac: "cmd-enter", win: "ctrl-enter" }, + name: "addLineAfter" +}, { + bindKey: { mac: "ctrl-shift-k", win: "ctrl-shift-k" }, + name: "removeline" +}, { + bindKey: { mac: "ctrl-alt-up", win: "ctrl-up" }, + name: "scrollup" +}, { + bindKey: { mac: "ctrl-alt-down", win: "ctrl-down" }, + name: "scrolldown" +}, { + bindKey: { mac: "cmd-a", win: "ctrl-a" }, + name: "selectall" +}, { + bindKey: { linux: "alt-shift-down", mac: "ctrl-shift-down", win: "ctrl-alt-down" }, + name: "addCursorBelow" +}, { + bindKey: { linux: "alt-shift-up", mac: "ctrl-shift-up", win: "ctrl-alt-up" }, + name: "addCursorAbove" +}, + + +{ + bindKey: { mac: "cmd-k cmd-c|ctrl-l", win: "ctrl-k ctrl-c" }, + name: "centerselection" +}, + +{ + bindKey: { mac: "f5", win: "f9" }, + name: "sortlines" +}, +{ + bindKey: {mac: "ctrl-f5", win: "ctrl-f9"}, + name: "sortlines", + args: {caseSensitive: true} +}, +{ + bindKey: { mac: "cmd-shift-l", win: "ctrl-shift-l" }, + name: "splitIntoLines" +}, { + bindKey: { mac: "ctrl-cmd-down", win: "ctrl-shift-down" }, + name: "movelinesdown" +}, { + bindKey: { mac: "ctrl-cmd-up", win: "ctrl-shift-up" }, + name: "movelinesup" +}, { + bindKey: { mac: "alt-down", win: "alt-down" }, + name: "modifyNumberDown" +}, { + bindKey: { mac: "alt-up", win: "alt-up" }, + name: "modifyNumberUp" +}, { + bindKey: { mac: "cmd-/", win: "ctrl-/" }, + name: "togglecomment" +}, { + bindKey: { mac: "cmd-alt-/", win: "ctrl-shift-/" }, + name: "toggleBlockComment" +}, + + +{ + bindKey: { linux: "ctrl-alt-q", mac: "ctrl-q", win: "ctrl-q" }, + name: "togglerecording" +}, { + bindKey: { linux: "ctrl-alt-shift-q", mac: "ctrl-shift-q", win: "ctrl-shift-q" }, + name: "replaymacro" +}, + +{ + bindKey: { mac: "ctrl-t", win: "ctrl-t" }, + name: "transpose" +} + +].forEach(function(binding) { + var command = exports.handler.commands[binding.name]; + if (command) + command.bindKey = binding.bindKey; + exports.handler.bindKey(binding.bindKey, command || binding.name); +}); + +}); diff --git a/lib/ace/keyboard/sublime_test.js b/lib/ace/keyboard/sublime_test.js new file mode 100644 index 00000000000..9630c9d93c9 --- /dev/null +++ b/lib/ace/keyboard/sublime_test.js @@ -0,0 +1,75 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("../test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +require("../multi_select"); + +var EditSession = require("./../edit_session").EditSession; +var Editor = require("./../editor").Editor; +var Range = require("./../range").Range; +var MockRenderer = require("./../test/mockrenderer").MockRenderer; +var assert = require("./../test/assertions"); +var handler = require("./sublime").handler; +var editor; + +function initEditor(docString) { + var doc = new EditSession(docString.split("\n")); + editor = new Editor(new MockRenderer(), doc); + editor.setKeyboardHandler(handler); +} + +module.exports = { + + "test: move by subwords": function() { + initEditor("\n abcDefGHKLmn_op ++ xyz$\nt"); + + [0, 3, 6, 9, 12, 15, 18, 21, 25, 26, 0, 1, 1].forEach(function(col) { + assert.equal(editor.selection.lead.column, col); + editor.execCommand(handler.commands.moveSubWordRight); + }); + [1, 0, 26, 25, 22, 19, 16, 12, 9, 6, 3, 0, 0].forEach(function(col) { + assert.equal(editor.selection.lead.column, col); + editor.execCommand(handler.commands.moveSubWordLeft); + }); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/lib/ace/test/all_browser.js b/lib/ace/test/all_browser.js index 783289007af..13acb416d4c 100644 --- a/lib/ace/test/all_browser.js +++ b/lib/ace/test/all_browser.js @@ -32,6 +32,7 @@ var testNames = [ "ace/keyboard/keybinding_test", "ace/keyboard/vim_test", "ace/keyboard/vim_ace_test", + "ace/keyboard/sublime_test", "ace/layer/text_test", "ace/lib/event_emitter_test", "ace/mode/coffee/parser_test", From 5ec606ffcf780699ecfb663cbdbf9583c12a6d71 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Wed, 20 Feb 2019 00:02:07 +0400 Subject: [PATCH 0132/1293] fix highlighting of raw identifiers --- lib/ace/mode/rust_highlight_rules.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ace/mode/rust_highlight_rules.js b/lib/ace/mode/rust_highlight_rules.js index 538d9ccb2c9..718e79ee1bd 100644 --- a/lib/ace/mode/rust_highlight_rules.js +++ b/lib/ace/mode/rust_highlight_rules.js @@ -49,6 +49,8 @@ var RustHighlightRules = function() { regex: '\'[a-zA-Z_][a-zA-Z0-9_]*(?![\\\'])' }, { token: 'string.quoted.single.source.rust', regex: "'(?:[^'\\\\]|" + stringEscape + ")'" }, + { token: 'identifier', + regex: /r#[a-zA-Z_][a-zA-Z0-9_]*\b/ }, { stateName: "bracketedComment", onMatch : function(value, currentState, stack){ @@ -88,7 +90,7 @@ var RustHighlightRules = function() { regex: stringEscape }, { defaultToken: 'string.quoted.double.source.rust' } ] }, { token: [ 'keyword.source.rust', 'text', 'entity.name.function.source.rust' ], - regex: '\\b(fn)(\\s+)([a-zA-Z_][a-zA-Z0-9_]*)' }, + regex: '\\b(fn)(\\s+)((?:r#)?[a-zA-Z_][a-zA-Z0-9_]*)' }, { token: 'support.constant', regex: '\\b[a-zA-Z_][\\w\\d]*::' }, { token: 'keyword.source.rust', regex: '\\b(?:abstract|alignof|as|become|box|break|catch|continue|const|crate|default|do|dyn|else|enum|extern|for|final|if|impl|in|let|loop|macro|match|mod|move|mut|offsetof|override|priv|proc|pub|pure|ref|return|self|sizeof|static|struct|super|trait|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\\b' }, From 58828f5613fc8865dc6ffeb1d3365aa62c5ee09c Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 5 Feb 2019 00:05:22 +0400 Subject: [PATCH 0133/1293] allow passing Worker instance to WorkerClient --- lib/ace/worker/worker_client.js | 97 +++++++++++++++++---------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/lib/ace/worker/worker_client.js b/lib/ace/worker/worker_client.js index d28ee255a92..7c7be791738 100644 --- a/lib/ace/worker/worker_client.js +++ b/lib/ace/worker/worker_client.js @@ -63,37 +63,14 @@ function createWorker(workerUrl) { return new Worker(workerUrl); } -var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl, importScripts) { +var WorkerClient = function(worker) { + if (!worker.postMessage) + worker = this.$createWorkerFromOldConfig.apply(this, arguments); + + this.$worker = worker; this.$sendDeltaQueue = this.$sendDeltaQueue.bind(this); this.changeListener = this.changeListener.bind(this); this.onMessage = this.onMessage.bind(this); - - // nameToUrl is renamed to toUrl in requirejs 2 - if (require.nameToUrl && !require.toUrl) - require.toUrl = require.nameToUrl; - - if (config.get("packaged") || !require.toUrl) { - workerUrl = workerUrl || config.moduleUrl(mod, "worker"); - } else { - var normalizePath = this.$normalizePath; - workerUrl = workerUrl || normalizePath(require.toUrl("ace/worker/worker.js", null, "_")); - - var tlns = {}; - topLevelNamespaces.forEach(function(ns) { - tlns[ns] = normalizePath(require.toUrl(ns, null, "_").replace(/(\.js)?(\?.*)?$/, "")); - }); - } - - this.$worker = exports.createWorker(workerUrl); - if (importScripts) { - this.send("importScripts", importScripts); - } - this.$worker.postMessage({ - init : true, - tlns : tlns, - module : mod, - classname : classname - }); this.callbackId = 1; this.callbacks = {}; @@ -105,6 +82,36 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl, impor oop.implement(this, EventEmitter); + this.$createWorkerFromOldConfig = function(topLevelNamespaces, mod, classname, workerUrl, importScripts) { + // nameToUrl is renamed to toUrl in requirejs 2 + if (require.nameToUrl && !require.toUrl) + require.toUrl = require.nameToUrl; + + if (config.get("packaged") || !require.toUrl) { + workerUrl = workerUrl || config.moduleUrl(mod, "worker"); + } else { + var normalizePath = this.$normalizePath; + workerUrl = workerUrl || normalizePath(require.toUrl("ace/worker/worker.js", null, "_")); + + var tlns = {}; + topLevelNamespaces.forEach(function(ns) { + tlns[ns] = normalizePath(require.toUrl(ns, null, "_").replace(/(\.js)?(\?.*)?$/, "")); + }); + } + + this.$worker = createWorker(workerUrl); + if (importScripts) { + this.send("importScripts", importScripts); + } + this.$worker.postMessage({ + init : true, + tlns : tlns, + module : mod, + classname : classname + }); + return this.$worker; + }; + this.onMessage = function(e) { var msg = e.data; switch (msg.type) { @@ -205,32 +212,28 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl, impor var UIWorkerClient = function(topLevelNamespaces, mod, classname) { - this.$sendDeltaQueue = this.$sendDeltaQueue.bind(this); - this.changeListener = this.changeListener.bind(this); - this.callbackId = 1; - this.callbacks = {}; - this.messageBuffer = []; - var main = null; var emitSync = false; var sender = Object.create(EventEmitter); - var _self = this; - this.$worker = {}; - this.$worker.terminate = function() {}; - this.$worker.postMessage = function(e) { - _self.messageBuffer.push(e); - if (main) { + var messageBuffer = []; + var workerClient = new WorkerClient({ + messageBuffer: messageBuffer, + terminate: function() {}, + postMessage: function(e) { + messageBuffer.push(e); + if (!main) return; if (emitSync) setTimeout(processNext); else processNext(); } - }; - this.setEmitSync = function(val) { emitSync = val; }; + }); + + workerClient.setEmitSync = function(val) { emitSync = val; }; var processNext = function() { - var msg = _self.messageBuffer.shift(); + var msg = messageBuffer.shift(); if (msg.command) main[msg.command].apply(main, msg.args); else if (msg.event) @@ -238,7 +241,7 @@ var UIWorkerClient = function(topLevelNamespaces, mod, classname) { }; sender.postMessage = function(msg) { - _self.onMessage({data: msg}); + workerClient.onMessage({data: msg}); }; sender.callback = function(data, callbackId) { this.postMessage({type: "call", id: callbackId, data: data}); @@ -249,12 +252,12 @@ var UIWorkerClient = function(topLevelNamespaces, mod, classname) { config.loadModule(["worker", mod], function(Main) { main = new Main[classname](sender); - while (_self.messageBuffer.length) + while (messageBuffer.length) processNext(); }); -}; -UIWorkerClient.prototype = WorkerClient.prototype; + return workerClient; +}; exports.UIWorkerClient = UIWorkerClient; exports.WorkerClient = WorkerClient; From abc6330dee91048ae79d1359247e4f071d8358be Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 21 Feb 2019 15:51:39 +0400 Subject: [PATCH 0134/1293] enable css completions in scss mode --- lib/ace/mode/css_completions.js | 6 +----- lib/ace/mode/scss.js | 8 ++++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/ace/mode/css_completions.js b/lib/ace/mode/css_completions.js index bda5f11b5f3..178e7ed93ae 100644 --- a/lib/ace/mode/css_completions.js +++ b/lib/ace/mode/css_completions.js @@ -156,11 +156,7 @@ var CssCompletions = function() { this.defineCompletions(); } - var token = session.getTokenAt(pos.row, pos.column); - - if (!token) - return []; - if (state==='ruleset'){ + if (state==='ruleset' || session.$mode.$id == "ace/mode/scss") { //css attribute value var line = session.getLine(pos.row).substr(0, pos.column); if (/:[^;]+$/.test(line)) { diff --git a/lib/ace/mode/scss.js b/lib/ace/mode/scss.js index f672d2571cf..bffc3bbb45c 100644 --- a/lib/ace/mode/scss.js +++ b/lib/ace/mode/scss.js @@ -37,11 +37,14 @@ var ScssHighlightRules = require("./scss_highlight_rules").ScssHighlightRules; var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; var CssBehaviour = require("./behaviour/css").CssBehaviour; var CStyleFoldMode = require("./folding/cstyle").FoldMode; +var CssCompletions = require("./css_completions").CssCompletions; + var Mode = function() { this.HighlightRules = ScssHighlightRules; this.$outdent = new MatchingBraceOutdent(); this.$behaviour = new CssBehaviour(); + this.$completer = new CssCompletions(); this.foldingRules = new CStyleFoldMode(); }; oop.inherits(Mode, TextMode); @@ -75,6 +78,11 @@ oop.inherits(Mode, TextMode); this.autoOutdent = function(state, doc, row) { this.$outdent.autoOutdent(doc, row); }; + + this.getCompletions = function(state, session, pos, prefix) { + return this.$completer.getCompletions(state, session, pos, prefix); + }; + this.$id = "ace/mode/scss"; }).call(Mode.prototype); From b23ed2497333b18bf7d7dc4d1fb25d6a59198f9f Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 21 Feb 2019 16:54:36 +0400 Subject: [PATCH 0135/1293] release v1.4.3 --- ChangeLog.txt | 5 +++++ Makefile.dryice.js | 2 +- build | 2 +- lib/ace/ace.js | 2 +- package.json | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index edb2a450d89..6be5d6d98b1 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,8 @@ +2019.02.21 Version 1.4.3 +* add sublime keybindings +* add rtl option +* implement ` and < textobjects in vim mode + 2018.11.21 Version 1.4.2 * fix regression in vim mode * improve keyboard input handling on ipad and IE diff --git a/Makefile.dryice.js b/Makefile.dryice.js index d7d5e33b6a9..dc5776114f9 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -397,7 +397,7 @@ function buildAce(options, callback) { }, "theme-" + name, addCb()); }); // keybindings - ["vim", "emacs"].forEach(function(name) { + ["vim", "emacs", "sublime"].forEach(function(name) { buildSubmodule(options, { projectType: "keybinding", require: ["ace/keyboard/" + name ] diff --git a/build b/build index 0d62c26de7b..32e27226d66 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 0d62c26de7b2e1922d8dd95ba587c9845c018c51 +Subproject commit 32e27226d66b2f3a63d4e393853f84ef3e17a003 diff --git a/lib/ace/ace.js b/lib/ace/ace.js index cdd0e6fe03e..a40add50732 100644 --- a/lib/ace/ace.js +++ b/lib/ace/ace.js @@ -132,5 +132,5 @@ exports.Editor = Editor; exports.EditSession = EditSession; exports.UndoManager = UndoManager; exports.VirtualRenderer = Renderer; -exports.version = "1.4.2"; +exports.version = "1.4.3"; }); diff --git a/package.json b/package.json index a3d44ced9a5..7d4405cd5f1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.4.2", + "version": "1.4.3", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" From 6babd4889ed1182252d71fae80fac5930e2e0368 Mon Sep 17 00:00:00 2001 From: Philip Pham Date: Thu, 21 Feb 2019 19:59:00 -0800 Subject: [PATCH 0136/1293] Fixes Emacs' killRingSave Behavior The mark should be cleared when saving to the kill ring. This is consistent with the actual behvaior of Emacs. The change is similar to #2821. Tested in the kitchen sink. --- lib/ace/keyboard/emacs.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ace/keyboard/emacs.js b/lib/ace/keyboard/emacs.js index fe8be728cce..988ec7cce25 100644 --- a/lib/ace/keyboard/emacs.js +++ b/lib/ace/keyboard/emacs.js @@ -598,6 +598,7 @@ exports.handler.addCommands({ editor.$handlesEmacsOnCopy = false; if (editor.inMultiSelectMode) editor.forEachSelection({exec: deselect}); else deselect(); + editor.setEmacsMark(null); editor.session.$emacsMarkRing = marks.concat(deselectedMarks.reverse()); }, 0); }, From ffe830515465da890b6e13c2f33ca463f73c3377 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 4 Mar 2019 19:59:37 +0400 Subject: [PATCH 0137/1293] add nim and nginx modes --- demo/kitchen-sink/docs/nginx.nginx | 70 +++++++++ demo/kitchen-sink/docs/nim.nim | 15 ++ lib/ace/ext/modelist.js | 2 + lib/ace/mode/nginx.js | 55 +++++++ lib/ace/mode/nim.js | 57 ++++++++ lib/ace/mode/nim_highlight_rules.js | 217 ++++++++++++++++++++++++++++ 6 files changed, 416 insertions(+) create mode 100644 demo/kitchen-sink/docs/nginx.nginx create mode 100644 demo/kitchen-sink/docs/nim.nim create mode 100644 lib/ace/mode/nginx.js create mode 100644 lib/ace/mode/nim.js create mode 100644 lib/ace/mode/nim_highlight_rules.js diff --git a/demo/kitchen-sink/docs/nginx.nginx b/demo/kitchen-sink/docs/nginx.nginx new file mode 100644 index 00000000000..5fec6bc14eb --- /dev/null +++ b/demo/kitchen-sink/docs/nginx.nginx @@ -0,0 +1,70 @@ +user www www; ## Default: nobody +worker_processes 5; ## Default: 1 +error_log logs/error.log; +pid logs/nginx.pid; +worker_rlimit_nofile 8192; + +events { + worker_connections 4096; ## Default: 1024 +} + +http { + include conf/mime.types; + include /etc/nginx/proxy.conf; + include /etc/nginx/fastcgi.conf; + index index.html index.htm index.php; + + default_type application/octet-stream; + log_format main '$remote_addr - $remote_user [$time_local] $status ' + '"$request" $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + access_log logs/access.log main; + sendfile on; + tcp_nopush on; + server_names_hash_bucket_size 128; # this seems to be required for some vhosts + + server { # php/fastcgi + listen 80; + server_name domain1.com www.domain1.com; + access_log logs/domain1.access.log main; + root html; + + location ~ \.php$ { + fastcgi_pass 127.0.0.1:1025; + } + } + + server { # simple reverse-proxy + listen 80; + server_name domain2.com www.domain2.com; + access_log logs/domain2.access.log main; + + # serve static files + location ~ ^/(images|javascript|js|css|flash|media|static)/ { + root /var/www/virtual/big.server.com/htdocs; + expires 30d; + } + + # pass requests for dynamic content to rails/turbogears/zope, et al + location / { + proxy_pass http://127.0.0.1:8080; + } + } + + upstream big_server_com { + server 127.0.0.3:8000 weight=5; + server 127.0.0.3:8001 weight=5; + server 192.168.0.1:8000; + server 192.168.0.1:8001; + } + + server { # simple load balancing + listen 80; + server_name big.server.com; + access_log logs/big.server.access.log main; + + location / { + proxy_pass http://big_server_com; + } + } +} \ No newline at end of file diff --git a/demo/kitchen-sink/docs/nim.nim b/demo/kitchen-sink/docs/nim.nim new file mode 100644 index 00000000000..834514ab2c5 --- /dev/null +++ b/demo/kitchen-sink/docs/nim.nim @@ -0,0 +1,15 @@ +#[ #[ Multiline comment in already + commented out code. ]# +proc p[T](x: T) = discard +]# +echo "This is code" +var + p = 0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64 + +proc getAlphabet(): string = + var accm = "" + for letter in 'a'..'z': # see iterators + accm.add(letter) + return accm + +assert("a" * 10 == "aaaaaaaaaa") diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index f4ea2fde9a4..7fbb9140d7b 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -134,7 +134,9 @@ var supportedModes = { MIXAL: ["mixal"], MUSHCode: ["mc|mush"], MySQL: ["mysql"], + Nginx: ["nginx|conf"], Nix: ["nix"], + Nim: ["nim"], NSIS: ["nsi|nsh"], ObjectiveC: ["m|mm"], OCaml: ["ml|mli"], diff --git a/lib/ace/mode/nginx.js b/lib/ace/mode/nginx.js new file mode 100644 index 00000000000..9a20d3c2a56 --- /dev/null +++ b/lib/ace/mode/nginx.js @@ -0,0 +1,55 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function (require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var NginxHighlightRules = require("./nginx_highlight_rules").NginxHighlightRules; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function () { + TextMode.call(this); + this.HighlightRules = NginxHighlightRules; + this.foldingRules = new CStyleFoldMode(); +}; + +oop.inherits(Mode, TextMode); + + +(function () { + this.lineCommentStart = "#"; + + this.$id = "ace/mode/nginx"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/nim.js b/lib/ace/mode/nim.js new file mode 100644 index 00000000000..51462e7728d --- /dev/null +++ b/lib/ace/mode/nim.js @@ -0,0 +1,57 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function (require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var NimHighlightRules = require("./nim_highlight_rules").NimHighlightRules; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function () { + TextMode.call(this); + this.HighlightRules = NimHighlightRules; + this.foldingRules = new CStyleFoldMode(); +}; + +oop.inherits(Mode, TextMode); + + +(function () { + this.lineCommentStart = "#"; + this.blockComment = {start: "#[", end: "]#", nestable: true}; + + + this.$id = "ace/mode/nim"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/nim_highlight_rules.js b/lib/ace/mode/nim_highlight_rules.js new file mode 100644 index 00000000000..5d9158e19f8 --- /dev/null +++ b/lib/ace/mode/nim_highlight_rules.js @@ -0,0 +1,217 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function (require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; +var NimHighlightRules = function () { + + var keywordMapper = this.createKeywordMapper({ + "variable": "var|let|const", + "keyword": "assert|parallel|spawn|export|include|from|template|mixin|bind|import|concept|raise|defer|try|finally|except|converter|proc|func|macro|method|and|or|not|xor|shl|shr|div|mod|in|notin|is|isnot|of|static|if|elif|else|case|of|discard|when|return|yield|block|break|while|echo|continue|asm|using|cast|addr|unsafeAddr|type|ref|ptr|do|declared|defined|definedInScope|compiles|sizeOf|is|shallowCopy|getAst|astToStr|spawn|procCall|for|iterator|as", + "storage.type": "newSeq|int|int8|int16|int32|int64|uint|uint8|uint16|uint32|uint64|float|char|bool|string|set|pointer|float32|float64|enum|object|cstring|array|seq|openArray|varargs|UncheckedArray|tuple|set|distinct|void|auto|openarray|range", + "support.function": "lock|ze|toU8|toU16|toU32|ord|low|len|high|add|pop|contains|card|incl|excl|dealloc|inc", + "constant.language": "nil|true|false" + }, "identifier"); + + var hexNumber = "(?:0[xX][\\dA-Fa-f][\\dA-Fa-f_]*)"; + var decNumber = "(?:[0-9][\\d_]*)"; + var octNumber = "(?:0o[0-7][0-7_]*)"; + var binNumber = "(?:0[bB][01][01_]*)"; + var intNumber = "(?:" + hexNumber + "|" + decNumber + "|" + octNumber + "|" + binNumber + ")(?:'?[iIuU](?:8|16|32|64)|u)?\\b"; + var exponent = "(?:[eE][+-]?[\\d][\\d_]*)"; + var floatNumber = "(?:[\\d][\\d_]*(?:[.][\\d](?:[\\d_]*)" + exponent + "?)|" + exponent + ")"; + var floatNumberExt = "(?:" + hexNumber + "(?:'(?:(?:[fF](?:32|64)?)|[dD])))|(?:" + floatNumber + "|" + decNumber + "|" + octNumber + "|" + binNumber + ")(?:'(?:(?:[fF](?:32|64)?)|[dD]))"; + var stringEscape = "\\\\([abeprcnlftv\\\"']|x[0-9A-Fa-f]{2}|[0-2][0-9]{2}|u[0-9A-Fa-f]{8}|u[0-9A-Fa-f]{4})"; + var identifier = '[a-zA-Z][a-zA-Z0-9_]*'; + this.$rules = { + "start": [{ + token: ["identifier", "keyword.operator", "support.function"], + regex: "(" + identifier + ")([.]{1})(" + identifier + ")(?=\\()" + }, {//pragmas + token: "paren.lpar", + regex: "(\\{\\.)", + next: [{ + token: "paren.rpar", + regex: '(\\.\\}|\\})', + next: "start" + }, { + include: "methods" + }, { + token: "identifier", + regex: identifier + }, { + token: "punctuation", + regex: /[,]/ + }, { + token: "keyword.operator", + regex: /[=:.]/ + }, { + token: "paren.lpar", + regex: /[[(]/ + }, { + token: "paren.rpar", + regex: /[\])]/ + }, { + include: "math" + }, { + include: "strings" + }, { + defaultToken: "text" + }] + }, { + token: "comment.doc.start", + regex: /##\[(?!])/, + push: "docBlockComment" + }, { + token: "comment.start", + regex: /#\[(?!])/, + push: "blockComment" + }, { + token: "comment.doc", + regex: '##.*$' + }, { + token: "comment", + regex: '#.*$' + }, { + include: "strings" + }, {// character + token: "string", + regex: "'(?:\\\\(?:[abercnlftv]|x[0-9A-Fa-f]{2}|[0-2][0-9]{2}|u[0-9A-Fa-f]{8}|u[0-9A-Fa-f]{4})|.{1})?'" + }, { + include: "methods" + }, { + token: keywordMapper, + regex: "[a-zA-Z][a-zA-Z0-9_]*\\b" + }, { + token: ["keyword.operator", "text", "storage.type"], + regex: "([:])(\\s+)(" + identifier + ")(?=$|\\)|\\[|,|\\s+=|;|\\s+\\{)" + }, { + token: "paren.lpar", + regex: /\[\.|{\||\(\.|\[:|[[({`]/ + }, { + token: "paren.rpar", + regex: /\.\)|\|}|\.]|[\])}]/ + }, { + token: "keyword.operator", + regex: /[=+\-*\/<>@$~&%|!?^.:\\]/ + }, { + token: "punctuation", + regex: /[,;]/ + }, { + include: "math" + }], + blockComment: [{ + regex: /#\[]/, + token: "comment" + }, { + regex: /#\[(?!])/, + token: "comment.start", + push: "blockComment" + }, { + regex: /]#/, + token: "comment.end", + next: "pop" + }, { + defaultToken: "comment" + }], + docBlockComment: [{ + regex: /##\[]/, + token: "comment.doc" + }, { + regex: /##\[(?!])/, + token: "comment.doc.start", + push: "docBlockComment" + }, { + regex: /]##/, + token: "comment.doc.end", + next: "pop" + }, { + defaultToken: "comment.doc" + }], + math: [{ + token: "constant.float", + regex: floatNumberExt + }, { + token: "constant.float", + regex: floatNumber + }, { + token: "constant.integer", + regex: intNumber + }], + methods: [{ + token: "support.function", + regex: "(\\w+)(?=\\()" + }], + strings: [{ + token: "string", + regex: '(\\b' + identifier + ')?"""', + push: [{ + token: "string", + regex: '"""', + next: "pop" + }, { + defaultToken: "string" + }] + }, { + token: "string", + regex: "\\b" + identifier + '"(?=.)', + push: [{ + token: "string", + regex: '"|$', + next: "pop" + }, { + defaultToken: "string" + }] + }, { + token: "string", + regex: '"', + push: [{ + token: "string", + regex: '"|$', + next: "pop" + }, { + token: "constant.language.escape", + regex: stringEscape + }, { + defaultToken: "string" + }] + }] + }; + this.normalizeRules(); +}; + + +oop.inherits(NimHighlightRules, TextHighlightRules); + +exports.NimHighlightRules = NimHighlightRules; +}); From 9f6a7021e5d998dbde8d99931009f81e6ac90467 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 5 Mar 2019 02:13:00 +0400 Subject: [PATCH 0138/1293] add nginx_highlight_rules.js to git --- lib/ace/mode/_test/tokens_apex.json | 551 ++++++++++++++++++ lib/ace/mode/_test/tokens_asl.json | 508 +++++++++++++++++ lib/ace/mode/_test/tokens_bro.json | 106 ++++ lib/ace/mode/_test/tokens_edifact.json | 252 +++++++++ lib/ace/mode/_test/tokens_fsl.json | 341 +++++++++++ lib/ace/mode/_test/tokens_logtalk.json | 222 ++++++++ lib/ace/mode/_test/tokens_nginx.json | 386 +++++++++++++ lib/ace/mode/_test/tokens_nim.json | 105 ++++ lib/ace/mode/_test/tokens_perl6.json | 315 +++++++++++ lib/ace/mode/_test/tokens_puppet.json | 443 +++++++++++++++ lib/ace/mode/_test/tokens_terraform.json | 629 +++++++++++++++++++++ lib/ace/mode/_test/tokens_visualforce.json | 306 ++++++++++ lib/ace/mode/nginx_highlight_rules.js | 154 +++++ 13 files changed, 4318 insertions(+) create mode 100644 lib/ace/mode/_test/tokens_apex.json create mode 100644 lib/ace/mode/_test/tokens_asl.json create mode 100644 lib/ace/mode/_test/tokens_bro.json create mode 100644 lib/ace/mode/_test/tokens_edifact.json create mode 100644 lib/ace/mode/_test/tokens_fsl.json create mode 100644 lib/ace/mode/_test/tokens_logtalk.json create mode 100644 lib/ace/mode/_test/tokens_nginx.json create mode 100644 lib/ace/mode/_test/tokens_nim.json create mode 100644 lib/ace/mode/_test/tokens_perl6.json create mode 100644 lib/ace/mode/_test/tokens_puppet.json create mode 100644 lib/ace/mode/_test/tokens_terraform.json create mode 100644 lib/ace/mode/_test/tokens_visualforce.json create mode 100644 lib/ace/mode/nginx_highlight_rules.js diff --git a/lib/ace/mode/_test/tokens_apex.json b/lib/ace/mode/_test/tokens_apex.json new file mode 100644 index 00000000000..e2874965ec6 --- /dev/null +++ b/lib/ace/mode/_test/tokens_apex.json @@ -0,0 +1,551 @@ +[[ + "start", + ["keyword","public"], + ["text"," "], + ["keyword","class"], + ["text"," "], + ["identifier","testBlockDuplicatesLeadTrigger"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t"] +],[ + "start", + ["text","\t"], + ["keyword","static"], + ["text"," "], + ["keyword","testMethod"], + ["text"," "], + ["storage.type","void"], + ["text"," "], + ["identifier","testDuplicateTrigger"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["paren.lparen","{"], + ["text"," "] +],[ + "start", + ["text","\t"] +],[ + "start", + ["text","\t\t"], + ["identifier","Lead"], + ["paren.lparen","["], + ["paren.rparen","]"], + ["text"," "], + ["identifier","l1"], + ["text"," "], + ["keyword.operator","="], + ["keyword","new"], + ["text"," "], + ["identifier","Lead"], + ["paren.lparen","["], + ["paren.rparen","]"], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t\t"], + ["keyword","new"], + ["text"," "], + ["identifier","Lead"], + ["paren.lparen","("], + ["text"," "], + ["identifier","Email"], + ["keyword.operator","="], + ["string.start","'"], + ["string","homer@fox.tv"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","LastName"], + ["keyword.operator","="], + ["string.start","'"], + ["string","Simpson"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","Company"], + ["keyword.operator","="], + ["string.start","'"], + ["string","fox"], + ["string.end","'"], + ["text"," "], + ["paren.rparen",")"] +],[ + "start", + ["text","\t\t"], + ["paren.rparen","}"], + ["punctuation.operator",";"] +],[ + "start", + ["text","\t\t"], + ["keyword","insert"], + ["text"," "], + ["identifier","l1"], + ["punctuation.operator",";"], + ["text","\t\t"], + ["comment","// add a known lead"] +],[ + "start", + ["text","\t\t"] +],[ + "start", + ["text","\t\t"], + ["identifier","Lead"], + ["paren.lparen","["], + ["paren.rparen","]"], + ["text"," "], + ["identifier","l2"], + ["text"," "], + ["keyword.operator","="], + ["keyword","new"], + ["text"," "], + ["identifier","Lead"], + ["paren.lparen","["], + ["paren.rparen","]"], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t\t"], + ["keyword","new"], + ["text"," "], + ["identifier","Lead"], + ["paren.lparen","("], + ["text"," "], + ["identifier","Email"], + ["keyword.operator","="], + ["string.start","'"], + ["string","homer@fox.tv"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","LastName"], + ["keyword.operator","="], + ["string.start","'"], + ["string","Simpson"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","Company"], + ["keyword.operator","="], + ["string.start","'"], + ["string","fox"], + ["string.end","'"], + ["text"," "], + ["paren.rparen",")"] +],[ + "start", + ["text","\t\t"], + ["paren.rparen","}"], + ["punctuation.operator",";"] +],[ + "start", + ["text","\t\t"], + ["comment","// try to add a matching lead"] +],[ + "start", + ["text","\t\t"], + ["keyword","try"], + ["text"," "], + ["paren.lparen","{"], + ["text","\t"], + ["keyword","insert"], + ["text"," "], + ["identifier","l2"], + ["punctuation.operator",";"], + ["text","\t"], + ["paren.rparen","}"], + ["text"," "], + ["keyword","catch"], + ["text"," "], + ["paren.lparen","("], + ["text"," "], + ["support.function","System"], + ["punctuation.operator","."], + ["identifier","DmlException"], + ["text"," "], + ["identifier","e"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "] +],[ + "start", + ["text","\t\t\t"], + ["support.function","system"], + ["punctuation.operator","."], + ["identifier","assert"], + ["paren.lparen","("], + ["identifier","e"], + ["punctuation.operator","."], + ["identifier","getMessage"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["punctuation.operator","."], + ["identifier","contains"], + ["paren.lparen","("], + ["string.start","'"], + ["string","first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, A lead with this email address already exists"], + ["string.end","'"], + ["paren.rparen",")"], + ["punctuation.operator",","] +],[ + "start", + ["text","\t\t\t "], + ["identifier","e"], + ["punctuation.operator","."], + ["identifier","getMessage"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text","\t\t"], + ["paren.rparen","}"] +],[ + "start", + ["text","\t\t"] +],[ + "start", + ["text","\t\t"], + ["comment","// test duplicates in the same batch"] +],[ + "start", + ["text","\t\t"], + ["identifier","Lead"], + ["paren.lparen","["], + ["paren.rparen","]"], + ["text"," "], + ["identifier","l3"], + ["text"," "], + ["keyword.operator","="], + ["keyword","new"], + ["text"," "], + ["identifier","Lead"], + ["paren.lparen","["], + ["paren.rparen","]"], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t\t"], + ["keyword","new"], + ["text"," "], + ["identifier","Lead"], + ["paren.lparen","("], + ["text"," "], + ["identifier","Email"], + ["keyword.operator","="], + ["string.start","'"], + ["string","marge@fox.tv"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","LastName"], + ["keyword.operator","="], + ["string.start","'"], + ["string","Simpson"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","Company"], + ["keyword.operator","="], + ["string.start","'"], + ["string","fox"], + ["string.end","'"], + ["text"," "], + ["paren.rparen",")"], + ["punctuation.operator",","] +],[ + "start", + ["text","\t\t\t"], + ["keyword","new"], + ["text"," "], + ["identifier","Lead"], + ["paren.lparen","("], + ["text"," "], + ["identifier","Email"], + ["keyword.operator","="], + ["string.start","'"], + ["string","marge@fox.tv"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","LastName"], + ["keyword.operator","="], + ["string.start","'"], + ["string","Simpson"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","Company"], + ["keyword.operator","="], + ["string.start","'"], + ["string","fox"], + ["string.end","'"], + ["text"," "], + ["paren.rparen",")"] +],[ + "start", + ["text","\t\t"], + ["paren.rparen","}"], + ["punctuation.operator",";"], + ["text","\t\t"] +],[ + "start", + ["text","\t\t"], + ["keyword","try"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["keyword","insert"], + ["text"," "], + ["identifier","l3"], + ["punctuation.operator",";"], + ["text","\t"], + ["paren.rparen","}"], + ["text"," "], + ["keyword","catch"], + ["text"," "], + ["paren.lparen","("], + ["text"," "], + ["support.function","System"], + ["punctuation.operator","."], + ["identifier","DmlException"], + ["text"," "], + ["identifier","e"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "] +],[ + "start", + ["text","\t\t\t"], + ["support.function","system"], + ["punctuation.operator","."], + ["identifier","assert"], + ["paren.lparen","("], + ["identifier","e"], + ["punctuation.operator","."], + ["identifier","getMessage"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["punctuation.operator","."], + ["identifier","contains"], + ["paren.lparen","("], + ["string.start","'"], + ["string","first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Another new lead has the same email"], + ["string.end","'"], + ["paren.rparen",")"], + ["punctuation.operator",","] +],[ + "start", + ["text","\t\t\t\t"], + ["identifier","e"], + ["punctuation.operator","."], + ["identifier","getMessage"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text","\t\t\t"] +],[ + "start", + ["text","\t\t"], + ["paren.rparen","}"] +],[ + "start", + ["text","\t\t"] +],[ + "start", + ["text","\t\t"], + ["comment","// test update also"] +],[ + "start", + ["text","\t\t"], + ["identifier","Lead"], + ["paren.lparen","["], + ["paren.rparen","]"], + ["text"," "], + ["identifier","lup"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["keyword","new"], + ["text"," "], + ["identifier","Lead"], + ["paren.lparen","["], + ["paren.rparen","]"], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t\t"], + ["keyword","new"], + ["text"," "], + ["identifier","Lead"], + ["paren.lparen","("], + ["text"," "], + ["identifier","Email"], + ["keyword.operator","="], + ["string.start","'"], + ["string","marge@fox.tv"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","LastName"], + ["keyword.operator","="], + ["string.start","'"], + ["string","Simpson"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","Company"], + ["keyword.operator","="], + ["string.start","'"], + ["string","fox"], + ["string.end","'"], + ["text"," "], + ["paren.rparen",")"] +],[ + "start", + ["text","\t\t"], + ["paren.rparen","}"], + ["punctuation.operator",";"] +],[ + "start", + ["text","\t\t"], + ["keyword","insert"], + ["text"," "], + ["identifier","lup"], + ["punctuation.operator",";"] +],[ + "start", + ["text","\t\t"], + ["identifier","Lead"], + ["text"," "], + ["identifier","marge"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","["], + ["text"," "], + ["keyword","select"], + ["text"," id"], + ["keyword.operator",","], + ["text","Email "], + ["keyword","from"], + ["text"," lead "], + ["keyword","where"], + ["text"," Email "], + ["keyword.operator","="], + ["text"," "], + ["string.start","'"], + ["string","marge@fox.tv"], + ["string.end","'"], + ["text"," "], + ["keyword","limit"], + ["text"," 1"], + ["paren.rparen","]"], + ["punctuation.operator",";"] +],[ + "start", + ["text","\t\t"], + ["support.function","system"], + ["punctuation.operator","."], + ["identifier","assert"], + ["paren.lparen","("], + ["identifier","marge"], + ["keyword.operator","!="], + ["constant.language","null"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text","\t\t"], + ["identifier","marge"], + ["punctuation.operator","."], + ["identifier","Email"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.start","'"], + ["string","homer@fox.tv"], + ["string.end","'"], + ["punctuation.operator",";"], + ["text"," "] +],[ + "start", + ["text","\t\t"] +],[ + "start", + ["text","\t\t"], + ["keyword","try"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["keyword","update"], + ["text"," "], + ["identifier","marge"], + ["punctuation.operator",";"], + ["text"," "], + ["paren.rparen","}"], + ["text"," "], + ["keyword","catch"], + ["text"," "], + ["paren.lparen","("], + ["text"," "], + ["support.function","System"], + ["punctuation.operator","."], + ["identifier","DmlException"], + ["text"," "], + ["identifier","e"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "] +],[ + "start", + ["text","\t\t\t"], + ["support.function","system"], + ["punctuation.operator","."], + ["identifier","assert"], + ["paren.lparen","("], + ["identifier","e"], + ["punctuation.operator","."], + ["identifier","getMessage"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["punctuation.operator","."], + ["identifier","contains"], + ["paren.lparen","("], + ["string.start","'"], + ["string","irst error: FIELD_CUSTOM_VALIDATION_EXCEPTION, A lead with this email address already exists"], + ["string.end","'"], + ["paren.rparen",")"], + ["punctuation.operator",","] +],[ + "start", + ["text","\t\t\t\t"], + ["identifier","e"], + ["punctuation.operator","."], + ["identifier","getMessage"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["paren.rparen",")"], + ["punctuation.operator",";"], + ["text","\t"] +],[ + "start", + ["text","\t\t"], + ["paren.rparen","}"] +],[ + "start", + ["text","\t"], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_asl.json b/lib/ace/mode/_test/tokens_asl.json new file mode 100644 index 00000000000..9218492ae5f --- /dev/null +++ b/lib/ace/mode/_test/tokens_asl.json @@ -0,0 +1,508 @@ +[[ + "comment", + ["comment","/*"] +],[ + "comment", + ["comment"," * Intel ACPI Component Architecture"] +],[ + "comment", + ["comment"," * AML/ASL+ Disassembler version 20180105"] +],[ + "comment", + ["comment"," *"] +],[ + "comment", + ["comment"," * ASL example"] +],[ + "start", + ["comment"," */"] +],[ + "start", + ["keyword","DefinitionBlock"], + ["text"," "], + ["lparen","("], + ["string","\"\""], + ["text",", "], + ["string","\"SSDT\""], + ["text",", "], + ["constant.numeric","1"], + ["text",", "], + ["string","\"PmRef\""], + ["text",", "], + ["string","\"Cpu0Ist\""], + ["text",", "], + ["constant.numeric","0x00003000"], + ["rparen",")"] +],[ + "start", + ["lparen","{"] +],[ + "start", + ["text"," "], + ["function.buildin","External"], + ["text"," "], + ["lparen","("], + ["identifier","_PR_"], + ["text","."], + ["identifier","CPU0"], + ["text",", "], + ["storage.type","DeviceObj"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["function.buildin","External"], + ["text"," "], + ["lparen","("], + ["identifier","_SB_"], + ["text","."], + ["identifier","CPUP"], + ["text",", "], + ["storage.type","UnknownObj"], + ["rparen",")"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","Scope"], + ["text"," "], + ["lparen","("], + ["text","\\"], + ["identifier","_PR"], + ["text","."], + ["identifier","CPU0"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","Method"], + ["text"," "], + ["lparen","("], + ["identifier","_PCT"], + ["text",", "], + ["constant.numeric","0"], + ["text",", "], + ["constant.character","NotSerialized"], + ["rparen",")"], + ["text"," "], + ["comment","// _PCT: Performance Control"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","If"], + ["text"," "], + ["lparen","((("], + ["identifier","CFGD"], + ["text"," "], + ["keyword.operator","&"], + ["text"," "], + ["constant.numeric","One"], + ["rparen",")"], + ["text"," "], + ["keyword.operator","&&"], + ["text"," "], + ["lparen","("], + ["identifier","PDC0"], + ["text"," "], + ["keyword.operator","&"], + ["text"," "], + ["constant.numeric","One"], + ["rparen",")))"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","Return"], + ["text"," "], + ["lparen","("], + ["function.buildin","Package"], + ["text"," "], + ["lparen","("], + ["constant.numeric","0x02"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["function.buildin","ResourceTemplate"], + ["text"," "], + ["lparen","("], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["function.buildin","Register"], + ["text"," "], + ["lparen","("], + ["constant.character","FFixedHW"], + ["text",", "] +],[ + "start", + ["text"," "], + ["constant.numeric","0x00"], + ["text",", "], + ["comment","// Bit Width"] +],[ + "start", + ["text"," "], + ["constant.numeric","0x00"], + ["text",", "], + ["comment","// Bit Offset"] +],[ + "start", + ["text"," "], + ["constant.numeric","0x0000000000000000"], + ["text",", "], + ["comment","// Address"] +],[ + "start", + ["text"," ,"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["rparen","}"], + ["text",", "] +],[ + "start" +],[ + "start", + ["text"," "], + ["function.buildin","ResourceTemplate"], + ["text"," "], + ["lparen","("], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["function.buildin","Register"], + ["text"," "], + ["lparen","("], + ["constant.character","FFixedHW"], + ["text",", "] +],[ + "start", + ["text"," "], + ["constant.numeric","0x00"], + ["text",", "], + ["comment","// Bit Width"] +],[ + "start", + ["text"," "], + ["constant.numeric","0x00"], + ["text",", "], + ["comment","// Bit Offset"] +],[ + "start", + ["text"," "], + ["constant.numeric","0x0000000000000000"], + ["text",", "], + ["comment","// Address"] +],[ + "start", + ["text"," ,"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start", + ["text"," "], + ["rparen","})"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","Return"], + ["text"," "], + ["lparen","("], + ["function.buildin","Package"], + ["text"," "], + ["lparen","("], + ["constant.numeric","0x02"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["function.buildin","ResourceTemplate"], + ["text"," "], + ["lparen","("], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["function.buildin","Register"], + ["text"," "], + ["lparen","("], + ["constant.character","SystemIO"], + ["text",", "] +],[ + "start", + ["text"," "], + ["constant.numeric","0x10"], + ["text",", "], + ["comment","// Bit Width"] +],[ + "start", + ["text"," "], + ["constant.numeric","0x00"], + ["text",", "], + ["comment","// Bit Offset"] +],[ + "start", + ["text"," "], + ["constant.numeric","0x0000000000001000"], + ["text",", "], + ["comment","// Address"] +],[ + "start", + ["text"," ,"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["rparen","}"], + ["text",", "] +],[ + "start" +],[ + "start", + ["text"," "], + ["function.buildin","ResourceTemplate"], + ["text"," "], + ["lparen","("], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["function.buildin","Register"], + ["text"," "], + ["lparen","("], + ["constant.character","SystemIO"], + ["text",", "] +],[ + "start", + ["text"," "], + ["constant.numeric","0x08"], + ["text",", "], + ["comment","// Bit Width"] +],[ + "start", + ["text"," "], + ["constant.numeric","0x00"], + ["text",", "], + ["comment","// Bit Offset"] +],[ + "start", + ["text"," "], + ["constant.numeric","0x00000000000000B3"], + ["text",", "], + ["comment","// Address"] +],[ + "start", + ["text"," ,"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start", + ["text"," "], + ["rparen","})"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["function.buildin","Name"], + ["text"," "], + ["lparen","("], + ["identifier","PSDF"], + ["text",", "], + ["constant.numeric","Zero"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","Method"], + ["text"," "], + ["lparen","("], + ["identifier","_PSD"], + ["text",", "], + ["constant.numeric","0"], + ["text",", "], + ["constant.character","NotSerialized"], + ["rparen",")"], + ["text"," "], + ["comment","// _PSD: Power State Dependencies"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","If"], + ["text"," "], + ["lparen","("], + ["keyword.operator","!"], + ["identifier","PSDF"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword.operator","DerefOf"], + ["text"," "], + ["lparen","("], + ["identifier","HPSD"], + ["text"," "], + ["comment","[Zero]"], + ["rparen",")"], + ["text"," "], + ["comment","[0x04]"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","TCNT"], + ["text"," "], + ["comment","/* External reference */"] +],[ + "start", + ["text"," "], + ["keyword.operator","DerefOf"], + ["text"," "], + ["lparen","("], + ["identifier","SPSD"], + ["text"," "], + ["comment","[Zero]"], + ["rparen",")"], + ["text"," "], + ["comment","[0x04]"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","TCNT"], + ["text"," "], + ["comment","/* External reference */"] +],[ + "start", + ["text"," "], + ["identifier","PSDF"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","Ones"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","If"], + ["text"," "], + ["lparen","(("], + ["identifier","PDC0"], + ["text"," "], + ["keyword.operator","&"], + ["text"," "], + ["constant.numeric","0x0800"], + ["rparen","))"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","Return"], + ["text"," "], + ["lparen","("], + ["identifier","HPSD"], + ["rparen",")"], + ["text"," "], + ["comment","/* \\_PR_.CPU0.HPSD */"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","Return"], + ["text"," "], + ["lparen","("], + ["identifier","SPSD"], + ["rparen",")"], + ["text"," "], + ["comment","/* \\_PR_.CPU0.SPSD */"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start", + ["rparen","}"] +],[ + "start" +],[ + "start" +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_bro.json b/lib/ace/mode/_test/tokens_bro.json new file mode 100644 index 00000000000..b0f42015ae4 --- /dev/null +++ b/lib/ace/mode/_test/tokens_bro.json @@ -0,0 +1,106 @@ +[[ + "start", + ["punctuation.definition.comment.bro","#"], + ["comment.line.number-sign.bro","#! Add countries for the originator and responder of a connection"] +],[ + "start", + ["punctuation.definition.comment.bro","#"], + ["comment.line.number-sign.bro","#! to the connection logs."] +],[ + "start" +],[ + "start", + ["text","module Conn;"] +],[ + "start" +],[ + "start", + ["text","export {"] +],[ + "start", + ["text","\t"], + ["storage.modifier.bro","redef"], + ["text"," "], + ["storage.type.bro","record"], + ["text"," Conn::Info += {"] +],[ + "start", + ["text","\t\t"], + ["punctuation.definition.comment.bro","#"], + ["comment.line.number-sign.bro","# Country code for the originator of the connection based "] +],[ + "start", + ["text","\t\t"], + ["punctuation.definition.comment.bro","#"], + ["comment.line.number-sign.bro","# on a GeoIP lookup."] +],[ + "start", + ["text","\t\torig_cc: "], + ["storage.type.bro","string"], + ["text"," &optional &log;"] +],[ + "start", + ["text","\t\t"], + ["punctuation.definition.comment.bro","#"], + ["comment.line.number-sign.bro","# Country code for the responser of the connection based "] +],[ + "start", + ["text","\t\t"], + ["punctuation.definition.comment.bro","#"], + ["comment.line.number-sign.bro","# on a GeoIP lookup."] +],[ + "start", + ["text","\t\tresp_cc: "], + ["storage.type.bro","string"], + ["text"," &optional &log;"] +],[ + "start", + ["text","\t};"] +],[ + "start", + ["text","}"] +],[ + "start" +],[ + "start", + ["meta.function.bro"," "], + ["storage.type.bro","connection_state_remove"], + ["meta.function.bro","("], + ["entity.name.function.bro","c: connection"], + ["meta.function.bro",") "], + "event connection_state_remove(c: connection) " +],[ + "start", + ["text","\t{"] +],[ + "start", + ["text","\t"], + ["storage.modifier.bro","local"], + ["text"," orig_loc = lookup_location(c$id$orig_h);"] +],[ + "start", + ["text","\t"], + ["keyword.control.bro","if"], + ["text"," ( orig_loc?$country_code )"] +],[ + "start", + ["text","\t\tc$conn$orig_cc = orig_loc$country_code;"] +],[ + "start" +],[ + "start", + ["text","\t"], + ["storage.modifier.bro","local"], + ["text"," resp_loc = lookup_location(c$id$resp_h);"] +],[ + "start", + ["text","\t"], + ["keyword.control.bro","if"], + ["text"," ( resp_loc?$country_code )"] +],[ + "start", + ["text","\t\tc$conn$resp_cc = resp_loc$country_code;"] +],[ + "start", + ["text","\t}"] +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_edifact.json b/lib/ace/mode/_test/tokens_edifact.json new file mode 100644 index 00000000000..cb5f4c1d7ce --- /dev/null +++ b/lib/ace/mode/_test/tokens_edifact.json @@ -0,0 +1,252 @@ +[[ + "start", + ["entity.name.segment","UNB"], + ["keyword.operator","+"], + ["keyword","UNOA"], + ["punctuation.operator",":"], + ["text","1"], + ["keyword.operator","+"], + ["text","005435656"], + ["punctuation.operator",":"], + ["text","1"], + ["keyword.operator","+"], + ["text","006415160"], + ["punctuation.operator",":"], + ["text","1"], + ["keyword.operator","+"], + ["text","060515"], + ["punctuation.operator",":"], + ["text","1434"], + ["keyword.operator","+"], + ["text","00000000000778"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.header","UNH"], + ["keyword.operator","+"], + ["text","00000000000117"], + ["keyword.operator","+"], + ["identifier","INVnrOIC"], + ["punctuation.operator",":"], + ["identifier","D"], + ["punctuation.operator",":"], + ["text","97"], + ["identifier","B"], + ["punctuation.operator",":"], + ["identifier","UN"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","BGM"], + ["keyword.operator","+"], + ["text","380"], + ["keyword.operator","+"], + ["text","342459"], + ["keyword.operator","+"], + ["text","9"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","DTM"], + ["keyword.operator","+"], + ["text","3"], + ["punctuation.operator",":"], + ["text","20060515"], + ["punctuation.operator",":"], + ["text","102"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","RFF"], + ["keyword.operator","+"], + ["keyword","ON"], + ["punctuation.operator",":"], + ["text","521052"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","NAD"], + ["keyword.operator","+"], + ["keyword","BY"], + ["keyword.operator","+"], + ["text","792820524"], + ["punctuation.operator","::"], + ["text","16"], + ["keyword.operator","++"], + ["identifier","CUMMINS"], + ["text"," "], + ["identifier","MID"], + ["text","-"], + ["identifier","RANGE"], + ["text"," "], + ["identifier","ENGINE"], + ["text"," "], + ["identifier","PLANT"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","NAD"], + ["keyword.operator","+"], + ["keyword","SE"], + ["keyword.operator","+"], + ["text","005435656"], + ["punctuation.operator","::"], + ["text","16"], + ["keyword.operator","++"], + ["identifier","GENERAL"], + ["text"," "], + ["identifier","WIDGET"], + ["text"," "], + ["identifier","COMPANY"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","CUX"], + ["keyword.operator","+"], + ["text","1"], + ["punctuation.operator",":"], + ["identifier","USD"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","LIN"], + ["punctuation.operator","+1+"], + ["keyword.operator","+"], + ["text","157870"], + ["punctuation.operator",":"], + ["identifier","IN"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","IMD"], + ["punctuation.operator","+F+"], + ["keyword.operator","+"], + ["punctuation.operator",":::"], + ["identifier","WIDGET"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","QTY"], + ["keyword.operator","+"], + ["text","47"], + ["punctuation.operator",":"], + ["text","1020"], + ["punctuation.operator",":"], + ["identifier","EA"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","ALI"], + ["keyword.operator","+"], + ["identifier","US"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","MOA"], + ["keyword.operator","+"], + ["text","203"], + ["punctuation.operator",":"], + ["text","1202.58"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","PRI"], + ["keyword.operator","+"], + ["entity.name.segment","INV"], + ["punctuation.operator",":"], + ["text","1.179"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","LIN"], + ["punctuation.operator","+2+"], + ["keyword.operator","+"], + ["text","157871"], + ["punctuation.operator",":"], + ["identifier","IN"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","IMD"], + ["punctuation.operator","+F+"], + ["keyword.operator","+"], + ["punctuation.operator",":::"], + ["identifier","DIFFERENT"], + ["text"," "], + ["identifier","WIDGET"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","QTY"], + ["keyword.operator","+"], + ["text","47"], + ["punctuation.operator",":"], + ["text","20"], + ["punctuation.operator",":"], + ["identifier","EA"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","ALI"], + ["keyword.operator","+"], + ["keyword","JP"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","MOA"], + ["keyword.operator","+"], + ["text","203"], + ["punctuation.operator",":"], + ["text","410"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","PRI"], + ["keyword.operator","+"], + ["entity.name.segment","INV"], + ["punctuation.operator",":"], + ["text","20.5"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","UNS"], + ["keyword.operator","+"], + ["identifier","S"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","MOA"], + ["keyword.operator","+"], + ["text","39"], + ["punctuation.operator",":"], + ["text","2137.58"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","ALC"], + ["punctuation.operator","+C+"], + ["identifier","ABG"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","MOA"], + ["keyword.operator","+"], + ["text","8"], + ["punctuation.operator",":"], + ["text","525"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","UNT"], + ["keyword.operator","+"], + ["text","23"], + ["keyword.operator","+"], + ["text","00000000000117"], + ["punctuation.operator","'"] +],[ + "start", + ["entity.name.segment","UNZ"], + ["punctuation.operator","+1+"], + ["text","00000000000778"], + ["punctuation.operator","'"] +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_fsl.json b/lib/ace/mode/_test/tokens_fsl.json new file mode 100644 index 00000000000..e1cff132924 --- /dev/null +++ b/lib/ace/mode/_test/tokens_fsl.json @@ -0,0 +1,341 @@ +[[ + "start", + ["constant.language.fslLanguage","machine_name :"], + ["text"," "], + ["string.quoted.double.fslLabel.doublequoted","\"BGP\""], + ["text",";"] +],[ + "start", + ["constant.language.fslLanguage","machine_version :"], + ["text"," "], + ["constant.numeric","1.0.0"], + ["text",";"] +],[ + "start" +],[ + "start", + ["constant.language.fslLanguage","machine_author :"], + ["text"," "], + ["string.quoted.double.fslLabel.doublequoted","\"John Haugeland \""], + ["text",";"] +],[ + "start", + ["constant.language.fslLanguage","machine_license :"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","MIT"], + ["text",";"] +],[ + "start" +],[ + "start", + ["constant.language.fslLanguage","graph_layout :"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","dot"], + ["text",";"] +],[ + "start" +],[ + "start" +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","Idle"], + ["text"," "], + ["constant.character.fslAction","'Invite'"], + ["text"," "], + ["keyword.control.transition.fslArrow","=>"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Invited"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","Invited"], + ["text"," "], + ["constant.character.fslAction","'Invite, 1xx'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Invited"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","Invited"], + ["text"," "], + ["constant.character.fslAction","'3xx'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Redirecting"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","Invited"], + ["text"," "], + ["constant.character.fslAction","'Cancel'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Cancelling"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","Invited"], + ["text"," "], + ["constant.character.fslAction","'200'"], + ["text"," "], + ["keyword.control.transition.fslArrow","=>"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Accepted"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","Invited"], + ["text"," "], + ["constant.character.fslAction","'407'"], + ["text"," "], + ["keyword.control.transition.fslArrow","=>"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","AuthRequested"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","Invited"], + ["text"," "], + ["constant.character.fslAction","'4xx-6xx'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Failed"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","AuthRequested"], + ["text"," "], + ["constant.character.fslAction","'Ack'"], + ["text"," "], + ["keyword.control.transition.fslArrow","=>"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Invited"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","Redirecting"], + ["text"," "], + ["constant.character.fslAction","'Act'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Redirected"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","Cancelling"], + ["text"," "], + ["constant.character.fslAction","'200 (Invite)'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","LateCancel"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","Cancelling"], + ["text"," "], + ["constant.character.fslAction","'200 (Cancel)'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Cancelled"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","Accepted"], + ["text"," "], + ["constant.character.fslAction","'Cancel'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","LateCancel"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","Accepted"], + ["text"," "], + ["constant.character.fslAction","'Ack'"], + ["text"," "], + ["keyword.control.transition.fslArrow","=>"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Established"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","Failed"], + ["text"," "], + ["constant.character.fslAction","'Ack'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Terminated"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","Redirected"], + ["text"," "], + ["constant.character.fslAction","'Invite'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Invited"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","Redirected"], + ["text"," "], + ["constant.character.fslAction","'Timeout'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Terminated"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","LateCancel"], + ["text"," "], + ["constant.character.fslAction","'Ack'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Established"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","Cancelled"], + ["text"," "], + ["constant.character.fslAction","'487'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Failed"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","Established"], + ["text"," "], + ["constant.character.fslAction","'Invite'"], + ["text"," "], + ["keyword.control.transition.fslArrow","=>"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","SessionModifying"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","Established"], + ["text"," "], + ["constant.character.fslAction","'Bye'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Closing"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","SessionModifying"], + ["text"," "], + ["constant.character.fslAction","'488'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","SessionModificationRefused"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","SessionModifying"], + ["text"," "], + ["constant.character.fslAction","'200'"], + ["text"," "], + ["keyword.control.transition.fslArrow","=>"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","SessionModified"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","Closing"], + ["text"," "], + ["constant.character.fslAction","'Bye,Ack,200 (Invite)'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Closing"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","Closing"], + ["text"," "], + ["constant.character.fslAction","'200 (Bye)'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Terminated"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","SessionModificationRefused"], + ["text"," "], + ["constant.character.fslAction","'Ack'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Established"], + ["text",";"] +],[ + "start" +],[ + "start", + ["entity.name.tag.fslLabel.atom","SessionModified"], + ["text"," "], + ["constant.character.fslAction","'Ack'"], + ["text"," "], + ["keyword.control.transition.fslArrow","=>"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Established"], + ["text",";"] +],[ + "start", + ["entity.name.tag.fslLabel.atom","SessionModified"], + ["text"," "], + ["constant.character.fslAction","'Bye'"], + ["text"," "], + ["keyword.control.transition.fslArrow","->"], + ["text"," "], + ["entity.name.tag.fslLabel.atom","Closing"], + ["text",";"] +],[ + "start" +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_logtalk.json b/lib/ace/mode/_test/tokens_logtalk.json new file mode 100644 index 00000000000..e257005affc --- /dev/null +++ b/lib/ace/mode/_test/tokens_logtalk.json @@ -0,0 +1,222 @@ +[[ + "start", + ["storage.type.opening.logtalk",":- object"], + ["text","(bottles)"], + ["keyword.operator.misc.logtalk","."] +],[ + "start" +],[ + "start", + ["text","\t"], + ["storage.modifier.others.logtalk",":- initialization"], + ["text","(sing("], + ["constant.numeric.logtalk","99"], + ["text","))"], + ["keyword.operator.misc.logtalk","."] +],[ + "start" +],[ + "start", + ["text","\tsing("], + ["constant.numeric.logtalk","0"], + ["text",") "], + ["keyword.operator.message-sending.logtalk",":"], + ["keyword.operator.evaluable.logtalk","-"] +],[ + "start", + ["text","\t\t"], + ["support.function.term-io.logtalk","write"], + ["text","("], + ["punctuation.definition.string.begin.logtalk","'"], + ["string.quoted.single.logtalk","No more bottles of beer on the wall, no more bottles of beer."], + ["punctuation.definition.string.end.logtalk","'"], + ["text",")"], + ["keyword.operator.misc.logtalk",","], + ["text"," "], + ["support.function.chars-and-bytes-io.logtalk","nl"], + ["keyword.operator.misc.logtalk",","] +],[ + "start", + ["text","\t\t"], + ["support.function.term-io.logtalk","write"], + ["text","("], + ["punctuation.definition.string.begin.logtalk","'"], + ["string.quoted.single.logtalk","Go to the store and buy some more, 99 bottles of beer on the wall."], + ["punctuation.definition.string.end.logtalk","'"], + ["text",")"], + ["keyword.operator.misc.logtalk",","], + ["text"," "], + ["support.function.chars-and-bytes-io.logtalk","nl"], + ["keyword.operator.misc.logtalk",","], + ["text"," "], + ["support.function.chars-and-bytes-io.logtalk","nl"], + ["keyword.operator.misc.logtalk","."] +],[ + "start", + ["text","\tsing("], + ["variable.other.logtalk","N"], + ["text",") "], + ["keyword.operator.message-sending.logtalk",":"], + ["keyword.operator.evaluable.logtalk","-"] +],[ + "start", + ["text","\t\t"], + ["variable.other.logtalk","N"], + ["text"," "], + ["keyword.operator.comparison.arithmetic.logtalk",">"], + ["text"," "], + ["constant.numeric.logtalk","0"], + ["keyword.operator.misc.logtalk",","] +],[ + "start", + ["text","\t\t"], + ["variable.other.logtalk","N2"], + ["text"," "], + ["keyword.operator.misc.logtalk","is"], + ["text"," "], + ["variable.other.logtalk","N"], + ["text"," "], + ["keyword.operator.evaluable.logtalk","-"], + ["text"," "], + ["constant.numeric.logtalk","1"], + ["keyword.operator.misc.logtalk",","] +],[ + "start", + ["text","\t\tbeers("], + ["variable.other.logtalk","N"], + ["text",")"], + ["keyword.operator.misc.logtalk",","], + ["text"," "], + ["support.function.term-io.logtalk","write"], + ["text","("], + ["punctuation.definition.string.begin.logtalk","'"], + ["string.quoted.single.logtalk"," of beer on the wall, "], + ["punctuation.definition.string.end.logtalk","'"], + ["text",")"], + ["keyword.operator.misc.logtalk",","], + ["text"," beers("], + ["variable.other.logtalk","N"], + ["text",")"], + ["keyword.operator.misc.logtalk",","], + ["text"," "], + ["support.function.term-io.logtalk","write"], + ["text","("], + ["punctuation.definition.string.begin.logtalk","'"], + ["string.quoted.single.logtalk"," of beer."], + ["punctuation.definition.string.end.logtalk","'"], + ["text",")"], + ["keyword.operator.misc.logtalk",","], + ["text"," "], + ["support.function.chars-and-bytes-io.logtalk","nl"], + ["keyword.operator.misc.logtalk",","] +],[ + "start", + ["text","\t\t"], + ["support.function.term-io.logtalk","write"], + ["text","("], + ["punctuation.definition.string.begin.logtalk","'"], + ["string.quoted.single.logtalk","Take one down and pass it around, "], + ["punctuation.definition.string.end.logtalk","'"], + ["text",")"], + ["keyword.operator.misc.logtalk",","], + ["text"," beers("], + ["variable.other.logtalk","N2"], + ["text",")"], + ["keyword.operator.misc.logtalk",","], + ["text"," "], + ["support.function.term-io.logtalk","write"], + ["text","("], + ["punctuation.definition.string.begin.logtalk","'"], + ["string.quoted.single.logtalk"," of beer on the wall."], + ["punctuation.definition.string.end.logtalk","'"], + ["text",")"], + ["keyword.operator.misc.logtalk",","], + ["text"," "], + ["support.function.chars-and-bytes-io.logtalk","nl"], + ["keyword.operator.misc.logtalk",","], + ["text"," "], + ["support.function.chars-and-bytes-io.logtalk","nl"], + ["keyword.operator.misc.logtalk",","] +],[ + "start", + ["text","\t\tsing("], + ["variable.other.logtalk","N2"], + ["text",")"], + ["keyword.operator.misc.logtalk","."] +],[ + "start" +],[ + "start", + ["text","\tbeers("], + ["constant.numeric.logtalk","0"], + ["text",") "], + ["keyword.operator.message-sending.logtalk",":"], + ["keyword.operator.evaluable.logtalk","-"] +],[ + "start", + ["text","\t\t"], + ["support.function.term-io.logtalk","write"], + ["text","("], + ["punctuation.definition.string.begin.logtalk","'"], + ["string.quoted.single.logtalk","no more bottles"], + ["punctuation.definition.string.end.logtalk","'"], + ["text",")"], + ["keyword.operator.misc.logtalk","."] +],[ + "start", + ["text","\tbeers("], + ["constant.numeric.logtalk","1"], + ["text",") "], + ["keyword.operator.message-sending.logtalk",":"], + ["keyword.operator.evaluable.logtalk","-"] +],[ + "start", + ["text","\t\t"], + ["support.function.term-io.logtalk","write"], + ["text","("], + ["punctuation.definition.string.begin.logtalk","'"], + ["string.quoted.single.logtalk","1 bottle"], + ["punctuation.definition.string.end.logtalk","'"], + ["text",")"], + ["keyword.operator.misc.logtalk","."] +],[ + "start", + ["text","\tbeers("], + ["variable.other.logtalk","N"], + ["text",") "], + ["keyword.operator.message-sending.logtalk",":"], + ["keyword.operator.evaluable.logtalk","-"] +],[ + "start", + ["text","\t\t"], + ["variable.other.logtalk","N"], + ["text"," "], + ["keyword.operator.comparison.arithmetic.logtalk",">"], + ["text"," "], + ["constant.numeric.logtalk","1"], + ["keyword.operator.misc.logtalk",","] +],[ + "start", + ["text","\t\t"], + ["support.function.term-io.logtalk","write"], + ["text","("], + ["variable.other.logtalk","N"], + ["text",")"], + ["keyword.operator.misc.logtalk",","], + ["text"," "], + ["support.function.term-io.logtalk","write"], + ["text","("], + ["punctuation.definition.string.begin.logtalk","'"], + ["string.quoted.single.logtalk"," bottles"], + ["punctuation.definition.string.end.logtalk","'"], + ["text",")"], + ["keyword.operator.misc.logtalk","."] +],[ + "start" +],[ + "start", + ["storage.type.closing.logtalk",":- end_object"], + ["keyword.operator.misc.logtalk","."] +],[ + "start" +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_nginx.json b/lib/ace/mode/_test/tokens_nginx.json new file mode 100644 index 00000000000..0142b2a4b48 --- /dev/null +++ b/lib/ace/mode/_test/tokens_nginx.json @@ -0,0 +1,386 @@ +[[ + "start", + ["keyword","user"], + ["text"," www www"], + ["punctuation",";"], + ["text"," "], + ["comment","## Default: nobody"] +],[ + "start", + ["keyword","worker_processes"], + ["text"," 5"], + ["punctuation",";"], + ["text"," "], + ["comment","## Default: 1"] +],[ + "start", + ["keyword","error_log"], + ["text"," logs/error.log"], + ["punctuation",";"] +],[ + "start", + ["keyword","pid"], + ["text"," logs/nginx.pid"], + ["punctuation",";"] +],[ + "start", + ["keyword","worker_rlimit_nofile"], + ["text"," 8192"], + ["punctuation",";"] +],[ + "start" +],[ + "start", + ["storage.type","events"], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["keyword","worker_connections"], + ["text"," 4096"], + ["punctuation",";"], + ["text"," "], + ["comment","## Default: 1024"] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["storage.type","http"], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["keyword","include"], + ["text"," conf/mime.types"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","include"], + ["text"," /etc/nginx/proxy.conf"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","include"], + ["text"," /etc/nginx/fastcgi.conf"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","index"], + ["text"," index.html index.htm index.php"], + ["punctuation",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","default_type"], + ["text"," application/octet-stream"], + ["punctuation",";"] +],[ + "keyword", + ["text"," "], + ["keyword","log_format"], + ["text"," "], + ["constant.language","main"], + ["text"," "], + ["string","'"], + ["variable","$remote_addr"], + ["string"," - "], + ["variable","$remote_user"], + ["string"," ["], + ["variable","$time_local"], + ["string","] "], + ["variable","$status"], + ["string"," '"] +],[ + "keyword", + ["text"," "], + ["string","'\""], + ["variable","$request"], + ["string","\" "], + ["variable","$body_bytes_sent"], + ["string"," \""], + ["variable","$http_referer"], + ["string","\" '"] +],[ + "start", + ["text"," "], + ["string","'\""], + ["variable","$http_user_agent"], + ["string","\" \""], + ["variable","$http_x_forwarded_for"], + ["string","\"'"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","access_log"], + ["text"," logs/access.log "], + ["constant.language","main"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","sendfile"], + ["text"," "], + ["constant.language","on"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","tcp_nopush"], + ["text"," "], + ["constant.language","on"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","server_names_hash_bucket_size"], + ["text"," 128"], + ["punctuation",";"], + ["text"," "], + ["comment","# this seems to be required for some vhosts"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.type","server"], + ["text"," "], + ["paren.lpar","{"], + ["text"," "], + ["comment","# php/fastcgi"] +],[ + "start", + ["text"," "], + ["keyword","listen"], + ["text"," 80"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","server_name"], + ["text"," domain1.com www.domain1.com"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","access_log"], + ["text"," logs/domain1.access.log "], + ["constant.language","main"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","root"], + ["text"," html"], + ["punctuation",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.type","location"], + ["text"," "], + ["string.regexp","~ \\.php$ "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["keyword","fastcgi_pass"], + ["text"," 127.0.0.1:1025"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.type","server"], + ["text"," "], + ["paren.lpar","{"], + ["text"," "], + ["comment","# simple reverse-proxy"] +],[ + "start", + ["text"," "], + ["keyword","listen"], + ["text"," 80"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","server_name"], + ["text"," domain2.com www.domain2.com"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","access_log"], + ["text"," logs/domain2.access.log "], + ["constant.language","main"], + ["punctuation",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment","# serve static files"] +],[ + "start", + ["text"," "], + ["storage.type","location"], + ["text"," "], + ["string.regexp","~ ^/(images|javascript|js|css|flash|media|static)/ "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["keyword","root"], + ["text"," /var/www/virtual/big.server.com/htdocs"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","expires"], + ["text"," 30d"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment","# pass requests for dynamic content to rails/turbogears/zope, et al"] +],[ + "start", + ["text"," "], + ["storage.type","location"], + ["text"," "], + ["text","/ "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["keyword","proxy_pass"], + ["text"," http://127.0.0.1:8080"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.type","upstream"], + ["text"," "], + ["text","big_server_com "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["keyword","server"], + ["text"," 127.0.0.3:8000 weight=5"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","server"], + ["text"," 127.0.0.3:8001 weight=5"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","server"], + ["text"," 192.168.0.1:8000"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","server"], + ["text"," 192.168.0.1:8001"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.type","server"], + ["text"," "], + ["paren.lpar","{"], + ["text"," "], + ["comment","# simple load balancing"] +],[ + "start", + ["text"," "], + ["keyword","listen"], + ["text"," 80"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","server_name"], + ["text"," big.server.com"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["keyword","access_log"], + ["text"," logs/big.server.access.log "], + ["constant.language","main"], + ["punctuation",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.type","location"], + ["text"," "], + ["text","/ "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["keyword","proxy_pass"], + ["text"," http://big_server_com"], + ["punctuation",";"] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["paren.rpar","}"] +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_nim.json b/lib/ace/mode/_test/tokens_nim.json new file mode 100644 index 00000000000..85d2a99407e --- /dev/null +++ b/lib/ace/mode/_test/tokens_nim.json @@ -0,0 +1,105 @@ +[[ + ["blockComment","blockComment"], + ["comment.start","#["], + ["comment"," "], + ["comment.start","#["], + ["comment"," Multiline comment in already"] +],[ + "blockComment", + ["comment"," commented out code. "], + ["comment.end","]#"] +],[ + "blockComment", + ["comment","proc p[T](x: T) = discard"] +],[ + "start", + ["comment.end","]#"] +],[ + "start", + ["keyword","echo"], + ["text"," "], + ["string","\"This is code\""] +],[ + "start", + ["variable","var"] +],[ + "start", + ["text"," "], + ["identifier","p"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.float","0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64"] +],[ + "start" +],[ + "start", + ["keyword","proc"], + ["text"," "], + ["support.function","getAlphabet"], + ["paren.lpar","("], + ["paren.rpar",")"], + ["keyword.operator",":"], + ["text"," "], + ["storage.type","string"], + ["text"," "], + ["keyword.operator","="] +],[ + "start", + ["text"," "], + ["variable","var"], + ["text"," "], + ["identifier","accm"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"\""] +],[ + "start", + ["text"," "], + ["keyword","for"], + ["text"," "], + ["identifier","letter"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["string","'a'"], + ["keyword.operator",".."], + ["string","'z'"], + ["keyword.operator",":"], + ["text"," "], + ["comment","# see iterators"] +],[ + "start", + ["text"," "], + ["identifier","accm"], + ["keyword.operator","."], + ["support.function","add"], + ["paren.lpar","("], + ["identifier","letter"], + ["paren.rpar",")"] +],[ + "start", + ["text"," "], + ["keyword","return"], + ["text"," "], + ["identifier","accm"] +],[ + "start" +],[ + "start", + ["support.function","assert"], + ["paren.lpar","("], + ["string","\"a\""], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["constant.integer","10"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["string","\"aaaaaaaaaa\""], + ["paren.rpar",")"] +],[ + "start" +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_perl6.json b/lib/ace/mode/_test/tokens_perl6.json new file mode 100644 index 00000000000..a45e3793481 --- /dev/null +++ b/lib/ace/mode/_test/tokens_perl6.json @@ -0,0 +1,315 @@ +[[ + "block_comment", + ["comment.doc","=begin comment"] +],[ + "block_comment", + ["comment.doc","Perl 6 example for ace"] +],[ + "start", + ["comment.doc","=end comment"] +],[ + "start", + ["keyword","class"], + ["text"," "], + ["identifier","Cook"], + ["text"," "], + ["keyword","is"], + ["text"," "], + ["identifier","Employee"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","has"], + ["text"," "], + ["variable.language","@.utensils"], + ["text"," "], + ["keyword","is"], + ["text"," "], + ["support.function","rw"], + ["text",";"] +],[ + "start", + ["text"," "], + ["keyword","has"], + ["text"," "], + ["variable.language","@.cookbooks"], + ["text"," "], + ["keyword","is"], + ["text"," "], + ["support.function","rw"], + ["text",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","method"], + ["text"," "], + ["identifier","cook"], + ["lparen","("], + ["text"," "], + ["variable.language","$food"], + ["text"," "], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["support.function","say"], + ["text"," "], + ["string.quoted.double","\"Cooking "], + ["variable.language","$food"], + ["string.quoted.double","\""], + ["text",";"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","method"], + ["text"," "], + ["identifier","clean_utensils"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["support.function","say"], + ["text"," "], + ["string.quoted.double","\"Cleaning "], + ["variable.language","$_"], + ["string.quoted.double","\""], + ["text"," "], + ["keyword","for"], + ["text"," "], + ["variable.language","@.utensils"], + ["text",";"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start", + ["rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","class"], + ["text"," "], + ["identifier","Baker"], + ["text"," "], + ["keyword","is"], + ["text"," "], + ["identifier","Cook"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","method"], + ["text"," "], + ["identifier","cook"], + ["lparen","("], + ["text"," "], + ["variable.language","$confection"], + ["text"," "], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["support.function","say"], + ["text"," "], + ["string.quoted.double","\"Baking a tasty "], + ["variable.language","$confection"], + ["string.quoted.double","\""], + ["text",";"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start", + ["rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","my"], + ["text"," "], + ["variable.language","$cook"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","Cook"], + ["keyword.operator","."], + ["support.function","new"], + ["lparen","("] +],[ + "start", + ["text"," "], + ["identifier","utensils"], + ["text"," "], + ["keyword.operator","=>"], + ["text"," "], + ["string.quoted.single",""], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["identifier","cookbooks"], + ["text"," "], + ["keyword.operator","=>"], + ["text"," "], + ["string.quoted.single","'The Joy of Cooking'"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["identifier","salary"], + ["text"," "], + ["keyword.operator","=>"], + ["text"," "], + ["constant.numeric","40000"], + ["rparen",")"], + ["text",";"] +],[ + "start" +],[ + "start", + ["variable.language","$cook"], + ["keyword.operator","."], + ["identifier","cook"], + ["lparen","("], + ["text"," "], + ["string.quoted.single","'pizza'"], + ["text"," "], + ["rparen",")"], + ["text","; "], + ["comment","# OUTPUT: «Cooking pizza␤»"] +],[ + "start", + ["support.function","say"], + ["text"," "], + ["variable.language","$cook"], + ["keyword.operator","."], + ["identifier","utensils"], + ["keyword.operator","."], + ["support.function","perl"], + ["text","; "], + ["comment","# OUTPUT: «[\"spoon\", \"ladle\", \"knife\", \"pan\"]␤»"] +],[ + "start", + ["support.function","say"], + ["text"," "], + ["variable.language","$cook"], + ["keyword.operator","."], + ["identifier","cookbooks"], + ["keyword.operator","."], + ["support.function","perl"], + ["text","; "], + ["comment","# OUTPUT: «[\"The Joy of Cooking\"]␤»"] +],[ + "start", + ["support.function","say"], + ["text"," "], + ["variable.language","$cook"], + ["keyword.operator","."], + ["identifier","salary"], + ["text","; "], + ["comment","# OUTPUT: «40000␤»"] +],[ + "start" +],[ + "start", + ["keyword","my"], + ["text"," "], + ["variable.language","$baker"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","Baker"], + ["keyword.operator","."], + ["support.function","new"], + ["lparen","("] +],[ + "start", + ["text"," "], + ["identifier","utensils"], + ["text"," "], + ["keyword.operator","=>"], + ["text"," "], + ["string.quoted.single","'self cleaning oven'"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["identifier","cookbooks"], + ["text"," "], + ["keyword.operator","=>"], + ["text"," "], + ["string.quoted.double","\"The Baker's Apprentice\""], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["identifier","salary"], + ["text"," "], + ["keyword.operator","=>"], + ["text"," "], + ["constant.numeric","50000"], + ["rparen",")"], + ["text",";"] +],[ + "start" +],[ + "start", + ["variable.language","$baker"], + ["keyword.operator","."], + ["identifier","cook"], + ["lparen","("], + ["string.quoted.single","'brioche'"], + ["rparen",")"], + ["text","; "], + ["comment","# OUTPUT: «Baking a tasty brioche␤»"] +],[ + "start", + ["support.function","say"], + ["text"," "], + ["variable.language","$baker"], + ["keyword.operator","."], + ["identifier","utensils"], + ["keyword.operator","."], + ["support.function","perl"], + ["text","; "], + ["comment","# OUTPUT: «[\"self cleaning oven\"]␤»"] +],[ + "start", + ["support.function","say"], + ["text"," "], + ["variable.language","$baker"], + ["keyword.operator","."], + ["identifier","cookbooks"], + ["keyword.operator","."], + ["support.function","perl"], + ["text","; "], + ["comment","# OUTPUT: «[\"The Baker's Apprentice\"]␤»"] +],[ + "start", + ["support.function","say"], + ["text"," "], + ["variable.language","$baker"], + ["keyword.operator","."], + ["identifier","salary"], + ["text","; "], + ["comment","# OUTPUT: «50000␤» "] +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_puppet.json b/lib/ace/mode/_test/tokens_puppet.json new file mode 100644 index 00000000000..fda5217325d --- /dev/null +++ b/lib/ace/mode/_test/tokens_puppet.json @@ -0,0 +1,443 @@ +[[ + "start", + ["storage.function.puppet","define"], + ["name.function.puppet"," apache::vhost "], + ["punctuation.lpar","("], + ["variable.puppet","$port"], + ["keyword.operator",","], + ["string"," "], + ["variable.puppet","$docroot"], + ["keyword.operator",","], + ["string"," "], + ["variable.puppet","$servername"], + ["string"," "], + ["keyword.operator","="], + ["string"," "], + ["variable.puppet","$title"], + ["keyword.operator",","], + ["string"," "], + ["variable.puppet","$vhost_name"], + ["string"," "], + ["keyword.operator","="], + ["string"," "], + ["punctuation.quote.puppet","'"], + ["string","*"], + ["punctuation.quote.puppet","'"], + ["punctuation.rpar.puppet",")"], + ["keyword.name.resource.puppet"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["keyword.control.puppet","include"], + ["text"," apache"] +],[ + "start", + ["text"," "], + ["keyword.control.puppet","include"], + ["text"," apache"], + ["keyword.operator","::"], + ["text","params"] +],[ + "start", + ["text"," "], + ["variable.puppet","$vhost_dir"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["qualified.variable.puppet","$apache::params::vhost_dir"] +],[ + "start", + ["keyword.name.resource.puppet"," file"], + ["paren.lpar"," {"], + ["text"," "], + ["punctuation.quote.puppet","\""], + ["variable.puppet","${vhost_dir"], + ["string","}/"], + ["variable.puppet","${servername"], + ["string","}.conf"], + ["punctuation.quote.puppet","\""], + ["text",":"] +],[ + "start", + ["text"," "], + ["language.support.class","content"], + ["keyword.operator"," =>"], + ["text"," "], + ["support.function.puppet","template"], + ["paren.lpar","("], + ["punctuation.quote.puppet","'"], + ["string","apache/vhost-default.conf.erb"], + ["punctuation.quote.puppet","'"], + ["paren.rpar",")"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["language.support.class","owner"], + ["keyword.operator"," =>"], + ["text"," "], + ["punctuation.quote.puppet","'"], + ["string","www"], + ["punctuation.quote.puppet","'"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["language.support.class","group"], + ["keyword.operator"," =>"], + ["text"," "], + ["punctuation.quote.puppet","'"], + ["string","www"], + ["punctuation.quote.puppet","'"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["language.support.class","mode"], + ["keyword.operator"," =>"], + ["text"," "], + ["punctuation.quote.puppet","'"], + ["string","644"], + ["punctuation.quote.puppet","'"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["language.support.class","require"], + ["keyword.operator"," =>"], + ["text"," "], + ["constant.types.puppet","Package"], + ["paren.lpar","["], + ["punctuation.quote.puppet","'"], + ["string","httpd"], + ["punctuation.quote.puppet","'"], + ["paren.rpar","]"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["language.support.class","notify"], + ["keyword.operator"," =>"], + ["text"," "], + ["constant.types.puppet","Service"], + ["paren.lpar","["], + ["punctuation.quote.puppet","'"], + ["string","httpd"], + ["punctuation.quote.puppet","'"], + ["paren.rpar","]"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["support.function.puppet","type"], + ["text"," MyModule"], + ["keyword.operator","::"], + ["text","Tree "], + ["keyword.operator","="], + ["text"," "], + ["constant.types.puppet","Array"], + ["paren.lpar","["], + ["constant.types.puppet","Variant"], + ["paren.lpar","["], + ["constant.types.puppet","Data"], + ["keyword.operator",","], + ["text"," Tree"], + ["paren.rpar","]]"] +],[ + "start" +],[ + "start", + ["keyword.control.puppet","function"], + ["text"," apache"], + ["keyword.operator","::"], + ["text","bool2http"], + ["paren.lpar","("], + ["constant.types.puppet","Variant"], + ["paren.lpar","["], + ["constant.types.puppet","String"], + ["keyword.operator",","], + ["text"," "], + ["constant.types.puppet","Boolean"], + ["paren.rpar","]"], + ["text"," "], + ["variable.puppet","$arg"], + ["paren.rpar",")"], + ["text"," "], + ["keyword.operator",">>"], + ["keyword.name.resource.puppet"," String"], + ["paren.lpar"," {"] +],[ + "start", + ["text"," "], + ["keyword.control.puppet","case "], + ["variable.puppet","$arg"], + ["keyword.name.resource.puppet"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["constant.language.puppet","false"], + ["keyword.operator",","], + ["text"," "], + ["constant.language.puppet","undef"], + ["keyword.operator",","], + ["regexp.begin.string.puppet"," /(?i:false)/"], + ["text"," :"], + ["keyword.name.resource.puppet"," "], + ["paren.lpar","{"], + ["text"," "], + ["punctuation.quote.puppet","'"], + ["string","Off"], + ["punctuation.quote.puppet","'"], + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["text"," "], + ["constant.language.puppet","true"], + ["keyword.operator",","], + ["regexp.begin.string.puppet"," /(?i:true)/"], + ["text"," :"], + ["keyword.name.resource.puppet"," "], + ["paren.lpar","{"], + ["text"," "], + ["punctuation.quote.puppet","'"], + ["string","On"], + ["punctuation.quote.puppet","'"], + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["text"," "], + ["keyword.control.puppet","default"], + ["text"," :"], + ["keyword.name.resource.puppet"," "], + ["paren.lpar","{"], + ["text"," "], + ["punctuation.quote.puppet","\""], + ["variable.puppet","$arg"], + ["punctuation.quote.puppet","\""], + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["singleline.comment.puppet","# A class with parameters"] +],[ + "start", + ["keyword.type.puppet","class"], + ["constant.class.puppet"," apache "], + ["paren.lpar","("], + ["constant.types.puppet","String"], + ["text"," "], + ["variable.puppet","$version"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.quote.puppet","'"], + ["string","latest"], + ["punctuation.quote.puppet","'"], + ["paren.rpar",")"], + ["keyword.name.resource.puppet"," "], + ["paren.lpar","{"] +],[ + "start", + ["keyword.name.resource.puppet"," package"], + ["paren.lpar"," {"], + ["punctuation.quote.puppet","'"], + ["string","httpd"], + ["punctuation.quote.puppet","'"], + ["text",":"] +],[ + "start", + ["text"," "], + ["language.support.class","ensure"], + ["keyword.operator"," =>"], + ["text"," "], + ["variable.puppet","$version"], + ["keyword.operator",","], + ["text"," "], + ["singleline.comment.puppet","# Using the class parameter from above"] +],[ + "start", + ["text"," "], + ["language.support.class","before"], + ["keyword.operator"," =>"], + ["text"," "], + ["constant.types.puppet","File"], + ["paren.lpar","["], + ["punctuation.quote.puppet","'"], + ["string","/etc/httpd.conf"], + ["punctuation.quote.puppet","'"], + ["paren.rpar","]"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["keyword.name.resource.puppet"," file"], + ["paren.lpar"," {"], + ["punctuation.quote.puppet","'"], + ["string","/etc/httpd.conf"], + ["punctuation.quote.puppet","'"], + ["text",":"] +],[ + "start", + ["text"," "], + ["language.support.class","ensure"], + ["keyword.operator"," =>"], + ["text"," "], + ["support.function.puppet","file"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["language.support.class","owner"], + ["keyword.operator"," =>"], + ["text"," "], + ["punctuation.quote.puppet","'"], + ["string","httpd"], + ["punctuation.quote.puppet","'"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["language.support.class","content"], + ["keyword.operator"," =>"], + ["text"," "], + ["support.function.puppet","template"], + ["paren.lpar","("], + ["punctuation.quote.puppet","'"], + ["string","apache/httpd.conf.erb"], + ["punctuation.quote.puppet","'"], + ["paren.rpar",")"], + ["keyword.operator",","], + ["text"," "], + ["singleline.comment.puppet","# Template from a module"] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["keyword.name.resource.puppet"," service"], + ["paren.lpar"," {"], + ["punctuation.quote.puppet","'"], + ["string","httpd"], + ["punctuation.quote.puppet","'"], + ["text",":"] +],[ + "start", + ["text"," "], + ["language.support.class","ensure"], + ["keyword.operator"," =>"], + ["text"," "], + ["constant.language.puppet","running"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["language.support.class","enable"], + ["keyword.operator"," =>"], + ["text"," "], + ["constant.language.puppet","true"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["language.support.class","subscribe"], + ["keyword.operator"," =>"], + ["text"," "], + ["constant.types.puppet","File"], + ["paren.lpar","["], + ["punctuation.quote.puppet","'"], + ["string","/etc/httpd.conf"], + ["punctuation.quote.puppet","'"], + ["paren.rpar","]"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start" +],[ + "start", + ["keyword.control.puppet","if "], + ["variable.puppet","$is_virtual"], + ["keyword.name.resource.puppet"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["support.function.puppet","warning"], + ["paren.lpar","("], + ["text"," "], + ["punctuation.quote.puppet","'"], + ["string","Tried to include class ntp on virtual machine; this node might be misclassified."], + ["punctuation.quote.puppet","'"], + ["text"," "], + ["paren.rpar",")"] +],[ + "start", + ["paren.rpar","}"] +],[ + "start", + ["keyword.control.puppet","elsif "], + ["variable.puppet","$operatingsystem"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["punctuation.quote.puppet","'"], + ["string","Darwin"], + ["punctuation.quote.puppet","'"], + ["keyword.name.resource.puppet"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["support.function.puppet","warning"], + ["paren.lpar","("], + ["text"," "], + ["punctuation.quote.puppet","'"], + ["string","This NTP module does not yet work on our Mac laptops."], + ["punctuation.quote.puppet","'"], + ["text"," "], + ["paren.rpar",")"] +],[ + "start", + ["keyword.name.resource.puppet","else"], + ["paren.lpar"," {"] +],[ + "start", + ["text"," "], + ["keyword.control.puppet","include"], + ["text"," ntp"] +],[ + "start", + ["paren.rpar","}"] +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_terraform.json b/lib/ace/mode/_test/tokens_terraform.json new file mode 100644 index 00000000000..bc0eb22c9d9 --- /dev/null +++ b/lib/ace/mode/_test/tokens_terraform.json @@ -0,0 +1,629 @@ +[[ + "start", + ["storage.function.terraform","export"], + ["text"," "], + ["variable.assignment.terraform","TF_LOG"], + ["keyword.operator","="], + ["text","TRACE"] +],[ + "start" +],[ + "start", + ["singleline.comment.terraform","# An AMI"] +],[ + "start", + ["storage.function.terraform","variable"], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","ami"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","description"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","the AMI to use"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "blockComment", + ["multiline.comment.begin.terraform","/*"], + ["comment"," A multi"] +],[ + "start", + ["comment"," line comment. "], + ["multiline.comment.end.terraform","*/"] +],[ + "start", + ["storage.function.terraform","resource"], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","aws_instance"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","web"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","ami"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["punctuation.interpolated.begin.terraform","${"], + ["variable.terraform","var.ami"], + ["punctuation.interpolated.end.terraform","}"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","count"], + ["keyword.operator"," ="], + ["text"," "], + ["constant.numeric.terraform","2"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","source_dest_check"], + ["keyword.operator"," ="], + ["text"," "], + ["constant.language.terraform","false"] +],[ + "start" +],[ + "start", + ["text"," "], + ["language.support.class","connection"], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","user"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","root"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["storage.function.terraform","resource"], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","aws_instance"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","web"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","subnet"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["punctuation.interpolated.begin.terraform","${"], + ["variable.terraform","var.env"], + ["punctuation"," "], + ["keyword.operator","=="], + ["punctuation"," "], + ["punctuation.quote.terraform","\""], + ["string","production"], + ["punctuation.quote.terraform","\""], + ["punctuation"," "], + ["keyword.operator","?"], + ["punctuation"," "], + ["variable.terraform","var.prod_subnet"], + ["punctuation"," "], + ["keyword.operator",":"], + ["punctuation"," "], + ["variable.terraform","var.dev_subnet"], + ["punctuation.interpolated.end.terraform","}"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["storage.function.terraform","variable"], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","count"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","default"], + ["keyword.operator"," ="], + ["text"," "], + ["constant.numeric.terraform","2"] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["storage.function.terraform","variable"], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","hostnames"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","default"], + ["keyword.operator"," ="], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","0"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","example1.org"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","1"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","example2.net"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["storage.function.terraform","data"], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","template_file"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","web_init"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["singleline.comment.terraform","# Render the template once for each instance"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","count"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["punctuation.interpolated.begin.terraform","${"], + ["keyword.function.terraform","length"], + ["punctuation","("], + ["variable.terraform","var.hostnames"], + ["punctuation",")"], + ["punctuation.interpolated.end.terraform","}"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","template"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["punctuation.interpolated.begin.terraform","${"], + ["keyword.function.terraform","file"], + ["punctuation","("], + ["punctuation.quote.terraform","\""], + ["string","templates/web_init.tpl"], + ["punctuation.quote.terraform","\""], + ["punctuation",")"], + ["punctuation.interpolated.end.terraform","}"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["text"," vars "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["singleline.comment.terraform","# count.index tells us the index of the instance we are rendering"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","hostname"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["punctuation.interpolated.begin.terraform","${"], + ["variable.terraform","var.hostnames"], + ["paren.lpar","["], + ["variable.terraform","count.index"], + ["paren.rpar","]"], + ["punctuation.interpolated.end.terraform","}"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["storage.function.terraform","resource"], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","aws_instance"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","web"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["singleline.comment.terraform","# Create one instance for each hostname"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","count"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["punctuation.interpolated.begin.terraform","${"], + ["keyword.function.terraform","length"], + ["punctuation","("], + ["variable.terraform","var.hostnames"], + ["punctuation",")"], + ["punctuation.interpolated.end.terraform","}"], + ["punctuation.quote.terraform","\""] +],[ + "start" +],[ + "start", + ["text"," "], + ["singleline.comment.terraform","# Pass each instance its corresponding template_file"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","user_data"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["punctuation.interpolated.begin.terraform","${"], + ["punctuation","data.template_file.web_init."], + ["keyword.operator","*"], + ["punctuation",".rendered"], + ["paren.lpar","["], + ["variable.terraform","count.index"], + ["paren.rpar","]"], + ["punctuation.interpolated.end.terraform","}"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["storage.function.terraform","variable"], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","count"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","default"], + ["keyword.operator"," ="], + ["text"," "], + ["constant.numeric.terraform","2"] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["singleline.comment.terraform","# Define the common tags for all resources"] +],[ + "start", + ["storage.function.terraform","locals {"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","common_tags"], + ["keyword.operator"," ="], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","Component"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","awesome-app"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","Environment"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","production"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["singleline.comment.terraform","# Create a resource that blends the common tags with instance-specific tags."] +],[ + "start", + ["storage.function.terraform","resource"], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","aws_instance"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","server"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","ami"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","ami-123456"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","instance_type"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","t2.micro"], + ["punctuation.quote.terraform","\""] +],[ + "start" +],[ + ["punctuation.interpolated.begin.terraform","punctuation.quote.terraform0"], + ["text"," "], + ["variable.assignment.terraform","tags"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["punctuation.interpolated.begin.terraform","${"], + ["keyword.function.terraform","merge"], + ["punctuation","("] +],[ + ["punctuation.interpolated.begin.terraform","punctuation.quote.terraform0"], + ["punctuation"," "], + ["variable.terraform","local.common_tags"], + ["punctuation",","] +],[ + ["punctuation.interpolated.begin.terraform","punctuation.quote.terraform0"], + ["punctuation"," "], + ["keyword.function.terraform","map"], + ["punctuation","("] +],[ + ["punctuation.interpolated.begin.terraform","punctuation.quote.terraform0"], + ["punctuation"," "], + ["punctuation.quote.terraform","\""], + ["string","Name"], + ["punctuation.quote.terraform","\""], + ["punctuation",", "], + ["punctuation.quote.terraform","\""], + ["string","awesome-app-server"], + ["punctuation.quote.terraform","\""], + ["punctuation",","] +],[ + ["punctuation.interpolated.begin.terraform","punctuation.quote.terraform0"], + ["punctuation"," "], + ["punctuation.quote.terraform","\""], + ["string","Role"], + ["punctuation.quote.terraform","\""], + ["punctuation",", "], + ["punctuation.quote.terraform","\""], + ["string","server"], + ["punctuation.quote.terraform","\""] +],[ + ["punctuation.interpolated.begin.terraform","punctuation.quote.terraform0"], + ["punctuation"," )"] +],[ + "start", + ["punctuation"," )"], + ["punctuation.interpolated.end.terraform","}"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["paren.rpar","}"] +],[ + "start" +],[ + "start", + ["variable.terraform","$ "], + ["text","terraform apply "], + ["keyword.terraform","-var"], + ["text"," "], + ["variable.assignment.terraform","foo"], + ["keyword.operator","="], + ["text","bar "], + ["keyword.terraform","-var"], + ["text"," "], + ["variable.assignment.terraform","foo"], + ["keyword.operator","="], + ["text","baz"] +],[ + "variable.terraform", + ["variable.terraform","$ "], + ["text","terraform apply "], + ["keyword.terraform","-var"], + ["text"," "], + ["punctuation.quote.terraform","'"], + ["string","foo={quux=\"bar\"}"], + ["punctuation.quote.terraform","'"], + ["text"," "], + ["keyword.terraform","-var"], + ["text"," "], + ["punctuation.quote.terraform","'"], + ["string","foo={bar=\"baz\"}"], + ["punctuation.quote.terraform","'"] +],[ + "start" +],[ + "start", + ["variable.terraform","$ "], + ["text","terraform apply "], + ["keyword.terraform","-var-file"], + ["keyword.operator","="], + ["text","foo.tfvars "], + ["keyword.terraform","-var-file"], + ["keyword.operator","="], + ["text","bar.tfvars"] +],[ + "start", + ["variable.terraform","$ "], + ["variable.assignment.terraform","TF_VAR_somemap"], + ["keyword.operator","="], + ["punctuation.quote.terraform","'"], + ["string","{foo = \"bar\", baz = \"qux\"}"], + ["punctuation.quote.terraform","'"], + ["text"," terraform plan"] +],[ + "start" +],[ + "start", + ["storage.function.terraform","resource"], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","aws_instance"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["string","web"], + ["punctuation.quote.terraform","\""], + ["text"," "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["singleline.comment.terraform","# ..."] +],[ + "start" +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","count"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["punctuation.interpolated.begin.terraform","${"], + ["variable.terraform","var.count"], + ["punctuation.interpolated.end.terraform","}"], + ["punctuation.quote.terraform","\""] +],[ + "start" +],[ + "start", + ["text"," "], + ["singleline.comment.terraform","# Tag the instance with a counter starting at 1, ie. web-001"] +],[ + "start", + ["text"," tags "], + ["paren.lpar","{"] +],[ + "start", + ["text"," "], + ["variable.assignment.terraform","Name"], + ["keyword.operator"," ="], + ["text"," "], + ["punctuation.quote.terraform","\""], + ["punctuation.interpolated.begin.terraform","${"], + ["keyword.function.terraform","format"], + ["punctuation","("], + ["punctuation.quote.terraform","\""], + ["string","web-%03d"], + ["punctuation.quote.terraform","\""], + ["punctuation",", "], + ["variable.terraform","count.index"], + ["punctuation"," "], + ["keyword.operator","+"], + ["punctuation"," "], + ["constant.numeric.terraform","1"], + ["punctuation",")"], + ["punctuation.interpolated.end.terraform","}"], + ["punctuation.quote.terraform","\""] +],[ + "start", + ["text"," "], + ["paren.rpar","}"] +],[ + "start", + ["paren.rpar","}"] +]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_visualforce.json b/lib/ace/mode/_test/tokens_visualforce.json new file mode 100644 index 00000000000..ebf416ae8df --- /dev/null +++ b/lib/ace/mode/_test/tokens_visualforce.json @@ -0,0 +1,306 @@ +[[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","apex:stylesheet"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","value"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["keyword.start","{!"], + ["support.function","URLFOR"], + ["keyword.operator","("], + ["variable.language","$Resource"], + ["punctuation.operator","."], + ["identifier","BrowserCompatibility"], + ["punctuation.operator",","], + ["text"," "], + ["string.start","'"], + ["string","css/style.css"], + ["string.end","'"], + ["keyword.operator",")"], + ["keyword.end","}"], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-close.xml","/>"] +],[ + "start" +],[ + ["Visualforce","string.attribute-value.xml0","string.attribute-value.xml0","tag_stuff"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","apex:page"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","action"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["keyword.start","{!"], + ["support.function","IF"], + ["keyword.operator","("], + ["variable.language","$User"], + ["punctuation.operator","."], + ["identifier","Alias"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.start","'"], + ["string","JohnDoe"], + ["string.end","'"], + ["text"," "], + ["keyword.operator","||"], + ["text"," "], + ["variable.language","$User"], + ["punctuation.operator","."], + ["identifier","Alias"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.start","'"], + ["string","JBloggs"], + ["string.end","'"], + ["text"," "], + ["keyword.operator","||"], + ["text"," "], + ["variable.language","$User"], + ["punctuation.operator","."], + ["identifier","Alias"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.start","'"], + ["string","FooBar"], + ["string.end","'"], + ["punctuation.operator",","] +],[ + ["Visualforce","string.attribute-value.xml0","string.attribute-value.xml0","tag_stuff"], + ["text"," "], + ["constant.language","null"], + ["punctuation.operator",","] +],[ + ["Visualforce","string.attribute-value.xml0","string.attribute-value.xml0","tag_stuff"], + ["text"," "], + ["identifier","urlFor"], + ["keyword.operator","("], + ["variable.language","$Action"], + ["punctuation.operator","."], + ["identifier","Account"], + ["punctuation.operator","."], + ["identifier","Delete"], + ["punctuation.operator",","], + ["text"," "], + ["variable.language","$CurrentPage"], + ["punctuation.operator","."], + ["identifier","Parameters"], + ["punctuation.operator","."], + ["identifier","id"], + ["punctuation.operator",","], + ["text"," "], + ["paren.lparen","["], + ["identifier","retURL"], + ["keyword.operator","="], + ["string.start","'"], + ["string","/001"], + ["string.end","'"], + ["paren.rparen","]"], + ["punctuation.operator",","], + ["text"," "], + ["constant.language","true"], + ["keyword.operator",")"] +],[ + "start", + ["keyword.operator",")"], + ["keyword.end","}"], + ["string.attribute-value.xml","\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","standardController"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"Account\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + ["Visualforce","string.attribute-value.xml0","string.attribute-value.xml0","tag_stuff"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","apex:page"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","action"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["keyword.start","{!"], + ["support.function","IF"], + ["keyword.operator","("], + ["support.function","OR"], + ["keyword.operator","("], + ["variable.language","$User"], + ["punctuation.operator","."], + ["identifier","Alias"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.start","'"], + ["string","JohnDoe"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["variable.language","$User"], + ["punctuation.operator","."], + ["identifier","Alias"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.start","'"], + ["string","JBloggs"], + ["string.end","'"], + ["punctuation.operator",","], + ["text"," "], + ["variable.language","$User"], + ["punctuation.operator","."], + ["identifier","Alias"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.start","'"], + ["string","FooBar"], + ["string.end","'"], + ["keyword.operator",")"], + ["punctuation.operator",","] +],[ + ["Visualforce","string.attribute-value.xml0","string.attribute-value.xml0","tag_stuff"], + ["text"," "], + ["constant.language","NULL"], + ["punctuation.operator",","] +],[ + ["Visualforce","string.attribute-value.xml0","string.attribute-value.xml0","tag_stuff"], + ["text"," "], + ["support.function","URLFOR"], + ["keyword.operator","("], + ["variable.language","$Action"], + ["punctuation.operator","."], + ["identifier","Account"], + ["punctuation.operator","."], + ["identifier","Delete"], + ["punctuation.operator",","], + ["text"," "], + ["variable.language","$CurrentPage"], + ["punctuation.operator","."], + ["identifier","Parameters"], + ["punctuation.operator","."], + ["identifier","id"], + ["punctuation.operator",","], + ["text"," "], + ["paren.lparen","["], + ["identifier","retURL"], + ["keyword.operator","="], + ["string.start","'"], + ["string","/001"], + ["string.end","'"], + ["paren.rparen","]"], + ["punctuation.operator",","], + ["text"," "], + ["constant.language","TRUE"], + ["keyword.operator",")"] +],[ + "start", + ["keyword.operator",")"], + ["keyword.end","}"], + ["string.attribute-value.xml","\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","standardController"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"Account\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "tag_stuff", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","apex:commandLink"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","action"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["keyword.start","{!"], + ["support.function","URLFOR"], + ["keyword.operator","("], + ["string.start","'"], + ["string","/apex/"], + ["string.end","'"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["variable.language","$CurrentPage"], + ["punctuation.operator","."], + ["identifier","Name"], + ["punctuation.operator",","], + ["text"," "], + ["constant.language","null"], + ["punctuation.operator",","], + ["text"," "], + ["paren.lparen","["], + ["string.start","'"], + ["string","id"], + ["string.end","'"], + ["keyword.operator","="], + ["identifier","id"], + ["paren.rparen","]"], + ["keyword.operator",")"], + ["keyword.end","}"], + ["string.attribute-value.xml","\""], + ["text.tag-whitespace.xml"," "] +],[ + "start", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","value"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"Full List\""], + ["text.tag-whitespace.xml"," "], + ["meta.tag.punctuation.tag-close.xml","/>"] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","ideas:listOutputLink"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","stickyAttributes"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"false\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["keyword.start","{!"], + ["support.function","IF"], + ["keyword.operator","("], + ["support.function","AND"], + ["keyword.operator","("], + ["identifier","Price"], + ["text"," "], + ["keyword.operator","<"], + ["text"," 1"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","Quantity"], + ["text"," "], + ["keyword.operator","<"], + ["text"," 1"], + ["keyword.operator",")"], + ["punctuation.operator",","], + ["text"," "], + ["string.start","\""], + ["string","Small"], + ["string.end","\""], + ["punctuation.operator",","], + ["text"," "], + ["constant.language","null"], + ["keyword.operator",")"], + ["keyword.end","}"] +]] \ No newline at end of file diff --git a/lib/ace/mode/nginx_highlight_rules.js b/lib/ace/mode/nginx_highlight_rules.js new file mode 100644 index 00000000000..b93d953d527 --- /dev/null +++ b/lib/ace/mode/nginx_highlight_rules.js @@ -0,0 +1,154 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function (require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; +var NginxHighlightRules = function () { + var keywords = "include|index|absolute_redirect|aio|output_buffers|directio|sendfile|aio_write|alias|root|chunked_transfer_encoding|client_body_buffer_size|client_body_in_file_only|client_body_in_single_buffer|client_body_temp_path|client_body_timeout|client_header_buffer_size|client_header_timeout|client_max_body_size|connection_pool_size|default_type|disable_symlinks|directio_alignment|error_page|etag|if_modified_since|ignore_invalid_headers|internal|keepalive_requests|keepalive_disable|keepalive_timeout|limit_except|large_client_header_buffers|limit_rate|limit_rate_after|lingering_close|lingering_time|lingering_timeout|listen|log_not_found|log_subrequest|max_ranges|merge_slashes|msie_padding|msie_refresh|open_file_cache|open_file_cache_errors|open_file_cache_min_uses|open_file_cache_valid|output_buffers|port_in_redirect|postpone_output|read_ahead|recursive_error_pages|request_pool_size|reset_timedout_connection|resolver|resolver_timeout|satisfy|send_lowat|send_timeout|sendfile|sendfile_max_chunk|server_name|server_name_in_redirect|server_names_hash_bucket_size|server_names_hash_max_size|server_tokens|subrequest_output_buffer_size|tcp_nodelay|tcp_nopush|try_files|types|types_hash_bucket_size|types_hash_max_size|underscores_in_headers|variables_hash_bucket_size|variables_hash_max_size|accept_mutex|accept_mutex_delay|debug_connection|error_log|daemon|debug_points|env|load_module|lock_file|master_process|multi_accept|pcre_jit|pid|ssl_engine|thread_pool|timer_resolution|use|user|worker_aio_requests|worker_connections|worker_cpu_affinity|worker_priority|worker_processes|worker_rlimit_core|worker_rlimit_nofile|worker_shutdown_timeout|working_directory|allow|deny|add_before_body|add_after_body|addition_types|api|status_zone|auth_basic|auth_basic_user_file|auth_jwt|auth_jwt|auth_jwt_claim_set|auth_jwt_header_set|auth_jwt_key_file|auth_jwt_key_request|auth_jwt_leeway|auth_request|auth_request_set|autoindex|autoindex_exact_size|autoindex_format|autoindex_localtime|ancient_browser|ancient_browser_value|modern_browser|modern_browser_value|charset|charset_map|charset_types|override_charset|source_charset|create_full_put_path|dav_access|dav_methods|min_delete_depth|empty_gif|f4f|f4f_buffer_size|fastcgi_bind|fastcgi_buffer_size|fastcgi_buffering|fastcgi_buffers|fastcgi_busy_buffers_size|fastcgi_cache|fastcgi_cache_background_update|fastcgi_cache_bypass|fastcgi_cache_key|fastcgi_cache_lock|fastcgi_cache_lock_age|fastcgi_cache_lock_timeout|fastcgi_cache_max_range_offset|fastcgi_cache_methods|fastcgi_cache_min_uses|fastcgi_cache_min_uses|fastcgi_cache_path|fastcgi_cache_purge|fastcgi_cache_revalidate|fastcgi_cache_use_stale|fastcgi_cache_valid|fastcgi_catch_stderr|fastcgi_connect_timeout|fastcgi_force_ranges|fastcgi_hide_header|fastcgi_ignore_client_abort|fastcgi_ignore_headers|fastcgi_index|fastcgi_intercept_errors|fastcgi_keep_conn|fastcgi_limit_rate|fastcgi_max_temp_file_size|fastcgi_next_upstream|fastcgi_next_upstream_timeout|fastcgi_next_upstream_tries|fastcgi_no_cache|fastcgi_param|fastcgi_pass|fastcgi_pass_header|fastcgi_pass_request_body|fastcgi_pass_request_headers|fastcgi_read_timeout|fastcgi_request_buffering|fastcgi_send_lowat|fastcgi_send_timeout|fastcgi_socket_keepalive|fastcgi_split_path_info|fastcgi_store|fastcgi_store_access|fastcgi_temp_file_write_size|fastcgi_temp_path|flv|geoip_country|geoip_city|geoip_org|geoip_proxy|geoip_proxy_recursive|grpc_bind|grpc_buffer_size|grpc_connect_timeout|grpc_hide_header|grpc_ignore_headers|grpc_intercept_errors|grpc_next_upstream|grpc_next_upstream_timeout|grpc_next_upstream_tries|grpc_pass|grpc_pass_header|grpc_read_timeout|grpc_send_timeout|grpc_set_header|grpc_socket_keepalive|grpc_ssl_certificate|grpc_ssl_certificate_key|grpc_ssl_ciphers|grpc_ssl_crl|grpc_ssl_name|grpc_ssl_password_file|grpc_ssl_protocols|grpc_ssl_server_name|grpc_ssl_session_reuse|grpc_ssl_trusted_certificate|grpc_ssl_verify|grpc_ssl_verify_depth|gunzip|gunzip_buffers|gzip|gzip_buffers|gzip_comp_level|gzip_disable|gzip_http_version|gzip_min_length|gzip_proxied|gzip_types|gzip_vary|gzip_static|add_header|add_trailer|expires|hlshls_buffers|hls_forward_args|hls_fragment|hls_mp4_buffer_size|hls_mp4_max_buffer_size|image_filter|image_filter_buffer|image_filter_interlace|image_filter_jpeg_quality|image_filter_sharpen|image_filter_transparency|image_filter_webp_quality|js_content|js_include|js_set|keyval|keyval_zone|limit_conn|limit_conn_log_level|limit_conn_status|limit_conn_zone|limit_zone|limit_req|limit_req_log_level|limit_req_status|limit_req_zone|access_log|log_format|open_log_file_cache|map_hash_bucket_size|map_hash_max_size|memcached_bind|memcached_buffer_size|memcached_connect_timeout|memcached_force_ranges|memcached_gzip_flag|memcached_next_upstream|memcached_next_upstream_timeout|memcached_next_upstream_tries|memcached_pass|memcached_read_timeout|memcached_send_timeout|memcached_socket_keepalive|mirror|mirror_request_body|mp4|mp4_buffer_size|mp4_max_buffer_size|mp4_limit_rate|mp4_limit_rate_after|perl_modules|perl_require|perl_set|proxy_bind|proxy_buffer_size|proxy_buffering|proxy_buffers|proxy_busy_buffers_size|proxy_cache|proxy_cache_background_update|proxy_cache_bypass|proxy_cache_convert_head|proxy_cache_key|proxy_cache_lock|proxy_cache_lock_age|proxy_cache_lock_timeout|proxy_cache_max_range_offset|proxy_cache_methods|proxy_cache_min_uses|proxy_cache_path|proxy_cache_purge|proxy_cache_revalidate|proxy_cache_use_stale|proxy_cache_valid|proxy_connect_timeout|proxy_cookie_domain|proxy_cookie_path|proxy_force_ranges|proxy_headers_hash_bucket_size|proxy_headers_hash_max_size|proxy_hide_header|proxy_http_version|proxy_ignore_client_abort|proxy_ignore_headers|proxy_intercept_errors|proxy_limit_rate|proxy_max_temp_file_size|proxy_method|proxy_next_upstream|proxy_next_upstream_timeout|proxy_next_upstream_tries|proxy_no_cache|proxy_pass|proxy_pass_header|proxy_pass_request_body|proxy_pass_request_headers|proxy_read_timeout|proxy_redirect|proxy_send_lowat|proxy_send_timeout|proxy_set_body|proxy_set_header|proxy_socket_keepalive|proxy_ssl_certificate|proxy_ssl_certificate_key|proxy_ssl_ciphers|proxy_ssl_crl|proxy_ssl_name|proxy_ssl_password_file|proxy_ssl_protocols|proxy_ssl_server_name|proxy_ssl_session_reuse|proxy_ssl_trusted_certificate|proxy_ssl_verify|proxy_ssl_verify_depth|proxy_store|proxy_store_access|proxy_temp_file_write_size|proxy_temp_path|random_index|set_real_ip_from|real_ip_header|real_ip_recursive|referer_hash_bucket_size|referer_hash_max_size|valid_referers|break|return|rewrite_log|set|uninitialized_variable_warn|scgi_bind|scgi_buffer_size|scgi_buffering|scgi_buffers|scgi_busy_buffers_size|scgi_cache|scgi_cache_background_update|scgi_cache_key|scgi_cache_lock|scgi_cache_lock_age|scgi_cache_lock_timeout|scgi_cache_max_range_offset|scgi_cache_methods|scgi_cache_min_uses|scgi_cache_path|scgi_cache_purge|scgi_cache_revalidate|scgi_cache_use_stale|scgi_cache_valid|scgi_connect_timeout|scgi_force_ranges|scgi_hide_header|scgi_ignore_client_abort|scgi_ignore_headers|scgi_intercept_errors|scgi_limit_rate|scgi_max_temp_file_size|scgi_next_upstream|scgi_next_upstream_timeout|scgi_next_upstream_tries|scgi_no_cache|scgi_param|scgi_pass|scgi_pass_header|scgi_pass_request_body|scgi_pass_request_headers|scgi_read_timeout|scgi_request_buffering|scgi_send_timeout|scgi_socket_keepalive|scgi_store|scgi_store_access|scgi_temp_file_write_size|scgi_temp_path|secure_link|secure_link_md5|secure_link_secret|session_log|session_log_format|session_log_zone|slice|spdy_chunk_size|spdy_headers_comp|ssi|ssi_last_modified|ssi_min_file_chunk|ssi_silent_errors|ssi_types|ssi_value_length|ssl|ssl_buffer_size|ssl_certificate|ssl_certificate_key|ssl_ciphers|ssl_client_certificate|ssl_crl|ssl_dhparam|ssl_early_data|ssl_ecdh_curve|ssl_password_file|ssl_prefer_server_ciphers|ssl_protocols|ssl_session_cache|ssl_session_ticket_key|ssl_session_tickets|ssl_session_timeout|ssl_stapling|ssl_stapling_file|ssl_stapling_responder|ssl_stapling_verify|ssl_trusted_certificate|ssl_verify_client|ssl_verify_depth|status|status_format|status_zone|stub_status|sub_filter|sub_filter_last_modified|sub_filter_once|sub_filter_types|server|zone|state|hash|ip_hash|keepalive|keepalive_requests|keepalive_timeout|ntlm|least_conn|least_time|queue|random|sticky|sticky_cookie_insert|upstream_conf|health_check|userid|userid_domain|userid_expires|userid_mark|userid_name|userid_p3p|userid_path|userid_service|uwsgi_bind|uwsgi_buffer_size|uwsgi_buffering|uwsgi_buffers|uwsgi_busy_buffers_size|uwsgi_cache|uwsgi_cache_background_update|uwsgi_cache_bypass|uwsgi_cache_key|uwsgi_cache_lock|uwsgi_cache_lock_age|uwsgi_cache_lock_timeout|uwsgi_cache_max_range_offset|uwsgi_cache_methods|uwsgi_cache_min_uses|uwsgi_cache_path|uwsgi_cache_purge|uwsgi_cache_revalidate|uwsgi_cache_use_stale|uwsgi_cache_valid|uwsgi_connect_timeout|uwsgi_force_ranges|uwsgi_hide_header|uwsgi_ignore_client_abort|uwsgi_ignore_headers|uwsgi_intercept_errors|uwsgi_limit_rate|uwsgi_max_temp_file_size|uwsgi_modifier1|uwsgi_modifier2|uwsgi_next_upstream|uwsgi_next_upstream_timeout|uwsgi_next_upstream_tries|uwsgi_no_cache|uwsgi_param|uwsgi_pass|uwsgi_pass_header|uwsgi_pass_request_body|uwsgi_pass_request_headers|uwsgi_read_timeout|uwsgi_request_buffering|uwsgi_send_timeout|uwsgi_socket_keepalive|uwsgi_ssl_certificate|uwsgi_ssl_certificate_key|uwsgi_ssl_ciphers|uwsgi_ssl_crl|uwsgi_ssl_name|uwsgi_ssl_password_file|uwsgi_ssl_protocols|uwsgi_ssl_server_name|uwsgi_ssl_session_reuse|uwsgi_ssl_trusted_certificate|uwsgi_ssl_verify|uwsgi_ssl_verify_depth|uwsgi_store|uwsgi_store_access|uwsgi_temp_file_write_size|uwsgi_temp_path|http2_body_preread_size|http2_chunk_size|http2_idle_timeout|http2_max_concurrent_pushes|http2_max_concurrent_streams|http2_max_field_size|http2_max_header_size|http2_max_requests|http2_push|http2_push_preload|http2_recv_buffer_size|http2_recv_timeout|xml_entities|xslt_last_modified|xslt_param|xslt_string_param|xslt_stylesheet|xslt_types|listen|protocol|resolver|resolver_timeout|timeout|auth_http|auth_http_header|auth_http_pass_client_cert|auth_http_timeout|proxy_buffer|proxy_pass_error_message|proxy_timeout|xclient|starttls|imap_auth|imap_capabilities|imap_client_buffer|pop3_auth|pop3_capabilities|smtp_auth|smtp_capabilities|smtp_client_buffer|smtp_greeting_delay|preread_buffer_size|preread_timeout|proxy_protocol_timeout|js_access|js_filter|js_preread|proxy_download_rate|proxy_requests|proxy_responses|proxy_upload_rate|ssl_handshake_timeout|ssl_preread|health_check_timeout|zone_sync|zone_sync_buffers|zone_sync_connect_retry_interval|zone_sync_connect_timeout|zone_sync_interval|zone_sync_recv_buffer_size|zone_sync_server|zone_sync_ssl|zone_sync_ssl_certificate|zone_sync_ssl_certificate_key|zone_sync_ssl_ciphers|zone_sync_ssl_crl|zone_sync_ssl_name|zone_sync_ssl_password_file|zone_sync_ssl_protocols|zone_sync_ssl_server_name|zone_sync_ssl_trusted_certificate|zone_sync_ssl_verify_depth|zone_sync_timeout|google_perftools_profiles|proxy|perl"; + + this.$rules = { + "start": [{ + token: ["storage.type", "text", "string.regexp", "paren.lpar"], + regex: "\\b(location)(\\s+)([\\^]?~[\\*]?\\s+.*?)({)" + }, { + token: ["storage.type", "text", "text", "paren.lpar"], + regex: "\\b(location|match|upstream)(\\s+)(.*?)({)" + }, { + token: ["storage.type", "text", "string", "text", "variable", "text", "paren.lpar"], + regex: '\\b(split_clients|map)(\\s+)(\\".*\\")(\\s+)(\\$[\\w_]+)(\\s*)({)' + }, { + token: ["storage.type", "text", "paren.lpar"], + regex: "\\b(http|events|server|mail|stream)(\\s*)({)" + }, { + token: ["storage.type", "text", "variable", "text", "variable", "text", "paren.lpar"], + regex: '\\b(geo|map)(\\s+)(\\$[\\w_]+)?(\\s*)(\\$[\\w_]+)(\\s*)({)' + }, { + token: "paren.rpar", + regex: "(})" + }, { + token: "paren.lpar", + regex: "({)" + }, { + token: ["storage.type", "text", "paren.lpar"], + regex: "\\b(if)(\\s+)(\\()", + push: [{ + token: "paren.rpar", + regex: "\\)|$", + next: "pop" + }, { + include: "lexical" + }] + }, { + token: "keyword", + regex: "\\b(" + keywords + ")\\b", + push: [{ + token: "punctuation", + regex: ";", + next: "pop" + }, { + include: "lexical" + }] + }, { + token: ["keyword", "text", "string.regexp", "text", "punctuation"], + regex: "\\b(rewrite)(\\s)(\\S*)(\\s.*)(;)" + }, { + include: "lexical" + }, { + include: "comments" + }], + comments: [{ + token: "comment", + regex: '#.*$' + }], + lexical: [{ + token: "string", + regex: "'", + push: [{ + token: "string", + regex: "'", + next: "pop" + }, { + include: "variables" + }, { + defaultToken: "string" + }] + }, { + token: "string", + regex: '"', + push: [{ + token: "string", + regex: '"', + next: "pop" + }, { + include: "variables" + }, { + defaultToken: "string" + }] + }, { + token: "string.regexp", + regex: /[!]?[~][*]?\s+.*(?=\))/ + }, { + token: "string.regexp", + regex: /[\^]\S*(?=;$)/ + }, { + token: "string.regexp", + regex: /[\^]\S*(?=;|\s|$)/ + }, { + token: "keyword.operator", + regex: "\\B(\\+|\\-|\\*|\\=|!=)\\B" + }, { + token: "constant.language", + regex: "\\b(true|false|on|off|all|any|main|always)\\b" + }, { + token: "text", + regex: "\\s+" + }, { + include: "variables" + } + ], + variables: [{ + token: "variable", + regex: "\\$[\\w_]+" + }, { + token: "variable.language", + regex: "\\b(GET|POST|HEAD)\\b" + }] + }; + this.normalizeRules(); +}; + + +oop.inherits(NginxHighlightRules, TextHighlightRules); + +exports.NginxHighlightRules = NginxHighlightRules; +}); From 9c02b5a450251c0a1f5b7ad8df78ec0c531b39d5 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 18 Mar 2019 23:51:39 +0400 Subject: [PATCH 0139/1293] add crystal mode --- demo/kitchen-sink/docs/crystal.cr | 33 ++ lib/ace/ext/modelist.js | 1 + lib/ace/mode/crystal.js | 100 +++++ lib/ace/mode/crystal_highlight_rules.js | 469 ++++++++++++++++++++++++ 4 files changed, 603 insertions(+) create mode 100644 demo/kitchen-sink/docs/crystal.cr create mode 100644 lib/ace/mode/crystal.js create mode 100644 lib/ace/mode/crystal_highlight_rules.js diff --git a/demo/kitchen-sink/docs/crystal.cr b/demo/kitchen-sink/docs/crystal.cr new file mode 100644 index 00000000000..fe27502adce --- /dev/null +++ b/demo/kitchen-sink/docs/crystal.cr @@ -0,0 +1,33 @@ +# crystal comment + +require "llvm" + +NUM_CELLS = 30000 +CELL_SIZE_IN_BYTES = 1 + +abstract class Instruction + abstract def compile(program, bb) +end + +class Increment < Instruction + def initialize(@amount : Int32) + end + + def compile(program, bb) + cell_val_is_zero = builder.icmp LLVM::IntPredicate::EQ, cell_val, zero + call_args = [@ctx.int32.const_int(NUM_CELLS), @ctx.int32.const_int(CELL_SIZE_IN_BYTES)] + builder.cond cell_val_is_zero, loop_after, loop_body_block + + @body.each do |instruction| + loop_body_block = instruction.compile(program, loop_body_block) + end + + builder.position_at_end loop_body_block + + unless matching_close_index + error "Unmatched '[' at position #{i}" + end + + bb + end +end diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 7fbb9140d7b..858652080ac 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -57,6 +57,7 @@ var supportedModes = { Bro: ["bro"], C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp|ino"], C9Search: ["c9search_results"], + Crystal: ["cr"], Cirru: ["cirru|cr"], Clojure: ["clj|cljs"], Cobol: ["CBL|COB"], diff --git a/lib/ace/mode/crystal.js b/lib/ace/mode/crystal.js new file mode 100644 index 00000000000..4b08dc6eece --- /dev/null +++ b/lib/ace/mode/crystal.js @@ -0,0 +1,100 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var CrystalHighlightRules = require("./crystal_highlight_rules").CrystalHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var Range = require("../range").Range; +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var FoldMode = require("./folding/coffee").FoldMode; + +var Mode = function() { + this.HighlightRules = CrystalHighlightRules; + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CstyleBehaviour(); + this.foldingRules = new FoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + + this.lineCommentStart = "#"; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.getTokenizer().getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start") { + var match = line.match(/^.*[\{\(\[]\s*$/); + var startingClassOrMethod = line.match(/^\s*(class|def|module)\s.*$/); + var startingDoBlock = line.match(/.*do(\s*|\s+\|.*\|\s*)$/); + var startingConditional = line.match(/^\s*(if|else|when)\s*/); + if (match || startingClassOrMethod || startingDoBlock || startingConditional) { + indent += tab; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return /^\s+(end|else)$/.test(line + input) || this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, session, row) { + var line = session.getLine(row); + if (/}/.test(line)) + return this.$outdent.autoOutdent(session, row); + var indent = this.$getIndent(line); + var prevLine = session.getLine(row - 1); + var prevIndent = this.$getIndent(prevLine); + var tab = session.getTabString(); + if (prevIndent.length <= indent.length) { + if (indent.slice(-tab.length) == tab) + session.remove(new Range(row, indent.length-tab.length, row, indent.length)); + } + }; + + this.$id = "ace/mode/crystal"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/crystal_highlight_rules.js b/lib/ace/mode/crystal_highlight_rules.js new file mode 100644 index 00000000000..f754143a20b --- /dev/null +++ b/lib/ace/mode/crystal_highlight_rules.js @@ -0,0 +1,469 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function (require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + + var CrystalHighlightRules = function () { + + var builtinFunctions = ( + "puts|initialize|previous_def|typeof|as|pointerof|sizeof|instance_sizeof" + ); + + var keywords = ( + "if|end|else|elsif|unless|case|when|break|while|next|until|def|return|class|new|getter|setter|property|lib" + + "|fun|do|struct|private|protected|public|module|super|abstract|include|extend|begin|enum|raise|yield|with" + + "|alias|rescue|ensure|macro|uninitialized|union|type|require" + ); + + var buildinConstants = ( + "true|TRUE|false|FALSE|nil|NIL|__LINE__|__END_LINE__|__FILE__|__DIR__" + ); + + var builtinVariables = ( + "$DEBUG|$defout|$FILENAME|$LOAD_PATH|$SAFE|$stdin|$stdout|$stderr|$VERBOSE|" + + "root_url|flash|session|cookies|params|request|response|logger|self" + ); + + var keywordMapper = this.$keywords = this.createKeywordMapper({ + "keyword": keywords, + "constant.language": buildinConstants, + "variable.language": builtinVariables, + "support.function": builtinFunctions + }, "identifier"); + + var hexNumber = "(?:0[xX][\\dA-Fa-f]+)"; + var decNumber = "(?:[0-9][\\d_]*)"; + var octNumber = "(?:0o[0-7][0-7]*)"; + var binNumber = "(?:0[bB][01]+)"; + var intNumber = "(?:[+-]?)(?:" + hexNumber + "|" + decNumber + "|" + octNumber + "|" + binNumber + ")(?:_?[iIuU](?:8|16|32|64))?\\b"; + var escapeExpression = /\\(?:[nsrtvfbae'"\\]|[0-7]{3}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u{[\da-fA-F]{1,6}})/; + var extEscapeExspresssion = /\\(?:[nsrtvfbae'"\\]|[0-7]{3}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u{[\da-fA-F]{1,6}}|u{(:?[\da-fA-F]{2}\s)*[\da-fA-F]{2}})/; + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + "start": [ + { + token: "comment", + regex: "#.*$" + }, { + token: "string.regexp", + regex: "[/]", + push: [{ + token: "constant.language.escape", + regex: extEscapeExspresssion + }, { + token: "string.regexp", + regex: "[/][imx]*(?=[).,;\\s]|$)", + next: "pop" + }, { + defaultToken: "string.regexp" + }] + }, + [{ + regex: "[{}]", onMatch: function (val, state, stack) { + this.next = val == "{" ? this.nextState : ""; + if (val == "{" && stack.length) { + stack.unshift("start", state); + return "paren.lparen"; + } + if (val == "}" && stack.length) { + stack.shift(); + this.next = stack.shift(); + if (this.next.indexOf("string") != -1) + return "paren.end"; + } + return val == "{" ? "paren.lparen" : "paren.rparen"; + }, + nextState: "start" + }, { + token: "string.start", + regex: /"/, + push: [{ + token: "constant.language.escape", + regex: extEscapeExspresssion + }, { + token: "string", + regex: /\\#{/ + }, { + token: "paren.start", + regex: /#{/, + push: "start" + }, { + token: "string.end", + regex: /"/, + next: "pop" + }, { + defaultToken: "string" + }] + }, { + token: "string.start", + regex: /`/, + push: [{ + token: "constant.language.escape", + regex: extEscapeExspresssion + }, { + token: "string", + regex: /\\#{/ + }, { + token: "paren.start", + regex: /#{/, + push: "start" + }, { + token: "string.end", + regex: /`/, + next: "pop" + }, { + defaultToken: "string" + }] + }, { + stateName: "rpstring", + token: "string.start", + regex: /%[Qx]?\(/, + push: [{ + token: "constant.language.escape", + regex: extEscapeExspresssion + }, { + token: "string.start", + regex: /\(/, + push: "rpstring" + }, { + token: "string.end", + regex: /\)/, + next: "pop" + }, { + token: "paren.start", + regex: /#{/, + push: "start" + }, { + defaultToken: "string" + }] + }, { + stateName: "spstring", + token: "string.start", + regex: /%[Qx]?\[/, + push: [{ + token: "constant.language.escape", + regex: extEscapeExspresssion + }, { + token: "string.start", + regex: /\[/, + push: "spstring" + }, { + token: "string.end", + regex: /]/, + next: "pop" + }, { + token: "paren.start", + regex: /#{/, + push: "start" + }, { + defaultToken: "string" + }] + }, { + stateName: "fpstring", + token: "string.start", + regex: /%[Qx]?{/, + push: [{ + token: "constant.language.escape", + regex: extEscapeExspresssion + }, { + token: "string.start", + regex: /{/, + push: "fpstring" + }, { + token: "string.end", + regex: /}/, + next: "pop" + }, { + token: "paren.start", + regex: /#{/, + push: "start" + }, { + defaultToken: "string" + }] + }, { + stateName: "tpstring", + token: "string.start", + regex: /%[Qx]?/, + next: "pop" + }, { + token: "paren.start", + regex: /#{/, + push: "start" + }, { + defaultToken: "string" + }] + }, { + stateName: "ppstring", + token: "string.start", + regex: /%[Qx]?\|/, + push: [{ + token: "constant.language.escape", + regex: extEscapeExspresssion + }, { + token: "string.end", + regex: /\|/, + next: "pop" + }, { + token: "paren.start", + regex: /#{/, + push: "start" + }, { + defaultToken: "string" + }] + }, { + stateName: "rpqstring", + token: "string.start", + regex: /%[qwir]\(/, + push: [{ + token: "string.start", + regex: /\(/, + push: "rpqstring" + }, { + token: "string.end", + regex: /\)/, + next: "pop" + }, { + defaultToken: "string" + }] + }, { + stateName: "spqstring", + token: "string.start", + regex: /%[qwir]\[/, + push: [{ + token: "string.start", + regex: /\[/, + push: "spqstring" + }, { + token: "string.end", + regex: /]/, + next: "pop" + }, { + defaultToken: "string" + }] + }, { + stateName: "fpqstring", + token: "string.start", + regex: /%[qwir]{/, + push: [{ + token: "string.start", + regex: /{/, + push: "fpqstring" + }, { + token: "string.end", + regex: /}/, + next: "pop" + }, { + defaultToken: "string" + }] + }, { + stateName: "tpqstring", + token: "string.start", + regex: /%[qwir]/, + next: "pop" + }, { + defaultToken: "string" + }] + }, { + stateName: "ppqstring", + token: "string.start", + regex: /%[qwir]\|/, + push: [{ + token: "string.end", + regex: /\|/, + next: "pop" + }, { + defaultToken: "string" + }] + }, { + token: "string.start", + regex: /'/, + push: [{ + token: "constant.language.escape", + regex: escapeExpression + }, { + token: "string.end", + regex: /'|$/, + next: "pop" + }, { + defaultToken: "string" + }] + }], { + token: "text", // namespaces aren't symbols + regex: "::" + }, { + token: "variable.instance", // instance variable + regex: "@{1,2}[a-zA-Z_\\d]+" + }, { + token: "variable.fresh", // fresh variable + regex: "%[a-zA-Z_\\d]+" + }, { + token: "support.class", // class name + regex: "[A-Z][a-zA-Z_\\d]+" + }, { + token: "constant.other.symbol", // symbol + regex: "[:](?:(?:===|<=>|\\[]\\?|\\[]=|\\[]|>>|\\*\\*|<<|==|!=|>=|<=|!~|=~|<|\\+|-|\\*|\\/|%|&|\\||\\^|>|!|~)|(?:(?:[A-Za-z_]|[@$](?=[a-zA-Z0-9_]))[a-zA-Z0-9_]*[!=?]?))" + }, { + token: "constant.numeric", // float + regex: "[+-]?\\d(?:\\d|_(?=\\d))*(?:(?:\\.\\d(?:\\d|_(?=\\d))*)?(?:[eE][+-]?\\d+)?)?(?:_?[fF](?:32|64))?\\b" + }, { + token: "constant.numeric", + regex: intNumber + }, { + token: "constant.other.symbol", + regex: ':"', + push: [{ + token: "constant.language.escape", + regex: extEscapeExspresssion + }, { + token: "constant.other.symbol", + regex: '"', + next: "pop" + }, { + defaultToken: "constant.other.symbol" + }] + }, { + token: "constant.language.boolean", + regex: "(?:true|false)\\b" + }, { + token: "support.function", + regex: "(?:is_a\\?|nil\\?|responds_to\\?|as\\?)" + }, { + token: keywordMapper, + regex: "[a-zA-Z_$][a-zA-Z0-9_$!?]*\\b" + }, { + token: "variable.system", + regex: "\\$\\!|\\$\\?" + }, { + token: "punctuation.separator.key-value", + regex: "=>" + }, { + stateName: "heredoc", + onMatch: function (value, currentState, stack) { + var next = "heredoc"; + var tokens = value.split(this.splitRegex); + stack.push(next, tokens[3]); + return [ + {type: "constant", value: tokens[1]}, + {type: "string", value: tokens[2]}, + {type: "support.class", value: tokens[3]}, + {type: "string", value: tokens[4]} + ]; + }, + regex: "(<<-)([']?)([\\w]+)([']?)", + rules: { + heredoc: [{ + token: "string", + regex: "^ +" + }, { + onMatch: function (value, currentState, stack) { + if (value === stack[1]) { + stack.shift(); + stack.shift(); + this.next = stack[0] || "start"; + return "support.class"; + } + this.next = ""; + return "string"; + }, + regex: ".*$", + next: "start" + }] + } + }, { + regex: "$", + token: "empty", + next: function (currentState, stack) { + if (stack[0] === "heredoc") + return stack[0]; + return currentState; + } + }, { + token: "punctuation.operator", + regex: /[.]\s*(?![.])/, + push: [{ + token : "punctuation.operator", + regex : /[.]\s*(?![.])/ + }, { + token : "support.function", + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + regex: "", + token: "empty", + next: "pop" + }] + }, { + token: "keyword.operator", + regex: "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|\\?|\\:|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\^|\\|" + }, { + token: "punctuation.operator", + regex: /[?:,;.]/ + }, { + token: "paren.lparen", + regex: "[[({]" + }, { + token: "paren.rparen", + regex: "[\\])}]" + }, { + token: "text", + regex: "\\s+" + } + ] + }; + + this.normalizeRules(); + }; + + oop.inherits(CrystalHighlightRules, TextHighlightRules); + + exports.CrystalHighlightRules = CrystalHighlightRules; +}); From a4a5af473e13fc28669ce00dceb01d084cbc4467 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 18 Mar 2019 23:56:38 +0400 Subject: [PATCH 0140/1293] add missing snippet files --- lib/ace/snippets/apex.js | 7 +++++++ lib/ace/snippets/apex.snippets | 0 lib/ace/snippets/bro.snippets | 0 lib/ace/snippets/crystal.js | 7 +++++++ lib/ace/snippets/crystal.snippets | 0 lib/ace/snippets/csp.snippets | 0 lib/ace/snippets/fortran.js | 7 +++++++ lib/ace/snippets/fortran.snippets | 0 lib/ace/snippets/haskell_cabal.js | 7 +++++++ lib/ace/snippets/haskell_cabal.snippets | 0 lib/ace/snippets/hjson.snippets | 0 lib/ace/snippets/kotlin.snippets | 0 lib/ace/snippets/logtalk.js | 7 +++++++ lib/ace/snippets/logtalk.snippets | 0 lib/ace/snippets/mask.js | 7 +++++++ lib/ace/snippets/mask.snippets | 0 lib/ace/snippets/mixal.js | 7 +++++++ lib/ace/snippets/mixal.snippets | 0 lib/ace/snippets/nginx.js | 7 +++++++ lib/ace/snippets/nginx.snippets | 0 lib/ace/snippets/nim.js | 7 +++++++ lib/ace/snippets/nim.snippets | 0 lib/ace/snippets/nsis.snippets | 0 lib/ace/snippets/perl6.js | 7 +++++++ lib/ace/snippets/perl6.snippets | 0 lib/ace/snippets/pig.js | 7 +++++++ lib/ace/snippets/pig.snippets | 0 lib/ace/snippets/redshift.js | 7 +++++++ lib/ace/snippets/redshift.snippets | 0 lib/ace/snippets/rst.js | 7 +++++++ lib/ace/snippets/sparql.snippets | 0 lib/ace/snippets/swift.js | 7 +++++++ lib/ace/snippets/swift.snippets | 0 lib/ace/snippets/tsx.js | 7 +++++++ lib/ace/snippets/tsx.snippets | 0 lib/ace/snippets/turtle.snippets | 0 lib/ace/snippets/visualforce.js | 7 +++++++ lib/ace/snippets/visualforce.snippets | 0 38 files changed, 112 insertions(+) create mode 100644 lib/ace/snippets/apex.js create mode 100644 lib/ace/snippets/apex.snippets create mode 100644 lib/ace/snippets/bro.snippets create mode 100644 lib/ace/snippets/crystal.js create mode 100644 lib/ace/snippets/crystal.snippets create mode 100644 lib/ace/snippets/csp.snippets create mode 100644 lib/ace/snippets/fortran.js create mode 100644 lib/ace/snippets/fortran.snippets create mode 100644 lib/ace/snippets/haskell_cabal.js create mode 100644 lib/ace/snippets/haskell_cabal.snippets create mode 100644 lib/ace/snippets/hjson.snippets create mode 100644 lib/ace/snippets/kotlin.snippets create mode 100644 lib/ace/snippets/logtalk.js create mode 100644 lib/ace/snippets/logtalk.snippets create mode 100644 lib/ace/snippets/mask.js create mode 100644 lib/ace/snippets/mask.snippets create mode 100644 lib/ace/snippets/mixal.js create mode 100644 lib/ace/snippets/mixal.snippets create mode 100644 lib/ace/snippets/nginx.js create mode 100644 lib/ace/snippets/nginx.snippets create mode 100644 lib/ace/snippets/nim.js create mode 100644 lib/ace/snippets/nim.snippets create mode 100644 lib/ace/snippets/nsis.snippets create mode 100644 lib/ace/snippets/perl6.js create mode 100644 lib/ace/snippets/perl6.snippets create mode 100644 lib/ace/snippets/pig.js create mode 100644 lib/ace/snippets/pig.snippets create mode 100644 lib/ace/snippets/redshift.js create mode 100644 lib/ace/snippets/redshift.snippets create mode 100644 lib/ace/snippets/rst.js create mode 100644 lib/ace/snippets/sparql.snippets create mode 100644 lib/ace/snippets/swift.js create mode 100644 lib/ace/snippets/swift.snippets create mode 100644 lib/ace/snippets/tsx.js create mode 100644 lib/ace/snippets/tsx.snippets create mode 100644 lib/ace/snippets/turtle.snippets create mode 100644 lib/ace/snippets/visualforce.js create mode 100644 lib/ace/snippets/visualforce.snippets diff --git a/lib/ace/snippets/apex.js b/lib/ace/snippets/apex.js new file mode 100644 index 00000000000..104722134c0 --- /dev/null +++ b/lib/ace/snippets/apex.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./apex.snippets"); +exports.scope = "apex"; + +}); diff --git a/lib/ace/snippets/apex.snippets b/lib/ace/snippets/apex.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/bro.snippets b/lib/ace/snippets/bro.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/crystal.js b/lib/ace/snippets/crystal.js new file mode 100644 index 00000000000..84b4a41a192 --- /dev/null +++ b/lib/ace/snippets/crystal.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./crystal.snippets"); +exports.scope = "crystal"; + +}); diff --git a/lib/ace/snippets/crystal.snippets b/lib/ace/snippets/crystal.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/csp.snippets b/lib/ace/snippets/csp.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/fortran.js b/lib/ace/snippets/fortran.js new file mode 100644 index 00000000000..65d8a0d98dd --- /dev/null +++ b/lib/ace/snippets/fortran.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./fortran.snippets"); +exports.scope = "fortran"; + +}); diff --git a/lib/ace/snippets/fortran.snippets b/lib/ace/snippets/fortran.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/haskell_cabal.js b/lib/ace/snippets/haskell_cabal.js new file mode 100644 index 00000000000..0dfda712cfe --- /dev/null +++ b/lib/ace/snippets/haskell_cabal.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./haskell_cabal.snippets"); +exports.scope = "haskell_cabal"; + +}); diff --git a/lib/ace/snippets/haskell_cabal.snippets b/lib/ace/snippets/haskell_cabal.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/hjson.snippets b/lib/ace/snippets/hjson.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/kotlin.snippets b/lib/ace/snippets/kotlin.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/logtalk.js b/lib/ace/snippets/logtalk.js new file mode 100644 index 00000000000..707176896b1 --- /dev/null +++ b/lib/ace/snippets/logtalk.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./logtalk.snippets"); +exports.scope = "logtalk"; + +}); diff --git a/lib/ace/snippets/logtalk.snippets b/lib/ace/snippets/logtalk.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/mask.js b/lib/ace/snippets/mask.js new file mode 100644 index 00000000000..7fbca678066 --- /dev/null +++ b/lib/ace/snippets/mask.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./mask.snippets"); +exports.scope = "mask"; + +}); diff --git a/lib/ace/snippets/mask.snippets b/lib/ace/snippets/mask.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/mixal.js b/lib/ace/snippets/mixal.js new file mode 100644 index 00000000000..0acfae2f338 --- /dev/null +++ b/lib/ace/snippets/mixal.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./mixal.snippets"); +exports.scope = "mixal"; + +}); diff --git a/lib/ace/snippets/mixal.snippets b/lib/ace/snippets/mixal.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/nginx.js b/lib/ace/snippets/nginx.js new file mode 100644 index 00000000000..068115831a4 --- /dev/null +++ b/lib/ace/snippets/nginx.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./nginx.snippets"); +exports.scope = "nginx"; + +}); diff --git a/lib/ace/snippets/nginx.snippets b/lib/ace/snippets/nginx.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/nim.js b/lib/ace/snippets/nim.js new file mode 100644 index 00000000000..6e6d02bbe48 --- /dev/null +++ b/lib/ace/snippets/nim.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./nim.snippets"); +exports.scope = "nim"; + +}); diff --git a/lib/ace/snippets/nim.snippets b/lib/ace/snippets/nim.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/nsis.snippets b/lib/ace/snippets/nsis.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/perl6.js b/lib/ace/snippets/perl6.js new file mode 100644 index 00000000000..af05b2520bb --- /dev/null +++ b/lib/ace/snippets/perl6.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./perl6.snippets"); +exports.scope = "perl6"; + +}); diff --git a/lib/ace/snippets/perl6.snippets b/lib/ace/snippets/perl6.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/pig.js b/lib/ace/snippets/pig.js new file mode 100644 index 00000000000..07d0d777e7b --- /dev/null +++ b/lib/ace/snippets/pig.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./pig.snippets"); +exports.scope = "pig"; + +}); diff --git a/lib/ace/snippets/pig.snippets b/lib/ace/snippets/pig.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/redshift.js b/lib/ace/snippets/redshift.js new file mode 100644 index 00000000000..1564301a4cd --- /dev/null +++ b/lib/ace/snippets/redshift.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./redshift.snippets"); +exports.scope = "redshift"; + +}); diff --git a/lib/ace/snippets/redshift.snippets b/lib/ace/snippets/redshift.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/rst.js b/lib/ace/snippets/rst.js new file mode 100644 index 00000000000..3e4a67eacb1 --- /dev/null +++ b/lib/ace/snippets/rst.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./rst.snippets"); +exports.scope = "rst"; + +}); diff --git a/lib/ace/snippets/sparql.snippets b/lib/ace/snippets/sparql.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/swift.js b/lib/ace/snippets/swift.js new file mode 100644 index 00000000000..46e5e1106b4 --- /dev/null +++ b/lib/ace/snippets/swift.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./swift.snippets"); +exports.scope = "swift"; + +}); diff --git a/lib/ace/snippets/swift.snippets b/lib/ace/snippets/swift.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/tsx.js b/lib/ace/snippets/tsx.js new file mode 100644 index 00000000000..457e33b24e6 --- /dev/null +++ b/lib/ace/snippets/tsx.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./tsx.snippets"); +exports.scope = "tsx"; + +}); diff --git a/lib/ace/snippets/tsx.snippets b/lib/ace/snippets/tsx.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/turtle.snippets b/lib/ace/snippets/turtle.snippets new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ace/snippets/visualforce.js b/lib/ace/snippets/visualforce.js new file mode 100644 index 00000000000..2d01c0f5d72 --- /dev/null +++ b/lib/ace/snippets/visualforce.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./visualforce.snippets"); +exports.scope = "visualforce"; + +}); diff --git a/lib/ace/snippets/visualforce.snippets b/lib/ace/snippets/visualforce.snippets new file mode 100644 index 00000000000..e69de29bb2d From 9ec1ecc86e2fe411cfbd207d8928612560af39e3 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 19 Mar 2019 23:55:39 +0400 Subject: [PATCH 0141/1293] use keywordMapper in pascal mode --- lib/ace/mode/_test/tokens_pascal.json | 156 +++++++++++------------ lib/ace/mode/pascal_highlight_rules.js | 166 +++++++++++++------------ 2 files changed, 163 insertions(+), 159 deletions(-) diff --git a/lib/ace/mode/_test/tokens_pascal.json b/lib/ace/mode/_test/tokens_pascal.json index 22c1f0c43e5..50fd5264840 100644 --- a/lib/ace/mode/_test/tokens_pascal.json +++ b/lib/ace/mode/_test/tokens_pascal.json @@ -1,20 +1,20 @@ [[ - "punctuation.definition.comment.pascal", - ["punctuation.definition.comment.pascal","(*"], - ["comment.block.pascal.one","****************************************************************************"] + "punctuation.definition.comment", + ["punctuation.definition.comment","(*"], + ["comment.block.one","****************************************************************************"] ],[ - "punctuation.definition.comment.pascal", - ["comment.block.pascal.one"," * A simple bubble sort program. Reads integers, one per line, and prints *"] + "punctuation.definition.comment", + ["comment.block.one"," * A simple bubble sort program. Reads integers, one per line, and prints *"] ],[ - "punctuation.definition.comment.pascal", - ["comment.block.pascal.one"," * them out in sorted order. Blows up if there are more than 49. *"] + "punctuation.definition.comment", + ["comment.block.one"," * them out in sorted order. Blows up if there are more than 49. *"] ],[ "start", - ["comment.block.pascal.one"," ****************************************************************************"], - ["punctuation.definition.comment.pascal","*)"] + ["comment.block.one"," ****************************************************************************"], + ["punctuation.definition.comment","*)"] ],[ "start", - ["keyword.control.pascal","PROGRAM"], + ["keyword.control","PROGRAM"], ["text"," Sort(input"], ["keyword.operator",","], ["text"," output)"], @@ -22,41 +22,41 @@ ],[ "start", ["text"," "], - ["keyword.control.pascal","CONST"] + ["keyword.control","CONST"] ],[ "start", ["text"," "], - ["punctuation.definition.comment.pascal","(*"], - ["comment.block.pascal.one"," Max array size. "], - ["punctuation.definition.comment.pascal","*)"] + ["punctuation.definition.comment","(*"], + ["comment.block.one"," Max array size. "], + ["punctuation.definition.comment","*)"] ],[ "start", ["text"," MaxElts "], ["keyword.operator","="], ["text"," "], - ["constant.numeric.pascal","50"], + ["constant.numeric","50"], ["keyword.operator",";"] ],[ "start", ["text"," "], - ["keyword.control.pascal","TYPE"], + ["keyword.control","TYPE"], ["text"," "] ],[ "start", ["text"," "], - ["punctuation.definition.comment.pascal","(*"], - ["comment.block.pascal.one"," Type of the element array. "], - ["punctuation.definition.comment.pascal","*)"] + ["punctuation.definition.comment","(*"], + ["comment.block.one"," Type of the element array. "], + ["punctuation.definition.comment","*)"] ],[ "start", ["text"," IntArrType "], ["keyword.operator","="], ["text"," "], - ["keyword.control.pascal","ARRAY"], + ["keyword.control","ARRAY"], ["text"," ["], - ["constant.numeric.pascal","1"], + ["constant.numeric","1"], ["text","..MaxElts] "], - ["keyword.control.pascal","OF"], + ["keyword.control","OF"], ["text"," Integer"], ["keyword.operator",";"] ],[ @@ -64,13 +64,13 @@ ],[ "start", ["text"," "], - ["keyword.control.pascal","VAR"] + ["keyword.control","VAR"] ],[ "start", ["text"," "], - ["punctuation.definition.comment.pascal","(*"], - ["comment.block.pascal.one"," Indexes, exchange temp, array size. "], - ["punctuation.definition.comment.pascal","*)"] + ["punctuation.definition.comment","(*"], + ["comment.block.one"," Indexes, exchange temp, array size. "], + ["punctuation.definition.comment","*)"] ],[ "start", ["text"," i"], @@ -86,9 +86,9 @@ ],[ "start", ["text"," "], - ["punctuation.definition.comment.pascal","(*"], - ["comment.block.pascal.one"," Array of ints "], - ["punctuation.definition.comment.pascal","*)"] + ["punctuation.definition.comment","(*"], + ["comment.block.one"," Array of ints "], + ["punctuation.definition.comment","*)"] ],[ "start", ["text"," arr: IntArrType"], @@ -98,45 +98,45 @@ ],[ "start", ["text"," "], - ["punctuation.definition.comment.pascal","(*"], - ["comment.block.pascal.one"," Read in the integers. "], - ["punctuation.definition.comment.pascal","*)"] + ["punctuation.definition.comment","(*"], + ["comment.block.one"," Read in the integers. "], + ["punctuation.definition.comment","*)"] ],[ "start", ["text"," "], - ["variable.pascal","PROCEDURE"], + ["variable","PROCEDURE"], ["text"," "], - ["storage.type.function.pascal","ReadArr"], + ["storage.type.function","ReadArr"], ["text","("], - ["keyword.control.pascal","VAR"], + ["keyword.control","VAR"], ["text"," size: Integer"], ["keyword.operator",";"], ["text"," "], - ["keyword.control.pascal","VAR"], + ["keyword.control","VAR"], ["text"," a: IntArrType)"], ["keyword.operator",";"], ["text"," "] ],[ "start", ["text"," "], - ["keyword.control.pascal","BEGIN"] + ["keyword.control","BEGIN"] ],[ "start", ["text"," size "], ["keyword.operator",":="], ["text"," "], - ["constant.numeric.pascal","1"], + ["constant.numeric","1"], ["keyword.operator",";"] ],[ "start", ["text"," "], - ["keyword.control.pascal","WHILE"], + ["keyword.control","WHILE"], ["text"," "], - ["keyword.control.pascal","NOT"], + ["keyword.control","NOT"], ["text"," eof "], - ["keyword.control.pascal","DO"], + ["keyword.control","DO"], ["text"," "], - ["keyword.control.pascal","BEGIN"] + ["keyword.control","BEGIN"] ],[ "start", ["text"," readln(a[size])"], @@ -144,11 +144,11 @@ ],[ "start", ["text"," "], - ["keyword.control.pascal","IF"], + ["keyword.control","IF"], ["text"," "], - ["keyword.control.pascal","NOT"], + ["keyword.control","NOT"], ["text"," eof "], - ["keyword.control.pascal","THEN"], + ["keyword.control","THEN"], ["text"," "] ],[ "start", @@ -157,28 +157,28 @@ ["text"," size "], ["keyword.operator","+"], ["text"," "], - ["constant.numeric.pascal","1"] + ["constant.numeric","1"] ],[ "start", ["text"," "], - ["keyword.control.pascal","END"] + ["keyword.control","END"] ],[ "start", ["text"," "], - ["keyword.control.pascal","END"], + ["keyword.control","END"], ["keyword.operator",";"] ],[ "start" ],[ "start", ["text"," "], - ["keyword.control.pascal","BEGIN"] + ["keyword.control","BEGIN"] ],[ "start", ["text"," "], - ["punctuation.definition.comment.pascal","(*"], - ["comment.block.pascal.one"," Read "], - ["punctuation.definition.comment.pascal","*)"] + ["punctuation.definition.comment","(*"], + ["comment.block.one"," Read "], + ["punctuation.definition.comment","*)"] ],[ "start", ["text"," ReadArr(size"], @@ -190,48 +190,48 @@ ],[ "start", ["text"," "], - ["punctuation.definition.comment.pascal","(*"], - ["comment.block.pascal.one"," Sort using bubble sort. "], - ["punctuation.definition.comment.pascal","*)"] + ["punctuation.definition.comment","(*"], + ["comment.block.one"," Sort using bubble sort. "], + ["punctuation.definition.comment","*)"] ],[ "start", ["text"," "], - ["keyword.control.pascal","FOR"], + ["keyword.control","FOR"], ["text"," i "], ["keyword.operator",":="], ["text"," size "], ["keyword.operator","-"], ["text"," "], - ["constant.numeric.pascal","1"], + ["constant.numeric","1"], ["text"," DOWNTO "], - ["constant.numeric.pascal","1"], + ["constant.numeric","1"], ["text"," "], - ["keyword.control.pascal","DO"] + ["keyword.control","DO"] ],[ "start", ["text"," "], - ["keyword.control.pascal","FOR"], + ["keyword.control","FOR"], ["text"," j "], ["keyword.operator",":="], ["text"," "], - ["constant.numeric.pascal","1"], + ["constant.numeric","1"], ["text"," "], - ["keyword.control.pascal","TO"], + ["keyword.control","TO"], ["text"," i "], - ["keyword.control.pascal","DO"], + ["keyword.control","DO"], ["text"," "] ],[ "start", ["text"," "], - ["keyword.control.pascal","IF"], + ["keyword.control","IF"], ["text"," arr[j] > arr[j "], ["keyword.operator","+"], ["text"," "], - ["constant.numeric.pascal","1"], + ["constant.numeric","1"], ["text","] "], - ["keyword.control.pascal","THEN"], + ["keyword.control","THEN"], ["text"," "], - ["keyword.control.pascal","BEGIN"] + ["keyword.control","BEGIN"] ],[ "start", ["text"," tmp "], @@ -245,7 +245,7 @@ ["text"," arr[j "], ["keyword.operator","+"], ["text"," "], - ["constant.numeric.pascal","1"], + ["constant.numeric","1"], ["text","]"], ["keyword.operator",";"] ],[ @@ -253,7 +253,7 @@ ["text"," arr[j "], ["keyword.operator","+"], ["text"," "], - ["constant.numeric.pascal","1"], + ["constant.numeric","1"], ["text","] "], ["keyword.operator",":="], ["text"," tmp"], @@ -261,35 +261,35 @@ ],[ "start", ["text"," "], - ["keyword.control.pascal","END"], + ["keyword.control","END"], ["keyword.operator",";"] ],[ "start" ],[ "start", ["text"," "], - ["punctuation.definition.comment.pascal","(*"], - ["comment.block.pascal.one"," Print. "], - ["punctuation.definition.comment.pascal","*)"] + ["punctuation.definition.comment","(*"], + ["comment.block.one"," Print. "], + ["punctuation.definition.comment","*)"] ],[ "start", ["text"," "], - ["keyword.control.pascal","FOR"], + ["keyword.control","FOR"], ["text"," i "], ["keyword.operator",":="], ["text"," "], - ["constant.numeric.pascal","1"], + ["constant.numeric","1"], ["text"," "], - ["keyword.control.pascal","TO"], + ["keyword.control","TO"], ["text"," size "], - ["keyword.control.pascal","DO"] + ["keyword.control","DO"] ],[ "start", ["text"," writeln(arr[i])"] ],[ "start", ["text"," "], - ["keyword.control.pascal","END"], + ["keyword.control","END"], ["text","."] ],[ "start", diff --git a/lib/ace/mode/pascal_highlight_rules.js b/lib/ace/mode/pascal_highlight_rules.js index a617da7709f..6befbd8e991 100644 --- a/lib/ace/mode/pascal_highlight_rules.js +++ b/lib/ace/mode/pascal_highlight_rules.js @@ -28,18 +28,6 @@ * * ***** END LICENSE BLOCK ***** */ -/* THIS FILE WAS AUTOGENERATED FROM tool\tm bundles\pascal.tmbundle\Syntaxes\Pascal.plist (UUID: F42FA544-6B1C-11D9-9517-000D93589AF6) */ -/**************************************************************** - * IT MIGHT NOT BE PERFECT, PARTICULARLY: * - * IN DECIDING STATES TO TRANSITION TO, * - * IGNORING WHITESPACE, * - * IGNORING GROUPS WITH ?:, * - * EXTENDING EXISTING MODES, * - * GATHERING KEYWORDS, OR * - * DECIDING WHEN TO USE PUSH. * - * ...But it's a good start from an existing *.tmlanguage file. * - ****************************************************************/ - define(function(require, exports, module) { "use strict"; @@ -47,81 +35,97 @@ var oop = require("../lib/oop"); var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var PascalHighlightRules = function() { - // regexp must not have capturing parentheses. Use (?:) instead. - // regexps are ordered -> the first match is used + var keywordMapper = this.createKeywordMapper({ + "keyword.control": "absolute|abstract|all|and|and_then|array|as|asm|attribute|begin|bindable|case|class" + + "|const|constructor|destructor|div|do|do|else|end|except|export|exports|external|far|file|finalization" + + "|finally|for|forward|goto|if|implementation|import|in|inherited|initialization|interface|interrupt|is" + + "|label|library|mod|module|name|near|nil|not|object|of|only|operator|or|or_else|otherwise|packed|pow|private" + + "|program|property|protected|public|published|qualified|record|repeat|resident|restricted|segment|set|shl|shr" + + "|then|to|try|type|unit|until|uses|value|var|view|virtual|while|with|xor" + }, "identifier", true); - this.$rules = { start: - [ { caseInsensitive: true, - token: 'keyword.control.pascal', - regex: '\\b(?:(absolute|abstract|all|and|and_then|array|as|asm|attribute|begin|bindable|case|class|const|constructor|destructor|div|do|do|else|end|except|export|exports|external|far|file|finalization|finally|for|forward|goto|if|implementation|import|in|inherited|initialization|interface|interrupt|is|label|library|mod|module|name|near|nil|not|object|of|only|operator|or|or_else|otherwise|packed|pow|private|program|property|protected|public|published|qualified|record|repeat|resident|restricted|segment|set|shl|shr|then|to|try|type|unit|until|uses|value|var|view|virtual|while|with|xor))\\b' }, - { caseInsensitive: true, - token: - [ 'variable.pascal', "text", - 'storage.type.prototype.pascal', - 'entity.name.function.prototype.pascal' ], - regex: '\\b(function|procedure)(\\s+)(\\w+)(\\.\\w+)?(?=(?:\\(.*?\\))?;\\s*(?:attribute|forward|external))' }, - { caseInsensitive: true, - token: - [ 'variable.pascal', "text", - 'storage.type.function.pascal', - 'entity.name.function.pascal' ], - regex: '\\b(function|procedure)(\\s+)(\\w+)(\\.\\w+)?' }, - { token: 'constant.numeric.pascal', - regex: '\\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\\.?[0-9]*)|(\\.[0-9]+))((e|E)(\\+|-)?[0-9]+)?)(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b' }, - { token: 'punctuation.definition.comment.pascal', - regex: '--.*$', - push_: - [ { token: 'comment.line.double-dash.pascal.one', - regex: '$', - next: 'pop' }, - { defaultToken: 'comment.line.double-dash.pascal.one' } ] }, - { token: 'punctuation.definition.comment.pascal', - regex: '//.*$', - push_: - [ { token: 'comment.line.double-slash.pascal.two', - regex: '$', - next: 'pop' }, - { defaultToken: 'comment.line.double-slash.pascal.two' } ] }, - { token: 'punctuation.definition.comment.pascal', - regex: '\\(\\*', - push: - [ { token: 'punctuation.definition.comment.pascal', - regex: '\\*\\)', - next: 'pop' }, - { defaultToken: 'comment.block.pascal.one' } ] }, - { token: 'punctuation.definition.comment.pascal', - regex: '\\{', - push: - [ { token: 'punctuation.definition.comment.pascal', - regex: '\\}', - next: 'pop' }, - { defaultToken: 'comment.block.pascal.two' } ] }, - { token: 'punctuation.definition.string.begin.pascal', - regex: '"', - push: - [ { token: 'constant.character.escape.pascal', regex: '\\\\.' }, - { token: 'punctuation.definition.string.end.pascal', + this.$rules = { + start: [{ + caseInsensitive: true, + token: ['variable', "text", + 'storage.type.prototype', + 'entity.name.function.prototype' + ], + regex: '\\b(function|procedure)(\\s+)(\\w+)(\\.\\w+)?(?=(?:\\(.*?\\))?;\\s*(?:attribute|forward|external))' + }, { + caseInsensitive: true, + token: ['variable', "text", 'storage.type.function', 'entity.name.function'], + regex: '\\b(function|procedure)(\\s+)(\\w+)(\\.\\w+)?' + }, { + caseInsensitive: true, + token: keywordMapper, + regex: /\b[a-z_]+\b/ + }, { + token: 'constant.numeric', + regex: '\\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\\.?[0-9]*)|(\\.[0-9]+))((e|E)(\\+|-)?[0-9]+)?)(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b' + }, { + token: 'punctuation.definition.comment', + regex: '--.*$' + }, { + token: 'punctuation.definition.comment', + regex: '//.*$' + }, { + token: 'punctuation.definition.comment', + regex: '\\(\\*', + push: [{ + token: 'punctuation.definition.comment', + regex: '\\*\\)', + next: 'pop' + }, + { defaultToken: 'comment.block.one' } + ] + }, { + token: 'punctuation.definition.comment', + regex: '\\{', + push: [{ + token: 'punctuation.definition.comment', + regex: '\\}', + next: 'pop' + }, + { defaultToken: 'comment.block.two' } + ] + }, { + token: 'punctuation.definition.string.begin', regex: '"', - next: 'pop' }, - { defaultToken: 'string.quoted.double.pascal' } ] - //Double quoted strings are an extension and (generally) support C-style escape sequences. - }, - { token: 'punctuation.definition.string.begin.pascal', - regex: '\'', - push: - [ { token: 'constant.character.escape.apostrophe.pascal', - regex: '\'\'' }, - { token: 'punctuation.definition.string.end.pascal', + push: [{ token: 'constant.character.escape', regex: '\\\\.' }, + { + token: 'punctuation.definition.string.end', + regex: '"', + next: 'pop' + }, + { defaultToken: 'string.quoted.double' } + ] + //Double quoted strings are an extension and (generally) support C-style escape sequences. + }, { + token: 'punctuation.definition.string.begin', regex: '\'', - next: 'pop' }, - { defaultToken: 'string.quoted.single.pascal' } ] }, - { token: 'keyword.operator', - regex: '[+\\-;,/*%]|:=|=' } ] }; - + push: [{ + token: 'constant.character.escape.apostrophe', + regex: '\'\'' + }, + { + token: 'punctuation.definition.string.end', + regex: '\'', + next: 'pop' + }, + { defaultToken: 'string.quoted.single' } + ] + }, { + token: 'keyword.operator', + regex: '[+\\-;,/*%]|:=|=' + } + ] + }; + this.normalizeRules(); }; oop.inherits(PascalHighlightRules, TextHighlightRules); exports.PascalHighlightRules = PascalHighlightRules; -}); \ No newline at end of file +}); From 2ebb93c77ff3c8e1ad0ec3ec3ba5bbff0dbfdf7b Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 19 Mar 2019 23:56:55 +0400 Subject: [PATCH 0142/1293] update pascal test --- lib/ace/mode/_test/tokens_pascal.json | 168 ++++++++++++++++++++------ 1 file changed, 132 insertions(+), 36 deletions(-) diff --git a/lib/ace/mode/_test/tokens_pascal.json b/lib/ace/mode/_test/tokens_pascal.json index 50fd5264840..4e41e2ab62f 100644 --- a/lib/ace/mode/_test/tokens_pascal.json +++ b/lib/ace/mode/_test/tokens_pascal.json @@ -15,9 +15,14 @@ ],[ "start", ["keyword.control","PROGRAM"], - ["text"," Sort(input"], + ["text"," "], + ["identifier","Sort"], + ["text","("], + ["identifier","input"], ["keyword.operator",","], - ["text"," output)"], + ["text"," "], + ["identifier","output"], + ["text",")"], ["keyword.operator",";"] ],[ "start", @@ -31,7 +36,9 @@ ["punctuation.definition.comment","*)"] ],[ "start", - ["text"," MaxElts "], + ["text"," "], + ["identifier","MaxElts"], + ["text"," "], ["keyword.operator","="], ["text"," "], ["constant.numeric","50"], @@ -49,15 +56,20 @@ ["punctuation.definition.comment","*)"] ],[ "start", - ["text"," IntArrType "], + ["text"," "], + ["identifier","IntArrType"], + ["text"," "], ["keyword.operator","="], ["text"," "], ["keyword.control","ARRAY"], ["text"," ["], ["constant.numeric","1"], - ["text","..MaxElts] "], + ["text",".."], + ["identifier","MaxElts"], + ["text","] "], ["keyword.control","OF"], - ["text"," Integer"], + ["text"," "], + ["identifier","Integer"], ["keyword.operator",";"] ],[ "start" @@ -73,13 +85,19 @@ ["punctuation.definition.comment","*)"] ],[ "start", - ["text"," i"], + ["text"," "], + ["identifier","i"], ["keyword.operator",","], - ["text"," j"], + ["text"," "], + ["identifier","j"], ["keyword.operator",","], - ["text"," tmp"], + ["text"," "], + ["identifier","tmp"], ["keyword.operator",","], - ["text"," size: integer"], + ["text"," "], + ["identifier","size"], + ["text",": "], + ["identifier","integer"], ["keyword.operator",";"] ],[ "start" @@ -91,7 +109,10 @@ ["punctuation.definition.comment","*)"] ],[ "start", - ["text"," arr: IntArrType"], + ["text"," "], + ["identifier","arr"], + ["text",": "], + ["identifier","IntArrType"], ["keyword.operator",";"] ],[ "start" @@ -109,11 +130,18 @@ ["storage.type.function","ReadArr"], ["text","("], ["keyword.control","VAR"], - ["text"," size: Integer"], + ["text"," "], + ["identifier","size"], + ["text",": "], + ["identifier","Integer"], ["keyword.operator",";"], ["text"," "], ["keyword.control","VAR"], - ["text"," a: IntArrType)"], + ["text"," "], + ["identifier","a"], + ["text",": "], + ["identifier","IntArrType"], + ["text",")"], ["keyword.operator",";"], ["text"," "] ],[ @@ -122,7 +150,9 @@ ["keyword.control","BEGIN"] ],[ "start", - ["text"," size "], + ["text"," "], + ["identifier","size"], + ["text"," "], ["keyword.operator",":="], ["text"," "], ["constant.numeric","1"], @@ -133,13 +163,21 @@ ["keyword.control","WHILE"], ["text"," "], ["keyword.control","NOT"], - ["text"," eof "], + ["text"," "], + ["identifier","eof"], + ["text"," "], ["keyword.control","DO"], ["text"," "], ["keyword.control","BEGIN"] ],[ "start", - ["text"," readln(a[size])"], + ["text"," "], + ["identifier","readln"], + ["text","("], + ["identifier","a"], + ["text","["], + ["identifier","size"], + ["text","])"], ["keyword.operator",";"] ],[ "start", @@ -147,14 +185,20 @@ ["keyword.control","IF"], ["text"," "], ["keyword.control","NOT"], - ["text"," eof "], + ["text"," "], + ["identifier","eof"], + ["text"," "], ["keyword.control","THEN"], ["text"," "] ],[ "start", - ["text"," size "], + ["text"," "], + ["identifier","size"], + ["text"," "], ["keyword.operator",":="], - ["text"," size "], + ["text"," "], + ["identifier","size"], + ["text"," "], ["keyword.operator","+"], ["text"," "], ["constant.numeric","1"] @@ -181,9 +225,14 @@ ["punctuation.definition.comment","*)"] ],[ "start", - ["text"," ReadArr(size"], + ["text"," "], + ["identifier","ReadArr"], + ["text","("], + ["identifier","size"], ["keyword.operator",","], - ["text"," arr)"], + ["text"," "], + ["identifier","arr"], + ["text",")"], ["keyword.operator",";"] ],[ "start" @@ -197,13 +246,19 @@ "start", ["text"," "], ["keyword.control","FOR"], - ["text"," i "], + ["text"," "], + ["identifier","i"], + ["text"," "], ["keyword.operator",":="], - ["text"," size "], + ["text"," "], + ["identifier","size"], + ["text"," "], ["keyword.operator","-"], ["text"," "], ["constant.numeric","1"], - ["text"," DOWNTO "], + ["text"," "], + ["identifier","DOWNTO"], + ["text"," "], ["constant.numeric","1"], ["text"," "], ["keyword.control","DO"] @@ -211,20 +266,32 @@ "start", ["text"," "], ["keyword.control","FOR"], - ["text"," j "], + ["text"," "], + ["identifier","j"], + ["text"," "], ["keyword.operator",":="], ["text"," "], ["constant.numeric","1"], ["text"," "], ["keyword.control","TO"], - ["text"," i "], + ["text"," "], + ["identifier","i"], + ["text"," "], ["keyword.control","DO"], ["text"," "] ],[ "start", ["text"," "], ["keyword.control","IF"], - ["text"," arr[j] > arr[j "], + ["text"," "], + ["identifier","arr"], + ["text","["], + ["identifier","j"], + ["text","] > "], + ["identifier","arr"], + ["text","["], + ["identifier","j"], + ["text"," "], ["keyword.operator","+"], ["text"," "], ["constant.numeric","1"], @@ -234,15 +301,29 @@ ["keyword.control","BEGIN"] ],[ "start", - ["text"," tmp "], + ["text"," "], + ["identifier","tmp"], + ["text"," "], ["keyword.operator",":="], - ["text"," arr[j]"], + ["text"," "], + ["identifier","arr"], + ["text","["], + ["identifier","j"], + ["text","]"], ["keyword.operator",";"] ],[ "start", - ["text"," arr[j] "], + ["text"," "], + ["identifier","arr"], + ["text","["], + ["identifier","j"], + ["text","] "], ["keyword.operator",":="], - ["text"," arr[j "], + ["text"," "], + ["identifier","arr"], + ["text","["], + ["identifier","j"], + ["text"," "], ["keyword.operator","+"], ["text"," "], ["constant.numeric","1"], @@ -250,13 +331,18 @@ ["keyword.operator",";"] ],[ "start", - ["text"," arr[j "], + ["text"," "], + ["identifier","arr"], + ["text","["], + ["identifier","j"], + ["text"," "], ["keyword.operator","+"], ["text"," "], ["constant.numeric","1"], ["text","] "], ["keyword.operator",":="], - ["text"," tmp"], + ["text"," "], + ["identifier","tmp"], ["keyword.operator",";"] ],[ "start", @@ -275,17 +361,27 @@ "start", ["text"," "], ["keyword.control","FOR"], - ["text"," i "], + ["text"," "], + ["identifier","i"], + ["text"," "], ["keyword.operator",":="], ["text"," "], ["constant.numeric","1"], ["text"," "], ["keyword.control","TO"], - ["text"," size "], + ["text"," "], + ["identifier","size"], + ["text"," "], ["keyword.control","DO"] ],[ "start", - ["text"," writeln(arr[i])"] + ["text"," "], + ["identifier","writeln"], + ["text","("], + ["identifier","arr"], + ["text","["], + ["identifier","i"], + ["text","])"] ],[ "start", ["text"," "], From 65c0953f692c9a4d0cd82735c21c59bc73b08957 Mon Sep 17 00:00:00 2001 From: Olivier BONNAURE Date: Thu, 21 Mar 2019 23:34:02 +0100 Subject: [PATCH 0143/1293] AQL syntax --- demo/kitchen-sink/docs/aql.aql | 3 + lib/ace/ext/modelist.js | 1 + lib/ace/mode/aql.js | 53 +++++++++++++++ lib/ace/mode/aql_highlight_rules.js | 102 ++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 demo/kitchen-sink/docs/aql.aql create mode 100644 lib/ace/mode/aql.js create mode 100644 lib/ace/mode/aql_highlight_rules.js diff --git a/demo/kitchen-sink/docs/aql.aql b/demo/kitchen-sink/docs/aql.aql new file mode 100644 index 00000000000..a5baf333a1a --- /dev/null +++ b/demo/kitchen-sink/docs/aql.aql @@ -0,0 +1,3 @@ +FOR user IN users + FILTER user.username == "olivier" + RETURN user \ No newline at end of file diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index f4ea2fde9a4..3e6f90bd41f 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -53,6 +53,7 @@ var supportedModes = { Assembly_x86:["asm|a"], AutoHotKey: ["ahk"], Apex: ["apex|cls|trigger|tgr"], + AQL: ["aql"], BatchFile: ["bat|cmd"], Bro: ["bro"], C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp|ino"], diff --git a/lib/ace/mode/aql.js b/lib/ace/mode/aql.js new file mode 100644 index 00000000000..0a3e96fa128 --- /dev/null +++ b/lib/ace/mode/aql.js @@ -0,0 +1,53 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextMode = require("./text").Mode; + var AqlHighlightRules = require("./aql_highlight_rules").AqlHighlightRules; + + var Mode = function() { + this.HighlightRules = AqlHighlightRules; + this.$behaviour = this.$defaultBehaviour; + }; + oop.inherits(Mode, TextMode); + + (function() { + + this.lineCommentStart = "//"; + + this.$id = "ace/mode/aql"; + }).call(Mode.prototype); + + exports.Mode = Mode; + + }); diff --git a/lib/ace/mode/aql_highlight_rules.js b/lib/ace/mode/aql_highlight_rules.js new file mode 100644 index 00000000000..085d03cb6d7 --- /dev/null +++ b/lib/ace/mode/aql_highlight_rules.js @@ -0,0 +1,102 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + + var AqlHighlightRules = function() { + + var keywords = ( + "for|search|outbound|inbound|any|graph|prune|options|shortest_path|to|in|return|filter|sort|limit|let|collect|remove|update|replace|insers|upsert|with" + ); + + var builtinConstants = ( + "true|false" + ); + + var builtinFunctions = ( + "append|contains_array|count|count_distinct|count_unique|first|flatten|intersection|last|length|minus|nth|outersection|pop|position|push|remove_nth|remove_value|remove_values|reverse|shift|slice|sorted|sorted_unique|union|union_distinct|unique|unshift|" + + "date_now|date_iso8601|date_timestamp|is_datestring|date_dayofweek|date_year|date_month|date_day|date_hour|date_minute|date_second|date_millisecond|date_dayofyear|date_isoweek|date_leapyear|date_quarter|date_days_in_month|date_trunc|date_format|date_add|date_subtract|date_diff|date_compare|" + + "attributes|count|has|is_same_collection|keep|length|matches|merge|merge_recursive|parse_identifier|translate|unset|unset_recursive|values|zip|" + + "fulltext|" + + "distance|geo_contains|geo_distance|geo_equals|geo_intersects|is_in_polygon|" + + "not_null|first_list|first_document|check_document|collection_count|collections|count|current_user|document|length|hash|apply|assert|/ warn|call|fail|noopt|passthru|sleep|v8|version|" + + "abs|acos|asin|atan|atan2|average|avg|ceil|cos|degrees|exp|exp2|floor|log|log2|log10|max|median|min|percentile|pi|pow|radians|rand|range|round|sin|sqrt|stddev_population|stddev_sample|stddev|sum|tan|variance_population|variance_sample|variance|" + + "char_length|concat|concat_separator|contains|count|encode_uri_component|find_first|find_last|json_parse|json_stringify|left|length|levenshtein_distance|like|lower|ltrim|md5|random_token|regex_matches|regex_split|regex_test|regex_replace|reverse|right|rtrim|sha1|sha512|split|soundex|substitute|substring|tokens|to_base64|to_hex|trim|upper|uuid|" + + "to_bool|to_number|to_string|to_array|to_list|is_null|is_bool|is_number|is_string|is_array|is_list|is_object|is_document|is_datestring|is_key|typename|" + ); + + var keywordMapper = this.createKeywordMapper({ + "support.function": builtinFunctions, + "keyword": keywords, + "constant.language": builtinConstants + }, "identifier", true); + + this.$rules = { + "start" : [ { + token : "comment", + regex : "//.*$" + }, { + token : "string", // " string + regex : '".*?"' + }, { + token : "string", // ' string + regex : "'.*?'" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, { + token : keywordMapper, + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token : "keyword.operator", + regex : "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=" + }, { + token : "paren.lparen", + regex : "[\\(]" + }, { + token : "paren.rparen", + regex : "[\\)]" + }, { + token : "text", + regex : "\\s+" + } ] + }; + this.normalizeRules(); + }; + + oop.inherits(AqlHighlightRules, TextHighlightRules); + + exports.AqlHighlightRules = AqlHighlightRules; + }); + From 7afd4ab0eb8dd01ae7d9fb885e5c7b770a3d4f22 Mon Sep 17 00:00:00 2001 From: emontnemery Date: Tue, 26 Mar 2019 23:08:03 +0100 Subject: [PATCH 0144/1293] fix highlighting of multiline yaml string in lists --- lib/ace/mode/yaml_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/yaml_highlight_rules.js b/lib/ace/mode/yaml_highlight_rules.js index 35425e63b50..7495f6f207f 100644 --- a/lib/ace/mode/yaml_highlight_rules.js +++ b/lib/ace/mode/yaml_highlight_rules.js @@ -74,7 +74,7 @@ var YamlHighlightRules = function() { token : "string", // multi line string start regex : /[|>][-+\d\s]*$/, onMatch: function(val, state, stack, line) { - var indent = /^\s*/.exec(line)[0]; + var indent = /^\s*(?:[-?]\s)?/.exec(line)[0]; if (stack.length < 1) { stack.push(this.next); } else { From 57c2ffe780a3de110a2da8ea029092e914e62838 Mon Sep 17 00:00:00 2001 From: emontnemery Date: Wed, 27 Mar 2019 21:28:17 +0100 Subject: [PATCH 0145/1293] Update yaml_highlight_rules.js --- lib/ace/mode/yaml_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/yaml_highlight_rules.js b/lib/ace/mode/yaml_highlight_rules.js index 7495f6f207f..063db80bcae 100644 --- a/lib/ace/mode/yaml_highlight_rules.js +++ b/lib/ace/mode/yaml_highlight_rules.js @@ -74,7 +74,7 @@ var YamlHighlightRules = function() { token : "string", // multi line string start regex : /[|>][-+\d\s]*$/, onMatch: function(val, state, stack, line) { - var indent = /^\s*(?:[-?]\s)?/.exec(line)[0]; + var indent = /^\s*(?:[-?]\s)?\s*/.exec(line)[0]; if (stack.length < 1) { stack.push(this.next); } else { From 8cbab2bcca20d7d94f41edec4bc6d53c1212a362 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 4 Apr 2019 18:01:49 +0200 Subject: [PATCH 0146/1293] fix textinput on ios in vim mode --- lib/ace/keyboard/textinput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 321f4575ed9..ca16825c3f6 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -159,7 +159,7 @@ var TextInput = function(parentNode, host) { var resetSelection = isIOS ? function(value) { - if (!isFocused || (copied && !value)) return; + if (!isFocused || (copied && !value) || sendingText) return; if (!value) value = ""; var newValue = "\n ab" + value + "cde fg\n"; From 32e531da44b096f313c19f54af945c3e01914cb7 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 14 Apr 2019 18:00:50 +0400 Subject: [PATCH 0147/1293] support manual indentation specification in yaml strings --- lib/ace/mode/_test/text_yaml.txt | 71 +++++++++++ lib/ace/mode/_test/tokens_yaml.json | 172 +++++++++++++++++++++++++-- lib/ace/mode/yaml_highlight_rules.js | 57 +++++++-- 3 files changed, 278 insertions(+), 22 deletions(-) create mode 100644 lib/ace/mode/_test/text_yaml.txt diff --git a/lib/ace/mode/_test/text_yaml.txt b/lib/ace/mode/_test/text_yaml.txt new file mode 100644 index 00000000000..506d3478e99 --- /dev/null +++ b/lib/ace/mode/_test/text_yaml.txt @@ -0,0 +1,71 @@ +# This sample document was taken from wikipedia: +# http://en.wikipedia.org/wiki/YAML#Sample_document +--- +receipt: Oz-Ware Purchase Invoice +date: 2007-08-06 +customer: + given: Dorothy + family: Gale + +items: + - part_no: 'A4786' + descrip: Water Bucket (Filled) + price: 1.47 + quantity: 4 + + - part_no: 'E1628' + descrip: High Heeled "Ruby" Slippers + size: 8 + price: 100.27 + quantity: 1 + +bill-to: &id001 + street: | + 123 Tornado Alley + Suite 16 + city: East Centerville + state: KS + +ship-to: *id001 + +specialDelivery: > + Follow the Yellow Brick + Road to the Emerald City. + Pay no attention to the + man behind the curtain. + +? | + block key #1 + kkk +: - | + one + - | + tw #o + - ? |- + + as #d + + q + b + - + x: xx + r: xx + z: sss + zdd: dddd + "block key 2" : + - two # block value + - ? | + as #d + : | + asdadas #d + asd + a: 2 + - ? | + asdas #d + : | + xx + s: |4+ #comment + 7 + + a + a diff --git a/lib/ace/mode/_test/tokens_yaml.json b/lib/ace/mode/_test/tokens_yaml.json index 0d2acadc4b9..29a89c6d76e 100644 --- a/lib/ace/mode/_test/tokens_yaml.json +++ b/lib/ace/mode/_test/tokens_yaml.json @@ -106,17 +106,17 @@ ["text"," "], ["constant.language","&id001"] ],[ - ["mlString",4], + ["mlStringPre",4], ["meta.tag"," street"], ["keyword",":"], ["text"," "], ["string","|"] ],[ - ["mlString",4], + ["mlString",11], ["indent"," "], ["string","123 Tornado Alley"] ],[ - ["mlString",4], + ["mlString",11], ["indent"," "], ["string","Suite 16"] ],[ @@ -141,27 +141,181 @@ ],[ "start" ],[ - ["mlString",0], + ["mlStringPre",0], ["meta.tag","specialDelivery"], ["keyword",":"], ["text"," "], ["string",">"] ],[ - ["mlString",0], + ["mlString",3], ["indent"," "], ["string","Follow the Yellow Brick"] ],[ - ["mlString",0], + ["mlString",3], ["indent"," "], ["string","Road to the Emerald City."] ],[ - ["mlString",0], + ["mlString",3], ["indent"," "], ["string","Pay no attention to the"] ],[ - ["mlString",0], + ["mlString",3], ["indent"," "], ["string","man behind the curtain."] ],[ - ["mlString",0] + ["mlString",3] +],[ + ["mlStringPre",0], + ["list.markup","? "], + ["text"," "], + ["string","|"] +],[ + ["mlString",0], + ["indent"," "], + ["string","block key #1"] +],[ + ["mlString",0], + ["indent"," "], + ["string","kkk"] +],[ + ["mlStringPre",2], + ["text",": - "], + ["string","|"] +],[ + ["mlString",2], + ["indent"," "], + ["string","one "] +],[ + ["mlStringPre",2], + ["indent"," "], + ["text","- "], + ["string","|"] +],[ + ["mlString",2], + ["indent"," "], + ["string","tw #o "] +],[ + ["mlStringPre",4], + ["indent"," "], + ["text","- ? "], + ["string","|- "] +],[ + ["mlStringPre",4] +],[ + ["mlString",4], + ["indent"," "], + ["string","as #d"] +],[ + ["mlString",4] +],[ + ["mlString",4], + ["indent"," "], + ["string","q"] +],[ + "start", + ["indent"," "], + ["text","b"] +],[ + "start", + ["list.markup"," - "] +],[ + "start", + ["meta.tag"," x"], + ["keyword",":"], + ["text"," xx"] +],[ + "start", + ["meta.tag"," r"], + ["keyword",":"], + ["text"," xx"] +],[ + "start", + ["meta.tag"," z"], + ["keyword",":"], + ["text"," sss"] +],[ + "start", + ["meta.tag"," zdd"], + ["keyword",":"], + ["text"," dddd"] +],[ + "start", + ["text"," "], + ["string","\"block key 2\""], + ["text"," : "] +],[ + "start", + ["list.markup"," - "], + ["text","two "], + ["comment","# block value"] +],[ + ["mlStringPre",9], + ["list.markup"," - "], + ["text","? "], + ["string","| "] +],[ + ["mlString",9], + ["indent"," "], + ["string","as #d"] +],[ + ["mlStringPre",9], + ["indent"," "], + ["text",": "], + ["string","|"] +],[ + ["mlString",9], + ["indent"," "], + ["string","asdadas #d"] +],[ + ["mlString",9], + ["indent"," "], + ["string","asd"] +],[ + "start", + ["indent"," "], + ["meta.tag","a"], + ["keyword",":"], + ["text"," "], + ["constant.numeric","2"] +],[ + ["mlStringPre",9], + ["list.markup"," - "], + ["text","? "], + ["string","| "] +],[ + ["mlString",9], + ["indent"," "], + ["string","asdas #d"] +],[ + ["mlStringPre",9], + ["indent"," "], + ["text",": "], + ["string","|"] +],[ + ["mlString",9], + ["indent"," "], + ["string","xx"] +],[ + ["mlString",12], + ["indent"," "], + ["meta.tag","s"], + ["keyword",":"], + ["text"," "], + ["string","|4+ #comment"] +],[ + ["mlString",12], + ["indent"," "], + ["string","7"] +],[ + ["mlString",12] +],[ + ["mlString",12], + ["indent"," "], + ["string","a "] +],[ + "start", + ["indent"," "], + ["text","a"] +],[ + "start" ]] \ No newline at end of file diff --git a/lib/ace/mode/yaml_highlight_rules.js b/lib/ace/mode/yaml_highlight_rules.js index 063db80bcae..56c9db44179 100644 --- a/lib/ace/mode/yaml_highlight_rules.js +++ b/lib/ace/mode/yaml_highlight_rules.js @@ -72,20 +72,25 @@ var YamlHighlightRules = function() { regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' }, { token : "string", // multi line string start - regex : /[|>][-+\d\s]*$/, + regex : /[|>][-+\d]*(?:$|\s+(?:$|#))/, onMatch: function(val, state, stack, line) { - var indent = /^\s*(?:[-?]\s)?\s*/.exec(line)[0]; - if (stack.length < 1) { - stack.push(this.next); + line = line.replace(/ #.*/, ""); + var indent = /^ *((:\s*)?-(\s*[^|>])?)?/.exec(line)[0] + .replace(/\S\s*$/, "").length; + var indentationIndicator = parseInt(/\d+[\s+-]*$/.exec(line)); + + if (indentationIndicator) { + indent += indentationIndicator - 1; + this.next = "mlString"; } else { - stack[0] = "mlString"; - } - - if (stack.length < 2) { - stack.push(indent.length); + this.next = "mlStringPre"; } - else { - stack[1] = indent.length; + if (!stack.length) { + stack.push(this.next); + stack.push(indent); + } else { + stack[0] = this.next; + stack[1] = indent; } return this.token; }, @@ -113,13 +118,39 @@ var YamlHighlightRules = function() { regex : /[^\s,:\[\]\{\}]+/ } ], + "mlStringPre" : [ + { + token : "indent", + regex : /^ *$/ + }, { + token : "indent", + regex : /^ */, + onMatch: function(val, state, stack) { + var curIndent = stack[1]; + + if (curIndent >= val.length) { + this.next = "start"; + stack.shift(); + stack.shift(); + } + else { + stack[1] = val.length - 1; + this.next = stack[0] = "mlString"; + } + return this.token; + }, + next : "mlString" + }, { + defaultToken : "string" + } + ], "mlString" : [ { token : "indent", - regex : /^\s*$/ + regex : /^ *$/ }, { token : "indent", - regex : /^\s*/, + regex : /^ */, onMatch: function(val, state, stack) { var curIndent = stack[1]; From 99bd8c644d2ca16edb205dbf77d70f272d6a09c7 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 22 Mar 2019 23:46:49 +0400 Subject: [PATCH 0148/1293] initial implementation of command prompt --- build | 2 +- demo/kitchen-sink/demo.js | 15 - lib/ace/autocomplete.js | 12 +- lib/ace/autocomplete/popup.js | 22 +- lib/ace/commands/default_commands.js | 110 ++++- lib/ace/commands/multi_select_commands.js | 12 + lib/ace/editor.js | 10 + lib/ace/ext/beautify.js | 1 + lib/ace/ext/keybinding_menu.js | 2 +- lib/ace/ext/menu_tools/overlay_page.js | 48 +-- lib/ace/ext/prompt.js | 472 ++++++++++++++++++++++ lib/ace/ext/settings_menu.js | 2 +- lib/ace/ext/whitespace.js | 4 + lib/ace/selection.js | 2 +- 14 files changed, 648 insertions(+), 66 deletions(-) create mode 100644 lib/ace/ext/prompt.js diff --git a/build b/build index 32e27226d66..f17f0751fc4 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 32e27226d66b2f3a63d4e393853f84ef3e17a003 +Subproject commit f17f0751fc4c2bb73cd9340e9cbc02e4d979608f diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index d8909ff1c26..49e0e771e1b 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -134,21 +134,6 @@ env.editor.showCommandLine = function(val) { * This demonstrates how you can define commands and bind shortcuts to them. */ env.editor.commands.addCommands([{ - name: "gotoline", - bindKey: {win: "Ctrl-L", mac: "Command-L"}, - exec: function(editor, line) { - if (typeof line == "object") { - var arg = this.name + " " + editor.getCursorPosition().row; - editor.cmdLine.setValue(arg, 1); - editor.cmdLine.focus(); - return; - } - line = parseInt(line, 10); - if (!isNaN(line)) - editor.gotoLine(line); - }, - readOnly: true -}, { name: "snippet", bindKey: {win: "Alt-C", mac: "Command-Alt-C"}, exec: function(editor, needle) { diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index a323dd882a6..1802d720e60 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -163,17 +163,7 @@ var Autocomplete = function() { }; this.goTo = function(where) { - var row = this.popup.getRow(); - var max = this.popup.session.getLength() - 1; - - switch(where) { - case "up": row = row <= 0 ? max : row - 1; break; - case "down": row = row >= max ? -1 : row + 1; break; - case "start": row = 0; break; - case "end": row = max; break; - } - - this.popup.setRow(row); + this.popup.goTo(where); }; this.insertMatch = function(data, options) { diff --git a/lib/ace/autocomplete/popup.js b/lib/ace/autocomplete/popup.js index bb0e21ea86d..01e9e02409d 100644 --- a/lib/ace/autocomplete/popup.js +++ b/lib/ace/autocomplete/popup.js @@ -204,6 +204,8 @@ var AcePopup = function(parentNode) { if (data.meta) tokens.push({type: "completion-meta", value: data.meta}); + if (data.message) + tokens.push({type: "completion-message", value: data.message}); return tokens; }; @@ -292,6 +294,21 @@ var AcePopup = function(parentNode) { popup.isOpen = true; }; + popup.goTo = function(where) { + var row = this.getRow(); + var max = this.session.getLength() - 1; + + switch(where) { + case "up": row = row < 0 ? max : row - 1; break; + case "down": row = row >= max ? -1 : row + 1; break; + case "start": row = 0; break; + case "end": row = max; break; + } + + this.setRow(row); + }; + + popup.getTextLeftOffset = function() { return this.$borderSize + this.renderer.$padding + this.$imageSize; }; @@ -325,6 +342,9 @@ dom.importCssString("\ opacity: 0.5;\ margin: 0.9em;\ }\ +.ace_completion-message {\ + color: blue;\ +}\ .ace_editor.ace_autocomplete .ace_completion-highlight{\ color: #2d69c7;\ }\ @@ -350,7 +370,7 @@ dom.importCssString("\ }", "autocompletion.css"); exports.AcePopup = AcePopup; - +exports.$singleLineEditor = $singleLineEditor; }); diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 527bebe874a..ac15251ab12 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -75,23 +75,25 @@ exports.commands = [{ readOnly: true }, { name: "selectall", + description: "Select all", bindKey: bindKey("Ctrl-A", "Command-A"), exec: function(editor) { editor.selectAll(); }, readOnly: true }, { name: "centerselection", + description: "Center selection", bindKey: bindKey(null, "Ctrl-L"), exec: function(editor) { editor.centerSelection(); }, readOnly: true }, { name: "gotoline", + description: "Go to line...", bindKey: bindKey("Ctrl-L", "Command-L"), exec: function(editor, line) { - if (typeof line !== "number") - line = parseInt(prompt("Enter line number:"), 10); - if (!isNaN(line)) { + // backwards compatibility + if (typeof line === "number" && !isNaN(line)) editor.gotoLine(line); - } + editor.prompt({ $type: "gotoLine" }); }, readOnly: true }, { @@ -124,12 +126,14 @@ exports.commands = [{ readOnly: true }, { name: "foldall", + description: "Fold all", bindKey: bindKey(null, "Ctrl-Command-Option-0"), exec: function(editor) { editor.session.foldAll(); }, scrollIntoView: "center", readOnly: true }, { name: "foldOther", + description: "Fold other", bindKey: bindKey("Alt-0", "Command-Option-0"), exec: function(editor) { editor.session.foldAll(); @@ -139,12 +143,14 @@ exports.commands = [{ readOnly: true }, { name: "unfoldall", + description: "Unfold all", bindKey: bindKey("Alt-Shift-0", "Command-Option-Shift-0"), exec: function(editor) { editor.session.unfold(); }, scrollIntoView: "center", readOnly: true }, { name: "findnext", + description: "Find next", bindKey: bindKey("Ctrl-K", "Command-G"), exec: function(editor) { editor.findNext(); }, multiSelectAction: "forEach", @@ -152,6 +158,7 @@ exports.commands = [{ readOnly: true }, { name: "findprevious", + description: "Find previous", bindKey: bindKey("Ctrl-Shift-K", "Command-Shift-G"), exec: function(editor) { editor.findPrevious(); }, multiSelectAction: "forEach", @@ -159,6 +166,7 @@ exports.commands = [{ readOnly: true }, { name: "selectOrFindNext", + description: "Select or find next", bindKey: bindKey("Alt-K", "Ctrl-G"), exec: function(editor) { if (editor.selection.isEmpty()) @@ -169,6 +177,7 @@ exports.commands = [{ readOnly: true }, { name: "selectOrFindPrevious", + description: "Select or find previous", bindKey: bindKey("Alt-Shift-K", "Ctrl-Shift-G"), exec: function(editor) { if (editor.selection.isEmpty()) @@ -179,6 +188,7 @@ exports.commands = [{ readOnly: true }, { name: "find", + description: "Find", bindKey: bindKey("Ctrl-F", "Command-F"), exec: function(editor) { config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor);}); @@ -186,11 +196,13 @@ exports.commands = [{ readOnly: true }, { name: "overwrite", + description: "Overwrite", bindKey: "Insert", exec: function(editor) { editor.toggleOverwrite(); }, readOnly: true }, { name: "selecttostart", + description: "Select to start", bindKey: bindKey("Ctrl-Shift-Home", "Command-Shift-Home|Command-Shift-Up"), exec: function(editor) { editor.getSelection().selectFileStart(); }, multiSelectAction: "forEach", @@ -199,6 +211,7 @@ exports.commands = [{ aceCommandGroup: "fileJump" }, { name: "gotostart", + description: "Go to start", bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"), exec: function(editor) { editor.navigateFileStart(); }, multiSelectAction: "forEach", @@ -207,6 +220,7 @@ exports.commands = [{ aceCommandGroup: "fileJump" }, { name: "selectup", + description: "Select up", bindKey: bindKey("Shift-Up", "Shift-Up|Ctrl-Shift-P"), exec: function(editor) { editor.getSelection().selectUp(); }, multiSelectAction: "forEach", @@ -214,6 +228,7 @@ exports.commands = [{ readOnly: true }, { name: "golineup", + description: "Go line up", bindKey: bindKey("Up", "Up|Ctrl-P"), exec: function(editor, args) { editor.navigateUp(args.times); }, multiSelectAction: "forEach", @@ -221,6 +236,7 @@ exports.commands = [{ readOnly: true }, { name: "selecttoend", + description: "Select to end", bindKey: bindKey("Ctrl-Shift-End", "Command-Shift-End|Command-Shift-Down"), exec: function(editor) { editor.getSelection().selectFileEnd(); }, multiSelectAction: "forEach", @@ -229,6 +245,7 @@ exports.commands = [{ aceCommandGroup: "fileJump" }, { name: "gotoend", + description: "Go to end", bindKey: bindKey("Ctrl-End", "Command-End|Command-Down"), exec: function(editor) { editor.navigateFileEnd(); }, multiSelectAction: "forEach", @@ -237,6 +254,7 @@ exports.commands = [{ aceCommandGroup: "fileJump" }, { name: "selectdown", + description: "Select down", bindKey: bindKey("Shift-Down", "Shift-Down|Ctrl-Shift-N"), exec: function(editor) { editor.getSelection().selectDown(); }, multiSelectAction: "forEach", @@ -244,6 +262,7 @@ exports.commands = [{ readOnly: true }, { name: "golinedown", + description: "Go line down", bindKey: bindKey("Down", "Down|Ctrl-N"), exec: function(editor, args) { editor.navigateDown(args.times); }, multiSelectAction: "forEach", @@ -251,6 +270,7 @@ exports.commands = [{ readOnly: true }, { name: "selectwordleft", + description: "Select word left", bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"), exec: function(editor) { editor.getSelection().selectWordLeft(); }, multiSelectAction: "forEach", @@ -258,6 +278,7 @@ exports.commands = [{ readOnly: true }, { name: "gotowordleft", + description: "Go to word left", bindKey: bindKey("Ctrl-Left", "Option-Left"), exec: function(editor) { editor.navigateWordLeft(); }, multiSelectAction: "forEach", @@ -265,6 +286,7 @@ exports.commands = [{ readOnly: true }, { name: "selecttolinestart", + description: "Select to line start", bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left|Ctrl-Shift-A"), exec: function(editor) { editor.getSelection().selectLineStart(); }, multiSelectAction: "forEach", @@ -272,6 +294,7 @@ exports.commands = [{ readOnly: true }, { name: "gotolinestart", + description: "Go to line start", bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"), exec: function(editor) { editor.navigateLineStart(); }, multiSelectAction: "forEach", @@ -279,6 +302,7 @@ exports.commands = [{ readOnly: true }, { name: "selectleft", + description: "Select left", bindKey: bindKey("Shift-Left", "Shift-Left|Ctrl-Shift-B"), exec: function(editor) { editor.getSelection().selectLeft(); }, multiSelectAction: "forEach", @@ -286,6 +310,7 @@ exports.commands = [{ readOnly: true }, { name: "gotoleft", + description: "Go to left", bindKey: bindKey("Left", "Left|Ctrl-B"), exec: function(editor, args) { editor.navigateLeft(args.times); }, multiSelectAction: "forEach", @@ -293,6 +318,7 @@ exports.commands = [{ readOnly: true }, { name: "selectwordright", + description: "Select word right", bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"), exec: function(editor) { editor.getSelection().selectWordRight(); }, multiSelectAction: "forEach", @@ -300,6 +326,7 @@ exports.commands = [{ readOnly: true }, { name: "gotowordright", + description: "Go to word right", bindKey: bindKey("Ctrl-Right", "Option-Right"), exec: function(editor) { editor.navigateWordRight(); }, multiSelectAction: "forEach", @@ -307,6 +334,7 @@ exports.commands = [{ readOnly: true }, { name: "selecttolineend", + description: "Select to line end", bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right|Shift-End|Ctrl-Shift-E"), exec: function(editor) { editor.getSelection().selectLineEnd(); }, multiSelectAction: "forEach", @@ -314,6 +342,7 @@ exports.commands = [{ readOnly: true }, { name: "gotolineend", + description: "Go to line end", bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"), exec: function(editor) { editor.navigateLineEnd(); }, multiSelectAction: "forEach", @@ -321,6 +350,7 @@ exports.commands = [{ readOnly: true }, { name: "selectright", + description: "Select right", bindKey: bindKey("Shift-Right", "Shift-Right"), exec: function(editor) { editor.getSelection().selectRight(); }, multiSelectAction: "forEach", @@ -328,6 +358,7 @@ exports.commands = [{ readOnly: true }, { name: "gotoright", + description: "Go to right", bindKey: bindKey("Right", "Right|Ctrl-F"), exec: function(editor, args) { editor.navigateRight(args.times); }, multiSelectAction: "forEach", @@ -335,46 +366,55 @@ exports.commands = [{ readOnly: true }, { name: "selectpagedown", + description: "Select page down", bindKey: "Shift-PageDown", exec: function(editor) { editor.selectPageDown(); }, readOnly: true }, { name: "pagedown", + description: "Page down", bindKey: bindKey(null, "Option-PageDown"), exec: function(editor) { editor.scrollPageDown(); }, readOnly: true }, { name: "gotopagedown", + description: "Go to page down", bindKey: bindKey("PageDown", "PageDown|Ctrl-V"), exec: function(editor) { editor.gotoPageDown(); }, readOnly: true }, { name: "selectpageup", + description: "Select page up", bindKey: "Shift-PageUp", exec: function(editor) { editor.selectPageUp(); }, readOnly: true }, { name: "pageup", + description: "Page up", bindKey: bindKey(null, "Option-PageUp"), exec: function(editor) { editor.scrollPageUp(); }, readOnly: true }, { name: "gotopageup", + description: "Go to page up", bindKey: "PageUp", exec: function(editor) { editor.gotoPageUp(); }, readOnly: true }, { name: "scrollup", + description: "Scroll up", bindKey: bindKey("Ctrl-Up", null), exec: function(e) { e.renderer.scrollBy(0, -2 * e.renderer.layerConfig.lineHeight); }, readOnly: true }, { name: "scrolldown", + description: "Scroll down", bindKey: bindKey("Ctrl-Down", null), exec: function(e) { e.renderer.scrollBy(0, 2 * e.renderer.layerConfig.lineHeight); }, readOnly: true }, { name: "selectlinestart", + description: "Select line start", bindKey: "Shift-Home", exec: function(editor) { editor.getSelection().selectLineStart(); }, multiSelectAction: "forEach", @@ -382,6 +422,7 @@ exports.commands = [{ readOnly: true }, { name: "selectlineend", + description: "Select line end", bindKey: "Shift-End", exec: function(editor) { editor.getSelection().selectLineEnd(); }, multiSelectAction: "forEach", @@ -389,16 +430,19 @@ exports.commands = [{ readOnly: true }, { name: "togglerecording", + description: "Toggle recording", bindKey: bindKey("Ctrl-Alt-E", "Command-Option-E"), exec: function(editor) { editor.commands.toggleRecording(editor); }, readOnly: true }, { name: "replaymacro", + description: "Replay macro", bindKey: bindKey("Ctrl-Shift-E", "Command-Shift-E"), exec: function(editor) { editor.commands.replay(editor); }, readOnly: true }, { name: "jumptomatching", + description: "Jump to matching", bindKey: bindKey("Ctrl-P", "Ctrl-P"), exec: function(editor) { editor.jumpToMatching(); }, multiSelectAction: "forEach", @@ -406,6 +450,7 @@ exports.commands = [{ readOnly: true }, { name: "selecttomatching", + description: "Select to matching", bindKey: bindKey("Ctrl-Shift-P", "Ctrl-Shift-P"), exec: function(editor) { editor.jumpToMatching(true); }, multiSelectAction: "forEach", @@ -413,6 +458,7 @@ exports.commands = [{ readOnly: true }, { name: "expandToMatching", + description: "Expand to matching", bindKey: bindKey("Ctrl-Shift-M", "Ctrl-Shift-M"), exec: function(editor) { editor.jumpToMatching(true, true); }, multiSelectAction: "forEach", @@ -420,12 +466,14 @@ exports.commands = [{ readOnly: true }, { name: "passKeysToBrowser", + description: "Pass keys to browser", bindKey: bindKey(null, null), exec: function() {}, passEvent: true, readOnly: true }, { name: "copy", + description: "Copy", exec: function(editor) { // placeholder for replay macro }, @@ -435,6 +483,7 @@ exports.commands = [{ // commands disabled in readOnly mode { name: "cut", + description: "Cut", exec: function(editor) { var cutLine = editor.$copyWithEmptySelection && editor.selection.isEmpty(); var range = cutLine ? editor.selection.getLineRange() : editor.selection.getRange(); @@ -448,94 +497,111 @@ exports.commands = [{ multiSelectAction: "forEach" }, { name: "paste", + description: "Paste", exec: function(editor, args) { editor.$handlePaste(args); }, scrollIntoView: "cursor" }, { name: "removeline", + description: "Remove line", bindKey: bindKey("Ctrl-D", "Command-D"), exec: function(editor) { editor.removeLines(); }, scrollIntoView: "cursor", multiSelectAction: "forEachLine" }, { name: "duplicateSelection", + description: "Duplicate selection", bindKey: bindKey("Ctrl-Shift-D", "Command-Shift-D"), exec: function(editor) { editor.duplicateSelection(); }, scrollIntoView: "cursor", multiSelectAction: "forEach" }, { name: "sortlines", + description: "Sort lines", bindKey: bindKey("Ctrl-Alt-S", "Command-Alt-S"), exec: function(editor) { editor.sortLines(); }, scrollIntoView: "selection", multiSelectAction: "forEachLine" }, { name: "togglecomment", + description: "Toggle comment", bindKey: bindKey("Ctrl-/", "Command-/"), exec: function(editor) { editor.toggleCommentLines(); }, multiSelectAction: "forEachLine", scrollIntoView: "selectionPart" }, { name: "toggleBlockComment", + description: "Toggle block comment", bindKey: bindKey("Ctrl-Shift-/", "Command-Shift-/"), exec: function(editor) { editor.toggleBlockComment(); }, multiSelectAction: "forEach", scrollIntoView: "selectionPart" }, { name: "modifyNumberUp", + description: "Modify number up", bindKey: bindKey("Ctrl-Shift-Up", "Alt-Shift-Up"), exec: function(editor) { editor.modifyNumber(1); }, scrollIntoView: "cursor", multiSelectAction: "forEach" }, { name: "modifyNumberDown", + description: "Modify number down", bindKey: bindKey("Ctrl-Shift-Down", "Alt-Shift-Down"), exec: function(editor) { editor.modifyNumber(-1); }, scrollIntoView: "cursor", multiSelectAction: "forEach" }, { name: "replace", + description: "Replace", bindKey: bindKey("Ctrl-H", "Command-Option-F"), exec: function(editor) { config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor, true);}); } }, { name: "undo", + description: "Undo", bindKey: bindKey("Ctrl-Z", "Command-Z"), exec: function(editor) { editor.undo(); } }, { name: "redo", + description: "Redo", bindKey: bindKey("Ctrl-Shift-Z|Ctrl-Y", "Command-Shift-Z|Command-Y"), exec: function(editor) { editor.redo(); } }, { name: "copylinesup", + description: "Copy lines up", bindKey: bindKey("Alt-Shift-Up", "Command-Option-Up"), exec: function(editor) { editor.copyLinesUp(); }, scrollIntoView: "cursor" }, { name: "movelinesup", + description: "Move lines up", bindKey: bindKey("Alt-Up", "Option-Up"), exec: function(editor) { editor.moveLinesUp(); }, scrollIntoView: "cursor" }, { name: "copylinesdown", + description: "Copy lines down", bindKey: bindKey("Alt-Shift-Down", "Command-Option-Down"), exec: function(editor) { editor.copyLinesDown(); }, scrollIntoView: "cursor" }, { name: "movelinesdown", + description: "Move lines down", bindKey: bindKey("Alt-Down", "Option-Down"), exec: function(editor) { editor.moveLinesDown(); }, scrollIntoView: "cursor" }, { name: "del", + description: "Delete", bindKey: bindKey("Delete", "Delete|Ctrl-D|Shift-Delete"), exec: function(editor) { editor.remove("right"); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "backspace", + description: "Backspace", bindKey: bindKey( "Shift-Backspace|Backspace", "Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H" @@ -545,6 +611,7 @@ exports.commands = [{ scrollIntoView: "cursor" }, { name: "cut_or_delete", + description: "Cut or delete", bindKey: bindKey("Shift-Delete", null), exec: function(editor) { if (editor.selection.isEmpty()) { @@ -557,18 +624,21 @@ exports.commands = [{ scrollIntoView: "cursor" }, { name: "removetolinestart", + description: "Remove to line start", bindKey: bindKey("Alt-Backspace", "Command-Backspace"), exec: function(editor) { editor.removeToLineStart(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "removetolineend", + description: "Remove to line end", bindKey: bindKey("Alt-Delete", "Ctrl-K|Command-Delete"), exec: function(editor) { editor.removeToLineEnd(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "removetolinestarthard", + description: "Remove to line start hard", bindKey: bindKey("Ctrl-Shift-Backspace", null), exec: function(editor) { var range = editor.selection.getRange(); @@ -579,6 +649,7 @@ exports.commands = [{ scrollIntoView: "cursor" }, { name: "removetolineendhard", + description: "Remove to line end hard", bindKey: bindKey("Ctrl-Shift-Delete", null), exec: function(editor) { var range = editor.selection.getRange(); @@ -589,47 +660,55 @@ exports.commands = [{ scrollIntoView: "cursor" }, { name: "removewordleft", + description: "Remove word left", bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"), exec: function(editor) { editor.removeWordLeft(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "removewordright", + description: "Remove word right", bindKey: bindKey("Ctrl-Delete", "Alt-Delete"), exec: function(editor) { editor.removeWordRight(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "outdent", + description: "Outdent", bindKey: bindKey("Shift-Tab", "Shift-Tab"), exec: function(editor) { editor.blockOutdent(); }, multiSelectAction: "forEach", scrollIntoView: "selectionPart" }, { name: "indent", + description: "Indent", bindKey: bindKey("Tab", "Tab"), exec: function(editor) { editor.indent(); }, multiSelectAction: "forEach", scrollIntoView: "selectionPart" }, { name: "blockoutdent", + description: "Block outdent", bindKey: bindKey("Ctrl-[", "Ctrl-["), exec: function(editor) { editor.blockOutdent(); }, multiSelectAction: "forEachLine", scrollIntoView: "selectionPart" }, { name: "blockindent", + description: "Block indent", bindKey: bindKey("Ctrl-]", "Ctrl-]"), exec: function(editor) { editor.blockIndent(); }, multiSelectAction: "forEachLine", scrollIntoView: "selectionPart" }, { name: "insertstring", + description: "Insert string", exec: function(editor, str) { editor.insert(str); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "inserttext", + description: "Insert text", exec: function(editor, args) { editor.insert(lang.stringRepeat(args.text || "", args.times || 1)); }, @@ -637,30 +716,35 @@ exports.commands = [{ scrollIntoView: "cursor" }, { name: "splitline", + description: "Split line", bindKey: bindKey(null, "Ctrl-O"), exec: function(editor) { editor.splitLine(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "transposeletters", + description: "Transpose letters", bindKey: bindKey("Alt-Shift-X", "Ctrl-T"), exec: function(editor) { editor.transposeLetters(); }, multiSelectAction: function(editor) {editor.transposeSelections(1); }, scrollIntoView: "cursor" }, { name: "touppercase", + description: "To uppercase", bindKey: bindKey("Ctrl-U", "Ctrl-U"), exec: function(editor) { editor.toUpperCase(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "tolowercase", + description: "To lowercase", bindKey: bindKey("Ctrl-Shift-U", "Ctrl-Shift-U"), exec: function(editor) { editor.toLowerCase(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "expandtoline", + description: "Expand to line", bindKey: bindKey("Ctrl-Shift-L", "Command-Shift-L"), exec: function(editor) { var range = editor.selection.getRange(); @@ -674,6 +758,7 @@ exports.commands = [{ readOnly: true }, { name: "joinlines", + description: "Join lines", bindKey: bindKey(null, null), exec: function(editor) { var isBackwards = editor.selection.isBackwards(); @@ -714,6 +799,7 @@ exports.commands = [{ readOnly: true }, { name: "invertSelection", + description: "Invert selection", bindKey: bindKey(null, null), exec: function(editor) { var endRow = editor.session.doc.getLength() - 1; @@ -753,6 +839,22 @@ exports.commands = [{ }, readOnly: true, scrollIntoView: "none" +}, { + name: "openCommandPallete", + description: "Open command pallete", + bindKey: bindKey("F1", "F1"), + exec: function(editor) { + editor.prompt({ $type: "commands" }); + }, + readOnly: true +}, { + name: "modeSelect", + description: "Change language mode...", + bindKey: bindKey(null, null), + exec: function(editor) { + editor.prompt({ $type: "modes" }); + }, + readOnly: true }]; }); diff --git a/lib/ace/commands/multi_select_commands.js b/lib/ace/commands/multi_select_commands.js index 26adc8351fb..361f625458e 100644 --- a/lib/ace/commands/multi_select_commands.js +++ b/lib/ace/commands/multi_select_commands.js @@ -33,64 +33,75 @@ define(function(require, exports, module) { // commands to enter multiselect mode exports.defaultCommands = [{ name: "addCursorAbove", + description: "Add cursor above", exec: function(editor) { editor.selectMoreLines(-1); }, bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"}, scrollIntoView: "cursor", readOnly: true }, { name: "addCursorBelow", + description: "Add cursor below", exec: function(editor) { editor.selectMoreLines(1); }, bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"}, scrollIntoView: "cursor", readOnly: true }, { name: "addCursorAboveSkipCurrent", + description: "Add cursor above (skip current)", exec: function(editor) { editor.selectMoreLines(-1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"}, scrollIntoView: "cursor", readOnly: true }, { name: "addCursorBelowSkipCurrent", + description: "Add cursor below (skip current)", exec: function(editor) { editor.selectMoreLines(1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"}, scrollIntoView: "cursor", readOnly: true }, { name: "selectMoreBefore", + description: "Select more before", exec: function(editor) { editor.selectMore(-1); }, bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"}, scrollIntoView: "cursor", readOnly: true }, { name: "selectMoreAfter", + description: "Select more after", exec: function(editor) { editor.selectMore(1); }, bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"}, scrollIntoView: "cursor", readOnly: true }, { name: "selectNextBefore", + description: "Select next before", exec: function(editor) { editor.selectMore(-1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"}, scrollIntoView: "cursor", readOnly: true }, { name: "selectNextAfter", + description: "Select next after", exec: function(editor) { editor.selectMore(1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"}, scrollIntoView: "cursor", readOnly: true }, { name: "splitIntoLines", + description: "Split into lines", exec: function(editor) { editor.multiSelect.splitIntoLines(); }, bindKey: {win: "Ctrl-Alt-L", mac: "Ctrl-Alt-L"}, readOnly: true }, { name: "alignCursors", + description: "Align cursors", exec: function(editor) { editor.alignCursors(); }, bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"}, scrollIntoView: "cursor" }, { name: "findAll", + description: "Find all", exec: function(editor) { editor.findAll(); }, bindKey: {win: "Ctrl-Alt-K", mac: "Ctrl-Alt-G"}, scrollIntoView: "cursor", @@ -100,6 +111,7 @@ exports.defaultCommands = [{ // commands active only in multiselect mode exports.multiSelectCommands = [{ name: "singleSelection", + description: "Single selection", bindKey: "esc", exec: function(editor) { editor.exitMultiSelectMode(); }, scrollIntoView: "cursor", diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 4c3e4f020ae..70a37ad482c 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -2735,6 +2735,16 @@ Editor.$uid = 0; dom.setCssClass(cursorLayer.element, "ace_slim-cursors", /slim/.test(style)); }; + /** + * opens a prompt displaying message + **/ + this.prompt = function(message, options, callback) { + var editor = this; + config.loadModule("./ext/prompt", function (module) { + module.prompt(editor, message, options, callback); + }); + }; + }).call(Editor.prototype); diff --git a/lib/ace/ext/beautify.js b/lib/ace/ext/beautify.js index 98f6abfef1b..a15bfbd8a9c 100644 --- a/lib/ace/ext/beautify.js +++ b/lib/ace/ext/beautify.js @@ -398,6 +398,7 @@ exports.beautify = function(session) { exports.commands = [{ name: "beautify", + description: "Format selection (Beautify)", exec: function(editor) { exports.beautify(editor.session); }, diff --git a/lib/ace/ext/keybinding_menu.js b/lib/ace/ext/keybinding_menu.js index 38e578d81f4..0898d7283a2 100644 --- a/lib/ace/ext/keybinding_menu.js +++ b/lib/ace/ext/keybinding_menu.js @@ -67,7 +67,7 @@ define(function(require, exports, module) { el.id = 'kbshortcutmenu'; el.innerHTML = '

    Keyboard Shortcuts

    ' + commands + ''; - overlayPage(editor, el, '0', '0', '0', null); + overlayPage(editor, el); } } module.exports.init = function(editor) { diff --git a/lib/ace/ext/menu_tools/overlay_page.js b/lib/ace/ext/menu_tools/overlay_page.js index bf985e29c6a..3ab3415d6ab 100644 --- a/lib/ace/ext/menu_tools/overlay_page.js +++ b/lib/ace/ext/menu_tools/overlay_page.js @@ -57,60 +57,46 @@ dom.importCssString(cssText); * ☭ Hial Atropa!! ☭ * @param {DOMElement} contentElement Any element which may be presented inside * a div. - * @param {string|number} top absolute position value. - * @param {string|number} right absolute position value. - * @param {string|number} bottom absolute position value. - * @param {string|number} left absolute position value. */ -module.exports.overlayPage = function overlayPage(editor, contentElement, top, right, bottom, left) { - top = top ? 'top: ' + top + ';' : ''; - bottom = bottom ? 'bottom: ' + bottom + ';' : ''; - right = right ? 'right: ' + right + ';' : ''; - left = left ? 'left: ' + left + ';' : ''; +module.exports.overlayPage = function overlayPage(editor, contentElement, callback) { var closer = document.createElement('div'); - var contentContainer = document.createElement('div'); function documentEscListener(e) { if (e.keyCode === 27) { - closer.click(); + close(); } } + function close() { + if (!closer) return; + document.removeEventListener('keydown', documentEscListener); + closer.parentNode.removeChild(closer); + editor.focus(); + closer = null; + callback && callback(); + } + closer.style.cssText = 'margin: 0; padding: 0; ' + 'position: fixed; top:0; bottom:0; left:0; right:0;' + 'z-index: 9990; ' + 'background-color: rgba(0, 0, 0, 0.3);'; closer.addEventListener('click', function() { - document.removeEventListener('keydown', documentEscListener); - closer.parentNode.removeChild(closer); - editor.focus(); - closer = null; + close(); }); // click closer if esc key is pressed document.addEventListener('keydown', documentEscListener); - contentContainer.style.cssText = top + right + bottom + left; - contentContainer.addEventListener('click', function(e) { + contentElement.addEventListener('click', function (e) { e.stopPropagation(); }); - var wrapper = dom.createElement("div"); - wrapper.style.position = "relative"; - - var closeButton = dom.createElement("div"); - closeButton.className = "ace_closeButton"; - closeButton.addEventListener('click', function() { - closer.click(); - }); - - wrapper.appendChild(closeButton); - contentContainer.appendChild(wrapper); - - contentContainer.appendChild(contentElement); - closer.appendChild(contentContainer); + closer.appendChild(contentElement); document.body.appendChild(closer); editor.blur(); + return { + close: close + }; }; }); \ No newline at end of file diff --git a/lib/ace/ext/prompt.js b/lib/ace/ext/prompt.js new file mode 100644 index 00000000000..e0c50f056bf --- /dev/null +++ b/lib/ace/ext/prompt.js @@ -0,0 +1,472 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; +var dom = require("../lib/dom"); +var shortcuts = require("../ext/menu_tools/get_editor_keyboard_shortcuts"); +var FilteredList= require("../autocomplete").FilteredList; +var AcePopup = require('../autocomplete/popup').AcePopup; +var $singleLineEditor = require('../autocomplete/popup').$singleLineEditor; +var UndoManager = require("../undomanager").UndoManager; +var Tokenizer = require("ace/tokenizer").Tokenizer; +var overlayPage = require('./menu_tools/overlay_page').overlayPage; +var modelist = require("ace/ext/modelist"); +var openPrompt; + +function prompt(editor, message, options, callback) { + if (typeof message == "object") { + return prompt(editor, "", message, options); + } + if (openPrompt) { + var lastPrompt = openPrompt; + editor = lastPrompt.editor; + lastPrompt.close(); + if (lastPrompt.name && lastPrompt.name == options.name) + return; + } + if (options.$type) + return prompt[options.$type](editor, callback); + + var cmdLine = $singleLineEditor(); + cmdLine.session.setUndoManager(new UndoManager()); + cmdLine.setOption("fontSize", editor.getOption("fontSize")); + + var el = dom.buildDom(["div", {class: "ace_prompt_container"}]); + var overlay = overlayPage(editor, el, done); + el.appendChild(cmdLine.container); + + editor.cmdLine = cmdLine; + cmdLine.setValue(message, 1); + if (options.selection) { + cmdLine.selection.setRange({ + start: cmdLine.session.doc.indexToPosition(options.selection[0]), + end: cmdLine.session.doc.indexToPosition(options.selection[1]) + }); + } + + if (options.getCompletions) { + var popup = new AcePopup(); + popup.renderer.setStyle("ace_autocomplete_inline"); + popup.container.style.display = "block"; + popup.container.style.maxWidth = "600px"; + popup.container.style.width = "100%"; + popup.container.style.marginTop = "3px"; + popup.renderer.setScrollMargin(2, 2, 0, 0); + popup.autoSelect = false; + popup.renderer.$maxLines = 15; + popup.setRow(-1); + popup.on("click", function(e) { + var data = popup.getData(popup.getRow()); + if (!data.error) { + cmdLine.setValue(data.value || data.name || data); + accept(); + e.stop(); + } + }); + el.appendChild(popup.container); + updateCompletions(); + } + + if (options.$rules) { + var tokenizer = new Tokenizer(options.$rules); + cmdLine.session.bgTokenizer.setTokenizer(tokenizer); + } + + function accept() { + var val; + if (popup.getCursorPosition().row > 0) { + val = valueFromRecentList(); + } else { + val = cmdLine.getValue(); + } + var curData = popup.getData(popup.getRow()); + if (curData && !curData.error) { + done(); + options.onAccept && options.onAccept({ + value: val, + item: curData + }, cmdLine); + } + } + + cmdLine.commands.bindKeys({ + "Enter": accept, + "Esc|Shift-Esc": function() { + options.onCancel && options.onCancel(cmdLine.getValue(), cmdLine); + done(); + }, + "Up": function(editor) { popup.goTo("up"); valueFromRecentList();}, + "Down": function(editor) { popup.goTo("down"); valueFromRecentList();}, + "Ctrl-Up|Ctrl-Home": function(editor) { popup.goTo("start"); valueFromRecentList();}, + "Ctrl-Down|Ctrl-End": function(editor) { popup.goTo("end"); valueFromRecentList();}, + "Tab": function(editor) { + popup.goTo("down"); valueFromRecentList(); + }, + "PageUp": function(editor) { popup.gotoPageUp(); valueFromRecentList();}, + "PageDown": function(editor) { popup.gotoPageDown(); valueFromRecentList();} + }); + + function done() { + overlay.close(); + callback && callback(); + openPrompt = null; + } + + cmdLine.on("input", function() { + options.onInput && options.onInput(); + updateCompletions(); + }); + + function updateCompletions() { + if (options.getCompletions) { + var prefix; + if (options.getPrefix) { + prefix = options.getPrefix(cmdLine); + } + + var completions = options.getCompletions(cmdLine); + popup.setData(completions, prefix); + popup.resize(true); + } + } + + function valueFromRecentList() { + var current = popup.getData(popup.getRow()); + if (current && !current.error) + return current.value || current.caption || current; + } + + cmdLine.resize(true); + popup.resize(true); + cmdLine.focus(); + + openPrompt = { + close: done, + name: options.name, + editor: editor + }; +} + +prompt.gotoLine = function(editor, callback) { + function stringifySelection(selection) { + if (!Array.isArray(selection)) + selection = [selection]; + return selection.map(function(r) { + var cursor = r.isBackwards ? r.start: r.end; + var anchor = r.isBackwards ? r.end: r.start; + var row = anchor.row; + var s = (row + 1) + ":" + anchor.column; + + if (anchor.row == cursor.row) { + if (anchor.column != cursor.column) + s += ">" + ":" + cursor.column; + } else { + s += ">" + (cursor.row + 1) + ":" + cursor.column; + } + return s; + }).reverse().join(", "); + } + + prompt(editor, ":" + stringifySelection(editor.selection.toJSON()), { + name: "gotoLine", + selection: [1, Number.MAX_VALUE], + onAccept: function(data) { + var value = data.value; + var _history = prompt.gotoLine._history; + if (!_history) + prompt.gotoLine._history = _history = []; + if (_history.indexOf(value) != -1) + _history.splice(_history.indexOf(value), 1); + _history.unshift(value); + if (_history.length > 20) _history.length = 20; + + + var pos = editor.getCursorPosition(); + var ranges = []; + value.replace(/^:/, "").split(/,/).map(function(str) { + var parts = str.split(/([<>:+-]|c?\d+)|[^c\d<>:+-]+/).filter(Boolean); + var i = 0; + function readPosition() { + var c = parts[i++]; + if (!c) return; + if (c[0] == "c") { + var index = parseInt(c.slice(1)) || 0; + return editor.session.doc.indexToPosition(index); + } + var row = pos.row; + var column = 0; + if (/\d/.test(c)) { + row = parseInt(c) - 1; + c = parts[i++]; + } + if (c == ":") { + c = parts[i++]; + if (/\d/.test(c)) { + column = parseInt(c) || 0; + } + } + return {row: row, column: column}; + } + pos = readPosition(); + var range = Range.fromPoints(pos, pos); + if (parts[i] == ">") { + i++; + range.end = readPosition(); + } + else if (parts[i] == "<") { + i++; + range.start = readPosition(); + } + ranges.unshift(range); + }); + editor.selection.fromJSON(ranges); + var scrollTop = editor.renderer.scrollTop; + editor.renderer.scrollSelectionIntoView( + editor.selection.anchor, + editor.selection.cursor, + 0.5 + ); + editor.renderer.animateScrolling(scrollTop); + }, + history: function() { + var undoManager = editor.session.getUndoManager(); + if (!prompt.gotoLine._history) + return []; + return prompt.gotoLine._history; + + }, + getCompletions: function(cmdLine) { + var value = cmdLine.getValue(); + var m = value.replace(/^:/, "").split(":"); + var row = Math.min(parseInt(m[0]) || 1, editor.session.getLength()) - 1; + var line = editor.session.getLine(row); + var current = value + " " + line; + return [current].concat(this.history()); + }, + $rules: { + start: [{ + regex: /\d+/, + token: "string" + }, { + regex: /[:,><+\-c]/, + token: "keyword" + }] + } + }); +}; + +prompt.commands = function(editor, callback) { + function normalizeName(name) { + return (name || "").replace(/^./, function(x) { + return x.toUpperCase(x); + }).replace(/[a-z][A-Z]/g, function(x) { + return x[0] + " " + x[1].toLowerCase(x); + }); + } + function getEditorCommandsByName(excludeCommands) { + var commandsByName = []; + var commandMap = {}; + editor.keyBinding.$handlers.forEach(function(handler) { + var platform = handler.platform; + var cbn = handler.byName; + for (var i in cbn) { + var key; + if (cbn[i].bindKey && cbn[i].bindKey[platform] !== null) { + key = cbn[i].bindKey["win"]; + } else { + key = ""; + } + + var commands = cbn[i]; + var description = commands.description || normalizeName(commands.name); + if (!Array.isArray(commands)) + commands = [commands]; + commands.forEach(function(command) { + if (typeof command != "string") + command = command.name; + var needle = excludeCommands.find(function(el) { + return el === command; + }); + if (!needle) { + if (commandMap[command]) { + commandMap[command].key += "|" + key; + } else { + commandMap[command] = {key: key, command: command, description: description}; + commandsByName.push(commandMap[command]); + } + } + }); + } + }); + return commandsByName; + } + // exclude commands that can not be executed without args + var excludeCommandsList = ["insertstring", "inserttext", "setIndentation", "paste"]; + var shortcutsArray = getEditorCommandsByName(excludeCommandsList); + shortcutsArray = shortcutsArray.map(function(item) { + return {value: item.description, meta: item.key, command: item.command}; + }); + prompt(editor, "", { + name: "commands", + selection: [0, Number.MAX_VALUE], + maxHistoryCount: 5, + onAccept: function(data) { + if (data.item) { + var commandName = data.item.command; + this.addToHistory(data.item); + + editor.execCommand(commandName); + } + }, + addToHistory: function(item) { + var history = this.history(); + history.unshift(item); + delete item.message; + for (var i = 1; i < history.length; i++) { + if (history[i]["command"] == item.command ) { + history.splice(i, 1); + break; + } + } + if (this.maxHistoryCount > 0 && history.length > this.maxHistoryCount) { + history.splice(history.length - 1, 1); + } + prompt.commands.history = history; + }, + history: function() { + return prompt.commands.history || []; + }, + getPrefix: function(cmdLine) { + var currentPos = cmdLine.getCursorPosition(); + var filterValue = cmdLine.getValue(); + return filterValue.substring(0, currentPos.column); + }, + getCompletions: function(cmdLine) { + function getFilteredCompletions(commands, prefix) { + var resultCommands = JSON.parse(JSON.stringify(commands)); + + var filtered = new FilteredList(resultCommands); + return filtered.filterCompletions(resultCommands, prefix); + } + + function getUniqueCommandList(commands, usedCommands) { + if (!usedCommands || !usedCommands.length) { + return commands; + } + var excludeCommands = []; + usedCommands.forEach(function(item) { + excludeCommands.push(item.command); + }); + + var resultCommands = []; + + commands.forEach(function(item) { + if (excludeCommands.indexOf(item.command) === -1) { + resultCommands.push(item); + } + }); + + return resultCommands; + } + + var prefix = this.getPrefix(cmdLine); + var recentlyUsedCommands = getFilteredCompletions(this.history(), prefix); + var otherCommands = getUniqueCommandList(shortcutsArray, recentlyUsedCommands); + otherCommands = getFilteredCompletions(otherCommands, prefix); + + if (recentlyUsedCommands.length && otherCommands.length) { + recentlyUsedCommands[0]["message"] = " Recently used"; + otherCommands[0]["message"] = " Other commands"; + } + + var completions = recentlyUsedCommands.concat(otherCommands); + return completions.length > 0 ? completions : [{ + value: "No matching commands", + error: 1 + }]; + } + }); +}; + +prompt.modes = function(editor, callback) { + var modesArray = modelist.modes; + modesArray = modesArray.map(function(item) { + return {value: item.caption, mode: item.name}; + }); + prompt(editor, "", { + name: "modes", + selection: [0, Number.MAX_VALUE], + onAccept: function(data) { + if (data.item) { + var modeName = "ace/mode/" + data.item.mode; + editor.session.setMode(modeName); + } + }, + getPrefix: function(cmdLine) { + var currentPos = cmdLine.getCursorPosition(); + var filterValue = cmdLine.getValue(); + return filterValue.substring(0, currentPos.column); + }, + getCompletions: function(cmdLine) { + function getFilteredCompletions(modes, prefix) { + var resultCommands = JSON.parse(JSON.stringify(modes)); + + var filtered = new FilteredList(resultCommands); + return filtered.filterCompletions(resultCommands, prefix); + } + + var prefix = this.getPrefix(cmdLine); + var completions = getFilteredCompletions(modesArray, prefix); + return completions.length > 0 ? completions : [{ + "caption": "No mode matching", + "value": "No mode matching", + "error": 1 + }]; + } + }); +}; + +dom.importCssString(".ace_prompt_container {\ + max-width: 600px;\ + width: 100%;\ + margin: 20px auto;\ + padding: 3px;\ + background: white;\ + border-radius: 2px;\ + box-shadow: 0px 2px 3px 0px #555;\ +}"); + + +exports.prompt = prompt; + +}); diff --git a/lib/ace/ext/settings_menu.js b/lib/ace/ext/settings_menu.js index 7ead5f9eeca..b03dfffe411 100644 --- a/lib/ace/ext/settings_menu.js +++ b/lib/ace/ext/settings_menu.js @@ -60,7 +60,7 @@ function showSettingsMenu(editor) { var options = new OptionPanel(editor); options.render(); options.container.id = "ace_settingsmenu"; - overlayPage(editor, options.container, '0', '0', '0'); + overlayPage(editor, options.container); options.container.querySelector("select,input,button,checkbox").focus(); } } diff --git a/lib/ace/ext/whitespace.js b/lib/ace/ext/whitespace.js index d820a6902b4..b8044813618 100644 --- a/lib/ace/ext/whitespace.js +++ b/lib/ace/ext/whitespace.js @@ -216,23 +216,27 @@ exports.$parseArg = function(arg) { exports.commands = [{ name: "detectIndentation", + description: "Detect indentation from content", exec: function(editor) { exports.detectIndentation(editor.session); // todo show message? } }, { name: "trimTrailingSpace", + description: "Trim trailing whitespace", exec: function(editor, args) { exports.trimTrailingSpace(editor.session, args); } }, { name: "convertIndentation", + description: "Convert indentation to ...", exec: function(editor, arg) { var indent = exports.$parseArg(arg); exports.convertIndentation(editor.session, indent.ch, indent.length); } }, { name: "setIndentation", + description: "Set indentation", exec: function(editor, arg) { var indent = exports.$parseArg(arg); indent.length && editor.session.setTabSize(indent.length); diff --git a/lib/ace/selection.js b/lib/ace/selection.js index 6be44c7a8b4..bf44460341c 100644 --- a/lib/ace/selection.js +++ b/lib/ace/selection.js @@ -894,7 +894,7 @@ var Selection = function(session) { this.fromJSON = function(data) { if (data.start == undefined) { - if (this.rangeList) { + if (this.rangeList && data.length > 1) { this.toSingleRange(data[0]); for (var i = data.length; i--; ) { var r = Range.fromPoints(data[i].start, data[i].end); From 14a06c1d6027a4b1d967bb147a0a36dfe46cf6e3 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Tue, 16 Apr 2019 14:01:28 +0800 Subject: [PATCH 0149/1293] Fix wrong "span" It will append element like "[object HTMLSpanElement]" into valueFragment. --- lib/ace/layer/text.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index 5623bb427ec..b85d3ec43e3 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -387,7 +387,7 @@ var Text = function(parentEl) { valueFragment.appendChild(span); } else if (cjk) { screenColumn += 1; - var span = dom.createElement("span"); + var span = this.dom.createElement("span"); span.style.width = (self.config.characterWidth * 2) + "px"; span.className = "ace_cjk"; span.textContent = cjk; From 59985569f091b694822c987dcb965d6152ba3c4b Mon Sep 17 00:00:00 2001 From: Bruno Souza Date: Tue, 16 Apr 2019 11:27:04 -0300 Subject: [PATCH 0150/1293] Fix changes variable overwrite --- lib/ace/virtual_renderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 9dd767554d4..c82679aefcd 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -1061,7 +1061,7 @@ var VirtualRenderer = function(container, theme) { // Horizontal scrollbar visibility may have changed, which changes // the client height of the scroller if (hScrollChanged || vScrollChanged) { - changes = this.$updateCachedSize(true, this.gutterWidth, size.width, size.height); + changes += this.$updateCachedSize(true, this.gutterWidth, size.width, size.height); this._signal("scrollbarVisibilityChanged"); if (vScrollChanged) longestLine = this.$getLongestLine(); From 58a36fa805bd5cbe008a8df50d16a77770c4dedb Mon Sep 17 00:00:00 2001 From: Bruno Souza Date: Thu, 18 Apr 2019 09:25:24 -0300 Subject: [PATCH 0151/1293] Fix changes variable overwrite bitwise or --- lib/ace/virtual_renderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index c82679aefcd..6f3aea37625 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -1061,7 +1061,7 @@ var VirtualRenderer = function(container, theme) { // Horizontal scrollbar visibility may have changed, which changes // the client height of the scroller if (hScrollChanged || vScrollChanged) { - changes += this.$updateCachedSize(true, this.gutterWidth, size.width, size.height); + changes |= this.$updateCachedSize(true, this.gutterWidth, size.width, size.height); this._signal("scrollbarVisibilityChanged"); if (vScrollChanged) longestLine = this.$getLongestLine(); From c483663034186d036e43818db71829c0614eee6a Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 23 Apr 2019 02:47:09 +0400 Subject: [PATCH 0152/1293] fix outdent regression in lua mode --- index.html | 4 ++-- lib/ace/mode/folding/lua.js | 8 +++++++- lib/ace/mode/lua.js | 33 +++++++++++++++++++++++---------- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/index.html b/index.html index b9d80172890..8177ad17088 100644 --- a/index.html +++ b/index.html @@ -133,8 +133,8 @@

    History

    Related Projects

    diff --git a/lib/ace/mode/folding/lua.js b/lib/ace/mode/folding/lua.js index f4b52334259..30c824d9d7e 100644 --- a/lib/ace/mode/folding/lua.js +++ b/lib/ace/mode/folding/lua.js @@ -108,7 +108,7 @@ oop.inherits(FoldMode, BaseFoldMode); } }; - this.luaBlock = function(session, row, column) { + this.luaBlock = function(session, row, column, tokenRange) { var stream = new TokenIterator(session, row, column); var indentKeywords = { "function": 1, @@ -151,6 +151,12 @@ oop.inherits(FoldMode, BaseFoldMode); } } + if (!token) + return null; + + if (tokenRange) + return stream.getCurrentTokenRange(); + var row = stream.getCurrentTokenRow(); if (dir === -1) return new Range(row, session.getLine(row).length, startRow, startColumn); diff --git a/lib/ace/mode/lua.js b/lib/ace/mode/lua.js index 51c9304c557..752ce69dd6c 100644 --- a/lib/ace/mode/lua.js +++ b/lib/ace/mode/lua.js @@ -131,18 +131,31 @@ oop.inherits(Mode, TextMode); return (tokens[0].type == "keyword" && outdentKeywords.indexOf(tokens[0].value) != -1); }; + this.getMatching = function(session, row, column) { + if (row == undefined) { + var pos = session.selection.lead; + column = pos.column; + row = pos.row; + } + + var startToken = session.getTokenAt(row, column); + if (startToken && startToken.value in indentKeywords) + return this.foldingRules.luaBlock(session, row, column, true); + }; + this.autoOutdent = function(state, session, row) { - var prevLine = session.getLine(row - 1); - var prevIndent = this.$getIndent(prevLine).length; - var prevTokens = this.getTokenizer().getLineTokens(prevLine, "start").tokens; - var tabLength = session.getTabString().length; - var expectedIndent = prevIndent + tabLength * getNetIndentLevel(prevTokens); - var curIndent = this.$getIndent(session.getLine(row)).length; - if (curIndent <= expectedIndent) { - // User already outdented // - return; + var line = session.getLine(row); + var column = line.match(/^\s*/)[0].length; + if (!column || !row) return; + + var startRange = this.getMatching(session, row, column + 1); + if (!startRange || startRange.start.row == row) + return; + var indent = this.$getIndent(session.getLine(startRange.start.row)); + if (indent.length != column) { + session.replace(new Range(row, 0, row, column), indent); + session.outdentRows(new Range(row + 1, 0, row + 1, 0)); } - session.outdentRows(new Range(row, 0, row + 2, 0)); }; this.createWorker = function(session) { From 2a0d9ab03d5ce263c0ae8a280b3a4dd898be9936 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 24 Apr 2019 22:19:38 +0400 Subject: [PATCH 0153/1293] release v1.4.4 --- ChangeLog.txt | 5 +++++ build | 2 +- lib/ace/ace.js | 2 +- lib/ace/ext/modelist.js | 2 +- package.json | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 6be5d6d98b1..06d9e104305 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,8 @@ +2019.04.24 Version 1.4.4 +* add experimental command prompt +* add chrystal, nim and nginx highlight rules +* fix regression in vim mode on ios + 2019.02.21 Version 1.4.3 * add sublime keybindings * add rtl option diff --git a/build b/build index f17f0751fc4..5fe4368221f 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit f17f0751fc4c2bb73cd9340e9cbc02e4d979608f +Subproject commit 5fe4368221f48b114387c2e7d67c9cd904ec30a2 diff --git a/lib/ace/ace.js b/lib/ace/ace.js index a40add50732..e34003b670e 100644 --- a/lib/ace/ace.js +++ b/lib/ace/ace.js @@ -132,5 +132,5 @@ exports.Editor = Editor; exports.EditSession = EditSession; exports.UndoManager = UndoManager; exports.VirtualRenderer = Renderer; -exports.version = "1.4.3"; +exports.version = "1.4.4"; }); diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index f22ffc08f4f..bb14e3455ce 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -166,7 +166,7 @@ var supportedModes = { Rust: ["rs"], SASS: ["sass"], SCAD: ["scad"], - Scala: ["scala"], + Scala: ["scala|sbt"], Scheme: ["scm|sm|rkt|oak|scheme"], SCSS: ["scss"], SH: ["sh|bash|^.bashrc"], diff --git a/package.json b/package.json index 7d4405cd5f1..30b08a160d2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.4.3", + "version": "1.4.4", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" From 9d90696f6bcae3bcc7b16bd714a39e4c2fec9588 Mon Sep 17 00:00:00 2001 From: Kevin Ushey Date: Thu, 25 Apr 2019 09:47:11 -0700 Subject: [PATCH 0154/1293] fix external selection check (closes #3943) --- lib/ace/keyboard/vim.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index a9a04f8749d..acfb9a8c279 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -5854,7 +5854,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ } vim.fakeCursor = cm.markText(from, to, {className: 'cm-animate-fat-cursor'}); } - function handleExternalSelection(cm, vim) { + function handleExternalSelection(cm, vim, keepHPos) { var anchor = cm.getCursor('anchor'); var head = cm.getCursor('head'); // Enter or exit visual mode to match mouse selection. @@ -5878,7 +5878,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ }; updateMark(cm, vim, '<', cursorMin(head, anchor)); updateMark(cm, vim, '>', cursorMax(head, anchor)); - } else if (!vim.insertMode) { + } else if (!vim.insertMode && !keepHPos) { // Reset lastHPos if selection was modified by something outside of vim mode e.g. by mouse. vim.lastHPos = cm.getCursor().ch; } @@ -6064,15 +6064,16 @@ dom.importCssString(".normal-mode .ace_cursor{\ var isHandled = false; var vim = Vim.maybeInitVimState_(cm); var visualBlock = vim.visualBlock || vim.wasInVisualBlock; - if (vim.wasInVisualBlock && !cm.ace.inMultiSelectMode) { + if (vim.wasInVisualBlock && !wasMultiselect) { vim.wasInVisualBlock = false; - } else if (cm.ace.inMultiSelectMode && vim.visualBlock) { + } else if (wasMultiselect && vim.visualBlock) { vim.wasInVisualBlock = true; } - if (key == '' && !vim.insertMode && !vim.visualMode && cm.ace.inMultiSelectMode) { + var wasMultiselect = cm.ace.inMultiSelectMode; + if (key == '' && !vim.insertMode && !vim.visualMode && wasMultiselect) { cm.ace.exitMultiSelectMode(); - } else if (visualBlock || !cm.ace.inMultiSelectMode || cm.ace.inVirtualSelectionMode) { + } else if (visualBlock || !wasMultiselect || cm.ace.inVirtualSelectionMode) { isHandled = Vim.handleKey(cm, key, origin); } else { var old = cloneVimState(vim); @@ -6099,8 +6100,10 @@ dom.importCssString(".normal-mode .ace_cursor{\ cm.curOp.cursorActivity = false; }, true); } - if (isHandled && !vim.visualMode && !vim.insert) - handleExternalSelection(cm, vim); + // ace commands like ctrl-alt-l may bring visualMode and selection out of sync + if (isHandled && !vim.visualMode && !vim.insert && vim.visualMode != cm.somethingSelected()) { + handleExternalSelection(cm, vim, true); + } return isHandled; } exports.CodeMirror = CodeMirror; From db76ae82ea3dc7837421a604d7bd35bdbc148810 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 6 May 2019 17:44:21 +0400 Subject: [PATCH 0155/1293] add tests --- lib/ace/keyboard/vim.js | 32 ++++++++++++++++++-------------- lib/ace/keyboard/vim_test.js | 27 ++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index acfb9a8c279..c2166f7c9f8 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -2400,6 +2400,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ vim.lastEditActionCommand = actionCommand; macroModeState.lastInsertModeChanges.changes = []; macroModeState.lastInsertModeChanges.expectCursorActivityForChange = false; + macroModeState.lastInsertModeChanges.visualBlock = vim.visualBlock ? vim.sel.head.line - vim.sel.anchor.line : 0; } }; @@ -2530,7 +2531,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ if (line < first && cur.line == first){ return this.moveToStartOfLine(cm, head, motionArgs, vim); }else if (line > last && cur.line == last){ - return this.moveToEol(cm, head, motionArgs, vim); + return this.moveToEol(cm, head, motionArgs, vim, true); } // ace_patch{ var fold = cm.ace.session.getFoldLine(line); @@ -2639,13 +2640,15 @@ dom.importCssString(".normal-mode .ace_cursor{\ vim.lastHSPos = cm.charCoords(head,'div').left; return moveToColumn(cm, repeat); }, - moveToEol: function(cm, head, motionArgs, vim) { + moveToEol: function(cm, head, motionArgs, vim, keepHPos) { var cur = head; - vim.lastHPos = Infinity; var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity); var end=cm.clipPos(retval); end.ch--; - vim.lastHSPos = cm.charCoords(end,'div').left; + if (!keepHPos) { + vim.lastHPos = Infinity; + vim.lastHSPos = cm.charCoords(end,'div').left; + } return retval; }, moveToFirstNonWhiteSpaceCharacter: function(cm, head) { @@ -2786,7 +2789,6 @@ dom.importCssString(".normal-mode .ace_cursor{\ change: function(cm, args, ranges) { var finalHead, text; var vim = cm.state.vim; - vimGlobalState.macroModeState.lastInsertModeChanges.inVisualBlock = vim.visualBlock; if (!vim.visualMode) { var anchor = ranges[0].anchor, head = ranges[0].head; @@ -3046,6 +3048,8 @@ dom.importCssString(".normal-mode .ace_cursor{\ } else if (insertAt == 'firstNonBlank') { head = motions.moveToFirstNonWhiteSpaceCharacter(cm, head); } else if (insertAt == 'startOfSelectedArea') { + if (!vim.visualMode) + return; if (!vim.visualBlock) { if (sel.head.line < sel.anchor.line) { head = sel.head; @@ -3059,6 +3063,8 @@ dom.importCssString(".normal-mode .ace_cursor{\ height = Math.abs(sel.head.line - sel.anchor.line) + 1; } } else if (insertAt == 'endOfSelectedArea') { + if (!vim.visualMode) + return; if (!vim.visualBlock) { if (sel.head.line >= sel.anchor.line) { head = offsetCursor(sel.head, 0, 1); @@ -5978,18 +5984,15 @@ dom.importCssString(".normal-mode .ace_cursor{\ return true; } var head = cm.getCursor('head'); - var inVisualBlock = vimGlobalState.macroModeState.lastInsertModeChanges.inVisualBlock; - if (inVisualBlock) { + var visualBlock = vimGlobalState.macroModeState.lastInsertModeChanges.visualBlock; + if (visualBlock) { // Set up block selection again for repeating the changes. - var vim = cm.state.vim; - var lastSel = vim.lastSelection; - var offset = getOffset(lastSel.anchor, lastSel.head); - selectForInsert(cm, head, offset.line + 1); + selectForInsert(cm, head, visualBlock + 1); repeat = cm.listSelections().length; cm.setCursor(head); } for (var i = 0; i < repeat; i++) { - if (inVisualBlock) { + if (visualBlock) { cm.setCursor(offsetCursor(head, i, 0)); } for (var j = 0; j < changes.length; j++) { @@ -6006,7 +6009,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ } } } - if (inVisualBlock) { + if (visualBlock) { cm.setCursor(offsetCursor(head, 0, 1)); } } @@ -6064,13 +6067,14 @@ dom.importCssString(".normal-mode .ace_cursor{\ var isHandled = false; var vim = Vim.maybeInitVimState_(cm); var visualBlock = vim.visualBlock || vim.wasInVisualBlock; + + var wasMultiselect = cm.ace.inMultiSelectMode; if (vim.wasInVisualBlock && !wasMultiselect) { vim.wasInVisualBlock = false; } else if (wasMultiselect && vim.visualBlock) { vim.wasInVisualBlock = true; } - var wasMultiselect = cm.ace.inMultiSelectMode; if (key == '' && !vim.insertMode && !vim.visualMode && wasMultiselect) { cm.ace.exitMultiSelectMode(); } else if (visualBlock || !wasMultiselect || cm.ace.inVirtualSelectionMode) { diff --git a/lib/ace/keyboard/vim_test.js b/lib/ace/keyboard/vim_test.js index cbe92ab1686..8a4316f9fde 100644 --- a/lib/ace/keyboard/vim_test.js +++ b/lib/ace/keyboard/vim_test.js @@ -231,7 +231,10 @@ function testVim(name, run, opts, expectedFail) { arguments = args; } for (var i = 0; i < arguments.length; i++) { - var result = CodeMirror.Vim.handleKey(cm, arguments[i]); + var ch = arguments[i]; + var result = ch.length == 1 + ? cm.ace.keyBinding.$callKeyboardHandlers(-1, ch, 0) + : CodeMirror.Vim.handleKey(cm, arguments[i]); if (!result && cm.state.vim.insertMode) { cm.replaceSelections(fillArray(arguments[i], cm.listSelections().length)); } @@ -1141,6 +1144,28 @@ testVim('c_visual_block_replay', function(cm, vim, helpers) { helpers.doKeys('.'); eq('foo4\nfoo8\nfoodefg', cm.getValue()); }, {value: '1234\n5678\nabcdefg'}); +testVim('I_visual_block_replay', function(cm, vim, helpers) { + cm.setCursor(0, 2); + helpers.doKeys('', '2', 'j', 'l', 'I'); + var replacement = fillArray('+-', 3); + cm.replaceSelections(replacement); + eq('12+-34\n56+-78\nab+-cdefg\nxyz', cm.getValue()); + helpers.doKeys(''); + // ensure that repeat location doesn't depend on last selection + cm.setCursor(3, 2); + helpers.doKeys('g', 'v') + eq("+-34\n+-78\n+-cd", cm.getSelection()) + cm.setCursor(0, 3); + helpers.doKeys('', '1', 'j', '2', 'l'); + eq("-34\n-78", cm.getSelection()); + cm.setCursor(0, 0); + eq("", cm.getSelection()); + helpers.doKeys('g', 'v'); + eq("-34\n-78", cm.getSelection()); + cm.setCursor(1, 1); + helpers.doKeys('.'); + eq('12+-34\n5+-6+-78\na+-b+-cdefg\nx+-yz', cm.getValue()); +}, {value: '1234\n5678\nabcdefg\nxyz'}); testVim('d_visual_block', function(cm, vim, helpers) { cm.setCursor(0, 1); From 70bf1447e9ffed3a591e309b2f2e505c1849bc8a Mon Sep 17 00:00:00 2001 From: nppoly Date: Thu, 9 May 2019 11:30:35 +0800 Subject: [PATCH 0156/1293] fix addMarker type --- ace.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ace.d.ts b/ace.d.ts index 1241ee83d8b..a1c7d2b9c81 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -439,7 +439,7 @@ export namespace Ace { clearBreakpoint(row: number): void; addMarker(range: Range, clazz: string, - type: MarkerRenderer, + type: MarkerRenderer | string, inFront: boolean): number; addDynamicMarker(marker: MarkerLike, inFront: boolean): MarkerLike; removeMarker(markerId: number): void; From 448b2edbcb93e5cb2d2f12a346fe139476756f8b Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 9 May 2019 10:06:10 -0700 Subject: [PATCH 0157/1293] Rename Bro to Zeek and improve syntax highlighting --- demo/kitchen-sink/docs/bro.bro | 26 - demo/kitchen-sink/docs/zeek.zeek | 179 +++ lib/ace/ext/modelist.js | 2 +- lib/ace/mode/_test/tokens_bro.json | 106 -- lib/ace/mode/_test/tokens_zeek.json | 1270 +++++++++++++++++ lib/ace/mode/bro_highlight_rules.js | 204 --- lib/ace/mode/{bro.js => zeek.js} | 12 +- lib/ace/mode/zeek_highlight_rules.js | 407 ++++++ lib/ace/snippets/{bro.js => zeek.js} | 2 +- .../snippets/{bro.snippets => zeek.snippets} | 0 10 files changed, 1863 insertions(+), 345 deletions(-) delete mode 100644 demo/kitchen-sink/docs/bro.bro create mode 100644 demo/kitchen-sink/docs/zeek.zeek delete mode 100644 lib/ace/mode/_test/tokens_bro.json create mode 100644 lib/ace/mode/_test/tokens_zeek.json delete mode 100644 lib/ace/mode/bro_highlight_rules.js rename lib/ace/mode/{bro.js => zeek.js} (88%) create mode 100644 lib/ace/mode/zeek_highlight_rules.js rename lib/ace/snippets/{bro.js => zeek.js} (55%) rename lib/ace/snippets/{bro.snippets => zeek.snippets} (100%) diff --git a/demo/kitchen-sink/docs/bro.bro b/demo/kitchen-sink/docs/bro.bro deleted file mode 100644 index 937d37dcd39..00000000000 --- a/demo/kitchen-sink/docs/bro.bro +++ /dev/null @@ -1,26 +0,0 @@ -##! Add countries for the originator and responder of a connection -##! to the connection logs. - -module Conn; - -export { - redef record Conn::Info += { - ## Country code for the originator of the connection based - ## on a GeoIP lookup. - orig_cc: string &optional &log; - ## Country code for the responser of the connection based - ## on a GeoIP lookup. - resp_cc: string &optional &log; - }; -} - -event connection_state_remove(c: connection) - { - local orig_loc = lookup_location(c$id$orig_h); - if ( orig_loc?$country_code ) - c$conn$orig_cc = orig_loc$country_code; - - local resp_loc = lookup_location(c$id$resp_h); - if ( resp_loc?$country_code ) - c$conn$resp_cc = resp_loc$country_code; - } \ No newline at end of file diff --git a/demo/kitchen-sink/docs/zeek.zeek b/demo/kitchen-sink/docs/zeek.zeek new file mode 100644 index 00000000000..a4c4bb7c50e --- /dev/null +++ b/demo/kitchen-sink/docs/zeek.zeek @@ -0,0 +1,179 @@ +# An example of the Zeek scripting language. + +##! A Zeekygen-style summmary comment. + +# TODO: just an example of a todo-indicator + +@load base/frameworks/notice + +@if ( F ) +@endif + +module Example; + +export { + + type SimpleEnum: enum { ONE, TWO, THREE }; + + redef enum SimpleEnum += { + + ## A Zeekygen-style comment. + FOUR, + FIVE, ##< A Zeekygen-style comment. + }; + + type SimpleRecord: record { + field1: count; + field2: bool; + } &redef; + + redef record SimpleRecord += { + + field3: string &optional; + + field4: string &default="blah"; + }; + + const init_option: bool = T; + + option runtime_option: bool = F; + + global test_opaque: opaque of md5; + + global test_vector: vector of count; + + global myfunction: function(msg: string, c: count &default=0): count; + + global myhook: hook(tag: string); + + global myevent: event(tag: string); +} + +function myfunction(msg: string, c: count): count + { + print "in myfunction", msg, c; + return 0; + } + +event myevent(msg: string) &priority=1 + { + print "in myevent"; + } + +hook myhook(msg: string) + { + print "in myevent"; + } + +event zeek_init() + { + local b = T; + local s = "\xff\xaf\"and more after the escaped quote"; + local p = /foo|bar\xbe\/and more after the escaped slash/; + local c = 10; + + local sr = SimpleRecord($field1 = 0, $field2 = T, $field3 = "hi"); + + print sr?$field3, sr$field1; + + local myset: set[string] = set("one", "two", "three"); + + add myset["four"]; + delete myset["one"]; + + for ( ms in myset ) + { + print ms is string, s as string; + + print s[1:3]; + + local tern: count = s == "two" ? 2 : 0; + + if ( s !in myset ) + print fmt("error %4.2f: %s", 3.14159, "wtf?"); + } + + switch ( c ) { + case 1: + break; + case 2: + fallthrough; + default: + break; + } + + if ( ! b ) + print "here"; + else + print "there"; + + while ( c != 0 ) + { + if ( c >= 5 ) + c += 0; + else if ( c == 8 ) + c -= 0; + + c = c / 1; + c = c / 1; + c = c - 1; + } + + print |myset|; + print ~5; + print 1 & 0xff; + print 2 ^ 5; + + myfunction("hello function"); + hook myhook("hell hook"); + event myevent("hello event"); + schedule 1sec { myevent("hello scheduled event") }; + + print 0, 7; + print 0xff, 0xdeadbeef; + + print 3.14159; + print 1234.0; + print 1234e0; + print .003E-23; + print .003E+23; + + print 123/udp; + print 8000/tcp; + print 13/icmp; + print 42/unknown; + + print google.com; + print 192.168.50.1; + print 255.255.255.255; + print 0.0.0.0; + + print 10.0.0.0/16; + + print [2001:0db8:85a3:0000:0000:8a2e:0370:7334]; + # test for case insensitivity + print [2001:0DB8:85A3:0000:0000:8A2E:0370:7334]; + # any case mixture is allowed + print [2001:0dB8:85a3:0000:0000:8A2E:0370:7334]; + # leading zeroes of a 16-bit group may be omitted + print [2001:db8:85a3:0:0:8a2e:370:7334]; + # a single occurrence of consecutive groups of zeroes may be replaced by :: + print [2001:db8:85a3::8a2e:370:7334]; + # all zeroes should work + print [0:0:0:0:0:0:0:0]; + # all zeroes condensed should work + print [::]; + # hybrid ipv6-ipv4 address should work + print [2001:db8:0:0:0:FFFF:192.168.0.5]; + # hybrid ipv6-ipv4 address with zero ommission should work + print [2001:db8::FFFF:192.168.0.5]; + + print [2001:0db8:85a3:0000:0000:8a2e:0370:7334]/64; + + print 1day, 1days, 1.0day, 1.0days; + print 1hr, 1hrs, 1.0hr, 1.0hrs; + print 1min, 1mins, 1.0min, 1.0mins; + print 1sec, 1secs, 1.0sec, 1.0secs; + print 1msec, 1msecs, 1.0msec, 1.0msecs; + print 1usec, 1usecs, 1.0usec, 1.0usecs; + } diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index bb14e3455ce..021e7fb06a5 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -55,7 +55,6 @@ var supportedModes = { Apex: ["apex|cls|trigger|tgr"], AQL: ["aql"], BatchFile: ["bat|cmd"], - Bro: ["bro"], C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp|ino"], C9Search: ["c9search_results"], Crystal: ["cr"], @@ -200,6 +199,7 @@ var supportedModes = { XML: ["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"], XQuery: ["xq"], YAML: ["yaml|yml"], + Zeek: ["zeek|bro"], // Add the missing mode "Django" to ext-modelist Django: ["html"] }; diff --git a/lib/ace/mode/_test/tokens_bro.json b/lib/ace/mode/_test/tokens_bro.json deleted file mode 100644 index b0f42015ae4..00000000000 --- a/lib/ace/mode/_test/tokens_bro.json +++ /dev/null @@ -1,106 +0,0 @@ -[[ - "start", - ["punctuation.definition.comment.bro","#"], - ["comment.line.number-sign.bro","#! Add countries for the originator and responder of a connection"] -],[ - "start", - ["punctuation.definition.comment.bro","#"], - ["comment.line.number-sign.bro","#! to the connection logs."] -],[ - "start" -],[ - "start", - ["text","module Conn;"] -],[ - "start" -],[ - "start", - ["text","export {"] -],[ - "start", - ["text","\t"], - ["storage.modifier.bro","redef"], - ["text"," "], - ["storage.type.bro","record"], - ["text"," Conn::Info += {"] -],[ - "start", - ["text","\t\t"], - ["punctuation.definition.comment.bro","#"], - ["comment.line.number-sign.bro","# Country code for the originator of the connection based "] -],[ - "start", - ["text","\t\t"], - ["punctuation.definition.comment.bro","#"], - ["comment.line.number-sign.bro","# on a GeoIP lookup."] -],[ - "start", - ["text","\t\torig_cc: "], - ["storage.type.bro","string"], - ["text"," &optional &log;"] -],[ - "start", - ["text","\t\t"], - ["punctuation.definition.comment.bro","#"], - ["comment.line.number-sign.bro","# Country code for the responser of the connection based "] -],[ - "start", - ["text","\t\t"], - ["punctuation.definition.comment.bro","#"], - ["comment.line.number-sign.bro","# on a GeoIP lookup."] -],[ - "start", - ["text","\t\tresp_cc: "], - ["storage.type.bro","string"], - ["text"," &optional &log;"] -],[ - "start", - ["text","\t};"] -],[ - "start", - ["text","}"] -],[ - "start" -],[ - "start", - ["meta.function.bro"," "], - ["storage.type.bro","connection_state_remove"], - ["meta.function.bro","("], - ["entity.name.function.bro","c: connection"], - ["meta.function.bro",") "], - "event connection_state_remove(c: connection) " -],[ - "start", - ["text","\t{"] -],[ - "start", - ["text","\t"], - ["storage.modifier.bro","local"], - ["text"," orig_loc = lookup_location(c$id$orig_h);"] -],[ - "start", - ["text","\t"], - ["keyword.control.bro","if"], - ["text"," ( orig_loc?$country_code )"] -],[ - "start", - ["text","\t\tc$conn$orig_cc = orig_loc$country_code;"] -],[ - "start" -],[ - "start", - ["text","\t"], - ["storage.modifier.bro","local"], - ["text"," resp_loc = lookup_location(c$id$resp_h);"] -],[ - "start", - ["text","\t"], - ["keyword.control.bro","if"], - ["text"," ( resp_loc?$country_code )"] -],[ - "start", - ["text","\t\tc$conn$resp_cc = resp_loc$country_code;"] -],[ - "start", - ["text","\t}"] -]] \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_zeek.json b/lib/ace/mode/_test/tokens_zeek.json new file mode 100644 index 00000000000..d9695b28c72 --- /dev/null +++ b/lib/ace/mode/_test/tokens_zeek.json @@ -0,0 +1,1270 @@ +[[ + "start", + ["comment.line","# An example of the Zeek scripting language."] +],[ + "start" +],[ + "start", + ["comment.line","##! A Zeekygen-style summmary comment."] +],[ + "start" +],[ + "start", + ["comment.line","# TODO: just an example of a todo-indicator"] +],[ + "start" +],[ + "start", + ["keyword.other","@load"], + ["meta.preprocessor"," base/frameworks/notice"] +],[ + "start" +],[ + "start", + ["keyword.other","@if"], + ["text"," "], + ["punctuation.section.parens.begin","("], + ["text"," "], + ["constant.language","F"], + ["text"," "], + ["punctuation.section.parens.end",")"] +],[ + "start", + ["keyword.other","@endif"] +],[ + "start" +],[ + "start", + ["keyword.other","module"], + ["meta.namespace"," "], + ["entity.name.namespace","Example"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["keyword.other","export"], + ["text"," "], + ["punctuation.section.block.begin","{"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","type"], + ["meta.enum"," "], + ["entity.name.enum","SimpleEnum"], + ["punctuation.separator",":"], + ["meta.enum"," "], + ["storage.type.enum","enum"], + ["text"," "], + ["punctuation.section.block.begin","{"], + ["text"," ONE"], + ["punctuation.separator",","], + ["text"," TWO"], + ["punctuation.separator",","], + ["text"," THREE "], + ["punctuation.section.block.end","}"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","redef"], + ["meta.enum"," "], + ["storage.type.enum","enum"], + ["meta.enum"," "], + ["entity.name.enum","SimpleEnum"], + ["text"," "], + ["keyword.operator","+="], + ["text"," "], + ["punctuation.section.block.begin","{"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment.line","## A Zeekygen-style comment."] +],[ + "start", + ["text"," FOUR"], + ["punctuation.separator",","] +],[ + "start", + ["text"," FIVE"], + ["punctuation.separator",","], + ["text"," "], + ["comment.line","##< A Zeekygen-style comment."] +],[ + "start", + ["text"," "], + ["punctuation.section.block.end","}"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","type"], + ["meta.struct.record"," "], + ["entity.name.struct.record","SimpleRecord"], + ["punctuation.separator",":"], + ["meta.struct.record"," "], + ["storage.type.struct.record","record"], + ["text"," "], + ["punctuation.section.block.begin","{"] +],[ + "start", + ["text"," field1"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","count"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," field2"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","bool"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.end","}"], + ["text"," "], + ["storage.modifier.attribute","&redef"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","redef"], + ["meta.struct.record"," "], + ["storage.type.struct.record","record"], + ["meta.struct.record"," "], + ["entity.name.struct.record","SimpleRecord"], + ["text"," "], + ["keyword.operator","+="], + ["text"," "], + ["punctuation.section.block.begin","{"] +],[ + "start" +],[ + "start", + ["text"," field3"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","string"], + ["text"," "], + ["storage.modifier.attribute","&optional"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," field4"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","string"], + ["text"," "], + ["storage.modifier.attribute","&default"], + ["keyword.operator","="], + ["string.double","\"blah\""], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.end","}"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.modifier","const"], + ["text"," init_option"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","bool"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.language","T"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.modifier","option"], + ["text"," runtime_option"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","bool"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.language","F"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.modifier","global"], + ["text"," test_opaque"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","opaque"], + ["text"," "], + ["keyword.operator","of"], + ["text"," "], + ["storage.type","md5"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.modifier","global"], + ["text"," test_vector"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","vector"], + ["text"," "], + ["keyword.operator","of"], + ["text"," "], + ["storage.type","count"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.modifier","global"], + ["text"," myfunction"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","function"], + ["punctuation.section.parens.begin","("], + ["text","msg"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","string"], + ["punctuation.separator",","], + ["text"," c"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","count"], + ["text"," "], + ["storage.modifier.attribute","&default"], + ["keyword.operator","="], + ["constant.numeric.integer.decimal","0"], + ["punctuation.section.parens.end",")"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","count"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.modifier","global"], + ["text"," myhook"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","hook"], + ["punctuation.section.parens.begin","("], + ["text","tag"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","string"], + ["punctuation.section.parens.end",")"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.modifier","global"], + ["text"," myevent"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","event"], + ["punctuation.section.parens.begin","("], + ["text","tag"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","string"], + ["punctuation.section.parens.end",")"], + ["punctuation.terminator",";"] +],[ + "start", + ["punctuation.section.block.end","}"] +],[ + "start" +],[ + "start", + ["storage.type","function"], + ["text"," "], + ["entity.name.function","myfunction"], + ["punctuation.section.parens.begin","("], + ["text","msg"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","string"], + ["punctuation.separator",","], + ["text"," c"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","count"], + ["punctuation.section.parens.end",")"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","count"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.begin","{"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["string.double","\"in myfunction\""], + ["punctuation.separator",","], + ["text"," msg"], + ["punctuation.separator",","], + ["text"," c"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.control","return"], + ["text"," "], + ["constant.numeric.integer.decimal","0"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.end","}"] +],[ + "start" +],[ + "start", + ["storage.type","event"], + ["text"," "], + ["entity.name.function.event","myevent"], + ["punctuation.section.parens.begin","("], + ["text","msg"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","string"], + ["punctuation.section.parens.end",")"], + ["text"," "], + ["storage.modifier.attribute","&priority"], + ["keyword.operator","="], + ["constant.numeric.integer.decimal","1"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.begin","{"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["string.double","\"in myevent\""], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.end","}"] +],[ + "start" +],[ + "start", + ["storage.type","hook"], + ["text"," "], + ["entity.name.function.hook","myhook"], + ["punctuation.section.parens.begin","("], + ["text","msg"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","string"], + ["punctuation.section.parens.end",")"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.begin","{"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["string.double","\"in myevent\""], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.end","}"] +],[ + "start" +],[ + "start", + ["storage.type","event"], + ["text"," "], + ["entity.name.function.event","zeek_init"], + ["punctuation.section.parens.begin","("], + ["punctuation.section.parens.end",")"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.begin","{"] +],[ + "start", + ["text"," "], + ["storage.modifier","local"], + ["text"," b "], + ["keyword.operator","="], + ["text"," "], + ["constant.language","T"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["storage.modifier","local"], + ["text"," s "], + ["keyword.operator","="], + ["text"," "], + ["string.double","\""], + ["constant.character.escape","\\x"], + ["string.double","ff"], + ["constant.character.escape","\\x"], + ["string.double","af"], + ["constant.character.escape","\\\""], + ["string.double","and more after the escaped quote\""], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["storage.modifier","local"], + ["text"," p "], + ["keyword.operator","="], + ["text"," "], + ["string.regexp","/foo|bar"], + ["constant.character.escape","\\x"], + ["string.regexp","be"], + ["constant.character.escape","\\/"], + ["string.regexp","and more after the escaped slash/"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["storage.modifier","local"], + ["text"," c "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric.integer.decimal","10"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.modifier","local"], + ["text"," sr "], + ["keyword.operator","="], + ["text"," "], + ["entity.name.function.call","SimpleRecord"], + ["punctuation.section.parens.begin","("], + ["punctuation.accessor","$"], + ["text","field1 "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric.integer.decimal","0"], + ["punctuation.separator",","], + ["text"," "], + ["punctuation.accessor","$"], + ["text","field2 "], + ["keyword.operator","="], + ["text"," "], + ["constant.language","T"], + ["punctuation.separator",","], + ["text"," "], + ["punctuation.accessor","$"], + ["text","field3 "], + ["keyword.operator","="], + ["text"," "], + ["string.double","\"hi\""], + ["punctuation.section.parens.end",")"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," sr"], + ["punctuation.accessor","?$"], + ["text","field3"], + ["punctuation.separator",","], + ["text"," sr"], + ["punctuation.accessor","$"], + ["text","field1"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.modifier","local"], + ["text"," myset"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","set"], + ["punctuation.section.brackets.begin","["], + ["storage.type","string"], + ["punctuation.section.brackets.end","]"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["storage.type","set"], + ["punctuation.section.parens.begin","("], + ["string.double","\"one\""], + ["punctuation.separator",","], + ["text"," "], + ["string.double","\"two\""], + ["punctuation.separator",","], + ["text"," "], + ["string.double","\"three\""], + ["punctuation.section.parens.end",")"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","add"], + ["text"," myset"], + ["punctuation.section.brackets.begin","["], + ["string.double","\"four\""], + ["punctuation.section.brackets.end","]"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","delete"], + ["text"," myset"], + ["punctuation.section.brackets.begin","["], + ["string.double","\"one\""], + ["punctuation.section.brackets.end","]"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.control","for"], + ["text"," "], + ["punctuation.section.parens.begin","("], + ["text"," ms "], + ["keyword.operator","in"], + ["text"," myset "], + ["punctuation.section.parens.end",")"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.begin","{"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," ms "], + ["keyword.operator","is"], + ["text"," "], + ["storage.type","string"], + ["punctuation.separator",","], + ["text"," s "], + ["keyword.operator","as"], + ["text"," "], + ["storage.type","string"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," s"], + ["punctuation.section.brackets.begin","["], + ["constant.numeric.integer.decimal","1"], + ["punctuation.separator",":"], + ["constant.numeric.integer.decimal","3"], + ["punctuation.section.brackets.end","]"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.modifier","local"], + ["text"," tern"], + ["punctuation.separator",":"], + ["text"," "], + ["storage.type","count"], + ["text"," "], + ["keyword.operator","="], + ["text"," s "], + ["keyword.operator","=="], + ["text"," "], + ["string.double","\"two\""], + ["text"," "], + ["keyword.operator","?"], + ["text"," "], + ["constant.numeric.integer.decimal","2"], + ["text"," "], + ["punctuation.separator",":"], + ["text"," "], + ["constant.numeric.integer.decimal","0"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.control.conditional","if"], + ["text"," "], + ["punctuation.section.parens.begin","("], + ["text"," s "], + ["keyword.operator","!in"], + ["text"," myset "], + ["punctuation.section.parens.end",")"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["entity.name.function.call","fmt"], + ["punctuation.section.parens.begin","("], + ["string.double","\"error "], + ["constant.other.placeholder","%4.2f"], + ["string.double",": "], + ["constant.other.placeholder","%s"], + ["string.double","\""], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal","3.14159"], + ["punctuation.separator",","], + ["text"," "], + ["string.double","\"wtf?\""], + ["punctuation.section.parens.end",")"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.end","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.control","switch"], + ["text"," "], + ["punctuation.section.parens.begin","("], + ["text"," c "], + ["punctuation.section.parens.end",")"], + ["text"," "], + ["punctuation.section.block.begin","{"] +],[ + "start", + ["text"," "], + ["keyword.control","case"], + ["text"," "], + ["constant.numeric.integer.decimal","1"], + ["punctuation.separator",":"] +],[ + "start", + ["text"," "], + ["keyword.control","break"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.control","case"], + ["text"," "], + ["constant.numeric.integer.decimal","2"], + ["punctuation.separator",":"] +],[ + "start", + ["text"," "], + ["keyword.control","fallthrough"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.control","default"], + ["punctuation.separator",":"] +],[ + "start", + ["text"," "], + ["keyword.control","break"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.end","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.control.conditional","if"], + ["text"," "], + ["punctuation.section.parens.begin","("], + ["text"," "], + ["keyword.operator","!"], + ["text"," b "], + ["punctuation.section.parens.end",")"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["string.double","\"here\""], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.control.conditional","else"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["string.double","\"there\""], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.control","while"], + ["text"," "], + ["punctuation.section.parens.begin","("], + ["text"," c "], + ["keyword.operator","!="], + ["text"," "], + ["constant.numeric.integer.decimal","0"], + ["text"," "], + ["punctuation.section.parens.end",")"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.begin","{"] +],[ + "start", + ["text"," "], + ["keyword.control.conditional","if"], + ["text"," "], + ["punctuation.section.parens.begin","("], + ["text"," c "], + ["keyword.operator",">="], + ["text"," "], + ["constant.numeric.integer.decimal","5"], + ["text"," "], + ["punctuation.section.parens.end",")"] +],[ + "start", + ["text"," c "], + ["keyword.operator","+="], + ["text"," "], + ["constant.numeric.integer.decimal","0"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.control.conditional","else"], + ["text"," "], + ["keyword.control.conditional","if"], + ["text"," "], + ["punctuation.section.parens.begin","("], + ["text"," c "], + ["keyword.operator","=="], + ["text"," "], + ["constant.numeric.integer.decimal","8"], + ["text"," "], + ["punctuation.section.parens.end",")"] +],[ + "start", + ["text"," c "], + ["keyword.operator","-="], + ["text"," "], + ["constant.numeric.integer.decimal","0"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," c "], + ["keyword.operator","="], + ["text"," c "], + ["keyword.operator","/"], + ["text"," "], + ["constant.numeric.integer.decimal","1"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," c "], + ["keyword.operator","="], + ["text"," c "], + ["keyword.operator","/"], + ["text"," "], + ["constant.numeric.integer.decimal","1"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," c "], + ["keyword.operator","="], + ["text"," c "], + ["keyword.operator","-"], + ["text"," "], + ["constant.numeric.integer.decimal","1"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.end","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["keyword.operator","|"], + ["text","myset"], + ["keyword.operator","|"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["keyword.operator","~"], + ["constant.numeric.integer.decimal","5"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.integer.decimal","1"], + ["text"," "], + ["keyword.operator","&"], + ["text"," "], + ["constant.numeric.integer.hexadecimal","0xff"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.integer.decimal","2"], + ["text"," "], + ["keyword.operator","^"], + ["text"," "], + ["constant.numeric.integer.decimal","5"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["entity.name.function.call","myfunction"], + ["punctuation.section.parens.begin","("], + ["string.double","\"hello function\""], + ["punctuation.section.parens.end",")"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["storage.type","hook"], + ["text"," "], + ["entity.name.function.hook","myhook"], + ["punctuation.section.parens.begin","("], + ["string.double","\"hell hook\""], + ["punctuation.section.parens.end",")"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["storage.type","event"], + ["text"," "], + ["entity.name.function.event","myevent"], + ["punctuation.section.parens.begin","("], + ["string.double","\"hello event\""], + ["punctuation.section.parens.end",")"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.control","schedule"], + ["text"," "], + ["constant.numeric.float.decimal.interval","1sec"], + ["text"," "], + ["punctuation.section.block.begin","{"], + ["text"," "], + ["entity.name.function.call","myevent"], + ["punctuation.section.parens.begin","("], + ["string.double","\"hello scheduled event\""], + ["punctuation.section.parens.end",")"], + ["text"," "], + ["punctuation.section.block.end","}"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.integer.decimal","0"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.integer.decimal","7"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.integer.hexadecimal","0xff"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.integer.hexadecimal","0xdeadbeef"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.float.decimal","3.14159"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.float.decimal","1234.0"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.float.decimal","1234e0"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.float.decimal",".003E-23"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.float.decimal",".003E+23"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.port","123/udp"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.port","8000/tcp"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.port","13/icmp"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.port","42/unknown"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.hostname","google.com"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","192.168.50.1"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","255.255.255.255"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","0.0.0.0"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","10.0.0.0"], + ["keyword.operator","/"], + ["constant.numeric.integer.decimal","16"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["comment.line","# test for case insensitivity"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","[2001:0DB8:85A3:0000:0000:8A2E:0370:7334]"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["comment.line","# any case mixture is allowed"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","[2001:0dB8:85a3:0000:0000:8A2E:0370:7334]"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["comment.line","# leading zeroes of a 16-bit group may be omitted"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","[2001:db8:85a3:0:0:8a2e:370:7334]"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["comment.line","# a single occurrence of consecutive groups of zeroes may be replaced by ::"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","[2001:db8:85a3::8a2e:370:7334]"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["comment.line","# all zeroes should work"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","[0:0:0:0:0:0:0:0]"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["comment.line","# all zeroes condensed should work"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","[::]"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["comment.line","# hybrid ipv6-ipv4 address should work"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","[2001:db8:0:0:0:FFFF:192.168.0.5]"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["comment.line","# hybrid ipv6-ipv4 address with zero ommission should work"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","[2001:db8::FFFF:192.168.0.5]"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.addr","[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"], + ["keyword.operator","/"], + ["constant.numeric.integer.decimal","64"], + ["punctuation.terminator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.float.decimal.interval","1day"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1days"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0day"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0days"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.float.decimal.interval","1hr"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1hrs"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0hr"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0hrs"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.float.decimal.interval","1min"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1mins"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0min"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0mins"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.float.decimal.interval","1sec"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1secs"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0sec"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0secs"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.float.decimal.interval","1msec"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1msecs"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0msec"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0msecs"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["keyword.other","print"], + ["text"," "], + ["constant.numeric.float.decimal.interval","1usec"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1usecs"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0usec"], + ["punctuation.separator",","], + ["text"," "], + ["constant.numeric.float.decimal.interval","1.0usecs"], + ["punctuation.terminator",";"] +],[ + "start", + ["text"," "], + ["punctuation.section.block.end","}"] +],[ + "start" +]] \ No newline at end of file diff --git a/lib/ace/mode/bro_highlight_rules.js b/lib/ace/mode/bro_highlight_rules.js deleted file mode 100644 index 6c36a839f75..00000000000 --- a/lib/ace/mode/bro_highlight_rules.js +++ /dev/null @@ -1,204 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Distributed under the BSD license: - * - * Copyright (c) 2012, Ajax.org B.V. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Ajax.org B.V. nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -/* This file was autogenerated from Bro.tmLanguage (uuid: ) */ -/**************************************************************************************** - * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. * - * fileTypes * - ****************************************************************************************/ - -define(function(require, exports, module) { -"use strict"; - -var oop = require("../lib/oop"); -var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; - -var BroHighlightRules = function() { - // regexp must not have capturing parentheses. Use (?:) instead. - // regexps are ordered -> the first match is used - - this.$rules = { - start: [{ - token: "punctuation.definition.comment.bro", - regex: /#/, - push: [{ - token: "comment.line.number-sign.bro", - regex: /$/, - next: "pop" - }, { - defaultToken: "comment.line.number-sign.bro" - }] - }, { - token: "keyword.control.bro", - regex: /\b(?:break|case|continue|else|for|if|return|switch|next|when|timeout|schedule)\b/ - }, { - token: [ - "meta.function.bro", - "meta.function.bro", - "storage.type.bro", - "meta.function.bro", - "entity.name.function.bro", - "meta.function.bro" - ], - regex: /^(\s*)(?:function|hook|event)(\s*)(.*)(\s*\()(.*)(\).*$)/ - }, { - token: "storage.type.bro", - regex: /\b(?:bool|enum|double|int|count|port|addr|subnet|any|file|interval|time|string|table|vector|set|record|pattern|hook)\b/ - }, { - token: "storage.modifier.bro", - regex: /\b(?:global|const|redef|local|&(?:optional|rotate_interval|rotate_size|add_func|del_func|expire_func|expire_create|expire_read|expire_write|persistent|synchronized|encrypt|mergeable|priority|group|type_column|log|error_handler))\b/ - }, { - token: "keyword.operator.bro", - regex: /\s*(?:\||&&|(?:>|<|!)=?|==)\s*|\b!?in\b/ - }, { - token: "constant.language.bro", - regex: /\b(?:T|F)\b/ - }, { - token: "constant.numeric.bro", - regex: /\b(?:0(?:x|X)[0-9a-fA-F]*|(?:[0-9]+\.?[0-9]*|\.[0-9]+)(?:(?:e|E)(?:\+|-)?[0-9]+)?)(?:\/(?:tcp|udp|icmp)|\s*(?:u?sec|min|hr|day)s?)?\b/ - }, { - token: "punctuation.definition.string.begin.bro", - regex: /"/, - push: [{ - token: "punctuation.definition.string.end.bro", - regex: /"/, - next: "pop" - }, { - include: "#string_escaped_char" - }, { - include: "#string_placeholder" - }, { - defaultToken: "string.quoted.double.bro" - }] - }, { - token: "punctuation.definition.string.begin.bro", - regex: /\//, - push: [{ - token: "punctuation.definition.string.end.bro", - regex: /\//, - next: "pop" - }, { - include: "#string_escaped_char" - }, { - include: "#string_placeholder" - }, { - defaultToken: "string.quoted.regex.bro" - }] - }, { - token: [ - "meta.preprocessor.bro.load", - "keyword.other.special-method.bro" - ], - regex: /^(\s*)(\@load(?:-sigs)?)\b/, - push: [{ - token: [], - regex: /(?=\#)|$/, - next: "pop" - }, { - defaultToken: "meta.preprocessor.bro.load" - }] - }, { - token: [ - "meta.preprocessor.bro.if", - "keyword.other.special-method.bro", - "meta.preprocessor.bro.if" - ], - regex: /^(\s*)(\@endif|\@if(?:n?def)?)(.*$)/, - push: [{ - token: [], - regex: /$/, - next: "pop" - }, { - defaultToken: "meta.preprocessor.bro.if" - }] - }], - "#disabled": [{ - token: "text", - regex: /^\s*\@if(?:n?def)?\b.*$/, - push: [{ - token: "text", - regex: /^\s*\@endif\b.*$/, - next: "pop" - }, { - include: "#disabled" - }, { - include: "#pragma-mark" - }], - comment: "eat nested preprocessor ifdefs" - }], - "#preprocessor-rule-other": [{ - token: [ - "text", - "meta.preprocessor.bro", - "meta.preprocessor.bro", - "text" - ], - regex: /^(\s*)(@if)((?:n?def)?)\b(.*?)(?:(?=)|$)/, - push: [{ - token: ["text", "meta.preprocessor.bro", "text"], - regex: /^(\s*)(@endif)\b(.*$)/, - next: "pop" - }, { - include: "$base" - }] - }], - "#string_escaped_char": [{ - token: "constant.character.escape.bro", - regex: /\\(?:\\|[abefnprtv'"?]|[0-3]\d{,2}|[4-7]\d?|x[a-fA-F0-9]{,2})/ - }, { - token: "invalid.illegal.unknown-escape.bro", - regex: /\\./ - }], - "#string_placeholder": [{ - token: "constant.other.placeholder.bro", - regex: /%(?:\d+\$)?[#0\- +']*[,;:_]?(?:-?\d+|\*(?:-?\d+\$)?)?(?:\.(?:-?\d+|\*(?:-?\d+\$)?)?)?(?:hh|h|ll|l|j|t|z|q|L|vh|vl|v|hv|hl)?[diouxXDOUeEfFgGaACcSspn%]/ - }, { - token: "invalid.illegal.placeholder.bro", - regex: /%/ - }] - }; - - this.normalizeRules(); -}; - -BroHighlightRules.metaData = { - fileTypes: ["bro"], - foldingStartMarker: "^(\\@if(n?def)?)", - foldingStopMarker: "^\\@endif", - keyEquivalent: "@B", - name: "Bro", - scopeName: "source.bro" -}; - - -oop.inherits(BroHighlightRules, TextHighlightRules); - -exports.BroHighlightRules = BroHighlightRules; -}); \ No newline at end of file diff --git a/lib/ace/mode/bro.js b/lib/ace/mode/zeek.js similarity index 88% rename from lib/ace/mode/bro.js rename to lib/ace/mode/zeek.js index fd9ff82eeb8..efcfe6e4951 100644 --- a/lib/ace/mode/bro.js +++ b/lib/ace/mode/zeek.js @@ -37,22 +37,20 @@ define(function(require, exports, module) { var oop = require("../lib/oop"); var TextMode = require("./text").Mode; -var BroHighlightRules = require("./bro_highlight_rules").BroHighlightRules; -// TODO: pick appropriate fold mode +var ZeekHighlightRules = require("./zeek_highlight_rules").ZeekHighlightRules; var FoldMode = require("./folding/cstyle").FoldMode; var Mode = function() { - this.HighlightRules = BroHighlightRules; + this.HighlightRules = ZeekHighlightRules; this.foldingRules = new FoldMode(); }; oop.inherits(Mode, TextMode); (function() { - // this.lineCommentStart = ""#""; - // this.blockComment = {start: ""/*"", end: ""*/""}; + this.lineCommentStart = "#"; // Extra logic goes here. - this.$id = "ace/mode/bro"; + this.$id = "ace/mode/zeek"; }).call(Mode.prototype); exports.Mode = Mode; -}); \ No newline at end of file +}); diff --git a/lib/ace/mode/zeek_highlight_rules.js b/lib/ace/mode/zeek_highlight_rules.js new file mode 100644 index 00000000000..bd70065efcf --- /dev/null +++ b/lib/ace/mode/zeek_highlight_rules.js @@ -0,0 +1,407 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var ZeekHighlightRules = function() { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + "start": [ + { + token: "comment.line", + regex: "#.*$" + }, + { + token: "string.double", + regex: /"/, + next: "string-state" + }, + { + token: "string.regexp", + regex: "(/)(?=.*/)", + next: "pattern-state" + }, + { + token: ["keyword.other", "meta.preprocessor"], + regex: /(@(?:load-plugin|load-sigs|load|unload))(.*$)/ + }, + { + token: "keyword.other", + regex: /@(?:DEBUG|DIR|FILENAME|deprecated|if|ifdef|ifndef|else|endif)/ + }, + { + token: [ + "keyword.other", + "meta.preprocessor", + "keyword.operator", + "meta.preprocessor" + ], + regex: /(@prefixes)(\s*)(\+?=)(.*$)/ + }, + { + token: "storage.modifier.attribute", + regex: /\&\b(?:redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|error_handler|type_column|deprecated)\b/ + }, + { + token: "constant.language", + regex: /\b(?:T|F)\b/ + }, + { + token: "constant.numeric.port", + regex: /\b\d{1,5}\/(?:udp|tcp|icmp|unknown)\b/ + }, + { + token: "constant.numeric.addr", + regex: /\b(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{1,2})\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{1,2})\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{1,2})\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{1,2})\b/, + comment: "IPv4 address" + }, + { + token: "constant.numeric.addr", + regex: /\[(?:[0-9a-fA-F]{0,4}:){2,7}(?:[0-9a-fA-F]{0,4})?(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{1,2})\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{1,2})\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{1,2})\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{1,2}))?\]/, + comment: "IPv6 address" + }, + { + token: "constant.numeric.float.decimal.interval", + regex: /(?:(?:\d*\.\d*(?:[eE][+-]?\d+)?|\d*[eE][+-]?\d+|\d*\.\d*)|\d+)\s*(?:day|hr|min|msec|usec|sec)s?/ + }, + { + token: "constant.numeric.float.decimal", + regex: /\d*\.\d*(?:[eE][+-]?\d+)?|\d*[eE][+-]?\d+|\d*\.\d*/ + }, + { + token: "constant.numeric.hostname", + regex: /\b[A-Za-z0-9][A-Za-z0-9\-]*(?:\.[A-Za-z0-9][A-Za-z0-9\-]*)+\b/ + }, + { + token: "constant.numeric.integer.hexadecimal", + regex: /\b0x[0-9a-fA-F]+\b/ + }, + { + token: "constant.numeric.integer.decimal", + regex: /\b\d+\b/ + }, + { + token: "keyword.operator", + regex: /==|!=|<=|<|>=|>/ + }, + { + token: "keyword.operator", + regex: /(&&)|(\|\|)|(!)/ + }, + { + token: "keyword.operator", + regex: /=|\+=|-=/ + }, + { + token: "keyword.operator", + regex: /\+\+|\+|--|-|\*|\/|%/ + }, + { + token: "keyword.operator", + regex: /&|\||\^|~/ + }, + { + token: "keyword.operator", + regex: /\b(?:in|as|is)\b/ + }, + { + token: "punctuation.terminator", + regex: /;/ + }, + { + token: "punctuation.accessor", + regex: /\??\$/ + }, + { + token: "punctuation.accessor", + regex: /::/ + }, + { + token: "keyword.operator", + regex: /\?/ + }, + // Unsure how to tell if colon is used as operator vs. separator. + // { + // token: "keyword.operator", + // regex: /:/ + // }, + { + token: "punctuation.separator", + regex: /:/ + }, + { + token: "punctuation.separator", + regex: /,/ + }, + { + token: [ + "keyword.other", + "meta.namespace", + "entity.name.namespace" + ], + regex: /(module)(\s+)([A-Za-z_][A-Za-z_0-9]*(?:::[A-Za-z_][A-Za-z_0-9]*)*)/ + }, + { + token: "keyword.other", + regex: /\bexport\b/ + }, + { + token: "keyword.control.conditional", + regex: /\b(?:if|else)\b/ + }, + { + token: "keyword.control", + regex: /\b(?:for|while)\b/ + }, + { + token: "keyword.control", + regex: /\b(?:return|break|next|continue|fallthrough)\b/ + }, + { + token: "keyword.control", + regex: /\b(?:switch|default|case)\b/ + }, + { + token: "keyword.other", + regex: /\b(?:add|delete)\b/ + }, + { + token: "keyword.other", + regex: /\bprint\b/ + }, + { + token: "keyword.control", + regex: /\b(?:when|timeout|schedule)\b/ + }, + { + token: [ + "keyword.other", + "meta.struct.record", + "entity.name.struct.record", + "meta.struct.record", + "punctuation.separator", + "meta.struct.record", + "storage.type.struct.record" + ], + regex: /\b(type)(\s+)([A-Za-z_][A-Za-z_0-9]*(?:::[A-Za-z_][A-Za-z_0-9]*)*)(\s*)(:)(\s*\b)(record)\b/ + }, + { + token: [ + "keyword.other", + "meta.enum", + "entity.name.enum", + "meta.enum", + "punctuation.separator", + "meta.enum", + "storage.type.enum" + ], + regex: /\b(type)(\s+)([A-Za-z_][A-Za-z_0-9]*(?:::[A-Za-z_][A-Za-z_0-9]*)*)(\s*)(:)(\s*\b)(enum)\b/ + }, + { + token: [ + "keyword.other", + "meta.type", + "entity.name.type", + "meta.type", + "punctuation.separator" + ], + regex: /\b(type)(\s+)([A-Za-z_][A-Za-z_0-9]*(?:::[A-Za-z_][A-Za-z_0-9]*)*)(\s*)(:)/ + }, + { + token: [ + "keyword.other", + "meta.struct.record", + "storage.type.struct.record", + "meta.struct.record", + "entity.name.struct.record" + ], + regex: /\b(redef)(\s+)(record)(\s+)([A-Za-z_][A-Za-z_0-9]*(?:::[A-Za-z_][A-Za-z_0-9]*)*)\b/ + }, + { + token: [ + "keyword.other", + "meta.enum", + "storage.type.enum", + "meta.enum", + "entity.name.enum" + ], + regex: /\b(redef)(\s+)(enum)(\s+)([A-Za-z_][A-Za-z_0-9]*(?:::[A-Za-z_][A-Za-z_0-9]*)*)\b/ + }, + { + token: [ + "storage.type", + "text", + "entity.name.function.event" + ], + regex: /\b(event)(\s+)([A-Za-z_][A-Za-z_0-9]*(?:::[A-Za-z_][A-Za-z_0-9]*)*)(?=s*\()/ + }, + { + token: [ + "storage.type", + "text", + "entity.name.function.hook" + ], + regex: /\b(hook)(\s+)([A-Za-z_][A-Za-z_0-9]*(?:::[A-Za-z_][A-Za-z_0-9]*)*)(?=s*\()/ + }, + { + token: [ + "storage.type", + "text", + "entity.name.function" + ], + regex: /\b(function)(\s+)([A-Za-z_][A-Za-z_0-9]*(?:::[A-Za-z_][A-Za-z_0-9]*)*)(?=s*\()/ + }, + { + token: "keyword.other", + regex: /\bredef\b/ + }, + { + token: "storage.type", + regex: /\bany\b/ + }, + { + token: "storage.type", + regex: /\b(?:enum|record|set|table|vector)\b/ + }, + { + token: [ + "storage.type", + "text", + "keyword.operator", + "text", + "storage.type" + ], + regex: /\b(opaque)(\s+)(of)(\s+)([A-Za-z_][A-Za-z_0-9]*(?:::[A-Za-z_][A-Za-z_0-9]*)*)\b/ + }, + { + token: "keyword.operator", + regex: /\bof\b/ + }, + { + token: "storage.type", + regex: /\b(?:addr|bool|count|double|file|int|interval|pattern|port|string|subnet|time)\b/ + }, + { + token: "storage.type", + regex: /\b(?:function|hook|event)\b/ + }, + { + token: "storage.modifier", + regex: /\b(?:global|local|const|option)\b/ + }, + { + token: "entity.name.function.call", + regex: /\b[A-Za-z_][A-Za-z_0-9]*(?:::[A-Za-z_][A-Za-z_0-9]*)*(?=s*\()/ + }, + { + token: "punctuation.section.block.begin", + regex: /\{/ + }, + { + token: "punctuation.section.block.end", + regex: /\}/ + }, + { + token: "punctuation.section.brackets.begin", + regex: /\[/ + }, + { + token: "punctuation.section.brackets.end", + regex: /\]/ + }, + { + token: "punctuation.section.parens.begin", + regex: /\(/ + }, + { + token: "punctuation.section.parens.end", + regex: /\)/ + } + + ], // state: start + + "string-state": [ + { + token: "constant.character.escape", + regex: /\\./ + }, + { + token: "string.double", + regex: /"/, + next: "start" + }, + { + token: "constant.other.placeholder", + regex: /%-?[0-9]*(\.[0-9]+)?[DTdxsefg]/ + }, + { + token: "string.double", + regex: "." + } + ], // state: string-state + + "pattern-state": [ + { + token: "constant.character.escape", + regex: /\\./ + }, + { + token: "string.regexp", + regex: "/", + next: "start" + }, + { + token: "string.regexp", + regex: "." + } + ] // state: pattern-state + + }; + + this.normalizeRules(); +}; + +ZeekHighlightRules.metaData = { + fileTypes: ["bro", "zeek"], + name: "Zeek", + scopeName: "source.zeek" +}; + + +oop.inherits(ZeekHighlightRules, TextHighlightRules); + +exports.ZeekHighlightRules = ZeekHighlightRules; +}); diff --git a/lib/ace/snippets/bro.js b/lib/ace/snippets/zeek.js similarity index 55% rename from lib/ace/snippets/bro.js rename to lib/ace/snippets/zeek.js index 359d9103986..fa638070c33 100644 --- a/lib/ace/snippets/bro.js +++ b/lib/ace/snippets/zeek.js @@ -1,7 +1,7 @@ define(function(require, exports, module) { "use strict"; -exports.snippetText = require("../requirejs/text!./.snippets"); +exports.snippetText = require("../requirejs/text!./zeek.snippets"); exports.scope = ""; }); diff --git a/lib/ace/snippets/bro.snippets b/lib/ace/snippets/zeek.snippets similarity index 100% rename from lib/ace/snippets/bro.snippets rename to lib/ace/snippets/zeek.snippets From 7c5ae22b86ce2eb8894e6e19343c74a31ceafa28 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 9 May 2019 23:41:08 +0400 Subject: [PATCH 0158/1293] improve the type of addMarker --- ace.d.ts | 8 ++++---- build | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index a1c7d2b9c81..330603d99b4 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -438,16 +438,16 @@ export namespace Ace { setBreakpoint(row: number, className: string): void; clearBreakpoint(row: number): void; addMarker(range: Range, - clazz: string, - type: MarkerRenderer | string, - inFront: boolean): number; + className: string, + type: "fullLine" | "screenLine" | "text" | MarkerRenderer, + inFront?: boolean): number; addDynamicMarker(marker: MarkerLike, inFront: boolean): MarkerLike; removeMarker(markerId: number): void; getMarkers(inFront?: boolean): MarkerLike[]; highlight(re: RegExp): void; highlightLines(startRow: number, endRow: number, - clazz: string, + className: string, inFront?: boolean): Range; setAnnotations(annotations: Annotation[]): void; getAnnotations(): Annotation[]; diff --git a/build b/build index 5fe4368221f..812e2c56aed 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 5fe4368221f48b114387c2e7d67c9cd904ec30a2 +Subproject commit 812e2c56aed246931a667f16c28b096e34597016 From ef35db4182f7cb05a5fc6ff55c82e7ce97aefd3d Mon Sep 17 00:00:00 2001 From: Adam Jimenez Date: Sun, 12 May 2019 10:53:43 +0100 Subject: [PATCH 0159/1293] missing grid properties and fr unit --- lib/ace/mode/css/csslint.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/ace/mode/css/csslint.js b/lib/ace/mode/css/csslint.js index fec652802a2..b9d0fa3d35f 100644 --- a/lib/ace/mode/css/csslint.js +++ b/lib/ace/mode/css/csslint.js @@ -3875,8 +3875,13 @@ var Properties = { "grid-row" : 1, "grid-rows" : 1, "grid-row-align" : "start | end | center | stretch", + "grid-row-gap" : 1, "grid-row-span" : "", "grid-row-sizing" : 1, + "grid-template" : 1, + "grid-template-areas" : 1, + "grid-template-columns" : 1, + "grid-template-rows" : 1, //H "hanging-punctuation" : 1, @@ -4308,6 +4313,7 @@ function PropertyValuePart(text, line, col){ case "ch": case "vh": case "vw": + case "fr": case "vmax": case "vmin": this.type = "length"; From fb1c82e2872e7aa9913e94db6ffcd7bd04d6c624 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 14 May 2019 01:19:39 +0400 Subject: [PATCH 0160/1293] update vim --- lib/ace/keyboard/vim.js | 340 +++++++++++++++++++++++++++++---- lib/ace/keyboard/vim_test.js | 351 ++++++++++++++++++++++++++--------- 2 files changed, 559 insertions(+), 132 deletions(-) diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index c2166f7c9f8..de7b14e5ac6 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -1,9 +1,9 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/LICENSE /** * Supported keybindings: - * Too many to list. Refer to defaultKeyMap below. + * Too many to list. Refer to defaultKeymap below. * * Supported Ex commands: * Refer to defaultExCommandMap below. @@ -114,6 +114,7 @@ define(function(require, exports, module) { }; }; CodeMirror.lookupKey = function lookupKey(key, map, handle) { + if (!map) map = "default"; if (typeof map == "string") map = CodeMirror.keyMap[map]; var found = typeof map == "function" ? map(key) : map[key]; @@ -513,6 +514,10 @@ define(function(require, exports, module) { name = optMap[name]; val = !val; break; + case 'keyMap': + this.state.$keyMap = val; + return; + break; default: name = optMap[name]; } @@ -527,6 +532,8 @@ define(function(require, exports, module) { case 'indentWithTabs': name = optMap[name]; return !val; + case 'keyMap': + return this.state.$keyMap; } return aceOpt ? val : this.state[name]; }; @@ -580,7 +587,7 @@ define(function(require, exports, module) { return this.ace.getValue(); }; this.setValue = function(v) { - return this.ace.setValue(v); + return this.ace.setValue(v, -1); }; this.getTokenTypeAt = function(pos) { var token = this.ace.session.getTokenAt(pos.line, pos.ch); @@ -626,7 +633,10 @@ define(function(require, exports, module) { }; this.getMode = function() { return { name : this.getOption("mode") }; - } + }; + this.execCommand = function() { + + }; }).call(CodeMirror.prototype); function toAcePos(cmPos) { return {row: cmPos.line, column: cmPos.ch}; @@ -867,6 +877,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ { keys: '', type: 'keyToKey', toKeys: 'j' }, { keys: '', type: 'keyToKey', toKeys: 'l' }, { keys: '', type: 'keyToKey', toKeys: 'h', context: 'normal'}, + { keys: '', type: 'keyToKey', toKeys: 'x', context: 'normal'}, { keys: '', type: 'keyToKey', toKeys: 'W' }, { keys: '', type: 'keyToKey', toKeys: 'B', context: 'normal' }, { keys: '', type: 'keyToKey', toKeys: 'w' }, @@ -907,6 +918,8 @@ dom.importCssString(".normal-mode .ace_cursor{\ { keys: 'gE', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true }}, { keys: '{', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: false, toJumplist: true }}, { keys: '}', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: true, toJumplist: true }}, + { keys: '(', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: false }}, + { keys: ')', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: true }}, { keys: '', type: 'motion', motion: 'moveByPage', motionArgs: { forward: true }}, { keys: '', type: 'motion', motion: 'moveByPage', motionArgs: { forward: false }}, { keys: '', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: true, explicitRepeat: true }}, @@ -944,6 +957,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ { keys: 'd', type: 'operator', operator: 'delete' }, { keys: 'y', type: 'operator', operator: 'yank' }, { keys: 'c', type: 'operator', operator: 'change' }, + { keys: '=', type: 'operator', operator: 'indentAuto' }, { keys: '>', type: 'operator', operator: 'indent', operatorArgs: { indentRight: true }}, { keys: '<', type: 'operator', operator: 'indent', operatorArgs: { indentRight: false }}, { keys: 'g~', type: 'operator', operator: 'changeCase' }, @@ -956,13 +970,15 @@ dom.importCssString(".normal-mode .ace_cursor{\ { keys: 'X', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: false }, operatorMotionArgs: { visualLine: true }}, { keys: 'D', type: 'operatorMotion', operator: 'delete', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'}, { keys: 'D', type: 'operator', operator: 'delete', operatorArgs: { linewise: true }, context: 'visual'}, - { keys: 'Y', type: 'operatorMotion', operator: 'yank', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'}, + { keys: 'Y', type: 'operatorMotion', operator: 'yank', motion: 'expandToLine', motionArgs: { linewise: true }, context: 'normal'}, { keys: 'Y', type: 'operator', operator: 'yank', operatorArgs: { linewise: true }, context: 'visual'}, { keys: 'C', type: 'operatorMotion', operator: 'change', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'}, { keys: 'C', type: 'operator', operator: 'change', operatorArgs: { linewise: true }, context: 'visual'}, { keys: '~', type: 'operatorMotion', operator: 'changeCase', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorArgs: { shouldMoveCursor: true }, context: 'normal'}, { keys: '~', type: 'operator', operator: 'changeCase', context: 'visual'}, { keys: '', type: 'operatorMotion', operator: 'delete', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }, context: 'insert' }, + //ignore C-w in normal mode + { keys: '', type: 'idle', context: 'normal' }, // Actions { keys: '', type: 'action', action: 'jumpListWalk', actionArgs: { forward: true }}, { keys: '', type: 'action', action: 'jumpListWalk', actionArgs: { forward: false }}, @@ -1019,6 +1035,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ // Ex command { keys: ':', type: 'ex' } ]; + var defaultKeymapLength = defaultKeymap.length; /** * Ex commands @@ -1190,6 +1207,9 @@ dom.importCssString(".normal-mode .ace_cursor{\ function isWhiteSpaceString(k) { return (/^\s*$/).test(k); } + function isEndOfSentenceSymbol(k) { + return '.?!'.indexOf(k) != -1; + } function inArray(val, arr) { for (var i = 0; i < arr.length; i++) { if (arr[i] == val) { @@ -1504,6 +1524,78 @@ dom.importCssString(".normal-mode .ace_cursor{\ unmap: function(lhs, ctx) { exCommandDispatcher.unmap(lhs, ctx); }, + // Non-recursive map function. + // NOTE: This will not create mappings to key maps that aren't present + // in the default key map. See TODO at bottom of function. + noremap: function(lhs, rhs, ctx) { + function toCtxArray(ctx) { + return ctx ? [ctx] : ['normal', 'insert', 'visual']; + } + var ctxsToMap = toCtxArray(ctx); + // Look through all actual defaults to find a map candidate. + var actualLength = defaultKeymap.length, origLength = defaultKeymapLength; + for (var i = actualLength - origLength; + i < actualLength && ctxsToMap.length; + i++) { + var mapping = defaultKeymap[i]; + // Omit mappings that operate in the wrong context(s) and those of invalid type. + if (mapping.keys == rhs && + (!ctx || !mapping.context || mapping.context === ctx) && + mapping.type.substr(0, 2) !== 'ex' && + mapping.type.substr(0, 3) !== 'key') { + // Make a shallow copy of the original keymap entry. + var newMapping = {}; + for (var key in mapping) { + newMapping[key] = mapping[key]; + } + // Modify it point to the new mapping with the proper context. + newMapping.keys = lhs; + if (ctx && !newMapping.context) { + newMapping.context = ctx; + } + // Add it to the keymap with a higher priority than the original. + this._mapCommand(newMapping); + // Record the mapped contexts as complete. + var mappedCtxs = toCtxArray(mapping.context); + ctxsToMap = ctxsToMap.filter(function(el) { return mappedCtxs.indexOf(el) === -1; }); + } + } + // TODO: Create non-recursive keyToKey mappings for the unmapped contexts once those exist. + }, + // Remove all user-defined mappings for the provided context. + mapclear: function(ctx) { + // Partition the existing keymap into user-defined and true defaults. + var actualLength = defaultKeymap.length, + origLength = defaultKeymapLength; + var userKeymap = defaultKeymap.slice(0, actualLength - origLength); + defaultKeymap = defaultKeymap.slice(actualLength - origLength); + if (ctx) { + // If a specific context is being cleared, we need to keep mappings + // from all other contexts. + for (var i = userKeymap.length - 1; i >= 0; i--) { + var mapping = userKeymap[i]; + if (ctx !== mapping.context) { + if (mapping.context) { + this._mapCommand(mapping); + } else { + // `mapping` applies to all contexts so create keymap copies + // for each context except the one being cleared. + var contexts = ['normal', 'insert', 'visual']; + for (var j in contexts) { + if (contexts[j] !== ctx) { + var newMapping = {}; + for (var key in mapping) { + newMapping[key] = mapping[key]; + } + newMapping.context = contexts[j]; + this._mapCommand(newMapping); + } + } + } + } + } + } + }, // TODO: Expose setOption and getOption as instance methods. Need to decide how to namespace // them, or somehow make them work with the existing CodeMirror setOption/getOption API. setOption: setOption, @@ -1633,7 +1725,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ if (vim.insertMode) { command = handleKeyInsertMode(); } else { command = handleKeyNonInsertMode(); } if (command === false) { - return undefined; + return undefined; //ace_patch } else if (command === true) { // TODO: Look into using CodeMirror's multi-key handling. // Return no-op since we are caching the key. Counts as handled, but @@ -1922,7 +2014,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ } if (bestMatch.keys.slice(-11) == '') { var character = lastChar(keys); - if (//.test(character)) return {type: 'none'}; + if (//.test(character) || !character) return {type: 'none'}; //ace_patch inputState.selectedCharacter = character; } return {type: 'full', command: bestMatch}; @@ -2591,6 +2683,10 @@ dom.importCssString(".normal-mode .ace_cursor{\ var dir = motionArgs.forward ? 1 : -1; return findParagraph(cm, head, motionArgs.repeat, dir); }, + moveBySentence: function(cm, head, motionArgs) { + var dir = motionArgs.forward ? 1 : -1; + return findSentence(cm, head, motionArgs.repeat, dir); + }, moveByScroll: function(cm, head, motionArgs, vim) { var scrollbox = cm.getScrollInfo(); var curEnd = null; @@ -2664,17 +2760,19 @@ dom.importCssString(".normal-mode .ace_cursor{\ var ch = cursor.ch; var lineText = cm.getLine(line); var symbol; - do { - symbol = lineText.charAt(ch++); + for (; ch < lineText.length; ch++) { + symbol = lineText.charAt(ch); if (symbol && isMatchableSymbol(symbol)) { - var style = cm.getTokenTypeAt(Pos(line, ch)); + var style = cm.getTokenTypeAt(Pos(line, ch + 1)); if (style !== "string" && style !== "comment") { break; } } - } while (symbol); - if (symbol) { - var matched = cm.findMatchingBracket(Pos(line, ch)); + } + if (ch < lineText.length) { + // Only include angle brackets in analysis if they are being matched. + var re = /[<>]/.test(lineText[ch]) ? /[(){}[\]<>]/ : /[(){}[\]]/; + var matched = cm.findMatchingBracket(Pos(line, ch+1), {bracketRegex: re}); return matched.to; } else { return cursor; @@ -2694,9 +2792,6 @@ dom.importCssString(".normal-mode .ace_cursor{\ textObjectManipulation: function(cm, head, motionArgs, vim) { // TODO: lots of possible exceptions that can be thrown here. Try da( // outside of a () block. - - // TODO: adding <> >< to this map doesn't work, presumably because - // they're operators var mirroredPairs = {'(': ')', ')': '(', '{': '}', '}': '{', '[': ']', ']': '[', @@ -2888,6 +2983,10 @@ dom.importCssString(".normal-mode .ace_cursor{\ } return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor); }, + indentAuto: function(cm, _args, ranges) { + cm.execCommand("indentAuto"); + return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor); + }, changeCase: function(cm, args, ranges, oldAnchor, newHead) { var selections = cm.getSelections(); var swapped = []; @@ -2997,9 +3096,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ switch (actionArgs.position) { case 'center': y = y - (height / 2) + lineHeight; break; - case 'bottom': y = y - height + lineHeight*1.4; - break; - case 'top': y = y + lineHeight*0.4; + case 'bottom': y = y - height + lineHeight; break; } cm.scrollTo(null, y); @@ -3010,6 +3107,8 @@ dom.importCssString(".normal-mode .ace_cursor{\ var macroModeState = vimGlobalState.macroModeState; if (registerName == '@') { registerName = macroModeState.latestRegister; + } else { + macroModeState.latestRegister = registerName; } while(repeat--){ executeMacroRegister(cm, vim, macroModeState, registerName); @@ -3258,7 +3357,7 @@ dom.importCssString(".normal-mode .ace_cursor{\ } var linewise = register.linewise; var blockwise = register.blockwise; - if (linewise && !blockwise) { + if (linewise && !blockwise) { // ace_patch if(vim.visualMode) { text = vim.visualLine ? text.slice(0, -1) : '\n' + text.slice(0, text.length - 1) + '\n'; } else if (actionArgs.after) { @@ -3510,12 +3609,6 @@ dom.importCssString(".normal-mode .ace_cursor{\ } return Pos(cur.line + offsetLine, cur.ch + offsetCh); } - function getOffset(anchor, head) { - return { - line: head.line - anchor.line, - ch: head.line - anchor.line - }; - } function commandMatches(keys, keyMap, context, inputState) { // Partial matches are not applied. They inform the key handler // that the current key sequence is a subsequence of a valid key @@ -4332,6 +4425,179 @@ dom.importCssString(".normal-mode .ace_cursor{\ return { start: start, end: end }; } + function findSentence(cm, cur, repeat, dir) { + + /* + Takes an index object + { + line: the line string, + ln: line number, + pos: index in line, + dir: direction of traversal (-1 or 1) + } + and modifies the line, ln, and pos members to represent the + next valid position or sets them to null if there are + no more valid positions. + */ + function nextChar(cm, idx) { + if (idx.pos + idx.dir < 0 || idx.pos + idx.dir >= idx.line.length) { + idx.ln += idx.dir; + if (!isLine(cm, idx.ln)) { + idx.line = null; + idx.ln = null; + idx.pos = null; + return; + } + idx.line = cm.getLine(idx.ln); + idx.pos = (idx.dir > 0) ? 0 : idx.line.length - 1; + } + else { + idx.pos += idx.dir; + } + } + + /* + Performs one iteration of traversal in forward direction + Returns an index object of the new location + */ + function forward(cm, ln, pos, dir) { + var line = cm.getLine(ln); + var stop = (line === ""); + + var curr = { + line: line, + ln: ln, + pos: pos, + dir: dir, + } + + var last_valid = { + ln: curr.ln, + pos: curr.pos, + } + + var skip_empty_lines = (curr.line === ""); + + // Move one step to skip character we start on + nextChar(cm, curr); + + while (curr.line !== null) { + last_valid.ln = curr.ln; + last_valid.pos = curr.pos; + + if (curr.line === "" && !skip_empty_lines) { + return { ln: curr.ln, pos: curr.pos, }; + } + else if (stop && curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) { + return { ln: curr.ln, pos: curr.pos, }; + } + else if (isEndOfSentenceSymbol(curr.line[curr.pos]) + && !stop + && (curr.pos === curr.line.length - 1 + || isWhiteSpaceString(curr.line[curr.pos + 1]))) { + stop = true; + } + + nextChar(cm, curr); + } + + /* + Set the position to the last non whitespace character on the last + valid line in the case that we reach the end of the document. + */ + var line = cm.getLine(last_valid.ln); + last_valid.pos = 0; + for(var i = line.length - 1; i >= 0; --i) { + if (!isWhiteSpaceString(line[i])) { + last_valid.pos = i; + break; + } + } + + return last_valid; + + } + + /* + Performs one iteration of traversal in reverse direction + Returns an index object of the new location + */ + function reverse(cm, ln, pos, dir) { + var line = cm.getLine(ln); + + var curr = { + line: line, + ln: ln, + pos: pos, + dir: dir, + } + + var last_valid = { + ln: curr.ln, + pos: null, + }; + + var skip_empty_lines = (curr.line === ""); + + // Move one step to skip character we start on + nextChar(cm, curr); + + while (curr.line !== null) { + + if (curr.line === "" && !skip_empty_lines) { + if (last_valid.pos !== null) { + return last_valid; + } + else { + return { ln: curr.ln, pos: curr.pos }; + } + } + else if (isEndOfSentenceSymbol(curr.line[curr.pos]) + && last_valid.pos !== null + && !(curr.ln === last_valid.ln && curr.pos + 1 === last_valid.pos)) { + return last_valid; + } + else if (curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) { + skip_empty_lines = false; + last_valid = { ln: curr.ln, pos: curr.pos } + } + + nextChar(cm, curr); + } + + /* + Set the position to the first non whitespace character on the last + valid line in the case that we reach the beginning of the document. + */ + var line = cm.getLine(last_valid.ln); + last_valid.pos = 0; + for(var i = 0; i < line.length; ++i) { + if (!isWhiteSpaceString(line[i])) { + last_valid.pos = i; + break; + } + } + return last_valid; + } + + var curr_index = { + ln: cur.line, + pos: cur.ch, + }; + + while (repeat > 0) { + if (dir < 0) { + curr_index = reverse(cm, curr_index.ln, curr_index.pos, dir); + } + else { + curr_index = forward(cm, curr_index.ln, curr_index.pos, dir); + } + repeat--; + } + + return Pos(curr_index.ln, curr_index.pos); + } + // TODO: perhaps this finagling of start and end positions belonds // in codemirror/replaceRange? function selectCompanionObject(cm, head, symb, inclusive) { @@ -4352,8 +4618,8 @@ dom.importCssString(".normal-mode .ace_cursor{\ // cursor is on a matching open bracket. var offset = curChar === openSym ? 1 : 0; - start = cm.scanForBracket(Pos(cur.line, cur.ch + offset), -1, null, {'bracketRegex': bracketRegexp}); - end = cm.scanForBracket(Pos(cur.line, cur.ch + offset), 1, null, {'bracketRegex': bracketRegexp}); + start = cm.scanForBracket(Pos(cur.line, cur.ch + offset), -1, undefined, {'bracketRegex': bracketRegexp}); + end = cm.scanForBracket(Pos(cur.line, cur.ch + offset), 1, undefined, {'bracketRegex': bracketRegexp}); if (!start || !end) { return { start: cur, end: cur }; @@ -4487,11 +4753,10 @@ dom.importCssString(".normal-mode .ace_cursor{\ onClose(prompt(shortText, '')); } } - function splitBySlash(argString) { return splitBySeparator(argString, '/'); } - + function findUnescapedSlashes(argString) { return findUnescapedSeparators(argString, '/'); } @@ -5710,13 +5975,6 @@ dom.importCssString(".normal-mode .ace_cursor{\ CodeMirror.keyMap['vim-insert'] = { // TODO: override navigation keys so that Esc will cancel automatic // indentation from o, O, i_ - 'Ctrl-N': 'autocomplete', - 'Ctrl-P': 'autocomplete', - 'Enter': function(cm) { - var fn = CodeMirror.commands.newlineAndIndentContinueComment || - CodeMirror.commands.newlineAndIndent; - fn(cm); - }, fallthrough: ['default'], attach: attachVimMap, detach: detachVimMap, @@ -5816,10 +6074,12 @@ dom.importCssString(".normal-mode .ace_cursor{\ lastChange.changes = []; lastChange.maybeReset = false; } - if (cm.state.overwrite && !/\n/.test(text)) { + if (text) { + if (cm.state.overwrite && !/\n/.test(text)) { lastChange.changes.push([text]); - } else { + } else { lastChange.changes.push(text); + } } } // Change objects may be chained with next. @@ -6319,6 +6579,4 @@ dom.importCssString(".normal-mode .ace_cursor{\ exports.handler.defaultKeymap = defaultKeymap; exports.handler.actions = actions; exports.Vim = Vim; - - Vim.map("Y", "yy", "normal"); }); diff --git a/lib/ace/keyboard/vim_test.js b/lib/ace/keyboard/vim_test.js index 8a4316f9fde..ecd964d73e8 100644 --- a/lib/ace/keyboard/vim_test.js +++ b/lib/ace/keyboard/vim_test.js @@ -74,15 +74,6 @@ function test(name, fn) { else exports["test " + name] = fn; } -function expectFail(fn, silent) { - try { - fn(); - } catch(expected) { - return; - }; - if (!silent) - throw new Error("Expected to throw an error"); -} vim.CodeMirror.Vim.unmap("Y"); vim.CodeMirror.Vim.defineEx('write', 'w', function(cm) { @@ -208,6 +199,15 @@ function forEach(arr, func) { } } +function expectFail(fn) { + try { + fn(); + } catch(expected) { + return; + }; + throw new Error("Expected to throw an error"); +} + function testVim(name, run, opts, expectedFail) { var vimOpts = { lineNumbers: true, @@ -231,10 +231,12 @@ function testVim(name, run, opts, expectedFail) { arguments = args; } for (var i = 0; i < arguments.length; i++) { + // ace_patch{ var ch = arguments[i]; var result = ch.length == 1 ? cm.ace.keyBinding.$callKeyboardHandlers(-1, ch, 0) : CodeMirror.Vim.handleKey(cm, arguments[i]); + // ace_patch} if (!result && cm.state.vim.insertMode) { cm.replaceSelections(fillArray(arguments[i], cm.listSelections().length)); } @@ -319,8 +321,8 @@ function testVim(name, run, opts, expectedFail) { cm.openDialog = savedOpenDialog; // ace_patch } - }); -} + }, expectedFail); +}; testVim('qq@q', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('q', 'q', 'l', 'l', 'q'); @@ -425,6 +427,8 @@ testMotion('k', 'k', offsetCursor(word3.end, -1, 0), word3.end); testMotion('k_repeat', ['2', 'k'], makeCursor(0, 4), makeCursor(2, 4)); testMotion('k_repeat_clip', ['1000', 'k'], makeCursor(0, 4), makeCursor(2, 4)); testMotion('w', 'w', word1.start); +testMotion('keepHPos', ['5', 'j', 'j', '7', 'k'], makeCursor(8, 12), makeCursor(12, 12)); +testMotion('keepHPosEol', ['$', '2', 'j'], makeCursor(2, 18)); testMotion('w_multiple_newlines_no_space', 'w', makeCursor(12, 2), makeCursor(11, 2)); testMotion('w_multiple_newlines_with_space', 'w', makeCursor(14, 0), makeCursor(12, 51)); testMotion('w_repeat', ['2', 'w'], word2.start); @@ -536,7 +540,6 @@ testVim('gj_gk_clipping', function(cm,vim,helpers){ },{value: 'line 1\n\nline 2'}); //testing a mix of j/k and gj/gk testVim('j_k_and_gj_gk', function(cm,vim,helpers){ - if (phantom) return; cm.setSize(120); cm.setCursor(0, 0); //go to the last character on the first line @@ -612,6 +615,40 @@ testVim('{', function(cm, vim, helpers) { helpers.doKeys('6', '{'); helpers.assertCursorAt(0, 0); }, { value: 'a\n\nb\nc\n\nd' }); +testVim('(', function(cm, vim, helpers) { + cm.setCursor(6, 23); + helpers.doKeys('('); + helpers.assertCursorAt(6, 14); + helpers.doKeys('2', '('); + helpers.assertCursorAt(5, 0); + helpers.doKeys('('); + helpers.assertCursorAt(4, 0); + helpers.doKeys('('); + helpers.assertCursorAt(3, 0); + helpers.doKeys('('); + helpers.assertCursorAt(2, 0); + helpers.doKeys('('); + helpers.assertCursorAt(0, 0); + helpers.doKeys('('); + helpers.assertCursorAt(0, 0); +}, { value: 'sentence1.\n\n\nsentence2\n\nsentence3. sentence4\n sentence5? sentence6!' }); +testVim(')', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('2', ')'); + helpers.assertCursorAt(3, 0); + helpers.doKeys(')'); + helpers.assertCursorAt(4, 0); + helpers.doKeys(')'); + helpers.assertCursorAt(5, 0); + helpers.doKeys(')'); + helpers.assertCursorAt(5, 11); + helpers.doKeys(')'); + helpers.assertCursorAt(6, 14); + helpers.doKeys(')'); + helpers.assertCursorAt(6, 23); + helpers.doKeys(')'); + helpers.assertCursorAt(6, 23); +}, { value: 'sentence1.\n\n\nsentence2\n\nsentence3. sentence4\n sentence5? sentence6!' }); testVim('paragraph_motions', function(cm, vim, helpers) { cm.setCursor(10, 0); helpers.doKeys('{'); @@ -1123,21 +1160,18 @@ function fillArray(val, times) { testVim('c_visual_block', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('', '2', 'j', 'l', 'l', 'l', 'c'); - var replacement = fillArray('hello', 3); - cm.replaceSelections(replacement); + helpers.doKeys('hello'); eq('1hello\n5hello\nahellofg', cm.getValue()); helpers.doKeys(''); cm.setCursor(2, 3); helpers.doKeys('', '2', 'k', 'h', 'C'); - replacement = fillArray('world', 3); - cm.replaceSelections(replacement); + helpers.doKeys('world'); eq('1hworld\n5hworld\nahworld', cm.getValue()); }, {value: '1234\n5678\nabcdefg'}); testVim('c_visual_block_replay', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('', '2', 'j', 'l', 'c'); - var replacement = fillArray('fo', 3); - cm.replaceSelections(replacement); + helpers.doKeys('fo'); eq('1fo4\n5fo8\nafodefg', cm.getValue()); helpers.doKeys(''); cm.setCursor(0, 0); @@ -1147,8 +1181,7 @@ testVim('c_visual_block_replay', function(cm, vim, helpers) { testVim('I_visual_block_replay', function(cm, vim, helpers) { cm.setCursor(0, 2); helpers.doKeys('', '2', 'j', 'l', 'I'); - var replacement = fillArray('+-', 3); - cm.replaceSelections(replacement); + helpers.doKeys('+-') eq('12+-34\n56+-78\nab+-cdefg\nxyz', cm.getValue()); helpers.doKeys(''); // ensure that repeat location doesn't depend on last selection @@ -1181,14 +1214,12 @@ testVim('D_visual_block', function(cm, vim, helpers) { testVim('s_visual_block', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('', '2', 'j', 'l', 'l', 'l', 's'); - var replacement = fillArray('hello{', 3); - cm.replaceSelections(replacement); + helpers.doKeys('hello{'); eq('1hello{\n5hello{\nahello{fg\n', cm.getValue()); helpers.doKeys(''); cm.setCursor(2, 3); helpers.doKeys('', '1', 'k', 'h', 'S'); - replacement = fillArray('world', 1); - cm.replaceSelections(replacement); + helpers.doKeys('world'); eq('1hello{\n world\n', cm.getValue()); }, {value: '1234\n5678\nabcdefg\n'}); @@ -1313,6 +1344,13 @@ testVim('<<', function(cm, vim, helpers) { is(!register.linewise); helpers.assertCursorAt(0, 1); }, { value: ' word1\n word2\nword3 ', indentUnit: 2 }); +isAce || testVim('=', function(cm, vim, helpers) { + cm.setCursor(0, 3); + helpers.doKeys('', 'j', 'j'); + var expectedValue = 'word1\nword2\nword3'; + helpers.doKeys('='); + eq(expectedValue, cm.getValue()); +}, { value: ' word1\n word2\n word3', indentUnit: 2 }); // Edit tests function testEdit(name, before, pos, edit, after) { @@ -1415,6 +1453,12 @@ testEdit('di]_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'di]', 'a\t[]b'); testEdit('da[_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'da[', 'a\tb'); testEdit('da]_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'da]', 'a\tb'); +// open and close on diff lines, open indented more than close +testEdit('di<_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'di<', 'a\t<>b'); +testEdit('di>_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'di>', 'a\t<>b'); +testEdit('da<_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'da<', 'a\tb'); +testEdit('da>_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'da>', 'a\tb'); + function testSelection(name, before, pos, keys, sel) { return testVim(name, function(cm, vim, helpers) { var ch = before.search(pos) @@ -1528,6 +1572,16 @@ testVim('insert_ctrl_w', function(cm, vim, helpers) { eqCursorPos(curEnd, cm.getCursor()); eq('vim-insert', cm.getOption('keyMap')); }, { value: 'word1/word2' }); +testVim('normal_ctrl_w', function(cm, vim, helpers) { + var curStart = makeCursor(0, 3); + cm.setCursor(curStart); + helpers.doKeys(''); + eq('word', cm.getValue()); + var curEnd = makeCursor(0, 3); + helpers.assertCursorAt(0,3); + eqCursorPos(curEnd, cm.getCursor()); + is(!vim.insertMode); +}, {value: 'word'}); testVim('a', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('a'); @@ -1555,7 +1609,7 @@ testVim('i', function(cm, vim, helpers) { }); testVim('i_repeat', function(cm, vim, helpers) { helpers.doKeys('3', 'i'); - cm.replaceRange('test', cm.getCursor()); + helpers.doKeys('test') helpers.doKeys(''); eq('testtesttest', cm.getValue()); helpers.assertCursorAt(0, 11); @@ -1563,7 +1617,7 @@ testVim('i_repeat', function(cm, vim, helpers) { testVim('i_repeat_delete', function(cm, vim, helpers) { cm.setCursor(0, 4); helpers.doKeys('2', 'i'); - cm.replaceRange('z', cm.getCursor()); + helpers.doKeys('z') helpers.doInsertModeKeys('Backspace', 'Backspace'); helpers.doKeys(''); eq('abe', cm.getValue()); @@ -1595,6 +1649,31 @@ isAce || testVim('i_overwrite_backspace', function(cm, vim, helpers) { helpers.assertCursorAt(Pos(0, 9, "after")); eq('0123456789', cm.getValue()); }, { value: '0123456789'}); +testVim('i_forward_delete', function(cm, vim, helpers) { + cm.setCursor(0, 3); + helpers.doKeys('i'); + helpers.doInsertModeKeys('Delete'); + helpers.assertCursorAt(0, 3); + eq('A124\nBCD', cm.getValue()); + helpers.doInsertModeKeys('Delete'); + helpers.assertCursorAt(0, 3); + eq('A12\nBCD', cm.getValue()); + helpers.doInsertModeKeys('Delete'); + helpers.assertCursorAt(0, 3); + eq('A12BCD', cm.getValue()); +}, { value: 'A1234\nBCD'}); +testVim('forward_delete', function(cm, vim, helpers) { + cm.setCursor(0, 3); + helpers.doKeys(''); + helpers.assertCursorAt(0, 3); + eq('A124\nBCD', cm.getValue()); + helpers.doKeys(''); + helpers.assertCursorAt(0, 2); + eq('A12\nBCD', cm.getValue()); + helpers.doKeys(''); + helpers.assertCursorAt(0, 1); + eq('A1\nBCD', cm.getValue()); +}, { value: 'A1234\nBCD'}); testVim('A', function(cm, vim, helpers) { helpers.doKeys('A'); helpers.assertCursorAt(0, lines[0].length); @@ -1603,9 +1682,7 @@ testVim('A', function(cm, vim, helpers) { testVim('A_visual_block', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('', '2', 'j', 'l', 'l', 'A'); - var replacement = new Array(cm.listSelections().length+1).join('hello ').split(' '); - replacement.pop(); - cm.replaceSelections(replacement); + helpers.doKeys('hello'); eq('testhello\nmehello\npleahellose', cm.getValue()); helpers.doKeys(''); cm.setCursor(0, 0); @@ -1622,7 +1699,7 @@ testVim('I', function(cm, vim, helpers) { testVim('I_repeat', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('3', 'I'); - cm.replaceRange('test', cm.getCursor()); + helpers.doKeys('test') helpers.doKeys(''); eq('testtesttestblah', cm.getValue()); helpers.assertCursorAt(0, 11); @@ -1630,9 +1707,7 @@ testVim('I_repeat', function(cm, vim, helpers) { testVim('I_visual_block', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('', '2', 'j', 'l', 'l', 'I'); - var replacement = new Array(cm.listSelections().length+1).join('hello ').split(' '); - replacement.pop(); - cm.replaceSelections(replacement); + helpers.doKeys('hello'); eq('hellotest\nhellome\nhelloplease', cm.getValue()); }, {value: 'test\nme\nplease'}); testVim('o', function(cm, vim, helpers) { @@ -1645,7 +1720,7 @@ testVim('o', function(cm, vim, helpers) { testVim('o_repeat', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('3', 'o'); - cm.replaceRange('test', cm.getCursor()); + helpers.doKeys('test') helpers.doKeys(''); eq('\ntest\ntest\ntest', cm.getValue()); helpers.assertCursorAt(3, 3); @@ -1753,7 +1828,6 @@ testVim('r', function(cm, vim, helpers) { cm.setCursor(0, 4); helpers.doKeys('v', 'j', 'h', 'r', ''); eq('wuuu \n her', cm.getValue(),'Replacing selection by space-characters failed'); - if (isAce) return; cm.setValue("ox"); helpers.doKeys('r', ''); eq('ox', cm.getValue()); @@ -1771,8 +1845,8 @@ testVim('r_visual_block', function(cm, vim, helpers) { eq('1 l\n5 l\nalllefg', cm.getValue()); cm.setCursor(2, 0); helpers.doKeys('o'); + helpers.doKeys('\t\t') helpers.doKeys(''); - cm.replaceRange('\t\t', cm.getCursor()); helpers.doKeys('', 'h', 'h', 'r', 'r'); eq('1 l\n5 l\nalllefg\nrrrrrrrr', cm.getValue()); }, {value: '1234\n5678\nabcdefg'}); @@ -2616,7 +2690,7 @@ testVim('g#', function(cm, vim, helpers) { testVim('macro_insert', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('q', 'a', '0', 'i'); - cm.replaceRange('foo', cm.getCursor()); + helpers.doKeys('foo') helpers.doKeys(''); helpers.doKeys('q', '@', 'a'); eq('foofoo', cm.getValue()); @@ -2624,14 +2698,14 @@ testVim('macro_insert', function(cm, vim, helpers) { testVim('macro_insert_repeat', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('q', 'a', '$', 'a'); - cm.replaceRange('larry.', cm.getCursor()); + helpers.doKeys('larry.') helpers.doKeys(''); helpers.doKeys('a'); - cm.replaceRange('curly.', cm.getCursor()); + helpers.doKeys('curly.') helpers.doKeys(''); helpers.doKeys('q'); helpers.doKeys('a'); - cm.replaceRange('moe.', cm.getCursor()); + helpers.doKeys('moe.') helpers.doKeys(''); helpers.doKeys('@', 'a'); // At this point, the most recent edit should be the 2nd insert change @@ -2697,13 +2771,22 @@ testVim('macro_last_ex_command_register', function (cm, vim, helpers) { eq('bbbaa', cm.getValue()); helpers.assertCursorAt(0, 2); }, { value: 'aaaaa'}); +testVim('macro_last_run_macro', function (cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'a', 'C', 'a', '', 'q'); + helpers.doKeys('q', 'b', 'C', 'b', '', 'q'); + helpers.doKeys('@', 'a'); + helpers.doKeys('d', 'd'); + helpers.doKeys('@', '@'); + eq('a', cm.getValue()); +}, { value: ''}); testVim('macro_parens', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('q', 'z', 'i'); - cm.replaceRange('(', cm.getCursor()); + helpers.doKeys('(') helpers.doKeys(''); helpers.doKeys('e', 'a'); - cm.replaceRange(')', cm.getCursor()); + helpers.doKeys(')') helpers.doKeys(''); helpers.doKeys('q'); helpers.doKeys('w', '@', 'z'); @@ -2713,13 +2796,13 @@ testVim('macro_parens', function(cm, vim, helpers) { testVim('macro_overwrite', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('q', 'z', '0', 'i'); - cm.replaceRange('I ', cm.getCursor()); + helpers.doKeys('I ') helpers.doKeys(''); helpers.doKeys('q'); helpers.doKeys('e'); // Now replace the macro with something else. helpers.doKeys('q', 'z', 'a'); - cm.replaceRange('.', cm.getCursor()); + helpers.doKeys('.') helpers.doKeys(''); helpers.doKeys('q'); helpers.doKeys('e', '@', 'z'); @@ -2818,11 +2901,11 @@ testVim('yank_append_word_to_line_register', function(cm, vim, helpers) { testVim('macro_register', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('q', 'a', 'i'); - cm.replaceRange('gangnam', cm.getCursor()); + helpers.doKeys('gangnam') helpers.doKeys(''); helpers.doKeys('q'); helpers.doKeys('q', 'b', 'o'); - cm.replaceRange('style', cm.getCursor()); + helpers.doKeys('style') helpers.doKeys(''); helpers.doKeys('q'); cm.openDialog = helpers.fakeOpenDialog('registers'); @@ -2835,7 +2918,7 @@ testVim('macro_register', function(cm, vim, helpers) { testVim('._register', function(cm,vim,helpers) { cm.setCursor(0,0); helpers.doKeys('i'); - cm.replaceRange('foo',cm.getCursor()); + helpers.doKeys('foo') helpers.doKeys(''); cm.openDialog = helpers.fakeOpenDialog('registers'); cm.openNotification = helpers.fakeOpenNotification(function(text) { @@ -3024,13 +3107,13 @@ testVim('._repeat', function(cm, vim, helpers) { }, { value: '1 2 3 4 5 6'}); testVim('._insert', function(cm, vim, helpers) { helpers.doKeys('i'); - cm.replaceRange('test', cm.getCursor()); + helpers.doKeys('test') helpers.doKeys(''); helpers.doKeys('.'); eq('testestt', cm.getValue()); helpers.assertCursorAt(0, 6); helpers.doKeys('O'); - cm.replaceRange('xyz', cm.getCursor()); + helpers.doKeys('xyz') helpers.doInsertModeKeys('Backspace'); helpers.doInsertModeKeys('Down'); helpers.doKeys(''); @@ -3040,7 +3123,7 @@ testVim('._insert', function(cm, vim, helpers) { }, { value: ''}); testVim('._insert_repeat', function(cm, vim, helpers) { helpers.doKeys('i'); - cm.replaceRange('test', cm.getCursor()); + helpers.doKeys('test') cm.setCursor(0, 4); helpers.doKeys(''); helpers.doKeys('2', '.'); @@ -3049,7 +3132,7 @@ testVim('._insert_repeat', function(cm, vim, helpers) { }, { value: ''}); testVim('._repeat_insert', function(cm, vim, helpers) { helpers.doKeys('3', 'i'); - cm.replaceRange('te', cm.getCursor()); + helpers.doKeys('te') cm.setCursor(0, 2); helpers.doKeys(''); helpers.doKeys('.'); @@ -3058,7 +3141,7 @@ testVim('._repeat_insert', function(cm, vim, helpers) { }, { value: ''}); testVim('._insert_o', function(cm, vim, helpers) { helpers.doKeys('o'); - cm.replaceRange('z', cm.getCursor()); + helpers.doKeys('z') cm.setCursor(1, 1); helpers.doKeys(''); helpers.doKeys('.'); @@ -3067,7 +3150,7 @@ testVim('._insert_o', function(cm, vim, helpers) { }, { value: ''}); testVim('._insert_o_repeat', function(cm, vim, helpers) { helpers.doKeys('o'); - cm.replaceRange('z', cm.getCursor()); + helpers.doKeys('z') helpers.doKeys(''); cm.setCursor(1, 0); helpers.doKeys('2', '.'); @@ -3076,7 +3159,7 @@ testVim('._insert_o_repeat', function(cm, vim, helpers) { }, { value: ''}); testVim('._insert_o_indent', function(cm, vim, helpers) { helpers.doKeys('o'); - cm.replaceRange('z', cm.getCursor()); + helpers.doKeys('z') helpers.doKeys(''); cm.setCursor(1, 2); helpers.doKeys('.'); @@ -3085,7 +3168,7 @@ testVim('._insert_o_indent', function(cm, vim, helpers) { }, { value: '{'}); testVim('._insert_cw', function(cm, vim, helpers) { helpers.doKeys('c', 'w'); - cm.replaceRange('test', cm.getCursor()); + helpers.doKeys('test') helpers.doKeys(''); cm.setCursor(0, 3); helpers.doKeys('2', 'l'); @@ -3097,7 +3180,7 @@ testVim('._insert_cw_repeat', function(cm, vim, helpers) { // For some reason, repeat cw in desktop VIM will does not repeat insert mode // changes. Will conform to that behavior. helpers.doKeys('c', 'w'); - cm.replaceRange('test', cm.getCursor()); + helpers.doKeys('test'); helpers.doKeys(''); cm.setCursor(0, 4); helpers.doKeys('l'); @@ -3334,7 +3417,6 @@ testVim('Ty,;', function(cm, vim, helpers) { eq('01230123456789', cm.getValue()); }, { value: '0123456789'}); testVim('HML', function(cm, vim, helpers) { - if (phantom) return; var lines = 35; var textHeight = cm.defaultTextHeight(); cm.setSize(600, lines*textHeight); @@ -3394,11 +3476,9 @@ testVim('zt_to_top', function(cm, vim, helpers){ return new Array(500).join('\n'); })()}); testVim('zb', 'insert'); @@ -4336,21 +4445,21 @@ testVim('ex_imap', function(cm, vim, helpers) { cm.setCursor(0, 1); CodeMirror.Vim.map('jj', '', 'insert'); helpers.doKeys('', '2', 'j', 'l', 'c'); - var replacement = fillArray('fo', 3); - cm.replaceSelections(replacement); + helpers.doKeys('f', 'o'); eq('1fo4\n5fo8\nafodefg', cm.getValue()); helpers.doKeys('j', 'j'); cm.setCursor(0, 0); helpers.doKeys('.'); eq('foo4\nfoo8\nfoodefg', cm.getValue()); + CodeMirror.Vim.mapclear(); }, { value: '1234\n5678\nabcdefg' }); testVim('ex_unmap_api', function(cm, vim, helpers) { CodeMirror.Vim.map('', 'gg', 'normal'); is(CodeMirror.Vim.handleKey(cm, "", "normal"), "Alt-X key is mapped"); CodeMirror.Vim.unmap("", "normal"); is(!CodeMirror.Vim.handleKey(cm, "", "normal"), "Alt-X key is unmapped"); + CodeMirror.Vim.mapclear(); }); - // Testing registration of functions as ex-commands and mapping to -keys testVim('ex_api_test', function(cm, vim, helpers) { var res=false; @@ -4364,6 +4473,7 @@ testVim('ex_api_test', function(cm, vim, helpers) { CodeMirror.Vim.map('',':ext'); helpers.doKeys('',''); is(res,'Mapping to key failed'); + CodeMirror.Vim.mapclear(); }); // For now, this test needs to be last because it messes up : for future tests. testVim('ex_map_key2key_from_colon', function(cm, vim, helpers) { @@ -4371,8 +4481,67 @@ testVim('ex_map_key2key_from_colon', function(cm, vim, helpers) { helpers.doKeys(':'); helpers.assertCursorAt(0, 0); eq('bc', cm.getValue()); + CodeMirror.Vim.mapclear(); }, { value: 'abc' }); +testVim('noremap', function(cm, vim, helpers) { + CodeMirror.Vim.noremap(';', 'l'); + cm.setCursor(0, 0); + eq('wOrd1', cm.getValue()); + // Mapping should work in normal mode. + helpers.doKeys(';', 'r', '1'); + eq('w1rd1', cm.getValue()); + // Mapping will not work in insert mode because of no current fallback + // keyToKey mapping support. + helpers.doKeys('i', ';', ''); + eq('w;1rd1', cm.getValue()); + // unmap all mappings + CodeMirror.Vim.mapclear(); +}, { value: 'wOrd1' }); +testVim('noremap_swap', function(cm, vim, helpers) { + CodeMirror.Vim.noremap('i', 'a', 'normal'); + CodeMirror.Vim.noremap('a', 'i', 'normal'); + cm.setCursor(0, 0); + // 'a' should act like 'i'. + helpers.doKeys('a'); + eqCursorPos(Pos(0, 0), cm.getCursor()); + // ...and 'i' should act like 'a'. + helpers.doKeys('', 'i'); + eqCursorPos(Pos(0, 1), cm.getCursor()); + // unmap all mappings + CodeMirror.Vim.mapclear(); +}, { value: 'foo' }); +testVim('noremap_map_interaction', function(cm, vim, helpers) { + // noremap should clobber map + CodeMirror.Vim.map(';', 'l'); + CodeMirror.Vim.noremap(';', 'l'); + CodeMirror.Vim.map('l', 'j'); + cm.setCursor(0, 0); + helpers.doKeys(';'); + eqCursorPos(Pos(0, 1), cm.getCursor()); + helpers.doKeys('l'); + eqCursorPos(Pos(1, 1), cm.getCursor()); + // map should be able to point to a noremap + CodeMirror.Vim.map('m', ';'); + helpers.doKeys('m'); + eqCursorPos(Pos(1, 2), cm.getCursor()); + // unmap all mappings + CodeMirror.Vim.mapclear(); +}, { value: 'wOrd1\nwOrd2' }); +testVim('noremap_map_interaction2', function(cm, vim, helpers) { + // map should point to the most recent noremap + CodeMirror.Vim.noremap(';', 'l'); + CodeMirror.Vim.map('m', ';'); + CodeMirror.Vim.noremap(';', 'h'); + cm.setCursor(0, 0); + helpers.doKeys('l'); + eqCursorPos(Pos(0, 1), cm.getCursor()); + helpers.doKeys('m'); + eqCursorPos(Pos(0, 0), cm.getCursor()); + // unmap all mappings + CodeMirror.Vim.mapclear(); +}, { value: 'wOrd1\nwOrd2' }); + // Test event handlers testVim('beforeSelectionChange', function(cm, vim, helpers) { cm.setCursor(0, 100); From 641037837261916bd9096f02067f3681f31e99ef Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 14 May 2019 21:37:23 +0400 Subject: [PATCH 0161/1293] [vim] fix blockwise yank --- lib/ace/keyboard/vim.js | 18 +++++++++++------- lib/ace/keyboard/vim_test.js | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index de7b14e5ac6..4125a210faf 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -3357,7 +3357,17 @@ dom.importCssString(".normal-mode .ace_cursor{\ } var linewise = register.linewise; var blockwise = register.blockwise; - if (linewise && !blockwise) { // ace_patch + if (blockwise) { + text = text.split('\n'); + if (linewise) { + text.pop(); + } + for (var i = 0; i < text.length; i++) { + text[i] = (text[i] == '') ? ' ' : text[i]; + } + cur.ch += actionArgs.after ? 1 : 0; + cur.ch = Math.min(lineLength(cm, cur.line), cur.ch); + } else if (linewise) { if(vim.visualMode) { text = vim.visualLine ? text.slice(0, -1) : '\n' + text.slice(0, text.length - 1) + '\n'; } else if (actionArgs.after) { @@ -3369,12 +3379,6 @@ dom.importCssString(".normal-mode .ace_cursor{\ cur.ch = 0; } } else { - if (blockwise) { - text = text.split('\n'); - for (var i = 0; i < text.length; i++) { - text[i] = (text[i] == '') ? ' ' : text[i]; - } - } cur.ch += actionArgs.after ? 1 : 0; } var curPosFinal; diff --git a/lib/ace/keyboard/vim_test.js b/lib/ace/keyboard/vim_test.js index ecd964d73e8..ac3084ffae1 100644 --- a/lib/ace/keyboard/vim_test.js +++ b/lib/ace/keyboard/vim_test.js @@ -1523,6 +1523,21 @@ testVim('Y', function(cm, vim, helpers) { is(register.linewise); helpers.assertCursorAt(0, 3); }, { value: ' word1\nword2\n word3' }); +testVim('Yy_blockwise', function(cm, vim, helpers) { + helpers.doKeys('', 'j', '2', 'l', 'Y'); + helpers.doKeys('G', 'p', 'g', 'g'); + helpers.doKeys('', 'j', '2', 'l', 'y'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('$', 'p'); + eq('123456123\n123456123\n123456\n123456', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('123\n123', register.toString()); + is(register.blockwise); + helpers.assertCursorAt(0, 6); + helpers.doKeys('$', 'j', 'p'); + helpers.doKeys('$', 'j', 'P'); + eq("123456123\n123456123123\n123456 121233\n123456 123", cm.getValue()); +}, { value: '123456\n123456\n' }); testVim('~', function(cm, vim, helpers) { helpers.doKeys('3', '~'); eq('ABCdefg', cm.getValue()); From dd94d564b8ea143b81ad39998b6d76745e8177bc Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 14 May 2019 21:38:21 +0400 Subject: [PATCH 0162/1293] improve devutil --- demo/kitchen-sink/dev_util.js | 22 ++++++---------------- package.json | 3 ++- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/demo/kitchen-sink/dev_util.js b/demo/kitchen-sink/dev_util.js index 33bf0ca0292..b16fef61a5f 100644 --- a/demo/kitchen-sink/dev_util.js +++ b/demo/kitchen-sink/dev_util.js @@ -34,18 +34,6 @@ var event = require("ace/lib/event"); var Range = require("ace/range").Range; var EditSession = require("ace/edit_session").EditSession; var UndoManager = require("ace/undomanager").UndoManager; -function warn() { - var s = (new Error()).stack || ""; - s = s.split("\n"); - if (s[1] == "Error") s.shift(); // remove error description on chrome - s.shift(); // remove warn - s.shift(); // remove the getter - s = s.join("\n"); - // allow easy access to ace in console, but not in ace code - if (!/at Object.InjectedScript.|@debugger eval|snippets:\/{3}|:\d+:\d+/.test(s)) { - console.error("trying to access to global variable"); - } -} function def(o, key, get) { try { Object.defineProperty(o, key, { @@ -60,13 +48,13 @@ function def(o, key, get) { console.error(e); } } -def(window, "ace", function(){ warn(); return window.env.editor }); -def(window, "editor", function(){ warn(); return window.env.editor == logEditor ? editor : window.env.editor }); +def(window, "ace", function(){ return window.env.editor }); +def(window, "editor", function(){ return window.env.editor == logEditor ? editor : window.env.editor }); def(window, "session", function(){ return window.editor.session }); -def(window, "split", function(){ warn(); return window.env.split }); +def(window, "split", function(){ return window.env.split }); -def(window, "devUtil", function(){ warn(); return exports }); +def(window, "devUtil", function(){ return exports }); exports.showTextArea = function(argument) { dom.importCssString("\ .ace_text-input {\ @@ -428,4 +416,6 @@ exports.textInputDebugger = { } } +exports.addGlobals(); + }); diff --git a/package.json b/package.json index 30b08a160d2..f9323dc7ec3 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "scripts": { "start": "node static.js", "test": "node lib/ace/test/all.js", - "lint": "eslint 'lib/ace/**/*.js'" + "lint": "eslint 'lib/ace/**/*.js'", + "fix": "eslint --fix 'lib/ace/**/*.js'" } } From 9bfb4f362ce5278be9dcd8e20d4d4711d2226e74 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 27 Apr 2019 01:15:35 +0400 Subject: [PATCH 0163/1293] move version to config --- lib/ace/ace.js | 2 +- lib/ace/config.js | 2 ++ lib/ace/ext/options.js | 4 +++- tool/release.sh | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/ace/ace.js b/lib/ace/ace.js index e34003b670e..be2be04b63e 100644 --- a/lib/ace/ace.js +++ b/lib/ace/ace.js @@ -132,5 +132,5 @@ exports.Editor = Editor; exports.EditSession = EditSession; exports.UndoManager = UndoManager; exports.VirtualRenderer = Renderer; -exports.version = "1.4.4"; +exports.version = exports.config.version; }); diff --git a/lib/ace/config.js b/lib/ace/config.js index bfbd83f44fc..c41fb604a9c 100644 --- a/lib/ace/config.js +++ b/lib/ace/config.js @@ -219,4 +219,6 @@ function deHyphenate(str) { return str.replace(/-(.)/g, function(m, m1) { return m1.toUpperCase(); }); } +exports.version = "1.4.4"; + }); diff --git a/lib/ace/ext/options.js b/lib/ace/ext/options.js index dafe40387c8..58cbb507332 100644 --- a/lib/ace/ext/options.js +++ b/lib/ace/ext/options.js @@ -5,6 +5,7 @@ var overlayPage = require('./menu_tools/overlay_page').overlayPage; var dom = require("../lib/dom"); var oop = require("../lib/oop"); +var config = require("../config"); var EventEmitter = require("../lib/event_emitter").EventEmitter; var buildDom = dom.buildDom; @@ -209,7 +210,8 @@ var OptionPanel = function(editor, element) { ["table", {id: "more-controls"}, this.renderOptionGroup(optionGroups.More) ] - ]] + ]], + ["tr", null, ["td", {colspan: 2}, "version " + config.version]] ], this.container); }; diff --git a/tool/release.sh b/tool/release.sh index 9caee348194..5c1a25f0886 100755 --- a/tool/release.sh +++ b/tool/release.sh @@ -73,7 +73,7 @@ node -e " } update('package.json'); update('build/package.json'); - update('./lib/ace/ace.js'); + update('./lib/ace/config.js'); update('ChangeLog.txt', function(str) { var date='"`date +%Y.%m.%d`"'; return date + ' Version ' + version + '\n' + str.replace(/^\d+.*/, '').replace(/^\n/, ''); From e2adfefdeea85ba3f38a5a74f18adf596d056ea5 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 14 May 2019 23:39:05 +0400 Subject: [PATCH 0164/1293] add ` to markdown quotes --- lib/ace/mode/markdown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ace/mode/markdown.js b/lib/ace/mode/markdown.js index 61a96f7edd0..f6c73d2ce03 100644 --- a/lib/ace/mode/markdown.js +++ b/lib/ace/mode/markdown.js @@ -59,6 +59,7 @@ oop.inherits(Mode, TextMode); (function() { this.type = "text"; this.blockComment = {start: ""}; + this.$quotes = {'"': '"', "`": "`"}; this.getNextLineIndent = function(state, line, tab) { if (state == "listblock") { From 49b923d2ed46c2e495538715c07b13b5e549a0b4 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 13 May 2019 16:06:54 +0000 Subject: [PATCH 0165/1293] touch handler --- .eslintrc | 4 +- experiments/cut_copy.html | 41 +++++- kitchen-sink.html | 1 + lib/ace/lib/event.js | 24 ---- lib/ace/mouse/default_handlers.js | 5 - lib/ace/mouse/mouse_handler.js | 11 +- lib/ace/mouse/touch_handler.js | 232 ++++++++++++++++++++++++++++++ 7 files changed, 277 insertions(+), 41 deletions(-) create mode 100644 lib/ace/mouse/touch_handler.js diff --git a/.eslintrc b/.eslintrc index 89da3026afa..5395a034dcb 100644 --- a/.eslintrc +++ b/.eslintrc @@ -75,7 +75,7 @@ no-undef: 2, no-redeclare: 0, - // no-unused-vars: 1, + no-unused-vars: 1, no-debugger: 2, @@ -88,7 +88,7 @@ // no-useless-concat: 2, // no-eval: 2, // dot-notation: 2, - // no-alert: 2, + no-alert: 2, no-extra-semi: 2, // doesn't handle ;(function() {})() pattern // radix: 2, // no-invalid-this: 2, diff --git a/experiments/cut_copy.html b/experiments/cut_copy.html index 3299f3ad618..9fcaf224111 100644 --- a/experiments/cut_copy.html +++ b/experiments/cut_copy.html @@ -4,6 +4,7 @@ + Text Events @@ -20,6 +21,10 @@ width: 590px; height: 400px; } + + #text { + position: absolute; + } @@ -70,6 +75,39 @@ console.log(e.type, e.charCode, e.keyCode, e); } +addListener(canvas, "mousedown", function(e) { + text.focus(); + e.preventDefault(); +}, false); + +var pos; +addListener(canvas, "touchstart", function(e) { + text.value = "" + pos = e.touches[0] + text.focus(); +}, false); +addListener(canvas, "contextmenu", function(e) { + text.value = "xxxxx"; + var rect = canvas.getBoundingClientRect() + // text.selectionStart = 0 + // text.selectionEnd = 20 + text.style.opacity = 0 + text.style.top = pos.clientY - 15 - rect.top + "px" + text.style.left = pos.clientX - 15 - rect.left + "px" + // canvas.style.fontSize = "300px" + // text.readOnly = true + // text.focus(); + text.style.width = "50px" + text.style.height = "50px" + text.select(); + setTimeout(function() { + text.readOnly = false + // text.style.top = pos.clientY - 5 + "px" + // text.style.left = pos.clientY - 5 + "px" + }, 100) + //e.preventDefault(); +}, false); + addListener(text, "keydown", logKey, false); addListener(text, "keyup", logKey, false); addListener(text, "keypress", logKey, false); @@ -78,8 +116,9 @@ console.log(e.type, e.data, e); }, false); +var i = 0; function fillSelection() { - text.value = "Juhu Kinners"; + text.value = "Juhu Kinners " + (i++); text.select(); } diff --git a/kitchen-sink.html b/kitchen-sink.html index c4be9da5a9f..89cd9443899 100644 --- a/kitchen-sink.html +++ b/kitchen-sink.html @@ -3,6 +3,7 @@ + Ace Kitchen Sink "); - - next(); }, - "test beautify js array of objects": function(next) { + "test beautify js array of objects": function() { var s = new EditSession([ ""); - - next(); }, - "test beautify js object": function(next) { + "test beautify js object": function() { var s = new EditSession([ '' ], new PHPMode()); @@ -423,8 +381,6 @@ module.exports = { + "\t\t\"b\": \"2\"\n" + "\t}\n" + ""); - - next(); } }; From 9a229d02b525ec667bc6d389a2e3d7b616336d4d Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 1 Feb 2020 14:20:16 +0700 Subject: [PATCH 0278/1293] removing preventDefault method this method cause editor to open virtual keyboard when scrolling and has focus at the same time --- lib/ace/mouse/touch_handler.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ace/mouse/touch_handler.js b/lib/ace/mouse/touch_handler.js index 07ae36b8b9f..78b2f9f5cfe 100644 --- a/lib/ace/mouse/touch_handler.js +++ b/lib/ace/mouse/touch_handler.js @@ -251,7 +251,6 @@ exports.addTouchListeners = function(el, editor) { showContextMenu(); } else if (mode == "scroll") { animate(); - e.preventDefault(); hideContextMenu(); } else { showContextMenu(); From 473831323e61feab63ff9e824f83d41b78ffe916 Mon Sep 17 00:00:00 2001 From: Nathan Whetsell Date: Wed, 5 Feb 2020 09:20:45 -0500 Subject: [PATCH 0279/1293] Update for Csound 6.14.0 --- lib/ace/mode/csound_orchestra_highlight_rules.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/ace/mode/csound_orchestra_highlight_rules.js b/lib/ace/mode/csound_orchestra_highlight_rules.js index 138f106e004..da5d6ef8253 100644 --- a/lib/ace/mode/csound_orchestra_highlight_rules.js +++ b/lib/ace/mode/csound_orchestra_highlight_rules.js @@ -230,11 +230,19 @@ var CsoundOrchestraHighlightRules = function(embeddedRulePrefix) { "chnclear", "chnexport", "chnget", + "chngeta", + "chngeti", + "chngetk", "chngetks", + "chngets", "chnmix", "chnparams", "chnset", + "chnseta", + "chnseti", + "chnsetk", "chnsetks", + "chnsets", "chuap", "clear", "clfilt", @@ -432,6 +440,7 @@ var CsoundOrchestraHighlightRules = function(embeddedRulePrefix) { "ftchnls", "ftconv", "ftcps", + "ftexists", "ftfree", "ftgen", "ftgenonce", @@ -713,6 +722,7 @@ var CsoundOrchestraHighlightRules = function(embeddedRulePrefix) { "la_k_upper_solve_mr", "la_k_vc_set", "la_k_vr_set", + "lastcycle", "lenarray", "lfo", "limit", @@ -803,6 +813,7 @@ var CsoundOrchestraHighlightRules = function(embeddedRulePrefix) { "median", "mediank", "metro", + "metro2", "mfb", "midglobal", "midiarp", @@ -1157,6 +1168,7 @@ var CsoundOrchestraHighlightRules = function(embeddedRulePrefix) { "qnan", "r2c", "rand", + "randc", "randh", "randi", "random", @@ -1217,6 +1229,7 @@ var CsoundOrchestraHighlightRules = function(embeddedRulePrefix) { "schedkwhen", "schedkwhennamed", "schedule", + "schedulek", "schedwhen", "scoreline", "scoreline_i", @@ -1327,6 +1340,7 @@ var CsoundOrchestraHighlightRules = function(embeddedRulePrefix) { "strrindex", "strrindexk", "strset", + "strstrip", "strsub", "strsubk", "strtod", From b48c893b731c18a8763cc88a52134ac6f1cb0d88 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Fri, 14 Feb 2020 18:53:34 +0000 Subject: [PATCH 0280/1293] Add files via upload --- lib/ace/mode/mediawiki.js | 20 + lib/ace/mode/mediawiki_highlight_rules.js | 558 ++++++++++++++++++++++ 2 files changed, 578 insertions(+) create mode 100644 lib/ace/mode/mediawiki.js create mode 100644 lib/ace/mode/mediawiki_highlight_rules.js diff --git a/lib/ace/mode/mediawiki.js b/lib/ace/mode/mediawiki.js new file mode 100644 index 00000000000..e6a48f31877 --- /dev/null +++ b/lib/ace/mode/mediawiki.js @@ -0,0 +1,20 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var MediaWikiHighlightRules = require("./mediawiki_highlight_rules").MediaWikiHighlightRules; + +var Mode = function() { + this.HighlightRules = MediaWikiHighlightRules; +}; +oop.inherits(Mode, TextMode); + +(function() { + this.type = "text"; + this.blockComment = {start: ""}; + this.$id = "ace/mode/mediawiki"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/lib/ace/mode/mediawiki_highlight_rules.js b/lib/ace/mode/mediawiki_highlight_rules.js new file mode 100644 index 00000000000..65063bcb31f --- /dev/null +++ b/lib/ace/mode/mediawiki_highlight_rules.js @@ -0,0 +1,558 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var MediaWikiHighlightRules = function() { + this.$rules = { + start: [{ + include: "#variable" + }, { + include: "#comment" + }, { + include: "#entity" + }, { + include: "#emphasis" + }, { + include: "#tag" + }, { + include: "#table" + }, { + include: "#hr" + }, { + include: "#heading" + }, { + include: "#link" + }, { + include: "#list" + }, { + include: "#template" + }], + "#hr": [{ + token: "markup.bold", + regex: /^[-]{4,}/ + }], + "#variable": [{ + token: "storage.type.variable", + regex: /{{{/, + push: [{ + token: "storage.type.variable", + regex: /}}}/, + next: "pop" + }, { + token: [ + "text", + "variable.other", + "text", + "keyword.operator" + ], + regex: /(\s*)(\w+)(\s*)((?:\|)?)/ + }, { + defaultToken: "storage.type.variable" + }] + }], + "#entity": [{ + token: "constant.character.entity", + regex: /&\w+;/ + }], + "#list": [{ + token: "markup.bold", + regex: /^[#*;:]+/, + push: [{ + token: "markup.list", + regex: /$/, + next: "pop" + }, { + include: "$self" + }, { + defaultToken: "markup.list" + }] + }], + "#template": [{ + token: [ + "storage.type.function", + "meta.template", + "entity.name.function", + "meta.template" + ], + regex: /({{)(\s*)([\w ]+)(\s*)/, + push: [{ + token: "storage.type.function", + regex: /}}/, + next: "pop" + }, { + token: [ + "storage", + "meta.structure.dictionary", + "support.type.property-name", + "meta.structure.dictionary", + "punctuation.separator.dictionary.key-value.mediawiki", + "meta.structure.dictionary", + "meta.structure.dictionary.value" + ], + regex: /(\|)(\s*)([a-zA-Z-]*)(\s*)(=)(\s*)([^|}]*)/, + push: [{ + token: "meta.structure.dictionary", + regex: /(?=}}|[|])/, + next: "pop" + }, { + defaultToken: "meta.structure.dictionary" + }] + }, { + token: ["storage", "meta.template.value"], + regex: /(\|)(.*?)/, + push: [{ + token: [], + regex: /(?=}}|[|])/, + next: "pop" + }, { + include: "$self" + }, { + defaultToken: "meta.template.value" + }] + }, { + defaultToken: "meta.template" + }] + }], + "#link": [{ + token: [ + "punctuation.definition.tag.begin", + "meta.tag.link.internal", + "entity.name.tag.mediawiki", + "meta.tag.link.internal", + "string.other.link.title.mediawiki", + "meta.tag.link.internal", + "punctuation.definition.tag" + ], + regex: /(\[\[)(\s*)((?:Category|Wikipedia)?)(:?)([^\]\]\|]+)(\s*)((?:\|)*)/, + push: [{ + token: "punctuation.definition.tag.end", + regex: /\]\]/, + next: "pop" + }, { + include: "$self" + }, { + defaultToken: "meta.tag.link.internal" + }] + }, { + token: [ + "punctuation.definition.tag.begin", + "meta.tag.link.external", + "meta.tag.link.external", + "string.unquoted", + "punctuation.definition.tag.end" + ], + regex: /(\[)(.*?)([\s]+)(.*?)(\])/ + }], + "#comment": [{ + token: "punctuation.definition.comment.html", + regex: //, + next: "pop" + }, { + token: "invalid.illegal.characters-not-allowed-here.html", + regex: /[^-]*-?>/ + }, { + token: "invalid.illegal.characters-not-allowed-here.html", + regex: /)/ + }, { + token: "invalid.illegal.characters-not-allowed-here.html", + regex: /--!>/ + }, { + defaultToken: "comment.block.html" + }] + }], + "#emphasis": [{ + token: [ + "punctuation.definition.tag.begin", + "markup.italic.bold", + "punctuation.definition.tag.end" + ], + regex: /(''''')(?!')(.*?)('''''|$)/ + }, { + token: [ + "punctuation.definition.tag.begin", + "markup.bold", + "punctuation.definition.tag.end" + ], + regex: /(''')(?!')(.*?)('''|$)/ + }, { + token: [ + "punctuation.definition.tag.begin", + "markup.italic", + "punctuation.definition.tag.end" + ], + regex: /('')(?!')(.*?)(''|$)/ + }], + "#heading": [{ + token: [ + "punctuation.definition.heading", + "entity.name.section.mediawiki", + "punctuation.definition.heading" + ], + regex: /(={1,6})(.+?)(\1)(?!=)/ + }], + "#tag": [{ + token: [ + "punctuation.definition.tag.begin", + "entity.name.tag", + "meta.tag.block.ref", + "punctuation.definition.tag.end" + ], + regex: /(<)(ref)((?:\s+.*?)?)(>)/, + caseInsensitive: true, + push: [{ + token: [ + "punctuation.definition.tag.begin", + "entity.name.tag", + "meta.tag.block.ref", + "punctuation.definition.tag.end" + ], + regex: /(<\/)(ref)(\s*)(>)/, + caseInsensitive: true, + next: "pop" + }, { + include: "$self" + }, { + defaultToken: "meta.tag.block.ref" + }] + }, + { + token: [ + "punctuation.definition.tag.begin", + "entity.name.tag", + "meta.tag.block.nowiki", + "punctuation.definition.tag.end" + ], + regex: /(<)(nowiki)((?:\s+.*?)?)(>)/, + caseInsensitive: true, + push: [{ + token: [ + "punctuation.definition.tag.begin", + "entity.name.tag", + "meta.tag.block.nowiki", + "punctuation.definition.tag.end" + ], + regex: /(<\/)(nowiki)(\s*)(>)/, + caseInsensitive: true, + next: "pop" + }, { + defaultToken: "meta.tag.block.nowiki" + }] + }, { + token: [ + "punctuation.definition.tag.begin", + "entity.name.tag" + ], + regex: /(<\/?)(noinclude|includeonly|onlyinclude)(?=\W)/, + caseInsensitive: true, + push: [{ + token: [ + "invalid.illegal.characters-not-allowed-here", + "punctuation.definition.tag.end" + ], + regex: /((?:\/)?)(>)/, + next: "pop" + }, { + include: "#attribute" + }, { + defaultToken: "meta.tag.block.any" + }] + }, { + token: [ + "punctuation.definition.tag.begin", + "entity.name.tag" + ], + regex: /(<)(br|wbr|hr|meta|link)(?=\W)/, + caseInsensitive: true, + push: [{ + token: "punctuation.definition.tag.end", + regex: /\/?>/, + next: "pop" + }, { + include: "#attribute" + }, { + defaultToken: "meta.tag.other" + }] + }, { + token: [ + "punctuation.definition.tag.begin", + "entity.name.tag" + ], + regex: /(<\/?)(div|center|span|h1|h2|h3|h4|h5|h6|bdo|em|strong|cite|dfn|code|samp|kbd|var|abbr|blockquote|q|sub|sup|p|pre|ins|del|ul|ol|li|dl|dd|dt|table|caption|thead|tfoot|tbody|colgroup|col|tr|td|th|a|img|video|source|track|tt|b|i|big|small|strike|s|u|font|ruby|rb|rp|rt|rtc|math|figure|figcaption|bdi|data|time|mark|html)(?=\W)/, + caseInsensitive: true, + push: [{ + token: [ + "invalid.illegal.characters-not-allowed-here", + "punctuation.definition.tag.end" + ], + regex: /((?:\/)?)(>)/, + next: "pop" + }, { + include: "#attribute" + }, { + defaultToken: "meta.tag.block" + }] + }, { + token: [ + "punctuation.definition.tag.begin", + "invalid.illegal.characters-not-allowed-here" + ], + regex: /(<\/)(br|wbr|hr|meta|link)(?=\W)/, + caseInsensitive: true, + push: [{ + token: "punctuation.definition.tag.end", + regex: /\/?>/, + next: "pop" + }, { + include: "#attribute" + }, { + defaultToken: "meta.tag.other" + }] + }], + "#caption": [{ + token: [ + "meta.tag.block.table-caption", + "punctuation.definition.tag.begin" + ], + regex: /^(\s*)(\|\+)/, + push: [{ + token: "meta.tag.block.table-caption", + regex: /$/, + next: "pop" + }, { + defaultToken: "meta.tag.block.table-caption" + }] + }], + "#tr": [{ + token: [ + "meta.tag.block.tr", + "punctuation.definition.tag.begin", + "meta.tag.block.tr", + "invalid.illegal" + ], + regex: /^(\s*)(\|\-)([\s]*)(.*)/ + }], + "#th": [{ + token: [ + "meta.tag.block.th.heading", + "punctuation.definition.tag.begin", + "meta.tag.block.th.heading", + "punctuation.definition.tag", + "markup.bold" + ], + regex: /^(\s*)(!)(?:(.*?)(\|))?(.*?)(?=!!|$)/, + push: [{ + token: "meta.tag.block.th.heading", + regex: /$/, + next: "pop" + }, { + token: [ + "punctuation.definition.tag.begin", + "meta.tag.block.th.inline", + "punctuation.definition.tag", + "markup.bold" + ], + regex: /(!!)(?:(.*?)(\|))?(.*?)(?=!!|$)/ + }, { + include: "$self" + }, { + defaultToken: "meta.tag.block.th.heading" + }] + }], + "#td": [{ + token: [ + "meta.tag.block.td", + "punctuation.definition.tag.begin" + ], + regex: /^(\s*)(\|)/, + push: [{ + token: "meta.tag.block.td", + regex: /$/, + next: "pop" + }, { + include: "$self" + }, { + defaultToken: "meta.tag.block.td" + }] + }], + "#table": [{ + patterns: [{ + name: "meta.tag.block.table", + begin: "^\\s*({\\|)(.*?)$", + end: "^\\s*\\|}", + beginCaptures: { + 1: { + name: "punctuation.definition.tag.begin" + }, + 2: { + patterns: [{ + include: "#attribute" + }] + }, + 3: { + name: "invalid.illegal" + } + }, + endCaptures: { + 0: { + name: "punctuation.definition.tag.end" + } + }, + patterns: [{ + include: "#comment" + }, { + include: "#template" + }, { + include: "#caption" + }, { + include: "#tr" + }, { + include: "#th" + }, { + include: "#td" + }] + }], + repository: { + caption: { + name: "meta.tag.block.table-caption", + begin: "^\\s*(\\|\\+)", + end: "$", + beginCaptures: { + 1: { + name: "punctuation.definition.tag.begin" + } + } + }, + tr: { + name: "meta.tag.block.tr", + match: "^\\s*(\\|\\-)[\\s]*(.*)", + captures: { + 1: { + name: "punctuation.definition.tag.begin" + }, + 2: { + name: "invalid.illegal" + } + } + }, + th: { + name: "meta.tag.block.th.heading", + begin: "^\\s*(!)((.*?)(\\|))?(.*?)(?=(!!)|$)", + end: "$", + beginCaptures: { + 1: { + name: "punctuation.definition.tag.begin" + }, + 3: { + patterns: [{ + include: "#attribute" + }] + }, + 4: { + name: "punctuation.definition.tag" + }, + 5: { + name: "markup.bold" + } + }, + patterns: [{ + name: "meta.tag.block.th.inline", + match: "(!!)((.*?)(\\|))?(.*?)(?=(!!)|$)", + captures: { + 1: { + name: "punctuation.definition.tag.begin" + }, + 3: { + patterns: [{ + include: "#attribute" + }] + }, + 4: { + name: "punctuation.definition.tag" + }, + 5: { + name: "markup.bold" + } + } + }, { + include: "$self" + }] + }, + td: { + name: "meta.tag.block.td", + begin: "^\\s*(\\|)", + end: "$", + beginCaptures: { + 1: { + name: "punctuation.definition.tag.begin" + }, + 2: { + patterns: [{ + include: "#attribute" + }] + }, + 3: { + name: "punctuation.definition.tag" + } + }, + patterns: [{ + include: "$self" + }] + } + } + }], + "#attribute": [{ + include: "#string" + }, { + token: "entity.other.attribute-name", + regex: /\w+/ + }], + "#string": [{ + token: "string.quoted.double", + regex: /\"/, + push: [{ + token: "string.quoted.double", + regex: /\"/, + next: "pop" + }, { + defaultToken: "string.quoted.double" + }] + }, { + token: "string.quoted.single", + regex: /\'/, + push: [{ + token: "string.quoted.single", + regex: /\'/, + next: "pop" + }, { + defaultToken: "string.quoted.single" + }] + }], + "#url": [{ + token: "markup.underline.link", + regex: /(?:http(?:s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:\/?#\[\]@!\$&'\(\)\*\+,;=.]+/ + }, { + token: "invalid.illegal.characters-not-allowed-here", + regex: /.*/ + }] + }; + + + this.normalizeRules(); +}; + +MediaWikiHighlightRules.metaData = { + name: "MediaWiki", + scopeName: "text.html.mediawiki", + fileTypes: ["mediawiki", "wiki"] +}; + + +oop.inherits(MediaWikiHighlightRules, TextHighlightRules); + +exports.MediaWikiHighlightRules = MediaWikiHighlightRules; +}); From 2087a585e5ed28c4c0be2b5092c3caea6072d8b1 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Fri, 14 Feb 2020 19:36:51 +0000 Subject: [PATCH 0281/1293] remove comment validation & vscode token classes --- lib/ace/mode/mediawiki_highlight_rules.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/lib/ace/mode/mediawiki_highlight_rules.js b/lib/ace/mode/mediawiki_highlight_rules.js index 65063bcb31f..a3b894df6d7 100644 --- a/lib/ace/mode/mediawiki_highlight_rules.js +++ b/lib/ace/mode/mediawiki_highlight_rules.js @@ -152,15 +152,6 @@ var MediaWikiHighlightRules = function() { token: "punctuation.definition.comment.html", regex: /-->/, next: "pop" - }, { - token: "invalid.illegal.characters-not-allowed-here.html", - regex: /[^-]*-?>/ - }, { - token: "invalid.illegal.characters-not-allowed-here.html", - regex: /)/ - }, { - token: "invalid.illegal.characters-not-allowed-here.html", - regex: /--!>/ }, { defaultToken: "comment.block.html" }] @@ -251,7 +242,7 @@ var MediaWikiHighlightRules = function() { caseInsensitive: true, push: [{ token: [ - "invalid.illegal.characters-not-allowed-here", + "invalid.illegal", "punctuation.definition.tag.end" ], regex: /((?:\/)?)(>)/, @@ -286,7 +277,7 @@ var MediaWikiHighlightRules = function() { caseInsensitive: true, push: [{ token: [ - "invalid.illegal.characters-not-allowed-here", + "invalid.illegal", "punctuation.definition.tag.end" ], regex: /((?:\/)?)(>)/, @@ -299,7 +290,7 @@ var MediaWikiHighlightRules = function() { }, { token: [ "punctuation.definition.tag.begin", - "invalid.illegal.characters-not-allowed-here" + "invalid.illegal" ], regex: /(<\/)(br|wbr|hr|meta|link)(?=\W)/, caseInsensitive: true, @@ -536,7 +527,7 @@ var MediaWikiHighlightRules = function() { token: "markup.underline.link", regex: /(?:http(?:s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:\/?#\[\]@!\$&'\(\)\*\+,;=.]+/ }, { - token: "invalid.illegal.characters-not-allowed-here", + token: "invalid.illegal", regex: /.*/ }] }; From e5b81c0104249fc19835840b7b90854b210ef566 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Fri, 14 Feb 2020 20:51:04 +0000 Subject: [PATCH 0282/1293] add support for parser functions, Lua invocations --- lib/ace/mode/mediawiki_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/mediawiki_highlight_rules.js b/lib/ace/mode/mediawiki_highlight_rules.js index a3b894df6d7..36e5e18784a 100644 --- a/lib/ace/mode/mediawiki_highlight_rules.js +++ b/lib/ace/mode/mediawiki_highlight_rules.js @@ -76,7 +76,7 @@ var MediaWikiHighlightRules = function() { "entity.name.function", "meta.template" ], - regex: /({{)(\s*)([\w ]+)(\s*)/, + regex: /({{)(\s*)([#\w: ]+)(\s*)/, push: [{ token: "storage.type.function", regex: /}}/, From 58cab80c616b3633448d62200b3832547e59d6c7 Mon Sep 17 00:00:00 2001 From: Gary Date: Thu, 20 Feb 2020 11:05:54 -0800 Subject: [PATCH 0283/1293] accessibility fixes to Kitchen Sink demo page I will be working with a developer who is blind to help evaluate Ace accessibility improvements I'll be making so having the kitchen sink be usable by him is potentially helpful. Also doing this for the practice and to avoid working on the more difficult problems of screen reader support in Ace itself just a little bit longer. - Fix the toggle control in upper-left work like a button (keyboard and screen reader in addition to mouse), and give it a label for screen readers - Mark layout tables as being for presentation so they aren't surfaced as containing tabular data by screen readers - Wrap the Test controls in a named group so screen reader identifies them as part of that group - Give the "O" and "X" test buttons more descriptive names for screen reader - Supply alt-text for the two image-based links in the options panel - Fix how ids and labels are associated for options containing multiple controls such as "Soft Tabs" and "Show Print Margin" and give the second control a screen reader label - Separate the option for persistent horizontal and vertical scrollbars into two rows - Improve the button-bar control to put them in named groups and to indicate which button is pressed via aria-pressed - Change styling of keyboard focus indicators (defaults are very hard to see on a blue background) --- demo/kitchen-sink/demo.js | 22 +++++++++++++++++----- demo/kitchen-sink/dev_util.js | 6 +++--- demo/kitchen-sink/styles.css | 11 ++++++++++- kitchen-sink.html | 8 ++++---- lib/ace/ext/options.js | 31 ++++++++++++++++++++++--------- 5 files changed, 56 insertions(+), 22 deletions(-) diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 634da7d2c64..603475e5c7f 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -255,13 +255,22 @@ commands.addCommand({ /*********** manage layout ***************************/ -var sidePanelContainer = document.getElementById("sidePanel"); -sidePanelContainer.onclick = function(e) { +function handleToggleActivate(target) { if (dom.hasCssClass(sidePanelContainer, "closed")) onResize(null, false); - else if (dom.hasCssClass(e.target, "toggleButton")) + else if (dom.hasCssClass(target, "toggleButton")) onResize(null, true); -} +}; +var sidePanelContainer = document.getElementById("sidePanel"); +sidePanelContainer.onclick = function(e) { + handleToggleActivate(e.target); +}; +var optionToggle = document.getElementById("optionToggle"); +optionToggle.onkeydown = function(e) { + if (e.code === "Space" || e.code === "Enter") { + handleToggleActivate(e.target); + } +}; var consoleHeight = 20; function onResize(e, closeSidePanel) { var left = 280; @@ -269,8 +278,11 @@ function onResize(e, closeSidePanel) { var height = document.documentElement.clientHeight; if (closeSidePanel == null) closeSidePanel = width < 2 * left; - if (closeSidePanel) + if (closeSidePanel) { left = 20; + document.getElementById("optionToggle").setAttribute("aria-label", "Show Options"); + } else + document.getElementById("optionToggle").setAttribute("aria-label", "Hide Options"); width -= left; container.style.width = width + "px"; container.style.height = height - consoleHeight + "px"; diff --git a/demo/kitchen-sink/dev_util.js b/demo/kitchen-sink/dev_util.js index b049c325157..c22cc4b1706 100644 --- a/demo/kitchen-sink/dev_util.js +++ b/demo/kitchen-sink/dev_util.js @@ -293,13 +293,13 @@ function toString(x) { } exports.getUI = function(container) { - return ["div", {}, + return ["div", {role: "group", "aria-label": "Test"}, " Test ", - ["button", {onclick: exports.openLogView}, "O"], + ["button", {"aria-label": "Open Log View", onclick: exports.openLogView}, "O"], ["button", {onclick: exports.record}, "Record"], ["button", {onclick: exports.stop}, "Stop"], ["button", {onclick: exports.play}, "Play"], - ["button", {onclick: exports.closeLogView}, "X"], + ["button", {"aria-label": "Close Log View", onclick: exports.closeLogView}, "X"], ]; }; diff --git a/demo/kitchen-sink/styles.css b/demo/kitchen-sink/styles.css index d2f822bcf53..a0ad03869ca 100644 --- a/demo/kitchen-sink/styles.css +++ b/demo/kitchen-sink/styles.css @@ -60,7 +60,16 @@ body { background-color: #eee; pointer-events: none; transition: 0.5s; -} +} + +#sidePanel *:focus { + outline: 3px solid orange; +} + +#sidePanel a { + display: inline-block; +} + #sidePanel:not(.closed) .toggleButton >div:nth-child(1) {transform: translate(0px, 5px) rotate(-45deg)} #sidePanel:not(.closed) .toggleButton >div:nth-child(2) {opacity: 0} #sidePanel:not(.closed) .toggleButton >div:nth-child(3) {transform: translate(0px, -5px) rotate(45deg)} diff --git a/kitchen-sink.html b/kitchen-sink.html index 45689816272..6cf83c887c0 100644 --- a/kitchen-sink.html +++ b/kitchen-sink.html @@ -21,18 +21,18 @@
    -
    +
    - - + +
    - +
    diff --git a/lib/ace/ext/options.js b/lib/ace/ext/options.js index ad47e6f0757..31750ac1520 100644 --- a/lib/ace/ext/options.js +++ b/lib/ace/ext/options.js @@ -85,6 +85,7 @@ var optionGroups = { "Soft Tabs": [{ path: "useSoftTabs" }, { + ariaLabel: "Tab Size", path: "tabSize", type: "number", values: [2, 3, 4, 8, 16] @@ -120,11 +121,12 @@ var optionGroups = { "Show Indent Guides": { path: "displayIndentGuides" }, - "Persistent Scrollbar": [{ + "Persistent HScrollbar": { path: "hScrollBarAlwaysVisible" - }, { + }, + "Persistent VScrollbar": { path: "vScrollBarAlwaysVisible" - }], + }, "Animate scrolling": { path: "animatedScroll" }, @@ -143,6 +145,7 @@ var optionGroups = { "Show Print Margin": [{ path: "showPrintMargin" }, { + ariaLabel: "Print Margin", type: "number", path: "printMarginColumn" }], @@ -205,10 +208,10 @@ var OptionPanel = function(editor, element) { this.render = function() { this.container.innerHTML = ""; - buildDom(["table", {id: "controls"}, + buildDom(["table", {role: "presentation", id: "controls"}, this.renderOptionGroup(optionGroups.Main), ["tr", null, ["td", {colspan: 2}, - ["table", {id: "more-controls"}, + ["table", {role: "presentation", id: "more-controls"}, this.renderOptionGroup(optionGroups.More) ] ]], @@ -251,17 +254,20 @@ var OptionPanel = function(editor, element) { } if (option.type == "buttonBar") { - control = ["div", option.items.map(function(item) { + control = ["div", {role: "group", "aria-labelledby": option.path + "-label"}, option.items.map(function(item) { return ["button", { value: item.value, ace_selected_button: value == item.value, + ['aria-pressed']: value == item.value, onclick: function() { self.setOption(option, item.value); var nodes = this.parentNode.querySelectorAll("[ace_selected_button]"); for (var i = 0; i < nodes.length; i++) { nodes[i].removeAttribute("ace_selected_button"); + nodes[i].setAttribute("aria-pressed", false); } this.setAttribute("ace_selected_button", true); + this.setAttribute("aria-pressed", true); } }, item.desc || item.caption || item.name]; })]; @@ -269,6 +275,11 @@ var OptionPanel = function(editor, element) { control = ["input", {type: "number", value: value || option.defaultValue, style:"width:3em", oninput: function() { self.setOption(option, parseInt(this.value)); }}]; + if (option.ariaLabel) { + control[1]["aria-label"] = option.ariaLabel; + } else { + control[1].id = key; + } if (option.defaults) { control = [control, option.defaults.map(function(item) { return ["button", {onclick: function() { @@ -312,11 +323,13 @@ var OptionPanel = function(editor, element) { this.renderOption = function(key, option) { if (option.path && !option.onchange && !this.editor.$options[option.path]) return; - this.options[option.path] = option; - var safeKey = "-" + option.path; + var path = Array.isArray(option) ? option[0].path : option.path; + this.options[path] = option; + var safeKey = "-" + path; + var safeId = path + "-label"; var control = this.renderOptionControl(safeKey, option); return ["tr", {class: "ace_optionsMenuEntry"}, ["td", - ["label", {for: safeKey}, key] + ["label", {for: safeKey, id: safeId}, key] ], ["td", control]]; }; From c93790498061cbb71dd0272bf55b296f793edeed Mon Sep 17 00:00:00 2001 From: Gary Date: Thu, 20 Feb 2020 11:32:39 -0800 Subject: [PATCH 0284/1293] remove unnecessary '[...]' --- lib/ace/ext/options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/ext/options.js b/lib/ace/ext/options.js index 31750ac1520..06fa2880c54 100644 --- a/lib/ace/ext/options.js +++ b/lib/ace/ext/options.js @@ -258,7 +258,7 @@ var OptionPanel = function(editor, element) { return ["button", { value: item.value, ace_selected_button: value == item.value, - ['aria-pressed']: value == item.value, + 'aria-pressed': value == item.value, onclick: function() { self.setOption(option, item.value); var nodes = this.parentNode.querySelectorAll("[ace_selected_button]"); From 2db11e59b676a9db7828695fd6b59cc59672abf0 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Thu, 20 Feb 2020 21:02:19 +0000 Subject: [PATCH 0285/1293] add behaviour switches --- lib/ace/mode/mediawiki_highlight_rules.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/ace/mode/mediawiki_highlight_rules.js b/lib/ace/mode/mediawiki_highlight_rules.js index 36e5e18784a..707c8da02b7 100644 --- a/lib/ace/mode/mediawiki_highlight_rules.js +++ b/lib/ace/mode/mediawiki_highlight_rules.js @@ -7,6 +7,8 @@ var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var MediaWikiHighlightRules = function() { this.$rules = { start: [{ + include: "#switch" + }, { include: "#variable" }, { include: "#comment" @@ -33,6 +35,14 @@ var MediaWikiHighlightRules = function() { token: "markup.bold", regex: /^[-]{4,}/ }], + "#switch": [{ + token: [ + "constant.language", + "constant.language.mediawiki", + "constant.language" + ], + regex: /(__)(NOTOC|FORCETOC|TOC|NOEDITSECTION|NEWSECTIONLINK|NONEWSECTIONLINK|NOWYSIWYG|NOGALLERY|HIDDENCAT|EXPECTUNUSEDCATEGORY|NOCONTENTCONVERT|NOCC|NOTITLECONVERT|NOTC|START|END|INDEX|NOINDEX|STATICREDIRECT|NOGLOBAL|DISAMBIG)(__)/ + }], "#variable": [{ token: "storage.type.variable", regex: /{{{/, From 9a22e71c88834fe34c0de5dfc2bfe318f7911522 Mon Sep 17 00:00:00 2001 From: William Luke Date: Sat, 22 Feb 2020 12:17:10 +0300 Subject: [PATCH 0286/1293] feat: Add Model for Prisma --- demo/kitchen-sink/docs/prisma.prisma | 334 +++++++++++++++++++++++ lib/ace/ext/modelist.js | 15 +- lib/ace/mode/_test/text_prisma.txt | 334 +++++++++++++++++++++++ lib/ace/mode/prisma.js | 58 ++++ lib/ace/mode/prisma_highlight_rules.js | 358 +++++++++++++++++++++++++ lib/ace/snippets/prisma.js | 7 + lib/ace/snippets/prisma.snippets | 0 7 files changed, 1099 insertions(+), 7 deletions(-) create mode 100644 demo/kitchen-sink/docs/prisma.prisma create mode 100644 lib/ace/mode/_test/text_prisma.txt create mode 100644 lib/ace/mode/prisma.js create mode 100644 lib/ace/mode/prisma_highlight_rules.js create mode 100644 lib/ace/snippets/prisma.js create mode 100644 lib/ace/snippets/prisma.snippets diff --git a/demo/kitchen-sink/docs/prisma.prisma b/demo/kitchen-sink/docs/prisma.prisma new file mode 100644 index 00000000000..56699d12758 --- /dev/null +++ b/demo/kitchen-sink/docs/prisma.prisma @@ -0,0 +1,334 @@ +generator photon { + provider = "photonjs" +} + +model User { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + firstName String + lastName String + email String @unique + password String + phone String + responseRate Float? + responseTime Int? + ReportsTo User? @relation("EmployeeToEmployee_ReportsTo") + employees User[] @relation("EmployeeToEmployee_ReportsTo") + isSuperHost Boolean + ownedPlaces Place[] + location Location? + bookings Booking[] + paymentAccount PaymentAccount[] + sentMessages Message[] @relation("SentMessages") + receivedMessages Message[] @relation("ReceivedMessages") + notifications Notification[] + profilePicture Picture? + hostingExperiences Experience[] +} + +model Place { + id String @default(cuid()) @id + name String + size PLACE_SIZES? + shortDescription String + description String + slug String + maxGuests Int + numBedrooms Int + numBeds Int + numBaths Int + reviews Review[] + amenities Amenities + host User + pricing Pricing + location Location + views Views + guestRequirements GuestRequirements? + policies Policies? + houseRules HouseRules? + bookings Booking[] + pictures Picture[] + popularity Int +} + +model Pricing { + id String @default(cuid()) @id + place Place + monthlyDiscount Int? + weeklyDiscount Int? + perNight Int + smartPricing Boolean + basePrice Int + averageWeekly Int + averageMonthly Int + cleaningFee Int? + securityDeposit Int? + extraGuests Int? + weekendPricing Int? + currency CURRENCY? +} + +model GuestRequirements { + id String @default(cuid()) @id + govIssuedId Boolean + recommendationsFromOtherHosts Boolean + guestTripInformation Boolean + place Place +} + +model Policies { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + checkInStartTime Float + checkInEndTime Float + checkoutTime Float + place Place +} + +model HouseRules { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + suitableForChildren Boolean? + suitableForInfants Boolean? + petsAllowed Boolean? + smokingAllowed Boolean? + partiesAndEventsAllowed Boolean? + additionalRules String? +} + +model Views { + id String @default(cuid()) @id + lastWeek Int + place Place +} + +model Location { + id String @default(cuid()) @id + lat Float + lng Float + neighbourHood Neighbourhood? + user User? + place Place? + address String + directions String + experience Experience? + restaurant Restaurant? +} + +model Neighbourhood { + id String @default(cuid()) @id + locations Location[] + name String + slug String + homePreview Picture? + city City + featured Boolean + popularity Int +} + +model City { + id String @default(cuid()) @id + name String + neighbourhoods Neighbourhood[] +} + +model Picture { + id String @default(cuid()) @id + url String +} + +model Experience { + id String @default(cuid()) @id + category ExperienceCategory? + title String + host User + location Location + pricePerPerson Int + reviews Review[] + preview Picture + popularity Int +} + +model ExperienceCategory { + id String @default(cuid()) @id + mainColor String + name String + experience Experience? +} + +model Amenities { + id String @default(cuid()) @id + place Place + elevator Boolean + petsAllowed Boolean + internet Boolean + kitchen Boolean + wirelessInternet Boolean + familyKidFriendly Boolean + freeParkingOnPremises Boolean + hotTub Boolean + pool Boolean + smokingAllowed Boolean + wheelchairAccessible Boolean + breakfast Boolean + cableTv Boolean + suitableForEvents Boolean + dryer Boolean + washer Boolean + indoorFireplace Boolean + tv Boolean + heating Boolean + hangers Boolean + iron Boolean + hairDryer Boolean + doorman Boolean + paidParkingOffPremises Boolean + freeParkingOnStreet Boolean + gym Boolean + airConditioning Boolean + shampoo Boolean + essentials Boolean + laptopFriendlyWorkspace Boolean + privateEntrance Boolean + buzzerWirelessIntercom Boolean + babyBath Boolean + babyMonitor Boolean + babysitterRecommendations Boolean + bathtub Boolean + changingTable Boolean + childrensBooksAndToys Boolean + childrensDinnerware Boolean + crib Boolean +} + +model Review { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + text String + stars Int + accuracy Int + location Int + checkIn Int + value Int + cleanliness Int + communication Int + place Place + experience Experience? +} + +model Booking { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + bookee User + place Place + startDate DateTime + endDate DateTime + payment Payment? +} + +model Payment { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + serviceFee Float + placePrice Float + totalPrice Float + booking Booking + paymentMethod PaymentAccount +} + +model PaymentAccount { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + type PAYMENT_PROVIDER? + user User + payments Payment[] + paypal PaypalInformation? + creditcard CreditCardInformation? +} + +model PaypalInformation { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + email String + paymentAccount PaymentAccount +} + +model CreditCardInformation { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + cardNumber String + expiresOnMonth Int + expiresOnYear Int + securityCode String + firstName String + lastName String + postalCode String + country String + paymentAccount PaymentAccount? +} + +model Message { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + from User @relation("SentMessages") + to User @relation("ReceivedMessages") + deliveredAt DateTime + readAt DateTime +} + +model Notification { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + type NOTIFICATION_TYPE? + user User + link String + readDate DateTime +} + +model Restaurant { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + title String + avgPricePerPerson Int + pictures Picture[] + location Location + isCurated Boolean + slug String + popularity Int +} + +enum CURRENCY { + CAD + CHF + EUR + JPY + USD + ZAR +} + +enum PLACE_SIZES { + ENTIRE_HOUSE + ENTIRE_APARTMENT + ENTIRE_EARTH_HOUSE + ENTIRE_CABIN + ENTIRE_VILLA + ENTIRE_PLACE + ENTIRE_BOAT + PRIVATE_ROOM +} + +enum PAYMENT_PROVIDER { + PAYPAL + CREDIT_CARD +} + +enum NOTIFICATION_TYPE { + OFFER + INSTANT_BOOK + RESPONSIVENESS + NEW_AMENITIES + HOUSE_RULES +} \ No newline at end of file diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 44419fe9d14..bb72d9e4308 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -48,21 +48,21 @@ var supportedModes = { ActionScript:["as"], ADA: ["ada|adb"], Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"], + Apex: ["apex|cls|trigger|tgr"], + AQL: ["aql"], AsciiDoc: ["asciidoc|adoc"], ASL: ["dsl|asl"], Assembly_x86:["asm|a"], AutoHotKey: ["ahk"], - Apex: ["apex|cls|trigger|tgr"], - AQL: ["aql"], BatchFile: ["bat|cmd"], C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp|ino"], C9Search: ["c9search_results"], - Crystal: ["cr"], Cirru: ["cirru|cr"], Clojure: ["clj|cljs"], Cobol: ["CBL|COB"], coffee: ["coffee|cf|cson|^Cakefile"], ColdFusion: ["cfm"], + Crystal: ["cr"], CSharp: ["cs"], Csound_Document: ["csd"], Csound_Orchestra: ["orc"], @@ -109,8 +109,8 @@ var supportedModes = { Jade: ["jade|pug"], Java: ["java"], JavaScript: ["js|jsm|jsx"], - JSON5: ["json5"], JSON: ["json"], + JSON5: ["json5"], JSONiq: ["jq"], JSP: ["jsp"], JSSM: ["jssm|jssm_state"], @@ -137,8 +137,8 @@ var supportedModes = { MUSHCode: ["mc|mush"], MySQL: ["mysql"], Nginx: ["nginx|conf"], - Nix: ["nix"], Nim: ["nim"], + Nix: ["nix"], NSIS: ["nsi|nsh"], Nunjucks: ["nunjucks|nunjs|nj|njk"], ObjectiveC: ["m|mm"], @@ -147,15 +147,16 @@ var supportedModes = { Perl: ["pl|pm"], Perl6: ["p6|pl6|pm6"], pgSQL: ["pgsql"], - PHP_Laravel_blade: ["blade.php"], PHP: ["php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"], - Puppet: ["epp|pp"], + PHP_Laravel_blade: ["blade.php"], Pig: ["pig"], Powershell: ["ps1"], Praat: ["praat|praatscript|psc|proc"], + Prisma: ["prisma"], Prolog: ["plg|prolog"], Properties: ["properties"], Protobuf: ["proto"], + Puppet: ["epp|pp"], Python: ["py"], R: ["r"], Razor: ["cshtml|asp"], diff --git a/lib/ace/mode/_test/text_prisma.txt b/lib/ace/mode/_test/text_prisma.txt new file mode 100644 index 00000000000..56699d12758 --- /dev/null +++ b/lib/ace/mode/_test/text_prisma.txt @@ -0,0 +1,334 @@ +generator photon { + provider = "photonjs" +} + +model User { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + firstName String + lastName String + email String @unique + password String + phone String + responseRate Float? + responseTime Int? + ReportsTo User? @relation("EmployeeToEmployee_ReportsTo") + employees User[] @relation("EmployeeToEmployee_ReportsTo") + isSuperHost Boolean + ownedPlaces Place[] + location Location? + bookings Booking[] + paymentAccount PaymentAccount[] + sentMessages Message[] @relation("SentMessages") + receivedMessages Message[] @relation("ReceivedMessages") + notifications Notification[] + profilePicture Picture? + hostingExperiences Experience[] +} + +model Place { + id String @default(cuid()) @id + name String + size PLACE_SIZES? + shortDescription String + description String + slug String + maxGuests Int + numBedrooms Int + numBeds Int + numBaths Int + reviews Review[] + amenities Amenities + host User + pricing Pricing + location Location + views Views + guestRequirements GuestRequirements? + policies Policies? + houseRules HouseRules? + bookings Booking[] + pictures Picture[] + popularity Int +} + +model Pricing { + id String @default(cuid()) @id + place Place + monthlyDiscount Int? + weeklyDiscount Int? + perNight Int + smartPricing Boolean + basePrice Int + averageWeekly Int + averageMonthly Int + cleaningFee Int? + securityDeposit Int? + extraGuests Int? + weekendPricing Int? + currency CURRENCY? +} + +model GuestRequirements { + id String @default(cuid()) @id + govIssuedId Boolean + recommendationsFromOtherHosts Boolean + guestTripInformation Boolean + place Place +} + +model Policies { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + checkInStartTime Float + checkInEndTime Float + checkoutTime Float + place Place +} + +model HouseRules { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + suitableForChildren Boolean? + suitableForInfants Boolean? + petsAllowed Boolean? + smokingAllowed Boolean? + partiesAndEventsAllowed Boolean? + additionalRules String? +} + +model Views { + id String @default(cuid()) @id + lastWeek Int + place Place +} + +model Location { + id String @default(cuid()) @id + lat Float + lng Float + neighbourHood Neighbourhood? + user User? + place Place? + address String + directions String + experience Experience? + restaurant Restaurant? +} + +model Neighbourhood { + id String @default(cuid()) @id + locations Location[] + name String + slug String + homePreview Picture? + city City + featured Boolean + popularity Int +} + +model City { + id String @default(cuid()) @id + name String + neighbourhoods Neighbourhood[] +} + +model Picture { + id String @default(cuid()) @id + url String +} + +model Experience { + id String @default(cuid()) @id + category ExperienceCategory? + title String + host User + location Location + pricePerPerson Int + reviews Review[] + preview Picture + popularity Int +} + +model ExperienceCategory { + id String @default(cuid()) @id + mainColor String + name String + experience Experience? +} + +model Amenities { + id String @default(cuid()) @id + place Place + elevator Boolean + petsAllowed Boolean + internet Boolean + kitchen Boolean + wirelessInternet Boolean + familyKidFriendly Boolean + freeParkingOnPremises Boolean + hotTub Boolean + pool Boolean + smokingAllowed Boolean + wheelchairAccessible Boolean + breakfast Boolean + cableTv Boolean + suitableForEvents Boolean + dryer Boolean + washer Boolean + indoorFireplace Boolean + tv Boolean + heating Boolean + hangers Boolean + iron Boolean + hairDryer Boolean + doorman Boolean + paidParkingOffPremises Boolean + freeParkingOnStreet Boolean + gym Boolean + airConditioning Boolean + shampoo Boolean + essentials Boolean + laptopFriendlyWorkspace Boolean + privateEntrance Boolean + buzzerWirelessIntercom Boolean + babyBath Boolean + babyMonitor Boolean + babysitterRecommendations Boolean + bathtub Boolean + changingTable Boolean + childrensBooksAndToys Boolean + childrensDinnerware Boolean + crib Boolean +} + +model Review { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + text String + stars Int + accuracy Int + location Int + checkIn Int + value Int + cleanliness Int + communication Int + place Place + experience Experience? +} + +model Booking { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + bookee User + place Place + startDate DateTime + endDate DateTime + payment Payment? +} + +model Payment { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + serviceFee Float + placePrice Float + totalPrice Float + booking Booking + paymentMethod PaymentAccount +} + +model PaymentAccount { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + type PAYMENT_PROVIDER? + user User + payments Payment[] + paypal PaypalInformation? + creditcard CreditCardInformation? +} + +model PaypalInformation { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + email String + paymentAccount PaymentAccount +} + +model CreditCardInformation { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + cardNumber String + expiresOnMonth Int + expiresOnYear Int + securityCode String + firstName String + lastName String + postalCode String + country String + paymentAccount PaymentAccount? +} + +model Message { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + from User @relation("SentMessages") + to User @relation("ReceivedMessages") + deliveredAt DateTime + readAt DateTime +} + +model Notification { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + type NOTIFICATION_TYPE? + user User + link String + readDate DateTime +} + +model Restaurant { + id String @default(cuid()) @id + createdAt DateTime @default(now()) + title String + avgPricePerPerson Int + pictures Picture[] + location Location + isCurated Boolean + slug String + popularity Int +} + +enum CURRENCY { + CAD + CHF + EUR + JPY + USD + ZAR +} + +enum PLACE_SIZES { + ENTIRE_HOUSE + ENTIRE_APARTMENT + ENTIRE_EARTH_HOUSE + ENTIRE_CABIN + ENTIRE_VILLA + ENTIRE_PLACE + ENTIRE_BOAT + PRIVATE_ROOM +} + +enum PAYMENT_PROVIDER { + PAYPAL + CREDIT_CARD +} + +enum NOTIFICATION_TYPE { + OFFER + INSTANT_BOOK + RESPONSIVENESS + NEW_AMENITIES + HOUSE_RULES +} \ No newline at end of file diff --git a/lib/ace/mode/prisma.js b/lib/ace/mode/prisma.js new file mode 100644 index 00000000000..5fd8b766471 --- /dev/null +++ b/lib/ace/mode/prisma.js @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js +*/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var PrismaHighlightRules = require("./prisma_highlight_rules").PrismaHighlightRules; +// TODO: pick appropriate fold mode +var FoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = PrismaHighlightRules; + this.foldingRules = new FoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + this.lineCommentStart = "//"; + // this.blockComment = {start: ""/*"", end: ""*/""}; + // Extra logic goes here. + this.$id = "ace/mode/prisma" +}).call(Mode.prototype); + +exports.Mode = Mode; +}); \ No newline at end of file diff --git a/lib/ace/mode/prisma_highlight_rules.js b/lib/ace/mode/prisma_highlight_rules.js new file mode 100644 index 00000000000..15d68b42f6a --- /dev/null +++ b/lib/ace/mode/prisma_highlight_rules.js @@ -0,0 +1,358 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +/* This file was autogenerated from ../convert.json (uuid: ) */ +/**************************************************************************************** + * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. * + * fileTypes * + ****************************************************************************************/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var PrismaHighlightRules = function() { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + start: [{ + include: "#triple_comment" + }, { + include: "#double_comment" + }, { + include: "#model_block_definition" + }, { + include: "#config_block_definition" + }, { + include: "#enum_block_definition" + }, { + include: "#type_definition" + }], + "#model_block_definition": [{ + token: [ + "source.prisma.embedded.source", + "storage.type.model.prisma", + "source.prisma.embedded.source", + "entity.name.type.model.prisma", + "source.prisma.embedded.source", + "punctuation.definition.tag.prisma" + ], + regex: /^(\s*)(model|type)(\s+)([A-Za-z][\w]*)(\s+)({)/, + push: [{ + token: "punctuation.definition.tag.prisma", + regex: /\s*\}/, + next: "pop" + }, { + include: "#triple_comment" + }, { + include: "#double_comment" + }, { + include: "#field_definition" + }, { + defaultToken: "source.prisma.embedded.source" + }] + }], + "#enum_block_definition": [{ + token: [ + "source.prisma.embedded.source", + "storage.type.enum.prisma", + "source.prisma.embedded.source", + "entity.name.type.enum.prisma", + "source.prisma.embedded.source", + "punctuation.definition.tag.prisma" + ], + regex: /^(\s*)(enum)(\s+)([A-Za-z][\w]*)(\s+)({)/, + push: [{ + token: "punctuation.definition.tag.prisma", + regex: /\s*\}/, + next: "pop" + }, { + include: "#triple_comment" + }, { + include: "#double_comment" + }, { + include: "#enum_value_definition" + }, { + defaultToken: "source.prisma.embedded.source" + }] + }], + "#config_block_definition": [{ + token: [ + "source.prisma.embedded.source", + "storage.type.config.prisma", + "source.prisma.embedded.source", + "entity.name.type.config.prisma", + "source.prisma.embedded.source", + "punctuation.definition.tag.prisma" + ], + regex: /^(\s*)(generator|datasource)(\s+)([A-Za-z][\w]*)(\s+)({)/, + push: [{ + token: "source.prisma.embedded.source", + regex: /\s*\}/, + next: "pop" + }, { + include: "#triple_comment" + }, { + include: "#double_comment" + }, { + include: "#assignment" + }, { + defaultToken: "source.prisma.embedded.source" + }] + }], + "#assignment": [{ + token: [ + "text", + "variable.other.assignment.prisma", + "text", + "keyword.operator.terraform", + "text" + ], + regex: /^(\s*)(\w+)(\s*)(=)(\s*)/, + push: [{ + token: "text", + regex: /$/, + next: "pop" + }, { + include: "#value" + }, { + include: "#double_comment_inline" + }] + }], + "#field_definition": [{ + token: [ + "text", + "variable.other.assignment.prisma", + "invalid.illegal.colon.prisma", + "text", + "support.type.primitive.prisma", + "keyword.operator.list_type.prisma", + "keyword.operator.optional_type.prisma", + "invalid.illegal.required_type.prisma" + ], + regex: /^(\s*)(\w+)((?:\s*:)?)(\s+)(\w+)((?:\[\])?)((?:\?)?)((?:\!)?)/ + }, { + include: "#attribute_with_arguments" + }, { + include: "#attribute" + }], + "#type_definition": [{ + token: [ + "text", + "storage.type.type.prisma", + "text", + "entity.name.type.type.prisma", + "text", + "support.type.primitive.prisma" + ], + regex: /^(\s*)(type)(\s+)(\w+)(\s*=\s*)(\w+)/ + }, { + include: "#attribute_with_arguments" + }, { + include: "#attribute" + }], + "#enum_value_definition": [{ + token: [ + "text", + "variable.other.assignment.prisma", + "text" + ], + regex: /^(\s*)(\w+)(\s*$)/ + }, { + include: "#attribute_with_arguments" + }, { + include: "#attribute" + }], + "#attribute_with_arguments": [{ + token: [ + "entity.name.function.attribute.prisma", + "punctuation.definition.tag.prisma" + ], + regex: /(@@?[\w\.]+)(\()/, + push: [{ + token: "punctuation.definition.tag.prisma", + regex: /\)/, + next: "pop" + }, { + include: "#named_argument" + }, { + include: "#value" + }, { + defaultToken: "source.prisma.attribute.with_arguments" + }] + }], + "#attribute": [{ + token: "entity.name.function.attribute.prisma", + regex: /@@?[\w\.]+/ + }], + "#array": [{ + token: "source.prisma.array", + regex: /\[/, + push: [{ + token: "source.prisma.array", + regex: /\]/, + next: "pop" + }, { + include: "#value" + }, { + defaultToken: "source.prisma.array" + }] + }], + "#value": [{ + include: "#array" + }, { + include: "#functional" + }, { + include: "#literal" + }], + "#functional": [{ + token: [ + "support.function.functional.prisma", + "punctuation.definition.tag.prisma" + ], + regex: /(\w+)(\()/, + push: [{ + token: "punctuation.definition.tag.prisma", + regex: /\)/, + next: "pop" + }, { + include: "#value" + }, { + defaultToken: "source.prisma.functional" + }] + }], + "#literal": [{ + include: "#boolean" + }, { + include: "#number" + }, { + include: "#double_quoted_string" + }, { + include: "#identifier" + }], + "#identifier": [{ + token: "support.constant.constant.prisma", + regex: /\b(?:\w)+\b/ + }], + "#map_key": [{ + token: [ + "variable.parameter.key.prisma", + "text", + "punctuation.definition.separator.key-value.prisma", + "text" + ], + regex: /(\w+)(\s*)(:)(\s*)/ + }], + "#named_argument": [{ + include: "#map_key" + }, { + include: "#value" + }], + "#triple_comment": [{ + token: "comment.prisma", + regex: /\/\/\//, + push: [{ + token: "comment.prisma", + regex: /$/, + next: "pop" + }, { + defaultToken: "comment.prisma" + }] + }], + "#double_comment": [{ + token: "comment.prisma", + regex: /\/\//, + push: [{ + token: "comment.prisma", + regex: /$/, + next: "pop" + }, { + defaultToken: "comment.prisma" + }] + }], + "#double_comment_inline": [{ + token: "comment.prisma", + regex: /\/\/[^$]*/ + }], + "#boolean": [{ + token: "constant.language.boolean.prisma", + regex: /\b(?:true|false)\b/ + }], + "#number": [{ + token: "constant.numeric.prisma", + regex: /(?:0(?:x|X)[0-9a-fA-F]*|(?:\+|-)?\b(?:[0-9]+\.?[0-9]*|\.[0-9]+)(?:(?:e|E)(?:\+|-)?[0-9]+)?)(?:[LlFfUuDdg]|UL|ul)?\b/ + }], + "#double_quoted_string": [{ + token: "string.quoted.double.start.prisma", + regex: /"/, + push: [{ + token: "string.quoted.double.end.prisma", + regex: /"/, + next: "pop" + }, { + include: "#string_interpolation" + }, { + token: "string.quoted.double.prisma", + regex: /[\w\-\/\._\\%@:\?=]+/ + }, { + defaultToken: "unnamed" + }] + }], + "#string_interpolation": [{ + token: "keyword.control.interpolation.start.prisma", + regex: /\$\{/, + push: [{ + token: "keyword.control.interpolation.end.prisma", + regex: /\s*\}/, + next: "pop" + }, { + include: "#value" + }, { + defaultToken: "source.tag.embedded.source.prisma" + }] + }] + } + + this.normalizeRules(); +}; + +PrismaHighlightRules.metaData = { + name: "Prisma", + scopeName: "source.prisma" +} + + +oop.inherits(PrismaHighlightRules, TextHighlightRules); + +exports.PrismaHighlightRules = PrismaHighlightRules; +}); \ No newline at end of file diff --git a/lib/ace/snippets/prisma.js b/lib/ace/snippets/prisma.js new file mode 100644 index 00000000000..b64d41ef7dc --- /dev/null +++ b/lib/ace/snippets/prisma.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./prisma.snippets"); +exports.scope = "prisma"; + +}); diff --git a/lib/ace/snippets/prisma.snippets b/lib/ace/snippets/prisma.snippets new file mode 100644 index 00000000000..e69de29bb2d From 7464b04e3078a4617039d24f52bcbe1c2b74385e Mon Sep 17 00:00:00 2001 From: tcme <546900+thisconnect@users.noreply.github.com> Date: Sat, 22 Feb 2020 19:14:21 +0100 Subject: [PATCH 0287/1293] important overwrite background arrow Fixes Chaos Theme many arrows in fold-widget end and close #4190 --- lib/ace/theme/chaos.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/theme/chaos.css b/lib/ace/theme/chaos.css index f57e59b3fdb..b6d02c8f796 100644 --- a/lib/ace/theme/chaos.css +++ b/lib/ace/theme/chaos.css @@ -120,7 +120,7 @@ .ace-chaos .ace_fold-widget.ace_start, .ace-chaos .ace_fold-widget.ace_end, .ace-chaos .ace_fold-widget.ace_closed{ - background: none; + background: none !important; border: none; box-shadow: none; } From c4d3152bf9fa00264f5d27403745d28102f65b8f Mon Sep 17 00:00:00 2001 From: tcme <546900+thisconnect@users.noreply.github.com> Date: Sat, 22 Feb 2020 19:17:32 +0100 Subject: [PATCH 0288/1293] important overwrite background arrow (ambiance) --- lib/ace/theme/ambiance.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/theme/ambiance.css b/lib/ace/theme/ambiance.css index 6e5a4ae5b7a..0c0d7e7bdde 100644 --- a/lib/ace/theme/ambiance.css +++ b/lib/ace/theme/ambiance.css @@ -26,7 +26,7 @@ .ace-ambiance .ace_fold-widget.ace_start, .ace-ambiance .ace_fold-widget.ace_end, .ace-ambiance .ace_fold-widget.ace_closed{ - background: none; + background: none !important; border: none; box-shadow: none; } @@ -213,4 +213,4 @@ .ace-ambiance .ace_indent-guide { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNQUFD4z6Crq/sfAAuYAuYl+7lfAAAAAElFTkSuQmCC") right repeat-y; -} \ No newline at end of file +} From c22d6aa741ec822b0205d6404182a49da9836a6b Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Tue, 25 Feb 2020 13:53:52 +0000 Subject: [PATCH 0289/1293] rm "mediawiki" tokens --- lib/ace/mode/mediawiki_highlight_rules.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/ace/mode/mediawiki_highlight_rules.js b/lib/ace/mode/mediawiki_highlight_rules.js index 707c8da02b7..c881743336a 100644 --- a/lib/ace/mode/mediawiki_highlight_rules.js +++ b/lib/ace/mode/mediawiki_highlight_rules.js @@ -36,12 +36,8 @@ var MediaWikiHighlightRules = function() { regex: /^[-]{4,}/ }], "#switch": [{ - token: [ - "constant.language", - "constant.language.mediawiki", - "constant.language" - ], - regex: /(__)(NOTOC|FORCETOC|TOC|NOEDITSECTION|NEWSECTIONLINK|NONEWSECTIONLINK|NOWYSIWYG|NOGALLERY|HIDDENCAT|EXPECTUNUSEDCATEGORY|NOCONTENTCONVERT|NOCC|NOTITLECONVERT|NOTC|START|END|INDEX|NOINDEX|STATICREDIRECT|NOGLOBAL|DISAMBIG)(__)/ + token: "constant.language", + regex: /(__NOTOC__|__FORCETOC__|__TOC__|__NOEDITSECTION__|__NEWSECTIONLINK__|__NONEWSECTIONLINK__|__NOWYSIWYG__|__NOGALLERY__|__HIDDENCAT__|__EXPECTUNUSEDCATEGORY__|__NOCONTENTCONVERT__|__NOCC__|__NOTITLECONVERT__|__NOTC__|__START__|__END__|__INDEX__|__NOINDEX__|__STATICREDIRECT__|__NOGLOBAL__|__DISAMBIG__)/ }], "#variable": [{ token: "storage.type.variable", @@ -97,7 +93,7 @@ var MediaWikiHighlightRules = function() { "meta.structure.dictionary", "support.type.property-name", "meta.structure.dictionary", - "punctuation.separator.dictionary.key-value.mediawiki", + "punctuation.separator.dictionary.key-value", "meta.structure.dictionary", "meta.structure.dictionary.value" ], @@ -129,9 +125,9 @@ var MediaWikiHighlightRules = function() { token: [ "punctuation.definition.tag.begin", "meta.tag.link.internal", - "entity.name.tag.mediawiki", + "entity.name.tag", "meta.tag.link.internal", - "string.other.link.title.mediawiki", + "string.other.link.title", "meta.tag.link.internal", "punctuation.definition.tag" ], @@ -191,7 +187,7 @@ var MediaWikiHighlightRules = function() { "#heading": [{ token: [ "punctuation.definition.heading", - "entity.name.section.mediawiki", + "entity.name.section", "punctuation.definition.heading" ], regex: /(={1,6})(.+?)(\1)(?!=)/ From 4dfdcf888ea0982bf050e7fd0caf669231f85145 Mon Sep 17 00:00:00 2001 From: Cameron Brill Date: Wed, 26 Feb 2020 17:36:45 -0600 Subject: [PATCH 0290/1293] Simplified recommended script for testing. --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index ad574bbb460..8ebb711b4a4 100644 --- a/Readme.md +++ b/Readme.md @@ -146,7 +146,7 @@ Running the Unit Tests The Ace unit tests can run on node.js. Assuming you have already done `npm install`, just call: ```bash -node lib/ace/test/all.js +npm run test ``` You can also run the tests in your browser by serving: From b0af241f257cc662690eec5e03ee0ddbfe97d6a8 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Thu, 27 Feb 2020 13:29:55 +0000 Subject: [PATCH 0291/1293] add mw mode to modelist --- lib/ace/ext/modelist.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 44419fe9d14..7292526c847 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -132,6 +132,7 @@ var supportedModes = { Mask: ["mask"], MATLAB: ["matlab"], Maze: ["mz"], + MediaWiki: ["mediawiki|wiki"], MEL: ["mel"], MIXAL: ["mixal"], MUSHCode: ["mc|mush"], From 184c339db7736e4c306ee76c8e94585cee7f7b90 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Thu, 27 Feb 2020 13:39:45 +0000 Subject: [PATCH 0292/1293] add demo text --- demo/kitchen-sink/docs/mediawiki.wiki | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 demo/kitchen-sink/docs/mediawiki.wiki diff --git a/demo/kitchen-sink/docs/mediawiki.wiki b/demo/kitchen-sink/docs/mediawiki.wiki new file mode 100644 index 00000000000..cb587b9280d --- /dev/null +++ b/demo/kitchen-sink/docs/mediawiki.wiki @@ -0,0 +1,31 @@ +{{Languages}} + +'''Ace''' is a standalone code editor written in [[wikipedia:JavaScript|JavaScript]]. Our goal is to create a browser based editor that matches and extends the features, usability and performance of existing native editors such as TextMate, Vim or Eclipse. It can be ''easily'' embedded in any web page or JavaScript application. Ace is developed as the primary editor for [http://www.cloud9ide.com/ Cloud9 IDE] and the successor of the Mozilla Skywriter (Bespin) Project. + +== Features == +* Syntax highlighting +* Automatic indent and outdent +* An optional command line +* Handles huge documents (100,000 lines and more are no problem) +* Fully customizable key bindings including VI and Emacs modes +* Themes (TextMate themes can be imported) +* Search and replace with regular expressions +* Highlight matching parentheses +* Toggle between soft tabs and real tabs +* Displays hidden characters +* Drag and drop text using the mouse +* Line wrapping +* Unstructured / user code folding +* Live syntax checker (currently JavaScript/CoffeeScript) + +== Take Ace for a spin! == +Check out the Ace live [http://ajaxorg.github.com/ace/ demo] or get a [http://run.cloud9ide.com Cloud9 IDE account] to experience Ace while editing one of your own GitHub projects. + +If you want, you can use Ace as a textarea replacement thanks to the [http://ajaxorg.github.com/ace/build/textarea/editor.html Ace Bookmarklet]. + +== Documentation == +You find a lot more sample code in the [https://github.com/ajaxorg/ace/blob/master/demo/demo.js demo app]. + +There is also some documentation on the [https://github.com/ajaxorg/ace/wiki wiki page]. + +If you still need help, feel free to drop a mail on the [http://groups.google.com/group/ace-discuss ace mailing list]. From cab2d6cfa561bdffd98b517cb18b5f7188adc8be Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Thu, 27 Feb 2020 21:19:47 +0000 Subject: [PATCH 0293/1293] add redirect support --- lib/ace/mode/mediawiki_highlight_rules.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/ace/mode/mediawiki_highlight_rules.js b/lib/ace/mode/mediawiki_highlight_rules.js index c881743336a..f31a57bc8ac 100644 --- a/lib/ace/mode/mediawiki_highlight_rules.js +++ b/lib/ace/mode/mediawiki_highlight_rules.js @@ -8,6 +8,8 @@ var MediaWikiHighlightRules = function() { this.$rules = { start: [{ include: "#switch" + }, { + include: "#redirect" }, { include: "#variable" }, { @@ -39,6 +41,10 @@ var MediaWikiHighlightRules = function() { token: "constant.language", regex: /(__NOTOC__|__FORCETOC__|__TOC__|__NOEDITSECTION__|__NEWSECTIONLINK__|__NONEWSECTIONLINK__|__NOWYSIWYG__|__NOGALLERY__|__HIDDENCAT__|__EXPECTUNUSEDCATEGORY__|__NOCONTENTCONVERT__|__NOCC__|__NOTITLECONVERT__|__NOTC__|__START__|__END__|__INDEX__|__NOINDEX__|__STATICREDIRECT__|__NOGLOBAL__|__DISAMBIG__)/ }], + "#redirect": [{ + token: "keyword.control.redirect", + regex: /(^#REDIRECT|^#redirect|^#Redirect)/ + }], "#variable": [{ token: "storage.type.variable", regex: /{{{/, From bffb7a2abc27323a5bce1eb352f0fce96ad208a2 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Fri, 28 Feb 2020 16:28:20 +0000 Subject: [PATCH 0294/1293] delimit redirects w/ whitespace --- lib/ace/mode/mediawiki_highlight_rules.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/ace/mode/mediawiki_highlight_rules.js b/lib/ace/mode/mediawiki_highlight_rules.js index f31a57bc8ac..ad17592b76e 100644 --- a/lib/ace/mode/mediawiki_highlight_rules.js +++ b/lib/ace/mode/mediawiki_highlight_rules.js @@ -42,8 +42,11 @@ var MediaWikiHighlightRules = function() { regex: /(__NOTOC__|__FORCETOC__|__TOC__|__NOEDITSECTION__|__NEWSECTIONLINK__|__NONEWSECTIONLINK__|__NOWYSIWYG__|__NOGALLERY__|__HIDDENCAT__|__EXPECTUNUSEDCATEGORY__|__NOCONTENTCONVERT__|__NOCC__|__NOTITLECONVERT__|__NOTC__|__START__|__END__|__INDEX__|__NOINDEX__|__STATICREDIRECT__|__NOGLOBAL__|__DISAMBIG__)/ }], "#redirect": [{ - token: "keyword.control.redirect", - regex: /(^#REDIRECT|^#redirect|^#Redirect)/ + token: [ + "keyword.control.redirect", + "meta.keyword.control" + ], + regex: /(^#REDIRECT|^#redirect|^#Redirect)(\s+)/ }], "#variable": [{ token: "storage.type.variable", From d346960c673e4b9e747c7e353bcd20b6ea84a701 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Tue, 3 Mar 2020 16:01:24 +0000 Subject: [PATCH 0295/1293] Add Nord theme (https://www.nordtheme.com/) --- lib/ace/theme/nord_dark.css | 107 ++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 lib/ace/theme/nord_dark.css diff --git a/lib/ace/theme/nord_dark.css b/lib/ace/theme/nord_dark.css new file mode 100644 index 00000000000..f1b8efa13e5 --- /dev/null +++ b/lib/ace/theme/nord_dark.css @@ -0,0 +1,107 @@ +.ace-nord-dark .ace_gutter { + background: #3b4252; + color: #d0edf7 +} + +.ace-nord-dark .ace_print-margin { + width: 1px; + background: #4c566a; +} + +.ace-nord-dark { + background-color: #2e3440; + color: #d8dee9; +} + +.ace-nord-dark .ace_entity.ace_other.ace_attribute-name, +.ace-nord-dark .ace_storage { + color: #d8dee9; +} + +.ace-nord-dark .ace_cursor { + color: #d8dee9; +}, + +.ace-nord-dark .ace_string.ace_regexp { + color: #bf616a; +} + +.ace-nord-dark .ace_marker-layer .ace_active-line, +.ace-nord-dark .ace_marker-layer .ace_selection { + background: rgba(255, 255, 255, 0.1); +} + +.ace-nord-dark.ace_multiselect .ace_selection.ace_start { + box-shadow: 0 0 3px 0px #2e3440; +} + +.ace-nord-dark .ace_marker-layer .ace_step { + background: #ebcb8b; +} + +.ace-nord-dark .ace_marker-layer .ace_bracket { + margin: -1px 0 0 -1px; + border: 1px solid #434c5e; +} + +.ace-nord-dark .ace_gutter-active-line { + background-color: #434c5e; +} + +.ace-nord-dark .ace_marker-layer .ace_selected-word { + border: 1px solid #434c5e; +} + +.ace-nord-dark .ace_invisible { + color: #4c566a; +} + +.ace-nord-dark .ace_keyword, +.ace-nord-dark .ace_meta, +.ace-nord-dark .ace_support.ace_class, +.ace-nord-dark .ace_support.ace_type { + color: #81a1c1; +} + +.ace-nord-dark .ace_constant.ace_character, +.ace-nord-dark .ace_constant.ace_other { + color: #d8Dee9; +} + +.ace-nord-dark .ace_constant.ace_language { + color: #5e81ac; +} + +.ace-nord-dark .ace_constant.ace_escape { + color: #ebcB8b; +} + +.ace-nord-dark .ace_constant.ace_numeric { + color: #b48ead; +} + +.ace-nord-dark .ace_fold { + background-color: #4c566a; + border-color: #d8dee9; +} + +.ace-nord-dark .ace_entity.ace_name.ace_function, +.ace-nord-dark .ace_entity.ace_name.ace_tag, +.ace-nord-dark .ace_support.ace_function, +.ace-nord-dark .ace_variable, +.ace-nord-dark .ace_variable.ace_language { + color: #8fbcbb; +} + +.ace-nord-dark .ace_string { + color: #a3be8c; +} + +.ace-nord-dark .ace_comment { + font-style: italic; + color: #4c566a +} + +.ace-nord-dark .ace_indent-guide { + box-shadow: inset -1px 0 0 0 #434c5eb3; +} From 1f20fd2c15bb8acd1178cf92d5438ca3acd894ac Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Tue, 3 Mar 2020 16:06:13 +0000 Subject: [PATCH 0296/1293] Add theme script for Nord --- lib/ace/theme/nord_dark.js | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 lib/ace/theme/nord_dark.js diff --git a/lib/ace/theme/nord_dark.js b/lib/ace/theme/nord_dark.js new file mode 100644 index 00000000000..70af5da870c --- /dev/null +++ b/lib/ace/theme/nord_dark.js @@ -0,0 +1,39 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-nord-dark"; +exports.cssText = require("../requirejs/text!./nord_dark.css"); + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); From 57a34af3613b71ebae9d44014d36a327cffcc8ae Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Tue, 3 Mar 2020 17:32:32 +0000 Subject: [PATCH 0297/1293] Add Nord to theme list --- tool/tmtheme.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tool/tmtheme.js b/tool/tmtheme.js index c3b5ef16443..2c21d992f2d 100755 --- a/tool/tmtheme.js +++ b/tool/tmtheme.js @@ -283,6 +283,7 @@ var themes = { "merbivore_soft": "Merbivore Soft", "mono_industrial": "monoindustrial", "monokai": "Monokai", + "nord": "Nord Dark", "pastel_on_dark": "Pastels on Dark", "solarized_dark": "Solarized-dark", "solarized_light": "Solarized-light", From abf4aa5a1de3df2d8ffe528777392a2cf7659786 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Tue, 3 Mar 2020 17:33:52 +0000 Subject: [PATCH 0298/1293] fix theme name --- tool/tmtheme.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/tmtheme.js b/tool/tmtheme.js index 2c21d992f2d..913e1155d90 100755 --- a/tool/tmtheme.js +++ b/tool/tmtheme.js @@ -283,7 +283,7 @@ var themes = { "merbivore_soft": "Merbivore Soft", "mono_industrial": "monoindustrial", "monokai": "Monokai", - "nord": "Nord Dark", + "nord-dark": "Nord Dark", "pastel_on_dark": "Pastels on Dark", "solarized_dark": "Solarized-dark", "solarized_light": "Solarized-light", From 760a8b7a5e6b160baf4675a2863cdcc6db8dc41b Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Tue, 3 Mar 2020 17:37:43 +0000 Subject: [PATCH 0299/1293] remove italic --- lib/ace/theme/nord_dark.css | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ace/theme/nord_dark.css b/lib/ace/theme/nord_dark.css index f1b8efa13e5..4bc1cd8a2de 100644 --- a/lib/ace/theme/nord_dark.css +++ b/lib/ace/theme/nord_dark.css @@ -98,7 +98,6 @@ } .ace-nord-dark .ace_comment { - font-style: italic; color: #4c566a } From 7200a9aca9e5be731ed585fc2ca95dbd333e99fb Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Tue, 3 Mar 2020 17:55:28 +0000 Subject: [PATCH 0300/1293] fix key name for Nord theme --- tool/tmtheme.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/tmtheme.js b/tool/tmtheme.js index 913e1155d90..e3f40ade43c 100755 --- a/tool/tmtheme.js +++ b/tool/tmtheme.js @@ -283,7 +283,7 @@ var themes = { "merbivore_soft": "Merbivore Soft", "mono_industrial": "monoindustrial", "monokai": "Monokai", - "nord-dark": "Nord Dark", + "nord_dark": "Nord Dark", "pastel_on_dark": "Pastels on Dark", "solarized_dark": "Solarized-dark", "solarized_light": "Solarized-light", From 4c291afbabd8a7e60cae6f8994fe307466c66c33 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Tue, 3 Mar 2020 18:16:03 +0000 Subject: [PATCH 0301/1293] color tweaks for Nord theme --- lib/ace/theme/nord_dark.css | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/ace/theme/nord_dark.css b/lib/ace/theme/nord_dark.css index 4bc1cd8a2de..44d3ef1437e 100644 --- a/lib/ace/theme/nord_dark.css +++ b/lib/ace/theme/nord_dark.css @@ -1,6 +1,5 @@ .ace-nord-dark .ace_gutter { - background: #3b4252; - color: #d0edf7 + color: #4c566a; } .ace-nord-dark .ace_print-margin { @@ -28,7 +27,7 @@ .ace-nord-dark .ace_marker-layer .ace_active-line, .ace-nord-dark .ace_marker-layer .ace_selection { - background: rgba(255, 255, 255, 0.1); + background: #434c5e; } .ace-nord-dark.ace_multiselect .ace_selection.ace_start { @@ -98,7 +97,7 @@ } .ace-nord-dark .ace_comment { - color: #4c566a + color: #4c566a; } .ace-nord-dark .ace_indent-guide { From 53697aeb2b8230c40a4fe518670b0e3d427de312 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Sat, 7 Mar 2020 20:55:10 +0000 Subject: [PATCH 0302/1293] +port comment color from arcticicestudio/nord#94 --- lib/ace/theme/nord_dark.css | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/ace/theme/nord_dark.css b/lib/ace/theme/nord_dark.css index 44d3ef1437e..648bfec6752 100644 --- a/lib/ace/theme/nord_dark.css +++ b/lib/ace/theme/nord_dark.css @@ -1,5 +1,5 @@ .ace-nord-dark .ace_gutter { - color: #4c566a; + color: #616e88; } .ace-nord-dark .ace_print-margin { @@ -25,10 +25,12 @@ color: #bf616a; } -.ace-nord-dark .ace_marker-layer .ace_active-line, -.ace-nord-dark .ace_marker-layer .ace_selection { +.ace-nord-dark .ace_marker-layer .ace_active-line { background: #434c5e; } +.ace-nord-dark .ace_marker-layer .ace_selection { + background: #88c0d066; +} .ace-nord-dark.ace_multiselect .ace_selection.ace_start { box-shadow: 0 0 3px 0px #2e3440; @@ -40,7 +42,7 @@ .ace-nord-dark .ace_marker-layer .ace_bracket { margin: -1px 0 0 -1px; - border: 1px solid #434c5e; + border: 1px solid #88c0d066; } .ace-nord-dark .ace_gutter-active-line { @@ -48,7 +50,7 @@ } .ace-nord-dark .ace_marker-layer .ace_selected-word { - border: 1px solid #434c5e; + border: 1px solid #88c0d066; } .ace-nord-dark .ace_invisible { @@ -64,7 +66,7 @@ .ace-nord-dark .ace_constant.ace_character, .ace-nord-dark .ace_constant.ace_other { - color: #d8Dee9; + color: #d8dee9; } .ace-nord-dark .ace_constant.ace_language { @@ -97,7 +99,7 @@ } .ace-nord-dark .ace_comment { - color: #4c566a; + color: #616e88; } .ace-nord-dark .ace_indent-guide { From 1f0ddc9c9c4ab253a0bf39b88d526646022222f1 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 8 Mar 2020 15:18:12 +0400 Subject: [PATCH 0303/1293] update themelist.js --- lib/ace/ext/modelist.js | 1 + lib/ace/ext/themelist.js | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 44419fe9d14..224a1e00d38 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -132,6 +132,7 @@ var supportedModes = { Mask: ["mask"], MATLAB: ["matlab"], Maze: ["mz"], + MediaWiki: ["wiki|mediawiki"], MEL: ["mel"], MIXAL: ["mixal"], MUSHCode: ["mc|mush"], diff --git a/lib/ace/ext/themelist.js b/lib/ace/ext/themelist.js index c489f3005fe..86ca0b6968f 100644 --- a/lib/ace/ext/themelist.js +++ b/lib/ace/ext/themelist.js @@ -71,6 +71,7 @@ var themeData = [ ["Merbivore Soft" ,"merbivore_soft" , "dark"], ["Mono Industrial" ,"mono_industrial" , "dark"], ["Monokai" ,"monokai" , "dark"], + ["Nord Dark" ,"nord_dark" , "dark"], ["Pastel on dark" ,"pastel_on_dark" , "dark"], ["Solarized Dark" ,"solarized_dark" , "dark"], ["Terminal" ,"terminal" , "dark"], From b3b293d581340934a1b3984c5d74ae174f829a1c Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 8 Mar 2020 15:42:28 +0400 Subject: [PATCH 0304/1293] use selection color from sublime --- lib/ace/theme/nord_dark.css | 4 ++-- lib/ace/theme/nord_dark.js | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ace/theme/nord_dark.css b/lib/ace/theme/nord_dark.css index 648bfec6752..7fa6f946a6d 100644 --- a/lib/ace/theme/nord_dark.css +++ b/lib/ace/theme/nord_dark.css @@ -26,10 +26,10 @@ } .ace-nord-dark .ace_marker-layer .ace_active-line { - background: #434c5e; + background: #434c5ecc; } .ace-nord-dark .ace_marker-layer .ace_selection { - background: #88c0d066; + background: #434c5ecc; } .ace-nord-dark.ace_multiselect .ace_selection.ace_start { diff --git a/lib/ace/theme/nord_dark.js b/lib/ace/theme/nord_dark.js index 70af5da870c..b1a19372687 100644 --- a/lib/ace/theme/nord_dark.js +++ b/lib/ace/theme/nord_dark.js @@ -33,6 +33,7 @@ define(function(require, exports, module) { exports.isDark = true; exports.cssClass = "ace-nord-dark"; exports.cssText = require("../requirejs/text!./nord_dark.css"); +exports.$selectionColorConflict = true; var dom = require("../lib/dom"); dom.importCssString(exports.cssText, exports.cssClass); From 2ac519617d0b4a43a253aec4e57a8a106a02d205 Mon Sep 17 00:00:00 2001 From: lmn8 <60514150+lmn8@users.noreply.github.com> Date: Sun, 8 Mar 2020 12:50:59 +0000 Subject: [PATCH 0305/1293] Update gutter color to match active line --- lib/ace/theme/nord_dark.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/theme/nord_dark.css b/lib/ace/theme/nord_dark.css index 7fa6f946a6d..8ef6e886ec7 100644 --- a/lib/ace/theme/nord_dark.css +++ b/lib/ace/theme/nord_dark.css @@ -46,7 +46,7 @@ } .ace-nord-dark .ace_gutter-active-line { - background-color: #434c5e; + background-color: #434c5ecc; } .ace-nord-dark .ace_marker-layer .ace_selected-word { From 8902cdabbd1ae6f0a42ffaf91757eb0a0e516382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Jos=C3=A9=20Pereira?= Date: Wed, 11 Mar 2020 19:24:49 -0300 Subject: [PATCH 0306/1293] Add QML language support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Patrick José Pereira --- demo/kitchen-sink/docs/qml.qml | 22 ++++++ lib/ace/ext/modelist.js | 1 + lib/ace/mode/qml.js | 59 +++++++++++++++ lib/ace/mode/qml_highlight_rules.js | 108 ++++++++++++++++++++++++++++ lib/ace/snippets/qml.js | 7 ++ lib/ace/snippets/qml.snippets | 0 6 files changed, 197 insertions(+) create mode 100644 demo/kitchen-sink/docs/qml.qml create mode 100644 lib/ace/mode/qml.js create mode 100644 lib/ace/mode/qml_highlight_rules.js create mode 100644 lib/ace/snippets/qml.js create mode 100644 lib/ace/snippets/qml.snippets diff --git a/demo/kitchen-sink/docs/qml.qml b/demo/kitchen-sink/docs/qml.qml new file mode 100644 index 00000000000..17c3e0398a2 --- /dev/null +++ b/demo/kitchen-sink/docs/qml.qml @@ -0,0 +1,22 @@ +// A simple example +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +Rectangle { + color: "red" + anchors.fill: parent + + Text { + text: "WEEEEEEEEEE" + font.pixelSize: 50 + color: "white" + anchors.centerIn: parent + RotationAnimator on rotation { + running: true + loops: Animation.Infinite + from: 0 + to: 360 + duration: 1500 + } + } +} diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 224a1e00d38..93c76930141 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -158,6 +158,7 @@ var supportedModes = { Properties: ["properties"], Protobuf: ["proto"], Python: ["py"], + QML: ["qml"], R: ["r"], Razor: ["cshtml|asp"], RDoc: ["Rd"], diff --git a/lib/ace/mode/qml.js b/lib/ace/mode/qml.js new file mode 100644 index 00000000000..66defa79772 --- /dev/null +++ b/lib/ace/mode/qml.js @@ -0,0 +1,59 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2020, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js +*/ + +define(function(require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextMode = require("./text").Mode; + var QmlHighlightRules = require("./qml_highlight_rules").QmlHighlightRules; + var FoldMode = require("./folding/cstyle").FoldMode; + + var Mode = function() { + this.HighlightRules = QmlHighlightRules; + this.foldingRules = new FoldMode(); + this.$behaviour = this.$defaultBehaviour; + }; + oop.inherits(Mode, TextMode); + + (function() { + this.lineCommentStart = "//"; + this.blockComment = {start: "/*", end: "*/"}; + this.$quotes = { '"': '"', "'": "'" }; + this.$id = "ace/mode/qml"; + }).call(Mode.prototype); + + exports.Mode = Mode; + }); diff --git a/lib/ace/mode/qml_highlight_rules.js b/lib/ace/mode/qml_highlight_rules.js new file mode 100644 index 00000000000..47556ebc23a --- /dev/null +++ b/lib/ace/mode/qml_highlight_rules.js @@ -0,0 +1,108 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2020, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + + var QmlHighlightRules = function() { + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + this.$rules = { + "start" : [ + { + token : "variable", // single line + regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)' + }, { + token : "string", // single line + regex : '"', + next : "string" + }, { + token : "constant.numeric", // hex + regex : "0[xX][0-9a-fA-F]+\\b" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, { + token : "constant.language.boolean", + regex : "(?:true|false)\\b" + }, { + token : "text", + regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" + }, { + token : "comment", + regex : "\\/\\/.*$" + }, { + token : "comment.start", + regex : "\\/\\*", + next : "comment" + }, { + token : "paren.lparen", + regex : "[[({]" + }, { + token : "paren.rparen", + regex : "[\\])}]" + }, { + token : "text", + regex : "\\s+" + } + ], + "string" : [ + { + token : "constant.language.escape", + regex : /\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|["\\\/bfnrt])/ + }, { + token : "string", + regex : '"|$', + next : "start" + }, { + defaultToken : "string" + } + ], + "comment" : [ + { + token : "comment.end", + regex : "\\*\\/", + next : "start" + }, { + defaultToken: "comment" + } + ] + }; + + }; + + oop.inherits(QmlHighlightRules, TextHighlightRules); + + exports.QmlHighlightRules = QmlHighlightRules; + }); diff --git a/lib/ace/snippets/qml.js b/lib/ace/snippets/qml.js new file mode 100644 index 00000000000..fffbdebb4b3 --- /dev/null +++ b/lib/ace/snippets/qml.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { + "use strict"; + + exports.snippetText = require("../requirejs/text!./qml.snippets"); + exports.scope = "qml"; + + }); diff --git a/lib/ace/snippets/qml.snippets b/lib/ace/snippets/qml.snippets new file mode 100644 index 00000000000..e69de29bb2d From 185daa178cefc01496d65d930a251ee955ce1792 Mon Sep 17 00:00:00 2001 From: jesse Date: Sat, 21 Mar 2020 11:15:47 -0400 Subject: [PATCH 0307/1293] Added Alda syntax highlighting + tests Added a proper example for the demo Added a semicolon to please circleci test updated highlightng rules to remove lookbehinds recreated tokens file for tests Added snippets for codecov. Rebasing --- demo/kitchen-sink/docs/alda.alda | 9 ++ lib/ace/ext/modelist.js | 1 + lib/ace/mode/_test/text_alda.txt | 11 ++ lib/ace/mode/_test/tokens_alda.json | 57 +++++++++ lib/ace/mode/alda.js | 58 +++++++++ lib/ace/mode/alda_highlight_rules.js | 183 +++++++++++++++++++++++++++ lib/ace/snippets/alda.js | 7 + lib/ace/snippets/alda.snippets | 0 8 files changed, 326 insertions(+) create mode 100644 demo/kitchen-sink/docs/alda.alda create mode 100644 lib/ace/mode/_test/text_alda.txt create mode 100644 lib/ace/mode/_test/tokens_alda.json create mode 100644 lib/ace/mode/alda.js create mode 100644 lib/ace/mode/alda_highlight_rules.js create mode 100644 lib/ace/snippets/alda.js create mode 100644 lib/ace/snippets/alda.snippets diff --git a/demo/kitchen-sink/docs/alda.alda b/demo/kitchen-sink/docs/alda.alda new file mode 100644 index 00000000000..423b03e9701 --- /dev/null +++ b/demo/kitchen-sink/docs/alda.alda @@ -0,0 +1,9 @@ +# Example taken from https://github.com/alda-lang/alda-core/blob/master/examples/across_the_sea.alda +(tempo! 90) +(quant! 95) + +piano: + o5 g- > g- g-/f > e- d-4. < b-8 d-2 | c-4 e- d- d- g- + +flute: + r2 g-4 a- b-2. > d-32~ e-16.~8 < b-2 a- g-1 \ No newline at end of file diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 224a1e00d38..e0b4b0cc0ec 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -47,6 +47,7 @@ var supportedModes = { ABC: ["abc"], ActionScript:["as"], ADA: ["ada|adb"], + Alda: ["alda"], Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"], AsciiDoc: ["asciidoc|adoc"], ASL: ["dsl|asl"], diff --git a/lib/ace/mode/_test/text_alda.txt b/lib/ace/mode/_test/text_alda.txt new file mode 100644 index 00000000000..f76d6c930d8 --- /dev/null +++ b/lib/ace/mode/_test/text_alda.txt @@ -0,0 +1,11 @@ +vibraphone: + (quant 200) + (key-signature "f+ c+ g+") + a8 b > c d e f g a < + a b > c_ d e f_ g_ a < + + (key-signature [:g :minor]) + g a b > c+ d e f+ g < + + (key-signature {:e [:flat] :b [:flat]}) + g1~1/b/d \ No newline at end of file diff --git a/lib/ace/mode/_test/tokens_alda.json b/lib/ace/mode/_test/tokens_alda.json new file mode 100644 index 00000000000..7e890771825 --- /dev/null +++ b/lib/ace/mode/_test/tokens_alda.json @@ -0,0 +1,57 @@ +[[ + "start", + ["constant.language.instrument.alda","vibraphone"], + ["meta.part.call.alda",":"] +],[ + "start", + ["text"," "], + ["meta.inline.clojure.alda","(quant 200)"] +],[ + "start", + ["text"," "], + ["meta.inline.clojure.alda","(key-signature \"f+ c+ g+\")"] +],[ + "start", + ["text"," a"], + ["string.quoted.operator.timing.alda","8"], + ["text"," b "], + ["keyword.operator.octave-shift.alda",">"], + ["text"," c d e f g a "], + ["keyword.operator.octave-shift.alda","<"] +],[ + "start", + ["text"," a b "], + ["keyword.operator.octave-shift.alda",">"], + ["text"," c_ d e f_ g_ a "], + ["keyword.operator.octave-shift.alda","<"] +],[ + "start" +],[ + "start", + ["text"," "], + ["meta.inline.clojure.alda","(key-signature [:g :minor])"] +],[ + "start", + ["text"," g a b "], + ["keyword.operator.octave-shift.alda",">"], + ["text"," c"], + ["variable.parameter.operator.pitch.alda","+"], + ["text"," d e f"], + ["variable.parameter.operator.pitch.alda","+"], + ["text"," g "], + ["keyword.operator.octave-shift.alda","<"] +],[ + "start" +],[ + "start", + ["text"," "], + ["meta.inline.clojure.alda","(key-signature {:e [:flat] :b [:flat]})"] +],[ + "pitch", + ["text"," g"], + ["string.quoted.operator.timing.alda","1~1"], + ["constant.numeric.subchord.alda","/"], + ["text","b"], + ["constant.numeric.subchord.alda","/"], + ["text","d"] +]] \ No newline at end of file diff --git a/lib/ace/mode/alda.js b/lib/ace/mode/alda.js new file mode 100644 index 00000000000..609b8322a71 --- /dev/null +++ b/lib/ace/mode/alda.js @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js +*/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var AldaHighlightRules = require("./alda_highlight_rules").AldaHighlightRules; +// TODO: pick appropriate fold mode +var FoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = AldaHighlightRules; + this.foldingRules = new FoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + // this.lineCommentStart = ""\\(comment\\b""; + // this.blockComment = {start: ""/*"", end: ""*/""}; + // Extra logic goes here. + this.$id = "ace/mode/alda"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); \ No newline at end of file diff --git a/lib/ace/mode/alda_highlight_rules.js b/lib/ace/mode/alda_highlight_rules.js new file mode 100644 index 00000000000..2f371ded7dd --- /dev/null +++ b/lib/ace/mode/alda_highlight_rules.js @@ -0,0 +1,183 @@ + + +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +/* This file was autogenerated from ../../src/alda.JSON-tmLanguage (uuid: ) */ +/**************************************************************************************** + * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. * + * fileTypes * + ****************************************************************************************/ + +define(function(require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + + var AldaHighlightRules = function() { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + pitch: [{ + token: "variable.parameter.operator.pitch.alda", + regex: /(?:[+\-]+|\=)/ + }, { + token: "", + regex: "", + next: "timing" + }], + timing: [{ + token: "string.quoted.operator.timing.alda", + regex: /\d+(?:s|ms)?/ + }, { + token: "", + regex: "", + next: "start" + }], + start: [{ + token: [ + "constant.language.instrument.alda", + "constant.language.instrument.alda", + "meta.part.call.alda", + "storage.type.nickname.alda", + "meta.part.call.alda" + ], + regex: /^([a-zA-Z]{2}[\w\-+\'()]*)((?:\s*\/\s*[a-zA-Z]{2}[\w\-+\'()]*)*)(?:(\s*)(\"[a-zA-Z]{2}[\w\-+\'()]*\"))?(\s*:)/ + }, { + token: [ + "text", + "entity.other.inherited-class.voice.alda", + "text" + ], + regex: /^(\s*)(V\d+)(:)/ + }, { + token: "comment.line.number-sign.alda", + regex: /#.*$/ + }, { + token: "entity.name.function.pipe.measure.alda", + regex: /\|/ + }, { + token: "comment.block.inline.alda", + regex: /\(comment\b/, + push: [{ + token: "comment.block.inline.alda", + regex: /\)/, + next: "pop" + }, { + defaultToken: "comment.block.inline.alda" + }] + }, { + token: "entity.name.function.marker.alda", + regex: /%[a-zA-Z]{2}[\w\-+\'()]*/ + }, { + token: "entity.name.function.at-marker.alda", + regex: /@[a-zA-Z]{2}[\w\-+\'()]*/ + }, { + token: "keyword.operator.octave-change.alda", + regex: /\bo\d+\b/ + }, { + token: "keyword.operator.octave-shift.alda", + regex: /[><]/ + }, { + token: "keyword.operator.repeat.alda", + regex: /\*\s*\d+/ + }, { + token: "string.quoted.operator.timing.alda", + regex: /[.]|r\d*(?:s|ms)?/ + },{ + token: "text", + regex: /([cdefgab])/, + next: "pitch" + }, { + token: "string.quoted.operator.timing.alda", + regex: /~/, + next: "timing" + }, { + token: "punctuation.section.embedded.cram.alda", + regex: /\}/, + next: "timing" + }, { + token: "constant.numeric.subchord.alda", + regex: /\// + }, { + todo: { + token: "punctuation.section.embedded.cram.alda", + regex: /\{/, + push: [{ + token: "punctuation.section.embedded.cram.alda", + regex: /\}/, + next: "pop" + }, { + include: "$self" + }] + } + }, { + todo: { + token: "keyword.control.sequence.alda", + regex: /\[/, + push: [{ + token: "keyword.control.sequence.alda", + regex: /\]/, + next: "pop" + }, { + include: "$self" + }] + } + }, { + token: "meta.inline.clojure.alda", + regex: /\(/, + push: [{ + token: "meta.inline.clojure.alda", + regex: /\)/, + next: "pop" + }, { + include: "source.clojure" + }, { + defaultToken: "meta.inline.clojure.alda" + }] + }] + }; + + this.normalizeRules(); + }; + + AldaHighlightRules.metaData = { + scopeName: "source.alda", + fileTypes: ["alda"], + name: "Alda" + }; + + + oop.inherits(AldaHighlightRules, TextHighlightRules); + + exports.AldaHighlightRules = AldaHighlightRules; + }); \ No newline at end of file diff --git a/lib/ace/snippets/alda.js b/lib/ace/snippets/alda.js new file mode 100644 index 00000000000..4747ff592eb --- /dev/null +++ b/lib/ace/snippets/alda.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { + "use strict"; + + exports.snippetText = require("../requirejs/text!./alda.snippets"); + exports.scope = "alda"; + + }); \ No newline at end of file diff --git a/lib/ace/snippets/alda.snippets b/lib/ace/snippets/alda.snippets new file mode 100644 index 00000000000..e69de29bb2d From 7c028c57ba5ea72a2fbf9529c1da77fddcd1ec74 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 24 Mar 2020 20:06:43 +0400 Subject: [PATCH 0308/1293] fix backspace at line start not working with some mobile keyboards --- demo/kitchen-sink/dev_util.js | 1 + lib/ace/editor.js | 4 ++++ lib/ace/keyboard/textinput.js | 17 +++++++++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/demo/kitchen-sink/dev_util.js b/demo/kitchen-sink/dev_util.js index c22cc4b1706..2dd54067c65 100644 --- a/demo/kitchen-sink/dev_util.js +++ b/demo/kitchen-sink/dev_util.js @@ -337,6 +337,7 @@ exports.textInputDebugger = { if (ignoreEvents) return; var data = { _: e.type, + inputType: e.inputType, range: [text.selectionStart, text.selectionEnd], value: text.value, key: e.key && { diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 8ae9d9f58d7..5e510b6bc04 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -1101,6 +1101,10 @@ Editor.$uid = 0; var r = this.selection.getRange(); r.start.column -= composition.extendLeft; r.end.column += composition.extendRight; + if (r.start.column < 0) { + r.start.row--; + r.start.column += this.session.getLine(r.start.row).length + 1; + } this.selection.setRange(r); if (!text && !r.isEmpty()) this.remove(); diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 6b62c626690..43e595b22e6 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -45,6 +45,7 @@ var KEYS = require("../lib/keys"); var MODS = KEYS.KEY_MODS; var isIOS = useragent.isIOS; var valueResetRegex = isIOS ? /\s/ : /\n/; +var isMobile = useragent.isMobile || 1; var TextInput = function(parentNode, host) { var text = dom.createElement("textarea"); @@ -64,7 +65,7 @@ var TextInput = function(parentNode, host) { var sendingText = false; var tempStyle = ''; - if (!useragent.isMobile) + if (!isMobile) text.style.fontSize = "1px"; var commandMode = false; @@ -204,6 +205,11 @@ var TextInput = function(parentNode, host) { selectionEnd += line.length + 1; line = line + "\n" + nextLine; } + else if (isMobile) { + line = "\n" + line; + selectionEnd += 1; + selectionStart += 1; + } if (line.length > MAX_LINE_LENGTH) { if (selectionStart < MAX_LINE_LENGTH && selectionEnd < MAX_LINE_LENGTH) { @@ -259,6 +265,8 @@ var TextInput = function(parentNode, host) { } else if (isAllSelected(text)) { host.selectAll(); resetSelection(); + } else if (isMobile && text.selectionStart != lastSelectionStart) { + resetSelection(); } }; @@ -339,8 +347,13 @@ var TextInput = function(parentNode, host) { } var data = text.value; var inserted = sendText(data, true); - if (data.length > MAX_LINE_LENGTH + 100 || valueResetRegex.test(inserted)) + if ( + data.length > MAX_LINE_LENGTH + 100 + || valueResetRegex.test(inserted) + || isMobile && lastSelectionStart < 1 && lastSelectionStart == lastSelectionEnd + ) { resetSelection(); + } }; var handleClipboardData = function(e, data, forceIEMime) { From 208b070b6ff5c1adc1ca289f518a81131c769ea7 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 25 Mar 2020 02:27:41 +0400 Subject: [PATCH 0309/1293] add an option to disable autoindent --- ace.d.ts | 1 + lib/ace/editor.js | 14 ++++++++------ lib/ace/ext/options.js | 6 ++++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index 5af94cb1881..34fb6665a93 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -211,6 +211,7 @@ export namespace Ace { mergeUndoDeltas: true | false | 'always'; behavioursEnabled: boolean; wrapBehavioursEnabled: boolean; + enableAutoIndent: boolean; autoScrollEditorIntoView: boolean; keyboardHandler: string; placeholder: string; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 8ae9d9f58d7..1a1adfdb452 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -1073,14 +1073,15 @@ Editor.$uid = 0; transform.selection[3])); } } + if (this.$enableAutoIndent) { + if (session.getDocument().isNewLine(text)) { + var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); - if (session.getDocument().isNewLine(text)) { - var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); - - session.insert({row: cursor.row+1, column: 0}, lineIndent); + session.insert({row: cursor.row+1, column: 0}, lineIndent); + } + if (shouldOutdent) + mode.autoOutdent(lineState, session, cursor.row); } - if (shouldOutdent) - mode.autoOutdent(lineState, session, cursor.row); }; this.onTextInput = function(text, composition) { @@ -2813,6 +2814,7 @@ config.defineOptions(Editor.prototype, "editor", { }, behavioursEnabled: {initialValue: true}, wrapBehavioursEnabled: {initialValue: true}, + enableAutoIndent: {initialValue: true}, autoScrollEditorIntoView: { set: function(val) {this.setAutoScrollEditorIntoView(val);} }, diff --git a/lib/ace/ext/options.js b/lib/ace/ext/options.js index 06fa2880c54..f78a53b9a13 100644 --- a/lib/ace/ext/options.js +++ b/lib/ace/ext/options.js @@ -107,6 +107,12 @@ var optionGroups = { "Enable Behaviours": { path: "behavioursEnabled" }, + "Wrap with quotes": { + path: "wrapBehavioursEnabled" + }, + "Enable Auto Indent": { + path: "enableAutoIndent" + }, "Full Line Selection": { type: "checkbox", values: "text|line", From bc4993bd69de2e7afee79e668c3dc8526fb70cb7 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 25 Mar 2020 03:19:00 +0400 Subject: [PATCH 0310/1293] allow setting invisible character classes separately --- lib/ace/layer/text.js | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index cb1f8244305..ff5748d3697 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -103,11 +103,21 @@ var Text = function(parentEl) { }; this.showInvisibles = false; + this.showSpaces = false; + this.showTabs = false; + this.showEOL = false; this.setShowInvisibles = function(showInvisibles) { if (this.showInvisibles == showInvisibles) return false; this.showInvisibles = showInvisibles; + if (typeof showInvisibles == "string") { + this.showSpaces = /tab/i.test(showInvisibles); + this.showTabs = /space/i.test(showInvisibles); + this.showEOL = /eol/i.test(showInvisibles); + } else { + this.showSpaces = this.showTabs = this.showEOL = showInvisibles; + } this.$computeTabString(); return true; }; @@ -129,7 +139,7 @@ var Text = function(parentEl) { this.tabSize = tabSize; var tabStr = this.$tabStrings = [0]; for (var i = 1; i < tabSize + 1; i++) { - if (this.showInvisibles) { + if (this.showTabs) { var span = this.dom.createElement("span"); span.className = "ace_invisible ace_invisible_tab"; span.textContent = lang.stringRepeat(this.TAB_CHAR, i); @@ -141,18 +151,15 @@ var Text = function(parentEl) { if (this.displayIndentGuides) { this.$indentGuideRe = /\s\S| \t|\t |\s$/; var className = "ace_indent-guide"; - var spaceClass = ""; - var tabClass = ""; - if (this.showInvisibles) { - className += " ace_invisible"; - spaceClass = " ace_invisible_space"; - tabClass = " ace_invisible_tab"; - var spaceContent = lang.stringRepeat(this.SPACE_CHAR, this.tabSize); - var tabContent = lang.stringRepeat(this.TAB_CHAR, this.tabSize); - } else { - var spaceContent = lang.stringRepeat(" ", this.tabSize); - var tabContent = spaceContent; - } + var spaceClass = this.showSpaces ? " ace_invisible ace_invisible_space" : ""; + var spaceContent = this.showSpaces + ? lang.stringRepeat(this.SPACE_CHAR, this.tabSize) + : lang.stringRepeat(" ", this.tabSize); + + var tabClass = this.showTabs ? " ace_invisible ace_invisible_tab" : ""; + var tabContent = this.showTabs + ? lang.stringRepeat(this.TAB_CHAR, this.tabSize) + : spaceContent; var span = this.dom.createElement("span"); span.className = className + spaceClass; @@ -350,7 +357,7 @@ var Text = function(parentEl) { var cjkSpace = m[4]; var cjk = m[5]; - if (!self.showInvisibles && simpleSpace) + if (!self.showSpaces && simpleSpace) continue; var before = i != m.index ? value.slice(i, m.index) : ""; @@ -366,7 +373,7 @@ var Text = function(parentEl) { valueFragment.appendChild(self.$tabStrings[tabSize].cloneNode(true)); screenColumn += tabSize - 1; } else if (simpleSpace) { - if (self.showInvisibles) { + if (self.showSpaces) { var span = this.dom.createElement("span"); span.className = "ace_invisible ace_invisible_space"; span.textContent = lang.stringRepeat(self.SPACE_CHAR, simpleSpace.length); @@ -385,8 +392,8 @@ var Text = function(parentEl) { var span = this.dom.createElement("span"); span.style.width = (self.config.characterWidth * 2) + "px"; - span.className = self.showInvisibles ? "ace_cjk ace_invisible ace_invisible_space" : "ace_cjk"; - span.textContent = self.showInvisibles ? self.SPACE_CHAR : cjkSpace; + span.className = self.showSpaces ? "ace_cjk ace_invisible ace_invisible_space" : "ace_cjk"; + span.textContent = self.showSpaces ? self.SPACE_CHAR : cjkSpace; valueFragment.appendChild(span); } else if (cjk) { screenColumn += 1; @@ -557,7 +564,7 @@ var Text = function(parentEl) { parent.appendChild(lastLineEl); } - if (this.showInvisibles && lastLineEl) { + if (this.showEOL && lastLineEl) { if (foldLine) row = foldLine.end.row; From c17b71dc4287e44486fe35daa68a893cf4fa41d7 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 24 Mar 2020 20:45:34 +0400 Subject: [PATCH 0311/1293] fix delta boundary checking in undomanager --- lib/ace/document.js | 13 ++++++++++++- lib/ace/edit_session.js | 7 +------ lib/ace/undomanager.js | 23 ++--------------------- lib/ace/undomanager_test.js | 12 +++++++++++- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/lib/ace/document.js b/lib/ace/document.js index 17f94427270..bccca6d4d4e 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -584,6 +584,17 @@ var Document = function(textOrLines) { } }; + this.$safeApplyDelta = function(delta) { + var docLength = this.$lines.length; + // verify that delta is in the document to prevent applyDelta from corrupting lines array + if ( + delta.action == "remove" && delta.start.row < docLength && delta.end.row < docLength + || delta.action == "insert" && delta.start.row <= docLength + ) { + this.applyDelta(delta); + } + }; + this.$splitAndapplyLargeDelta = function(delta, MAX) { // Split large insert deltas. This is necessary because: // 1. We need to support splicing delta lines into the document via $lines.splice.apply(...) @@ -621,7 +632,7 @@ var Document = function(textOrLines) { * @param {Object} delta A delta object (can include "insert" and "remove" actions) **/ this.revertDelta = function(delta) { - this.applyDelta({ + this.$safeApplyDelta({ start: this.clonePos(delta.start), end: this.clonePos(delta.end), action: (delta.action == "insert" ? "remove" : "insert"), diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 395afe816e1..e7a122c3e29 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1184,7 +1184,7 @@ EditSession.$uid = 0; for (var i = 0; i < deltas.length; i++) { var delta = deltas[i]; if (delta.action == "insert" || delta.action == "remove") { - this.doc.applyDelta(delta); + this.doc.$safeApplyDelta(delta); } } @@ -1212,7 +1212,6 @@ EditSession.$uid = 0; } var range, point; - var lastDeltaIsInsert; for (var i = 0; i < deltas.length; i++) { var delta = deltas[i]; @@ -1220,10 +1219,8 @@ EditSession.$uid = 0; if (!range) { if (isInsert(delta)) { range = Range.fromPoints(delta.start, delta.end); - lastDeltaIsInsert = true; } else { range = Range.fromPoints(delta.start, delta.start); - lastDeltaIsInsert = false; } continue; } @@ -1237,13 +1234,11 @@ EditSession.$uid = 0; if (range.compare(point.row, point.column) == 1) { range.setEnd(point); } - lastDeltaIsInsert = true; } else { point = delta.start; if (range.compare(point.row, point.column) == -1) { range = Range.fromPoints(delta.start, delta.start); } - lastDeltaIsInsert = false; } } return range; diff --git a/lib/ace/undomanager.js b/lib/ace/undomanager.js index 48d6982bfb2..f9c767230a8 100644 --- a/lib/ace/undomanager.js +++ b/lib/ace/undomanager.js @@ -142,25 +142,6 @@ var UndoManager = function() { }; - this.validateDeltaBoundaries = function(deltaSet, docLength, invertAction) { - if (!deltaSet) { - return false; - } - return deltaSet.every(function(delta) { - var action = delta.action; - if (invertAction && delta.action === "insert") action = "remove"; - if (invertAction && delta.action === "remove") action = "insert"; - switch(action) { - case "insert": - return delta.start.row <= docLength; - case "remove": - return delta.start.row < docLength && delta.end.row < docLength; - default: - return true; - } - }); - }; - /** * [Perform an undo operation on the document, reverting the last change.]{: #UndoManager.undo} * @param {Boolean} dontSelect {:dontSelect} @@ -184,7 +165,7 @@ var UndoManager = function() { var deltaSet = stack.pop(); var undoSelectionRange = null; - if (this.validateDeltaBoundaries(deltaSet, session.getLength(), true)) { + if (deltaSet) { undoSelectionRange = session.undoChanges(deltaSet, dontSelect); this.$redoStack.push(deltaSet); this.$syncRev(); @@ -218,7 +199,7 @@ var UndoManager = function() { var deltaSet = this.$redoStack.pop(); var redoSelectionRange = null; - if (this.validateDeltaBoundaries(deltaSet, session.getLength(), false)) { + if (deltaSet) { redoSelectionRange = session.redoChanges(deltaSet, dontSelect); this.$undoStack.push(deltaSet); this.$syncRev(); diff --git a/lib/ace/undomanager_test.js b/lib/ace/undomanager_test.js index cd0fd91fedb..3b0da96f274 100644 --- a/lib/ace/undomanager_test.js +++ b/lib/ace/undomanager_test.js @@ -187,7 +187,6 @@ module.exports = { undoManager.markIgnored(rev); editor.undo(); assert.equal(editor.getValue(), "0yyyy12345"); - }, "test: swap deltas delete/delete": function () { session.setValue("012345"); @@ -360,6 +359,17 @@ module.exports = { }]); editor.redo(); assert.equal(editor.getValue(), "012\n345\n678"); + }, + "test: do not ignore valid deltas": function () { + editor.setValue(""); + editor.insert("\n"); + editor.insert("\n"); + editor.insert("\n"); + editor.insert("\n"); + editor.undo(); + assert.equal(editor.getValue(), ""); + editor.redo(); + assert.equal(editor.getValue(), "\n\n\n\n"); } }; From 7602bb048b1425d8e2153dcc89eaa42d63cab8b8 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 24 Mar 2020 16:08:02 +0400 Subject: [PATCH 0312/1293] allow registering snippets in json format --- lib/ace/snippets.js | 17 +++++++++++++---- lib/ace/snippets_test.js | 31 ++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/lib/ace/snippets.js b/lib/ace/snippets.js index f41ca5bfe21..a96e91bfea1 100644 --- a/lib/ace/snippets.js +++ b/lib/ace/snippets.js @@ -659,6 +659,12 @@ var SnippetManager = function() { } snippetMap[scope].push(s); + if (s.prefix) + s.tabTrigger = s.prefix; + + if (!s.content && s.body) + s.content = Array.isArray(s.body) ? s.body.join("\n") : s.body; + if (s.tabTrigger && !s.trigger) { if (!s.guard && /^\w/.test(s.tabTrigger)) s.guard = "\\b"; @@ -675,10 +681,13 @@ var SnippetManager = function() { s.endTriggerRe = new RegExp(s.endTrigger); } - if (snippets && snippets.content) - addSnippet(snippets); - else if (Array.isArray(snippets)) + if (Array.isArray(snippets)) { snippets.forEach(addSnippet); + } else { + Object.keys(snippets).forEach(function(key) { + addSnippet(snippets[key]); + }); + } this._signal("registerSnippets", {scope: scope}); }; @@ -728,7 +737,7 @@ var SnippetManager = function() { snippet.tabTrigger = val.match(/^\S*/)[0]; if (!snippet.name) snippet.name = val; - } else { + } else if (key) { snippet[key] = val; } } diff --git a/lib/ace/snippets_test.js b/lib/ace/snippets_test.js index 8fcdda51ac6..2845554631f 100644 --- a/lib/ace/snippets_test.js +++ b/lib/ace/snippets_test.js @@ -37,7 +37,9 @@ define(function(require, exports, module) { "use strict"; var Editor = require("./editor").Editor; var MockRenderer = require("./test/mockrenderer").MockRenderer; -require("./multi_select").MultiSelect; +var JavascriptMode = require("./mode/javascript").Mode; +require("./multi_select"); +require("./ext/language_tools"); var snippetManager = require("./snippets").snippetManager; var assert = require("./test/assertions"); @@ -97,6 +99,33 @@ module.exports = { assert.equal(tokens[1].guard, "as\\/d"); assert.equal(tokens[1].flag, "g"); }, + "test: register snippets in json format": function() { + require("./config").loadModule = function() {}; + this.editor.setOption("enableSnippets", true); + this.editor.session.setMode(new JavascriptMode()); + + snippetManager.register({ + "Snippet 1": { + prefix: "xy", + body: [ + "x", + "$0", + "y" + ] + }, + "Snippet 2": { + prefix: "s", + body: "$0expanded" + } + }, "javascript"); + + this.editor.execCommand("paste", "xy"); + this.editor.onCommandKey(null, 0, 9); + this.editor.execCommand("paste", "s"); + this.editor.onCommandKey(null, 0, 9); + assert.equal(this.editor.getValue(), "x\nexpanded\ny"); + assert.position(this.editor.getCursorPosition(), 1, 0); + }, "test: expand snippet with nested tabstops": function() { var content = "-${1}-${1:t\n1}--${2:2 ${3} 2}-${3:3 $1 3}-${4:4 $2 4}"; this.editor.setValue(""); From 163926bebdd7b6f18dfa048b7a05cf60aa880c13 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 9 Mar 2020 02:30:05 +0400 Subject: [PATCH 0313/1293] remove empty snippet files --- lib/ace/snippets/_all_modes.js | 7 ------- lib/ace/snippets/_all_modes.snippets | 0 lib/ace/snippets/abap.js | 7 ------- lib/ace/snippets/abap.snippets | 0 lib/ace/snippets/ada.js | 7 ------- lib/ace/snippets/ada.snippets | 0 lib/ace/snippets/alda.js | 7 ------- lib/ace/snippets/alda.snippets | 0 lib/ace/snippets/all_modes.js | 7 ------- lib/ace/snippets/all_modes.snippets | 0 lib/ace/snippets/apache_conf.js | 7 ------- lib/ace/snippets/apache_conf.snippets | 0 lib/ace/snippets/apex.js | 7 ------- lib/ace/snippets/apex.snippets | 0 lib/ace/snippets/applescript.js | 7 ------- lib/ace/snippets/applescript.snippets | 0 lib/ace/snippets/asciidoc.js | 7 ------- lib/ace/snippets/asciidoc.snippets | 0 lib/ace/snippets/asl.js | 6 ------ lib/ace/snippets/asl.snippets | 0 lib/ace/snippets/assembly_x86.js | 7 ------- lib/ace/snippets/assembly_x86.snippets | 0 lib/ace/snippets/autohotkey.js | 7 ------- lib/ace/snippets/autohotkey.snippets | 0 lib/ace/snippets/batchfile.js | 7 ------- lib/ace/snippets/batchfile.snippets | 0 lib/ace/snippets/c9search.js | 7 ------- lib/ace/snippets/c9search.snippets | 0 lib/ace/snippets/cirru.js | 7 ------- lib/ace/snippets/cirru.snippets | 0 lib/ace/snippets/cobol.js | 7 ------- lib/ace/snippets/cobol.snippets | 0 lib/ace/snippets/coldfusion.js | 7 ------- lib/ace/snippets/coldfusion.snippets | 0 lib/ace/snippets/crystal.js | 7 ------- lib/ace/snippets/crystal.snippets | 0 lib/ace/snippets/csharp.js | 7 ------- lib/ace/snippets/csharp.snippets | 0 lib/ace/snippets/csound_score.js | 7 ------- lib/ace/snippets/csound_score.snippets | 0 lib/ace/snippets/csp.js | 7 ------- lib/ace/snippets/csp.snippets | 0 lib/ace/snippets/curly.js | 7 ------- lib/ace/snippets/curly.snippets | 0 lib/ace/snippets/d.js | 7 ------- lib/ace/snippets/d.snippets | 0 lib/ace/snippets/dockerfile.js | 7 ------- lib/ace/snippets/dockerfile.snippets | 0 lib/ace/snippets/dot.js | 7 ------- lib/ace/snippets/dot.snippets | 0 lib/ace/snippets/eiffel.js | 7 ------- lib/ace/snippets/eiffel.snippets | 0 lib/ace/snippets/ejs.js | 7 ------- lib/ace/snippets/ejs.snippets | 0 lib/ace/snippets/elixir.js | 7 ------- lib/ace/snippets/elixir.snippets | 0 lib/ace/snippets/elm.js | 7 ------- lib/ace/snippets/elm.snippets | 0 lib/ace/snippets/forth.js | 7 ------- lib/ace/snippets/forth.snippets | 0 lib/ace/snippets/fortran.js | 7 ------- lib/ace/snippets/fortran.snippets | 0 lib/ace/snippets/fsharp.js | 7 ------- lib/ace/snippets/fsharp.snippets | 0 lib/ace/snippets/ftl.js | 7 ------- lib/ace/snippets/ftl.snippets | 0 lib/ace/snippets/gcode.js | 7 ------- lib/ace/snippets/gcode.snippets | 0 lib/ace/snippets/gherkin.js | 7 ------- lib/ace/snippets/gherkin.snippets | 0 lib/ace/snippets/gitignore.js | 7 ------- lib/ace/snippets/gitignore.snippets | 0 lib/ace/snippets/glsl.js | 7 ------- lib/ace/snippets/glsl.snippets | 0 lib/ace/snippets/golang.js | 7 ------- lib/ace/snippets/golang.snippets | 0 lib/ace/snippets/groovy.js | 7 ------- lib/ace/snippets/groovy.snippets | 0 lib/ace/snippets/handlebars.js | 7 ------- lib/ace/snippets/handlebars.snippets | 0 lib/ace/snippets/haskell_cabal.js | 7 ------- lib/ace/snippets/haskell_cabal.snippets | 0 lib/ace/snippets/haxe.js | 7 ------- lib/ace/snippets/haxe.snippets | 0 lib/ace/snippets/hjson.js | 7 ------- lib/ace/snippets/hjson.snippets | 0 lib/ace/snippets/html_elixir.js | 7 ------- lib/ace/snippets/html_elixir.snippets | 0 lib/ace/snippets/html_ruby.js | 7 ------- lib/ace/snippets/html_ruby.snippets | 0 lib/ace/snippets/ini.js | 7 ------- lib/ace/snippets/ini.snippets | 0 lib/ace/snippets/io.snippets | 0 lib/ace/snippets/jack.js | 7 ------- lib/ace/snippets/jack.snippets | 0 lib/ace/snippets/jade.js | 7 ------- lib/ace/snippets/jade.snippets | 0 lib/ace/snippets/json.js | 7 ------- lib/ace/snippets/json.snippets | 0 lib/ace/snippets/jssm.js | 7 ------- lib/ace/snippets/jssm.snippets | 0 lib/ace/snippets/jsx.js | 7 ------- lib/ace/snippets/jsx.snippets | 0 lib/ace/snippets/julia.js | 7 ------- lib/ace/snippets/julia.snippets | 0 lib/ace/snippets/kotlin.js | 7 ------- lib/ace/snippets/kotlin.snippets | 0 lib/ace/snippets/latex.js | 7 ------- lib/ace/snippets/latex.snippets | 0 lib/ace/snippets/less.js | 7 ------- lib/ace/snippets/less.snippets | 0 lib/ace/snippets/lisp.js | 7 ------- lib/ace/snippets/lisp.snippets | 0 lib/ace/snippets/livescript.js | 7 ------- lib/ace/snippets/livescript.snippets | 0 lib/ace/snippets/logiql.js | 7 ------- lib/ace/snippets/logiql.snippets | 0 lib/ace/snippets/logtalk.js | 7 ------- lib/ace/snippets/logtalk.snippets | 0 lib/ace/snippets/luapage.js | 7 ------- lib/ace/snippets/luapage.snippets | 0 lib/ace/snippets/lucene.js | 7 ------- lib/ace/snippets/lucene.snippets | 0 lib/ace/snippets/mask.js | 7 ------- lib/ace/snippets/mask.snippets | 0 lib/ace/snippets/matlab.js | 7 ------- lib/ace/snippets/matlab.snippets | 0 lib/ace/snippets/mel.js | 7 ------- lib/ace/snippets/mel.snippets | 0 lib/ace/snippets/mixal.js | 7 ------- lib/ace/snippets/mixal.snippets | 0 lib/ace/snippets/mushcode.js | 7 ------- lib/ace/snippets/mushcode.snippets | 0 lib/ace/snippets/mushcode_high_rules.js | 7 ------- lib/ace/snippets/mushcode_high_rules.snippets | 0 lib/ace/snippets/mysql.js | 7 ------- lib/ace/snippets/mysql.snippets | 0 lib/ace/snippets/nginx.js | 7 ------- lib/ace/snippets/nginx.snippets | 0 lib/ace/snippets/nim.js | 7 ------- lib/ace/snippets/nim.snippets | 0 lib/ace/snippets/nix.js | 7 ------- lib/ace/snippets/nix.snippets | 0 lib/ace/snippets/nsis.js | 7 ------- lib/ace/snippets/nsis.snippets | 0 lib/ace/snippets/objectivec.js | 7 ------- lib/ace/snippets/objectivec.snippets | 0 lib/ace/snippets/ocaml.js | 7 ------- lib/ace/snippets/ocaml.snippets | 0 lib/ace/snippets/pascal.js | 7 ------- lib/ace/snippets/pascal.snippets | 0 lib/ace/snippets/perl6.js | 7 ------- lib/ace/snippets/perl6.snippets | 0 lib/ace/snippets/pgsql.js | 7 ------- lib/ace/snippets/pgsql.snippets | 0 lib/ace/snippets/php_laravel_blade.js | 7 ------- lib/ace/snippets/php_laravel_blade.snippets | 0 lib/ace/snippets/pig.js | 7 ------- lib/ace/snippets/pig.snippets | 0 lib/ace/snippets/plain_text.js | 7 ------- lib/ace/snippets/plain_text.snippets | 0 lib/ace/snippets/powershell.js | 7 ------- lib/ace/snippets/powershell.snippets | 0 lib/ace/snippets/praat.js | 7 ------- lib/ace/snippets/praat.snippets | 0 lib/ace/snippets/prisma.js | 7 ------- lib/ace/snippets/prisma.snippets | 0 lib/ace/snippets/prolog.js | 7 ------- lib/ace/snippets/prolog.snippets | 0 lib/ace/snippets/properties.js | 7 ------- lib/ace/snippets/properties.snippets | 0 lib/ace/snippets/protobuf.js | 7 ------- lib/ace/snippets/protobuf.snippets | 0 lib/ace/snippets/puppet.js | 7 ------- lib/ace/snippets/puppet.snippets | 0 lib/ace/snippets/qml.js | 7 ------- lib/ace/snippets/qml.snippets | 0 lib/ace/snippets/rdoc.js | 7 ------- lib/ace/snippets/rdoc.snippets | 0 lib/ace/snippets/red.js | 7 ------- lib/ace/snippets/red.snippets | 1 - lib/ace/snippets/redshift.js | 7 ------- lib/ace/snippets/redshift.snippets | 0 lib/ace/snippets/rhtml.js | 7 ------- lib/ace/snippets/rhtml.snippets | 0 lib/ace/snippets/rust.js | 7 ------- lib/ace/snippets/rust.snippets | 0 lib/ace/snippets/sass.js | 7 ------- lib/ace/snippets/sass.snippets | 0 lib/ace/snippets/scad.js | 7 ------- lib/ace/snippets/scad.snippets | 0 lib/ace/snippets/scala.js | 7 ------- lib/ace/snippets/scala.snippets | 0 lib/ace/snippets/scheme.js | 7 ------- lib/ace/snippets/scheme.snippets | 0 lib/ace/snippets/scss.js | 7 ------- lib/ace/snippets/scss.snippets | 0 lib/ace/snippets/sjs.js | 7 ------- lib/ace/snippets/sjs.snippets | 0 lib/ace/snippets/slim.js | 7 ------- lib/ace/snippets/slim.snippets | 0 lib/ace/snippets/smarty.js | 7 ------- lib/ace/snippets/smarty.snippets | 0 lib/ace/snippets/soy_template.js | 7 ------- lib/ace/snippets/soy_template.snippets | 0 lib/ace/snippets/space.js | 7 ------- lib/ace/snippets/space.snippets | 0 lib/ace/snippets/sparql.js | 7 ------- lib/ace/snippets/sparql.snippets | 0 lib/ace/snippets/stylus.js | 7 ------- lib/ace/snippets/stylus.snippets | 0 lib/ace/snippets/svg.js | 7 ------- lib/ace/snippets/svg.snippets | 0 lib/ace/snippets/swift.js | 7 ------- lib/ace/snippets/swift.snippets | 0 lib/ace/snippets/terraform.js | 7 ------- lib/ace/snippets/terraform.snippets | 0 lib/ace/snippets/text.js | 7 ------- lib/ace/snippets/text.snippets | 0 lib/ace/snippets/tmsnippet.snippets | 0 lib/ace/snippets/toml.js | 7 ------- lib/ace/snippets/toml.snippets | 0 lib/ace/snippets/tsx.js | 7 ------- lib/ace/snippets/tsx.snippets | 0 lib/ace/snippets/turtle.js | 7 ------- lib/ace/snippets/turtle.snippets | 0 lib/ace/snippets/twig.js | 7 ------- lib/ace/snippets/twig.snippets | 0 lib/ace/snippets/typescript.js | 7 ------- lib/ace/snippets/typescript.snippets | 0 lib/ace/snippets/vala.snippets | 0 lib/ace/snippets/vbscript.js | 7 ------- lib/ace/snippets/vbscript.snippets | 0 lib/ace/snippets/verilog.js | 7 ------- lib/ace/snippets/verilog.snippets | 0 lib/ace/snippets/vhdl.js | 7 ------- lib/ace/snippets/vhdl.snippets | 0 lib/ace/snippets/visualforce.js | 7 ------- lib/ace/snippets/visualforce.snippets | 0 lib/ace/snippets/xml.js | 7 ------- lib/ace/snippets/xml.snippets | 0 lib/ace/snippets/yaml.js | 7 ------- lib/ace/snippets/yaml.snippets | 0 lib/ace/snippets/zeek.js | 7 ------- lib/ace/snippets/zeek.snippets | 0 245 files changed, 847 deletions(-) delete mode 100644 lib/ace/snippets/_all_modes.js delete mode 100644 lib/ace/snippets/_all_modes.snippets delete mode 100644 lib/ace/snippets/abap.js delete mode 100644 lib/ace/snippets/abap.snippets delete mode 100644 lib/ace/snippets/ada.js delete mode 100644 lib/ace/snippets/ada.snippets delete mode 100644 lib/ace/snippets/alda.js delete mode 100644 lib/ace/snippets/alda.snippets delete mode 100644 lib/ace/snippets/all_modes.js delete mode 100644 lib/ace/snippets/all_modes.snippets delete mode 100644 lib/ace/snippets/apache_conf.js delete mode 100644 lib/ace/snippets/apache_conf.snippets delete mode 100644 lib/ace/snippets/apex.js delete mode 100644 lib/ace/snippets/apex.snippets delete mode 100644 lib/ace/snippets/applescript.js delete mode 100644 lib/ace/snippets/applescript.snippets delete mode 100644 lib/ace/snippets/asciidoc.js delete mode 100644 lib/ace/snippets/asciidoc.snippets delete mode 100644 lib/ace/snippets/asl.js delete mode 100644 lib/ace/snippets/asl.snippets delete mode 100644 lib/ace/snippets/assembly_x86.js delete mode 100644 lib/ace/snippets/assembly_x86.snippets delete mode 100644 lib/ace/snippets/autohotkey.js delete mode 100644 lib/ace/snippets/autohotkey.snippets delete mode 100644 lib/ace/snippets/batchfile.js delete mode 100644 lib/ace/snippets/batchfile.snippets delete mode 100644 lib/ace/snippets/c9search.js delete mode 100644 lib/ace/snippets/c9search.snippets delete mode 100644 lib/ace/snippets/cirru.js delete mode 100644 lib/ace/snippets/cirru.snippets delete mode 100644 lib/ace/snippets/cobol.js delete mode 100644 lib/ace/snippets/cobol.snippets delete mode 100644 lib/ace/snippets/coldfusion.js delete mode 100644 lib/ace/snippets/coldfusion.snippets delete mode 100644 lib/ace/snippets/crystal.js delete mode 100644 lib/ace/snippets/crystal.snippets delete mode 100644 lib/ace/snippets/csharp.js delete mode 100644 lib/ace/snippets/csharp.snippets delete mode 100644 lib/ace/snippets/csound_score.js delete mode 100644 lib/ace/snippets/csound_score.snippets delete mode 100644 lib/ace/snippets/csp.js delete mode 100644 lib/ace/snippets/csp.snippets delete mode 100644 lib/ace/snippets/curly.js delete mode 100644 lib/ace/snippets/curly.snippets delete mode 100644 lib/ace/snippets/d.js delete mode 100644 lib/ace/snippets/d.snippets delete mode 100644 lib/ace/snippets/dockerfile.js delete mode 100644 lib/ace/snippets/dockerfile.snippets delete mode 100644 lib/ace/snippets/dot.js delete mode 100644 lib/ace/snippets/dot.snippets delete mode 100644 lib/ace/snippets/eiffel.js delete mode 100644 lib/ace/snippets/eiffel.snippets delete mode 100644 lib/ace/snippets/ejs.js delete mode 100644 lib/ace/snippets/ejs.snippets delete mode 100644 lib/ace/snippets/elixir.js delete mode 100644 lib/ace/snippets/elixir.snippets delete mode 100644 lib/ace/snippets/elm.js delete mode 100644 lib/ace/snippets/elm.snippets delete mode 100644 lib/ace/snippets/forth.js delete mode 100644 lib/ace/snippets/forth.snippets delete mode 100644 lib/ace/snippets/fortran.js delete mode 100644 lib/ace/snippets/fortran.snippets delete mode 100644 lib/ace/snippets/fsharp.js delete mode 100644 lib/ace/snippets/fsharp.snippets delete mode 100644 lib/ace/snippets/ftl.js delete mode 100644 lib/ace/snippets/ftl.snippets delete mode 100644 lib/ace/snippets/gcode.js delete mode 100644 lib/ace/snippets/gcode.snippets delete mode 100644 lib/ace/snippets/gherkin.js delete mode 100644 lib/ace/snippets/gherkin.snippets delete mode 100644 lib/ace/snippets/gitignore.js delete mode 100644 lib/ace/snippets/gitignore.snippets delete mode 100644 lib/ace/snippets/glsl.js delete mode 100644 lib/ace/snippets/glsl.snippets delete mode 100644 lib/ace/snippets/golang.js delete mode 100644 lib/ace/snippets/golang.snippets delete mode 100644 lib/ace/snippets/groovy.js delete mode 100644 lib/ace/snippets/groovy.snippets delete mode 100644 lib/ace/snippets/handlebars.js delete mode 100644 lib/ace/snippets/handlebars.snippets delete mode 100644 lib/ace/snippets/haskell_cabal.js delete mode 100644 lib/ace/snippets/haskell_cabal.snippets delete mode 100644 lib/ace/snippets/haxe.js delete mode 100644 lib/ace/snippets/haxe.snippets delete mode 100644 lib/ace/snippets/hjson.js delete mode 100644 lib/ace/snippets/hjson.snippets delete mode 100644 lib/ace/snippets/html_elixir.js delete mode 100644 lib/ace/snippets/html_elixir.snippets delete mode 100644 lib/ace/snippets/html_ruby.js delete mode 100644 lib/ace/snippets/html_ruby.snippets delete mode 100644 lib/ace/snippets/ini.js delete mode 100644 lib/ace/snippets/ini.snippets delete mode 100644 lib/ace/snippets/io.snippets delete mode 100644 lib/ace/snippets/jack.js delete mode 100644 lib/ace/snippets/jack.snippets delete mode 100644 lib/ace/snippets/jade.js delete mode 100644 lib/ace/snippets/jade.snippets delete mode 100644 lib/ace/snippets/json.js delete mode 100644 lib/ace/snippets/json.snippets delete mode 100644 lib/ace/snippets/jssm.js delete mode 100644 lib/ace/snippets/jssm.snippets delete mode 100644 lib/ace/snippets/jsx.js delete mode 100644 lib/ace/snippets/jsx.snippets delete mode 100644 lib/ace/snippets/julia.js delete mode 100644 lib/ace/snippets/julia.snippets delete mode 100644 lib/ace/snippets/kotlin.js delete mode 100644 lib/ace/snippets/kotlin.snippets delete mode 100644 lib/ace/snippets/latex.js delete mode 100644 lib/ace/snippets/latex.snippets delete mode 100644 lib/ace/snippets/less.js delete mode 100644 lib/ace/snippets/less.snippets delete mode 100644 lib/ace/snippets/lisp.js delete mode 100644 lib/ace/snippets/lisp.snippets delete mode 100644 lib/ace/snippets/livescript.js delete mode 100644 lib/ace/snippets/livescript.snippets delete mode 100644 lib/ace/snippets/logiql.js delete mode 100644 lib/ace/snippets/logiql.snippets delete mode 100644 lib/ace/snippets/logtalk.js delete mode 100644 lib/ace/snippets/logtalk.snippets delete mode 100644 lib/ace/snippets/luapage.js delete mode 100644 lib/ace/snippets/luapage.snippets delete mode 100644 lib/ace/snippets/lucene.js delete mode 100644 lib/ace/snippets/lucene.snippets delete mode 100644 lib/ace/snippets/mask.js delete mode 100644 lib/ace/snippets/mask.snippets delete mode 100644 lib/ace/snippets/matlab.js delete mode 100644 lib/ace/snippets/matlab.snippets delete mode 100644 lib/ace/snippets/mel.js delete mode 100644 lib/ace/snippets/mel.snippets delete mode 100644 lib/ace/snippets/mixal.js delete mode 100644 lib/ace/snippets/mixal.snippets delete mode 100644 lib/ace/snippets/mushcode.js delete mode 100644 lib/ace/snippets/mushcode.snippets delete mode 100644 lib/ace/snippets/mushcode_high_rules.js delete mode 100644 lib/ace/snippets/mushcode_high_rules.snippets delete mode 100644 lib/ace/snippets/mysql.js delete mode 100644 lib/ace/snippets/mysql.snippets delete mode 100644 lib/ace/snippets/nginx.js delete mode 100644 lib/ace/snippets/nginx.snippets delete mode 100644 lib/ace/snippets/nim.js delete mode 100644 lib/ace/snippets/nim.snippets delete mode 100644 lib/ace/snippets/nix.js delete mode 100644 lib/ace/snippets/nix.snippets delete mode 100644 lib/ace/snippets/nsis.js delete mode 100644 lib/ace/snippets/nsis.snippets delete mode 100644 lib/ace/snippets/objectivec.js delete mode 100644 lib/ace/snippets/objectivec.snippets delete mode 100644 lib/ace/snippets/ocaml.js delete mode 100644 lib/ace/snippets/ocaml.snippets delete mode 100644 lib/ace/snippets/pascal.js delete mode 100644 lib/ace/snippets/pascal.snippets delete mode 100644 lib/ace/snippets/perl6.js delete mode 100644 lib/ace/snippets/perl6.snippets delete mode 100644 lib/ace/snippets/pgsql.js delete mode 100644 lib/ace/snippets/pgsql.snippets delete mode 100644 lib/ace/snippets/php_laravel_blade.js delete mode 100644 lib/ace/snippets/php_laravel_blade.snippets delete mode 100644 lib/ace/snippets/pig.js delete mode 100644 lib/ace/snippets/pig.snippets delete mode 100644 lib/ace/snippets/plain_text.js delete mode 100644 lib/ace/snippets/plain_text.snippets delete mode 100644 lib/ace/snippets/powershell.js delete mode 100644 lib/ace/snippets/powershell.snippets delete mode 100644 lib/ace/snippets/praat.js delete mode 100644 lib/ace/snippets/praat.snippets delete mode 100644 lib/ace/snippets/prisma.js delete mode 100644 lib/ace/snippets/prisma.snippets delete mode 100644 lib/ace/snippets/prolog.js delete mode 100644 lib/ace/snippets/prolog.snippets delete mode 100644 lib/ace/snippets/properties.js delete mode 100644 lib/ace/snippets/properties.snippets delete mode 100644 lib/ace/snippets/protobuf.js delete mode 100644 lib/ace/snippets/protobuf.snippets delete mode 100644 lib/ace/snippets/puppet.js delete mode 100644 lib/ace/snippets/puppet.snippets delete mode 100644 lib/ace/snippets/qml.js delete mode 100644 lib/ace/snippets/qml.snippets delete mode 100644 lib/ace/snippets/rdoc.js delete mode 100644 lib/ace/snippets/rdoc.snippets delete mode 100644 lib/ace/snippets/red.js delete mode 100644 lib/ace/snippets/red.snippets delete mode 100644 lib/ace/snippets/redshift.js delete mode 100644 lib/ace/snippets/redshift.snippets delete mode 100644 lib/ace/snippets/rhtml.js delete mode 100644 lib/ace/snippets/rhtml.snippets delete mode 100644 lib/ace/snippets/rust.js delete mode 100644 lib/ace/snippets/rust.snippets delete mode 100644 lib/ace/snippets/sass.js delete mode 100644 lib/ace/snippets/sass.snippets delete mode 100644 lib/ace/snippets/scad.js delete mode 100644 lib/ace/snippets/scad.snippets delete mode 100644 lib/ace/snippets/scala.js delete mode 100644 lib/ace/snippets/scala.snippets delete mode 100644 lib/ace/snippets/scheme.js delete mode 100644 lib/ace/snippets/scheme.snippets delete mode 100644 lib/ace/snippets/scss.js delete mode 100644 lib/ace/snippets/scss.snippets delete mode 100644 lib/ace/snippets/sjs.js delete mode 100644 lib/ace/snippets/sjs.snippets delete mode 100644 lib/ace/snippets/slim.js delete mode 100644 lib/ace/snippets/slim.snippets delete mode 100644 lib/ace/snippets/smarty.js delete mode 100644 lib/ace/snippets/smarty.snippets delete mode 100644 lib/ace/snippets/soy_template.js delete mode 100644 lib/ace/snippets/soy_template.snippets delete mode 100644 lib/ace/snippets/space.js delete mode 100644 lib/ace/snippets/space.snippets delete mode 100644 lib/ace/snippets/sparql.js delete mode 100644 lib/ace/snippets/sparql.snippets delete mode 100644 lib/ace/snippets/stylus.js delete mode 100644 lib/ace/snippets/stylus.snippets delete mode 100644 lib/ace/snippets/svg.js delete mode 100644 lib/ace/snippets/svg.snippets delete mode 100644 lib/ace/snippets/swift.js delete mode 100644 lib/ace/snippets/swift.snippets delete mode 100644 lib/ace/snippets/terraform.js delete mode 100644 lib/ace/snippets/terraform.snippets delete mode 100644 lib/ace/snippets/text.js delete mode 100644 lib/ace/snippets/text.snippets delete mode 100644 lib/ace/snippets/tmsnippet.snippets delete mode 100644 lib/ace/snippets/toml.js delete mode 100644 lib/ace/snippets/toml.snippets delete mode 100644 lib/ace/snippets/tsx.js delete mode 100644 lib/ace/snippets/tsx.snippets delete mode 100644 lib/ace/snippets/turtle.js delete mode 100644 lib/ace/snippets/turtle.snippets delete mode 100644 lib/ace/snippets/twig.js delete mode 100644 lib/ace/snippets/twig.snippets delete mode 100644 lib/ace/snippets/typescript.js delete mode 100644 lib/ace/snippets/typescript.snippets delete mode 100644 lib/ace/snippets/vala.snippets delete mode 100644 lib/ace/snippets/vbscript.js delete mode 100644 lib/ace/snippets/vbscript.snippets delete mode 100644 lib/ace/snippets/verilog.js delete mode 100644 lib/ace/snippets/verilog.snippets delete mode 100644 lib/ace/snippets/vhdl.js delete mode 100644 lib/ace/snippets/vhdl.snippets delete mode 100644 lib/ace/snippets/visualforce.js delete mode 100644 lib/ace/snippets/visualforce.snippets delete mode 100644 lib/ace/snippets/xml.js delete mode 100644 lib/ace/snippets/xml.snippets delete mode 100644 lib/ace/snippets/yaml.js delete mode 100644 lib/ace/snippets/yaml.snippets delete mode 100644 lib/ace/snippets/zeek.js delete mode 100644 lib/ace/snippets/zeek.snippets diff --git a/lib/ace/snippets/_all_modes.js b/lib/ace/snippets/_all_modes.js deleted file mode 100644 index 17086d08a4f..00000000000 --- a/lib/ace/snippets/_all_modes.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./_all_modes.snippets"); -exports.scope = "_all_modes"; - -}); diff --git a/lib/ace/snippets/_all_modes.snippets b/lib/ace/snippets/_all_modes.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/abap.js b/lib/ace/snippets/abap.js deleted file mode 100644 index 902cb1bbc69..00000000000 --- a/lib/ace/snippets/abap.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./abap.snippets"); -exports.scope = "abap"; - -}); diff --git a/lib/ace/snippets/abap.snippets b/lib/ace/snippets/abap.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/ada.js b/lib/ace/snippets/ada.js deleted file mode 100644 index 5b3ea2150b4..00000000000 --- a/lib/ace/snippets/ada.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./ada.snippets"); -exports.scope = "ada"; - -}); diff --git a/lib/ace/snippets/ada.snippets b/lib/ace/snippets/ada.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/alda.js b/lib/ace/snippets/alda.js deleted file mode 100644 index 4747ff592eb..00000000000 --- a/lib/ace/snippets/alda.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { - "use strict"; - - exports.snippetText = require("../requirejs/text!./alda.snippets"); - exports.scope = "alda"; - - }); \ No newline at end of file diff --git a/lib/ace/snippets/alda.snippets b/lib/ace/snippets/alda.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/all_modes.js b/lib/ace/snippets/all_modes.js deleted file mode 100644 index d0e46233743..00000000000 --- a/lib/ace/snippets/all_modes.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./all_modes.snippets"); -exports.scope = "all_modes"; - -}); diff --git a/lib/ace/snippets/all_modes.snippets b/lib/ace/snippets/all_modes.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/apache_conf.js b/lib/ace/snippets/apache_conf.js deleted file mode 100644 index 86aa69b422d..00000000000 --- a/lib/ace/snippets/apache_conf.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./apache_conf.snippets"); -exports.scope = "apache_conf"; - -}); diff --git a/lib/ace/snippets/apache_conf.snippets b/lib/ace/snippets/apache_conf.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/apex.js b/lib/ace/snippets/apex.js deleted file mode 100644 index 104722134c0..00000000000 --- a/lib/ace/snippets/apex.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./apex.snippets"); -exports.scope = "apex"; - -}); diff --git a/lib/ace/snippets/apex.snippets b/lib/ace/snippets/apex.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/applescript.js b/lib/ace/snippets/applescript.js deleted file mode 100644 index 5536397c4e0..00000000000 --- a/lib/ace/snippets/applescript.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./applescript.snippets"); -exports.scope = "applescript"; - -}); diff --git a/lib/ace/snippets/applescript.snippets b/lib/ace/snippets/applescript.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/asciidoc.js b/lib/ace/snippets/asciidoc.js deleted file mode 100644 index 7857020ccf1..00000000000 --- a/lib/ace/snippets/asciidoc.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./asciidoc.snippets"); -exports.scope = "asciidoc"; - -}); diff --git a/lib/ace/snippets/asciidoc.snippets b/lib/ace/snippets/asciidoc.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/asl.js b/lib/ace/snippets/asl.js deleted file mode 100644 index bc6911f46dc..00000000000 --- a/lib/ace/snippets/asl.js +++ /dev/null @@ -1,6 +0,0 @@ -define(function (require, exports, module) { - "use strict"; - - exports.snippetText = require("../requirejs/text!./asl.snippets"); - exports.scope = "asl"; -}); diff --git a/lib/ace/snippets/asl.snippets b/lib/ace/snippets/asl.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/assembly_x86.js b/lib/ace/snippets/assembly_x86.js deleted file mode 100644 index 747335be0c1..00000000000 --- a/lib/ace/snippets/assembly_x86.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./assembly_x86.snippets"); -exports.scope = "assembly_x86"; - -}); diff --git a/lib/ace/snippets/assembly_x86.snippets b/lib/ace/snippets/assembly_x86.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/autohotkey.js b/lib/ace/snippets/autohotkey.js deleted file mode 100644 index 064647e3fb4..00000000000 --- a/lib/ace/snippets/autohotkey.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./autohotkey.snippets"); -exports.scope = "autohotkey"; - -}); diff --git a/lib/ace/snippets/autohotkey.snippets b/lib/ace/snippets/autohotkey.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/batchfile.js b/lib/ace/snippets/batchfile.js deleted file mode 100644 index ec949d9618a..00000000000 --- a/lib/ace/snippets/batchfile.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./batchfile.snippets"); -exports.scope = "batchfile"; - -}); diff --git a/lib/ace/snippets/batchfile.snippets b/lib/ace/snippets/batchfile.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/c9search.js b/lib/ace/snippets/c9search.js deleted file mode 100644 index 62bc4403a5a..00000000000 --- a/lib/ace/snippets/c9search.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./c9search.snippets"); -exports.scope = "c9search"; - -}); diff --git a/lib/ace/snippets/c9search.snippets b/lib/ace/snippets/c9search.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/cirru.js b/lib/ace/snippets/cirru.js deleted file mode 100644 index c0d3416d07f..00000000000 --- a/lib/ace/snippets/cirru.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./cirru.snippets"); -exports.scope = "cirru"; - -}); diff --git a/lib/ace/snippets/cirru.snippets b/lib/ace/snippets/cirru.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/cobol.js b/lib/ace/snippets/cobol.js deleted file mode 100644 index 885f1c46e41..00000000000 --- a/lib/ace/snippets/cobol.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./cobol.snippets"); -exports.scope = "cobol"; - -}); diff --git a/lib/ace/snippets/cobol.snippets b/lib/ace/snippets/cobol.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/coldfusion.js b/lib/ace/snippets/coldfusion.js deleted file mode 100644 index 6f44f9f754f..00000000000 --- a/lib/ace/snippets/coldfusion.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./coldfusion.snippets"); -exports.scope = "coldfusion"; - -}); diff --git a/lib/ace/snippets/coldfusion.snippets b/lib/ace/snippets/coldfusion.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/crystal.js b/lib/ace/snippets/crystal.js deleted file mode 100644 index 84b4a41a192..00000000000 --- a/lib/ace/snippets/crystal.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./crystal.snippets"); -exports.scope = "crystal"; - -}); diff --git a/lib/ace/snippets/crystal.snippets b/lib/ace/snippets/crystal.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/csharp.js b/lib/ace/snippets/csharp.js deleted file mode 100644 index 3aafdf85501..00000000000 --- a/lib/ace/snippets/csharp.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./csharp.snippets"); -exports.scope = "csharp"; - -}); diff --git a/lib/ace/snippets/csharp.snippets b/lib/ace/snippets/csharp.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/csound_score.js b/lib/ace/snippets/csound_score.js deleted file mode 100644 index 1b787d81b14..00000000000 --- a/lib/ace/snippets/csound_score.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./csound_score.snippets"); -exports.scope = "csound_score"; - -}); diff --git a/lib/ace/snippets/csound_score.snippets b/lib/ace/snippets/csound_score.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/csp.js b/lib/ace/snippets/csp.js deleted file mode 100644 index 359d9103986..00000000000 --- a/lib/ace/snippets/csp.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./.snippets"); -exports.scope = ""; - -}); diff --git a/lib/ace/snippets/csp.snippets b/lib/ace/snippets/csp.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/curly.js b/lib/ace/snippets/curly.js deleted file mode 100644 index aa59f286326..00000000000 --- a/lib/ace/snippets/curly.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./curly.snippets"); -exports.scope = "curly"; - -}); diff --git a/lib/ace/snippets/curly.snippets b/lib/ace/snippets/curly.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/d.js b/lib/ace/snippets/d.js deleted file mode 100644 index 79446fdc867..00000000000 --- a/lib/ace/snippets/d.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./d.snippets"); -exports.scope = "d"; - -}); diff --git a/lib/ace/snippets/d.snippets b/lib/ace/snippets/d.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/dockerfile.js b/lib/ace/snippets/dockerfile.js deleted file mode 100644 index 057347fb2c0..00000000000 --- a/lib/ace/snippets/dockerfile.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./dockerfile.snippets"); -exports.scope = "dockerfile"; - -}); diff --git a/lib/ace/snippets/dockerfile.snippets b/lib/ace/snippets/dockerfile.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/dot.js b/lib/ace/snippets/dot.js deleted file mode 100644 index 420f4f0174c..00000000000 --- a/lib/ace/snippets/dot.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./dot.snippets"); -exports.scope = "dot"; - -}); diff --git a/lib/ace/snippets/dot.snippets b/lib/ace/snippets/dot.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/eiffel.js b/lib/ace/snippets/eiffel.js deleted file mode 100644 index 04f4c5a9bef..00000000000 --- a/lib/ace/snippets/eiffel.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./eiffel.snippets"); -exports.scope = "eiffel"; - -}); diff --git a/lib/ace/snippets/eiffel.snippets b/lib/ace/snippets/eiffel.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/ejs.js b/lib/ace/snippets/ejs.js deleted file mode 100644 index be477738822..00000000000 --- a/lib/ace/snippets/ejs.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./ejs.snippets"); -exports.scope = "ejs"; - -}); diff --git a/lib/ace/snippets/ejs.snippets b/lib/ace/snippets/ejs.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/elixir.js b/lib/ace/snippets/elixir.js deleted file mode 100644 index 359d9103986..00000000000 --- a/lib/ace/snippets/elixir.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./.snippets"); -exports.scope = ""; - -}); diff --git a/lib/ace/snippets/elixir.snippets b/lib/ace/snippets/elixir.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/elm.js b/lib/ace/snippets/elm.js deleted file mode 100644 index 44f18c1132f..00000000000 --- a/lib/ace/snippets/elm.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./elm.snippets"); -exports.scope = "elm"; - -}); diff --git a/lib/ace/snippets/elm.snippets b/lib/ace/snippets/elm.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/forth.js b/lib/ace/snippets/forth.js deleted file mode 100644 index c2bf910792d..00000000000 --- a/lib/ace/snippets/forth.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./forth.snippets"); -exports.scope = "forth"; - -}); diff --git a/lib/ace/snippets/forth.snippets b/lib/ace/snippets/forth.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/fortran.js b/lib/ace/snippets/fortran.js deleted file mode 100644 index 65d8a0d98dd..00000000000 --- a/lib/ace/snippets/fortran.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./fortran.snippets"); -exports.scope = "fortran"; - -}); diff --git a/lib/ace/snippets/fortran.snippets b/lib/ace/snippets/fortran.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/fsharp.js b/lib/ace/snippets/fsharp.js deleted file mode 100644 index e1feb72e218..00000000000 --- a/lib/ace/snippets/fsharp.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { - "use strict"; - - exports.snippetText = require("../requirejs/text!./fsharp.snippets"); - exports.scope = "fsharp"; - -}); diff --git a/lib/ace/snippets/fsharp.snippets b/lib/ace/snippets/fsharp.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/ftl.js b/lib/ace/snippets/ftl.js deleted file mode 100644 index 1cbcc0be61a..00000000000 --- a/lib/ace/snippets/ftl.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./ftl.snippets"); -exports.scope = "ftl"; - -}); diff --git a/lib/ace/snippets/ftl.snippets b/lib/ace/snippets/ftl.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/gcode.js b/lib/ace/snippets/gcode.js deleted file mode 100644 index bf5e5bc9fcb..00000000000 --- a/lib/ace/snippets/gcode.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./gcode.snippets"); -exports.scope = "gcode"; - -}); diff --git a/lib/ace/snippets/gcode.snippets b/lib/ace/snippets/gcode.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/gherkin.js b/lib/ace/snippets/gherkin.js deleted file mode 100644 index da0b684d9e0..00000000000 --- a/lib/ace/snippets/gherkin.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./gherkin.snippets"); -exports.scope = "gherkin"; - -}); diff --git a/lib/ace/snippets/gherkin.snippets b/lib/ace/snippets/gherkin.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/gitignore.js b/lib/ace/snippets/gitignore.js deleted file mode 100644 index 0a632c9901f..00000000000 --- a/lib/ace/snippets/gitignore.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./gitignore.snippets"); -exports.scope = "gitignore"; - -}); diff --git a/lib/ace/snippets/gitignore.snippets b/lib/ace/snippets/gitignore.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/glsl.js b/lib/ace/snippets/glsl.js deleted file mode 100644 index d9c5fc25644..00000000000 --- a/lib/ace/snippets/glsl.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./glsl.snippets"); -exports.scope = "glsl"; - -}); diff --git a/lib/ace/snippets/glsl.snippets b/lib/ace/snippets/glsl.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/golang.js b/lib/ace/snippets/golang.js deleted file mode 100644 index f7b0eeccdc2..00000000000 --- a/lib/ace/snippets/golang.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./golang.snippets"); -exports.scope = "golang"; - -}); diff --git a/lib/ace/snippets/golang.snippets b/lib/ace/snippets/golang.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/groovy.js b/lib/ace/snippets/groovy.js deleted file mode 100644 index 2fe4e111611..00000000000 --- a/lib/ace/snippets/groovy.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./groovy.snippets"); -exports.scope = "groovy"; - -}); diff --git a/lib/ace/snippets/groovy.snippets b/lib/ace/snippets/groovy.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/handlebars.js b/lib/ace/snippets/handlebars.js deleted file mode 100644 index 64ba39b3e2c..00000000000 --- a/lib/ace/snippets/handlebars.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./handlebars.snippets"); -exports.scope = "handlebars"; - -}); diff --git a/lib/ace/snippets/handlebars.snippets b/lib/ace/snippets/handlebars.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/haskell_cabal.js b/lib/ace/snippets/haskell_cabal.js deleted file mode 100644 index 0dfda712cfe..00000000000 --- a/lib/ace/snippets/haskell_cabal.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./haskell_cabal.snippets"); -exports.scope = "haskell_cabal"; - -}); diff --git a/lib/ace/snippets/haskell_cabal.snippets b/lib/ace/snippets/haskell_cabal.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/haxe.js b/lib/ace/snippets/haxe.js deleted file mode 100644 index b67f91eb095..00000000000 --- a/lib/ace/snippets/haxe.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./haxe.snippets"); -exports.scope = "haxe"; - -}); diff --git a/lib/ace/snippets/haxe.snippets b/lib/ace/snippets/haxe.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/hjson.js b/lib/ace/snippets/hjson.js deleted file mode 100644 index 359d9103986..00000000000 --- a/lib/ace/snippets/hjson.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./.snippets"); -exports.scope = ""; - -}); diff --git a/lib/ace/snippets/hjson.snippets b/lib/ace/snippets/hjson.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/html_elixir.js b/lib/ace/snippets/html_elixir.js deleted file mode 100644 index 9902adbed2a..00000000000 --- a/lib/ace/snippets/html_elixir.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./html_elixir.snippets"); -exports.scope = "html_elixir"; - -}); diff --git a/lib/ace/snippets/html_elixir.snippets b/lib/ace/snippets/html_elixir.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/html_ruby.js b/lib/ace/snippets/html_ruby.js deleted file mode 100644 index d985d568f2b..00000000000 --- a/lib/ace/snippets/html_ruby.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./html_ruby.snippets"); -exports.scope = "html_ruby"; - -}); diff --git a/lib/ace/snippets/html_ruby.snippets b/lib/ace/snippets/html_ruby.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/ini.js b/lib/ace/snippets/ini.js deleted file mode 100644 index df09d575c9d..00000000000 --- a/lib/ace/snippets/ini.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./ini.snippets"); -exports.scope = "ini"; - -}); diff --git a/lib/ace/snippets/ini.snippets b/lib/ace/snippets/ini.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/io.snippets b/lib/ace/snippets/io.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/jack.js b/lib/ace/snippets/jack.js deleted file mode 100644 index 29b8f9d26ec..00000000000 --- a/lib/ace/snippets/jack.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./jack.snippets"); -exports.scope = "jack"; - -}); diff --git a/lib/ace/snippets/jack.snippets b/lib/ace/snippets/jack.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/jade.js b/lib/ace/snippets/jade.js deleted file mode 100644 index ca83d483644..00000000000 --- a/lib/ace/snippets/jade.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./jade.snippets"); -exports.scope = "jade"; - -}); diff --git a/lib/ace/snippets/jade.snippets b/lib/ace/snippets/jade.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/json.js b/lib/ace/snippets/json.js deleted file mode 100644 index d57fe6c5098..00000000000 --- a/lib/ace/snippets/json.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./json.snippets"); -exports.scope = "json"; - -}); diff --git a/lib/ace/snippets/json.snippets b/lib/ace/snippets/json.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/jssm.js b/lib/ace/snippets/jssm.js deleted file mode 100644 index 359d9103986..00000000000 --- a/lib/ace/snippets/jssm.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./.snippets"); -exports.scope = ""; - -}); diff --git a/lib/ace/snippets/jssm.snippets b/lib/ace/snippets/jssm.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/jsx.js b/lib/ace/snippets/jsx.js deleted file mode 100644 index 9792a7a00d6..00000000000 --- a/lib/ace/snippets/jsx.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./jsx.snippets"); -exports.scope = "jsx"; - -}); diff --git a/lib/ace/snippets/jsx.snippets b/lib/ace/snippets/jsx.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/julia.js b/lib/ace/snippets/julia.js deleted file mode 100644 index f83777efa9d..00000000000 --- a/lib/ace/snippets/julia.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./julia.snippets"); -exports.scope = "julia"; - -}); diff --git a/lib/ace/snippets/julia.snippets b/lib/ace/snippets/julia.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/kotlin.js b/lib/ace/snippets/kotlin.js deleted file mode 100644 index 359d9103986..00000000000 --- a/lib/ace/snippets/kotlin.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./.snippets"); -exports.scope = ""; - -}); diff --git a/lib/ace/snippets/kotlin.snippets b/lib/ace/snippets/kotlin.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/latex.js b/lib/ace/snippets/latex.js deleted file mode 100644 index 44bef369180..00000000000 --- a/lib/ace/snippets/latex.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./latex.snippets"); -exports.scope = "latex"; - -}); diff --git a/lib/ace/snippets/latex.snippets b/lib/ace/snippets/latex.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/less.js b/lib/ace/snippets/less.js deleted file mode 100644 index 7acf02f29d7..00000000000 --- a/lib/ace/snippets/less.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./less.snippets"); -exports.scope = "less"; - -}); diff --git a/lib/ace/snippets/less.snippets b/lib/ace/snippets/less.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/lisp.js b/lib/ace/snippets/lisp.js deleted file mode 100644 index 2b6870bc4ec..00000000000 --- a/lib/ace/snippets/lisp.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./lisp.snippets"); -exports.scope = "lisp"; - -}); diff --git a/lib/ace/snippets/lisp.snippets b/lib/ace/snippets/lisp.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/livescript.js b/lib/ace/snippets/livescript.js deleted file mode 100644 index ba20e7e4212..00000000000 --- a/lib/ace/snippets/livescript.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./livescript.snippets"); -exports.scope = "livescript"; - -}); diff --git a/lib/ace/snippets/livescript.snippets b/lib/ace/snippets/livescript.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/logiql.js b/lib/ace/snippets/logiql.js deleted file mode 100644 index 7d0167dab2d..00000000000 --- a/lib/ace/snippets/logiql.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./logiql.snippets"); -exports.scope = "logiql"; - -}); diff --git a/lib/ace/snippets/logiql.snippets b/lib/ace/snippets/logiql.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/logtalk.js b/lib/ace/snippets/logtalk.js deleted file mode 100644 index 707176896b1..00000000000 --- a/lib/ace/snippets/logtalk.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./logtalk.snippets"); -exports.scope = "logtalk"; - -}); diff --git a/lib/ace/snippets/logtalk.snippets b/lib/ace/snippets/logtalk.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/luapage.js b/lib/ace/snippets/luapage.js deleted file mode 100644 index 86b228427c7..00000000000 --- a/lib/ace/snippets/luapage.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./luapage.snippets"); -exports.scope = "luapage"; - -}); diff --git a/lib/ace/snippets/luapage.snippets b/lib/ace/snippets/luapage.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/lucene.js b/lib/ace/snippets/lucene.js deleted file mode 100644 index 01edb07de93..00000000000 --- a/lib/ace/snippets/lucene.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./lucene.snippets"); -exports.scope = "lucene"; - -}); diff --git a/lib/ace/snippets/lucene.snippets b/lib/ace/snippets/lucene.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/mask.js b/lib/ace/snippets/mask.js deleted file mode 100644 index 7fbca678066..00000000000 --- a/lib/ace/snippets/mask.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./mask.snippets"); -exports.scope = "mask"; - -}); diff --git a/lib/ace/snippets/mask.snippets b/lib/ace/snippets/mask.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/matlab.js b/lib/ace/snippets/matlab.js deleted file mode 100644 index 698366ba455..00000000000 --- a/lib/ace/snippets/matlab.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./matlab.snippets"); -exports.scope = "matlab"; - -}); diff --git a/lib/ace/snippets/matlab.snippets b/lib/ace/snippets/matlab.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/mel.js b/lib/ace/snippets/mel.js deleted file mode 100644 index 090d79b32db..00000000000 --- a/lib/ace/snippets/mel.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./mel.snippets"); -exports.scope = "mel"; - -}); diff --git a/lib/ace/snippets/mel.snippets b/lib/ace/snippets/mel.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/mixal.js b/lib/ace/snippets/mixal.js deleted file mode 100644 index 0acfae2f338..00000000000 --- a/lib/ace/snippets/mixal.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./mixal.snippets"); -exports.scope = "mixal"; - -}); diff --git a/lib/ace/snippets/mixal.snippets b/lib/ace/snippets/mixal.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/mushcode.js b/lib/ace/snippets/mushcode.js deleted file mode 100644 index 8b0d2dcb0ba..00000000000 --- a/lib/ace/snippets/mushcode.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./mushcode.snippets"); -exports.scope = "mushcode"; - -}); diff --git a/lib/ace/snippets/mushcode.snippets b/lib/ace/snippets/mushcode.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/mushcode_high_rules.js b/lib/ace/snippets/mushcode_high_rules.js deleted file mode 100644 index 25d42827437..00000000000 --- a/lib/ace/snippets/mushcode_high_rules.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./mushcode_high_rules.snippets"); -exports.scope = "mushcode_high_rules"; - -}); diff --git a/lib/ace/snippets/mushcode_high_rules.snippets b/lib/ace/snippets/mushcode_high_rules.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/mysql.js b/lib/ace/snippets/mysql.js deleted file mode 100644 index e5462390b37..00000000000 --- a/lib/ace/snippets/mysql.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./mysql.snippets"); -exports.scope = "mysql"; - -}); diff --git a/lib/ace/snippets/mysql.snippets b/lib/ace/snippets/mysql.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/nginx.js b/lib/ace/snippets/nginx.js deleted file mode 100644 index 068115831a4..00000000000 --- a/lib/ace/snippets/nginx.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./nginx.snippets"); -exports.scope = "nginx"; - -}); diff --git a/lib/ace/snippets/nginx.snippets b/lib/ace/snippets/nginx.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/nim.js b/lib/ace/snippets/nim.js deleted file mode 100644 index 6e6d02bbe48..00000000000 --- a/lib/ace/snippets/nim.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./nim.snippets"); -exports.scope = "nim"; - -}); diff --git a/lib/ace/snippets/nim.snippets b/lib/ace/snippets/nim.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/nix.js b/lib/ace/snippets/nix.js deleted file mode 100644 index 583abf85b4d..00000000000 --- a/lib/ace/snippets/nix.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./nix.snippets"); -exports.scope = "nix"; - -}); diff --git a/lib/ace/snippets/nix.snippets b/lib/ace/snippets/nix.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/nsis.js b/lib/ace/snippets/nsis.js deleted file mode 100644 index 359d9103986..00000000000 --- a/lib/ace/snippets/nsis.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./.snippets"); -exports.scope = ""; - -}); diff --git a/lib/ace/snippets/nsis.snippets b/lib/ace/snippets/nsis.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/objectivec.js b/lib/ace/snippets/objectivec.js deleted file mode 100644 index ed5d5fa8331..00000000000 --- a/lib/ace/snippets/objectivec.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./objectivec.snippets"); -exports.scope = "objectivec"; - -}); diff --git a/lib/ace/snippets/objectivec.snippets b/lib/ace/snippets/objectivec.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/ocaml.js b/lib/ace/snippets/ocaml.js deleted file mode 100644 index a6e6842e931..00000000000 --- a/lib/ace/snippets/ocaml.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./ocaml.snippets"); -exports.scope = "ocaml"; - -}); diff --git a/lib/ace/snippets/ocaml.snippets b/lib/ace/snippets/ocaml.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/pascal.js b/lib/ace/snippets/pascal.js deleted file mode 100644 index cd8f19fe272..00000000000 --- a/lib/ace/snippets/pascal.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./pascal.snippets"); -exports.scope = "pascal"; - -}); diff --git a/lib/ace/snippets/pascal.snippets b/lib/ace/snippets/pascal.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/perl6.js b/lib/ace/snippets/perl6.js deleted file mode 100644 index af05b2520bb..00000000000 --- a/lib/ace/snippets/perl6.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./perl6.snippets"); -exports.scope = "perl6"; - -}); diff --git a/lib/ace/snippets/perl6.snippets b/lib/ace/snippets/perl6.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/pgsql.js b/lib/ace/snippets/pgsql.js deleted file mode 100644 index 9bbd9012e77..00000000000 --- a/lib/ace/snippets/pgsql.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./pgsql.snippets"); -exports.scope = "pgsql"; - -}); diff --git a/lib/ace/snippets/pgsql.snippets b/lib/ace/snippets/pgsql.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/php_laravel_blade.js b/lib/ace/snippets/php_laravel_blade.js deleted file mode 100644 index 8f911d3ebb5..00000000000 --- a/lib/ace/snippets/php_laravel_blade.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { - "use strict"; - - exports.snippetText = require("../requirejs/text!./php_laravel_blade.snippets"); - exports.scope = "php"; - -}); diff --git a/lib/ace/snippets/php_laravel_blade.snippets b/lib/ace/snippets/php_laravel_blade.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/pig.js b/lib/ace/snippets/pig.js deleted file mode 100644 index 07d0d777e7b..00000000000 --- a/lib/ace/snippets/pig.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./pig.snippets"); -exports.scope = "pig"; - -}); diff --git a/lib/ace/snippets/pig.snippets b/lib/ace/snippets/pig.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/plain_text.js b/lib/ace/snippets/plain_text.js deleted file mode 100644 index 4b4dad55b94..00000000000 --- a/lib/ace/snippets/plain_text.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./plain_text.snippets"); -exports.scope = "plain_text"; - -}); diff --git a/lib/ace/snippets/plain_text.snippets b/lib/ace/snippets/plain_text.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/powershell.js b/lib/ace/snippets/powershell.js deleted file mode 100644 index 4639a304b1f..00000000000 --- a/lib/ace/snippets/powershell.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./powershell.snippets"); -exports.scope = "powershell"; - -}); diff --git a/lib/ace/snippets/powershell.snippets b/lib/ace/snippets/powershell.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/praat.js b/lib/ace/snippets/praat.js deleted file mode 100644 index 18afa87f042..00000000000 --- a/lib/ace/snippets/praat.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./praat.snippets"); -exports.scope = "praat"; - -}); diff --git a/lib/ace/snippets/praat.snippets b/lib/ace/snippets/praat.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/prisma.js b/lib/ace/snippets/prisma.js deleted file mode 100644 index b64d41ef7dc..00000000000 --- a/lib/ace/snippets/prisma.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./prisma.snippets"); -exports.scope = "prisma"; - -}); diff --git a/lib/ace/snippets/prisma.snippets b/lib/ace/snippets/prisma.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/prolog.js b/lib/ace/snippets/prolog.js deleted file mode 100644 index 7c9d0fbc932..00000000000 --- a/lib/ace/snippets/prolog.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./prolog.snippets"); -exports.scope = "prolog"; - -}); diff --git a/lib/ace/snippets/prolog.snippets b/lib/ace/snippets/prolog.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/properties.js b/lib/ace/snippets/properties.js deleted file mode 100644 index 18bd3883023..00000000000 --- a/lib/ace/snippets/properties.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./properties.snippets"); -exports.scope = "properties"; - -}); diff --git a/lib/ace/snippets/properties.snippets b/lib/ace/snippets/properties.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/protobuf.js b/lib/ace/snippets/protobuf.js deleted file mode 100644 index 24855545453..00000000000 --- a/lib/ace/snippets/protobuf.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = ""; -exports.scope = "protobuf"; - -}); \ No newline at end of file diff --git a/lib/ace/snippets/protobuf.snippets b/lib/ace/snippets/protobuf.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/puppet.js b/lib/ace/snippets/puppet.js deleted file mode 100644 index 61d1a67081f..00000000000 --- a/lib/ace/snippets/puppet.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./puppet.snippets"); -exports.scope = "puppet"; - -}); diff --git a/lib/ace/snippets/puppet.snippets b/lib/ace/snippets/puppet.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/qml.js b/lib/ace/snippets/qml.js deleted file mode 100644 index fffbdebb4b3..00000000000 --- a/lib/ace/snippets/qml.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { - "use strict"; - - exports.snippetText = require("../requirejs/text!./qml.snippets"); - exports.scope = "qml"; - - }); diff --git a/lib/ace/snippets/qml.snippets b/lib/ace/snippets/qml.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/rdoc.js b/lib/ace/snippets/rdoc.js deleted file mode 100644 index 0d9e6c95814..00000000000 --- a/lib/ace/snippets/rdoc.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./rdoc.snippets"); -exports.scope = "rdoc"; - -}); diff --git a/lib/ace/snippets/rdoc.snippets b/lib/ace/snippets/rdoc.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/red.js b/lib/ace/snippets/red.js deleted file mode 100644 index bc0c39c8777..00000000000 --- a/lib/ace/snippets/red.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./red.snippets"); -exports.scope = "red"; - -}); diff --git a/lib/ace/snippets/red.snippets b/lib/ace/snippets/red.snippets deleted file mode 100644 index 0519ecba6ea..00000000000 --- a/lib/ace/snippets/red.snippets +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/lib/ace/snippets/redshift.js b/lib/ace/snippets/redshift.js deleted file mode 100644 index 1564301a4cd..00000000000 --- a/lib/ace/snippets/redshift.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./redshift.snippets"); -exports.scope = "redshift"; - -}); diff --git a/lib/ace/snippets/redshift.snippets b/lib/ace/snippets/redshift.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/rhtml.js b/lib/ace/snippets/rhtml.js deleted file mode 100644 index 96707f21916..00000000000 --- a/lib/ace/snippets/rhtml.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./rhtml.snippets"); -exports.scope = "rhtml"; - -}); diff --git a/lib/ace/snippets/rhtml.snippets b/lib/ace/snippets/rhtml.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/rust.js b/lib/ace/snippets/rust.js deleted file mode 100644 index 556d9a6b100..00000000000 --- a/lib/ace/snippets/rust.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./rust.snippets"); -exports.scope = "rust"; - -}); diff --git a/lib/ace/snippets/rust.snippets b/lib/ace/snippets/rust.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/sass.js b/lib/ace/snippets/sass.js deleted file mode 100644 index ba728ac2fee..00000000000 --- a/lib/ace/snippets/sass.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./sass.snippets"); -exports.scope = "sass"; - -}); diff --git a/lib/ace/snippets/sass.snippets b/lib/ace/snippets/sass.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/scad.js b/lib/ace/snippets/scad.js deleted file mode 100644 index 28db2155d16..00000000000 --- a/lib/ace/snippets/scad.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./scad.snippets"); -exports.scope = "scad"; - -}); diff --git a/lib/ace/snippets/scad.snippets b/lib/ace/snippets/scad.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/scala.js b/lib/ace/snippets/scala.js deleted file mode 100644 index 2e5a8c57789..00000000000 --- a/lib/ace/snippets/scala.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./scala.snippets"); -exports.scope = "scala"; - -}); diff --git a/lib/ace/snippets/scala.snippets b/lib/ace/snippets/scala.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/scheme.js b/lib/ace/snippets/scheme.js deleted file mode 100644 index 7d3c6f65ea3..00000000000 --- a/lib/ace/snippets/scheme.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./scheme.snippets"); -exports.scope = "scheme"; - -}); diff --git a/lib/ace/snippets/scheme.snippets b/lib/ace/snippets/scheme.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/scss.js b/lib/ace/snippets/scss.js deleted file mode 100644 index a940eabdb6d..00000000000 --- a/lib/ace/snippets/scss.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./scss.snippets"); -exports.scope = "scss"; - -}); diff --git a/lib/ace/snippets/scss.snippets b/lib/ace/snippets/scss.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/sjs.js b/lib/ace/snippets/sjs.js deleted file mode 100644 index a88cfc90cef..00000000000 --- a/lib/ace/snippets/sjs.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./sjs.snippets"); -exports.scope = "sjs"; - -}); diff --git a/lib/ace/snippets/sjs.snippets b/lib/ace/snippets/sjs.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/slim.js b/lib/ace/snippets/slim.js deleted file mode 100644 index 6f77deb658c..00000000000 --- a/lib/ace/snippets/slim.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { - "use strict"; - - exports.snippetText = require("../requirejs/text!./slim.snippets"); - exports.scope = "slim"; - -}); diff --git a/lib/ace/snippets/slim.snippets b/lib/ace/snippets/slim.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/smarty.js b/lib/ace/snippets/smarty.js deleted file mode 100644 index 121d0b7c421..00000000000 --- a/lib/ace/snippets/smarty.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./smarty.snippets"); -exports.scope = "smarty"; - -}); diff --git a/lib/ace/snippets/smarty.snippets b/lib/ace/snippets/smarty.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/soy_template.js b/lib/ace/snippets/soy_template.js deleted file mode 100644 index 194da7574ea..00000000000 --- a/lib/ace/snippets/soy_template.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./soy_template.snippets"); -exports.scope = "soy_template"; - -}); diff --git a/lib/ace/snippets/soy_template.snippets b/lib/ace/snippets/soy_template.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/space.js b/lib/ace/snippets/space.js deleted file mode 100644 index 766d493e9d8..00000000000 --- a/lib/ace/snippets/space.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./space.snippets"); -exports.scope = "space"; - -}); diff --git a/lib/ace/snippets/space.snippets b/lib/ace/snippets/space.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/sparql.js b/lib/ace/snippets/sparql.js deleted file mode 100644 index 359d9103986..00000000000 --- a/lib/ace/snippets/sparql.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./.snippets"); -exports.scope = ""; - -}); diff --git a/lib/ace/snippets/sparql.snippets b/lib/ace/snippets/sparql.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/stylus.js b/lib/ace/snippets/stylus.js deleted file mode 100644 index 86a79f7aca1..00000000000 --- a/lib/ace/snippets/stylus.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./stylus.snippets"); -exports.scope = "stylus"; - -}); diff --git a/lib/ace/snippets/stylus.snippets b/lib/ace/snippets/stylus.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/svg.js b/lib/ace/snippets/svg.js deleted file mode 100644 index aeb6245619d..00000000000 --- a/lib/ace/snippets/svg.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./svg.snippets"); -exports.scope = "svg"; - -}); diff --git a/lib/ace/snippets/svg.snippets b/lib/ace/snippets/svg.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/swift.js b/lib/ace/snippets/swift.js deleted file mode 100644 index 46e5e1106b4..00000000000 --- a/lib/ace/snippets/swift.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./swift.snippets"); -exports.scope = "swift"; - -}); diff --git a/lib/ace/snippets/swift.snippets b/lib/ace/snippets/swift.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/terraform.js b/lib/ace/snippets/terraform.js deleted file mode 100644 index d681d4e5278..00000000000 --- a/lib/ace/snippets/terraform.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./terraform.snippets"); -exports.scope = "terraform"; - -}); diff --git a/lib/ace/snippets/terraform.snippets b/lib/ace/snippets/terraform.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/text.js b/lib/ace/snippets/text.js deleted file mode 100644 index 434d75bed46..00000000000 --- a/lib/ace/snippets/text.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./text.snippets"); -exports.scope = "text"; - -}); diff --git a/lib/ace/snippets/text.snippets b/lib/ace/snippets/text.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/tmsnippet.snippets b/lib/ace/snippets/tmsnippet.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/toml.js b/lib/ace/snippets/toml.js deleted file mode 100644 index 419b06d83e2..00000000000 --- a/lib/ace/snippets/toml.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./toml.snippets"); -exports.scope = "toml"; - -}); diff --git a/lib/ace/snippets/toml.snippets b/lib/ace/snippets/toml.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/tsx.js b/lib/ace/snippets/tsx.js deleted file mode 100644 index 457e33b24e6..00000000000 --- a/lib/ace/snippets/tsx.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./tsx.snippets"); -exports.scope = "tsx"; - -}); diff --git a/lib/ace/snippets/tsx.snippets b/lib/ace/snippets/tsx.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/turtle.js b/lib/ace/snippets/turtle.js deleted file mode 100644 index 359d9103986..00000000000 --- a/lib/ace/snippets/turtle.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./.snippets"); -exports.scope = ""; - -}); diff --git a/lib/ace/snippets/turtle.snippets b/lib/ace/snippets/turtle.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/twig.js b/lib/ace/snippets/twig.js deleted file mode 100644 index b08b884c500..00000000000 --- a/lib/ace/snippets/twig.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./twig.snippets"); -exports.scope = "twig"; - -}); diff --git a/lib/ace/snippets/twig.snippets b/lib/ace/snippets/twig.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/typescript.js b/lib/ace/snippets/typescript.js deleted file mode 100644 index 495da3f35b1..00000000000 --- a/lib/ace/snippets/typescript.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./typescript.snippets"); -exports.scope = "typescript"; - -}); diff --git a/lib/ace/snippets/typescript.snippets b/lib/ace/snippets/typescript.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/vala.snippets b/lib/ace/snippets/vala.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/vbscript.js b/lib/ace/snippets/vbscript.js deleted file mode 100644 index 5ab8e650d5e..00000000000 --- a/lib/ace/snippets/vbscript.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./vbscript.snippets"); -exports.scope = "vbscript"; - -}); diff --git a/lib/ace/snippets/vbscript.snippets b/lib/ace/snippets/vbscript.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/verilog.js b/lib/ace/snippets/verilog.js deleted file mode 100644 index 7360341e6d3..00000000000 --- a/lib/ace/snippets/verilog.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./verilog.snippets"); -exports.scope = "verilog"; - -}); diff --git a/lib/ace/snippets/verilog.snippets b/lib/ace/snippets/verilog.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/vhdl.js b/lib/ace/snippets/vhdl.js deleted file mode 100644 index fe5e708fb8e..00000000000 --- a/lib/ace/snippets/vhdl.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./vhdl.snippets"); -exports.scope = "vhdl"; - -}); \ No newline at end of file diff --git a/lib/ace/snippets/vhdl.snippets b/lib/ace/snippets/vhdl.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/visualforce.js b/lib/ace/snippets/visualforce.js deleted file mode 100644 index 2d01c0f5d72..00000000000 --- a/lib/ace/snippets/visualforce.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./visualforce.snippets"); -exports.scope = "visualforce"; - -}); diff --git a/lib/ace/snippets/visualforce.snippets b/lib/ace/snippets/visualforce.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/xml.js b/lib/ace/snippets/xml.js deleted file mode 100644 index 83b1870c9bc..00000000000 --- a/lib/ace/snippets/xml.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./xml.snippets"); -exports.scope = "xml"; - -}); diff --git a/lib/ace/snippets/xml.snippets b/lib/ace/snippets/xml.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/yaml.js b/lib/ace/snippets/yaml.js deleted file mode 100644 index 17e70a3cbfb..00000000000 --- a/lib/ace/snippets/yaml.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./yaml.snippets"); -exports.scope = "yaml"; - -}); diff --git a/lib/ace/snippets/yaml.snippets b/lib/ace/snippets/yaml.snippets deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ace/snippets/zeek.js b/lib/ace/snippets/zeek.js deleted file mode 100644 index fa638070c33..00000000000 --- a/lib/ace/snippets/zeek.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./zeek.snippets"); -exports.scope = ""; - -}); diff --git a/lib/ace/snippets/zeek.snippets b/lib/ace/snippets/zeek.snippets deleted file mode 100644 index e69de29bb2d..00000000000 From f5f83a2ef8d363bfcb7332db883d12a6db23f6c8 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 26 Mar 2020 02:49:41 +0400 Subject: [PATCH 0314/1293] load snippets only if the mode has snippetFileId --- lib/ace/ext/language_tools.js | 34 +-- lib/ace/mode/_test/highlight_rules_test.js | 14 ++ lib/ace/mode/abc.js | 1 + lib/ace/mode/actionscript.js | 1 + lib/ace/mode/c_cpp.js | 1 + lib/ace/mode/clojure.js | 1 + lib/ace/mode/coffee.js | 1 + lib/ace/mode/csound_document.js | 5 + lib/ace/mode/csound_orchestra.js | 2 + lib/ace/mode/csound_score.js | 1 + lib/ace/mode/css.js | 1 + lib/ace/mode/dart.js | 1 + lib/ace/mode/diff.js | 1 + lib/ace/mode/django.js | 1 + lib/ace/mode/drools.js | 1 + lib/ace/mode/edifact.js | 1 + lib/ace/mode/erlang.js | 1 + lib/ace/mode/fsl.js | 1 + lib/ace/mode/gobstones.js | 1 + lib/ace/mode/graphqlschema.js | 1 + lib/ace/mode/haml.js | 1 + lib/ace/mode/haskell.js | 1 + lib/ace/mode/html.js | 1 + lib/ace/mode/io.js | 1 + lib/ace/mode/java.js | 1 + lib/ace/mode/javascript.js | 1 + lib/ace/mode/json.js | 3 + lib/ace/mode/jsoniq.js | 1 + lib/ace/mode/jsp.js | 1 + lib/ace/mode/liquid.js | 1 + lib/ace/mode/lsl.js | 1 + lib/ace/mode/lua.js | 1 + lib/ace/mode/makefile.js | 1 + lib/ace/mode/markdown.js | 1 + lib/ace/mode/maze.js | 1 + lib/ace/mode/perl.js | 1 + lib/ace/mode/php.js | 1 + lib/ace/mode/python.js | 1 + lib/ace/mode/r.js | 1 + lib/ace/mode/razor.js | 1 + lib/ace/mode/rst.js | 1 + lib/ace/mode/ruby.js | 1 + lib/ace/mode/sh.js | 1 + lib/ace/mode/snippets.js | 1 + lib/ace/mode/sql.js | 1 + lib/ace/mode/sqlserver.js | 3 +- lib/ace/mode/tcl.js | 1 + lib/ace/mode/tex.js | 1 + lib/ace/mode/textile.js | 1 + lib/ace/mode/vala.js | 1 + lib/ace/mode/velocity.js | 1 + lib/ace/mode/wollok.js | 1 + lib/ace/mode/xquery.js | 1 + lib/ace/snippets/_.snippets | 240 --------------------- lib/ace/snippets/dummy.js | 7 - lib/ace/snippets/dummy_syntax.js | 7 - 56 files changed, 91 insertions(+), 271 deletions(-) delete mode 100644 lib/ace/snippets/_.snippets delete mode 100644 lib/ace/snippets/dummy.js delete mode 100644 lib/ace/snippets/dummy_syntax.js diff --git a/lib/ace/ext/language_tools.js b/lib/ace/ext/language_tools.js index 18c3378c118..2cbeea45a27 100644 --- a/lib/ace/ext/language_tools.js +++ b/lib/ace/ext/language_tools.js @@ -117,31 +117,33 @@ var onChangeMode = function(e, editor) { }; var loadSnippetsForMode = function(mode) { - var id = mode.$id; + if (typeof mode == "string") + mode = config.$modes[mode]; + if (!mode) + return; if (!snippetManager.files) snippetManager.files = {}; - loadSnippetFile(id); + + loadSnippetFile(mode.$id, mode.snippetFileId); if (mode.modes) mode.modes.forEach(loadSnippetsForMode); }; -var loadSnippetFile = function(id) { - if (!id || snippetManager.files[id]) +var loadSnippetFile = function(id, snippetFilePath) { + if (!snippetFilePath || !id || snippetManager.files[id]) return; - var snippetFilePath = id.replace("mode", "snippets"); snippetManager.files[id] = {}; config.loadModule(snippetFilePath, function(m) { - if (m) { - snippetManager.files[id] = m; - if (!m.snippets && m.snippetText) - m.snippets = snippetManager.parseSnippetFile(m.snippetText); - snippetManager.register(m.snippets || [], m.scope); - if (m.includeScopes) { - snippetManager.snippetMap[m.scope].includeScopes = m.includeScopes; - m.includeScopes.forEach(function(x) { - loadSnippetFile("ace/mode/" + x); - }); - } + if (!m) return; + snippetManager.files[id] = m; + if (!m.snippets && m.snippetText) + m.snippets = snippetManager.parseSnippetFile(m.snippetText); + snippetManager.register(m.snippets || [], m.scope); + if (m.includeScopes) { + snippetManager.snippetMap[m.scope].includeScopes = m.includeScopes; + m.includeScopes.forEach(function(x) { + loadSnippetsForMode("ace/mode/" + x); + }); } }); }; diff --git a/lib/ace/mode/_test/highlight_rules_test.js b/lib/ace/mode/_test/highlight_rules_test.js index da72dc06b1d..c35cbf04097 100644 --- a/lib/ace/mode/_test/highlight_rules_test.js +++ b/lib/ace/mode/_test/highlight_rules_test.js @@ -28,6 +28,7 @@ function modeList() { } function checkModes() { + var snippets = {}; modeList().forEach(function(modeName, i) { console.log(padNumber(i+1, 3) + ") check: \u001b[33m" + modeName + "\u001b[0m"); try { @@ -48,8 +49,21 @@ function checkModes() { testComments(m.lineCommentStart, testLineComment, tokenizer, modeName); testComments(m.blockComment, testBlockComment, tokenizer, modeName); testBrackets(m, modeName); + + if (m.snippetFileId) + snippets[m.snippetFileId] = modeName; }); + jsFileList(cwd + "../../snippets").forEach(function(snippetFileName) { + if (!snippets["ace/snippets/" + snippetFileName]) + throw new Error(snippetFileName + " is not used"); + delete snippets["ace/snippets/" + snippetFileName]; + }) ; + if (Object.keys(snippets).length) { + console.error("Snippet files missing", snippets); + throw new Error("Snippet files missing"); + } + function testComments(desc, fn, tokenizer, modeName) { if (desc) { if (Array.isArray(desc)) { diff --git a/lib/ace/mode/abc.js b/lib/ace/mode/abc.js index 344c950629a..30a443cc729 100644 --- a/lib/ace/mode/abc.js +++ b/lib/ace/mode/abc.js @@ -52,6 +52,7 @@ define(function (require, exports, module) { // this.blockComment = {start: ""/*"", end: ""*/""}; // Extra logic goes here. this.$id = "ace/mode/abc"; + this.snippetFileId = "ace/snippets/abc"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/actionscript.js b/lib/ace/mode/actionscript.js index 70eaaba684b..314d9602af4 100644 --- a/lib/ace/mode/actionscript.js +++ b/lib/ace/mode/actionscript.js @@ -52,6 +52,7 @@ oop.inherits(Mode, TextMode); this.lineCommentStart = "//"; this.blockComment = {start: "/*", end: "*/"}; this.$id = "ace/mode/actionscript"; + this.snippetFileId = "ace/snippets/actionscript"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/c_cpp.js b/lib/ace/mode/c_cpp.js index a2dc133f412..dae15b1bbe8 100644 --- a/lib/ace/mode/c_cpp.js +++ b/lib/ace/mode/c_cpp.js @@ -95,6 +95,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/c_cpp"; + this.snippetFileId = "ace/snippets/c_cpp"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/clojure.js b/lib/ace/mode/clojure.js index 6bb9b0ae01c..4d93013fdf2 100644 --- a/lib/ace/mode/clojure.js +++ b/lib/ace/mode/clojure.js @@ -123,6 +123,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/clojure"; + this.snippetFileId = "ace/snippets/clojure"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/coffee.js b/lib/ace/mode/coffee.js index 9782fc7181f..2a847432cf8 100644 --- a/lib/ace/mode/coffee.js +++ b/lib/ace/mode/coffee.js @@ -109,6 +109,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/coffee"; + this.snippetFileId = "ace/snippets/coffee"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/csound_document.js b/lib/ace/mode/csound_document.js index a10d7d5ecfb..6812aba4fe9 100644 --- a/lib/ace/mode/csound_document.js +++ b/lib/ace/mode/csound_document.js @@ -10,5 +10,10 @@ var Mode = function() { }; oop.inherits(Mode, TextMode); +(function() { + this.$id = "ace/mode/csound_document"; + this.snippetFileId = "ace/snippets/csound_document"; +}).call(Mode.prototype); + exports.Mode = Mode; }); diff --git a/lib/ace/mode/csound_orchestra.js b/lib/ace/mode/csound_orchestra.js index 4f712911eba..103a4eabe54 100644 --- a/lib/ace/mode/csound_orchestra.js +++ b/lib/ace/mode/csound_orchestra.js @@ -15,6 +15,8 @@ oop.inherits(Mode, TextMode); this.lineCommentStart = ";"; this.blockComment = {start: "/*", end: "*/"}; + this.$id = "ace/mode/csound_orchestra"; + this.snippetFileId = "ace/snippets/csound_orchestra"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/csound_score.js b/lib/ace/mode/csound_score.js index 2abb00cd0e4..2e15da36235 100644 --- a/lib/ace/mode/csound_score.js +++ b/lib/ace/mode/csound_score.js @@ -15,6 +15,7 @@ oop.inherits(Mode, TextMode); this.lineCommentStart = ";"; this.blockComment = {start: "/*", end: "*/"}; + this.$id = "ace/mode/csound_score"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/css.js b/lib/ace/mode/css.js index cafa502cf13..e37d457d1bd 100644 --- a/lib/ace/mode/css.js +++ b/lib/ace/mode/css.js @@ -99,6 +99,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/css"; + this.snippetFileId = "ace/snippets/css"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/dart.js b/lib/ace/mode/dart.js index ba9fff183c4..dcfae6039aa 100644 --- a/lib/ace/mode/dart.js +++ b/lib/ace/mode/dart.js @@ -56,6 +56,7 @@ oop.inherits(Mode, CMode); this.lineCommentStart = "//"; this.blockComment = {start: "/*", end: "*/"}; this.$id = "ace/mode/dart"; + this.snippetFileId = "ace/snippets/dart"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/diff.js b/lib/ace/mode/diff.js index f3c46a1b014..47e1ecf542e 100644 --- a/lib/ace/mode/diff.js +++ b/lib/ace/mode/diff.js @@ -45,6 +45,7 @@ oop.inherits(Mode, TextMode); (function() { this.$id = "ace/mode/diff"; + this.snippetFileId = "ace/snippets/diff"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/django.js b/lib/ace/mode/django.js index 59f9cb3ab43..67ce5175eb1 100644 --- a/lib/ace/mode/django.js +++ b/lib/ace/mode/django.js @@ -108,6 +108,7 @@ oop.inherits(Mode, HtmlMode); (function() { this.$id = "ace/mode/django"; + this.snippetFileId = "ace/snippets/django"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/drools.js b/lib/ace/mode/drools.js index 3a361ec8791..9e2ea016eac 100644 --- a/lib/ace/mode/drools.js +++ b/lib/ace/mode/drools.js @@ -47,6 +47,7 @@ oop.inherits(Mode, TextMode); (function() { this.lineCommentStart = "//"; this.$id = "ace/mode/drools"; + this.snippetFileId = "ace/snippets/drools"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/edifact.js b/lib/ace/mode/edifact.js index 3e2d8e9894a..5718a0c5a9b 100644 --- a/lib/ace/mode/edifact.js +++ b/lib/ace/mode/edifact.js @@ -43,6 +43,7 @@ oop.inherits(Mode, TextMode); (function() { this.$id = "ace/mode/edifact"; + this.snippetFileId = "ace/snippets/edifact"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/erlang.js b/lib/ace/mode/erlang.js index 7ab9c026e6c..86644ba54ec 100644 --- a/lib/ace/mode/erlang.js +++ b/lib/ace/mode/erlang.js @@ -51,6 +51,7 @@ oop.inherits(Mode, TextMode); this.lineCommentStart = "%"; this.blockComment = null; this.$id = "ace/mode/erlang"; + this.snippetFileId = "ace/snippets/erlang"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/fsl.js b/lib/ace/mode/fsl.js index b3c6c8f3644..fe3a81ce3ea 100644 --- a/lib/ace/mode/fsl.js +++ b/lib/ace/mode/fsl.js @@ -52,6 +52,7 @@ oop.inherits(Mode, TextMode); this.blockComment = {start: "/*", end: "*/"}; // Extra logic goes here. this.$id = "ace/mode/fsl"; + this.snippetFileId = "ace/snippets/fsl"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/gobstones.js b/lib/ace/mode/gobstones.js index 1daf6424b0b..3fb16d9cc7e 100644 --- a/lib/ace/mode/gobstones.js +++ b/lib/ace/mode/gobstones.js @@ -19,6 +19,7 @@ oop.inherits(Mode, JavaScriptMode); }; this.$id = "ace/mode/gobstones"; + this.snippetFileId = "ace/snippets/gobstones"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/graphqlschema.js b/lib/ace/mode/graphqlschema.js index a23fd32df14..07804b00146 100644 --- a/lib/ace/mode/graphqlschema.js +++ b/lib/ace/mode/graphqlschema.js @@ -45,6 +45,7 @@ oop.inherits(Mode, TextMode); (function() { this.lineCommentStart = "#"; this.$id = "ace/mode/graphqlschema"; + this.snippetFileId = "ace/snippets/graphqlschema"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/haml.js b/lib/ace/mode/haml.js index bce4e1e9b67..514a8fda96b 100644 --- a/lib/ace/mode/haml.js +++ b/lib/ace/mode/haml.js @@ -56,6 +56,7 @@ oop.inherits(Mode, TextMode); this.lineCommentStart = "//"; this.$id = "ace/mode/haml"; + this.snippetFileId = "ace/snippets/haml"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/haskell.js b/lib/ace/mode/haskell.js index 1a06441734b..d7765ab10ed 100644 --- a/lib/ace/mode/haskell.js +++ b/lib/ace/mode/haskell.js @@ -57,6 +57,7 @@ oop.inherits(Mode, TextMode); this.lineCommentStart = "--"; this.blockComment = null; this.$id = "ace/mode/haskell"; + this.snippetFileId = "ace/snippets/haskell"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/html.js b/lib/ace/mode/html.js index a74ee3ded0f..9dd65b58d7e 100644 --- a/lib/ace/mode/html.js +++ b/lib/ace/mode/html.js @@ -100,6 +100,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/html"; + this.snippetFileId = "ace/snippets/html"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/io.js b/lib/ace/mode/io.js index fd1ecf85ddf..2cbeb723bc0 100644 --- a/lib/ace/mode/io.js +++ b/lib/ace/mode/io.js @@ -52,6 +52,7 @@ oop.inherits(Mode, TextMode); this.blockComment = {start: "/*", end: "*/"}; // Extra logic goes here. this.$id = "ace/mode/io"; + this.snippetFileId = "ace/snippets/io"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/java.js b/lib/ace/mode/java.js index 78b914043f0..da3599b50a4 100644 --- a/lib/ace/mode/java.js +++ b/lib/ace/mode/java.js @@ -20,6 +20,7 @@ oop.inherits(Mode, JavaScriptMode); }; this.$id = "ace/mode/java"; + this.snippetFileId = "ace/snippets/java"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/javascript.js b/lib/ace/mode/javascript.js index 509c271cb32..5de11877c27 100644 --- a/lib/ace/mode/javascript.js +++ b/lib/ace/mode/javascript.js @@ -110,6 +110,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/javascript"; + this.snippetFileId = "ace/snippets/javascript"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/json.js b/lib/ace/mode/json.js index cfb00daba7d..ccfca1f6abe 100644 --- a/lib/ace/mode/json.js +++ b/lib/ace/mode/json.js @@ -49,6 +49,9 @@ oop.inherits(Mode, TextMode); (function() { + this.lineCommentStart = "//"; + this.blockComment = {start: "/*", end: "*/"}; + this.getNextLineIndent = function(state, line, tab) { var indent = this.$getIndent(line); diff --git a/lib/ace/mode/jsoniq.js b/lib/ace/mode/jsoniq.js index 64dc9541f62..d160b314ce7 100644 --- a/lib/ace/mode/jsoniq.js +++ b/lib/ace/mode/jsoniq.js @@ -197,6 +197,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/jsoniq"; + this.snippetFileId = "ace/snippets/jsoniq"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/jsp.js b/lib/ace/mode/jsp.js index c1cb02548c8..00d69db31cc 100644 --- a/lib/ace/mode/jsp.js +++ b/lib/ace/mode/jsp.js @@ -49,6 +49,7 @@ oop.inherits(Mode, TextMode); (function() { this.$id = "ace/mode/jsp"; + this.snippetFileId = "ace/snippets/jsp"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/liquid.js b/lib/ace/mode/liquid.js index 5284d7f447d..8003e0c00d2 100644 --- a/lib/ace/mode/liquid.js +++ b/lib/ace/mode/liquid.js @@ -81,6 +81,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/liquid"; + this.snippetFileId = "ace/snippets/liquid"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/lsl.js b/lib/ace/mode/lsl.js index 14a67244ce8..f55a9dfdf9a 100644 --- a/lib/ace/mode/lsl.js +++ b/lib/ace/mode/lsl.js @@ -86,6 +86,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/lsl"; + this.snippetFileId = "ace/snippets/lsl"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/lua.js b/lib/ace/mode/lua.js index 752ce69dd6c..32faf8e6b39 100644 --- a/lib/ace/mode/lua.js +++ b/lib/ace/mode/lua.js @@ -174,6 +174,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/lua"; + this.snippetFileId = "ace/snippets/lua"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/makefile.js b/lib/ace/mode/makefile.js index df599327993..0ca274631cc 100644 --- a/lib/ace/mode/makefile.js +++ b/lib/ace/mode/makefile.js @@ -53,6 +53,7 @@ oop.inherits(Mode, TextMode); this.$indentWithTabs = true; this.$id = "ace/mode/makefile"; + this.snippetFileId = "ace/snippets/makefile"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/markdown.js b/lib/ace/mode/markdown.js index f6c73d2ce03..b99dca87550 100644 --- a/lib/ace/mode/markdown.js +++ b/lib/ace/mode/markdown.js @@ -75,6 +75,7 @@ oop.inherits(Mode, TextMode); } }; this.$id = "ace/mode/markdown"; + this.snippetFileId = "ace/snippets/markdown"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/maze.js b/lib/ace/mode/maze.js index a23631f89be..f97b2a8ad94 100644 --- a/lib/ace/mode/maze.js +++ b/lib/ace/mode/maze.js @@ -47,6 +47,7 @@ oop.inherits(Mode, TextMode); (function() { this.lineCommentStart = "//"; this.$id = "ace/mode/maze"; + this.snippetFileId = "ace/snippets/maze"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/perl.js b/lib/ace/mode/perl.js index 01778a7cf49..1b591287d7e 100644 --- a/lib/ace/mode/perl.js +++ b/lib/ace/mode/perl.js @@ -84,6 +84,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/perl"; + this.snippetFileId = "ace/snippets/perl"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/php.js b/lib/ace/mode/php.js index 48f70eb6975..edcbf0a507b 100644 --- a/lib/ace/mode/php.js +++ b/lib/ace/mode/php.js @@ -149,6 +149,7 @@ oop.inherits(Mode, HtmlMode); }; this.$id = "ace/mode/php"; + this.snippetFileId = "ace/snippets/php"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/python.js b/lib/ace/mode/python.js index 86cabedcdf2..c5cbfac31a1 100644 --- a/lib/ace/mode/python.js +++ b/lib/ace/mode/python.js @@ -108,6 +108,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/python"; + this.snippetFileId = "ace/snippets/python"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/r.js b/lib/ace/mode/r.js index 8aa2a7f6f39..afe4cc2b767 100644 --- a/lib/ace/mode/r.js +++ b/lib/ace/mode/r.js @@ -138,6 +138,7 @@ define(function(require, exports, module) { return false; };*/ this.$id = "ace/mode/r"; + this.snippetFileId = "ace/snippets/r"; }).call(Mode.prototype); exports.Mode = Mode; }); diff --git a/lib/ace/mode/razor.js b/lib/ace/mode/razor.js index d13c58e6408..b27ef26bbcd 100644 --- a/lib/ace/mode/razor.js +++ b/lib/ace/mode/razor.js @@ -27,6 +27,7 @@ oop.inherits(Mode, HtmlMode); }; this.$id = "ace/mode/razor"; + this.snippetFileId = "ace/snippets/razor"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/rst.js b/lib/ace/mode/rst.js index bde43b17569..bb76e9265c1 100644 --- a/lib/ace/mode/rst.js +++ b/lib/ace/mode/rst.js @@ -44,6 +44,7 @@ oop.inherits(Mode, TextMode); this.type = "text"; this.$id = "ace/mode/rst"; + this.snippetFileId = "ace/snippets/rst"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/ruby.js b/lib/ace/mode/ruby.js index b1af827b244..7a0ac99cde0 100644 --- a/lib/ace/mode/ruby.js +++ b/lib/ace/mode/ruby.js @@ -94,6 +94,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/ruby"; + this.snippetFileId = "ace/snippets/ruby"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/sh.js b/lib/ace/mode/sh.js index 92195657cd6..44dcbeb266e 100644 --- a/lib/ace/mode/sh.js +++ b/lib/ace/mode/sh.js @@ -110,6 +110,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/sh"; + this.snippetFileId = "ace/snippets/sh"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/snippets.js b/lib/ace/mode/snippets.js index 493fc4b0cc2..7ac885285b4 100644 --- a/lib/ace/mode/snippets.js +++ b/lib/ace/mode/snippets.js @@ -107,6 +107,7 @@ oop.inherits(Mode, TextMode); this.$indentWithTabs = true; this.lineCommentStart = "#"; this.$id = "ace/mode/snippets"; + this.snippetFileId = "ace/snippets/snippets"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/sql.js b/lib/ace/mode/sql.js index 3f267c5c860..f0cf0f7bcbb 100644 --- a/lib/ace/mode/sql.js +++ b/lib/ace/mode/sql.js @@ -46,6 +46,7 @@ oop.inherits(Mode, TextMode); this.lineCommentStart = "--"; this.$id = "ace/mode/sql"; + this.snippetFileId = "ace/snippets/sql"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/sqlserver.js b/lib/ace/mode/sqlserver.js index 69e4ffd8e3c..8aa48d9fe85 100644 --- a/lib/ace/mode/sqlserver.js +++ b/lib/ace/mode/sqlserver.js @@ -54,7 +54,8 @@ oop.inherits(Mode, TextMode); return session.$mode.$highlightRules.completions; }; - this.$id = "ace/mode/sql"; + this.$id = "ace/mode/sqlserver"; + this.snippetFileId = "ace/snippets/sqlserver"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/tcl.js b/lib/ace/mode/tcl.js index a7b0e6dd297..602ba35644d 100644 --- a/lib/ace/mode/tcl.js +++ b/lib/ace/mode/tcl.js @@ -79,6 +79,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/tcl"; + this.snippetFileId = "ace/snippets/tcl"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/tex.js b/lib/ace/mode/tex.js index aad0776314b..daa6df02719 100644 --- a/lib/ace/mode/tex.js +++ b/lib/ace/mode/tex.js @@ -64,6 +64,7 @@ oop.inherits(Mode, TextMode); return false; }; this.$id = "ace/mode/tex"; + this.snippetFileId = "ace/snippets/tex"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/textile.js b/lib/ace/mode/textile.js index 8419c409933..9587cd6d3cc 100644 --- a/lib/ace/mode/textile.js +++ b/lib/ace/mode/textile.js @@ -61,6 +61,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/textile"; + this.snippetFileId = "ace/snippets/textile"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/vala.js b/lib/ace/mode/vala.js index f3950b8b3a1..2a018d78713 100644 --- a/lib/ace/mode/vala.js +++ b/lib/ace/mode/vala.js @@ -99,6 +99,7 @@ oop.inherits(Mode, TextMode); // Extra logic goes here. this.$id = "ace/mode/vala"; + this.snippetFileId = "ace/snippets/vala"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/velocity.js b/lib/ace/mode/velocity.js index 94cbd388dc6..01a6335c562 100644 --- a/lib/ace/mode/velocity.js +++ b/lib/ace/mode/velocity.js @@ -52,6 +52,7 @@ oop.inherits(Mode, HtmlMode); this.lineCommentStart = "##"; this.blockComment = {start: "#*", end: "*#"}; this.$id = "ace/mode/velocity"; + this.snippetFileId = "ace/snippets/velocity"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/wollok.js b/lib/ace/mode/wollok.js index c9a33217212..dcc4aacb356 100644 --- a/lib/ace/mode/wollok.js +++ b/lib/ace/mode/wollok.js @@ -18,6 +18,7 @@ oop.inherits(Mode, JavaScriptMode); }; this.$id = "ace/mode/wollok"; + this.snippetFileId = "ace/snippets/wollok"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/xquery.js b/lib/ace/mode/xquery.js index 024a5c6a198..840a4c31d21 100644 --- a/lib/ace/mode/xquery.js +++ b/lib/ace/mode/xquery.js @@ -210,6 +210,7 @@ oop.inherits(Mode, TextMode); }; this.$id = "ace/mode/xquery"; + this.snippetFileId = "ace/snippets/xquery"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/snippets/_.snippets b/lib/ace/snippets/_.snippets deleted file mode 100644 index d553449d02c..00000000000 --- a/lib/ace/snippets/_.snippets +++ /dev/null @@ -1,240 +0,0 @@ -# Global snippets - -# (c) holds no legal value ;) -snippet c) - Copyright `&enc[:2] == "utf" ? "©" : "(c)"` `strftime("%Y")` ${1:`g:snips_author`}. All Rights Reserved.${2} -snippet date - `strftime("%Y-%m-%d")` -snippet ddate - `strftime("%B %d, %Y")` -snippet time - `strftime("%H:%M")` -snippet lorem - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -snippet GPL2 - ${1:One line to give the program's name and a brief description.} - Copyright (C) `strftime("%Y")` ${2:copyright holder} - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ${3} -snippet LGPL2 - ${1:One line to give the program's name and a brief description.} - Copyright (C) `strftime("%Y")` ${2:copyright holder} - - This library is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ${3} -snippet GPL3 - ${1:one line to give the program's name and a brief description.} - Copyright (C) `strftime("%Y")` ${2:copyright holder} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - ${3} -snippet LGPL3 - ${1:One line to give the program's name and a brief description.} - Copyright (C) `strftime("%Y")` ${2:copyright holder} - - This library is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ${3} -snippet BSD2 - ${1:one line to give the program's name and a brief description} - Copyright (C) `strftime("%Y")` ${2:copyright holder} - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY $2 ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL $2 BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - The views and conclusions contained in the software and documentation - are those of the authors and should not be interpreted as representing - official policies, either expressedor implied, of $2. - - ${4} -snippet BSD3 - ${1:one line to give the program's name and a brief description} - Copyright (C) `strftime("%Y")` ${2:copyright holder} - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the ${3:organization} nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY $2 ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL $2 BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ${4} -snippet BSD4 - ${1:one line to give the program's name and a brief description} - Copyright (C) `strftime("%Y")` ${2:copyright holder} - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by the ${3:organization}. - 4. Neither the name of the $3 nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY $2 ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL $2 BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ${4} -snippet MIT - ${1:one line to give the program's name and a brief description} - Copyright (C) `strftime("%Y")` ${2:copyright holder} - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - ${3} -snippet APACHE - ${1:one line to give the program's name and a brief description} - Copyright `strftime("%Y")` ${2:copyright holder} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - ${3} -snippet BEERWARE - ${2:one line to give the program's name and a brief description} - Copyright `strftime("%Y")` ${3:copyright holder} - - Licensed under the "THE BEER-WARE LICENSE" (Revision 42): - ${1:`g:snips_author`} wrote this file. As long as you retain this notice you - can do whatever you want with this stuff. If we meet some day, and you think - this stuff is worth it, you can buy me a beer or coffee in return - - ${4} - -snippet WTFPL - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 - - Copyright `strftime("%Y")` ${1:copyright holder} - - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION diff --git a/lib/ace/snippets/dummy.js b/lib/ace/snippets/dummy.js deleted file mode 100644 index 359d9103986..00000000000 --- a/lib/ace/snippets/dummy.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./.snippets"); -exports.scope = ""; - -}); diff --git a/lib/ace/snippets/dummy_syntax.js b/lib/ace/snippets/dummy_syntax.js deleted file mode 100644 index 359d9103986..00000000000 --- a/lib/ace/snippets/dummy_syntax.js +++ /dev/null @@ -1,7 +0,0 @@ -define(function(require, exports, module) { -"use strict"; - -exports.snippetText = require("../requirejs/text!./.snippets"); -exports.scope = ""; - -}); From cca3f5fbc6abf98660428a728ea430bcdfcd58c8 Mon Sep 17 00:00:00 2001 From: Krkyasharyan Date: Sun, 29 Mar 2020 15:20:35 +0400 Subject: [PATCH 0315/1293] [vim] fix autoIndent command --- lib/ace/commands/default_commands.js | 7 +++++ lib/ace/editor.js | 45 ++++++++++++++++++++++++++++ lib/ace/keyboard/vim.js | 5 ++-- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index a337682f946..fa6276ff64c 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -742,6 +742,13 @@ exports.commands = [{ exec: function(editor) { editor.toLowerCase(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" +}, { + name: "autoindent", + description: "Auto Indent", + bindKey: bindKey(null, null), + exec: function(editor) { editor.autoIndent(); }, + multiSelectAction: "forEachLine", + scrollIntoView: "animate" }, { name: "expandtoline", description: "Expand to line", diff --git a/lib/ace/editor.js b/lib/ace/editor.js index ac7698ba05d..d731396222b 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -1084,6 +1084,51 @@ Editor.$uid = 0; } }; + this.autoIndent = function () { + var session = this.session; + var mode = session.getMode(); + + var startRow, endRow; + if (this.selection.isEmpty()) { + startRow = 0; + endRow = session.doc.getLength() - 1; + } else { + var selectedRange = this.getSelectionRange(); + + startRow = selectedRange.start.row; + endRow = selectedRange.end.row; + } + + var prevLineState = ""; + var prevLine = ""; + var lineIndent = ""; + var line, currIndent, range; + var tab = session.getTabString(); + + for (var row = startRow; row <= endRow; row++) { + if (row > 0) { + prevLineState = session.getState(row - 1); + prevLine = session.getLine(row - 1); + lineIndent = mode.getNextLineIndent(prevLineState, prevLine, tab); + } + + line = session.getLine(row); + currIndent = mode.$getIndent(line); + if (lineIndent !== currIndent) { + if (currIndent.length > 0) { + range = new Range(row, 0, row, currIndent.length); + session.remove(range); + } + if (lineIndent.length > 0) { + session.insert({row: row, column: 0}, lineIndent); + } + } + + mode.autoOutdent(prevLineState, session, row); + } + }; + + this.onTextInput = function(text, composition) { if (!composition) return this.keyBinding.onTextInput(text); diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index e10cf0d4fdd..8e87d78c5ce 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -635,8 +635,9 @@ define(function(require, exports, module) { this.getMode = function() { return { name : this.getOption("mode") }; }; - this.execCommand = function() { - + this.execCommand = function(name) { + if (name == "indentAuto") this.ace.execCommand("autoindent"); + else console.log(name + " is not implemented"); }; }).call(CodeMirror.prototype); function toAcePos(cmPos) { From 0991056186cdaa721012cd1df01f9e1985bf3c67 Mon Sep 17 00:00:00 2001 From: Krkyasharyan Date: Sun, 29 Mar 2020 19:29:20 +0400 Subject: [PATCH 0316/1293] fix debug code breaking tests --- lib/ace/keyboard/textinput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 43e595b22e6..a816cf1d59d 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -45,7 +45,7 @@ var KEYS = require("../lib/keys"); var MODS = KEYS.KEY_MODS; var isIOS = useragent.isIOS; var valueResetRegex = isIOS ? /\s/ : /\n/; -var isMobile = useragent.isMobile || 1; +var isMobile = useragent.isMobile; var TextInput = function(parentNode, host) { var text = dom.createElement("textarea"); From 00426593da51b36f56eee60f4edc5fc5752234e2 Mon Sep 17 00:00:00 2001 From: Krkyasharyan Date: Sun, 29 Mar 2020 19:30:03 +0400 Subject: [PATCH 0317/1293] fix ime in hidpi mode --- lib/ace/css/editor.css | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ace/css/editor.css b/lib/ace/css/editor.css index 677ec894522..e290c568e81 100644 --- a/lib/ace/css/editor.css +++ b/lib/ace/css/editor.css @@ -29,6 +29,7 @@ styles.join("\n") .ace_editor { position: relative; overflow: hidden; + padding: 0; font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace; direction: ltr; text-align: left; From a7897dd13068a82e4f8c4071ea21eb341b02a836 Mon Sep 17 00:00:00 2001 From: Krkyasharyan Date: Sun, 29 Mar 2020 20:42:35 +0400 Subject: [PATCH 0318/1293] fix snippets test --- lib/ace/css/editor.css | 2 +- lib/ace/snippets_test.js | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/ace/css/editor.css b/lib/ace/css/editor.css index e290c568e81..cf65fb83fbb 100644 --- a/lib/ace/css/editor.css +++ b/lib/ace/css/editor.css @@ -29,7 +29,7 @@ styles.join("\n") .ace_editor { position: relative; overflow: hidden; - padding: 0; + padding: 0; font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace; direction: ltr; text-align: left; diff --git a/lib/ace/snippets_test.js b/lib/ace/snippets_test.js index 2845554631f..2d32f4ff142 100644 --- a/lib/ace/snippets_test.js +++ b/lib/ace/snippets_test.js @@ -43,12 +43,17 @@ require("./ext/language_tools"); var snippetManager = require("./snippets").snippetManager; var assert = require("./test/assertions"); +var config = require("./config"); +var loadModule = config.loadModule; module.exports = { setUp : function(next) { this.editor = new Editor(new MockRenderer()); next(); }, + tearDown: function() { + config.loadModule = loadModule; + }, "test: textmate style format strings" : function() { snippetManager.tmStrFormat("hello", { @@ -100,7 +105,7 @@ module.exports = { assert.equal(tokens[1].flag, "g"); }, "test: register snippets in json format": function() { - require("./config").loadModule = function() {}; + config.loadModule = function() {}; this.editor.setOption("enableSnippets", true); this.editor.session.setMode(new JavascriptMode()); From 26df413fc4ff8b219e421076f9f901669b619d1a Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 1 Apr 2020 15:42:11 +0400 Subject: [PATCH 0319/1293] release v1.4.9 --- ChangeLog.txt | 5 +++++ build | 2 +- lib/ace/config.js | 2 +- lib/ace/editor.js | 2 +- package.json | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 824f8750e12..32702197942 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,8 @@ +2020.04.01 Version 1.4.9 +* added option to disable autoindent +* added new language modes +* fixed backspace not working with some mobile keyboards + 2020.01.14 Version 1.4.8 * highlight both matched braces, and highlight unmatched brace in red * improve snippet manager diff --git a/build b/build index a279fe5367e..bd7ce25eaba 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit a279fe5367ed15a2c2f3fca96fccd1fe0681a547 +Subproject commit bd7ce25eaba22b54e3f7e5f46b8596bb90d4a341 diff --git a/lib/ace/config.js b/lib/ace/config.js index 4500e37357d..a5b1ceca964 100644 --- a/lib/ace/config.js +++ b/lib/ace/config.js @@ -220,6 +220,6 @@ function deHyphenate(str) { return str.replace(/-(.)/g, function(m, m1) { return m1.toUpperCase(); }); } -exports.version = "1.4.8"; +exports.version = "1.4.9"; }); diff --git a/lib/ace/editor.js b/lib/ace/editor.js index d731396222b..edbe7cb05b1 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -2908,7 +2908,7 @@ config.defineOptions(Editor.prototype, "editor", { set: function(message) { if (!this.$updatePlaceholder) { this.$updatePlaceholder = function() { - var value = this.renderer.$composition || this.getValue(); + var value = this.session && (this.renderer.$composition || this.getValue()); if (value && this.renderer.placeholderNode) { this.renderer.off("afterRender", this.$updatePlaceholder); dom.removeCssClass(this.container, "ace_hasPlaceholder"); diff --git a/package.json b/package.json index 0b4788b80d4..11089e90963 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.4.8", + "version": "1.4.9", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" From 829245c2432c10223d5df3bf5dd83cd06038f24e Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 3 Apr 2020 01:51:24 +0400 Subject: [PATCH 0320/1293] always use on/off instead of old add/removeEventListener --- lib/ace/anchor.js | 2 +- lib/ace/commands/command_manager.js | 2 +- .../commands/incremental_search_commands.js | 6 ++--- lib/ace/edit_session.js | 6 ++--- lib/ace/incremental_search.js | 23 ++++++++++--------- lib/ace/keyboard/emacs.js | 12 +++++----- lib/ace/layer/gutter.js | 2 +- lib/ace/lib/event_emitter.js | 4 ++-- lib/ace/mouse/default_gutter_handler.js | 2 +- lib/ace/mouse/dragdrop_handler.js | 2 +- lib/ace/placeholder.js | 4 ++-- 11 files changed, 33 insertions(+), 32 deletions(-) diff --git a/lib/ace/anchor.js b/lib/ace/anchor.js index 39b78e0f2d9..5fdf1440836 100644 --- a/lib/ace/anchor.js +++ b/lib/ace/anchor.js @@ -187,7 +187,7 @@ var Anchor = exports.Anchor = function(doc, row, column) { * **/ this.detach = function() { - this.document.removeEventListener("change", this.$onChange); + this.document.off("change", this.$onChange); }; this.attach = function(doc) { this.document = doc || this.document; diff --git a/lib/ace/commands/command_manager.js b/lib/ace/commands/command_manager.js index a6fcb82c765..00b85b25d32 100644 --- a/lib/ace/commands/command_manager.js +++ b/lib/ace/commands/command_manager.js @@ -65,7 +65,7 @@ oop.inherits(CommandManager, MultiHashHandler); editor && editor._emit("changeStatus"); if (this.recording) { this.macro.pop(); - this.removeEventListener("exec", this.$addCommandToMacro); + this.off("exec", this.$addCommandToMacro); if (!this.macro.length) this.macro = this.oldMacro; diff --git a/lib/ace/commands/incremental_search_commands.js b/lib/ace/commands/incremental_search_commands.js index 1954866509e..7ae7ee40f99 100644 --- a/lib/ace/commands/incremental_search_commands.js +++ b/lib/ace/commands/incremental_search_commands.js @@ -174,7 +174,7 @@ oop.inherits(IncrementalSearchKeyboardHandler, HashHandler); this.attach = function(editor) { var iSearch = this.$iSearch; HashHandler.call(this, exports.iSearchCommands, editor.commands.platform); - this.$commandExecHandler = editor.commands.addEventListener('exec', function(e) { + this.$commandExecHandler = editor.commands.on('exec', function(e) { if (!e.command.isIncrementalSearchCommand) return iSearch.deactivate(); e.stopPropagation(); @@ -189,7 +189,7 @@ oop.inherits(IncrementalSearchKeyboardHandler, HashHandler); this.detach = function(editor) { if (!this.$commandExecHandler) return; - editor.commands.removeEventListener('exec', this.$commandExecHandler); + editor.commands.off('exec', this.$commandExecHandler); delete this.$commandExecHandler; }; @@ -198,7 +198,7 @@ oop.inherits(IncrementalSearchKeyboardHandler, HashHandler); if (((hashId === 1/*ctrl*/ || hashId === 8/*command*/) && key === 'v') || (hashId === 1/*ctrl*/ && key === 'y')) return null; var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode); - if (cmd.command) { return cmd; } + if (cmd && cmd.command) { return cmd; } if (hashId == -1) { var extendCmd = this.commands.extendSearchTerm; if (extendCmd) { return {command: extendCmd, args: key}; } diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index e7a122c3e29..6f5569e731d 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -908,15 +908,15 @@ EditSession.$uid = 0; var tokenizer = mode.getTokenizer(); - if(tokenizer.addEventListener !== undefined) { + if(tokenizer.on !== undefined) { var onReloadTokenizer = this.onReloadTokenizer.bind(this); - tokenizer.addEventListener("update", onReloadTokenizer); + tokenizer.on("update", onReloadTokenizer); } if (!this.bgTokenizer) { this.bgTokenizer = new BackgroundTokenizer(tokenizer); var _self = this; - this.bgTokenizer.addEventListener("update", function(e) { + this.bgTokenizer.on("update", function(e) { _self._signal("tokenizerUpdate", e); }); } else { diff --git a/lib/ace/incremental_search.js b/lib/ace/incremental_search.js index b4c27a929d2..4b898ea0187 100644 --- a/lib/ace/incremental_search.js +++ b/lib/ace/incremental_search.js @@ -94,28 +94,29 @@ function objectToRegExp(obj) { (function() { - this.activate = function(ed, backwards) { - this.$editor = ed; - this.$startPos = this.$currentPos = ed.getCursorPosition(); + this.activate = function(editor, backwards) { + this.$editor = editor; + this.$startPos = this.$currentPos = editor.getCursorPosition(); this.$options.needle = ''; this.$options.backwards = backwards; - ed.keyBinding.addKeyboardHandler(this.$keyboardHandler); + editor.keyBinding.addKeyboardHandler(this.$keyboardHandler); // we need to completely intercept paste, just registering an event handler does not work - this.$originalEditorOnPaste = ed.onPaste; ed.onPaste = this.onPaste.bind(this); - this.$mousedownHandler = ed.addEventListener('mousedown', this.onMouseDown.bind(this)); - this.selectionFix(ed); + this.$originalEditorOnPaste = editor.onPaste; + editor.onPaste = this.onPaste.bind(this); + this.$mousedownHandler = editor.addEventListener('mousedown', this.onMouseDown.bind(this)); + this.selectionFix(editor); this.statusMessage(true); }; this.deactivate = function(reset) { this.cancelSearch(reset); - var ed = this.$editor; - ed.keyBinding.removeKeyboardHandler(this.$keyboardHandler); + var editor = this.$editor; + editor.keyBinding.removeKeyboardHandler(this.$keyboardHandler); if (this.$mousedownHandler) { - ed.removeEventListener('mousedown', this.$mousedownHandler); + editor.off('mousedown', this.$mousedownHandler); delete this.$mousedownHandler; } - ed.onPaste = this.$originalEditorOnPaste; + editor.onPaste = this.$originalEditorOnPaste; this.message(''); }; diff --git a/lib/ace/keyboard/emacs.js b/lib/ace/keyboard/emacs.js index 988ec7cce25..41421b1ef3a 100644 --- a/lib/ace/keyboard/emacs.js +++ b/lib/ace/keyboard/emacs.js @@ -135,20 +135,20 @@ exports.handler.attach = function(editor) { editor.commands.addCommands(commands); exports.handler.platform = editor.commands.platform; editor.$emacsModeHandler = this; - editor.addEventListener('copy', this.onCopy); - editor.addEventListener('paste', this.onPaste); + editor.on('copy', this.onCopy); + editor.on('paste', this.onPaste); }; exports.handler.detach = function(editor) { editor.renderer.$blockCursor = false; editor.session.$selectLongWords = $formerLongWords; editor.session.$useEmacsStyleLineStart = $formerLineStart; - editor.removeEventListener("click", $resetMarkMode); - editor.removeEventListener("changeSession", $kbSessionChange); + editor.off("click", $resetMarkMode); + editor.off("changeSession", $kbSessionChange); editor.unsetStyle("emacs-mode"); editor.commands.removeCommands(commands); - editor.removeEventListener('copy', this.onCopy); - editor.removeEventListener('paste', this.onPaste); + editor.off('copy', this.onCopy); + editor.off('paste', this.onPaste); editor.$emacsModeHandler = null; }; diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js index e8563c0c1cf..0c17e0b5039 100644 --- a/lib/ace/layer/gutter.js +++ b/lib/ace/layer/gutter.js @@ -58,7 +58,7 @@ var Gutter = function(parentEl) { this.setSession = function(session) { if (this.session) - this.session.removeEventListener("change", this.$updateAnnotations); + this.session.off("change", this.$updateAnnotations); this.session = session; if (session) session.on("change", this.$updateAnnotations); diff --git a/lib/ace/lib/event_emitter.js b/lib/ace/lib/event_emitter.js index 228f6c844cc..6dea033a15b 100644 --- a/lib/ace/lib/event_emitter.js +++ b/lib/ace/lib/event_emitter.js @@ -78,8 +78,8 @@ EventEmitter._signal = function(eventName, e) { EventEmitter.once = function(eventName, callback) { var _self = this; - this.addEventListener(eventName, function newCallback() { - _self.removeEventListener(eventName, newCallback); + this.on(eventName, function newCallback() { + _self.off(eventName, newCallback); callback.apply(null, arguments); }); if (!callback) { diff --git a/lib/ace/mouse/default_gutter_handler.js b/lib/ace/mouse/default_gutter_handler.js index db35a5085bc..2ef41371c59 100644 --- a/lib/ace/mouse/default_gutter_handler.js +++ b/lib/ace/mouse/default_gutter_handler.js @@ -109,7 +109,7 @@ function GutterHandler(mouseHandler) { tooltip.hide(); tooltipAnnotation = null; editor._signal("hideGutterTooltip", tooltip); - editor.removeEventListener("mousewheel", hideTooltip); + editor.off("mousewheel", hideTooltip); } } diff --git a/lib/ace/mouse/dragdrop_handler.js b/lib/ace/mouse/dragdrop_handler.js index a8f2999ef2c..ee5d243c8f3 100644 --- a/lib/ace/mouse/dragdrop_handler.js +++ b/lib/ace/mouse/dragdrop_handler.js @@ -54,7 +54,7 @@ function DragdropHandler(mouseHandler) { exports.forEach(function(x) { mouseHandler[x] = this[x]; }, this); - editor.addEventListener("mousedown", this.onMouseDown.bind(mouseHandler)); + editor.on("mousedown", this.onMouseDown.bind(mouseHandler)); var mouseTarget = editor.container; diff --git a/lib/ace/placeholder.js b/lib/ace/placeholder.js index 88b96dd5687..96eb36bfc00 100644 --- a/lib/ace/placeholder.js +++ b/lib/ace/placeholder.js @@ -232,8 +232,8 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) this.detach = function() { this.session.removeMarker(this.pos && this.pos.markerId); this.hideOtherMarkers(); - this.doc.removeEventListener("change", this.$onUpdate); - this.session.selection.removeEventListener("changeCursor", this.$onCursorChange); + this.doc.off("change", this.$onUpdate); + this.session.selection.off("changeCursor", this.$onCursorChange); this.session.setUndoSelect(true); this.session = null; }; From 1e90e0533880755f605d646ffeb4480b3f725119 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 3 Apr 2020 01:51:58 +0400 Subject: [PATCH 0321/1293] cleanup Makefile.js --- Makefile.dryice.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 2d00848a4f3..5fc94bd974e 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -382,9 +382,6 @@ function buildAce(options, callback) { }); // snippets modeNames.forEach(function(name) { - if (snippetFiles.indexOf(name + ".js") == -1) - addSnippetFile(name); - buildSubmodule(options, { require: ["ace/snippets/" + name] }, "snippets/" + name, addCb()); @@ -605,18 +602,6 @@ function generateThemesModule(themes) { fs.writeFileSync(__dirname + '/lib/ace/ext/themelist_utils/themes.js', themelist, 'utf8'); } -function addSnippetFile(modeName) { - var snippetFilePath = ACE_HOME + "/lib/ace/snippets/" + modeName; - if (!fs.existsSync(snippetFilePath + ".js")) { - copy.file(ACE_HOME + "/tool/templates/snippets.js", snippetFilePath + ".js", function(t) { - return t.replace(/%modeName%/g, modeName); - }); - } - if (!fs.existsSync(snippetFilePath + ".snippets")) { - fs.writeFileSync(snippetFilePath + ".snippets", ""); - } -} - function compress(text) { var uglify = require("dryice").copy.filter.uglifyjs; uglify.options.mangle_toplevel = {except: ["ACE_NAMESPACE", "requirejs"]}; From d5ecf0693399bf969dceef2e19b68e8619aeef5d Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 3 Apr 2020 01:52:33 +0400 Subject: [PATCH 0322/1293] remove all listeners when destroying the editor --- lib/ace/edit_session.js | 2 + lib/ace/editor.js | 10 +++- lib/ace/ext/code_lens.js | 3 +- lib/ace/incremental_search.js | 2 +- lib/ace/keyboard/textinput.js | 41 ++++++++------- lib/ace/lib/event.js | 67 ++++++++++++++----------- lib/ace/lib/event_emitter.js | 4 +- lib/ace/mode/prisma.js | 2 +- lib/ace/mode/prisma_highlight_rules.js | 4 +- lib/ace/mouse/default_gutter_handler.js | 2 +- lib/ace/mouse/dragdrop_handler.js | 12 ++--- lib/ace/mouse/mouse_handler.js | 26 +++++----- lib/ace/mouse/touch_handler.js | 8 +-- lib/ace/multi_select.js | 6 +-- lib/ace/virtual_renderer.js | 8 +-- 15 files changed, 114 insertions(+), 83 deletions(-) diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 6f5569e731d..25b95427075 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -2402,6 +2402,8 @@ EditSession.$uid = 0; this.bgTokenizer = null; } this.$stopWorker(); + this.removeAllListeners(); + this.selection.detach(); }; this.isFullWidth = isFullWidth; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index edbe7cb05b1..5edea1ea8f8 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -71,6 +71,7 @@ var clipboard = require("./clipboard"); * @constructor **/ var Editor = function(renderer, session, options) { + this.$toDestroy = []; var container = renderer.getContainerElement(); this.container = container; this.renderer = renderer; @@ -2731,13 +2732,20 @@ Editor.$uid = 0; * Cleans up the entire editor. **/ this.destroy = function() { + if (this.$toDestroy) { + this.$toDestroy.forEach(function(el) { + el.destroy(); + }); + this.$toDestroy = null; + } this.renderer.destroy(); + this.textInput.destroy(); this._signal("destroy", this); if (this.session) this.session.destroy(); if (this._$emitInputEvent) this._$emitInputEvent.cancel(); - this.session = null; + this.removeAllListeners(); }; /** diff --git a/lib/ace/ext/code_lens.js b/lib/ace/ext/code_lens.js index 35c7ca3be99..0247a6e2bf9 100644 --- a/lib/ace/ext/code_lens.js +++ b/lib/ace/ext/code_lens.js @@ -31,6 +31,7 @@ define(function(require, exports, module) { "use strict"; var LineWidgets = require("../line_widgets").LineWidgets; +var event = require("../lib/event"); var lang = require("../lib/lang"); var dom = require("../lib/dom"); @@ -155,7 +156,7 @@ function attachToEditor(editor) { if (command) editor.execCommand(command.id, command.arguments); }; - editor.container.addEventListener("click", editor.$codeLensClickHandler); + event.addListener(editor.container, "click", editor.$codeLensClickHandler, editor); editor.$updateLenses = function() { var session = editor.session; if (!session) return; diff --git a/lib/ace/incremental_search.js b/lib/ace/incremental_search.js index 4b898ea0187..643fd6f8099 100644 --- a/lib/ace/incremental_search.js +++ b/lib/ace/incremental_search.js @@ -103,7 +103,7 @@ function objectToRegExp(obj) { // we need to completely intercept paste, just registering an event handler does not work this.$originalEditorOnPaste = editor.onPaste; editor.onPaste = this.onPaste.bind(this); - this.$mousedownHandler = editor.addEventListener('mousedown', this.onMouseDown.bind(this)); + this.$mousedownHandler = editor.on('mousedown', this.onMouseDown.bind(this)); this.selectionFix(editor); this.statusMessage(true); }; diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index a816cf1d59d..3ce3e3f6cf1 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -84,7 +84,7 @@ var TextInput = function(parentNode, host) { if (ignoreFocusEvents) return; host.onBlur(e); isFocused = false; - }); + }, host); event.addListener(text, "focus", function(e) { if (ignoreFocusEvents) return; isFocused = true; @@ -100,7 +100,7 @@ var TextInput = function(parentNode, host) { setTimeout(resetSelection); else resetSelection(); - }); + }, host); this.$focusScroll = false; this.focus = function() { if (tempStyle || HAS_FOCUS_ARGS || this.$focusScroll == "browser") @@ -427,14 +427,14 @@ var TextInput = function(parentNode, host) { } }; - event.addCommandKeyListener(text, host.onCommandKey.bind(host)); + event.addCommandKeyListener(text, host.onCommandKey.bind(host), host); - event.addListener(text, "select", onSelect); - event.addListener(text, "input", onInput); + event.addListener(text, "select", onSelect, host); + event.addListener(text, "input", onInput, host); - event.addListener(text, "cut", onCut); - event.addListener(text, "copy", onCopy); - event.addListener(text, "paste", onPaste); + event.addListener(text, "cut", onCut, host); + event.addListener(text, "copy", onCopy, host); + event.addListener(text, "paste", onPaste, host); // Opera has no clipboard events @@ -454,7 +454,7 @@ var TextInput = function(parentNode, host) { onCut(e); break; } - }); + }, host); } @@ -547,11 +547,11 @@ var TextInput = function(parentNode, host) { syncComposition(); } - event.addListener(text, "compositionstart", onCompositionStart); - event.addListener(text, "compositionupdate", onCompositionUpdate); - event.addListener(text, "keyup", onKeyup); - event.addListener(text, "keydown", syncComposition); - event.addListener(text, "compositionend", onCompositionEnd); + event.addListener(text, "compositionstart", onCompositionStart, host); + event.addListener(text, "compositionupdate", onCompositionUpdate, host); + event.addListener(text, "keyup", onKeyup, host); + event.addListener(text, "keydown", syncComposition, host); + event.addListener(text, "compositionend", onCompositionEnd, host); this.getElement = function() { return text; @@ -626,13 +626,13 @@ var TextInput = function(parentNode, host) { host.textInput.onContextMenu(e); onContextMenuClose(); }; - event.addListener(text, "mouseup", onContextMenu); + event.addListener(text, "mouseup", onContextMenu, host); event.addListener(text, "mousedown", function(e) { e.preventDefault(); onContextMenuClose(); - }); - event.addListener(host.renderer.scroller, "contextmenu", onContextMenu); - event.addListener(text, "contextmenu", onContextMenu); + }, host); + event.addListener(host.renderer.scroller, "contextmenu", onContextMenu, host); + event.addListener(text, "contextmenu", onContextMenu, host); if (isIOS) addIosSelectionHandler(parentNode, host, text); @@ -723,6 +723,11 @@ var TextInput = function(parentNode, host) { }); } + this.destroy = function() { + if (text.parentElement) + text.parentElement.removeChild(text); + host = text = parentNode = null; + }; }; exports.TextInput = TextInput; diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js index 8c0dbe008a7..3b0c8332d24 100644 --- a/lib/ace/lib/event.js +++ b/lib/ace/lib/event.js @@ -55,12 +55,24 @@ function getListenerOptions() { return activeListenerOptions; } -exports.addListener = function(elem, type, callback) { - return elem.addEventListener(type, callback, getListenerOptions()); +function EventListener(elem, type, callback) { + this.elem = elem; + this.type = type; + this.callback = callback; +} +EventListener.prototype.destroy = function() { + removeListener(this.elem, this.type, this.callback); + this.elem = this.type = this.callback = undefined; +}; + +var addListener = exports.addListener = function(elem, type, callback, destroyable) { + elem.addEventListener(type, callback, getListenerOptions()); + if (destroyable && destroyable.$toDestroy) + destroyable.$toDestroy.push(new EventListener(elem, type, callback)); }; -exports.removeListener = function(elem, type, callback) { - return elem.removeEventListener(type, callback, getListenerOptions()); +var removeListener = exports.removeListener = function(elem, type, callback) { + elem.removeEventListener(type, callback, getListenerOptions()); }; /* @@ -100,21 +112,21 @@ exports.capture = function(el, eventHandler, releaseCaptureHandler) { eventHandler && eventHandler(e); releaseCaptureHandler && releaseCaptureHandler(e); - exports.removeListener(document, "mousemove", eventHandler, true); - exports.removeListener(document, "mouseup", onMouseUp, true); - exports.removeListener(document, "dragstart", onMouseUp, true); + removeListener(document, "mousemove", eventHandler); + removeListener(document, "mouseup", onMouseUp); + removeListener(document, "dragstart", onMouseUp); } - exports.addListener(document, "mousemove", eventHandler, true); - exports.addListener(document, "mouseup", onMouseUp, true); - exports.addListener(document, "dragstart", onMouseUp, true); + addListener(document, "mousemove", eventHandler); + addListener(document, "mouseup", onMouseUp); + addListener(document, "dragstart", onMouseUp); return onMouseUp; }; -exports.addMouseWheelListener = function(el, callback) { +exports.addMouseWheelListener = function(el, callback, destroyable) { if ("onmousewheel" in el) { - exports.addListener(el, "mousewheel", function(e) { + addListener(el, "mousewheel", function(e) { var factor = 8; if (e.wheelDeltaX !== undefined) { e.wheelX = -e.wheelDeltaX / factor; @@ -124,9 +136,9 @@ exports.addMouseWheelListener = function(el, callback) { e.wheelY = -e.wheelDelta / factor; } callback(e); - }); + }, destroyable); } else if ("onwheel" in el) { - exports.addListener(el, "wheel", function(e) { + addListener(el, "wheel", function(e) { var factor = 0.35; switch (e.deltaMode) { case e.DOM_DELTA_PIXEL: @@ -141,9 +153,9 @@ exports.addMouseWheelListener = function(el, callback) { } callback(e); - }); + }, destroyable); } else { - exports.addListener(el, "DOMMouseScroll", function(e) { + addListener(el, "DOMMouseScroll", function(e) { if (e.axis && e.axis == e.HORIZONTAL_AXIS) { e.wheelX = (e.detail || 0) * 5; e.wheelY = 0; @@ -152,11 +164,11 @@ exports.addMouseWheelListener = function(el, callback) { e.wheelY = (e.detail || 0) * 5; } callback(e); - }); + }, destroyable); } }; -exports.addMultiMouseDownListener = function(elements, timeouts, eventHandler, callbackName) { +exports.addMultiMouseDownListener = function(elements, timeouts, eventHandler, callbackName, destroyable) { var clicks = 0; var startX, startY, timer; var eventNames = { @@ -201,7 +213,7 @@ exports.addMultiMouseDownListener = function(elements, timeouts, eventHandler, c if (!Array.isArray(elements)) elements = [elements]; elements.forEach(function(el) { - exports.addListener(el, "mousedown", onMousedown); + addListener(el, "mousedown", onMousedown, destroyable); }); }; @@ -270,8 +282,7 @@ function normalizeCommandKeys(callback, e, keyCode) { } -exports.addCommandKeyListener = function(el, callback) { - var addListener = exports.addListener; +exports.addCommandKeyListener = function(el, callback, destroyable) { if (useragent.isOldGecko || (useragent.isOpera && !("KeyboardEvent" in window))) { // Old versions of Gecko aka. Firefox < 4.0 didn't repeat the keydown // event if the user pressed the key for a longer time. Instead, the @@ -282,10 +293,10 @@ exports.addCommandKeyListener = function(el, callback) { var lastKeyDownKeyCode = null; addListener(el, "keydown", function(e) { lastKeyDownKeyCode = e.keyCode; - }); + }, destroyable); addListener(el, "keypress", function(e) { return normalizeCommandKeys(callback, e, lastKeyDownKeyCode); - }); + }, destroyable); } else { var lastDefaultPrevented = null; @@ -294,18 +305,18 @@ exports.addCommandKeyListener = function(el, callback) { var result = normalizeCommandKeys(callback, e, e.keyCode); lastDefaultPrevented = e.defaultPrevented; return result; - }); + }, destroyable); addListener(el, "keypress", function(e) { if (lastDefaultPrevented && (e.ctrlKey || e.altKey || e.shiftKey || e.metaKey)) { exports.stopEvent(e); lastDefaultPrevented = null; } - }); + }, destroyable); addListener(el, "keyup", function(e) { pressedKeys[e.keyCode] = null; - }); + }, destroyable); if (!pressedKeys) { resetPressedKeys(); @@ -326,12 +337,12 @@ if (typeof window == "object" && window.postMessage && !useragent.isOldIE) { var listener = function(e) { if (e.data == messageName) { exports.stopPropagation(e); - exports.removeListener(win, "message", listener); + removeListener(win, "message", listener); callback(); } }; - exports.addListener(win, "message", listener); + addListener(win, "message", listener); win.postMessage(messageName, "*"); }; } diff --git a/lib/ace/lib/event_emitter.js b/lib/ace/lib/event_emitter.js index 6dea033a15b..422e228bd0c 100644 --- a/lib/ace/lib/event_emitter.js +++ b/lib/ace/lib/event_emitter.js @@ -152,7 +152,9 @@ EventEmitter.removeEventListener = function(eventName, callback) { }; EventEmitter.removeAllListeners = function(eventName) { - if (this._eventRegistry) this._eventRegistry[eventName] = []; + if (!eventName) this._eventRegistry = this._defaultHandlers = undefined; + if (this._eventRegistry) this._eventRegistry[eventName] = undefined; + if (this._defaultHandlers) this._defaultHandlers[eventName] = undefined; }; exports.EventEmitter = EventEmitter; diff --git a/lib/ace/mode/prisma.js b/lib/ace/mode/prisma.js index 5fd8b766471..f38b3865c0d 100644 --- a/lib/ace/mode/prisma.js +++ b/lib/ace/mode/prisma.js @@ -51,7 +51,7 @@ oop.inherits(Mode, TextMode); this.lineCommentStart = "//"; // this.blockComment = {start: ""/*"", end: ""*/""}; // Extra logic goes here. - this.$id = "ace/mode/prisma" + this.$id = "ace/mode/prisma"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/prisma_highlight_rules.js b/lib/ace/mode/prisma_highlight_rules.js index 15d68b42f6a..c1b61964471 100644 --- a/lib/ace/mode/prisma_highlight_rules.js +++ b/lib/ace/mode/prisma_highlight_rules.js @@ -341,7 +341,7 @@ var PrismaHighlightRules = function() { defaultToken: "source.tag.embedded.source.prisma" }] }] - } + }; this.normalizeRules(); }; @@ -349,7 +349,7 @@ var PrismaHighlightRules = function() { PrismaHighlightRules.metaData = { name: "Prisma", scopeName: "source.prisma" -} +}; oop.inherits(PrismaHighlightRules, TextHighlightRules); diff --git a/lib/ace/mouse/default_gutter_handler.js b/lib/ace/mouse/default_gutter_handler.js index 2ef41371c59..34c4482a6c8 100644 --- a/lib/ace/mouse/default_gutter_handler.js +++ b/lib/ace/mouse/default_gutter_handler.js @@ -146,7 +146,7 @@ function GutterHandler(mouseHandler) { tooltipTimeout = null; hideTooltip(); }, 50); - }); + }, editor); editor.on("changeSession", hideTooltip); } diff --git a/lib/ace/mouse/dragdrop_handler.js b/lib/ace/mouse/dragdrop_handler.js index ee5d243c8f3..c7841beeb02 100644 --- a/lib/ace/mouse/dragdrop_handler.js +++ b/lib/ace/mouse/dragdrop_handler.js @@ -188,12 +188,12 @@ function DragdropHandler(mouseHandler) { return event.preventDefault(e); }; - event.addListener(mouseTarget, "dragstart", this.onDragStart.bind(mouseHandler)); - event.addListener(mouseTarget, "dragend", this.onDragEnd.bind(mouseHandler)); - event.addListener(mouseTarget, "dragenter", this.onDragEnter.bind(mouseHandler)); - event.addListener(mouseTarget, "dragover", this.onDragOver.bind(mouseHandler)); - event.addListener(mouseTarget, "dragleave", this.onDragLeave.bind(mouseHandler)); - event.addListener(mouseTarget, "drop", this.onDrop.bind(mouseHandler)); + event.addListener(mouseTarget, "dragstart", this.onDragStart.bind(mouseHandler), editor); + event.addListener(mouseTarget, "dragend", this.onDragEnd.bind(mouseHandler), editor); + event.addListener(mouseTarget, "dragenter", this.onDragEnter.bind(mouseHandler), editor); + event.addListener(mouseTarget, "dragover", this.onDragOver.bind(mouseHandler), editor); + event.addListener(mouseTarget, "dragleave", this.onDragLeave.bind(mouseHandler), editor); + event.addListener(mouseTarget, "drop", this.onDrop.bind(mouseHandler), editor); function scrollCursorIntoView(cursor, prevCursor) { var now = Date.now(); diff --git a/lib/ace/mouse/mouse_handler.js b/lib/ace/mouse/mouse_handler.js index b370eb5aaed..37cce5fc6fc 100644 --- a/lib/ace/mouse/mouse_handler.js +++ b/lib/ace/mouse/mouse_handler.js @@ -59,28 +59,28 @@ var MouseHandler = function(editor) { }; var mouseTarget = editor.renderer.getMouseEventTarget(); - event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click")); - event.addListener(mouseTarget, "mousemove", this.onMouseMove.bind(this, "mousemove")); + event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click"), editor); + event.addListener(mouseTarget, "mousemove", this.onMouseMove.bind(this, "mousemove"), editor); event.addMultiMouseDownListener([ mouseTarget, editor.renderer.scrollBarV && editor.renderer.scrollBarV.inner, editor.renderer.scrollBarH && editor.renderer.scrollBarH.inner, editor.textInput && editor.textInput.getElement() - ].filter(Boolean), [400, 300, 250], this, "onMouseEvent"); - event.addMouseWheelListener(editor.container, this.onMouseWheel.bind(this, "mousewheel")); + ].filter(Boolean), [400, 300, 250], this, "onMouseEvent", editor); + event.addMouseWheelListener(editor.container, this.onMouseWheel.bind(this, "mousewheel"), editor); addTouchListeners(editor.container, editor); var gutterEl = editor.renderer.$gutter; - event.addListener(gutterEl, "mousedown", this.onMouseEvent.bind(this, "guttermousedown")); - event.addListener(gutterEl, "click", this.onMouseEvent.bind(this, "gutterclick")); - event.addListener(gutterEl, "dblclick", this.onMouseEvent.bind(this, "gutterdblclick")); - event.addListener(gutterEl, "mousemove", this.onMouseEvent.bind(this, "guttermousemove")); + event.addListener(gutterEl, "mousedown", this.onMouseEvent.bind(this, "guttermousedown"), editor); + event.addListener(gutterEl, "click", this.onMouseEvent.bind(this, "gutterclick"), editor); + event.addListener(gutterEl, "dblclick", this.onMouseEvent.bind(this, "gutterdblclick"), editor); + event.addListener(gutterEl, "mousemove", this.onMouseEvent.bind(this, "guttermousemove"), editor); - event.addListener(mouseTarget, "mousedown", focusEditor); - event.addListener(gutterEl, "mousedown", focusEditor); + event.addListener(mouseTarget, "mousedown", focusEditor, editor); + event.addListener(gutterEl, "mousedown", focusEditor, editor); if (useragent.isIE && editor.renderer.scrollBarV) { - event.addListener(editor.renderer.scrollBarV.element, "mousedown", focusEditor); - event.addListener(editor.renderer.scrollBarH.element, "mousedown", focusEditor); + event.addListener(editor.renderer.scrollBarV.element, "mousedown", focusEditor, editor); + event.addListener(editor.renderer.scrollBarH.element, "mousedown", focusEditor, editor); } editor.on("mousemove", function(e){ @@ -96,7 +96,7 @@ var MouseHandler = function(editor) { } else { renderer.setCursorStyle(""); } - }); + }, editor); }; (function() { diff --git a/lib/ace/mouse/touch_handler.js b/lib/ace/mouse/touch_handler.js index 78b2f9f5cfe..5f1eb07c7c0 100644 --- a/lib/ace/mouse/touch_handler.js +++ b/lib/ace/mouse/touch_handler.js @@ -163,7 +163,7 @@ exports.addTouchListeners = function(el, editor) { if (!pressed) return; var textarea = editor.textInput.getElement(); textarea.focus(); - }); + }, editor); event.addListener(el, "touchstart", function (e) { var touches = e.touches; if (longTouchTimer || touches.length > 1) { @@ -237,7 +237,7 @@ exports.addTouchListeners = function(el, editor) { longTouchTimer = setTimeout(handleLongTap, 450); } touchStartT = t; - }); + }, editor); event.addListener(el, "touchend", function (e) { pressed = editor.$mouseHandler.isMousePressed = false; @@ -257,7 +257,7 @@ exports.addTouchListeners = function(el, editor) { } clearTimeout(longTouchTimer); longTouchTimer = null; - }); + }, editor); event.addListener(el, "touchmove", function (e) { if (longTouchTimer) { clearTimeout(longTouchTimer); @@ -313,7 +313,7 @@ exports.addTouchListeners = function(el, editor) { editor.renderer.scrollCursorIntoView(pos); e.preventDefault(); } - }); + }, editor); function animate() { animationSteps += 60; diff --git a/lib/ace/multi_select.js b/lib/ace/multi_select.js index 2b40d32ef21..eeab7b98ab5 100644 --- a/lib/ace/multi_select.js +++ b/lib/ace/multi_select.js @@ -927,10 +927,10 @@ function addAltCursorListeners(editor){ } else if (altCursor) { reset(); } - }); + }, editor); - event.addListener(el, "keyup", reset); - event.addListener(el, "blur", reset); + event.addListener(el, "keyup", reset, editor); + event.addListener(el, "blur", reset, editor); function reset(e) { if (altCursor) { editor.renderer.setMouseCursor(""); diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index acd4ebd306a..79ff3f6543e 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -107,11 +107,11 @@ var VirtualRenderer = function(container, theme) { this.scrollBar = this.scrollBarV = new VScrollBar(this.container, this); this.scrollBarH = new HScrollBar(this.container, this); - this.scrollBarV.addEventListener("scroll", function(e) { + this.scrollBarV.on("scroll", function(e) { if (!_self.$scrollAnimation) _self.session.setScrollTop(e.data - _self.scrollMargin.top); }); - this.scrollBarH.addEventListener("scroll", function(e) { + this.scrollBarH.on("scroll", function(e) { if (!_self.$scrollAnimation) _self.session.setScrollLeft(e.data - _self.scrollMargin.left); }); @@ -126,7 +126,7 @@ var VirtualRenderer = function(container, theme) { this.$fontMetrics = new FontMetrics(this.container); this.$textLayer.$setFontMetrics(this.$fontMetrics); - this.$textLayer.addEventListener("changeCharacterSize", function(e) { + this.$textLayer.on("changeCharacterSize", function(e) { _self.updateCharacterSize(); _self.onResize(true, _self.gutterWidth, _self.$size.width, _self.$size.height); _self._signal("changeCharacterSize", e); @@ -1724,6 +1724,8 @@ var VirtualRenderer = function(container, theme) { this.freeze(); this.$fontMetrics.destroy(); this.$cursorLayer.destroy(); + this.removeAllListeners(); + this.container.textContent = ""; }; }).call(VirtualRenderer.prototype); From d91a52d1ba6b724c713d5db35fe4f3bc2d488832 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 3 Apr 2020 02:48:03 +0400 Subject: [PATCH 0323/1293] update bracket highlight after document change too --- lib/ace/editor.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index edbe7cb05b1..8b457eb633b 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -722,6 +722,9 @@ Editor.$uid = 0; this.$cursorChange = function() { this.renderer.updateCursor(); + this.$highlightBrackets(); + this.$highlightTags(); + this.$updateHighlightActiveLine(); }; /** @@ -742,7 +745,6 @@ Editor.$uid = 0; // Update cursor because tab characters can influence the cursor position. this.$cursorChange(); - this.$updateHighlightActiveLine(); }; this.onTokenizerUpdate = function(e) { @@ -765,10 +767,6 @@ Editor.$uid = 0; **/ this.onCursorChange = function() { this.$cursorChange(); - - this.$highlightBrackets(); - this.$highlightTags(); - this.$updateHighlightActiveLine(); this._signal("changeSelection"); }; From 83ad14c4ec854a2743cf78c267b66f535ff39f12 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 3 Apr 2020 04:02:56 +0400 Subject: [PATCH 0324/1293] contentRect passed on safari is broken when zoomed --- lib/ace/layer/font_metrics.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/ace/layer/font_metrics.js b/lib/ace/layer/font_metrics.js index 372711fa51b..d0f83978a8c 100644 --- a/lib/ace/layer/font_metrics.js +++ b/lib/ace/layer/font_metrics.js @@ -105,11 +105,8 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { this.$addObserver = function() { var self = this; this.$observer = new window.ResizeObserver(function(e) { - var rect = e[0].contentRect; - self.checkForSizeChanges({ - height: rect.height, - width: rect.width / CHAR_COUNT - }); + // e[0].contentRect is broken on safari when zoomed; + self.checkForSizeChanges(); }); this.$observer.observe(this.$measureNode); }; From f2550525dcd3c616af4b63802edfc6e70d7724ac Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 3 Apr 2020 19:20:53 +0400 Subject: [PATCH 0325/1293] add a test --- lib/ace/ace_test.js | 38 +++++++++++++++++++++++++++++++++++++ lib/ace/lib/event.js | 30 ++++++++++++++--------------- lib/ace/test/all_browser.js | 1 + lib/ace/test/mockdom.js | 2 +- 4 files changed, 55 insertions(+), 16 deletions(-) diff --git a/lib/ace/ace_test.js b/lib/ace/ace_test.js index 2554bb527df..563735c084f 100644 --- a/lib/ace/ace_test.js +++ b/lib/ace/ace_test.js @@ -83,15 +83,53 @@ module.exports = { }, "test: destroy": function(done) { var editor = ace.edit(); + var mouseTarget = editor.renderer.getMouseEventTarget(); + var textarea = editor.textInput.getElement(); + + // editor.curOp is undefined after commands + sendText(textarea, "x"); + assert.ok(!editor.curOp); + assert.equal(editor.getValue(), "x"); + + // editor.curOp is defined if api is used without endOperation editor.insert("1"); assert.ok(editor.curOp); + + // clicking on editor calls focus + var focusCalled = 0; + editor.focus = function() { focusCalled++; }; + click(mouseTarget); + assert.equal(focusCalled, 1); + editor.destroy(); + + // clicking on destroyed editor doesn't call focus + click(mouseTarget); + assert.equal(focusCalled, 1); + setTimeout(function() { assert.notOk(!!editor.curOp); + + // input commands on destroed editor without session do not throw errors + editor.setSession(null); + sendText(textarea, "2"); + done(); }); } }; + +/*global CustomEvent*/ +function click(node) { + node.dispatchEvent(new CustomEvent("mousedown")); +} + +function sendText(textarea, text) { + textarea.value = textarea.value.slice(0, textarea.selectionStart) + text + + textarea.value.slice(textarea.selectionEnd); + textarea.dispatchEvent(new CustomEvent("input")); +} + }); if (typeof module !== "undefined" && module === require.main) { diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js index 3b0c8332d24..3edef160496 100644 --- a/lib/ace/lib/event.js +++ b/lib/ace/lib/event.js @@ -65,10 +65,10 @@ EventListener.prototype.destroy = function() { this.elem = this.type = this.callback = undefined; }; -var addListener = exports.addListener = function(elem, type, callback, destroyable) { +var addListener = exports.addListener = function(elem, type, callback, destroyer) { elem.addEventListener(type, callback, getListenerOptions()); - if (destroyable && destroyable.$toDestroy) - destroyable.$toDestroy.push(new EventListener(elem, type, callback)); + if (destroyer) + destroyer.$toDestroy.push(new EventListener(elem, type, callback)); }; var removeListener = exports.removeListener = function(elem, type, callback) { @@ -124,7 +124,7 @@ exports.capture = function(el, eventHandler, releaseCaptureHandler) { return onMouseUp; }; -exports.addMouseWheelListener = function(el, callback, destroyable) { +exports.addMouseWheelListener = function(el, callback, destroyer) { if ("onmousewheel" in el) { addListener(el, "mousewheel", function(e) { var factor = 8; @@ -136,7 +136,7 @@ exports.addMouseWheelListener = function(el, callback, destroyable) { e.wheelY = -e.wheelDelta / factor; } callback(e); - }, destroyable); + }, destroyer); } else if ("onwheel" in el) { addListener(el, "wheel", function(e) { var factor = 0.35; @@ -153,7 +153,7 @@ exports.addMouseWheelListener = function(el, callback, destroyable) { } callback(e); - }, destroyable); + }, destroyer); } else { addListener(el, "DOMMouseScroll", function(e) { if (e.axis && e.axis == e.HORIZONTAL_AXIS) { @@ -164,11 +164,11 @@ exports.addMouseWheelListener = function(el, callback, destroyable) { e.wheelY = (e.detail || 0) * 5; } callback(e); - }, destroyable); + }, destroyer); } }; -exports.addMultiMouseDownListener = function(elements, timeouts, eventHandler, callbackName, destroyable) { +exports.addMultiMouseDownListener = function(elements, timeouts, eventHandler, callbackName, destroyer) { var clicks = 0; var startX, startY, timer; var eventNames = { @@ -213,7 +213,7 @@ exports.addMultiMouseDownListener = function(elements, timeouts, eventHandler, c if (!Array.isArray(elements)) elements = [elements]; elements.forEach(function(el) { - addListener(el, "mousedown", onMousedown, destroyable); + addListener(el, "mousedown", onMousedown, destroyer); }); }; @@ -282,7 +282,7 @@ function normalizeCommandKeys(callback, e, keyCode) { } -exports.addCommandKeyListener = function(el, callback, destroyable) { +exports.addCommandKeyListener = function(el, callback, destroyer) { if (useragent.isOldGecko || (useragent.isOpera && !("KeyboardEvent" in window))) { // Old versions of Gecko aka. Firefox < 4.0 didn't repeat the keydown // event if the user pressed the key for a longer time. Instead, the @@ -293,10 +293,10 @@ exports.addCommandKeyListener = function(el, callback, destroyable) { var lastKeyDownKeyCode = null; addListener(el, "keydown", function(e) { lastKeyDownKeyCode = e.keyCode; - }, destroyable); + }, destroyer); addListener(el, "keypress", function(e) { return normalizeCommandKeys(callback, e, lastKeyDownKeyCode); - }, destroyable); + }, destroyer); } else { var lastDefaultPrevented = null; @@ -305,18 +305,18 @@ exports.addCommandKeyListener = function(el, callback, destroyable) { var result = normalizeCommandKeys(callback, e, e.keyCode); lastDefaultPrevented = e.defaultPrevented; return result; - }, destroyable); + }, destroyer); addListener(el, "keypress", function(e) { if (lastDefaultPrevented && (e.ctrlKey || e.altKey || e.shiftKey || e.metaKey)) { exports.stopEvent(e); lastDefaultPrevented = null; } - }, destroyable); + }, destroyer); addListener(el, "keyup", function(e) { pressedKeys[e.keyCode] = null; - }, destroyable); + }, destroyer); if (!pressedKeys) { resetPressedKeys(); diff --git a/lib/ace/test/all_browser.js b/lib/ace/test/all_browser.js index a77453eb856..b76abc8c29c 100644 --- a/lib/ace/test/all_browser.js +++ b/lib/ace/test/all_browser.js @@ -12,6 +12,7 @@ var log = document.getElementById("log"); var el = document.createElement.bind(document); var testNames = [ + "ace/ace_test", "ace/anchor_test", "ace/autocomplete_test", "ace/background_tokenizer_test", diff --git a/lib/ace/test/mockdom.js b/lib/ace/test/mockdom.js index 0990240a368..e63f6106820 100644 --- a/lib/ace/test/mockdom.js +++ b/lib/ace/test/mockdom.js @@ -380,7 +380,7 @@ function Node(name) { this.removeEventListener = function(name, listener) { if (!this._events) return; if (!this._events[name]) return; - var i = this._events[name].indexOf(this._events[name]); + var i = this._events[name].indexOf(listener); if (i !== -1) this._events[name].splice(i, 1); }; From abf1a195211d8b5eded5e5f0449a566b80594b6e Mon Sep 17 00:00:00 2001 From: psillithid Date: Sun, 5 Apr 2020 16:15:11 +1000 Subject: [PATCH 0326/1293] Update jshint.js to 2.11.0, mostly de-lodash'd. --- lib/ace/mode/javascript/jshint.js | 26773 +++++++++++++++++----------- 1 file changed, 16597 insertions(+), 10176 deletions(-) diff --git a/lib/ace/mode/javascript/jshint.js b/lib/ace/mode/javascript/jshint.js index 4bafb996c17..3aa24224034 100644 --- a/lib/ace/mode/javascript/jshint.js +++ b/lib/ace/mode/javascript/jshint.js @@ -1,5 +1,6 @@ define(function(require, exports, module) { -module.exports = (function outer (modules, cache, entry) { +module.exports = (function() { +function outer(modules, cache, entry) { var previousRequire = typeof require == "function" && require; function newRequire(name, jumped){ if(!cache[name]) { @@ -21,11790 +22,16244 @@ module.exports = (function outer (modules, cache, entry) { } for(var i=0;i= 65 && i <= 90 || // A-Z + i === 95 || // _ + i >= 97 && i <= 122; // a-z +} -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; +var identifierPartTable = []; -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; +for (var i = 0; i < 128; i++) { + identifierPartTable[i] = + identifierStartTable[i] || // $, _, A-Z, a-z + i >= 48 && i <= 57; // 0-9 +} -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; +module.exports = { + asciiIdentifierStartTable: identifierStartTable, + asciiIdentifierPartTable: identifierPartTable }; -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; +},{}],"/../../jshint/data/es5-identifier-names.js":[function(_dereq_,module,exports){ +module.exports = /^(?:[\$A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0525\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0621-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971\u0972\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3D\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC\u0EDD\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8B\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10D0-\u10FA\u10FC\u1100-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u2094\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2D00-\u2D25\u2D30-\u2D65\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31B7\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCB\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA65F\uA662-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B\uA78C\uA7FB-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA2D\uFA30-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC])(?:[\$0-9A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0525\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0621-\u065E\u0660-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0900-\u0939\u093C-\u094E\u0950-\u0955\u0958-\u0963\u0966-\u096F\u0971\u0972\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC\u0EDD\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F8B\u0F90-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10D0-\u10FA\u10FC\u1100-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17B3\u17B6-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BAA\u1BAE-\u1BB9\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF2\u1D00-\u1DE6\u1DFD-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u2094\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF1\u2D00-\u2D25\u2D30-\u2D65\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31B7\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCB\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA65F\uA662-\uA66F\uA67C\uA67D\uA67F-\uA697\uA6A0-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B\uA78C\uA7FB-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA2D\uFA30-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC])*$/; +},{}],"/../../jshint/data/non-ascii-identifier-part-only.js":[function(_dereq_,module,exports){ +var str = '183,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,903,1155,1156,1157,1158,1159,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1471,1473,1474,1476,1477,1479,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1648,1750,1751,1752,1753,1754,1755,1756,1759,1760,1761,1762,1763,1764,1767,1768,1770,1771,1772,1773,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1809,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,2027,2028,2029,2030,2031,2032,2033,2034,2035,2045,2070,2071,2072,2073,2075,2076,2077,2078,2079,2080,2081,2082,2083,2085,2086,2087,2089,2090,2091,2092,2093,2137,2138,2139,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2362,2363,2364,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2385,2386,2387,2388,2389,2390,2391,2402,2403,2406,2407,2408,2409,2410,2411,2412,2413,2414,2415,2433,2434,2435,2492,2494,2495,2496,2497,2498,2499,2500,2503,2504,2507,2508,2509,2519,2530,2531,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2558,2561,2562,2563,2620,2622,2623,2624,2625,2626,2631,2632,2635,2636,2637,2641,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2677,2689,2690,2691,2748,2750,2751,2752,2753,2754,2755,2756,2757,2759,2760,2761,2763,2764,2765,2786,2787,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,2810,2811,2812,2813,2814,2815,2817,2818,2819,2876,2878,2879,2880,2881,2882,2883,2884,2887,2888,2891,2892,2893,2902,2903,2914,2915,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2946,3006,3007,3008,3009,3010,3014,3015,3016,3018,3019,3020,3021,3031,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3072,3073,3074,3075,3076,3134,3135,3136,3137,3138,3139,3140,3142,3143,3144,3146,3147,3148,3149,3157,3158,3170,3171,3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3201,3202,3203,3260,3262,3263,3264,3265,3266,3267,3268,3270,3271,3272,3274,3275,3276,3277,3285,3286,3298,3299,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3328,3329,3330,3331,3387,3388,3390,3391,3392,3393,3394,3395,3396,3398,3399,3400,3402,3403,3404,3405,3415,3426,3427,3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3458,3459,3530,3535,3536,3537,3538,3539,3540,3542,3544,3545,3546,3547,3548,3549,3550,3551,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3570,3571,3633,3636,3637,3638,3639,3640,3641,3642,3655,3656,3657,3658,3659,3660,3661,3662,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3761,3764,3765,3766,3767,3768,3769,3771,3772,3784,3785,3786,3787,3788,3789,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3864,3865,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3893,3895,3897,3902,3903,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3974,3975,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4038,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4160,4161,4162,4163,4164,4165,4166,4167,4168,4169,4182,4183,4184,4185,4190,4191,4192,4194,4195,4196,4199,4200,4201,4202,4203,4204,4205,4209,4210,4211,4212,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4239,4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4957,4958,4959,4969,4970,4971,4972,4973,4974,4975,4976,4977,5906,5907,5908,5938,5939,5940,5970,5971,6002,6003,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6109,6112,6113,6114,6115,6116,6117,6118,6119,6120,6121,6155,6156,6157,6160,6161,6162,6163,6164,6165,6166,6167,6168,6169,6313,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459,6470,6471,6472,6473,6474,6475,6476,6477,6478,6479,6608,6609,6610,6611,6612,6613,6614,6615,6616,6617,6618,6679,6680,6681,6682,6683,6741,6742,6743,6744,6745,6746,6747,6748,6749,6750,6752,6753,6754,6755,6756,6757,6758,6759,6760,6761,6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,6779,6780,6783,6784,6785,6786,6787,6788,6789,6790,6791,6792,6793,6800,6801,6802,6803,6804,6805,6806,6807,6808,6809,6832,6833,6834,6835,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6912,6913,6914,6915,6916,6964,6965,6966,6967,6968,6969,6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,6992,6993,6994,6995,6996,6997,6998,6999,7000,7001,7019,7020,7021,7022,7023,7024,7025,7026,7027,7040,7041,7042,7073,7074,7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7088,7089,7090,7091,7092,7093,7094,7095,7096,7097,7142,7143,7144,7145,7146,7147,7148,7149,7150,7151,7152,7153,7154,7155,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213,7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7232,7233,7234,7235,7236,7237,7238,7239,7240,7241,7248,7249,7250,7251,7252,7253,7254,7255,7256,7257,7376,7377,7378,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400,7405,7410,7411,7412,7415,7416,7417,7616,7617,7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628,7629,7630,7631,7632,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7675,7676,7677,7678,7679,8204,8205,8255,8256,8276,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,8411,8412,8417,8421,8422,8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,11503,11504,11505,11647,11744,11745,11746,11747,11748,11749,11750,11751,11752,11753,11754,11755,11756,11757,11758,11759,11760,11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,11774,11775,12330,12331,12332,12333,12334,12335,12441,12442,42528,42529,42530,42531,42532,42533,42534,42535,42536,42537,42607,42612,42613,42614,42615,42616,42617,42618,42619,42620,42621,42654,42655,42736,42737,43010,43014,43019,43043,43044,43045,43046,43047,43136,43137,43188,43189,43190,43191,43192,43193,43194,43195,43196,43197,43198,43199,43200,43201,43202,43203,43204,43205,43216,43217,43218,43219,43220,43221,43222,43223,43224,43225,43232,43233,43234,43235,43236,43237,43238,43239,43240,43241,43242,43243,43244,43245,43246,43247,43248,43249,43263,43264,43265,43266,43267,43268,43269,43270,43271,43272,43273,43302,43303,43304,43305,43306,43307,43308,43309,43335,43336,43337,43338,43339,43340,43341,43342,43343,43344,43345,43346,43347,43392,43393,43394,43395,43443,43444,43445,43446,43447,43448,43449,43450,43451,43452,43453,43454,43455,43456,43472,43473,43474,43475,43476,43477,43478,43479,43480,43481,43493,43504,43505,43506,43507,43508,43509,43510,43511,43512,43513,43561,43562,43563,43564,43565,43566,43567,43568,43569,43570,43571,43572,43573,43574,43587,43596,43597,43600,43601,43602,43603,43604,43605,43606,43607,43608,43609,43643,43644,43645,43696,43698,43699,43700,43703,43704,43710,43711,43713,43755,43756,43757,43758,43759,43765,43766,44003,44004,44005,44006,44007,44008,44009,44010,44012,44013,44016,44017,44018,44019,44020,44021,44022,44023,44024,44025,64286,65024,65025,65026,65027,65028,65029,65030,65031,65032,65033,65034,65035,65036,65037,65038,65039,65056,65057,65058,65059,65060,65061,65062,65063,65064,65065,65066,65067,65068,65069,65070,65071,65075,65076,65101,65102,65103,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,65343'; +var arr = str.split(',').map(function(code) { + return parseInt(code, 10); +}); +module.exports = arr; +},{}],"/../../jshint/data/non-ascii-identifier-start.js":[function(_dereq_,module,exports){ +var str = '170,181,186,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,710,711,712,713,714,715,716,717,718,719,720,721,736,737,738,739,740,748,750,880,881,882,883,884,886,887,890,891,892,893,895,902,904,905,906,908,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976,977,978,979,980,981,982,983,984,985,986,987,988,989,990,991,992,993,994,995,996,997,998,999,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269,1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,1311,1312,1313,1314,1315,1316,1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1369,1376,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1519,1520,1521,1522,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1646,1647,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1749,1765,1766,1774,1775,1786,1787,1788,1791,1808,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1969,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2036,2037,2042,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2074,2084,2088,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,2125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2230,2231,2232,2233,2234,2235,2236,2237,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2365,2384,2392,2393,2394,2395,2396,2397,2398,2399,2400,2401,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,2429,2430,2431,2432,2437,2438,2439,2440,2441,2442,2443,2444,2447,2448,2451,2452,2453,2454,2455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2474,2475,2476,2477,2478,2479,2480,2482,2486,2487,2488,2489,2493,2510,2524,2525,2527,2528,2529,2544,2545,2556,2565,2566,2567,2568,2569,2570,2575,2576,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2602,2603,2604,2605,2606,2607,2608,2610,2611,2613,2614,2616,2617,2649,2650,2651,2652,2654,2674,2675,2676,2693,2694,2695,2696,2697,2698,2699,2700,2701,2703,2704,2705,2707,2708,2709,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,2725,2726,2727,2728,2730,2731,2732,2733,2734,2735,2736,2738,2739,2741,2742,2743,2744,2745,2749,2768,2784,2785,2809,2821,2822,2823,2824,2825,2826,2827,2828,2831,2832,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2858,2859,2860,2861,2862,2863,2864,2866,2867,2869,2870,2871,2872,2873,2877,2908,2909,2911,2912,2913,2929,2947,2949,2950,2951,2952,2953,2954,2958,2959,2960,2962,2963,2964,2965,2969,2970,2972,2974,2975,2979,2980,2984,2985,2986,2990,2991,2992,2993,2994,2995,2996,2997,2998,2999,3000,3001,3024,3077,3078,3079,3080,3081,3082,3083,3084,3086,3087,3088,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3114,3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3133,3160,3161,3162,3168,3169,3200,3205,3206,3207,3208,3209,3210,3211,3212,3214,3215,3216,3218,3219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,3239,3240,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3253,3254,3255,3256,3257,3261,3294,3296,3297,3313,3314,3333,3334,3335,3336,3337,3338,3339,3340,3342,3343,3344,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3389,3406,3412,3413,3414,3423,3424,3425,3450,3451,3452,3453,3454,3455,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,3505,3507,3508,3509,3510,3511,3512,3513,3514,3515,3517,3520,3521,3522,3523,3524,3525,3526,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3634,3635,3648,3649,3650,3651,3652,3653,3654,3713,3714,3716,3719,3720,3722,3725,3732,3733,3734,3735,3737,3738,3739,3740,3741,3742,3743,3745,3746,3747,3749,3751,3754,3755,3757,3758,3759,3760,3762,3763,3773,3776,3777,3778,3779,3780,3782,3804,3805,3806,3807,3840,3904,3905,3906,3907,3908,3909,3910,3911,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3976,3977,3978,3979,3980,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,4159,4176,4177,4178,4179,4180,4181,4186,4187,4188,4189,4193,4197,4198,4206,4207,4208,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4238,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4295,4301,4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,4345,4346,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,4679,4680,4682,4683,4684,4685,4688,4689,4690,4691,4692,4693,4694,4696,4698,4699,4700,4701,4704,4705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4746,4747,4748,4749,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,4784,4786,4787,4788,4789,4792,4793,4794,4795,4796,4797,4798,4800,4802,4803,4804,4805,4808,4809,4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4824,4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4882,4883,4884,4885,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103,5104,5105,5106,5107,5108,5109,5112,5113,5114,5115,5116,5117,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133,5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149,5150,5151,5152,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164,5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,5176,5177,5178,5179,5180,5181,5182,5183,5184,5185,5186,5187,5188,5189,5190,5191,5192,5193,5194,5195,5196,5197,5198,5199,5200,5201,5202,5203,5204,5205,5206,5207,5208,5209,5210,5211,5212,5213,5214,5215,5216,5217,5218,5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,5248,5249,5250,5251,5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,5380,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408,5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424,5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440,5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456,5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472,5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488,5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504,5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520,5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536,5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552,5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648,5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664,5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680,5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696,5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712,5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728,5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5743,5744,5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776,5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5792,5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5870,5871,5872,5873,5874,5875,5876,5877,5878,5879,5880,5888,5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5902,5903,5904,5905,5920,5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936,5937,5952,5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968,5969,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5998,5999,6000,6016,6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6103,6108,6176,6177,6178,6179,6180,6181,6182,6183,6184,6185,6186,6187,6188,6189,6190,6191,6192,6193,6194,6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,6209,6210,6211,6212,6213,6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,6224,6225,6226,6227,6228,6229,6230,6231,6232,6233,6234,6235,6236,6237,6238,6239,6240,6241,6242,6243,6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,6254,6255,6256,6257,6258,6259,6260,6261,6262,6263,6264,6272,6273,6274,6275,6276,6277,6278,6279,6280,6281,6282,6283,6284,6285,6286,6287,6288,6289,6290,6291,6292,6293,6294,6295,6296,6297,6298,6299,6300,6301,6302,6303,6304,6305,6306,6307,6308,6309,6310,6311,6312,6314,6320,6321,6322,6323,6324,6325,6326,6327,6328,6329,6330,6331,6332,6333,6334,6335,6336,6337,6338,6339,6340,6341,6342,6343,6344,6345,6346,6347,6348,6349,6350,6351,6352,6353,6354,6355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365,6366,6367,6368,6369,6370,6371,6372,6373,6374,6375,6376,6377,6378,6379,6380,6381,6382,6383,6384,6385,6386,6387,6388,6389,6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,6411,6412,6413,6414,6415,6416,6417,6418,6419,6420,6421,6422,6423,6424,6425,6426,6427,6428,6429,6430,6480,6481,6482,6483,6484,6485,6486,6487,6488,6489,6490,6491,6492,6493,6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,6504,6505,6506,6507,6508,6509,6512,6513,6514,6515,6516,6528,6529,6530,6531,6532,6533,6534,6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,6550,6551,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,6565,6566,6567,6568,6569,6570,6571,6576,6577,6578,6579,6580,6581,6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,6595,6596,6597,6598,6599,6600,6601,6656,6657,6658,6659,6660,6661,6662,6663,6664,6665,6666,6667,6668,6669,6670,6671,6672,6673,6674,6675,6676,6677,6678,6688,6689,6690,6691,6692,6693,6694,6695,6696,6697,6698,6699,6700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714,6715,6716,6717,6718,6719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,6730,6731,6732,6733,6734,6735,6736,6737,6738,6739,6740,6823,6917,6918,6919,6920,6921,6922,6923,6924,6925,6926,6927,6928,6929,6930,6931,6932,6933,6934,6935,6936,6937,6938,6939,6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,6955,6956,6957,6958,6959,6960,6961,6962,6963,6981,6982,6983,6984,6985,6986,6987,7043,7044,7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059,7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,7071,7072,7086,7087,7098,7099,7100,7101,7102,7103,7104,7105,7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,7120,7121,7122,7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,7135,7136,7137,7138,7139,7140,7141,7168,7169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179,7180,7181,7182,7183,7184,7185,7186,7187,7188,7189,7190,7191,7192,7193,7194,7195,7196,7197,7198,7199,7200,7201,7202,7203,7245,7246,7247,7258,7259,7260,7261,7262,7263,7264,7265,7266,7267,7268,7269,7270,7271,7272,7273,7274,7275,7276,7277,7278,7279,7280,7281,7282,7283,7284,7285,7286,7287,7288,7289,7290,7291,7292,7293,7296,7297,7298,7299,7300,7301,7302,7303,7304,7312,7313,7314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327,7328,7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342,7343,7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7357,7358,7359,7401,7402,7403,7404,7406,7407,7408,7409,7413,7414,7424,7425,7426,7427,7428,7429,7430,7431,7432,7433,7434,7435,7436,7437,7438,7439,7440,7441,7442,7443,7444,7445,7446,7447,7448,7449,7450,7451,7452,7453,7454,7455,7456,7457,7458,7459,7460,7461,7462,7463,7464,7465,7466,7467,7468,7469,7470,7471,7472,7473,7474,7475,7476,7477,7478,7479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491,7492,7493,7494,7495,7496,7497,7498,7499,7500,7501,7502,7503,7504,7505,7506,7507,7508,7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519,7520,7521,7522,7523,7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535,7536,7537,7538,7539,7540,7541,7542,7543,7544,7545,7546,7547,7548,7549,7550,7551,7552,7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,7566,7567,7568,7569,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,7580,7581,7582,7583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598,7599,7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,7613,7614,7615,7680,7681,7682,7683,7684,7685,7686,7687,7688,7689,7690,7691,7692,7693,7694,7695,7696,7697,7698,7699,7700,7701,7702,7703,7704,7705,7706,7707,7708,7709,7710,7711,7712,7713,7714,7715,7716,7717,7718,7719,7720,7721,7722,7723,7724,7725,7726,7727,7728,7729,7730,7731,7732,7733,7734,7735,7736,7737,7738,7739,7740,7741,7742,7743,7744,7745,7746,7747,7748,7749,7750,7751,7752,7753,7754,7755,7756,7757,7758,7759,7760,7761,7762,7763,7764,7765,7766,7767,7768,7769,7770,7771,7772,7773,7774,7775,7776,7777,7778,7779,7780,7781,7782,7783,7784,7785,7786,7787,7788,7789,7790,7791,7792,7793,7794,7795,7796,7797,7798,7799,7800,7801,7802,7803,7804,7805,7806,7807,7808,7809,7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823,7824,7825,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839,7840,7841,7842,7843,7844,7845,7846,7847,7848,7849,7850,7851,7852,7853,7854,7855,7856,7857,7858,7859,7860,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870,7871,7872,7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886,7887,7888,7889,7890,7891,7892,7893,7894,7895,7896,7897,7898,7899,7900,7901,7902,7903,7904,7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919,7920,7921,7922,7923,7924,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935,7936,7937,7938,7939,7940,7941,7942,7943,7944,7945,7946,7947,7948,7949,7950,7951,7952,7953,7954,7955,7956,7957,7960,7961,7962,7963,7964,7965,7968,7969,7970,7971,7972,7973,7974,7975,7976,7977,7978,7979,7980,7981,7982,7983,7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7994,7995,7996,7997,7998,7999,8000,8001,8002,8003,8004,8005,8008,8009,8010,8011,8012,8013,8016,8017,8018,8019,8020,8021,8022,8023,8025,8027,8029,8031,8032,8033,8034,8035,8036,8037,8038,8039,8040,8041,8042,8043,8044,8045,8046,8047,8048,8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095,8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111,8112,8113,8114,8115,8116,8118,8119,8120,8121,8122,8123,8124,8126,8130,8131,8132,8134,8135,8136,8137,8138,8139,8140,8144,8145,8146,8147,8150,8151,8152,8153,8154,8155,8160,8161,8162,8163,8164,8165,8166,8167,8168,8169,8170,8171,8172,8178,8179,8180,8182,8183,8184,8185,8186,8187,8188,8305,8319,8336,8337,8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,8348,8450,8455,8458,8459,8460,8461,8462,8463,8464,8465,8466,8467,8469,8472,8473,8474,8475,8476,8477,8484,8486,8488,8490,8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501,8502,8503,8504,8505,8508,8509,8510,8511,8517,8518,8519,8520,8521,8526,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8570,8571,8572,8573,8574,8575,8576,8577,8578,8579,8580,8581,8582,8583,8584,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,11274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,11310,11312,11313,11314,11315,11316,11317,11318,11319,11320,11321,11322,11323,11324,11325,11326,11327,11328,11329,11330,11331,11332,11333,11334,11335,11336,11337,11338,11339,11340,11341,11342,11343,11344,11345,11346,11347,11348,11349,11350,11351,11352,11353,11354,11355,11356,11357,11358,11360,11361,11362,11363,11364,11365,11366,11367,11368,11369,11370,11371,11372,11373,11374,11375,11376,11377,11378,11379,11380,11381,11382,11383,11384,11385,11386,11387,11388,11389,11390,11391,11392,11393,11394,11395,11396,11397,11398,11399,11400,11401,11402,11403,11404,11405,11406,11407,11408,11409,11410,11411,11412,11413,11414,11415,11416,11417,11418,11419,11420,11421,11422,11423,11424,11425,11426,11427,11428,11429,11430,11431,11432,11433,11434,11435,11436,11437,11438,11439,11440,11441,11442,11443,11444,11445,11446,11447,11448,11449,11450,11451,11452,11453,11454,11455,11456,11457,11458,11459,11460,11461,11462,11463,11464,11465,11466,11467,11468,11469,11470,11471,11472,11473,11474,11475,11476,11477,11478,11479,11480,11481,11482,11483,11484,11485,11486,11487,11488,11489,11490,11491,11492,11499,11500,11501,11502,11506,11507,11520,11521,11522,11523,11524,11525,11526,11527,11528,11529,11530,11531,11532,11533,11534,11535,11536,11537,11538,11539,11540,11541,11542,11543,11544,11545,11546,11547,11548,11549,11550,11551,11552,11553,11554,11555,11556,11557,11559,11565,11568,11569,11570,11571,11572,11573,11574,11575,11576,11577,11578,11579,11580,11581,11582,11583,11584,11585,11586,11587,11588,11589,11590,11591,11592,11593,11594,11595,11596,11597,11598,11599,11600,11601,11602,11603,11604,11605,11606,11607,11608,11609,11610,11611,11612,11613,11614,11615,11616,11617,11618,11619,11620,11621,11622,11623,11631,11648,11649,11650,11651,11652,11653,11654,11655,11656,11657,11658,11659,11660,11661,11662,11663,11664,11665,11666,11667,11668,11669,11670,11680,11681,11682,11683,11684,11685,11686,11688,11689,11690,11691,11692,11693,11694,11696,11697,11698,11699,11700,11701,11702,11704,11705,11706,11707,11708,11709,11710,11712,11713,11714,11715,11716,11717,11718,11720,11721,11722,11723,11724,11725,11726,11728,11729,11730,11731,11732,11733,11734,11736,11737,11738,11739,11740,11741,11742,12293,12294,12295,12321,12322,12323,12324,12325,12326,12327,12328,12329,12337,12338,12339,12340,12341,12344,12345,12346,12347,12348,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,12436,12437,12438,12443,12444,12445,12446,12447,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,12535,12536,12537,12538,12540,12541,12542,12543,12549,12550,12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,12586,12587,12588,12589,12590,12591,12593,12594,12595,12596,12597,12598,12599,12600,12601,12602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,12614,12615,12616,12617,12618,12619,12620,12621,12622,12623,12624,12625,12626,12627,12628,12629,12630,12631,12632,12633,12634,12635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646,12647,12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679,12680,12681,12682,12683,12684,12685,12686,12704,12705,12706,12707,12708,12709,12710,12711,12712,12713,12714,12715,12716,12717,12718,12719,12720,12721,12722,12723,12724,12725,12726,12727,12728,12729,12730,12784,12785,12786,12787,12788,12789,12790,12791,12792,12793,12794,12795,12796,12797,12798,12799,13312,13313,13314,13315,13316,13317,13318,13319,13320,13321,13322,13323,13324,13325,13326,13327,13328,13329,13330,13331,13332,13333,13334,13335,13336,13337,13338,13339,13340,13341,13342,13343,13344,13345,13346,13347,13348,13349,13350,13351,13352,13353,13354,13355,13356,13357,13358,13359,13360,13361,13362,13363,13364,13365,13366,13367,13368,13369,13370,13371,13372,13373,13374,13375,13376,13377,13378,13379,13380,13381,13382,13383,13384,13385,13386,13387,13388,13389,13390,13391,13392,13393,13394,13395,13396,13397,13398,13399,13400,13401,13402,13403,13404,13405,13406,13407,13408,13409,13410,13411,13412,13413,13414,13415,13416,13417,13418,13419,13420,13421,13422,13423,13424,13425,13426,13427,13428,13429,13430,13431,13432,13433,13434,13435,13436,13437,13438,13439,13440,13441,13442,13443,13444,13445,13446,13447,13448,13449,13450,13451,13452,13453,13454,13455,13456,13457,13458,13459,13460,13461,13462,13463,13464,13465,13466,13467,13468,13469,13470,13471,13472,13473,13474,13475,13476,13477,13478,13479,13480,13481,13482,13483,13484,13485,13486,13487,13488,13489,13490,13491,13492,13493,13494,13495,13496,13497,13498,13499,13500,13501,13502,13503,13504,13505,13506,13507,13508,13509,13510,13511,13512,13513,13514,13515,13516,13517,13518,13519,13520,13521,13522,13523,13524,13525,13526,13527,13528,13529,13530,13531,13532,13533,13534,13535,13536,13537,13538,13539,13540,13541,13542,13543,13544,13545,13546,13547,13548,13549,13550,13551,13552,13553,13554,13555,13556,13557,13558,13559,13560,13561,13562,13563,13564,13565,13566,13567,13568,13569,13570,13571,13572,13573,13574,13575,13576,13577,13578,13579,13580,13581,13582,13583,13584,13585,13586,13587,13588,13589,13590,13591,13592,13593,13594,13595,13596,13597,13598,13599,13600,13601,13602,13603,13604,13605,13606,13607,13608,13609,13610,13611,13612,13613,13614,13615,13616,13617,13618,13619,13620,13621,13622,13623,13624,13625,13626,13627,13628,13629,13630,13631,13632,13633,13634,13635,13636,13637,13638,13639,13640,13641,13642,13643,13644,13645,13646,13647,13648,13649,13650,13651,13652,13653,13654,13655,13656,13657,13658,13659,13660,13661,13662,13663,13664,13665,13666,13667,13668,13669,13670,13671,13672,13673,13674,13675,13676,13677,13678,13679,13680,13681,13682,13683,13684,13685,13686,13687,13688,13689,13690,13691,13692,13693,13694,13695,13696,13697,13698,13699,13700,13701,13702,13703,13704,13705,13706,13707,13708,13709,13710,13711,13712,13713,13714,13715,13716,13717,13718,13719,13720,13721,13722,13723,13724,13725,13726,13727,13728,13729,13730,13731,13732,13733,13734,13735,13736,13737,13738,13739,13740,13741,13742,13743,13744,13745,13746,13747,13748,13749,13750,13751,13752,13753,13754,13755,13756,13757,13758,13759,13760,13761,13762,13763,13764,13765,13766,13767,13768,13769,13770,13771,13772,13773,13774,13775,13776,13777,13778,13779,13780,13781,13782,13783,13784,13785,13786,13787,13788,13789,13790,13791,13792,13793,13794,13795,13796,13797,13798,13799,13800,13801,13802,13803,13804,13805,13806,13807,13808,13809,13810,13811,13812,13813,13814,13815,13816,13817,13818,13819,13820,13821,13822,13823,13824,13825,13826,13827,13828,13829,13830,13831,13832,13833,13834,13835,13836,13837,13838,13839,13840,13841,13842,13843,13844,13845,13846,13847,13848,13849,13850,13851,13852,13853,13854,13855,13856,13857,13858,13859,13860,13861,13862,13863,13864,13865,13866,13867,13868,13869,13870,13871,13872,13873,13874,13875,13876,13877,13878,13879,13880,13881,13882,13883,13884,13885,13886,13887,13888,13889,13890,13891,13892,13893,13894,13895,13896,13897,13898,13899,13900,13901,13902,13903,13904,13905,13906,13907,13908,13909,13910,13911,13912,13913,13914,13915,13916,13917,13918,13919,13920,13921,13922,13923,13924,13925,13926,13927,13928,13929,13930,13931,13932,13933,13934,13935,13936,13937,13938,13939,13940,13941,13942,13943,13944,13945,13946,13947,13948,13949,13950,13951,13952,13953,13954,13955,13956,13957,13958,13959,13960,13961,13962,13963,13964,13965,13966,13967,13968,13969,13970,13971,13972,13973,13974,13975,13976,13977,13978,13979,13980,13981,13982,13983,13984,13985,13986,13987,13988,13989,13990,13991,13992,13993,13994,13995,13996,13997,13998,13999,14000,14001,14002,14003,14004,14005,14006,14007,14008,14009,14010,14011,14012,14013,14014,14015,14016,14017,14018,14019,14020,14021,14022,14023,14024,14025,14026,14027,14028,14029,14030,14031,14032,14033,14034,14035,14036,14037,14038,14039,14040,14041,14042,14043,14044,14045,14046,14047,14048,14049,14050,14051,14052,14053,14054,14055,14056,14057,14058,14059,14060,14061,14062,14063,14064,14065,14066,14067,14068,14069,14070,14071,14072,14073,14074,14075,14076,14077,14078,14079,14080,14081,14082,14083,14084,14085,14086,14087,14088,14089,14090,14091,14092,14093,14094,14095,14096,14097,14098,14099,14100,14101,14102,14103,14104,14105,14106,14107,14108,14109,14110,14111,14112,14113,14114,14115,14116,14117,14118,14119,14120,14121,14122,14123,14124,14125,14126,14127,14128,14129,14130,14131,14132,14133,14134,14135,14136,14137,14138,14139,14140,14141,14142,14143,14144,14145,14146,14147,14148,14149,14150,14151,14152,14153,14154,14155,14156,14157,14158,14159,14160,14161,14162,14163,14164,14165,14166,14167,14168,14169,14170,14171,14172,14173,14174,14175,14176,14177,14178,14179,14180,14181,14182,14183,14184,14185,14186,14187,14188,14189,14190,14191,14192,14193,14194,14195,14196,14197,14198,14199,14200,14201,14202,14203,14204,14205,14206,14207,14208,14209,14210,14211,14212,14213,14214,14215,14216,14217,14218,14219,14220,14221,14222,14223,14224,14225,14226,14227,14228,14229,14230,14231,14232,14233,14234,14235,14236,14237,14238,14239,14240,14241,14242,14243,14244,14245,14246,14247,14248,14249,14250,14251,14252,14253,14254,14255,14256,14257,14258,14259,14260,14261,14262,14263,14264,14265,14266,14267,14268,14269,14270,14271,14272,14273,14274,14275,14276,14277,14278,14279,14280,14281,14282,14283,14284,14285,14286,14287,14288,14289,14290,14291,14292,14293,14294,14295,14296,14297,14298,14299,14300,14301,14302,14303,14304,14305,14306,14307,14308,14309,14310,14311,14312,14313,14314,14315,14316,14317,14318,14319,14320,14321,14322,14323,14324,14325,14326,14327,14328,14329,14330,14331,14332,14333,14334,14335,14336,14337,14338,14339,14340,14341,14342,14343,14344,14345,14346,14347,14348,14349,14350,14351,14352,14353,14354,14355,14356,14357,14358,14359,14360,14361,14362,14363,14364,14365,14366,14367,14368,14369,14370,14371,14372,14373,14374,14375,14376,14377,14378,14379,14380,14381,14382,14383,14384,14385,14386,14387,14388,14389,14390,14391,14392,14393,14394,14395,14396,14397,14398,14399,14400,14401,14402,14403,14404,14405,14406,14407,14408,14409,14410,14411,14412,14413,14414,14415,14416,14417,14418,14419,14420,14421,14422,14423,14424,14425,14426,14427,14428,14429,14430,14431,14432,14433,14434,14435,14436,14437,14438,14439,14440,14441,14442,14443,14444,14445,14446,14447,14448,14449,14450,14451,14452,14453,14454,14455,14456,14457,14458,14459,14460,14461,14462,14463,14464,14465,14466,14467,14468,14469,14470,14471,14472,14473,14474,14475,14476,14477,14478,14479,14480,14481,14482,14483,14484,14485,14486,14487,14488,14489,14490,14491,14492,14493,14494,14495,14496,14497,14498,14499,14500,14501,14502,14503,14504,14505,14506,14507,14508,14509,14510,14511,14512,14513,14514,14515,14516,14517,14518,14519,14520,14521,14522,14523,14524,14525,14526,14527,14528,14529,14530,14531,14532,14533,14534,14535,14536,14537,14538,14539,14540,14541,14542,14543,14544,14545,14546,14547,14548,14549,14550,14551,14552,14553,14554,14555,14556,14557,14558,14559,14560,14561,14562,14563,14564,14565,14566,14567,14568,14569,14570,14571,14572,14573,14574,14575,14576,14577,14578,14579,14580,14581,14582,14583,14584,14585,14586,14587,14588,14589,14590,14591,14592,14593,14594,14595,14596,14597,14598,14599,14600,14601,14602,14603,14604,14605,14606,14607,14608,14609,14610,14611,14612,14613,14614,14615,14616,14617,14618,14619,14620,14621,14622,14623,14624,14625,14626,14627,14628,14629,14630,14631,14632,14633,14634,14635,14636,14637,14638,14639,14640,14641,14642,14643,14644,14645,14646,14647,14648,14649,14650,14651,14652,14653,14654,14655,14656,14657,14658,14659,14660,14661,14662,14663,14664,14665,14666,14667,14668,14669,14670,14671,14672,14673,14674,14675,14676,14677,14678,14679,14680,14681,14682,14683,14684,14685,14686,14687,14688,14689,14690,14691,14692,14693,14694,14695,14696,14697,14698,14699,14700,14701,14702,14703,14704,14705,14706,14707,14708,14709,14710,14711,14712,14713,14714,14715,14716,14717,14718,14719,14720,14721,14722,14723,14724,14725,14726,14727,14728,14729,14730,14731,14732,14733,14734,14735,14736,14737,14738,14739,14740,14741,14742,14743,14744,14745,14746,14747,14748,14749,14750,14751,14752,14753,14754,14755,14756,14757,14758,14759,14760,14761,14762,14763,14764,14765,14766,14767,14768,14769,14770,14771,14772,14773,14774,14775,14776,14777,14778,14779,14780,14781,14782,14783,14784,14785,14786,14787,14788,14789,14790,14791,14792,14793,14794,14795,14796,14797,14798,14799,14800,14801,14802,14803,14804,14805,14806,14807,14808,14809,14810,14811,14812,14813,14814,14815,14816,14817,14818,14819,14820,14821,14822,14823,14824,14825,14826,14827,14828,14829,14830,14831,14832,14833,14834,14835,14836,14837,14838,14839,14840,14841,14842,14843,14844,14845,14846,14847,14848,14849,14850,14851,14852,14853,14854,14855,14856,14857,14858,14859,14860,14861,14862,14863,14864,14865,14866,14867,14868,14869,14870,14871,14872,14873,14874,14875,14876,14877,14878,14879,14880,14881,14882,14883,14884,14885,14886,14887,14888,14889,14890,14891,14892,14893,14894,14895,14896,14897,14898,14899,14900,14901,14902,14903,14904,14905,14906,14907,14908,14909,14910,14911,14912,14913,14914,14915,14916,14917,14918,14919,14920,14921,14922,14923,14924,14925,14926,14927,14928,14929,14930,14931,14932,14933,14934,14935,14936,14937,14938,14939,14940,14941,14942,14943,14944,14945,14946,14947,14948,14949,14950,14951,14952,14953,14954,14955,14956,14957,14958,14959,14960,14961,14962,14963,14964,14965,14966,14967,14968,14969,14970,14971,14972,14973,14974,14975,14976,14977,14978,14979,14980,14981,14982,14983,14984,14985,14986,14987,14988,14989,14990,14991,14992,14993,14994,14995,14996,14997,14998,14999,15000,15001,15002,15003,15004,15005,15006,15007,15008,15009,15010,15011,15012,15013,15014,15015,15016,15017,15018,15019,15020,15021,15022,15023,15024,15025,15026,15027,15028,15029,15030,15031,15032,15033,15034,15035,15036,15037,15038,15039,15040,15041,15042,15043,15044,15045,15046,15047,15048,15049,15050,15051,15052,15053,15054,15055,15056,15057,15058,15059,15060,15061,15062,15063,15064,15065,15066,15067,15068,15069,15070,15071,15072,15073,15074,15075,15076,15077,15078,15079,15080,15081,15082,15083,15084,15085,15086,15087,15088,15089,15090,15091,15092,15093,15094,15095,15096,15097,15098,15099,15100,15101,15102,15103,15104,15105,15106,15107,15108,15109,15110,15111,15112,15113,15114,15115,15116,15117,15118,15119,15120,15121,15122,15123,15124,15125,15126,15127,15128,15129,15130,15131,15132,15133,15134,15135,15136,15137,15138,15139,15140,15141,15142,15143,15144,15145,15146,15147,15148,15149,15150,15151,15152,15153,15154,15155,15156,15157,15158,15159,15160,15161,15162,15163,15164,15165,15166,15167,15168,15169,15170,15171,15172,15173,15174,15175,15176,15177,15178,15179,15180,15181,15182,15183,15184,15185,15186,15187,15188,15189,15190,15191,15192,15193,15194,15195,15196,15197,15198,15199,15200,15201,15202,15203,15204,15205,15206,15207,15208,15209,15210,15211,15212,15213,15214,15215,15216,15217,15218,15219,15220,15221,15222,15223,15224,15225,15226,15227,15228,15229,15230,15231,15232,15233,15234,15235,15236,15237,15238,15239,15240,15241,15242,15243,15244,15245,15246,15247,15248,15249,15250,15251,15252,15253,15254,15255,15256,15257,15258,15259,15260,15261,15262,15263,15264,15265,15266,15267,15268,15269,15270,15271,15272,15273,15274,15275,15276,15277,15278,15279,15280,15281,15282,15283,15284,15285,15286,15287,15288,15289,15290,15291,15292,15293,15294,15295,15296,15297,15298,15299,15300,15301,15302,15303,15304,15305,15306,15307,15308,15309,15310,15311,15312,15313,15314,15315,15316,15317,15318,15319,15320,15321,15322,15323,15324,15325,15326,15327,15328,15329,15330,15331,15332,15333,15334,15335,15336,15337,15338,15339,15340,15341,15342,15343,15344,15345,15346,15347,15348,15349,15350,15351,15352,15353,15354,15355,15356,15357,15358,15359,15360,15361,15362,15363,15364,15365,15366,15367,15368,15369,15370,15371,15372,15373,15374,15375,15376,15377,15378,15379,15380,15381,15382,15383,15384,15385,15386,15387,15388,15389,15390,15391,15392,15393,15394,15395,15396,15397,15398,15399,15400,15401,15402,15403,15404,15405,15406,15407,15408,15409,15410,15411,15412,15413,15414,15415,15416,15417,15418,15419,15420,15421,15422,15423,15424,15425,15426,15427,15428,15429,15430,15431,15432,15433,15434,15435,15436,15437,15438,15439,15440,15441,15442,15443,15444,15445,15446,15447,15448,15449,15450,15451,15452,15453,15454,15455,15456,15457,15458,15459,15460,15461,15462,15463,15464,15465,15466,15467,15468,15469,15470,15471,15472,15473,15474,15475,15476,15477,15478,15479,15480,15481,15482,15483,15484,15485,15486,15487,15488,15489,15490,15491,15492,15493,15494,15495,15496,15497,15498,15499,15500,15501,15502,15503,15504,15505,15506,15507,15508,15509,15510,15511,15512,15513,15514,15515,15516,15517,15518,15519,15520,15521,15522,15523,15524,15525,15526,15527,15528,15529,15530,15531,15532,15533,15534,15535,15536,15537,15538,15539,15540,15541,15542,15543,15544,15545,15546,15547,15548,15549,15550,15551,15552,15553,15554,15555,15556,15557,15558,15559,15560,15561,15562,15563,15564,15565,15566,15567,15568,15569,15570,15571,15572,15573,15574,15575,15576,15577,15578,15579,15580,15581,15582,15583,15584,15585,15586,15587,15588,15589,15590,15591,15592,15593,15594,15595,15596,15597,15598,15599,15600,15601,15602,15603,15604,15605,15606,15607,15608,15609,15610,15611,15612,15613,15614,15615,15616,15617,15618,15619,15620,15621,15622,15623,15624,15625,15626,15627,15628,15629,15630,15631,15632,15633,15634,15635,15636,15637,15638,15639,15640,15641,15642,15643,15644,15645,15646,15647,15648,15649,15650,15651,15652,15653,15654,15655,15656,15657,15658,15659,15660,15661,15662,15663,15664,15665,15666,15667,15668,15669,15670,15671,15672,15673,15674,15675,15676,15677,15678,15679,15680,15681,15682,15683,15684,15685,15686,15687,15688,15689,15690,15691,15692,15693,15694,15695,15696,15697,15698,15699,15700,15701,15702,15703,15704,15705,15706,15707,15708,15709,15710,15711,15712,15713,15714,15715,15716,15717,15718,15719,15720,15721,15722,15723,15724,15725,15726,15727,15728,15729,15730,15731,15732,15733,15734,15735,15736,15737,15738,15739,15740,15741,15742,15743,15744,15745,15746,15747,15748,15749,15750,15751,15752,15753,15754,15755,15756,15757,15758,15759,15760,15761,15762,15763,15764,15765,15766,15767,15768,15769,15770,15771,15772,15773,15774,15775,15776,15777,15778,15779,15780,15781,15782,15783,15784,15785,15786,15787,15788,15789,15790,15791,15792,15793,15794,15795,15796,15797,15798,15799,15800,15801,15802,15803,15804,15805,15806,15807,15808,15809,15810,15811,15812,15813,15814,15815,15816,15817,15818,15819,15820,15821,15822,15823,15824,15825,15826,15827,15828,15829,15830,15831,15832,15833,15834,15835,15836,15837,15838,15839,15840,15841,15842,15843,15844,15845,15846,15847,15848,15849,15850,15851,15852,15853,15854,15855,15856,15857,15858,15859,15860,15861,15862,15863,15864,15865,15866,15867,15868,15869,15870,15871,15872,15873,15874,15875,15876,15877,15878,15879,15880,15881,15882,15883,15884,15885,15886,15887,15888,15889,15890,15891,15892,15893,15894,15895,15896,15897,15898,15899,15900,15901,15902,15903,15904,15905,15906,15907,15908,15909,15910,15911,15912,15913,15914,15915,15916,15917,15918,15919,15920,15921,15922,15923,15924,15925,15926,15927,15928,15929,15930,15931,15932,15933,15934,15935,15936,15937,15938,15939,15940,15941,15942,15943,15944,15945,15946,15947,15948,15949,15950,15951,15952,15953,15954,15955,15956,15957,15958,15959,15960,15961,15962,15963,15964,15965,15966,15967,15968,15969,15970,15971,15972,15973,15974,15975,15976,15977,15978,15979,15980,15981,15982,15983,15984,15985,15986,15987,15988,15989,15990,15991,15992,15993,15994,15995,15996,15997,15998,15999,16000,16001,16002,16003,16004,16005,16006,16007,16008,16009,16010,16011,16012,16013,16014,16015,16016,16017,16018,16019,16020,16021,16022,16023,16024,16025,16026,16027,16028,16029,16030,16031,16032,16033,16034,16035,16036,16037,16038,16039,16040,16041,16042,16043,16044,16045,16046,16047,16048,16049,16050,16051,16052,16053,16054,16055,16056,16057,16058,16059,16060,16061,16062,16063,16064,16065,16066,16067,16068,16069,16070,16071,16072,16073,16074,16075,16076,16077,16078,16079,16080,16081,16082,16083,16084,16085,16086,16087,16088,16089,16090,16091,16092,16093,16094,16095,16096,16097,16098,16099,16100,16101,16102,16103,16104,16105,16106,16107,16108,16109,16110,16111,16112,16113,16114,16115,16116,16117,16118,16119,16120,16121,16122,16123,16124,16125,16126,16127,16128,16129,16130,16131,16132,16133,16134,16135,16136,16137,16138,16139,16140,16141,16142,16143,16144,16145,16146,16147,16148,16149,16150,16151,16152,16153,16154,16155,16156,16157,16158,16159,16160,16161,16162,16163,16164,16165,16166,16167,16168,16169,16170,16171,16172,16173,16174,16175,16176,16177,16178,16179,16180,16181,16182,16183,16184,16185,16186,16187,16188,16189,16190,16191,16192,16193,16194,16195,16196,16197,16198,16199,16200,16201,16202,16203,16204,16205,16206,16207,16208,16209,16210,16211,16212,16213,16214,16215,16216,16217,16218,16219,16220,16221,16222,16223,16224,16225,16226,16227,16228,16229,16230,16231,16232,16233,16234,16235,16236,16237,16238,16239,16240,16241,16242,16243,16244,16245,16246,16247,16248,16249,16250,16251,16252,16253,16254,16255,16256,16257,16258,16259,16260,16261,16262,16263,16264,16265,16266,16267,16268,16269,16270,16271,16272,16273,16274,16275,16276,16277,16278,16279,16280,16281,16282,16283,16284,16285,16286,16287,16288,16289,16290,16291,16292,16293,16294,16295,16296,16297,16298,16299,16300,16301,16302,16303,16304,16305,16306,16307,16308,16309,16310,16311,16312,16313,16314,16315,16316,16317,16318,16319,16320,16321,16322,16323,16324,16325,16326,16327,16328,16329,16330,16331,16332,16333,16334,16335,16336,16337,16338,16339,16340,16341,16342,16343,16344,16345,16346,16347,16348,16349,16350,16351,16352,16353,16354,16355,16356,16357,16358,16359,16360,16361,16362,16363,16364,16365,16366,16367,16368,16369,16370,16371,16372,16373,16374,16375,16376,16377,16378,16379,16380,16381,16382,16383,16384,16385,16386,16387,16388,16389,16390,16391,16392,16393,16394,16395,16396,16397,16398,16399,16400,16401,16402,16403,16404,16405,16406,16407,16408,16409,16410,16411,16412,16413,16414,16415,16416,16417,16418,16419,16420,16421,16422,16423,16424,16425,16426,16427,16428,16429,16430,16431,16432,16433,16434,16435,16436,16437,16438,16439,16440,16441,16442,16443,16444,16445,16446,16447,16448,16449,16450,16451,16452,16453,16454,16455,16456,16457,16458,16459,16460,16461,16462,16463,16464,16465,16466,16467,16468,16469,16470,16471,16472,16473,16474,16475,16476,16477,16478,16479,16480,16481,16482,16483,16484,16485,16486,16487,16488,16489,16490,16491,16492,16493,16494,16495,16496,16497,16498,16499,16500,16501,16502,16503,16504,16505,16506,16507,16508,16509,16510,16511,16512,16513,16514,16515,16516,16517,16518,16519,16520,16521,16522,16523,16524,16525,16526,16527,16528,16529,16530,16531,16532,16533,16534,16535,16536,16537,16538,16539,16540,16541,16542,16543,16544,16545,16546,16547,16548,16549,16550,16551,16552,16553,16554,16555,16556,16557,16558,16559,16560,16561,16562,16563,16564,16565,16566,16567,16568,16569,16570,16571,16572,16573,16574,16575,16576,16577,16578,16579,16580,16581,16582,16583,16584,16585,16586,16587,16588,16589,16590,16591,16592,16593,16594,16595,16596,16597,16598,16599,16600,16601,16602,16603,16604,16605,16606,16607,16608,16609,16610,16611,16612,16613,16614,16615,16616,16617,16618,16619,16620,16621,16622,16623,16624,16625,16626,16627,16628,16629,16630,16631,16632,16633,16634,16635,16636,16637,16638,16639,16640,16641,16642,16643,16644,16645,16646,16647,16648,16649,16650,16651,16652,16653,16654,16655,16656,16657,16658,16659,16660,16661,16662,16663,16664,16665,16666,16667,16668,16669,16670,16671,16672,16673,16674,16675,16676,16677,16678,16679,16680,16681,16682,16683,16684,16685,16686,16687,16688,16689,16690,16691,16692,16693,16694,16695,16696,16697,16698,16699,16700,16701,16702,16703,16704,16705,16706,16707,16708,16709,16710,16711,16712,16713,16714,16715,16716,16717,16718,16719,16720,16721,16722,16723,16724,16725,16726,16727,16728,16729,16730,16731,16732,16733,16734,16735,16736,16737,16738,16739,16740,16741,16742,16743,16744,16745,16746,16747,16748,16749,16750,16751,16752,16753,16754,16755,16756,16757,16758,16759,16760,16761,16762,16763,16764,16765,16766,16767,16768,16769,16770,16771,16772,16773,16774,16775,16776,16777,16778,16779,16780,16781,16782,16783,16784,16785,16786,16787,16788,16789,16790,16791,16792,16793,16794,16795,16796,16797,16798,16799,16800,16801,16802,16803,16804,16805,16806,16807,16808,16809,16810,16811,16812,16813,16814,16815,16816,16817,16818,16819,16820,16821,16822,16823,16824,16825,16826,16827,16828,16829,16830,16831,16832,16833,16834,16835,16836,16837,16838,16839,16840,16841,16842,16843,16844,16845,16846,16847,16848,16849,16850,16851,16852,16853,16854,16855,16856,16857,16858,16859,16860,16861,16862,16863,16864,16865,16866,16867,16868,16869,16870,16871,16872,16873,16874,16875,16876,16877,16878,16879,16880,16881,16882,16883,16884,16885,16886,16887,16888,16889,16890,16891,16892,16893,16894,16895,16896,16897,16898,16899,16900,16901,16902,16903,16904,16905,16906,16907,16908,16909,16910,16911,16912,16913,16914,16915,16916,16917,16918,16919,16920,16921,16922,16923,16924,16925,16926,16927,16928,16929,16930,16931,16932,16933,16934,16935,16936,16937,16938,16939,16940,16941,16942,16943,16944,16945,16946,16947,16948,16949,16950,16951,16952,16953,16954,16955,16956,16957,16958,16959,16960,16961,16962,16963,16964,16965,16966,16967,16968,16969,16970,16971,16972,16973,16974,16975,16976,16977,16978,16979,16980,16981,16982,16983,16984,16985,16986,16987,16988,16989,16990,16991,16992,16993,16994,16995,16996,16997,16998,16999,17000,17001,17002,17003,17004,17005,17006,17007,17008,17009,17010,17011,17012,17013,17014,17015,17016,17017,17018,17019,17020,17021,17022,17023,17024,17025,17026,17027,17028,17029,17030,17031,17032,17033,17034,17035,17036,17037,17038,17039,17040,17041,17042,17043,17044,17045,17046,17047,17048,17049,17050,17051,17052,17053,17054,17055,17056,17057,17058,17059,17060,17061,17062,17063,17064,17065,17066,17067,17068,17069,17070,17071,17072,17073,17074,17075,17076,17077,17078,17079,17080,17081,17082,17083,17084,17085,17086,17087,17088,17089,17090,17091,17092,17093,17094,17095,17096,17097,17098,17099,17100,17101,17102,17103,17104,17105,17106,17107,17108,17109,17110,17111,17112,17113,17114,17115,17116,17117,17118,17119,17120,17121,17122,17123,17124,17125,17126,17127,17128,17129,17130,17131,17132,17133,17134,17135,17136,17137,17138,17139,17140,17141,17142,17143,17144,17145,17146,17147,17148,17149,17150,17151,17152,17153,17154,17155,17156,17157,17158,17159,17160,17161,17162,17163,17164,17165,17166,17167,17168,17169,17170,17171,17172,17173,17174,17175,17176,17177,17178,17179,17180,17181,17182,17183,17184,17185,17186,17187,17188,17189,17190,17191,17192,17193,17194,17195,17196,17197,17198,17199,17200,17201,17202,17203,17204,17205,17206,17207,17208,17209,17210,17211,17212,17213,17214,17215,17216,17217,17218,17219,17220,17221,17222,17223,17224,17225,17226,17227,17228,17229,17230,17231,17232,17233,17234,17235,17236,17237,17238,17239,17240,17241,17242,17243,17244,17245,17246,17247,17248,17249,17250,17251,17252,17253,17254,17255,17256,17257,17258,17259,17260,17261,17262,17263,17264,17265,17266,17267,17268,17269,17270,17271,17272,17273,17274,17275,17276,17277,17278,17279,17280,17281,17282,17283,17284,17285,17286,17287,17288,17289,17290,17291,17292,17293,17294,17295,17296,17297,17298,17299,17300,17301,17302,17303,17304,17305,17306,17307,17308,17309,17310,17311,17312,17313,17314,17315,17316,17317,17318,17319,17320,17321,17322,17323,17324,17325,17326,17327,17328,17329,17330,17331,17332,17333,17334,17335,17336,17337,17338,17339,17340,17341,17342,17343,17344,17345,17346,17347,17348,17349,17350,17351,17352,17353,17354,17355,17356,17357,17358,17359,17360,17361,17362,17363,17364,17365,17366,17367,17368,17369,17370,17371,17372,17373,17374,17375,17376,17377,17378,17379,17380,17381,17382,17383,17384,17385,17386,17387,17388,17389,17390,17391,17392,17393,17394,17395,17396,17397,17398,17399,17400,17401,17402,17403,17404,17405,17406,17407,17408,17409,17410,17411,17412,17413,17414,17415,17416,17417,17418,17419,17420,17421,17422,17423,17424,17425,17426,17427,17428,17429,17430,17431,17432,17433,17434,17435,17436,17437,17438,17439,17440,17441,17442,17443,17444,17445,17446,17447,17448,17449,17450,17451,17452,17453,17454,17455,17456,17457,17458,17459,17460,17461,17462,17463,17464,17465,17466,17467,17468,17469,17470,17471,17472,17473,17474,17475,17476,17477,17478,17479,17480,17481,17482,17483,17484,17485,17486,17487,17488,17489,17490,17491,17492,17493,17494,17495,17496,17497,17498,17499,17500,17501,17502,17503,17504,17505,17506,17507,17508,17509,17510,17511,17512,17513,17514,17515,17516,17517,17518,17519,17520,17521,17522,17523,17524,17525,17526,17527,17528,17529,17530,17531,17532,17533,17534,17535,17536,17537,17538,17539,17540,17541,17542,17543,17544,17545,17546,17547,17548,17549,17550,17551,17552,17553,17554,17555,17556,17557,17558,17559,17560,17561,17562,17563,17564,17565,17566,17567,17568,17569,17570,17571,17572,17573,17574,17575,17576,17577,17578,17579,17580,17581,17582,17583,17584,17585,17586,17587,17588,17589,17590,17591,17592,17593,17594,17595,17596,17597,17598,17599,17600,17601,17602,17603,17604,17605,17606,17607,17608,17609,17610,17611,17612,17613,17614,17615,17616,17617,17618,17619,17620,17621,17622,17623,17624,17625,17626,17627,17628,17629,17630,17631,17632,17633,17634,17635,17636,17637,17638,17639,17640,17641,17642,17643,17644,17645,17646,17647,17648,17649,17650,17651,17652,17653,17654,17655,17656,17657,17658,17659,17660,17661,17662,17663,17664,17665,17666,17667,17668,17669,17670,17671,17672,17673,17674,17675,17676,17677,17678,17679,17680,17681,17682,17683,17684,17685,17686,17687,17688,17689,17690,17691,17692,17693,17694,17695,17696,17697,17698,17699,17700,17701,17702,17703,17704,17705,17706,17707,17708,17709,17710,17711,17712,17713,17714,17715,17716,17717,17718,17719,17720,17721,17722,17723,17724,17725,17726,17727,17728,17729,17730,17731,17732,17733,17734,17735,17736,17737,17738,17739,17740,17741,17742,17743,17744,17745,17746,17747,17748,17749,17750,17751,17752,17753,17754,17755,17756,17757,17758,17759,17760,17761,17762,17763,17764,17765,17766,17767,17768,17769,17770,17771,17772,17773,17774,17775,17776,17777,17778,17779,17780,17781,17782,17783,17784,17785,17786,17787,17788,17789,17790,17791,17792,17793,17794,17795,17796,17797,17798,17799,17800,17801,17802,17803,17804,17805,17806,17807,17808,17809,17810,17811,17812,17813,17814,17815,17816,17817,17818,17819,17820,17821,17822,17823,17824,17825,17826,17827,17828,17829,17830,17831,17832,17833,17834,17835,17836,17837,17838,17839,17840,17841,17842,17843,17844,17845,17846,17847,17848,17849,17850,17851,17852,17853,17854,17855,17856,17857,17858,17859,17860,17861,17862,17863,17864,17865,17866,17867,17868,17869,17870,17871,17872,17873,17874,17875,17876,17877,17878,17879,17880,17881,17882,17883,17884,17885,17886,17887,17888,17889,17890,17891,17892,17893,17894,17895,17896,17897,17898,17899,17900,17901,17902,17903,17904,17905,17906,17907,17908,17909,17910,17911,17912,17913,17914,17915,17916,17917,17918,17919,17920,17921,17922,17923,17924,17925,17926,17927,17928,17929,17930,17931,17932,17933,17934,17935,17936,17937,17938,17939,17940,17941,17942,17943,17944,17945,17946,17947,17948,17949,17950,17951,17952,17953,17954,17955,17956,17957,17958,17959,17960,17961,17962,17963,17964,17965,17966,17967,17968,17969,17970,17971,17972,17973,17974,17975,17976,17977,17978,17979,17980,17981,17982,17983,17984,17985,17986,17987,17988,17989,17990,17991,17992,17993,17994,17995,17996,17997,17998,17999,18000,18001,18002,18003,18004,18005,18006,18007,18008,18009,18010,18011,18012,18013,18014,18015,18016,18017,18018,18019,18020,18021,18022,18023,18024,18025,18026,18027,18028,18029,18030,18031,18032,18033,18034,18035,18036,18037,18038,18039,18040,18041,18042,18043,18044,18045,18046,18047,18048,18049,18050,18051,18052,18053,18054,18055,18056,18057,18058,18059,18060,18061,18062,18063,18064,18065,18066,18067,18068,18069,18070,18071,18072,18073,18074,18075,18076,18077,18078,18079,18080,18081,18082,18083,18084,18085,18086,18087,18088,18089,18090,18091,18092,18093,18094,18095,18096,18097,18098,18099,18100,18101,18102,18103,18104,18105,18106,18107,18108,18109,18110,18111,18112,18113,18114,18115,18116,18117,18118,18119,18120,18121,18122,18123,18124,18125,18126,18127,18128,18129,18130,18131,18132,18133,18134,18135,18136,18137,18138,18139,18140,18141,18142,18143,18144,18145,18146,18147,18148,18149,18150,18151,18152,18153,18154,18155,18156,18157,18158,18159,18160,18161,18162,18163,18164,18165,18166,18167,18168,18169,18170,18171,18172,18173,18174,18175,18176,18177,18178,18179,18180,18181,18182,18183,18184,18185,18186,18187,18188,18189,18190,18191,18192,18193,18194,18195,18196,18197,18198,18199,18200,18201,18202,18203,18204,18205,18206,18207,18208,18209,18210,18211,18212,18213,18214,18215,18216,18217,18218,18219,18220,18221,18222,18223,18224,18225,18226,18227,18228,18229,18230,18231,18232,18233,18234,18235,18236,18237,18238,18239,18240,18241,18242,18243,18244,18245,18246,18247,18248,18249,18250,18251,18252,18253,18254,18255,18256,18257,18258,18259,18260,18261,18262,18263,18264,18265,18266,18267,18268,18269,18270,18271,18272,18273,18274,18275,18276,18277,18278,18279,18280,18281,18282,18283,18284,18285,18286,18287,18288,18289,18290,18291,18292,18293,18294,18295,18296,18297,18298,18299,18300,18301,18302,18303,18304,18305,18306,18307,18308,18309,18310,18311,18312,18313,18314,18315,18316,18317,18318,18319,18320,18321,18322,18323,18324,18325,18326,18327,18328,18329,18330,18331,18332,18333,18334,18335,18336,18337,18338,18339,18340,18341,18342,18343,18344,18345,18346,18347,18348,18349,18350,18351,18352,18353,18354,18355,18356,18357,18358,18359,18360,18361,18362,18363,18364,18365,18366,18367,18368,18369,18370,18371,18372,18373,18374,18375,18376,18377,18378,18379,18380,18381,18382,18383,18384,18385,18386,18387,18388,18389,18390,18391,18392,18393,18394,18395,18396,18397,18398,18399,18400,18401,18402,18403,18404,18405,18406,18407,18408,18409,18410,18411,18412,18413,18414,18415,18416,18417,18418,18419,18420,18421,18422,18423,18424,18425,18426,18427,18428,18429,18430,18431,18432,18433,18434,18435,18436,18437,18438,18439,18440,18441,18442,18443,18444,18445,18446,18447,18448,18449,18450,18451,18452,18453,18454,18455,18456,18457,18458,18459,18460,18461,18462,18463,18464,18465,18466,18467,18468,18469,18470,18471,18472,18473,18474,18475,18476,18477,18478,18479,18480,18481,18482,18483,18484,18485,18486,18487,18488,18489,18490,18491,18492,18493,18494,18495,18496,18497,18498,18499,18500,18501,18502,18503,18504,18505,18506,18507,18508,18509,18510,18511,18512,18513,18514,18515,18516,18517,18518,18519,18520,18521,18522,18523,18524,18525,18526,18527,18528,18529,18530,18531,18532,18533,18534,18535,18536,18537,18538,18539,18540,18541,18542,18543,18544,18545,18546,18547,18548,18549,18550,18551,18552,18553,18554,18555,18556,18557,18558,18559,18560,18561,18562,18563,18564,18565,18566,18567,18568,18569,18570,18571,18572,18573,18574,18575,18576,18577,18578,18579,18580,18581,18582,18583,18584,18585,18586,18587,18588,18589,18590,18591,18592,18593,18594,18595,18596,18597,18598,18599,18600,18601,18602,18603,18604,18605,18606,18607,18608,18609,18610,18611,18612,18613,18614,18615,18616,18617,18618,18619,18620,18621,18622,18623,18624,18625,18626,18627,18628,18629,18630,18631,18632,18633,18634,18635,18636,18637,18638,18639,18640,18641,18642,18643,18644,18645,18646,18647,18648,18649,18650,18651,18652,18653,18654,18655,18656,18657,18658,18659,18660,18661,18662,18663,18664,18665,18666,18667,18668,18669,18670,18671,18672,18673,18674,18675,18676,18677,18678,18679,18680,18681,18682,18683,18684,18685,18686,18687,18688,18689,18690,18691,18692,18693,18694,18695,18696,18697,18698,18699,18700,18701,18702,18703,18704,18705,18706,18707,18708,18709,18710,18711,18712,18713,18714,18715,18716,18717,18718,18719,18720,18721,18722,18723,18724,18725,18726,18727,18728,18729,18730,18731,18732,18733,18734,18735,18736,18737,18738,18739,18740,18741,18742,18743,18744,18745,18746,18747,18748,18749,18750,18751,18752,18753,18754,18755,18756,18757,18758,18759,18760,18761,18762,18763,18764,18765,18766,18767,18768,18769,18770,18771,18772,18773,18774,18775,18776,18777,18778,18779,18780,18781,18782,18783,18784,18785,18786,18787,18788,18789,18790,18791,18792,18793,18794,18795,18796,18797,18798,18799,18800,18801,18802,18803,18804,18805,18806,18807,18808,18809,18810,18811,18812,18813,18814,18815,18816,18817,18818,18819,18820,18821,18822,18823,18824,18825,18826,18827,18828,18829,18830,18831,18832,18833,18834,18835,18836,18837,18838,18839,18840,18841,18842,18843,18844,18845,18846,18847,18848,18849,18850,18851,18852,18853,18854,18855,18856,18857,18858,18859,18860,18861,18862,18863,18864,18865,18866,18867,18868,18869,18870,18871,18872,18873,18874,18875,18876,18877,18878,18879,18880,18881,18882,18883,18884,18885,18886,18887,18888,18889,18890,18891,18892,18893,18894,18895,18896,18897,18898,18899,18900,18901,18902,18903,18904,18905,18906,18907,18908,18909,18910,18911,18912,18913,18914,18915,18916,18917,18918,18919,18920,18921,18922,18923,18924,18925,18926,18927,18928,18929,18930,18931,18932,18933,18934,18935,18936,18937,18938,18939,18940,18941,18942,18943,18944,18945,18946,18947,18948,18949,18950,18951,18952,18953,18954,18955,18956,18957,18958,18959,18960,18961,18962,18963,18964,18965,18966,18967,18968,18969,18970,18971,18972,18973,18974,18975,18976,18977,18978,18979,18980,18981,18982,18983,18984,18985,18986,18987,18988,18989,18990,18991,18992,18993,18994,18995,18996,18997,18998,18999,19000,19001,19002,19003,19004,19005,19006,19007,19008,19009,19010,19011,19012,19013,19014,19015,19016,19017,19018,19019,19020,19021,19022,19023,19024,19025,19026,19027,19028,19029,19030,19031,19032,19033,19034,19035,19036,19037,19038,19039,19040,19041,19042,19043,19044,19045,19046,19047,19048,19049,19050,19051,19052,19053,19054,19055,19056,19057,19058,19059,19060,19061,19062,19063,19064,19065,19066,19067,19068,19069,19070,19071,19072,19073,19074,19075,19076,19077,19078,19079,19080,19081,19082,19083,19084,19085,19086,19087,19088,19089,19090,19091,19092,19093,19094,19095,19096,19097,19098,19099,19100,19101,19102,19103,19104,19105,19106,19107,19108,19109,19110,19111,19112,19113,19114,19115,19116,19117,19118,19119,19120,19121,19122,19123,19124,19125,19126,19127,19128,19129,19130,19131,19132,19133,19134,19135,19136,19137,19138,19139,19140,19141,19142,19143,19144,19145,19146,19147,19148,19149,19150,19151,19152,19153,19154,19155,19156,19157,19158,19159,19160,19161,19162,19163,19164,19165,19166,19167,19168,19169,19170,19171,19172,19173,19174,19175,19176,19177,19178,19179,19180,19181,19182,19183,19184,19185,19186,19187,19188,19189,19190,19191,19192,19193,19194,19195,19196,19197,19198,19199,19200,19201,19202,19203,19204,19205,19206,19207,19208,19209,19210,19211,19212,19213,19214,19215,19216,19217,19218,19219,19220,19221,19222,19223,19224,19225,19226,19227,19228,19229,19230,19231,19232,19233,19234,19235,19236,19237,19238,19239,19240,19241,19242,19243,19244,19245,19246,19247,19248,19249,19250,19251,19252,19253,19254,19255,19256,19257,19258,19259,19260,19261,19262,19263,19264,19265,19266,19267,19268,19269,19270,19271,19272,19273,19274,19275,19276,19277,19278,19279,19280,19281,19282,19283,19284,19285,19286,19287,19288,19289,19290,19291,19292,19293,19294,19295,19296,19297,19298,19299,19300,19301,19302,19303,19304,19305,19306,19307,19308,19309,19310,19311,19312,19313,19314,19315,19316,19317,19318,19319,19320,19321,19322,19323,19324,19325,19326,19327,19328,19329,19330,19331,19332,19333,19334,19335,19336,19337,19338,19339,19340,19341,19342,19343,19344,19345,19346,19347,19348,19349,19350,19351,19352,19353,19354,19355,19356,19357,19358,19359,19360,19361,19362,19363,19364,19365,19366,19367,19368,19369,19370,19371,19372,19373,19374,19375,19376,19377,19378,19379,19380,19381,19382,19383,19384,19385,19386,19387,19388,19389,19390,19391,19392,19393,19394,19395,19396,19397,19398,19399,19400,19401,19402,19403,19404,19405,19406,19407,19408,19409,19410,19411,19412,19413,19414,19415,19416,19417,19418,19419,19420,19421,19422,19423,19424,19425,19426,19427,19428,19429,19430,19431,19432,19433,19434,19435,19436,19437,19438,19439,19440,19441,19442,19443,19444,19445,19446,19447,19448,19449,19450,19451,19452,19453,19454,19455,19456,19457,19458,19459,19460,19461,19462,19463,19464,19465,19466,19467,19468,19469,19470,19471,19472,19473,19474,19475,19476,19477,19478,19479,19480,19481,19482,19483,19484,19485,19486,19487,19488,19489,19490,19491,19492,19493,19494,19495,19496,19497,19498,19499,19500,19501,19502,19503,19504,19505,19506,19507,19508,19509,19510,19511,19512,19513,19514,19515,19516,19517,19518,19519,19520,19521,19522,19523,19524,19525,19526,19527,19528,19529,19530,19531,19532,19533,19534,19535,19536,19537,19538,19539,19540,19541,19542,19543,19544,19545,19546,19547,19548,19549,19550,19551,19552,19553,19554,19555,19556,19557,19558,19559,19560,19561,19562,19563,19564,19565,19566,19567,19568,19569,19570,19571,19572,19573,19574,19575,19576,19577,19578,19579,19580,19581,19582,19583,19584,19585,19586,19587,19588,19589,19590,19591,19592,19593,19594,19595,19596,19597,19598,19599,19600,19601,19602,19603,19604,19605,19606,19607,19608,19609,19610,19611,19612,19613,19614,19615,19616,19617,19618,19619,19620,19621,19622,19623,19624,19625,19626,19627,19628,19629,19630,19631,19632,19633,19634,19635,19636,19637,19638,19639,19640,19641,19642,19643,19644,19645,19646,19647,19648,19649,19650,19651,19652,19653,19654,19655,19656,19657,19658,19659,19660,19661,19662,19663,19664,19665,19666,19667,19668,19669,19670,19671,19672,19673,19674,19675,19676,19677,19678,19679,19680,19681,19682,19683,19684,19685,19686,19687,19688,19689,19690,19691,19692,19693,19694,19695,19696,19697,19698,19699,19700,19701,19702,19703,19704,19705,19706,19707,19708,19709,19710,19711,19712,19713,19714,19715,19716,19717,19718,19719,19720,19721,19722,19723,19724,19725,19726,19727,19728,19729,19730,19731,19732,19733,19734,19735,19736,19737,19738,19739,19740,19741,19742,19743,19744,19745,19746,19747,19748,19749,19750,19751,19752,19753,19754,19755,19756,19757,19758,19759,19760,19761,19762,19763,19764,19765,19766,19767,19768,19769,19770,19771,19772,19773,19774,19775,19776,19777,19778,19779,19780,19781,19782,19783,19784,19785,19786,19787,19788,19789,19790,19791,19792,19793,19794,19795,19796,19797,19798,19799,19800,19801,19802,19803,19804,19805,19806,19807,19808,19809,19810,19811,19812,19813,19814,19815,19816,19817,19818,19819,19820,19821,19822,19823,19824,19825,19826,19827,19828,19829,19830,19831,19832,19833,19834,19835,19836,19837,19838,19839,19840,19841,19842,19843,19844,19845,19846,19847,19848,19849,19850,19851,19852,19853,19854,19855,19856,19857,19858,19859,19860,19861,19862,19863,19864,19865,19866,19867,19868,19869,19870,19871,19872,19873,19874,19875,19876,19877,19878,19879,19880,19881,19882,19883,19884,19885,19886,19887,19888,19889,19890,19891,19892,19893,19968,19969,19970,19971,19972,19973,19974,19975,19976,19977,19978,19979,19980,19981,19982,19983,19984,19985,19986,19987,19988,19989,19990,19991,19992,19993,19994,19995,19996,19997,19998,19999,20000,20001,20002,20003,20004,20005,20006,20007,20008,20009,20010,20011,20012,20013,20014,20015,20016,20017,20018,20019,20020,20021,20022,20023,20024,20025,20026,20027,20028,20029,20030,20031,20032,20033,20034,20035,20036,20037,20038,20039,20040,20041,20042,20043,20044,20045,20046,20047,20048,20049,20050,20051,20052,20053,20054,20055,20056,20057,20058,20059,20060,20061,20062,20063,20064,20065,20066,20067,20068,20069,20070,20071,20072,20073,20074,20075,20076,20077,20078,20079,20080,20081,20082,20083,20084,20085,20086,20087,20088,20089,20090,20091,20092,20093,20094,20095,20096,20097,20098,20099,20100,20101,20102,20103,20104,20105,20106,20107,20108,20109,20110,20111,20112,20113,20114,20115,20116,20117,20118,20119,20120,20121,20122,20123,20124,20125,20126,20127,20128,20129,20130,20131,20132,20133,20134,20135,20136,20137,20138,20139,20140,20141,20142,20143,20144,20145,20146,20147,20148,20149,20150,20151,20152,20153,20154,20155,20156,20157,20158,20159,20160,20161,20162,20163,20164,20165,20166,20167,20168,20169,20170,20171,20172,20173,20174,20175,20176,20177,20178,20179,20180,20181,20182,20183,20184,20185,20186,20187,20188,20189,20190,20191,20192,20193,20194,20195,20196,20197,20198,20199,20200,20201,20202,20203,20204,20205,20206,20207,20208,20209,20210,20211,20212,20213,20214,20215,20216,20217,20218,20219,20220,20221,20222,20223,20224,20225,20226,20227,20228,20229,20230,20231,20232,20233,20234,20235,20236,20237,20238,20239,20240,20241,20242,20243,20244,20245,20246,20247,20248,20249,20250,20251,20252,20253,20254,20255,20256,20257,20258,20259,20260,20261,20262,20263,20264,20265,20266,20267,20268,20269,20270,20271,20272,20273,20274,20275,20276,20277,20278,20279,20280,20281,20282,20283,20284,20285,20286,20287,20288,20289,20290,20291,20292,20293,20294,20295,20296,20297,20298,20299,20300,20301,20302,20303,20304,20305,20306,20307,20308,20309,20310,20311,20312,20313,20314,20315,20316,20317,20318,20319,20320,20321,20322,20323,20324,20325,20326,20327,20328,20329,20330,20331,20332,20333,20334,20335,20336,20337,20338,20339,20340,20341,20342,20343,20344,20345,20346,20347,20348,20349,20350,20351,20352,20353,20354,20355,20356,20357,20358,20359,20360,20361,20362,20363,20364,20365,20366,20367,20368,20369,20370,20371,20372,20373,20374,20375,20376,20377,20378,20379,20380,20381,20382,20383,20384,20385,20386,20387,20388,20389,20390,20391,20392,20393,20394,20395,20396,20397,20398,20399,20400,20401,20402,20403,20404,20405,20406,20407,20408,20409,20410,20411,20412,20413,20414,20415,20416,20417,20418,20419,20420,20421,20422,20423,20424,20425,20426,20427,20428,20429,20430,20431,20432,20433,20434,20435,20436,20437,20438,20439,20440,20441,20442,20443,20444,20445,20446,20447,20448,20449,20450,20451,20452,20453,20454,20455,20456,20457,20458,20459,20460,20461,20462,20463,20464,20465,20466,20467,20468,20469,20470,20471,20472,20473,20474,20475,20476,20477,20478,20479,20480,20481,20482,20483,20484,20485,20486,20487,20488,20489,20490,20491,20492,20493,20494,20495,20496,20497,20498,20499,20500,20501,20502,20503,20504,20505,20506,20507,20508,20509,20510,20511,20512,20513,20514,20515,20516,20517,20518,20519,20520,20521,20522,20523,20524,20525,20526,20527,20528,20529,20530,20531,20532,20533,20534,20535,20536,20537,20538,20539,20540,20541,20542,20543,20544,20545,20546,20547,20548,20549,20550,20551,20552,20553,20554,20555,20556,20557,20558,20559,20560,20561,20562,20563,20564,20565,20566,20567,20568,20569,20570,20571,20572,20573,20574,20575,20576,20577,20578,20579,20580,20581,20582,20583,20584,20585,20586,20587,20588,20589,20590,20591,20592,20593,20594,20595,20596,20597,20598,20599,20600,20601,20602,20603,20604,20605,20606,20607,20608,20609,20610,20611,20612,20613,20614,20615,20616,20617,20618,20619,20620,20621,20622,20623,20624,20625,20626,20627,20628,20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,20639,20640,20641,20642,20643,20644,20645,20646,20647,20648,20649,20650,20651,20652,20653,20654,20655,20656,20657,20658,20659,20660,20661,20662,20663,20664,20665,20666,20667,20668,20669,20670,20671,20672,20673,20674,20675,20676,20677,20678,20679,20680,20681,20682,20683,20684,20685,20686,20687,20688,20689,20690,20691,20692,20693,20694,20695,20696,20697,20698,20699,20700,20701,20702,20703,20704,20705,20706,20707,20708,20709,20710,20711,20712,20713,20714,20715,20716,20717,20718,20719,20720,20721,20722,20723,20724,20725,20726,20727,20728,20729,20730,20731,20732,20733,20734,20735,20736,20737,20738,20739,20740,20741,20742,20743,20744,20745,20746,20747,20748,20749,20750,20751,20752,20753,20754,20755,20756,20757,20758,20759,20760,20761,20762,20763,20764,20765,20766,20767,20768,20769,20770,20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782,20783,20784,20785,20786,20787,20788,20789,20790,20791,20792,20793,20794,20795,20796,20797,20798,20799,20800,20801,20802,20803,20804,20805,20806,20807,20808,20809,20810,20811,20812,20813,20814,20815,20816,20817,20818,20819,20820,20821,20822,20823,20824,20825,20826,20827,20828,20829,20830,20831,20832,20833,20834,20835,20836,20837,20838,20839,20840,20841,20842,20843,20844,20845,20846,20847,20848,20849,20850,20851,20852,20853,20854,20855,20856,20857,20858,20859,20860,20861,20862,20863,20864,20865,20866,20867,20868,20869,20870,20871,20872,20873,20874,20875,20876,20877,20878,20879,20880,20881,20882,20883,20884,20885,20886,20887,20888,20889,20890,20891,20892,20893,20894,20895,20896,20897,20898,20899,20900,20901,20902,20903,20904,20905,20906,20907,20908,20909,20910,20911,20912,20913,20914,20915,20916,20917,20918,20919,20920,20921,20922,20923,20924,20925,20926,20927,20928,20929,20930,20931,20932,20933,20934,20935,20936,20937,20938,20939,20940,20941,20942,20943,20944,20945,20946,20947,20948,20949,20950,20951,20952,20953,20954,20955,20956,20957,20958,20959,20960,20961,20962,20963,20964,20965,20966,20967,20968,20969,20970,20971,20972,20973,20974,20975,20976,20977,20978,20979,20980,20981,20982,20983,20984,20985,20986,20987,20988,20989,20990,20991,20992,20993,20994,20995,20996,20997,20998,20999,21000,21001,21002,21003,21004,21005,21006,21007,21008,21009,21010,21011,21012,21013,21014,21015,21016,21017,21018,21019,21020,21021,21022,21023,21024,21025,21026,21027,21028,21029,21030,21031,21032,21033,21034,21035,21036,21037,21038,21039,21040,21041,21042,21043,21044,21045,21046,21047,21048,21049,21050,21051,21052,21053,21054,21055,21056,21057,21058,21059,21060,21061,21062,21063,21064,21065,21066,21067,21068,21069,21070,21071,21072,21073,21074,21075,21076,21077,21078,21079,21080,21081,21082,21083,21084,21085,21086,21087,21088,21089,21090,21091,21092,21093,21094,21095,21096,21097,21098,21099,21100,21101,21102,21103,21104,21105,21106,21107,21108,21109,21110,21111,21112,21113,21114,21115,21116,21117,21118,21119,21120,21121,21122,21123,21124,21125,21126,21127,21128,21129,21130,21131,21132,21133,21134,21135,21136,21137,21138,21139,21140,21141,21142,21143,21144,21145,21146,21147,21148,21149,21150,21151,21152,21153,21154,21155,21156,21157,21158,21159,21160,21161,21162,21163,21164,21165,21166,21167,21168,21169,21170,21171,21172,21173,21174,21175,21176,21177,21178,21179,21180,21181,21182,21183,21184,21185,21186,21187,21188,21189,21190,21191,21192,21193,21194,21195,21196,21197,21198,21199,21200,21201,21202,21203,21204,21205,21206,21207,21208,21209,21210,21211,21212,21213,21214,21215,21216,21217,21218,21219,21220,21221,21222,21223,21224,21225,21226,21227,21228,21229,21230,21231,21232,21233,21234,21235,21236,21237,21238,21239,21240,21241,21242,21243,21244,21245,21246,21247,21248,21249,21250,21251,21252,21253,21254,21255,21256,21257,21258,21259,21260,21261,21262,21263,21264,21265,21266,21267,21268,21269,21270,21271,21272,21273,21274,21275,21276,21277,21278,21279,21280,21281,21282,21283,21284,21285,21286,21287,21288,21289,21290,21291,21292,21293,21294,21295,21296,21297,21298,21299,21300,21301,21302,21303,21304,21305,21306,21307,21308,21309,21310,21311,21312,21313,21314,21315,21316,21317,21318,21319,21320,21321,21322,21323,21324,21325,21326,21327,21328,21329,21330,21331,21332,21333,21334,21335,21336,21337,21338,21339,21340,21341,21342,21343,21344,21345,21346,21347,21348,21349,21350,21351,21352,21353,21354,21355,21356,21357,21358,21359,21360,21361,21362,21363,21364,21365,21366,21367,21368,21369,21370,21371,21372,21373,21374,21375,21376,21377,21378,21379,21380,21381,21382,21383,21384,21385,21386,21387,21388,21389,21390,21391,21392,21393,21394,21395,21396,21397,21398,21399,21400,21401,21402,21403,21404,21405,21406,21407,21408,21409,21410,21411,21412,21413,21414,21415,21416,21417,21418,21419,21420,21421,21422,21423,21424,21425,21426,21427,21428,21429,21430,21431,21432,21433,21434,21435,21436,21437,21438,21439,21440,21441,21442,21443,21444,21445,21446,21447,21448,21449,21450,21451,21452,21453,21454,21455,21456,21457,21458,21459,21460,21461,21462,21463,21464,21465,21466,21467,21468,21469,21470,21471,21472,21473,21474,21475,21476,21477,21478,21479,21480,21481,21482,21483,21484,21485,21486,21487,21488,21489,21490,21491,21492,21493,21494,21495,21496,21497,21498,21499,21500,21501,21502,21503,21504,21505,21506,21507,21508,21509,21510,21511,21512,21513,21514,21515,21516,21517,21518,21519,21520,21521,21522,21523,21524,21525,21526,21527,21528,21529,21530,21531,21532,21533,21534,21535,21536,21537,21538,21539,21540,21541,21542,21543,21544,21545,21546,21547,21548,21549,21550,21551,21552,21553,21554,21555,21556,21557,21558,21559,21560,21561,21562,21563,21564,21565,21566,21567,21568,21569,21570,21571,21572,21573,21574,21575,21576,21577,21578,21579,21580,21581,21582,21583,21584,21585,21586,21587,21588,21589,21590,21591,21592,21593,21594,21595,21596,21597,21598,21599,21600,21601,21602,21603,21604,21605,21606,21607,21608,21609,21610,21611,21612,21613,21614,21615,21616,21617,21618,21619,21620,21621,21622,21623,21624,21625,21626,21627,21628,21629,21630,21631,21632,21633,21634,21635,21636,21637,21638,21639,21640,21641,21642,21643,21644,21645,21646,21647,21648,21649,21650,21651,21652,21653,21654,21655,21656,21657,21658,21659,21660,21661,21662,21663,21664,21665,21666,21667,21668,21669,21670,21671,21672,21673,21674,21675,21676,21677,21678,21679,21680,21681,21682,21683,21684,21685,21686,21687,21688,21689,21690,21691,21692,21693,21694,21695,21696,21697,21698,21699,21700,21701,21702,21703,21704,21705,21706,21707,21708,21709,21710,21711,21712,21713,21714,21715,21716,21717,21718,21719,21720,21721,21722,21723,21724,21725,21726,21727,21728,21729,21730,21731,21732,21733,21734,21735,21736,21737,21738,21739,21740,21741,21742,21743,21744,21745,21746,21747,21748,21749,21750,21751,21752,21753,21754,21755,21756,21757,21758,21759,21760,21761,21762,21763,21764,21765,21766,21767,21768,21769,21770,21771,21772,21773,21774,21775,21776,21777,21778,21779,21780,21781,21782,21783,21784,21785,21786,21787,21788,21789,21790,21791,21792,21793,21794,21795,21796,21797,21798,21799,21800,21801,21802,21803,21804,21805,21806,21807,21808,21809,21810,21811,21812,21813,21814,21815,21816,21817,21818,21819,21820,21821,21822,21823,21824,21825,21826,21827,21828,21829,21830,21831,21832,21833,21834,21835,21836,21837,21838,21839,21840,21841,21842,21843,21844,21845,21846,21847,21848,21849,21850,21851,21852,21853,21854,21855,21856,21857,21858,21859,21860,21861,21862,21863,21864,21865,21866,21867,21868,21869,21870,21871,21872,21873,21874,21875,21876,21877,21878,21879,21880,21881,21882,21883,21884,21885,21886,21887,21888,21889,21890,21891,21892,21893,21894,21895,21896,21897,21898,21899,21900,21901,21902,21903,21904,21905,21906,21907,21908,21909,21910,21911,21912,21913,21914,21915,21916,21917,21918,21919,21920,21921,21922,21923,21924,21925,21926,21927,21928,21929,21930,21931,21932,21933,21934,21935,21936,21937,21938,21939,21940,21941,21942,21943,21944,21945,21946,21947,21948,21949,21950,21951,21952,21953,21954,21955,21956,21957,21958,21959,21960,21961,21962,21963,21964,21965,21966,21967,21968,21969,21970,21971,21972,21973,21974,21975,21976,21977,21978,21979,21980,21981,21982,21983,21984,21985,21986,21987,21988,21989,21990,21991,21992,21993,21994,21995,21996,21997,21998,21999,22000,22001,22002,22003,22004,22005,22006,22007,22008,22009,22010,22011,22012,22013,22014,22015,22016,22017,22018,22019,22020,22021,22022,22023,22024,22025,22026,22027,22028,22029,22030,22031,22032,22033,22034,22035,22036,22037,22038,22039,22040,22041,22042,22043,22044,22045,22046,22047,22048,22049,22050,22051,22052,22053,22054,22055,22056,22057,22058,22059,22060,22061,22062,22063,22064,22065,22066,22067,22068,22069,22070,22071,22072,22073,22074,22075,22076,22077,22078,22079,22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22092,22093,22094,22095,22096,22097,22098,22099,22100,22101,22102,22103,22104,22105,22106,22107,22108,22109,22110,22111,22112,22113,22114,22115,22116,22117,22118,22119,22120,22121,22122,22123,22124,22125,22126,22127,22128,22129,22130,22131,22132,22133,22134,22135,22136,22137,22138,22139,22140,22141,22142,22143,22144,22145,22146,22147,22148,22149,22150,22151,22152,22153,22154,22155,22156,22157,22158,22159,22160,22161,22162,22163,22164,22165,22166,22167,22168,22169,22170,22171,22172,22173,22174,22175,22176,22177,22178,22179,22180,22181,22182,22183,22184,22185,22186,22187,22188,22189,22190,22191,22192,22193,22194,22195,22196,22197,22198,22199,22200,22201,22202,22203,22204,22205,22206,22207,22208,22209,22210,22211,22212,22213,22214,22215,22216,22217,22218,22219,22220,22221,22222,22223,22224,22225,22226,22227,22228,22229,22230,22231,22232,22233,22234,22235,22236,22237,22238,22239,22240,22241,22242,22243,22244,22245,22246,22247,22248,22249,22250,22251,22252,22253,22254,22255,22256,22257,22258,22259,22260,22261,22262,22263,22264,22265,22266,22267,22268,22269,22270,22271,22272,22273,22274,22275,22276,22277,22278,22279,22280,22281,22282,22283,22284,22285,22286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,22298,22299,22300,22301,22302,22303,22304,22305,22306,22307,22308,22309,22310,22311,22312,22313,22314,22315,22316,22317,22318,22319,22320,22321,22322,22323,22324,22325,22326,22327,22328,22329,22330,22331,22332,22333,22334,22335,22336,22337,22338,22339,22340,22341,22342,22343,22344,22345,22346,22347,22348,22349,22350,22351,22352,22353,22354,22355,22356,22357,22358,22359,22360,22361,22362,22363,22364,22365,22366,22367,22368,22369,22370,22371,22372,22373,22374,22375,22376,22377,22378,22379,22380,22381,22382,22383,22384,22385,22386,22387,22388,22389,22390,22391,22392,22393,22394,22395,22396,22397,22398,22399,22400,22401,22402,22403,22404,22405,22406,22407,22408,22409,22410,22411,22412,22413,22414,22415,22416,22417,22418,22419,22420,22421,22422,22423,22424,22425,22426,22427,22428,22429,22430,22431,22432,22433,22434,22435,22436,22437,22438,22439,22440,22441,22442,22443,22444,22445,22446,22447,22448,22449,22450,22451,22452,22453,22454,22455,22456,22457,22458,22459,22460,22461,22462,22463,22464,22465,22466,22467,22468,22469,22470,22471,22472,22473,22474,22475,22476,22477,22478,22479,22480,22481,22482,22483,22484,22485,22486,22487,22488,22489,22490,22491,22492,22493,22494,22495,22496,22497,22498,22499,22500,22501,22502,22503,22504,22505,22506,22507,22508,22509,22510,22511,22512,22513,22514,22515,22516,22517,22518,22519,22520,22521,22522,22523,22524,22525,22526,22527,22528,22529,22530,22531,22532,22533,22534,22535,22536,22537,22538,22539,22540,22541,22542,22543,22544,22545,22546,22547,22548,22549,22550,22551,22552,22553,22554,22555,22556,22557,22558,22559,22560,22561,22562,22563,22564,22565,22566,22567,22568,22569,22570,22571,22572,22573,22574,22575,22576,22577,22578,22579,22580,22581,22582,22583,22584,22585,22586,22587,22588,22589,22590,22591,22592,22593,22594,22595,22596,22597,22598,22599,22600,22601,22602,22603,22604,22605,22606,22607,22608,22609,22610,22611,22612,22613,22614,22615,22616,22617,22618,22619,22620,22621,22622,22623,22624,22625,22626,22627,22628,22629,22630,22631,22632,22633,22634,22635,22636,22637,22638,22639,22640,22641,22642,22643,22644,22645,22646,22647,22648,22649,22650,22651,22652,22653,22654,22655,22656,22657,22658,22659,22660,22661,22662,22663,22664,22665,22666,22667,22668,22669,22670,22671,22672,22673,22674,22675,22676,22677,22678,22679,22680,22681,22682,22683,22684,22685,22686,22687,22688,22689,22690,22691,22692,22693,22694,22695,22696,22697,22698,22699,22700,22701,22702,22703,22704,22705,22706,22707,22708,22709,22710,22711,22712,22713,22714,22715,22716,22717,22718,22719,22720,22721,22722,22723,22724,22725,22726,22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,22737,22738,22739,22740,22741,22742,22743,22744,22745,22746,22747,22748,22749,22750,22751,22752,22753,22754,22755,22756,22757,22758,22759,22760,22761,22762,22763,22764,22765,22766,22767,22768,22769,22770,22771,22772,22773,22774,22775,22776,22777,22778,22779,22780,22781,22782,22783,22784,22785,22786,22787,22788,22789,22790,22791,22792,22793,22794,22795,22796,22797,22798,22799,22800,22801,22802,22803,22804,22805,22806,22807,22808,22809,22810,22811,22812,22813,22814,22815,22816,22817,22818,22819,22820,22821,22822,22823,22824,22825,22826,22827,22828,22829,22830,22831,22832,22833,22834,22835,22836,22837,22838,22839,22840,22841,22842,22843,22844,22845,22846,22847,22848,22849,22850,22851,22852,22853,22854,22855,22856,22857,22858,22859,22860,22861,22862,22863,22864,22865,22866,22867,22868,22869,22870,22871,22872,22873,22874,22875,22876,22877,22878,22879,22880,22881,22882,22883,22884,22885,22886,22887,22888,22889,22890,22891,22892,22893,22894,22895,22896,22897,22898,22899,22900,22901,22902,22903,22904,22905,22906,22907,22908,22909,22910,22911,22912,22913,22914,22915,22916,22917,22918,22919,22920,22921,22922,22923,22924,22925,22926,22927,22928,22929,22930,22931,22932,22933,22934,22935,22936,22937,22938,22939,22940,22941,22942,22943,22944,22945,22946,22947,22948,22949,22950,22951,22952,22953,22954,22955,22956,22957,22958,22959,22960,22961,22962,22963,22964,22965,22966,22967,22968,22969,22970,22971,22972,22973,22974,22975,22976,22977,22978,22979,22980,22981,22982,22983,22984,22985,22986,22987,22988,22989,22990,22991,22992,22993,22994,22995,22996,22997,22998,22999,23000,23001,23002,23003,23004,23005,23006,23007,23008,23009,23010,23011,23012,23013,23014,23015,23016,23017,23018,23019,23020,23021,23022,23023,23024,23025,23026,23027,23028,23029,23030,23031,23032,23033,23034,23035,23036,23037,23038,23039,23040,23041,23042,23043,23044,23045,23046,23047,23048,23049,23050,23051,23052,23053,23054,23055,23056,23057,23058,23059,23060,23061,23062,23063,23064,23065,23066,23067,23068,23069,23070,23071,23072,23073,23074,23075,23076,23077,23078,23079,23080,23081,23082,23083,23084,23085,23086,23087,23088,23089,23090,23091,23092,23093,23094,23095,23096,23097,23098,23099,23100,23101,23102,23103,23104,23105,23106,23107,23108,23109,23110,23111,23112,23113,23114,23115,23116,23117,23118,23119,23120,23121,23122,23123,23124,23125,23126,23127,23128,23129,23130,23131,23132,23133,23134,23135,23136,23137,23138,23139,23140,23141,23142,23143,23144,23145,23146,23147,23148,23149,23150,23151,23152,23153,23154,23155,23156,23157,23158,23159,23160,23161,23162,23163,23164,23165,23166,23167,23168,23169,23170,23171,23172,23173,23174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185,23186,23187,23188,23189,23190,23191,23192,23193,23194,23195,23196,23197,23198,23199,23200,23201,23202,23203,23204,23205,23206,23207,23208,23209,23210,23211,23212,23213,23214,23215,23216,23217,23218,23219,23220,23221,23222,23223,23224,23225,23226,23227,23228,23229,23230,23231,23232,23233,23234,23235,23236,23237,23238,23239,23240,23241,23242,23243,23244,23245,23246,23247,23248,23249,23250,23251,23252,23253,23254,23255,23256,23257,23258,23259,23260,23261,23262,23263,23264,23265,23266,23267,23268,23269,23270,23271,23272,23273,23274,23275,23276,23277,23278,23279,23280,23281,23282,23283,23284,23285,23286,23287,23288,23289,23290,23291,23292,23293,23294,23295,23296,23297,23298,23299,23300,23301,23302,23303,23304,23305,23306,23307,23308,23309,23310,23311,23312,23313,23314,23315,23316,23317,23318,23319,23320,23321,23322,23323,23324,23325,23326,23327,23328,23329,23330,23331,23332,23333,23334,23335,23336,23337,23338,23339,23340,23341,23342,23343,23344,23345,23346,23347,23348,23349,23350,23351,23352,23353,23354,23355,23356,23357,23358,23359,23360,23361,23362,23363,23364,23365,23366,23367,23368,23369,23370,23371,23372,23373,23374,23375,23376,23377,23378,23379,23380,23381,23382,23383,23384,23385,23386,23387,23388,23389,23390,23391,23392,23393,23394,23395,23396,23397,23398,23399,23400,23401,23402,23403,23404,23405,23406,23407,23408,23409,23410,23411,23412,23413,23414,23415,23416,23417,23418,23419,23420,23421,23422,23423,23424,23425,23426,23427,23428,23429,23430,23431,23432,23433,23434,23435,23436,23437,23438,23439,23440,23441,23442,23443,23444,23445,23446,23447,23448,23449,23450,23451,23452,23453,23454,23455,23456,23457,23458,23459,23460,23461,23462,23463,23464,23465,23466,23467,23468,23469,23470,23471,23472,23473,23474,23475,23476,23477,23478,23479,23480,23481,23482,23483,23484,23485,23486,23487,23488,23489,23490,23491,23492,23493,23494,23495,23496,23497,23498,23499,23500,23501,23502,23503,23504,23505,23506,23507,23508,23509,23510,23511,23512,23513,23514,23515,23516,23517,23518,23519,23520,23521,23522,23523,23524,23525,23526,23527,23528,23529,23530,23531,23532,23533,23534,23535,23536,23537,23538,23539,23540,23541,23542,23543,23544,23545,23546,23547,23548,23549,23550,23551,23552,23553,23554,23555,23556,23557,23558,23559,23560,23561,23562,23563,23564,23565,23566,23567,23568,23569,23570,23571,23572,23573,23574,23575,23576,23577,23578,23579,23580,23581,23582,23583,23584,23585,23586,23587,23588,23589,23590,23591,23592,23593,23594,23595,23596,23597,23598,23599,23600,23601,23602,23603,23604,23605,23606,23607,23608,23609,23610,23611,23612,23613,23614,23615,23616,23617,23618,23619,23620,23621,23622,23623,23624,23625,23626,23627,23628,23629,23630,23631,23632,23633,23634,23635,23636,23637,23638,23639,23640,23641,23642,23643,23644,23645,23646,23647,23648,23649,23650,23651,23652,23653,23654,23655,23656,23657,23658,23659,23660,23661,23662,23663,23664,23665,23666,23667,23668,23669,23670,23671,23672,23673,23674,23675,23676,23677,23678,23679,23680,23681,23682,23683,23684,23685,23686,23687,23688,23689,23690,23691,23692,23693,23694,23695,23696,23697,23698,23699,23700,23701,23702,23703,23704,23705,23706,23707,23708,23709,23710,23711,23712,23713,23714,23715,23716,23717,23718,23719,23720,23721,23722,23723,23724,23725,23726,23727,23728,23729,23730,23731,23732,23733,23734,23735,23736,23737,23738,23739,23740,23741,23742,23743,23744,23745,23746,23747,23748,23749,23750,23751,23752,23753,23754,23755,23756,23757,23758,23759,23760,23761,23762,23763,23764,23765,23766,23767,23768,23769,23770,23771,23772,23773,23774,23775,23776,23777,23778,23779,23780,23781,23782,23783,23784,23785,23786,23787,23788,23789,23790,23791,23792,23793,23794,23795,23796,23797,23798,23799,23800,23801,23802,23803,23804,23805,23806,23807,23808,23809,23810,23811,23812,23813,23814,23815,23816,23817,23818,23819,23820,23821,23822,23823,23824,23825,23826,23827,23828,23829,23830,23831,23832,23833,23834,23835,23836,23837,23838,23839,23840,23841,23842,23843,23844,23845,23846,23847,23848,23849,23850,23851,23852,23853,23854,23855,23856,23857,23858,23859,23860,23861,23862,23863,23864,23865,23866,23867,23868,23869,23870,23871,23872,23873,23874,23875,23876,23877,23878,23879,23880,23881,23882,23883,23884,23885,23886,23887,23888,23889,23890,23891,23892,23893,23894,23895,23896,23897,23898,23899,23900,23901,23902,23903,23904,23905,23906,23907,23908,23909,23910,23911,23912,23913,23914,23915,23916,23917,23918,23919,23920,23921,23922,23923,23924,23925,23926,23927,23928,23929,23930,23931,23932,23933,23934,23935,23936,23937,23938,23939,23940,23941,23942,23943,23944,23945,23946,23947,23948,23949,23950,23951,23952,23953,23954,23955,23956,23957,23958,23959,23960,23961,23962,23963,23964,23965,23966,23967,23968,23969,23970,23971,23972,23973,23974,23975,23976,23977,23978,23979,23980,23981,23982,23983,23984,23985,23986,23987,23988,23989,23990,23991,23992,23993,23994,23995,23996,23997,23998,23999,24000,24001,24002,24003,24004,24005,24006,24007,24008,24009,24010,24011,24012,24013,24014,24015,24016,24017,24018,24019,24020,24021,24022,24023,24024,24025,24026,24027,24028,24029,24030,24031,24032,24033,24034,24035,24036,24037,24038,24039,24040,24041,24042,24043,24044,24045,24046,24047,24048,24049,24050,24051,24052,24053,24054,24055,24056,24057,24058,24059,24060,24061,24062,24063,24064,24065,24066,24067,24068,24069,24070,24071,24072,24073,24074,24075,24076,24077,24078,24079,24080,24081,24082,24083,24084,24085,24086,24087,24088,24089,24090,24091,24092,24093,24094,24095,24096,24097,24098,24099,24100,24101,24102,24103,24104,24105,24106,24107,24108,24109,24110,24111,24112,24113,24114,24115,24116,24117,24118,24119,24120,24121,24122,24123,24124,24125,24126,24127,24128,24129,24130,24131,24132,24133,24134,24135,24136,24137,24138,24139,24140,24141,24142,24143,24144,24145,24146,24147,24148,24149,24150,24151,24152,24153,24154,24155,24156,24157,24158,24159,24160,24161,24162,24163,24164,24165,24166,24167,24168,24169,24170,24171,24172,24173,24174,24175,24176,24177,24178,24179,24180,24181,24182,24183,24184,24185,24186,24187,24188,24189,24190,24191,24192,24193,24194,24195,24196,24197,24198,24199,24200,24201,24202,24203,24204,24205,24206,24207,24208,24209,24210,24211,24212,24213,24214,24215,24216,24217,24218,24219,24220,24221,24222,24223,24224,24225,24226,24227,24228,24229,24230,24231,24232,24233,24234,24235,24236,24237,24238,24239,24240,24241,24242,24243,24244,24245,24246,24247,24248,24249,24250,24251,24252,24253,24254,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24265,24266,24267,24268,24269,24270,24271,24272,24273,24274,24275,24276,24277,24278,24279,24280,24281,24282,24283,24284,24285,24286,24287,24288,24289,24290,24291,24292,24293,24294,24295,24296,24297,24298,24299,24300,24301,24302,24303,24304,24305,24306,24307,24308,24309,24310,24311,24312,24313,24314,24315,24316,24317,24318,24319,24320,24321,24322,24323,24324,24325,24326,24327,24328,24329,24330,24331,24332,24333,24334,24335,24336,24337,24338,24339,24340,24341,24342,24343,24344,24345,24346,24347,24348,24349,24350,24351,24352,24353,24354,24355,24356,24357,24358,24359,24360,24361,24362,24363,24364,24365,24366,24367,24368,24369,24370,24371,24372,24373,24374,24375,24376,24377,24378,24379,24380,24381,24382,24383,24384,24385,24386,24387,24388,24389,24390,24391,24392,24393,24394,24395,24396,24397,24398,24399,24400,24401,24402,24403,24404,24405,24406,24407,24408,24409,24410,24411,24412,24413,24414,24415,24416,24417,24418,24419,24420,24421,24422,24423,24424,24425,24426,24427,24428,24429,24430,24431,24432,24433,24434,24435,24436,24437,24438,24439,24440,24441,24442,24443,24444,24445,24446,24447,24448,24449,24450,24451,24452,24453,24454,24455,24456,24457,24458,24459,24460,24461,24462,24463,24464,24465,24466,24467,24468,24469,24470,24471,24472,24473,24474,24475,24476,24477,24478,24479,24480,24481,24482,24483,24484,24485,24486,24487,24488,24489,24490,24491,24492,24493,24494,24495,24496,24497,24498,24499,24500,24501,24502,24503,24504,24505,24506,24507,24508,24509,24510,24511,24512,24513,24514,24515,24516,24517,24518,24519,24520,24521,24522,24523,24524,24525,24526,24527,24528,24529,24530,24531,24532,24533,24534,24535,24536,24537,24538,24539,24540,24541,24542,24543,24544,24545,24546,24547,24548,24549,24550,24551,24552,24553,24554,24555,24556,24557,24558,24559,24560,24561,24562,24563,24564,24565,24566,24567,24568,24569,24570,24571,24572,24573,24574,24575,24576,24577,24578,24579,24580,24581,24582,24583,24584,24585,24586,24587,24588,24589,24590,24591,24592,24593,24594,24595,24596,24597,24598,24599,24600,24601,24602,24603,24604,24605,24606,24607,24608,24609,24610,24611,24612,24613,24614,24615,24616,24617,24618,24619,24620,24621,24622,24623,24624,24625,24626,24627,24628,24629,24630,24631,24632,24633,24634,24635,24636,24637,24638,24639,24640,24641,24642,24643,24644,24645,24646,24647,24648,24649,24650,24651,24652,24653,24654,24655,24656,24657,24658,24659,24660,24661,24662,24663,24664,24665,24666,24667,24668,24669,24670,24671,24672,24673,24674,24675,24676,24677,24678,24679,24680,24681,24682,24683,24684,24685,24686,24687,24688,24689,24690,24691,24692,24693,24694,24695,24696,24697,24698,24699,24700,24701,24702,24703,24704,24705,24706,24707,24708,24709,24710,24711,24712,24713,24714,24715,24716,24717,24718,24719,24720,24721,24722,24723,24724,24725,24726,24727,24728,24729,24730,24731,24732,24733,24734,24735,24736,24737,24738,24739,24740,24741,24742,24743,24744,24745,24746,24747,24748,24749,24750,24751,24752,24753,24754,24755,24756,24757,24758,24759,24760,24761,24762,24763,24764,24765,24766,24767,24768,24769,24770,24771,24772,24773,24774,24775,24776,24777,24778,24779,24780,24781,24782,24783,24784,24785,24786,24787,24788,24789,24790,24791,24792,24793,24794,24795,24796,24797,24798,24799,24800,24801,24802,24803,24804,24805,24806,24807,24808,24809,24810,24811,24812,24813,24814,24815,24816,24817,24818,24819,24820,24821,24822,24823,24824,24825,24826,24827,24828,24829,24830,24831,24832,24833,24834,24835,24836,24837,24838,24839,24840,24841,24842,24843,24844,24845,24846,24847,24848,24849,24850,24851,24852,24853,24854,24855,24856,24857,24858,24859,24860,24861,24862,24863,24864,24865,24866,24867,24868,24869,24870,24871,24872,24873,24874,24875,24876,24877,24878,24879,24880,24881,24882,24883,24884,24885,24886,24887,24888,24889,24890,24891,24892,24893,24894,24895,24896,24897,24898,24899,24900,24901,24902,24903,24904,24905,24906,24907,24908,24909,24910,24911,24912,24913,24914,24915,24916,24917,24918,24919,24920,24921,24922,24923,24924,24925,24926,24927,24928,24929,24930,24931,24932,24933,24934,24935,24936,24937,24938,24939,24940,24941,24942,24943,24944,24945,24946,24947,24948,24949,24950,24951,24952,24953,24954,24955,24956,24957,24958,24959,24960,24961,24962,24963,24964,24965,24966,24967,24968,24969,24970,24971,24972,24973,24974,24975,24976,24977,24978,24979,24980,24981,24982,24983,24984,24985,24986,24987,24988,24989,24990,24991,24992,24993,24994,24995,24996,24997,24998,24999,25000,25001,25002,25003,25004,25005,25006,25007,25008,25009,25010,25011,25012,25013,25014,25015,25016,25017,25018,25019,25020,25021,25022,25023,25024,25025,25026,25027,25028,25029,25030,25031,25032,25033,25034,25035,25036,25037,25038,25039,25040,25041,25042,25043,25044,25045,25046,25047,25048,25049,25050,25051,25052,25053,25054,25055,25056,25057,25058,25059,25060,25061,25062,25063,25064,25065,25066,25067,25068,25069,25070,25071,25072,25073,25074,25075,25076,25077,25078,25079,25080,25081,25082,25083,25084,25085,25086,25087,25088,25089,25090,25091,25092,25093,25094,25095,25096,25097,25098,25099,25100,25101,25102,25103,25104,25105,25106,25107,25108,25109,25110,25111,25112,25113,25114,25115,25116,25117,25118,25119,25120,25121,25122,25123,25124,25125,25126,25127,25128,25129,25130,25131,25132,25133,25134,25135,25136,25137,25138,25139,25140,25141,25142,25143,25144,25145,25146,25147,25148,25149,25150,25151,25152,25153,25154,25155,25156,25157,25158,25159,25160,25161,25162,25163,25164,25165,25166,25167,25168,25169,25170,25171,25172,25173,25174,25175,25176,25177,25178,25179,25180,25181,25182,25183,25184,25185,25186,25187,25188,25189,25190,25191,25192,25193,25194,25195,25196,25197,25198,25199,25200,25201,25202,25203,25204,25205,25206,25207,25208,25209,25210,25211,25212,25213,25214,25215,25216,25217,25218,25219,25220,25221,25222,25223,25224,25225,25226,25227,25228,25229,25230,25231,25232,25233,25234,25235,25236,25237,25238,25239,25240,25241,25242,25243,25244,25245,25246,25247,25248,25249,25250,25251,25252,25253,25254,25255,25256,25257,25258,25259,25260,25261,25262,25263,25264,25265,25266,25267,25268,25269,25270,25271,25272,25273,25274,25275,25276,25277,25278,25279,25280,25281,25282,25283,25284,25285,25286,25287,25288,25289,25290,25291,25292,25293,25294,25295,25296,25297,25298,25299,25300,25301,25302,25303,25304,25305,25306,25307,25308,25309,25310,25311,25312,25313,25314,25315,25316,25317,25318,25319,25320,25321,25322,25323,25324,25325,25326,25327,25328,25329,25330,25331,25332,25333,25334,25335,25336,25337,25338,25339,25340,25341,25342,25343,25344,25345,25346,25347,25348,25349,25350,25351,25352,25353,25354,25355,25356,25357,25358,25359,25360,25361,25362,25363,25364,25365,25366,25367,25368,25369,25370,25371,25372,25373,25374,25375,25376,25377,25378,25379,25380,25381,25382,25383,25384,25385,25386,25387,25388,25389,25390,25391,25392,25393,25394,25395,25396,25397,25398,25399,25400,25401,25402,25403,25404,25405,25406,25407,25408,25409,25410,25411,25412,25413,25414,25415,25416,25417,25418,25419,25420,25421,25422,25423,25424,25425,25426,25427,25428,25429,25430,25431,25432,25433,25434,25435,25436,25437,25438,25439,25440,25441,25442,25443,25444,25445,25446,25447,25448,25449,25450,25451,25452,25453,25454,25455,25456,25457,25458,25459,25460,25461,25462,25463,25464,25465,25466,25467,25468,25469,25470,25471,25472,25473,25474,25475,25476,25477,25478,25479,25480,25481,25482,25483,25484,25485,25486,25487,25488,25489,25490,25491,25492,25493,25494,25495,25496,25497,25498,25499,25500,25501,25502,25503,25504,25505,25506,25507,25508,25509,25510,25511,25512,25513,25514,25515,25516,25517,25518,25519,25520,25521,25522,25523,25524,25525,25526,25527,25528,25529,25530,25531,25532,25533,25534,25535,25536,25537,25538,25539,25540,25541,25542,25543,25544,25545,25546,25547,25548,25549,25550,25551,25552,25553,25554,25555,25556,25557,25558,25559,25560,25561,25562,25563,25564,25565,25566,25567,25568,25569,25570,25571,25572,25573,25574,25575,25576,25577,25578,25579,25580,25581,25582,25583,25584,25585,25586,25587,25588,25589,25590,25591,25592,25593,25594,25595,25596,25597,25598,25599,25600,25601,25602,25603,25604,25605,25606,25607,25608,25609,25610,25611,25612,25613,25614,25615,25616,25617,25618,25619,25620,25621,25622,25623,25624,25625,25626,25627,25628,25629,25630,25631,25632,25633,25634,25635,25636,25637,25638,25639,25640,25641,25642,25643,25644,25645,25646,25647,25648,25649,25650,25651,25652,25653,25654,25655,25656,25657,25658,25659,25660,25661,25662,25663,25664,25665,25666,25667,25668,25669,25670,25671,25672,25673,25674,25675,25676,25677,25678,25679,25680,25681,25682,25683,25684,25685,25686,25687,25688,25689,25690,25691,25692,25693,25694,25695,25696,25697,25698,25699,25700,25701,25702,25703,25704,25705,25706,25707,25708,25709,25710,25711,25712,25713,25714,25715,25716,25717,25718,25719,25720,25721,25722,25723,25724,25725,25726,25727,25728,25729,25730,25731,25732,25733,25734,25735,25736,25737,25738,25739,25740,25741,25742,25743,25744,25745,25746,25747,25748,25749,25750,25751,25752,25753,25754,25755,25756,25757,25758,25759,25760,25761,25762,25763,25764,25765,25766,25767,25768,25769,25770,25771,25772,25773,25774,25775,25776,25777,25778,25779,25780,25781,25782,25783,25784,25785,25786,25787,25788,25789,25790,25791,25792,25793,25794,25795,25796,25797,25798,25799,25800,25801,25802,25803,25804,25805,25806,25807,25808,25809,25810,25811,25812,25813,25814,25815,25816,25817,25818,25819,25820,25821,25822,25823,25824,25825,25826,25827,25828,25829,25830,25831,25832,25833,25834,25835,25836,25837,25838,25839,25840,25841,25842,25843,25844,25845,25846,25847,25848,25849,25850,25851,25852,25853,25854,25855,25856,25857,25858,25859,25860,25861,25862,25863,25864,25865,25866,25867,25868,25869,25870,25871,25872,25873,25874,25875,25876,25877,25878,25879,25880,25881,25882,25883,25884,25885,25886,25887,25888,25889,25890,25891,25892,25893,25894,25895,25896,25897,25898,25899,25900,25901,25902,25903,25904,25905,25906,25907,25908,25909,25910,25911,25912,25913,25914,25915,25916,25917,25918,25919,25920,25921,25922,25923,25924,25925,25926,25927,25928,25929,25930,25931,25932,25933,25934,25935,25936,25937,25938,25939,25940,25941,25942,25943,25944,25945,25946,25947,25948,25949,25950,25951,25952,25953,25954,25955,25956,25957,25958,25959,25960,25961,25962,25963,25964,25965,25966,25967,25968,25969,25970,25971,25972,25973,25974,25975,25976,25977,25978,25979,25980,25981,25982,25983,25984,25985,25986,25987,25988,25989,25990,25991,25992,25993,25994,25995,25996,25997,25998,25999,26000,26001,26002,26003,26004,26005,26006,26007,26008,26009,26010,26011,26012,26013,26014,26015,26016,26017,26018,26019,26020,26021,26022,26023,26024,26025,26026,26027,26028,26029,26030,26031,26032,26033,26034,26035,26036,26037,26038,26039,26040,26041,26042,26043,26044,26045,26046,26047,26048,26049,26050,26051,26052,26053,26054,26055,26056,26057,26058,26059,26060,26061,26062,26063,26064,26065,26066,26067,26068,26069,26070,26071,26072,26073,26074,26075,26076,26077,26078,26079,26080,26081,26082,26083,26084,26085,26086,26087,26088,26089,26090,26091,26092,26093,26094,26095,26096,26097,26098,26099,26100,26101,26102,26103,26104,26105,26106,26107,26108,26109,26110,26111,26112,26113,26114,26115,26116,26117,26118,26119,26120,26121,26122,26123,26124,26125,26126,26127,26128,26129,26130,26131,26132,26133,26134,26135,26136,26137,26138,26139,26140,26141,26142,26143,26144,26145,26146,26147,26148,26149,26150,26151,26152,26153,26154,26155,26156,26157,26158,26159,26160,26161,26162,26163,26164,26165,26166,26167,26168,26169,26170,26171,26172,26173,26174,26175,26176,26177,26178,26179,26180,26181,26182,26183,26184,26185,26186,26187,26188,26189,26190,26191,26192,26193,26194,26195,26196,26197,26198,26199,26200,26201,26202,26203,26204,26205,26206,26207,26208,26209,26210,26211,26212,26213,26214,26215,26216,26217,26218,26219,26220,26221,26222,26223,26224,26225,26226,26227,26228,26229,26230,26231,26232,26233,26234,26235,26236,26237,26238,26239,26240,26241,26242,26243,26244,26245,26246,26247,26248,26249,26250,26251,26252,26253,26254,26255,26256,26257,26258,26259,26260,26261,26262,26263,26264,26265,26266,26267,26268,26269,26270,26271,26272,26273,26274,26275,26276,26277,26278,26279,26280,26281,26282,26283,26284,26285,26286,26287,26288,26289,26290,26291,26292,26293,26294,26295,26296,26297,26298,26299,26300,26301,26302,26303,26304,26305,26306,26307,26308,26309,26310,26311,26312,26313,26314,26315,26316,26317,26318,26319,26320,26321,26322,26323,26324,26325,26326,26327,26328,26329,26330,26331,26332,26333,26334,26335,26336,26337,26338,26339,26340,26341,26342,26343,26344,26345,26346,26347,26348,26349,26350,26351,26352,26353,26354,26355,26356,26357,26358,26359,26360,26361,26362,26363,26364,26365,26366,26367,26368,26369,26370,26371,26372,26373,26374,26375,26376,26377,26378,26379,26380,26381,26382,26383,26384,26385,26386,26387,26388,26389,26390,26391,26392,26393,26394,26395,26396,26397,26398,26399,26400,26401,26402,26403,26404,26405,26406,26407,26408,26409,26410,26411,26412,26413,26414,26415,26416,26417,26418,26419,26420,26421,26422,26423,26424,26425,26426,26427,26428,26429,26430,26431,26432,26433,26434,26435,26436,26437,26438,26439,26440,26441,26442,26443,26444,26445,26446,26447,26448,26449,26450,26451,26452,26453,26454,26455,26456,26457,26458,26459,26460,26461,26462,26463,26464,26465,26466,26467,26468,26469,26470,26471,26472,26473,26474,26475,26476,26477,26478,26479,26480,26481,26482,26483,26484,26485,26486,26487,26488,26489,26490,26491,26492,26493,26494,26495,26496,26497,26498,26499,26500,26501,26502,26503,26504,26505,26506,26507,26508,26509,26510,26511,26512,26513,26514,26515,26516,26517,26518,26519,26520,26521,26522,26523,26524,26525,26526,26527,26528,26529,26530,26531,26532,26533,26534,26535,26536,26537,26538,26539,26540,26541,26542,26543,26544,26545,26546,26547,26548,26549,26550,26551,26552,26553,26554,26555,26556,26557,26558,26559,26560,26561,26562,26563,26564,26565,26566,26567,26568,26569,26570,26571,26572,26573,26574,26575,26576,26577,26578,26579,26580,26581,26582,26583,26584,26585,26586,26587,26588,26589,26590,26591,26592,26593,26594,26595,26596,26597,26598,26599,26600,26601,26602,26603,26604,26605,26606,26607,26608,26609,26610,26611,26612,26613,26614,26615,26616,26617,26618,26619,26620,26621,26622,26623,26624,26625,26626,26627,26628,26629,26630,26631,26632,26633,26634,26635,26636,26637,26638,26639,26640,26641,26642,26643,26644,26645,26646,26647,26648,26649,26650,26651,26652,26653,26654,26655,26656,26657,26658,26659,26660,26661,26662,26663,26664,26665,26666,26667,26668,26669,26670,26671,26672,26673,26674,26675,26676,26677,26678,26679,26680,26681,26682,26683,26684,26685,26686,26687,26688,26689,26690,26691,26692,26693,26694,26695,26696,26697,26698,26699,26700,26701,26702,26703,26704,26705,26706,26707,26708,26709,26710,26711,26712,26713,26714,26715,26716,26717,26718,26719,26720,26721,26722,26723,26724,26725,26726,26727,26728,26729,26730,26731,26732,26733,26734,26735,26736,26737,26738,26739,26740,26741,26742,26743,26744,26745,26746,26747,26748,26749,26750,26751,26752,26753,26754,26755,26756,26757,26758,26759,26760,26761,26762,26763,26764,26765,26766,26767,26768,26769,26770,26771,26772,26773,26774,26775,26776,26777,26778,26779,26780,26781,26782,26783,26784,26785,26786,26787,26788,26789,26790,26791,26792,26793,26794,26795,26796,26797,26798,26799,26800,26801,26802,26803,26804,26805,26806,26807,26808,26809,26810,26811,26812,26813,26814,26815,26816,26817,26818,26819,26820,26821,26822,26823,26824,26825,26826,26827,26828,26829,26830,26831,26832,26833,26834,26835,26836,26837,26838,26839,26840,26841,26842,26843,26844,26845,26846,26847,26848,26849,26850,26851,26852,26853,26854,26855,26856,26857,26858,26859,26860,26861,26862,26863,26864,26865,26866,26867,26868,26869,26870,26871,26872,26873,26874,26875,26876,26877,26878,26879,26880,26881,26882,26883,26884,26885,26886,26887,26888,26889,26890,26891,26892,26893,26894,26895,26896,26897,26898,26899,26900,26901,26902,26903,26904,26905,26906,26907,26908,26909,26910,26911,26912,26913,26914,26915,26916,26917,26918,26919,26920,26921,26922,26923,26924,26925,26926,26927,26928,26929,26930,26931,26932,26933,26934,26935,26936,26937,26938,26939,26940,26941,26942,26943,26944,26945,26946,26947,26948,26949,26950,26951,26952,26953,26954,26955,26956,26957,26958,26959,26960,26961,26962,26963,26964,26965,26966,26967,26968,26969,26970,26971,26972,26973,26974,26975,26976,26977,26978,26979,26980,26981,26982,26983,26984,26985,26986,26987,26988,26989,26990,26991,26992,26993,26994,26995,26996,26997,26998,26999,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015,27016,27017,27018,27019,27020,27021,27022,27023,27024,27025,27026,27027,27028,27029,27030,27031,27032,27033,27034,27035,27036,27037,27038,27039,27040,27041,27042,27043,27044,27045,27046,27047,27048,27049,27050,27051,27052,27053,27054,27055,27056,27057,27058,27059,27060,27061,27062,27063,27064,27065,27066,27067,27068,27069,27070,27071,27072,27073,27074,27075,27076,27077,27078,27079,27080,27081,27082,27083,27084,27085,27086,27087,27088,27089,27090,27091,27092,27093,27094,27095,27096,27097,27098,27099,27100,27101,27102,27103,27104,27105,27106,27107,27108,27109,27110,27111,27112,27113,27114,27115,27116,27117,27118,27119,27120,27121,27122,27123,27124,27125,27126,27127,27128,27129,27130,27131,27132,27133,27134,27135,27136,27137,27138,27139,27140,27141,27142,27143,27144,27145,27146,27147,27148,27149,27150,27151,27152,27153,27154,27155,27156,27157,27158,27159,27160,27161,27162,27163,27164,27165,27166,27167,27168,27169,27170,27171,27172,27173,27174,27175,27176,27177,27178,27179,27180,27181,27182,27183,27184,27185,27186,27187,27188,27189,27190,27191,27192,27193,27194,27195,27196,27197,27198,27199,27200,27201,27202,27203,27204,27205,27206,27207,27208,27209,27210,27211,27212,27213,27214,27215,27216,27217,27218,27219,27220,27221,27222,27223,27224,27225,27226,27227,27228,27229,27230,27231,27232,27233,27234,27235,27236,27237,27238,27239,27240,27241,27242,27243,27244,27245,27246,27247,27248,27249,27250,27251,27252,27253,27254,27255,27256,27257,27258,27259,27260,27261,27262,27263,27264,27265,27266,27267,27268,27269,27270,27271,27272,27273,27274,27275,27276,27277,27278,27279,27280,27281,27282,27283,27284,27285,27286,27287,27288,27289,27290,27291,27292,27293,27294,27295,27296,27297,27298,27299,27300,27301,27302,27303,27304,27305,27306,27307,27308,27309,27310,27311,27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,27322,27323,27324,27325,27326,27327,27328,27329,27330,27331,27332,27333,27334,27335,27336,27337,27338,27339,27340,27341,27342,27343,27344,27345,27346,27347,27348,27349,27350,27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,27362,27363,27364,27365,27366,27367,27368,27369,27370,27371,27372,27373,27374,27375,27376,27377,27378,27379,27380,27381,27382,27383,27384,27385,27386,27387,27388,27389,27390,27391,27392,27393,27394,27395,27396,27397,27398,27399,27400,27401,27402,27403,27404,27405,27406,27407,27408,27409,27410,27411,27412,27413,27414,27415,27416,27417,27418,27419,27420,27421,27422,27423,27424,27425,27426,27427,27428,27429,27430,27431,27432,27433,27434,27435,27436,27437,27438,27439,27440,27441,27442,27443,27444,27445,27446,27447,27448,27449,27450,27451,27452,27453,27454,27455,27456,27457,27458,27459,27460,27461,27462,27463,27464,27465,27466,27467,27468,27469,27470,27471,27472,27473,27474,27475,27476,27477,27478,27479,27480,27481,27482,27483,27484,27485,27486,27487,27488,27489,27490,27491,27492,27493,27494,27495,27496,27497,27498,27499,27500,27501,27502,27503,27504,27505,27506,27507,27508,27509,27510,27511,27512,27513,27514,27515,27516,27517,27518,27519,27520,27521,27522,27523,27524,27525,27526,27527,27528,27529,27530,27531,27532,27533,27534,27535,27536,27537,27538,27539,27540,27541,27542,27543,27544,27545,27546,27547,27548,27549,27550,27551,27552,27553,27554,27555,27556,27557,27558,27559,27560,27561,27562,27563,27564,27565,27566,27567,27568,27569,27570,27571,27572,27573,27574,27575,27576,27577,27578,27579,27580,27581,27582,27583,27584,27585,27586,27587,27588,27589,27590,27591,27592,27593,27594,27595,27596,27597,27598,27599,27600,27601,27602,27603,27604,27605,27606,27607,27608,27609,27610,27611,27612,27613,27614,27615,27616,27617,27618,27619,27620,27621,27622,27623,27624,27625,27626,27627,27628,27629,27630,27631,27632,27633,27634,27635,27636,27637,27638,27639,27640,27641,27642,27643,27644,27645,27646,27647,27648,27649,27650,27651,27652,27653,27654,27655,27656,27657,27658,27659,27660,27661,27662,27663,27664,27665,27666,27667,27668,27669,27670,27671,27672,27673,27674,27675,27676,27677,27678,27679,27680,27681,27682,27683,27684,27685,27686,27687,27688,27689,27690,27691,27692,27693,27694,27695,27696,27697,27698,27699,27700,27701,27702,27703,27704,27705,27706,27707,27708,27709,27710,27711,27712,27713,27714,27715,27716,27717,27718,27719,27720,27721,27722,27723,27724,27725,27726,27727,27728,27729,27730,27731,27732,27733,27734,27735,27736,27737,27738,27739,27740,27741,27742,27743,27744,27745,27746,27747,27748,27749,27750,27751,27752,27753,27754,27755,27756,27757,27758,27759,27760,27761,27762,27763,27764,27765,27766,27767,27768,27769,27770,27771,27772,27773,27774,27775,27776,27777,27778,27779,27780,27781,27782,27783,27784,27785,27786,27787,27788,27789,27790,27791,27792,27793,27794,27795,27796,27797,27798,27799,27800,27801,27802,27803,27804,27805,27806,27807,27808,27809,27810,27811,27812,27813,27814,27815,27816,27817,27818,27819,27820,27821,27822,27823,27824,27825,27826,27827,27828,27829,27830,27831,27832,27833,27834,27835,27836,27837,27838,27839,27840,27841,27842,27843,27844,27845,27846,27847,27848,27849,27850,27851,27852,27853,27854,27855,27856,27857,27858,27859,27860,27861,27862,27863,27864,27865,27866,27867,27868,27869,27870,27871,27872,27873,27874,27875,27876,27877,27878,27879,27880,27881,27882,27883,27884,27885,27886,27887,27888,27889,27890,27891,27892,27893,27894,27895,27896,27897,27898,27899,27900,27901,27902,27903,27904,27905,27906,27907,27908,27909,27910,27911,27912,27913,27914,27915,27916,27917,27918,27919,27920,27921,27922,27923,27924,27925,27926,27927,27928,27929,27930,27931,27932,27933,27934,27935,27936,27937,27938,27939,27940,27941,27942,27943,27944,27945,27946,27947,27948,27949,27950,27951,27952,27953,27954,27955,27956,27957,27958,27959,27960,27961,27962,27963,27964,27965,27966,27967,27968,27969,27970,27971,27972,27973,27974,27975,27976,27977,27978,27979,27980,27981,27982,27983,27984,27985,27986,27987,27988,27989,27990,27991,27992,27993,27994,27995,27996,27997,27998,27999,28000,28001,28002,28003,28004,28005,28006,28007,28008,28009,28010,28011,28012,28013,28014,28015,28016,28017,28018,28019,28020,28021,28022,28023,28024,28025,28026,28027,28028,28029,28030,28031,28032,28033,28034,28035,28036,28037,28038,28039,28040,28041,28042,28043,28044,28045,28046,28047,28048,28049,28050,28051,28052,28053,28054,28055,28056,28057,28058,28059,28060,28061,28062,28063,28064,28065,28066,28067,28068,28069,28070,28071,28072,28073,28074,28075,28076,28077,28078,28079,28080,28081,28082,28083,28084,28085,28086,28087,28088,28089,28090,28091,28092,28093,28094,28095,28096,28097,28098,28099,28100,28101,28102,28103,28104,28105,28106,28107,28108,28109,28110,28111,28112,28113,28114,28115,28116,28117,28118,28119,28120,28121,28122,28123,28124,28125,28126,28127,28128,28129,28130,28131,28132,28133,28134,28135,28136,28137,28138,28139,28140,28141,28142,28143,28144,28145,28146,28147,28148,28149,28150,28151,28152,28153,28154,28155,28156,28157,28158,28159,28160,28161,28162,28163,28164,28165,28166,28167,28168,28169,28170,28171,28172,28173,28174,28175,28176,28177,28178,28179,28180,28181,28182,28183,28184,28185,28186,28187,28188,28189,28190,28191,28192,28193,28194,28195,28196,28197,28198,28199,28200,28201,28202,28203,28204,28205,28206,28207,28208,28209,28210,28211,28212,28213,28214,28215,28216,28217,28218,28219,28220,28221,28222,28223,28224,28225,28226,28227,28228,28229,28230,28231,28232,28233,28234,28235,28236,28237,28238,28239,28240,28241,28242,28243,28244,28245,28246,28247,28248,28249,28250,28251,28252,28253,28254,28255,28256,28257,28258,28259,28260,28261,28262,28263,28264,28265,28266,28267,28268,28269,28270,28271,28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284,28285,28286,28287,28288,28289,28290,28291,28292,28293,28294,28295,28296,28297,28298,28299,28300,28301,28302,28303,28304,28305,28306,28307,28308,28309,28310,28311,28312,28313,28314,28315,28316,28317,28318,28319,28320,28321,28322,28323,28324,28325,28326,28327,28328,28329,28330,28331,28332,28333,28334,28335,28336,28337,28338,28339,28340,28341,28342,28343,28344,28345,28346,28347,28348,28349,28350,28351,28352,28353,28354,28355,28356,28357,28358,28359,28360,28361,28362,28363,28364,28365,28366,28367,28368,28369,28370,28371,28372,28373,28374,28375,28376,28377,28378,28379,28380,28381,28382,28383,28384,28385,28386,28387,28388,28389,28390,28391,28392,28393,28394,28395,28396,28397,28398,28399,28400,28401,28402,28403,28404,28405,28406,28407,28408,28409,28410,28411,28412,28413,28414,28415,28416,28417,28418,28419,28420,28421,28422,28423,28424,28425,28426,28427,28428,28429,28430,28431,28432,28433,28434,28435,28436,28437,28438,28439,28440,28441,28442,28443,28444,28445,28446,28447,28448,28449,28450,28451,28452,28453,28454,28455,28456,28457,28458,28459,28460,28461,28462,28463,28464,28465,28466,28467,28468,28469,28470,28471,28472,28473,28474,28475,28476,28477,28478,28479,28480,28481,28482,28483,28484,28485,28486,28487,28488,28489,28490,28491,28492,28493,28494,28495,28496,28497,28498,28499,28500,28501,28502,28503,28504,28505,28506,28507,28508,28509,28510,28511,28512,28513,28514,28515,28516,28517,28518,28519,28520,28521,28522,28523,28524,28525,28526,28527,28528,28529,28530,28531,28532,28533,28534,28535,28536,28537,28538,28539,28540,28541,28542,28543,28544,28545,28546,28547,28548,28549,28550,28551,28552,28553,28554,28555,28556,28557,28558,28559,28560,28561,28562,28563,28564,28565,28566,28567,28568,28569,28570,28571,28572,28573,28574,28575,28576,28577,28578,28579,28580,28581,28582,28583,28584,28585,28586,28587,28588,28589,28590,28591,28592,28593,28594,28595,28596,28597,28598,28599,28600,28601,28602,28603,28604,28605,28606,28607,28608,28609,28610,28611,28612,28613,28614,28615,28616,28617,28618,28619,28620,28621,28622,28623,28624,28625,28626,28627,28628,28629,28630,28631,28632,28633,28634,28635,28636,28637,28638,28639,28640,28641,28642,28643,28644,28645,28646,28647,28648,28649,28650,28651,28652,28653,28654,28655,28656,28657,28658,28659,28660,28661,28662,28663,28664,28665,28666,28667,28668,28669,28670,28671,28672,28673,28674,28675,28676,28677,28678,28679,28680,28681,28682,28683,28684,28685,28686,28687,28688,28689,28690,28691,28692,28693,28694,28695,28696,28697,28698,28699,28700,28701,28702,28703,28704,28705,28706,28707,28708,28709,28710,28711,28712,28713,28714,28715,28716,28717,28718,28719,28720,28721,28722,28723,28724,28725,28726,28727,28728,28729,28730,28731,28732,28733,28734,28735,28736,28737,28738,28739,28740,28741,28742,28743,28744,28745,28746,28747,28748,28749,28750,28751,28752,28753,28754,28755,28756,28757,28758,28759,28760,28761,28762,28763,28764,28765,28766,28767,28768,28769,28770,28771,28772,28773,28774,28775,28776,28777,28778,28779,28780,28781,28782,28783,28784,28785,28786,28787,28788,28789,28790,28791,28792,28793,28794,28795,28796,28797,28798,28799,28800,28801,28802,28803,28804,28805,28806,28807,28808,28809,28810,28811,28812,28813,28814,28815,28816,28817,28818,28819,28820,28821,28822,28823,28824,28825,28826,28827,28828,28829,28830,28831,28832,28833,28834,28835,28836,28837,28838,28839,28840,28841,28842,28843,28844,28845,28846,28847,28848,28849,28850,28851,28852,28853,28854,28855,28856,28857,28858,28859,28860,28861,28862,28863,28864,28865,28866,28867,28868,28869,28870,28871,28872,28873,28874,28875,28876,28877,28878,28879,28880,28881,28882,28883,28884,28885,28886,28887,28888,28889,28890,28891,28892,28893,28894,28895,28896,28897,28898,28899,28900,28901,28902,28903,28904,28905,28906,28907,28908,28909,28910,28911,28912,28913,28914,28915,28916,28917,28918,28919,28920,28921,28922,28923,28924,28925,28926,28927,28928,28929,28930,28931,28932,28933,28934,28935,28936,28937,28938,28939,28940,28941,28942,28943,28944,28945,28946,28947,28948,28949,28950,28951,28952,28953,28954,28955,28956,28957,28958,28959,28960,28961,28962,28963,28964,28965,28966,28967,28968,28969,28970,28971,28972,28973,28974,28975,28976,28977,28978,28979,28980,28981,28982,28983,28984,28985,28986,28987,28988,28989,28990,28991,28992,28993,28994,28995,28996,28997,28998,28999,29000,29001,29002,29003,29004,29005,29006,29007,29008,29009,29010,29011,29012,29013,29014,29015,29016,29017,29018,29019,29020,29021,29022,29023,29024,29025,29026,29027,29028,29029,29030,29031,29032,29033,29034,29035,29036,29037,29038,29039,29040,29041,29042,29043,29044,29045,29046,29047,29048,29049,29050,29051,29052,29053,29054,29055,29056,29057,29058,29059,29060,29061,29062,29063,29064,29065,29066,29067,29068,29069,29070,29071,29072,29073,29074,29075,29076,29077,29078,29079,29080,29081,29082,29083,29084,29085,29086,29087,29088,29089,29090,29091,29092,29093,29094,29095,29096,29097,29098,29099,29100,29101,29102,29103,29104,29105,29106,29107,29108,29109,29110,29111,29112,29113,29114,29115,29116,29117,29118,29119,29120,29121,29122,29123,29124,29125,29126,29127,29128,29129,29130,29131,29132,29133,29134,29135,29136,29137,29138,29139,29140,29141,29142,29143,29144,29145,29146,29147,29148,29149,29150,29151,29152,29153,29154,29155,29156,29157,29158,29159,29160,29161,29162,29163,29164,29165,29166,29167,29168,29169,29170,29171,29172,29173,29174,29175,29176,29177,29178,29179,29180,29181,29182,29183,29184,29185,29186,29187,29188,29189,29190,29191,29192,29193,29194,29195,29196,29197,29198,29199,29200,29201,29202,29203,29204,29205,29206,29207,29208,29209,29210,29211,29212,29213,29214,29215,29216,29217,29218,29219,29220,29221,29222,29223,29224,29225,29226,29227,29228,29229,29230,29231,29232,29233,29234,29235,29236,29237,29238,29239,29240,29241,29242,29243,29244,29245,29246,29247,29248,29249,29250,29251,29252,29253,29254,29255,29256,29257,29258,29259,29260,29261,29262,29263,29264,29265,29266,29267,29268,29269,29270,29271,29272,29273,29274,29275,29276,29277,29278,29279,29280,29281,29282,29283,29284,29285,29286,29287,29288,29289,29290,29291,29292,29293,29294,29295,29296,29297,29298,29299,29300,29301,29302,29303,29304,29305,29306,29307,29308,29309,29310,29311,29312,29313,29314,29315,29316,29317,29318,29319,29320,29321,29322,29323,29324,29325,29326,29327,29328,29329,29330,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341,29342,29343,29344,29345,29346,29347,29348,29349,29350,29351,29352,29353,29354,29355,29356,29357,29358,29359,29360,29361,29362,29363,29364,29365,29366,29367,29368,29369,29370,29371,29372,29373,29374,29375,29376,29377,29378,29379,29380,29381,29382,29383,29384,29385,29386,29387,29388,29389,29390,29391,29392,29393,29394,29395,29396,29397,29398,29399,29400,29401,29402,29403,29404,29405,29406,29407,29408,29409,29410,29411,29412,29413,29414,29415,29416,29417,29418,29419,29420,29421,29422,29423,29424,29425,29426,29427,29428,29429,29430,29431,29432,29433,29434,29435,29436,29437,29438,29439,29440,29441,29442,29443,29444,29445,29446,29447,29448,29449,29450,29451,29452,29453,29454,29455,29456,29457,29458,29459,29460,29461,29462,29463,29464,29465,29466,29467,29468,29469,29470,29471,29472,29473,29474,29475,29476,29477,29478,29479,29480,29481,29482,29483,29484,29485,29486,29487,29488,29489,29490,29491,29492,29493,29494,29495,29496,29497,29498,29499,29500,29501,29502,29503,29504,29505,29506,29507,29508,29509,29510,29511,29512,29513,29514,29515,29516,29517,29518,29519,29520,29521,29522,29523,29524,29525,29526,29527,29528,29529,29530,29531,29532,29533,29534,29535,29536,29537,29538,29539,29540,29541,29542,29543,29544,29545,29546,29547,29548,29549,29550,29551,29552,29553,29554,29555,29556,29557,29558,29559,29560,29561,29562,29563,29564,29565,29566,29567,29568,29569,29570,29571,29572,29573,29574,29575,29576,29577,29578,29579,29580,29581,29582,29583,29584,29585,29586,29587,29588,29589,29590,29591,29592,29593,29594,29595,29596,29597,29598,29599,29600,29601,29602,29603,29604,29605,29606,29607,29608,29609,29610,29611,29612,29613,29614,29615,29616,29617,29618,29619,29620,29621,29622,29623,29624,29625,29626,29627,29628,29629,29630,29631,29632,29633,29634,29635,29636,29637,29638,29639,29640,29641,29642,29643,29644,29645,29646,29647,29648,29649,29650,29651,29652,29653,29654,29655,29656,29657,29658,29659,29660,29661,29662,29663,29664,29665,29666,29667,29668,29669,29670,29671,29672,29673,29674,29675,29676,29677,29678,29679,29680,29681,29682,29683,29684,29685,29686,29687,29688,29689,29690,29691,29692,29693,29694,29695,29696,29697,29698,29699,29700,29701,29702,29703,29704,29705,29706,29707,29708,29709,29710,29711,29712,29713,29714,29715,29716,29717,29718,29719,29720,29721,29722,29723,29724,29725,29726,29727,29728,29729,29730,29731,29732,29733,29734,29735,29736,29737,29738,29739,29740,29741,29742,29743,29744,29745,29746,29747,29748,29749,29750,29751,29752,29753,29754,29755,29756,29757,29758,29759,29760,29761,29762,29763,29764,29765,29766,29767,29768,29769,29770,29771,29772,29773,29774,29775,29776,29777,29778,29779,29780,29781,29782,29783,29784,29785,29786,29787,29788,29789,29790,29791,29792,29793,29794,29795,29796,29797,29798,29799,29800,29801,29802,29803,29804,29805,29806,29807,29808,29809,29810,29811,29812,29813,29814,29815,29816,29817,29818,29819,29820,29821,29822,29823,29824,29825,29826,29827,29828,29829,29830,29831,29832,29833,29834,29835,29836,29837,29838,29839,29840,29841,29842,29843,29844,29845,29846,29847,29848,29849,29850,29851,29852,29853,29854,29855,29856,29857,29858,29859,29860,29861,29862,29863,29864,29865,29866,29867,29868,29869,29870,29871,29872,29873,29874,29875,29876,29877,29878,29879,29880,29881,29882,29883,29884,29885,29886,29887,29888,29889,29890,29891,29892,29893,29894,29895,29896,29897,29898,29899,29900,29901,29902,29903,29904,29905,29906,29907,29908,29909,29910,29911,29912,29913,29914,29915,29916,29917,29918,29919,29920,29921,29922,29923,29924,29925,29926,29927,29928,29929,29930,29931,29932,29933,29934,29935,29936,29937,29938,29939,29940,29941,29942,29943,29944,29945,29946,29947,29948,29949,29950,29951,29952,29953,29954,29955,29956,29957,29958,29959,29960,29961,29962,29963,29964,29965,29966,29967,29968,29969,29970,29971,29972,29973,29974,29975,29976,29977,29978,29979,29980,29981,29982,29983,29984,29985,29986,29987,29988,29989,29990,29991,29992,29993,29994,29995,29996,29997,29998,29999,30000,30001,30002,30003,30004,30005,30006,30007,30008,30009,30010,30011,30012,30013,30014,30015,30016,30017,30018,30019,30020,30021,30022,30023,30024,30025,30026,30027,30028,30029,30030,30031,30032,30033,30034,30035,30036,30037,30038,30039,30040,30041,30042,30043,30044,30045,30046,30047,30048,30049,30050,30051,30052,30053,30054,30055,30056,30057,30058,30059,30060,30061,30062,30063,30064,30065,30066,30067,30068,30069,30070,30071,30072,30073,30074,30075,30076,30077,30078,30079,30080,30081,30082,30083,30084,30085,30086,30087,30088,30089,30090,30091,30092,30093,30094,30095,30096,30097,30098,30099,30100,30101,30102,30103,30104,30105,30106,30107,30108,30109,30110,30111,30112,30113,30114,30115,30116,30117,30118,30119,30120,30121,30122,30123,30124,30125,30126,30127,30128,30129,30130,30131,30132,30133,30134,30135,30136,30137,30138,30139,30140,30141,30142,30143,30144,30145,30146,30147,30148,30149,30150,30151,30152,30153,30154,30155,30156,30157,30158,30159,30160,30161,30162,30163,30164,30165,30166,30167,30168,30169,30170,30171,30172,30173,30174,30175,30176,30177,30178,30179,30180,30181,30182,30183,30184,30185,30186,30187,30188,30189,30190,30191,30192,30193,30194,30195,30196,30197,30198,30199,30200,30201,30202,30203,30204,30205,30206,30207,30208,30209,30210,30211,30212,30213,30214,30215,30216,30217,30218,30219,30220,30221,30222,30223,30224,30225,30226,30227,30228,30229,30230,30231,30232,30233,30234,30235,30236,30237,30238,30239,30240,30241,30242,30243,30244,30245,30246,30247,30248,30249,30250,30251,30252,30253,30254,30255,30256,30257,30258,30259,30260,30261,30262,30263,30264,30265,30266,30267,30268,30269,30270,30271,30272,30273,30274,30275,30276,30277,30278,30279,30280,30281,30282,30283,30284,30285,30286,30287,30288,30289,30290,30291,30292,30293,30294,30295,30296,30297,30298,30299,30300,30301,30302,30303,30304,30305,30306,30307,30308,30309,30310,30311,30312,30313,30314,30315,30316,30317,30318,30319,30320,30321,30322,30323,30324,30325,30326,30327,30328,30329,30330,30331,30332,30333,30334,30335,30336,30337,30338,30339,30340,30341,30342,30343,30344,30345,30346,30347,30348,30349,30350,30351,30352,30353,30354,30355,30356,30357,30358,30359,30360,30361,30362,30363,30364,30365,30366,30367,30368,30369,30370,30371,30372,30373,30374,30375,30376,30377,30378,30379,30380,30381,30382,30383,30384,30385,30386,30387,30388,30389,30390,30391,30392,30393,30394,30395,30396,30397,30398,30399,30400,30401,30402,30403,30404,30405,30406,30407,30408,30409,30410,30411,30412,30413,30414,30415,30416,30417,30418,30419,30420,30421,30422,30423,30424,30425,30426,30427,30428,30429,30430,30431,30432,30433,30434,30435,30436,30437,30438,30439,30440,30441,30442,30443,30444,30445,30446,30447,30448,30449,30450,30451,30452,30453,30454,30455,30456,30457,30458,30459,30460,30461,30462,30463,30464,30465,30466,30467,30468,30469,30470,30471,30472,30473,30474,30475,30476,30477,30478,30479,30480,30481,30482,30483,30484,30485,30486,30487,30488,30489,30490,30491,30492,30493,30494,30495,30496,30497,30498,30499,30500,30501,30502,30503,30504,30505,30506,30507,30508,30509,30510,30511,30512,30513,30514,30515,30516,30517,30518,30519,30520,30521,30522,30523,30524,30525,30526,30527,30528,30529,30530,30531,30532,30533,30534,30535,30536,30537,30538,30539,30540,30541,30542,30543,30544,30545,30546,30547,30548,30549,30550,30551,30552,30553,30554,30555,30556,30557,30558,30559,30560,30561,30562,30563,30564,30565,30566,30567,30568,30569,30570,30571,30572,30573,30574,30575,30576,30577,30578,30579,30580,30581,30582,30583,30584,30585,30586,30587,30588,30589,30590,30591,30592,30593,30594,30595,30596,30597,30598,30599,30600,30601,30602,30603,30604,30605,30606,30607,30608,30609,30610,30611,30612,30613,30614,30615,30616,30617,30618,30619,30620,30621,30622,30623,30624,30625,30626,30627,30628,30629,30630,30631,30632,30633,30634,30635,30636,30637,30638,30639,30640,30641,30642,30643,30644,30645,30646,30647,30648,30649,30650,30651,30652,30653,30654,30655,30656,30657,30658,30659,30660,30661,30662,30663,30664,30665,30666,30667,30668,30669,30670,30671,30672,30673,30674,30675,30676,30677,30678,30679,30680,30681,30682,30683,30684,30685,30686,30687,30688,30689,30690,30691,30692,30693,30694,30695,30696,30697,30698,30699,30700,30701,30702,30703,30704,30705,30706,30707,30708,30709,30710,30711,30712,30713,30714,30715,30716,30717,30718,30719,30720,30721,30722,30723,30724,30725,30726,30727,30728,30729,30730,30731,30732,30733,30734,30735,30736,30737,30738,30739,30740,30741,30742,30743,30744,30745,30746,30747,30748,30749,30750,30751,30752,30753,30754,30755,30756,30757,30758,30759,30760,30761,30762,30763,30764,30765,30766,30767,30768,30769,30770,30771,30772,30773,30774,30775,30776,30777,30778,30779,30780,30781,30782,30783,30784,30785,30786,30787,30788,30789,30790,30791,30792,30793,30794,30795,30796,30797,30798,30799,30800,30801,30802,30803,30804,30805,30806,30807,30808,30809,30810,30811,30812,30813,30814,30815,30816,30817,30818,30819,30820,30821,30822,30823,30824,30825,30826,30827,30828,30829,30830,30831,30832,30833,30834,30835,30836,30837,30838,30839,30840,30841,30842,30843,30844,30845,30846,30847,30848,30849,30850,30851,30852,30853,30854,30855,30856,30857,30858,30859,30860,30861,30862,30863,30864,30865,30866,30867,30868,30869,30870,30871,30872,30873,30874,30875,30876,30877,30878,30879,30880,30881,30882,30883,30884,30885,30886,30887,30888,30889,30890,30891,30892,30893,30894,30895,30896,30897,30898,30899,30900,30901,30902,30903,30904,30905,30906,30907,30908,30909,30910,30911,30912,30913,30914,30915,30916,30917,30918,30919,30920,30921,30922,30923,30924,30925,30926,30927,30928,30929,30930,30931,30932,30933,30934,30935,30936,30937,30938,30939,30940,30941,30942,30943,30944,30945,30946,30947,30948,30949,30950,30951,30952,30953,30954,30955,30956,30957,30958,30959,30960,30961,30962,30963,30964,30965,30966,30967,30968,30969,30970,30971,30972,30973,30974,30975,30976,30977,30978,30979,30980,30981,30982,30983,30984,30985,30986,30987,30988,30989,30990,30991,30992,30993,30994,30995,30996,30997,30998,30999,31000,31001,31002,31003,31004,31005,31006,31007,31008,31009,31010,31011,31012,31013,31014,31015,31016,31017,31018,31019,31020,31021,31022,31023,31024,31025,31026,31027,31028,31029,31030,31031,31032,31033,31034,31035,31036,31037,31038,31039,31040,31041,31042,31043,31044,31045,31046,31047,31048,31049,31050,31051,31052,31053,31054,31055,31056,31057,31058,31059,31060,31061,31062,31063,31064,31065,31066,31067,31068,31069,31070,31071,31072,31073,31074,31075,31076,31077,31078,31079,31080,31081,31082,31083,31084,31085,31086,31087,31088,31089,31090,31091,31092,31093,31094,31095,31096,31097,31098,31099,31100,31101,31102,31103,31104,31105,31106,31107,31108,31109,31110,31111,31112,31113,31114,31115,31116,31117,31118,31119,31120,31121,31122,31123,31124,31125,31126,31127,31128,31129,31130,31131,31132,31133,31134,31135,31136,31137,31138,31139,31140,31141,31142,31143,31144,31145,31146,31147,31148,31149,31150,31151,31152,31153,31154,31155,31156,31157,31158,31159,31160,31161,31162,31163,31164,31165,31166,31167,31168,31169,31170,31171,31172,31173,31174,31175,31176,31177,31178,31179,31180,31181,31182,31183,31184,31185,31186,31187,31188,31189,31190,31191,31192,31193,31194,31195,31196,31197,31198,31199,31200,31201,31202,31203,31204,31205,31206,31207,31208,31209,31210,31211,31212,31213,31214,31215,31216,31217,31218,31219,31220,31221,31222,31223,31224,31225,31226,31227,31228,31229,31230,31231,31232,31233,31234,31235,31236,31237,31238,31239,31240,31241,31242,31243,31244,31245,31246,31247,31248,31249,31250,31251,31252,31253,31254,31255,31256,31257,31258,31259,31260,31261,31262,31263,31264,31265,31266,31267,31268,31269,31270,31271,31272,31273,31274,31275,31276,31277,31278,31279,31280,31281,31282,31283,31284,31285,31286,31287,31288,31289,31290,31291,31292,31293,31294,31295,31296,31297,31298,31299,31300,31301,31302,31303,31304,31305,31306,31307,31308,31309,31310,31311,31312,31313,31314,31315,31316,31317,31318,31319,31320,31321,31322,31323,31324,31325,31326,31327,31328,31329,31330,31331,31332,31333,31334,31335,31336,31337,31338,31339,31340,31341,31342,31343,31344,31345,31346,31347,31348,31349,31350,31351,31352,31353,31354,31355,31356,31357,31358,31359,31360,31361,31362,31363,31364,31365,31366,31367,31368,31369,31370,31371,31372,31373,31374,31375,31376,31377,31378,31379,31380,31381,31382,31383,31384,31385,31386,31387,31388,31389,31390,31391,31392,31393,31394,31395,31396,31397,31398,31399,31400,31401,31402,31403,31404,31405,31406,31407,31408,31409,31410,31411,31412,31413,31414,31415,31416,31417,31418,31419,31420,31421,31422,31423,31424,31425,31426,31427,31428,31429,31430,31431,31432,31433,31434,31435,31436,31437,31438,31439,31440,31441,31442,31443,31444,31445,31446,31447,31448,31449,31450,31451,31452,31453,31454,31455,31456,31457,31458,31459,31460,31461,31462,31463,31464,31465,31466,31467,31468,31469,31470,31471,31472,31473,31474,31475,31476,31477,31478,31479,31480,31481,31482,31483,31484,31485,31486,31487,31488,31489,31490,31491,31492,31493,31494,31495,31496,31497,31498,31499,31500,31501,31502,31503,31504,31505,31506,31507,31508,31509,31510,31511,31512,31513,31514,31515,31516,31517,31518,31519,31520,31521,31522,31523,31524,31525,31526,31527,31528,31529,31530,31531,31532,31533,31534,31535,31536,31537,31538,31539,31540,31541,31542,31543,31544,31545,31546,31547,31548,31549,31550,31551,31552,31553,31554,31555,31556,31557,31558,31559,31560,31561,31562,31563,31564,31565,31566,31567,31568,31569,31570,31571,31572,31573,31574,31575,31576,31577,31578,31579,31580,31581,31582,31583,31584,31585,31586,31587,31588,31589,31590,31591,31592,31593,31594,31595,31596,31597,31598,31599,31600,31601,31602,31603,31604,31605,31606,31607,31608,31609,31610,31611,31612,31613,31614,31615,31616,31617,31618,31619,31620,31621,31622,31623,31624,31625,31626,31627,31628,31629,31630,31631,31632,31633,31634,31635,31636,31637,31638,31639,31640,31641,31642,31643,31644,31645,31646,31647,31648,31649,31650,31651,31652,31653,31654,31655,31656,31657,31658,31659,31660,31661,31662,31663,31664,31665,31666,31667,31668,31669,31670,31671,31672,31673,31674,31675,31676,31677,31678,31679,31680,31681,31682,31683,31684,31685,31686,31687,31688,31689,31690,31691,31692,31693,31694,31695,31696,31697,31698,31699,31700,31701,31702,31703,31704,31705,31706,31707,31708,31709,31710,31711,31712,31713,31714,31715,31716,31717,31718,31719,31720,31721,31722,31723,31724,31725,31726,31727,31728,31729,31730,31731,31732,31733,31734,31735,31736,31737,31738,31739,31740,31741,31742,31743,31744,31745,31746,31747,31748,31749,31750,31751,31752,31753,31754,31755,31756,31757,31758,31759,31760,31761,31762,31763,31764,31765,31766,31767,31768,31769,31770,31771,31772,31773,31774,31775,31776,31777,31778,31779,31780,31781,31782,31783,31784,31785,31786,31787,31788,31789,31790,31791,31792,31793,31794,31795,31796,31797,31798,31799,31800,31801,31802,31803,31804,31805,31806,31807,31808,31809,31810,31811,31812,31813,31814,31815,31816,31817,31818,31819,31820,31821,31822,31823,31824,31825,31826,31827,31828,31829,31830,31831,31832,31833,31834,31835,31836,31837,31838,31839,31840,31841,31842,31843,31844,31845,31846,31847,31848,31849,31850,31851,31852,31853,31854,31855,31856,31857,31858,31859,31860,31861,31862,31863,31864,31865,31866,31867,31868,31869,31870,31871,31872,31873,31874,31875,31876,31877,31878,31879,31880,31881,31882,31883,31884,31885,31886,31887,31888,31889,31890,31891,31892,31893,31894,31895,31896,31897,31898,31899,31900,31901,31902,31903,31904,31905,31906,31907,31908,31909,31910,31911,31912,31913,31914,31915,31916,31917,31918,31919,31920,31921,31922,31923,31924,31925,31926,31927,31928,31929,31930,31931,31932,31933,31934,31935,31936,31937,31938,31939,31940,31941,31942,31943,31944,31945,31946,31947,31948,31949,31950,31951,31952,31953,31954,31955,31956,31957,31958,31959,31960,31961,31962,31963,31964,31965,31966,31967,31968,31969,31970,31971,31972,31973,31974,31975,31976,31977,31978,31979,31980,31981,31982,31983,31984,31985,31986,31987,31988,31989,31990,31991,31992,31993,31994,31995,31996,31997,31998,31999,32000,32001,32002,32003,32004,32005,32006,32007,32008,32009,32010,32011,32012,32013,32014,32015,32016,32017,32018,32019,32020,32021,32022,32023,32024,32025,32026,32027,32028,32029,32030,32031,32032,32033,32034,32035,32036,32037,32038,32039,32040,32041,32042,32043,32044,32045,32046,32047,32048,32049,32050,32051,32052,32053,32054,32055,32056,32057,32058,32059,32060,32061,32062,32063,32064,32065,32066,32067,32068,32069,32070,32071,32072,32073,32074,32075,32076,32077,32078,32079,32080,32081,32082,32083,32084,32085,32086,32087,32088,32089,32090,32091,32092,32093,32094,32095,32096,32097,32098,32099,32100,32101,32102,32103,32104,32105,32106,32107,32108,32109,32110,32111,32112,32113,32114,32115,32116,32117,32118,32119,32120,32121,32122,32123,32124,32125,32126,32127,32128,32129,32130,32131,32132,32133,32134,32135,32136,32137,32138,32139,32140,32141,32142,32143,32144,32145,32146,32147,32148,32149,32150,32151,32152,32153,32154,32155,32156,32157,32158,32159,32160,32161,32162,32163,32164,32165,32166,32167,32168,32169,32170,32171,32172,32173,32174,32175,32176,32177,32178,32179,32180,32181,32182,32183,32184,32185,32186,32187,32188,32189,32190,32191,32192,32193,32194,32195,32196,32197,32198,32199,32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,32210,32211,32212,32213,32214,32215,32216,32217,32218,32219,32220,32221,32222,32223,32224,32225,32226,32227,32228,32229,32230,32231,32232,32233,32234,32235,32236,32237,32238,32239,32240,32241,32242,32243,32244,32245,32246,32247,32248,32249,32250,32251,32252,32253,32254,32255,32256,32257,32258,32259,32260,32261,32262,32263,32264,32265,32266,32267,32268,32269,32270,32271,32272,32273,32274,32275,32276,32277,32278,32279,32280,32281,32282,32283,32284,32285,32286,32287,32288,32289,32290,32291,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,32302,32303,32304,32305,32306,32307,32308,32309,32310,32311,32312,32313,32314,32315,32316,32317,32318,32319,32320,32321,32322,32323,32324,32325,32326,32327,32328,32329,32330,32331,32332,32333,32334,32335,32336,32337,32338,32339,32340,32341,32342,32343,32344,32345,32346,32347,32348,32349,32350,32351,32352,32353,32354,32355,32356,32357,32358,32359,32360,32361,32362,32363,32364,32365,32366,32367,32368,32369,32370,32371,32372,32373,32374,32375,32376,32377,32378,32379,32380,32381,32382,32383,32384,32385,32386,32387,32388,32389,32390,32391,32392,32393,32394,32395,32396,32397,32398,32399,32400,32401,32402,32403,32404,32405,32406,32407,32408,32409,32410,32411,32412,32413,32414,32415,32416,32417,32418,32419,32420,32421,32422,32423,32424,32425,32426,32427,32428,32429,32430,32431,32432,32433,32434,32435,32436,32437,32438,32439,32440,32441,32442,32443,32444,32445,32446,32447,32448,32449,32450,32451,32452,32453,32454,32455,32456,32457,32458,32459,32460,32461,32462,32463,32464,32465,32466,32467,32468,32469,32470,32471,32472,32473,32474,32475,32476,32477,32478,32479,32480,32481,32482,32483,32484,32485,32486,32487,32488,32489,32490,32491,32492,32493,32494,32495,32496,32497,32498,32499,32500,32501,32502,32503,32504,32505,32506,32507,32508,32509,32510,32511,32512,32513,32514,32515,32516,32517,32518,32519,32520,32521,32522,32523,32524,32525,32526,32527,32528,32529,32530,32531,32532,32533,32534,32535,32536,32537,32538,32539,32540,32541,32542,32543,32544,32545,32546,32547,32548,32549,32550,32551,32552,32553,32554,32555,32556,32557,32558,32559,32560,32561,32562,32563,32564,32565,32566,32567,32568,32569,32570,32571,32572,32573,32574,32575,32576,32577,32578,32579,32580,32581,32582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32592,32593,32594,32595,32596,32597,32598,32599,32600,32601,32602,32603,32604,32605,32606,32607,32608,32609,32610,32611,32612,32613,32614,32615,32616,32617,32618,32619,32620,32621,32622,32623,32624,32625,32626,32627,32628,32629,32630,32631,32632,32633,32634,32635,32636,32637,32638,32639,32640,32641,32642,32643,32644,32645,32646,32647,32648,32649,32650,32651,32652,32653,32654,32655,32656,32657,32658,32659,32660,32661,32662,32663,32664,32665,32666,32667,32668,32669,32670,32671,32672,32673,32674,32675,32676,32677,32678,32679,32680,32681,32682,32683,32684,32685,32686,32687,32688,32689,32690,32691,32692,32693,32694,32695,32696,32697,32698,32699,32700,32701,32702,32703,32704,32705,32706,32707,32708,32709,32710,32711,32712,32713,32714,32715,32716,32717,32718,32719,32720,32721,32722,32723,32724,32725,32726,32727,32728,32729,32730,32731,32732,32733,32734,32735,32736,32737,32738,32739,32740,32741,32742,32743,32744,32745,32746,32747,32748,32749,32750,32751,32752,32753,32754,32755,32756,32757,32758,32759,32760,32761,32762,32763,32764,32765,32766,32767,32768,32769,32770,32771,32772,32773,32774,32775,32776,32777,32778,32779,32780,32781,32782,32783,32784,32785,32786,32787,32788,32789,32790,32791,32792,32793,32794,32795,32796,32797,32798,32799,32800,32801,32802,32803,32804,32805,32806,32807,32808,32809,32810,32811,32812,32813,32814,32815,32816,32817,32818,32819,32820,32821,32822,32823,32824,32825,32826,32827,32828,32829,32830,32831,32832,32833,32834,32835,32836,32837,32838,32839,32840,32841,32842,32843,32844,32845,32846,32847,32848,32849,32850,32851,32852,32853,32854,32855,32856,32857,32858,32859,32860,32861,32862,32863,32864,32865,32866,32867,32868,32869,32870,32871,32872,32873,32874,32875,32876,32877,32878,32879,32880,32881,32882,32883,32884,32885,32886,32887,32888,32889,32890,32891,32892,32893,32894,32895,32896,32897,32898,32899,32900,32901,32902,32903,32904,32905,32906,32907,32908,32909,32910,32911,32912,32913,32914,32915,32916,32917,32918,32919,32920,32921,32922,32923,32924,32925,32926,32927,32928,32929,32930,32931,32932,32933,32934,32935,32936,32937,32938,32939,32940,32941,32942,32943,32944,32945,32946,32947,32948,32949,32950,32951,32952,32953,32954,32955,32956,32957,32958,32959,32960,32961,32962,32963,32964,32965,32966,32967,32968,32969,32970,32971,32972,32973,32974,32975,32976,32977,32978,32979,32980,32981,32982,32983,32984,32985,32986,32987,32988,32989,32990,32991,32992,32993,32994,32995,32996,32997,32998,32999,33000,33001,33002,33003,33004,33005,33006,33007,33008,33009,33010,33011,33012,33013,33014,33015,33016,33017,33018,33019,33020,33021,33022,33023,33024,33025,33026,33027,33028,33029,33030,33031,33032,33033,33034,33035,33036,33037,33038,33039,33040,33041,33042,33043,33044,33045,33046,33047,33048,33049,33050,33051,33052,33053,33054,33055,33056,33057,33058,33059,33060,33061,33062,33063,33064,33065,33066,33067,33068,33069,33070,33071,33072,33073,33074,33075,33076,33077,33078,33079,33080,33081,33082,33083,33084,33085,33086,33087,33088,33089,33090,33091,33092,33093,33094,33095,33096,33097,33098,33099,33100,33101,33102,33103,33104,33105,33106,33107,33108,33109,33110,33111,33112,33113,33114,33115,33116,33117,33118,33119,33120,33121,33122,33123,33124,33125,33126,33127,33128,33129,33130,33131,33132,33133,33134,33135,33136,33137,33138,33139,33140,33141,33142,33143,33144,33145,33146,33147,33148,33149,33150,33151,33152,33153,33154,33155,33156,33157,33158,33159,33160,33161,33162,33163,33164,33165,33166,33167,33168,33169,33170,33171,33172,33173,33174,33175,33176,33177,33178,33179,33180,33181,33182,33183,33184,33185,33186,33187,33188,33189,33190,33191,33192,33193,33194,33195,33196,33197,33198,33199,33200,33201,33202,33203,33204,33205,33206,33207,33208,33209,33210,33211,33212,33213,33214,33215,33216,33217,33218,33219,33220,33221,33222,33223,33224,33225,33226,33227,33228,33229,33230,33231,33232,33233,33234,33235,33236,33237,33238,33239,33240,33241,33242,33243,33244,33245,33246,33247,33248,33249,33250,33251,33252,33253,33254,33255,33256,33257,33258,33259,33260,33261,33262,33263,33264,33265,33266,33267,33268,33269,33270,33271,33272,33273,33274,33275,33276,33277,33278,33279,33280,33281,33282,33283,33284,33285,33286,33287,33288,33289,33290,33291,33292,33293,33294,33295,33296,33297,33298,33299,33300,33301,33302,33303,33304,33305,33306,33307,33308,33309,33310,33311,33312,33313,33314,33315,33316,33317,33318,33319,33320,33321,33322,33323,33324,33325,33326,33327,33328,33329,33330,33331,33332,33333,33334,33335,33336,33337,33338,33339,33340,33341,33342,33343,33344,33345,33346,33347,33348,33349,33350,33351,33352,33353,33354,33355,33356,33357,33358,33359,33360,33361,33362,33363,33364,33365,33366,33367,33368,33369,33370,33371,33372,33373,33374,33375,33376,33377,33378,33379,33380,33381,33382,33383,33384,33385,33386,33387,33388,33389,33390,33391,33392,33393,33394,33395,33396,33397,33398,33399,33400,33401,33402,33403,33404,33405,33406,33407,33408,33409,33410,33411,33412,33413,33414,33415,33416,33417,33418,33419,33420,33421,33422,33423,33424,33425,33426,33427,33428,33429,33430,33431,33432,33433,33434,33435,33436,33437,33438,33439,33440,33441,33442,33443,33444,33445,33446,33447,33448,33449,33450,33451,33452,33453,33454,33455,33456,33457,33458,33459,33460,33461,33462,33463,33464,33465,33466,33467,33468,33469,33470,33471,33472,33473,33474,33475,33476,33477,33478,33479,33480,33481,33482,33483,33484,33485,33486,33487,33488,33489,33490,33491,33492,33493,33494,33495,33496,33497,33498,33499,33500,33501,33502,33503,33504,33505,33506,33507,33508,33509,33510,33511,33512,33513,33514,33515,33516,33517,33518,33519,33520,33521,33522,33523,33524,33525,33526,33527,33528,33529,33530,33531,33532,33533,33534,33535,33536,33537,33538,33539,33540,33541,33542,33543,33544,33545,33546,33547,33548,33549,33550,33551,33552,33553,33554,33555,33556,33557,33558,33559,33560,33561,33562,33563,33564,33565,33566,33567,33568,33569,33570,33571,33572,33573,33574,33575,33576,33577,33578,33579,33580,33581,33582,33583,33584,33585,33586,33587,33588,33589,33590,33591,33592,33593,33594,33595,33596,33597,33598,33599,33600,33601,33602,33603,33604,33605,33606,33607,33608,33609,33610,33611,33612,33613,33614,33615,33616,33617,33618,33619,33620,33621,33622,33623,33624,33625,33626,33627,33628,33629,33630,33631,33632,33633,33634,33635,33636,33637,33638,33639,33640,33641,33642,33643,33644,33645,33646,33647,33648,33649,33650,33651,33652,33653,33654,33655,33656,33657,33658,33659,33660,33661,33662,33663,33664,33665,33666,33667,33668,33669,33670,33671,33672,33673,33674,33675,33676,33677,33678,33679,33680,33681,33682,33683,33684,33685,33686,33687,33688,33689,33690,33691,33692,33693,33694,33695,33696,33697,33698,33699,33700,33701,33702,33703,33704,33705,33706,33707,33708,33709,33710,33711,33712,33713,33714,33715,33716,33717,33718,33719,33720,33721,33722,33723,33724,33725,33726,33727,33728,33729,33730,33731,33732,33733,33734,33735,33736,33737,33738,33739,33740,33741,33742,33743,33744,33745,33746,33747,33748,33749,33750,33751,33752,33753,33754,33755,33756,33757,33758,33759,33760,33761,33762,33763,33764,33765,33766,33767,33768,33769,33770,33771,33772,33773,33774,33775,33776,33777,33778,33779,33780,33781,33782,33783,33784,33785,33786,33787,33788,33789,33790,33791,33792,33793,33794,33795,33796,33797,33798,33799,33800,33801,33802,33803,33804,33805,33806,33807,33808,33809,33810,33811,33812,33813,33814,33815,33816,33817,33818,33819,33820,33821,33822,33823,33824,33825,33826,33827,33828,33829,33830,33831,33832,33833,33834,33835,33836,33837,33838,33839,33840,33841,33842,33843,33844,33845,33846,33847,33848,33849,33850,33851,33852,33853,33854,33855,33856,33857,33858,33859,33860,33861,33862,33863,33864,33865,33866,33867,33868,33869,33870,33871,33872,33873,33874,33875,33876,33877,33878,33879,33880,33881,33882,33883,33884,33885,33886,33887,33888,33889,33890,33891,33892,33893,33894,33895,33896,33897,33898,33899,33900,33901,33902,33903,33904,33905,33906,33907,33908,33909,33910,33911,33912,33913,33914,33915,33916,33917,33918,33919,33920,33921,33922,33923,33924,33925,33926,33927,33928,33929,33930,33931,33932,33933,33934,33935,33936,33937,33938,33939,33940,33941,33942,33943,33944,33945,33946,33947,33948,33949,33950,33951,33952,33953,33954,33955,33956,33957,33958,33959,33960,33961,33962,33963,33964,33965,33966,33967,33968,33969,33970,33971,33972,33973,33974,33975,33976,33977,33978,33979,33980,33981,33982,33983,33984,33985,33986,33987,33988,33989,33990,33991,33992,33993,33994,33995,33996,33997,33998,33999,34000,34001,34002,34003,34004,34005,34006,34007,34008,34009,34010,34011,34012,34013,34014,34015,34016,34017,34018,34019,34020,34021,34022,34023,34024,34025,34026,34027,34028,34029,34030,34031,34032,34033,34034,34035,34036,34037,34038,34039,34040,34041,34042,34043,34044,34045,34046,34047,34048,34049,34050,34051,34052,34053,34054,34055,34056,34057,34058,34059,34060,34061,34062,34063,34064,34065,34066,34067,34068,34069,34070,34071,34072,34073,34074,34075,34076,34077,34078,34079,34080,34081,34082,34083,34084,34085,34086,34087,34088,34089,34090,34091,34092,34093,34094,34095,34096,34097,34098,34099,34100,34101,34102,34103,34104,34105,34106,34107,34108,34109,34110,34111,34112,34113,34114,34115,34116,34117,34118,34119,34120,34121,34122,34123,34124,34125,34126,34127,34128,34129,34130,34131,34132,34133,34134,34135,34136,34137,34138,34139,34140,34141,34142,34143,34144,34145,34146,34147,34148,34149,34150,34151,34152,34153,34154,34155,34156,34157,34158,34159,34160,34161,34162,34163,34164,34165,34166,34167,34168,34169,34170,34171,34172,34173,34174,34175,34176,34177,34178,34179,34180,34181,34182,34183,34184,34185,34186,34187,34188,34189,34190,34191,34192,34193,34194,34195,34196,34197,34198,34199,34200,34201,34202,34203,34204,34205,34206,34207,34208,34209,34210,34211,34212,34213,34214,34215,34216,34217,34218,34219,34220,34221,34222,34223,34224,34225,34226,34227,34228,34229,34230,34231,34232,34233,34234,34235,34236,34237,34238,34239,34240,34241,34242,34243,34244,34245,34246,34247,34248,34249,34250,34251,34252,34253,34254,34255,34256,34257,34258,34259,34260,34261,34262,34263,34264,34265,34266,34267,34268,34269,34270,34271,34272,34273,34274,34275,34276,34277,34278,34279,34280,34281,34282,34283,34284,34285,34286,34287,34288,34289,34290,34291,34292,34293,34294,34295,34296,34297,34298,34299,34300,34301,34302,34303,34304,34305,34306,34307,34308,34309,34310,34311,34312,34313,34314,34315,34316,34317,34318,34319,34320,34321,34322,34323,34324,34325,34326,34327,34328,34329,34330,34331,34332,34333,34334,34335,34336,34337,34338,34339,34340,34341,34342,34343,34344,34345,34346,34347,34348,34349,34350,34351,34352,34353,34354,34355,34356,34357,34358,34359,34360,34361,34362,34363,34364,34365,34366,34367,34368,34369,34370,34371,34372,34373,34374,34375,34376,34377,34378,34379,34380,34381,34382,34383,34384,34385,34386,34387,34388,34389,34390,34391,34392,34393,34394,34395,34396,34397,34398,34399,34400,34401,34402,34403,34404,34405,34406,34407,34408,34409,34410,34411,34412,34413,34414,34415,34416,34417,34418,34419,34420,34421,34422,34423,34424,34425,34426,34427,34428,34429,34430,34431,34432,34433,34434,34435,34436,34437,34438,34439,34440,34441,34442,34443,34444,34445,34446,34447,34448,34449,34450,34451,34452,34453,34454,34455,34456,34457,34458,34459,34460,34461,34462,34463,34464,34465,34466,34467,34468,34469,34470,34471,34472,34473,34474,34475,34476,34477,34478,34479,34480,34481,34482,34483,34484,34485,34486,34487,34488,34489,34490,34491,34492,34493,34494,34495,34496,34497,34498,34499,34500,34501,34502,34503,34504,34505,34506,34507,34508,34509,34510,34511,34512,34513,34514,34515,34516,34517,34518,34519,34520,34521,34522,34523,34524,34525,34526,34527,34528,34529,34530,34531,34532,34533,34534,34535,34536,34537,34538,34539,34540,34541,34542,34543,34544,34545,34546,34547,34548,34549,34550,34551,34552,34553,34554,34555,34556,34557,34558,34559,34560,34561,34562,34563,34564,34565,34566,34567,34568,34569,34570,34571,34572,34573,34574,34575,34576,34577,34578,34579,34580,34581,34582,34583,34584,34585,34586,34587,34588,34589,34590,34591,34592,34593,34594,34595,34596,34597,34598,34599,34600,34601,34602,34603,34604,34605,34606,34607,34608,34609,34610,34611,34612,34613,34614,34615,34616,34617,34618,34619,34620,34621,34622,34623,34624,34625,34626,34627,34628,34629,34630,34631,34632,34633,34634,34635,34636,34637,34638,34639,34640,34641,34642,34643,34644,34645,34646,34647,34648,34649,34650,34651,34652,34653,34654,34655,34656,34657,34658,34659,34660,34661,34662,34663,34664,34665,34666,34667,34668,34669,34670,34671,34672,34673,34674,34675,34676,34677,34678,34679,34680,34681,34682,34683,34684,34685,34686,34687,34688,34689,34690,34691,34692,34693,34694,34695,34696,34697,34698,34699,34700,34701,34702,34703,34704,34705,34706,34707,34708,34709,34710,34711,34712,34713,34714,34715,34716,34717,34718,34719,34720,34721,34722,34723,34724,34725,34726,34727,34728,34729,34730,34731,34732,34733,34734,34735,34736,34737,34738,34739,34740,34741,34742,34743,34744,34745,34746,34747,34748,34749,34750,34751,34752,34753,34754,34755,34756,34757,34758,34759,34760,34761,34762,34763,34764,34765,34766,34767,34768,34769,34770,34771,34772,34773,34774,34775,34776,34777,34778,34779,34780,34781,34782,34783,34784,34785,34786,34787,34788,34789,34790,34791,34792,34793,34794,34795,34796,34797,34798,34799,34800,34801,34802,34803,34804,34805,34806,34807,34808,34809,34810,34811,34812,34813,34814,34815,34816,34817,34818,34819,34820,34821,34822,34823,34824,34825,34826,34827,34828,34829,34830,34831,34832,34833,34834,34835,34836,34837,34838,34839,34840,34841,34842,34843,34844,34845,34846,34847,34848,34849,34850,34851,34852,34853,34854,34855,34856,34857,34858,34859,34860,34861,34862,34863,34864,34865,34866,34867,34868,34869,34870,34871,34872,34873,34874,34875,34876,34877,34878,34879,34880,34881,34882,34883,34884,34885,34886,34887,34888,34889,34890,34891,34892,34893,34894,34895,34896,34897,34898,34899,34900,34901,34902,34903,34904,34905,34906,34907,34908,34909,34910,34911,34912,34913,34914,34915,34916,34917,34918,34919,34920,34921,34922,34923,34924,34925,34926,34927,34928,34929,34930,34931,34932,34933,34934,34935,34936,34937,34938,34939,34940,34941,34942,34943,34944,34945,34946,34947,34948,34949,34950,34951,34952,34953,34954,34955,34956,34957,34958,34959,34960,34961,34962,34963,34964,34965,34966,34967,34968,34969,34970,34971,34972,34973,34974,34975,34976,34977,34978,34979,34980,34981,34982,34983,34984,34985,34986,34987,34988,34989,34990,34991,34992,34993,34994,34995,34996,34997,34998,34999,35000,35001,35002,35003,35004,35005,35006,35007,35008,35009,35010,35011,35012,35013,35014,35015,35016,35017,35018,35019,35020,35021,35022,35023,35024,35025,35026,35027,35028,35029,35030,35031,35032,35033,35034,35035,35036,35037,35038,35039,35040,35041,35042,35043,35044,35045,35046,35047,35048,35049,35050,35051,35052,35053,35054,35055,35056,35057,35058,35059,35060,35061,35062,35063,35064,35065,35066,35067,35068,35069,35070,35071,35072,35073,35074,35075,35076,35077,35078,35079,35080,35081,35082,35083,35084,35085,35086,35087,35088,35089,35090,35091,35092,35093,35094,35095,35096,35097,35098,35099,35100,35101,35102,35103,35104,35105,35106,35107,35108,35109,35110,35111,35112,35113,35114,35115,35116,35117,35118,35119,35120,35121,35122,35123,35124,35125,35126,35127,35128,35129,35130,35131,35132,35133,35134,35135,35136,35137,35138,35139,35140,35141,35142,35143,35144,35145,35146,35147,35148,35149,35150,35151,35152,35153,35154,35155,35156,35157,35158,35159,35160,35161,35162,35163,35164,35165,35166,35167,35168,35169,35170,35171,35172,35173,35174,35175,35176,35177,35178,35179,35180,35181,35182,35183,35184,35185,35186,35187,35188,35189,35190,35191,35192,35193,35194,35195,35196,35197,35198,35199,35200,35201,35202,35203,35204,35205,35206,35207,35208,35209,35210,35211,35212,35213,35214,35215,35216,35217,35218,35219,35220,35221,35222,35223,35224,35225,35226,35227,35228,35229,35230,35231,35232,35233,35234,35235,35236,35237,35238,35239,35240,35241,35242,35243,35244,35245,35246,35247,35248,35249,35250,35251,35252,35253,35254,35255,35256,35257,35258,35259,35260,35261,35262,35263,35264,35265,35266,35267,35268,35269,35270,35271,35272,35273,35274,35275,35276,35277,35278,35279,35280,35281,35282,35283,35284,35285,35286,35287,35288,35289,35290,35291,35292,35293,35294,35295,35296,35297,35298,35299,35300,35301,35302,35303,35304,35305,35306,35307,35308,35309,35310,35311,35312,35313,35314,35315,35316,35317,35318,35319,35320,35321,35322,35323,35324,35325,35326,35327,35328,35329,35330,35331,35332,35333,35334,35335,35336,35337,35338,35339,35340,35341,35342,35343,35344,35345,35346,35347,35348,35349,35350,35351,35352,35353,35354,35355,35356,35357,35358,35359,35360,35361,35362,35363,35364,35365,35366,35367,35368,35369,35370,35371,35372,35373,35374,35375,35376,35377,35378,35379,35380,35381,35382,35383,35384,35385,35386,35387,35388,35389,35390,35391,35392,35393,35394,35395,35396,35397,35398,35399,35400,35401,35402,35403,35404,35405,35406,35407,35408,35409,35410,35411,35412,35413,35414,35415,35416,35417,35418,35419,35420,35421,35422,35423,35424,35425,35426,35427,35428,35429,35430,35431,35432,35433,35434,35435,35436,35437,35438,35439,35440,35441,35442,35443,35444,35445,35446,35447,35448,35449,35450,35451,35452,35453,35454,35455,35456,35457,35458,35459,35460,35461,35462,35463,35464,35465,35466,35467,35468,35469,35470,35471,35472,35473,35474,35475,35476,35477,35478,35479,35480,35481,35482,35483,35484,35485,35486,35487,35488,35489,35490,35491,35492,35493,35494,35495,35496,35497,35498,35499,35500,35501,35502,35503,35504,35505,35506,35507,35508,35509,35510,35511,35512,35513,35514,35515,35516,35517,35518,35519,35520,35521,35522,35523,35524,35525,35526,35527,35528,35529,35530,35531,35532,35533,35534,35535,35536,35537,35538,35539,35540,35541,35542,35543,35544,35545,35546,35547,35548,35549,35550,35551,35552,35553,35554,35555,35556,35557,35558,35559,35560,35561,35562,35563,35564,35565,35566,35567,35568,35569,35570,35571,35572,35573,35574,35575,35576,35577,35578,35579,35580,35581,35582,35583,35584,35585,35586,35587,35588,35589,35590,35591,35592,35593,35594,35595,35596,35597,35598,35599,35600,35601,35602,35603,35604,35605,35606,35607,35608,35609,35610,35611,35612,35613,35614,35615,35616,35617,35618,35619,35620,35621,35622,35623,35624,35625,35626,35627,35628,35629,35630,35631,35632,35633,35634,35635,35636,35637,35638,35639,35640,35641,35642,35643,35644,35645,35646,35647,35648,35649,35650,35651,35652,35653,35654,35655,35656,35657,35658,35659,35660,35661,35662,35663,35664,35665,35666,35667,35668,35669,35670,35671,35672,35673,35674,35675,35676,35677,35678,35679,35680,35681,35682,35683,35684,35685,35686,35687,35688,35689,35690,35691,35692,35693,35694,35695,35696,35697,35698,35699,35700,35701,35702,35703,35704,35705,35706,35707,35708,35709,35710,35711,35712,35713,35714,35715,35716,35717,35718,35719,35720,35721,35722,35723,35724,35725,35726,35727,35728,35729,35730,35731,35732,35733,35734,35735,35736,35737,35738,35739,35740,35741,35742,35743,35744,35745,35746,35747,35748,35749,35750,35751,35752,35753,35754,35755,35756,35757,35758,35759,35760,35761,35762,35763,35764,35765,35766,35767,35768,35769,35770,35771,35772,35773,35774,35775,35776,35777,35778,35779,35780,35781,35782,35783,35784,35785,35786,35787,35788,35789,35790,35791,35792,35793,35794,35795,35796,35797,35798,35799,35800,35801,35802,35803,35804,35805,35806,35807,35808,35809,35810,35811,35812,35813,35814,35815,35816,35817,35818,35819,35820,35821,35822,35823,35824,35825,35826,35827,35828,35829,35830,35831,35832,35833,35834,35835,35836,35837,35838,35839,35840,35841,35842,35843,35844,35845,35846,35847,35848,35849,35850,35851,35852,35853,35854,35855,35856,35857,35858,35859,35860,35861,35862,35863,35864,35865,35866,35867,35868,35869,35870,35871,35872,35873,35874,35875,35876,35877,35878,35879,35880,35881,35882,35883,35884,35885,35886,35887,35888,35889,35890,35891,35892,35893,35894,35895,35896,35897,35898,35899,35900,35901,35902,35903,35904,35905,35906,35907,35908,35909,35910,35911,35912,35913,35914,35915,35916,35917,35918,35919,35920,35921,35922,35923,35924,35925,35926,35927,35928,35929,35930,35931,35932,35933,35934,35935,35936,35937,35938,35939,35940,35941,35942,35943,35944,35945,35946,35947,35948,35949,35950,35951,35952,35953,35954,35955,35956,35957,35958,35959,35960,35961,35962,35963,35964,35965,35966,35967,35968,35969,35970,35971,35972,35973,35974,35975,35976,35977,35978,35979,35980,35981,35982,35983,35984,35985,35986,35987,35988,35989,35990,35991,35992,35993,35994,35995,35996,35997,35998,35999,36000,36001,36002,36003,36004,36005,36006,36007,36008,36009,36010,36011,36012,36013,36014,36015,36016,36017,36018,36019,36020,36021,36022,36023,36024,36025,36026,36027,36028,36029,36030,36031,36032,36033,36034,36035,36036,36037,36038,36039,36040,36041,36042,36043,36044,36045,36046,36047,36048,36049,36050,36051,36052,36053,36054,36055,36056,36057,36058,36059,36060,36061,36062,36063,36064,36065,36066,36067,36068,36069,36070,36071,36072,36073,36074,36075,36076,36077,36078,36079,36080,36081,36082,36083,36084,36085,36086,36087,36088,36089,36090,36091,36092,36093,36094,36095,36096,36097,36098,36099,36100,36101,36102,36103,36104,36105,36106,36107,36108,36109,36110,36111,36112,36113,36114,36115,36116,36117,36118,36119,36120,36121,36122,36123,36124,36125,36126,36127,36128,36129,36130,36131,36132,36133,36134,36135,36136,36137,36138,36139,36140,36141,36142,36143,36144,36145,36146,36147,36148,36149,36150,36151,36152,36153,36154,36155,36156,36157,36158,36159,36160,36161,36162,36163,36164,36165,36166,36167,36168,36169,36170,36171,36172,36173,36174,36175,36176,36177,36178,36179,36180,36181,36182,36183,36184,36185,36186,36187,36188,36189,36190,36191,36192,36193,36194,36195,36196,36197,36198,36199,36200,36201,36202,36203,36204,36205,36206,36207,36208,36209,36210,36211,36212,36213,36214,36215,36216,36217,36218,36219,36220,36221,36222,36223,36224,36225,36226,36227,36228,36229,36230,36231,36232,36233,36234,36235,36236,36237,36238,36239,36240,36241,36242,36243,36244,36245,36246,36247,36248,36249,36250,36251,36252,36253,36254,36255,36256,36257,36258,36259,36260,36261,36262,36263,36264,36265,36266,36267,36268,36269,36270,36271,36272,36273,36274,36275,36276,36277,36278,36279,36280,36281,36282,36283,36284,36285,36286,36287,36288,36289,36290,36291,36292,36293,36294,36295,36296,36297,36298,36299,36300,36301,36302,36303,36304,36305,36306,36307,36308,36309,36310,36311,36312,36313,36314,36315,36316,36317,36318,36319,36320,36321,36322,36323,36324,36325,36326,36327,36328,36329,36330,36331,36332,36333,36334,36335,36336,36337,36338,36339,36340,36341,36342,36343,36344,36345,36346,36347,36348,36349,36350,36351,36352,36353,36354,36355,36356,36357,36358,36359,36360,36361,36362,36363,36364,36365,36366,36367,36368,36369,36370,36371,36372,36373,36374,36375,36376,36377,36378,36379,36380,36381,36382,36383,36384,36385,36386,36387,36388,36389,36390,36391,36392,36393,36394,36395,36396,36397,36398,36399,36400,36401,36402,36403,36404,36405,36406,36407,36408,36409,36410,36411,36412,36413,36414,36415,36416,36417,36418,36419,36420,36421,36422,36423,36424,36425,36426,36427,36428,36429,36430,36431,36432,36433,36434,36435,36436,36437,36438,36439,36440,36441,36442,36443,36444,36445,36446,36447,36448,36449,36450,36451,36452,36453,36454,36455,36456,36457,36458,36459,36460,36461,36462,36463,36464,36465,36466,36467,36468,36469,36470,36471,36472,36473,36474,36475,36476,36477,36478,36479,36480,36481,36482,36483,36484,36485,36486,36487,36488,36489,36490,36491,36492,36493,36494,36495,36496,36497,36498,36499,36500,36501,36502,36503,36504,36505,36506,36507,36508,36509,36510,36511,36512,36513,36514,36515,36516,36517,36518,36519,36520,36521,36522,36523,36524,36525,36526,36527,36528,36529,36530,36531,36532,36533,36534,36535,36536,36537,36538,36539,36540,36541,36542,36543,36544,36545,36546,36547,36548,36549,36550,36551,36552,36553,36554,36555,36556,36557,36558,36559,36560,36561,36562,36563,36564,36565,36566,36567,36568,36569,36570,36571,36572,36573,36574,36575,36576,36577,36578,36579,36580,36581,36582,36583,36584,36585,36586,36587,36588,36589,36590,36591,36592,36593,36594,36595,36596,36597,36598,36599,36600,36601,36602,36603,36604,36605,36606,36607,36608,36609,36610,36611,36612,36613,36614,36615,36616,36617,36618,36619,36620,36621,36622,36623,36624,36625,36626,36627,36628,36629,36630,36631,36632,36633,36634,36635,36636,36637,36638,36639,36640,36641,36642,36643,36644,36645,36646,36647,36648,36649,36650,36651,36652,36653,36654,36655,36656,36657,36658,36659,36660,36661,36662,36663,36664,36665,36666,36667,36668,36669,36670,36671,36672,36673,36674,36675,36676,36677,36678,36679,36680,36681,36682,36683,36684,36685,36686,36687,36688,36689,36690,36691,36692,36693,36694,36695,36696,36697,36698,36699,36700,36701,36702,36703,36704,36705,36706,36707,36708,36709,36710,36711,36712,36713,36714,36715,36716,36717,36718,36719,36720,36721,36722,36723,36724,36725,36726,36727,36728,36729,36730,36731,36732,36733,36734,36735,36736,36737,36738,36739,36740,36741,36742,36743,36744,36745,36746,36747,36748,36749,36750,36751,36752,36753,36754,36755,36756,36757,36758,36759,36760,36761,36762,36763,36764,36765,36766,36767,36768,36769,36770,36771,36772,36773,36774,36775,36776,36777,36778,36779,36780,36781,36782,36783,36784,36785,36786,36787,36788,36789,36790,36791,36792,36793,36794,36795,36796,36797,36798,36799,36800,36801,36802,36803,36804,36805,36806,36807,36808,36809,36810,36811,36812,36813,36814,36815,36816,36817,36818,36819,36820,36821,36822,36823,36824,36825,36826,36827,36828,36829,36830,36831,36832,36833,36834,36835,36836,36837,36838,36839,36840,36841,36842,36843,36844,36845,36846,36847,36848,36849,36850,36851,36852,36853,36854,36855,36856,36857,36858,36859,36860,36861,36862,36863,36864,36865,36866,36867,36868,36869,36870,36871,36872,36873,36874,36875,36876,36877,36878,36879,36880,36881,36882,36883,36884,36885,36886,36887,36888,36889,36890,36891,36892,36893,36894,36895,36896,36897,36898,36899,36900,36901,36902,36903,36904,36905,36906,36907,36908,36909,36910,36911,36912,36913,36914,36915,36916,36917,36918,36919,36920,36921,36922,36923,36924,36925,36926,36927,36928,36929,36930,36931,36932,36933,36934,36935,36936,36937,36938,36939,36940,36941,36942,36943,36944,36945,36946,36947,36948,36949,36950,36951,36952,36953,36954,36955,36956,36957,36958,36959,36960,36961,36962,36963,36964,36965,36966,36967,36968,36969,36970,36971,36972,36973,36974,36975,36976,36977,36978,36979,36980,36981,36982,36983,36984,36985,36986,36987,36988,36989,36990,36991,36992,36993,36994,36995,36996,36997,36998,36999,37000,37001,37002,37003,37004,37005,37006,37007,37008,37009,37010,37011,37012,37013,37014,37015,37016,37017,37018,37019,37020,37021,37022,37023,37024,37025,37026,37027,37028,37029,37030,37031,37032,37033,37034,37035,37036,37037,37038,37039,37040,37041,37042,37043,37044,37045,37046,37047,37048,37049,37050,37051,37052,37053,37054,37055,37056,37057,37058,37059,37060,37061,37062,37063,37064,37065,37066,37067,37068,37069,37070,37071,37072,37073,37074,37075,37076,37077,37078,37079,37080,37081,37082,37083,37084,37085,37086,37087,37088,37089,37090,37091,37092,37093,37094,37095,37096,37097,37098,37099,37100,37101,37102,37103,37104,37105,37106,37107,37108,37109,37110,37111,37112,37113,37114,37115,37116,37117,37118,37119,37120,37121,37122,37123,37124,37125,37126,37127,37128,37129,37130,37131,37132,37133,37134,37135,37136,37137,37138,37139,37140,37141,37142,37143,37144,37145,37146,37147,37148,37149,37150,37151,37152,37153,37154,37155,37156,37157,37158,37159,37160,37161,37162,37163,37164,37165,37166,37167,37168,37169,37170,37171,37172,37173,37174,37175,37176,37177,37178,37179,37180,37181,37182,37183,37184,37185,37186,37187,37188,37189,37190,37191,37192,37193,37194,37195,37196,37197,37198,37199,37200,37201,37202,37203,37204,37205,37206,37207,37208,37209,37210,37211,37212,37213,37214,37215,37216,37217,37218,37219,37220,37221,37222,37223,37224,37225,37226,37227,37228,37229,37230,37231,37232,37233,37234,37235,37236,37237,37238,37239,37240,37241,37242,37243,37244,37245,37246,37247,37248,37249,37250,37251,37252,37253,37254,37255,37256,37257,37258,37259,37260,37261,37262,37263,37264,37265,37266,37267,37268,37269,37270,37271,37272,37273,37274,37275,37276,37277,37278,37279,37280,37281,37282,37283,37284,37285,37286,37287,37288,37289,37290,37291,37292,37293,37294,37295,37296,37297,37298,37299,37300,37301,37302,37303,37304,37305,37306,37307,37308,37309,37310,37311,37312,37313,37314,37315,37316,37317,37318,37319,37320,37321,37322,37323,37324,37325,37326,37327,37328,37329,37330,37331,37332,37333,37334,37335,37336,37337,37338,37339,37340,37341,37342,37343,37344,37345,37346,37347,37348,37349,37350,37351,37352,37353,37354,37355,37356,37357,37358,37359,37360,37361,37362,37363,37364,37365,37366,37367,37368,37369,37370,37371,37372,37373,37374,37375,37376,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37387,37388,37389,37390,37391,37392,37393,37394,37395,37396,37397,37398,37399,37400,37401,37402,37403,37404,37405,37406,37407,37408,37409,37410,37411,37412,37413,37414,37415,37416,37417,37418,37419,37420,37421,37422,37423,37424,37425,37426,37427,37428,37429,37430,37431,37432,37433,37434,37435,37436,37437,37438,37439,37440,37441,37442,37443,37444,37445,37446,37447,37448,37449,37450,37451,37452,37453,37454,37455,37456,37457,37458,37459,37460,37461,37462,37463,37464,37465,37466,37467,37468,37469,37470,37471,37472,37473,37474,37475,37476,37477,37478,37479,37480,37481,37482,37483,37484,37485,37486,37487,37488,37489,37490,37491,37492,37493,37494,37495,37496,37497,37498,37499,37500,37501,37502,37503,37504,37505,37506,37507,37508,37509,37510,37511,37512,37513,37514,37515,37516,37517,37518,37519,37520,37521,37522,37523,37524,37525,37526,37527,37528,37529,37530,37531,37532,37533,37534,37535,37536,37537,37538,37539,37540,37541,37542,37543,37544,37545,37546,37547,37548,37549,37550,37551,37552,37553,37554,37555,37556,37557,37558,37559,37560,37561,37562,37563,37564,37565,37566,37567,37568,37569,37570,37571,37572,37573,37574,37575,37576,37577,37578,37579,37580,37581,37582,37583,37584,37585,37586,37587,37588,37589,37590,37591,37592,37593,37594,37595,37596,37597,37598,37599,37600,37601,37602,37603,37604,37605,37606,37607,37608,37609,37610,37611,37612,37613,37614,37615,37616,37617,37618,37619,37620,37621,37622,37623,37624,37625,37626,37627,37628,37629,37630,37631,37632,37633,37634,37635,37636,37637,37638,37639,37640,37641,37642,37643,37644,37645,37646,37647,37648,37649,37650,37651,37652,37653,37654,37655,37656,37657,37658,37659,37660,37661,37662,37663,37664,37665,37666,37667,37668,37669,37670,37671,37672,37673,37674,37675,37676,37677,37678,37679,37680,37681,37682,37683,37684,37685,37686,37687,37688,37689,37690,37691,37692,37693,37694,37695,37696,37697,37698,37699,37700,37701,37702,37703,37704,37705,37706,37707,37708,37709,37710,37711,37712,37713,37714,37715,37716,37717,37718,37719,37720,37721,37722,37723,37724,37725,37726,37727,37728,37729,37730,37731,37732,37733,37734,37735,37736,37737,37738,37739,37740,37741,37742,37743,37744,37745,37746,37747,37748,37749,37750,37751,37752,37753,37754,37755,37756,37757,37758,37759,37760,37761,37762,37763,37764,37765,37766,37767,37768,37769,37770,37771,37772,37773,37774,37775,37776,37777,37778,37779,37780,37781,37782,37783,37784,37785,37786,37787,37788,37789,37790,37791,37792,37793,37794,37795,37796,37797,37798,37799,37800,37801,37802,37803,37804,37805,37806,37807,37808,37809,37810,37811,37812,37813,37814,37815,37816,37817,37818,37819,37820,37821,37822,37823,37824,37825,37826,37827,37828,37829,37830,37831,37832,37833,37834,37835,37836,37837,37838,37839,37840,37841,37842,37843,37844,37845,37846,37847,37848,37849,37850,37851,37852,37853,37854,37855,37856,37857,37858,37859,37860,37861,37862,37863,37864,37865,37866,37867,37868,37869,37870,37871,37872,37873,37874,37875,37876,37877,37878,37879,37880,37881,37882,37883,37884,37885,37886,37887,37888,37889,37890,37891,37892,37893,37894,37895,37896,37897,37898,37899,37900,37901,37902,37903,37904,37905,37906,37907,37908,37909,37910,37911,37912,37913,37914,37915,37916,37917,37918,37919,37920,37921,37922,37923,37924,37925,37926,37927,37928,37929,37930,37931,37932,37933,37934,37935,37936,37937,37938,37939,37940,37941,37942,37943,37944,37945,37946,37947,37948,37949,37950,37951,37952,37953,37954,37955,37956,37957,37958,37959,37960,37961,37962,37963,37964,37965,37966,37967,37968,37969,37970,37971,37972,37973,37974,37975,37976,37977,37978,37979,37980,37981,37982,37983,37984,37985,37986,37987,37988,37989,37990,37991,37992,37993,37994,37995,37996,37997,37998,37999,38000,38001,38002,38003,38004,38005,38006,38007,38008,38009,38010,38011,38012,38013,38014,38015,38016,38017,38018,38019,38020,38021,38022,38023,38024,38025,38026,38027,38028,38029,38030,38031,38032,38033,38034,38035,38036,38037,38038,38039,38040,38041,38042,38043,38044,38045,38046,38047,38048,38049,38050,38051,38052,38053,38054,38055,38056,38057,38058,38059,38060,38061,38062,38063,38064,38065,38066,38067,38068,38069,38070,38071,38072,38073,38074,38075,38076,38077,38078,38079,38080,38081,38082,38083,38084,38085,38086,38087,38088,38089,38090,38091,38092,38093,38094,38095,38096,38097,38098,38099,38100,38101,38102,38103,38104,38105,38106,38107,38108,38109,38110,38111,38112,38113,38114,38115,38116,38117,38118,38119,38120,38121,38122,38123,38124,38125,38126,38127,38128,38129,38130,38131,38132,38133,38134,38135,38136,38137,38138,38139,38140,38141,38142,38143,38144,38145,38146,38147,38148,38149,38150,38151,38152,38153,38154,38155,38156,38157,38158,38159,38160,38161,38162,38163,38164,38165,38166,38167,38168,38169,38170,38171,38172,38173,38174,38175,38176,38177,38178,38179,38180,38181,38182,38183,38184,38185,38186,38187,38188,38189,38190,38191,38192,38193,38194,38195,38196,38197,38198,38199,38200,38201,38202,38203,38204,38205,38206,38207,38208,38209,38210,38211,38212,38213,38214,38215,38216,38217,38218,38219,38220,38221,38222,38223,38224,38225,38226,38227,38228,38229,38230,38231,38232,38233,38234,38235,38236,38237,38238,38239,38240,38241,38242,38243,38244,38245,38246,38247,38248,38249,38250,38251,38252,38253,38254,38255,38256,38257,38258,38259,38260,38261,38262,38263,38264,38265,38266,38267,38268,38269,38270,38271,38272,38273,38274,38275,38276,38277,38278,38279,38280,38281,38282,38283,38284,38285,38286,38287,38288,38289,38290,38291,38292,38293,38294,38295,38296,38297,38298,38299,38300,38301,38302,38303,38304,38305,38306,38307,38308,38309,38310,38311,38312,38313,38314,38315,38316,38317,38318,38319,38320,38321,38322,38323,38324,38325,38326,38327,38328,38329,38330,38331,38332,38333,38334,38335,38336,38337,38338,38339,38340,38341,38342,38343,38344,38345,38346,38347,38348,38349,38350,38351,38352,38353,38354,38355,38356,38357,38358,38359,38360,38361,38362,38363,38364,38365,38366,38367,38368,38369,38370,38371,38372,38373,38374,38375,38376,38377,38378,38379,38380,38381,38382,38383,38384,38385,38386,38387,38388,38389,38390,38391,38392,38393,38394,38395,38396,38397,38398,38399,38400,38401,38402,38403,38404,38405,38406,38407,38408,38409,38410,38411,38412,38413,38414,38415,38416,38417,38418,38419,38420,38421,38422,38423,38424,38425,38426,38427,38428,38429,38430,38431,38432,38433,38434,38435,38436,38437,38438,38439,38440,38441,38442,38443,38444,38445,38446,38447,38448,38449,38450,38451,38452,38453,38454,38455,38456,38457,38458,38459,38460,38461,38462,38463,38464,38465,38466,38467,38468,38469,38470,38471,38472,38473,38474,38475,38476,38477,38478,38479,38480,38481,38482,38483,38484,38485,38486,38487,38488,38489,38490,38491,38492,38493,38494,38495,38496,38497,38498,38499,38500,38501,38502,38503,38504,38505,38506,38507,38508,38509,38510,38511,38512,38513,38514,38515,38516,38517,38518,38519,38520,38521,38522,38523,38524,38525,38526,38527,38528,38529,38530,38531,38532,38533,38534,38535,38536,38537,38538,38539,38540,38541,38542,38543,38544,38545,38546,38547,38548,38549,38550,38551,38552,38553,38554,38555,38556,38557,38558,38559,38560,38561,38562,38563,38564,38565,38566,38567,38568,38569,38570,38571,38572,38573,38574,38575,38576,38577,38578,38579,38580,38581,38582,38583,38584,38585,38586,38587,38588,38589,38590,38591,38592,38593,38594,38595,38596,38597,38598,38599,38600,38601,38602,38603,38604,38605,38606,38607,38608,38609,38610,38611,38612,38613,38614,38615,38616,38617,38618,38619,38620,38621,38622,38623,38624,38625,38626,38627,38628,38629,38630,38631,38632,38633,38634,38635,38636,38637,38638,38639,38640,38641,38642,38643,38644,38645,38646,38647,38648,38649,38650,38651,38652,38653,38654,38655,38656,38657,38658,38659,38660,38661,38662,38663,38664,38665,38666,38667,38668,38669,38670,38671,38672,38673,38674,38675,38676,38677,38678,38679,38680,38681,38682,38683,38684,38685,38686,38687,38688,38689,38690,38691,38692,38693,38694,38695,38696,38697,38698,38699,38700,38701,38702,38703,38704,38705,38706,38707,38708,38709,38710,38711,38712,38713,38714,38715,38716,38717,38718,38719,38720,38721,38722,38723,38724,38725,38726,38727,38728,38729,38730,38731,38732,38733,38734,38735,38736,38737,38738,38739,38740,38741,38742,38743,38744,38745,38746,38747,38748,38749,38750,38751,38752,38753,38754,38755,38756,38757,38758,38759,38760,38761,38762,38763,38764,38765,38766,38767,38768,38769,38770,38771,38772,38773,38774,38775,38776,38777,38778,38779,38780,38781,38782,38783,38784,38785,38786,38787,38788,38789,38790,38791,38792,38793,38794,38795,38796,38797,38798,38799,38800,38801,38802,38803,38804,38805,38806,38807,38808,38809,38810,38811,38812,38813,38814,38815,38816,38817,38818,38819,38820,38821,38822,38823,38824,38825,38826,38827,38828,38829,38830,38831,38832,38833,38834,38835,38836,38837,38838,38839,38840,38841,38842,38843,38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38854,38855,38856,38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869,38870,38871,38872,38873,38874,38875,38876,38877,38878,38879,38880,38881,38882,38883,38884,38885,38886,38887,38888,38889,38890,38891,38892,38893,38894,38895,38896,38897,38898,38899,38900,38901,38902,38903,38904,38905,38906,38907,38908,38909,38910,38911,38912,38913,38914,38915,38916,38917,38918,38919,38920,38921,38922,38923,38924,38925,38926,38927,38928,38929,38930,38931,38932,38933,38934,38935,38936,38937,38938,38939,38940,38941,38942,38943,38944,38945,38946,38947,38948,38949,38950,38951,38952,38953,38954,38955,38956,38957,38958,38959,38960,38961,38962,38963,38964,38965,38966,38967,38968,38969,38970,38971,38972,38973,38974,38975,38976,38977,38978,38979,38980,38981,38982,38983,38984,38985,38986,38987,38988,38989,38990,38991,38992,38993,38994,38995,38996,38997,38998,38999,39000,39001,39002,39003,39004,39005,39006,39007,39008,39009,39010,39011,39012,39013,39014,39015,39016,39017,39018,39019,39020,39021,39022,39023,39024,39025,39026,39027,39028,39029,39030,39031,39032,39033,39034,39035,39036,39037,39038,39039,39040,39041,39042,39043,39044,39045,39046,39047,39048,39049,39050,39051,39052,39053,39054,39055,39056,39057,39058,39059,39060,39061,39062,39063,39064,39065,39066,39067,39068,39069,39070,39071,39072,39073,39074,39075,39076,39077,39078,39079,39080,39081,39082,39083,39084,39085,39086,39087,39088,39089,39090,39091,39092,39093,39094,39095,39096,39097,39098,39099,39100,39101,39102,39103,39104,39105,39106,39107,39108,39109,39110,39111,39112,39113,39114,39115,39116,39117,39118,39119,39120,39121,39122,39123,39124,39125,39126,39127,39128,39129,39130,39131,39132,39133,39134,39135,39136,39137,39138,39139,39140,39141,39142,39143,39144,39145,39146,39147,39148,39149,39150,39151,39152,39153,39154,39155,39156,39157,39158,39159,39160,39161,39162,39163,39164,39165,39166,39167,39168,39169,39170,39171,39172,39173,39174,39175,39176,39177,39178,39179,39180,39181,39182,39183,39184,39185,39186,39187,39188,39189,39190,39191,39192,39193,39194,39195,39196,39197,39198,39199,39200,39201,39202,39203,39204,39205,39206,39207,39208,39209,39210,39211,39212,39213,39214,39215,39216,39217,39218,39219,39220,39221,39222,39223,39224,39225,39226,39227,39228,39229,39230,39231,39232,39233,39234,39235,39236,39237,39238,39239,39240,39241,39242,39243,39244,39245,39246,39247,39248,39249,39250,39251,39252,39253,39254,39255,39256,39257,39258,39259,39260,39261,39262,39263,39264,39265,39266,39267,39268,39269,39270,39271,39272,39273,39274,39275,39276,39277,39278,39279,39280,39281,39282,39283,39284,39285,39286,39287,39288,39289,39290,39291,39292,39293,39294,39295,39296,39297,39298,39299,39300,39301,39302,39303,39304,39305,39306,39307,39308,39309,39310,39311,39312,39313,39314,39315,39316,39317,39318,39319,39320,39321,39322,39323,39324,39325,39326,39327,39328,39329,39330,39331,39332,39333,39334,39335,39336,39337,39338,39339,39340,39341,39342,39343,39344,39345,39346,39347,39348,39349,39350,39351,39352,39353,39354,39355,39356,39357,39358,39359,39360,39361,39362,39363,39364,39365,39366,39367,39368,39369,39370,39371,39372,39373,39374,39375,39376,39377,39378,39379,39380,39381,39382,39383,39384,39385,39386,39387,39388,39389,39390,39391,39392,39393,39394,39395,39396,39397,39398,39399,39400,39401,39402,39403,39404,39405,39406,39407,39408,39409,39410,39411,39412,39413,39414,39415,39416,39417,39418,39419,39420,39421,39422,39423,39424,39425,39426,39427,39428,39429,39430,39431,39432,39433,39434,39435,39436,39437,39438,39439,39440,39441,39442,39443,39444,39445,39446,39447,39448,39449,39450,39451,39452,39453,39454,39455,39456,39457,39458,39459,39460,39461,39462,39463,39464,39465,39466,39467,39468,39469,39470,39471,39472,39473,39474,39475,39476,39477,39478,39479,39480,39481,39482,39483,39484,39485,39486,39487,39488,39489,39490,39491,39492,39493,39494,39495,39496,39497,39498,39499,39500,39501,39502,39503,39504,39505,39506,39507,39508,39509,39510,39511,39512,39513,39514,39515,39516,39517,39518,39519,39520,39521,39522,39523,39524,39525,39526,39527,39528,39529,39530,39531,39532,39533,39534,39535,39536,39537,39538,39539,39540,39541,39542,39543,39544,39545,39546,39547,39548,39549,39550,39551,39552,39553,39554,39555,39556,39557,39558,39559,39560,39561,39562,39563,39564,39565,39566,39567,39568,39569,39570,39571,39572,39573,39574,39575,39576,39577,39578,39579,39580,39581,39582,39583,39584,39585,39586,39587,39588,39589,39590,39591,39592,39593,39594,39595,39596,39597,39598,39599,39600,39601,39602,39603,39604,39605,39606,39607,39608,39609,39610,39611,39612,39613,39614,39615,39616,39617,39618,39619,39620,39621,39622,39623,39624,39625,39626,39627,39628,39629,39630,39631,39632,39633,39634,39635,39636,39637,39638,39639,39640,39641,39642,39643,39644,39645,39646,39647,39648,39649,39650,39651,39652,39653,39654,39655,39656,39657,39658,39659,39660,39661,39662,39663,39664,39665,39666,39667,39668,39669,39670,39671,39672,39673,39674,39675,39676,39677,39678,39679,39680,39681,39682,39683,39684,39685,39686,39687,39688,39689,39690,39691,39692,39693,39694,39695,39696,39697,39698,39699,39700,39701,39702,39703,39704,39705,39706,39707,39708,39709,39710,39711,39712,39713,39714,39715,39716,39717,39718,39719,39720,39721,39722,39723,39724,39725,39726,39727,39728,39729,39730,39731,39732,39733,39734,39735,39736,39737,39738,39739,39740,39741,39742,39743,39744,39745,39746,39747,39748,39749,39750,39751,39752,39753,39754,39755,39756,39757,39758,39759,39760,39761,39762,39763,39764,39765,39766,39767,39768,39769,39770,39771,39772,39773,39774,39775,39776,39777,39778,39779,39780,39781,39782,39783,39784,39785,39786,39787,39788,39789,39790,39791,39792,39793,39794,39795,39796,39797,39798,39799,39800,39801,39802,39803,39804,39805,39806,39807,39808,39809,39810,39811,39812,39813,39814,39815,39816,39817,39818,39819,39820,39821,39822,39823,39824,39825,39826,39827,39828,39829,39830,39831,39832,39833,39834,39835,39836,39837,39838,39839,39840,39841,39842,39843,39844,39845,39846,39847,39848,39849,39850,39851,39852,39853,39854,39855,39856,39857,39858,39859,39860,39861,39862,39863,39864,39865,39866,39867,39868,39869,39870,39871,39872,39873,39874,39875,39876,39877,39878,39879,39880,39881,39882,39883,39884,39885,39886,39887,39888,39889,39890,39891,39892,39893,39894,39895,39896,39897,39898,39899,39900,39901,39902,39903,39904,39905,39906,39907,39908,39909,39910,39911,39912,39913,39914,39915,39916,39917,39918,39919,39920,39921,39922,39923,39924,39925,39926,39927,39928,39929,39930,39931,39932,39933,39934,39935,39936,39937,39938,39939,39940,39941,39942,39943,39944,39945,39946,39947,39948,39949,39950,39951,39952,39953,39954,39955,39956,39957,39958,39959,39960,39961,39962,39963,39964,39965,39966,39967,39968,39969,39970,39971,39972,39973,39974,39975,39976,39977,39978,39979,39980,39981,39982,39983,39984,39985,39986,39987,39988,39989,39990,39991,39992,39993,39994,39995,39996,39997,39998,39999,40000,40001,40002,40003,40004,40005,40006,40007,40008,40009,40010,40011,40012,40013,40014,40015,40016,40017,40018,40019,40020,40021,40022,40023,40024,40025,40026,40027,40028,40029,40030,40031,40032,40033,40034,40035,40036,40037,40038,40039,40040,40041,40042,40043,40044,40045,40046,40047,40048,40049,40050,40051,40052,40053,40054,40055,40056,40057,40058,40059,40060,40061,40062,40063,40064,40065,40066,40067,40068,40069,40070,40071,40072,40073,40074,40075,40076,40077,40078,40079,40080,40081,40082,40083,40084,40085,40086,40087,40088,40089,40090,40091,40092,40093,40094,40095,40096,40097,40098,40099,40100,40101,40102,40103,40104,40105,40106,40107,40108,40109,40110,40111,40112,40113,40114,40115,40116,40117,40118,40119,40120,40121,40122,40123,40124,40125,40126,40127,40128,40129,40130,40131,40132,40133,40134,40135,40136,40137,40138,40139,40140,40141,40142,40143,40144,40145,40146,40147,40148,40149,40150,40151,40152,40153,40154,40155,40156,40157,40158,40159,40160,40161,40162,40163,40164,40165,40166,40167,40168,40169,40170,40171,40172,40173,40174,40175,40176,40177,40178,40179,40180,40181,40182,40183,40184,40185,40186,40187,40188,40189,40190,40191,40192,40193,40194,40195,40196,40197,40198,40199,40200,40201,40202,40203,40204,40205,40206,40207,40208,40209,40210,40211,40212,40213,40214,40215,40216,40217,40218,40219,40220,40221,40222,40223,40224,40225,40226,40227,40228,40229,40230,40231,40232,40233,40234,40235,40236,40237,40238,40239,40240,40241,40242,40243,40244,40245,40246,40247,40248,40249,40250,40251,40252,40253,40254,40255,40256,40257,40258,40259,40260,40261,40262,40263,40264,40265,40266,40267,40268,40269,40270,40271,40272,40273,40274,40275,40276,40277,40278,40279,40280,40281,40282,40283,40284,40285,40286,40287,40288,40289,40290,40291,40292,40293,40294,40295,40296,40297,40298,40299,40300,40301,40302,40303,40304,40305,40306,40307,40308,40309,40310,40311,40312,40313,40314,40315,40316,40317,40318,40319,40320,40321,40322,40323,40324,40325,40326,40327,40328,40329,40330,40331,40332,40333,40334,40335,40336,40337,40338,40339,40340,40341,40342,40343,40344,40345,40346,40347,40348,40349,40350,40351,40352,40353,40354,40355,40356,40357,40358,40359,40360,40361,40362,40363,40364,40365,40366,40367,40368,40369,40370,40371,40372,40373,40374,40375,40376,40377,40378,40379,40380,40381,40382,40383,40384,40385,40386,40387,40388,40389,40390,40391,40392,40393,40394,40395,40396,40397,40398,40399,40400,40401,40402,40403,40404,40405,40406,40407,40408,40409,40410,40411,40412,40413,40414,40415,40416,40417,40418,40419,40420,40421,40422,40423,40424,40425,40426,40427,40428,40429,40430,40431,40432,40433,40434,40435,40436,40437,40438,40439,40440,40441,40442,40443,40444,40445,40446,40447,40448,40449,40450,40451,40452,40453,40454,40455,40456,40457,40458,40459,40460,40461,40462,40463,40464,40465,40466,40467,40468,40469,40470,40471,40472,40473,40474,40475,40476,40477,40478,40479,40480,40481,40482,40483,40484,40485,40486,40487,40488,40489,40490,40491,40492,40493,40494,40495,40496,40497,40498,40499,40500,40501,40502,40503,40504,40505,40506,40507,40508,40509,40510,40511,40512,40513,40514,40515,40516,40517,40518,40519,40520,40521,40522,40523,40524,40525,40526,40527,40528,40529,40530,40531,40532,40533,40534,40535,40536,40537,40538,40539,40540,40541,40542,40543,40544,40545,40546,40547,40548,40549,40550,40551,40552,40553,40554,40555,40556,40557,40558,40559,40560,40561,40562,40563,40564,40565,40566,40567,40568,40569,40570,40571,40572,40573,40574,40575,40576,40577,40578,40579,40580,40581,40582,40583,40584,40585,40586,40587,40588,40589,40590,40591,40592,40593,40594,40595,40596,40597,40598,40599,40600,40601,40602,40603,40604,40605,40606,40607,40608,40609,40610,40611,40612,40613,40614,40615,40616,40617,40618,40619,40620,40621,40622,40623,40624,40625,40626,40627,40628,40629,40630,40631,40632,40633,40634,40635,40636,40637,40638,40639,40640,40641,40642,40643,40644,40645,40646,40647,40648,40649,40650,40651,40652,40653,40654,40655,40656,40657,40658,40659,40660,40661,40662,40663,40664,40665,40666,40667,40668,40669,40670,40671,40672,40673,40674,40675,40676,40677,40678,40679,40680,40681,40682,40683,40684,40685,40686,40687,40688,40689,40690,40691,40692,40693,40694,40695,40696,40697,40698,40699,40700,40701,40702,40703,40704,40705,40706,40707,40708,40709,40710,40711,40712,40713,40714,40715,40716,40717,40718,40719,40720,40721,40722,40723,40724,40725,40726,40727,40728,40729,40730,40731,40732,40733,40734,40735,40736,40737,40738,40739,40740,40741,40742,40743,40744,40745,40746,40747,40748,40749,40750,40751,40752,40753,40754,40755,40756,40757,40758,40759,40760,40761,40762,40763,40764,40765,40766,40767,40768,40769,40770,40771,40772,40773,40774,40775,40776,40777,40778,40779,40780,40781,40782,40783,40784,40785,40786,40787,40788,40789,40790,40791,40792,40793,40794,40795,40796,40797,40798,40799,40800,40801,40802,40803,40804,40805,40806,40807,40808,40809,40810,40811,40812,40813,40814,40815,40816,40817,40818,40819,40820,40821,40822,40823,40824,40825,40826,40827,40828,40829,40830,40831,40832,40833,40834,40835,40836,40837,40838,40839,40840,40841,40842,40843,40844,40845,40846,40847,40848,40849,40850,40851,40852,40853,40854,40855,40856,40857,40858,40859,40860,40861,40862,40863,40864,40865,40866,40867,40868,40869,40870,40871,40872,40873,40874,40875,40876,40877,40878,40879,40880,40881,40882,40883,40884,40885,40886,40887,40888,40889,40890,40891,40892,40893,40894,40895,40896,40897,40898,40899,40900,40901,40902,40903,40904,40905,40906,40907,40908,40909,40910,40911,40912,40913,40914,40915,40916,40917,40918,40919,40920,40921,40922,40923,40924,40925,40926,40927,40928,40929,40930,40931,40932,40933,40934,40935,40936,40937,40938,40939,40940,40941,40942,40943,40960,40961,40962,40963,40964,40965,40966,40967,40968,40969,40970,40971,40972,40973,40974,40975,40976,40977,40978,40979,40980,40981,40982,40983,40984,40985,40986,40987,40988,40989,40990,40991,40992,40993,40994,40995,40996,40997,40998,40999,41000,41001,41002,41003,41004,41005,41006,41007,41008,41009,41010,41011,41012,41013,41014,41015,41016,41017,41018,41019,41020,41021,41022,41023,41024,41025,41026,41027,41028,41029,41030,41031,41032,41033,41034,41035,41036,41037,41038,41039,41040,41041,41042,41043,41044,41045,41046,41047,41048,41049,41050,41051,41052,41053,41054,41055,41056,41057,41058,41059,41060,41061,41062,41063,41064,41065,41066,41067,41068,41069,41070,41071,41072,41073,41074,41075,41076,41077,41078,41079,41080,41081,41082,41083,41084,41085,41086,41087,41088,41089,41090,41091,41092,41093,41094,41095,41096,41097,41098,41099,41100,41101,41102,41103,41104,41105,41106,41107,41108,41109,41110,41111,41112,41113,41114,41115,41116,41117,41118,41119,41120,41121,41122,41123,41124,41125,41126,41127,41128,41129,41130,41131,41132,41133,41134,41135,41136,41137,41138,41139,41140,41141,41142,41143,41144,41145,41146,41147,41148,41149,41150,41151,41152,41153,41154,41155,41156,41157,41158,41159,41160,41161,41162,41163,41164,41165,41166,41167,41168,41169,41170,41171,41172,41173,41174,41175,41176,41177,41178,41179,41180,41181,41182,41183,41184,41185,41186,41187,41188,41189,41190,41191,41192,41193,41194,41195,41196,41197,41198,41199,41200,41201,41202,41203,41204,41205,41206,41207,41208,41209,41210,41211,41212,41213,41214,41215,41216,41217,41218,41219,41220,41221,41222,41223,41224,41225,41226,41227,41228,41229,41230,41231,41232,41233,41234,41235,41236,41237,41238,41239,41240,41241,41242,41243,41244,41245,41246,41247,41248,41249,41250,41251,41252,41253,41254,41255,41256,41257,41258,41259,41260,41261,41262,41263,41264,41265,41266,41267,41268,41269,41270,41271,41272,41273,41274,41275,41276,41277,41278,41279,41280,41281,41282,41283,41284,41285,41286,41287,41288,41289,41290,41291,41292,41293,41294,41295,41296,41297,41298,41299,41300,41301,41302,41303,41304,41305,41306,41307,41308,41309,41310,41311,41312,41313,41314,41315,41316,41317,41318,41319,41320,41321,41322,41323,41324,41325,41326,41327,41328,41329,41330,41331,41332,41333,41334,41335,41336,41337,41338,41339,41340,41341,41342,41343,41344,41345,41346,41347,41348,41349,41350,41351,41352,41353,41354,41355,41356,41357,41358,41359,41360,41361,41362,41363,41364,41365,41366,41367,41368,41369,41370,41371,41372,41373,41374,41375,41376,41377,41378,41379,41380,41381,41382,41383,41384,41385,41386,41387,41388,41389,41390,41391,41392,41393,41394,41395,41396,41397,41398,41399,41400,41401,41402,41403,41404,41405,41406,41407,41408,41409,41410,41411,41412,41413,41414,41415,41416,41417,41418,41419,41420,41421,41422,41423,41424,41425,41426,41427,41428,41429,41430,41431,41432,41433,41434,41435,41436,41437,41438,41439,41440,41441,41442,41443,41444,41445,41446,41447,41448,41449,41450,41451,41452,41453,41454,41455,41456,41457,41458,41459,41460,41461,41462,41463,41464,41465,41466,41467,41468,41469,41470,41471,41472,41473,41474,41475,41476,41477,41478,41479,41480,41481,41482,41483,41484,41485,41486,41487,41488,41489,41490,41491,41492,41493,41494,41495,41496,41497,41498,41499,41500,41501,41502,41503,41504,41505,41506,41507,41508,41509,41510,41511,41512,41513,41514,41515,41516,41517,41518,41519,41520,41521,41522,41523,41524,41525,41526,41527,41528,41529,41530,41531,41532,41533,41534,41535,41536,41537,41538,41539,41540,41541,41542,41543,41544,41545,41546,41547,41548,41549,41550,41551,41552,41553,41554,41555,41556,41557,41558,41559,41560,41561,41562,41563,41564,41565,41566,41567,41568,41569,41570,41571,41572,41573,41574,41575,41576,41577,41578,41579,41580,41581,41582,41583,41584,41585,41586,41587,41588,41589,41590,41591,41592,41593,41594,41595,41596,41597,41598,41599,41600,41601,41602,41603,41604,41605,41606,41607,41608,41609,41610,41611,41612,41613,41614,41615,41616,41617,41618,41619,41620,41621,41622,41623,41624,41625,41626,41627,41628,41629,41630,41631,41632,41633,41634,41635,41636,41637,41638,41639,41640,41641,41642,41643,41644,41645,41646,41647,41648,41649,41650,41651,41652,41653,41654,41655,41656,41657,41658,41659,41660,41661,41662,41663,41664,41665,41666,41667,41668,41669,41670,41671,41672,41673,41674,41675,41676,41677,41678,41679,41680,41681,41682,41683,41684,41685,41686,41687,41688,41689,41690,41691,41692,41693,41694,41695,41696,41697,41698,41699,41700,41701,41702,41703,41704,41705,41706,41707,41708,41709,41710,41711,41712,41713,41714,41715,41716,41717,41718,41719,41720,41721,41722,41723,41724,41725,41726,41727,41728,41729,41730,41731,41732,41733,41734,41735,41736,41737,41738,41739,41740,41741,41742,41743,41744,41745,41746,41747,41748,41749,41750,41751,41752,41753,41754,41755,41756,41757,41758,41759,41760,41761,41762,41763,41764,41765,41766,41767,41768,41769,41770,41771,41772,41773,41774,41775,41776,41777,41778,41779,41780,41781,41782,41783,41784,41785,41786,41787,41788,41789,41790,41791,41792,41793,41794,41795,41796,41797,41798,41799,41800,41801,41802,41803,41804,41805,41806,41807,41808,41809,41810,41811,41812,41813,41814,41815,41816,41817,41818,41819,41820,41821,41822,41823,41824,41825,41826,41827,41828,41829,41830,41831,41832,41833,41834,41835,41836,41837,41838,41839,41840,41841,41842,41843,41844,41845,41846,41847,41848,41849,41850,41851,41852,41853,41854,41855,41856,41857,41858,41859,41860,41861,41862,41863,41864,41865,41866,41867,41868,41869,41870,41871,41872,41873,41874,41875,41876,41877,41878,41879,41880,41881,41882,41883,41884,41885,41886,41887,41888,41889,41890,41891,41892,41893,41894,41895,41896,41897,41898,41899,41900,41901,41902,41903,41904,41905,41906,41907,41908,41909,41910,41911,41912,41913,41914,41915,41916,41917,41918,41919,41920,41921,41922,41923,41924,41925,41926,41927,41928,41929,41930,41931,41932,41933,41934,41935,41936,41937,41938,41939,41940,41941,41942,41943,41944,41945,41946,41947,41948,41949,41950,41951,41952,41953,41954,41955,41956,41957,41958,41959,41960,41961,41962,41963,41964,41965,41966,41967,41968,41969,41970,41971,41972,41973,41974,41975,41976,41977,41978,41979,41980,41981,41982,41983,41984,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,41997,41998,41999,42000,42001,42002,42003,42004,42005,42006,42007,42008,42009,42010,42011,42012,42013,42014,42015,42016,42017,42018,42019,42020,42021,42022,42023,42024,42025,42026,42027,42028,42029,42030,42031,42032,42033,42034,42035,42036,42037,42038,42039,42040,42041,42042,42043,42044,42045,42046,42047,42048,42049,42050,42051,42052,42053,42054,42055,42056,42057,42058,42059,42060,42061,42062,42063,42064,42065,42066,42067,42068,42069,42070,42071,42072,42073,42074,42075,42076,42077,42078,42079,42080,42081,42082,42083,42084,42085,42086,42087,42088,42089,42090,42091,42092,42093,42094,42095,42096,42097,42098,42099,42100,42101,42102,42103,42104,42105,42106,42107,42108,42109,42110,42111,42112,42113,42114,42115,42116,42117,42118,42119,42120,42121,42122,42123,42124,42192,42193,42194,42195,42196,42197,42198,42199,42200,42201,42202,42203,42204,42205,42206,42207,42208,42209,42210,42211,42212,42213,42214,42215,42216,42217,42218,42219,42220,42221,42222,42223,42224,42225,42226,42227,42228,42229,42230,42231,42232,42233,42234,42235,42236,42237,42240,42241,42242,42243,42244,42245,42246,42247,42248,42249,42250,42251,42252,42253,42254,42255,42256,42257,42258,42259,42260,42261,42262,42263,42264,42265,42266,42267,42268,42269,42270,42271,42272,42273,42274,42275,42276,42277,42278,42279,42280,42281,42282,42283,42284,42285,42286,42287,42288,42289,42290,42291,42292,42293,42294,42295,42296,42297,42298,42299,42300,42301,42302,42303,42304,42305,42306,42307,42308,42309,42310,42311,42312,42313,42314,42315,42316,42317,42318,42319,42320,42321,42322,42323,42324,42325,42326,42327,42328,42329,42330,42331,42332,42333,42334,42335,42336,42337,42338,42339,42340,42341,42342,42343,42344,42345,42346,42347,42348,42349,42350,42351,42352,42353,42354,42355,42356,42357,42358,42359,42360,42361,42362,42363,42364,42365,42366,42367,42368,42369,42370,42371,42372,42373,42374,42375,42376,42377,42378,42379,42380,42381,42382,42383,42384,42385,42386,42387,42388,42389,42390,42391,42392,42393,42394,42395,42396,42397,42398,42399,42400,42401,42402,42403,42404,42405,42406,42407,42408,42409,42410,42411,42412,42413,42414,42415,42416,42417,42418,42419,42420,42421,42422,42423,42424,42425,42426,42427,42428,42429,42430,42431,42432,42433,42434,42435,42436,42437,42438,42439,42440,42441,42442,42443,42444,42445,42446,42447,42448,42449,42450,42451,42452,42453,42454,42455,42456,42457,42458,42459,42460,42461,42462,42463,42464,42465,42466,42467,42468,42469,42470,42471,42472,42473,42474,42475,42476,42477,42478,42479,42480,42481,42482,42483,42484,42485,42486,42487,42488,42489,42490,42491,42492,42493,42494,42495,42496,42497,42498,42499,42500,42501,42502,42503,42504,42505,42506,42507,42508,42512,42513,42514,42515,42516,42517,42518,42519,42520,42521,42522,42523,42524,42525,42526,42527,42538,42539,42560,42561,42562,42563,42564,42565,42566,42567,42568,42569,42570,42571,42572,42573,42574,42575,42576,42577,42578,42579,42580,42581,42582,42583,42584,42585,42586,42587,42588,42589,42590,42591,42592,42593,42594,42595,42596,42597,42598,42599,42600,42601,42602,42603,42604,42605,42606,42623,42624,42625,42626,42627,42628,42629,42630,42631,42632,42633,42634,42635,42636,42637,42638,42639,42640,42641,42642,42643,42644,42645,42646,42647,42648,42649,42650,42651,42652,42653,42656,42657,42658,42659,42660,42661,42662,42663,42664,42665,42666,42667,42668,42669,42670,42671,42672,42673,42674,42675,42676,42677,42678,42679,42680,42681,42682,42683,42684,42685,42686,42687,42688,42689,42690,42691,42692,42693,42694,42695,42696,42697,42698,42699,42700,42701,42702,42703,42704,42705,42706,42707,42708,42709,42710,42711,42712,42713,42714,42715,42716,42717,42718,42719,42720,42721,42722,42723,42724,42725,42726,42727,42728,42729,42730,42731,42732,42733,42734,42735,42775,42776,42777,42778,42779,42780,42781,42782,42783,42786,42787,42788,42789,42790,42791,42792,42793,42794,42795,42796,42797,42798,42799,42800,42801,42802,42803,42804,42805,42806,42807,42808,42809,42810,42811,42812,42813,42814,42815,42816,42817,42818,42819,42820,42821,42822,42823,42824,42825,42826,42827,42828,42829,42830,42831,42832,42833,42834,42835,42836,42837,42838,42839,42840,42841,42842,42843,42844,42845,42846,42847,42848,42849,42850,42851,42852,42853,42854,42855,42856,42857,42858,42859,42860,42861,42862,42863,42864,42865,42866,42867,42868,42869,42870,42871,42872,42873,42874,42875,42876,42877,42878,42879,42880,42881,42882,42883,42884,42885,42886,42887,42888,42891,42892,42893,42894,42895,42896,42897,42898,42899,42900,42901,42902,42903,42904,42905,42906,42907,42908,42909,42910,42911,42912,42913,42914,42915,42916,42917,42918,42919,42920,42921,42922,42923,42924,42925,42926,42927,42928,42929,42930,42931,42932,42933,42934,42935,42936,42937,42999,43000,43001,43002,43003,43004,43005,43006,43007,43008,43009,43011,43012,43013,43015,43016,43017,43018,43020,43021,43022,43023,43024,43025,43026,43027,43028,43029,43030,43031,43032,43033,43034,43035,43036,43037,43038,43039,43040,43041,43042,43072,43073,43074,43075,43076,43077,43078,43079,43080,43081,43082,43083,43084,43085,43086,43087,43088,43089,43090,43091,43092,43093,43094,43095,43096,43097,43098,43099,43100,43101,43102,43103,43104,43105,43106,43107,43108,43109,43110,43111,43112,43113,43114,43115,43116,43117,43118,43119,43120,43121,43122,43123,43138,43139,43140,43141,43142,43143,43144,43145,43146,43147,43148,43149,43150,43151,43152,43153,43154,43155,43156,43157,43158,43159,43160,43161,43162,43163,43164,43165,43166,43167,43168,43169,43170,43171,43172,43173,43174,43175,43176,43177,43178,43179,43180,43181,43182,43183,43184,43185,43186,43187,43250,43251,43252,43253,43254,43255,43259,43261,43262,43274,43275,43276,43277,43278,43279,43280,43281,43282,43283,43284,43285,43286,43287,43288,43289,43290,43291,43292,43293,43294,43295,43296,43297,43298,43299,43300,43301,43312,43313,43314,43315,43316,43317,43318,43319,43320,43321,43322,43323,43324,43325,43326,43327,43328,43329,43330,43331,43332,43333,43334,43360,43361,43362,43363,43364,43365,43366,43367,43368,43369,43370,43371,43372,43373,43374,43375,43376,43377,43378,43379,43380,43381,43382,43383,43384,43385,43386,43387,43388,43396,43397,43398,43399,43400,43401,43402,43403,43404,43405,43406,43407,43408,43409,43410,43411,43412,43413,43414,43415,43416,43417,43418,43419,43420,43421,43422,43423,43424,43425,43426,43427,43428,43429,43430,43431,43432,43433,43434,43435,43436,43437,43438,43439,43440,43441,43442,43471,43488,43489,43490,43491,43492,43494,43495,43496,43497,43498,43499,43500,43501,43502,43503,43514,43515,43516,43517,43518,43520,43521,43522,43523,43524,43525,43526,43527,43528,43529,43530,43531,43532,43533,43534,43535,43536,43537,43538,43539,43540,43541,43542,43543,43544,43545,43546,43547,43548,43549,43550,43551,43552,43553,43554,43555,43556,43557,43558,43559,43560,43584,43585,43586,43588,43589,43590,43591,43592,43593,43594,43595,43616,43617,43618,43619,43620,43621,43622,43623,43624,43625,43626,43627,43628,43629,43630,43631,43632,43633,43634,43635,43636,43637,43638,43642,43646,43647,43648,43649,43650,43651,43652,43653,43654,43655,43656,43657,43658,43659,43660,43661,43662,43663,43664,43665,43666,43667,43668,43669,43670,43671,43672,43673,43674,43675,43676,43677,43678,43679,43680,43681,43682,43683,43684,43685,43686,43687,43688,43689,43690,43691,43692,43693,43694,43695,43697,43701,43702,43705,43706,43707,43708,43709,43712,43714,43739,43740,43741,43744,43745,43746,43747,43748,43749,43750,43751,43752,43753,43754,43762,43763,43764,43777,43778,43779,43780,43781,43782,43785,43786,43787,43788,43789,43790,43793,43794,43795,43796,43797,43798,43808,43809,43810,43811,43812,43813,43814,43816,43817,43818,43819,43820,43821,43822,43824,43825,43826,43827,43828,43829,43830,43831,43832,43833,43834,43835,43836,43837,43838,43839,43840,43841,43842,43843,43844,43845,43846,43847,43848,43849,43850,43851,43852,43853,43854,43855,43856,43857,43858,43859,43860,43861,43862,43863,43864,43865,43866,43868,43869,43870,43871,43872,43873,43874,43875,43876,43877,43888,43889,43890,43891,43892,43893,43894,43895,43896,43897,43898,43899,43900,43901,43902,43903,43904,43905,43906,43907,43908,43909,43910,43911,43912,43913,43914,43915,43916,43917,43918,43919,43920,43921,43922,43923,43924,43925,43926,43927,43928,43929,43930,43931,43932,43933,43934,43935,43936,43937,43938,43939,43940,43941,43942,43943,43944,43945,43946,43947,43948,43949,43950,43951,43952,43953,43954,43955,43956,43957,43958,43959,43960,43961,43962,43963,43964,43965,43966,43967,43968,43969,43970,43971,43972,43973,43974,43975,43976,43977,43978,43979,43980,43981,43982,43983,43984,43985,43986,43987,43988,43989,43990,43991,43992,43993,43994,43995,43996,43997,43998,43999,44000,44001,44002,44032,44033,44034,44035,44036,44037,44038,44039,44040,44041,44042,44043,44044,44045,44046,44047,44048,44049,44050,44051,44052,44053,44054,44055,44056,44057,44058,44059,44060,44061,44062,44063,44064,44065,44066,44067,44068,44069,44070,44071,44072,44073,44074,44075,44076,44077,44078,44079,44080,44081,44082,44083,44084,44085,44086,44087,44088,44089,44090,44091,44092,44093,44094,44095,44096,44097,44098,44099,44100,44101,44102,44103,44104,44105,44106,44107,44108,44109,44110,44111,44112,44113,44114,44115,44116,44117,44118,44119,44120,44121,44122,44123,44124,44125,44126,44127,44128,44129,44130,44131,44132,44133,44134,44135,44136,44137,44138,44139,44140,44141,44142,44143,44144,44145,44146,44147,44148,44149,44150,44151,44152,44153,44154,44155,44156,44157,44158,44159,44160,44161,44162,44163,44164,44165,44166,44167,44168,44169,44170,44171,44172,44173,44174,44175,44176,44177,44178,44179,44180,44181,44182,44183,44184,44185,44186,44187,44188,44189,44190,44191,44192,44193,44194,44195,44196,44197,44198,44199,44200,44201,44202,44203,44204,44205,44206,44207,44208,44209,44210,44211,44212,44213,44214,44215,44216,44217,44218,44219,44220,44221,44222,44223,44224,44225,44226,44227,44228,44229,44230,44231,44232,44233,44234,44235,44236,44237,44238,44239,44240,44241,44242,44243,44244,44245,44246,44247,44248,44249,44250,44251,44252,44253,44254,44255,44256,44257,44258,44259,44260,44261,44262,44263,44264,44265,44266,44267,44268,44269,44270,44271,44272,44273,44274,44275,44276,44277,44278,44279,44280,44281,44282,44283,44284,44285,44286,44287,44288,44289,44290,44291,44292,44293,44294,44295,44296,44297,44298,44299,44300,44301,44302,44303,44304,44305,44306,44307,44308,44309,44310,44311,44312,44313,44314,44315,44316,44317,44318,44319,44320,44321,44322,44323,44324,44325,44326,44327,44328,44329,44330,44331,44332,44333,44334,44335,44336,44337,44338,44339,44340,44341,44342,44343,44344,44345,44346,44347,44348,44349,44350,44351,44352,44353,44354,44355,44356,44357,44358,44359,44360,44361,44362,44363,44364,44365,44366,44367,44368,44369,44370,44371,44372,44373,44374,44375,44376,44377,44378,44379,44380,44381,44382,44383,44384,44385,44386,44387,44388,44389,44390,44391,44392,44393,44394,44395,44396,44397,44398,44399,44400,44401,44402,44403,44404,44405,44406,44407,44408,44409,44410,44411,44412,44413,44414,44415,44416,44417,44418,44419,44420,44421,44422,44423,44424,44425,44426,44427,44428,44429,44430,44431,44432,44433,44434,44435,44436,44437,44438,44439,44440,44441,44442,44443,44444,44445,44446,44447,44448,44449,44450,44451,44452,44453,44454,44455,44456,44457,44458,44459,44460,44461,44462,44463,44464,44465,44466,44467,44468,44469,44470,44471,44472,44473,44474,44475,44476,44477,44478,44479,44480,44481,44482,44483,44484,44485,44486,44487,44488,44489,44490,44491,44492,44493,44494,44495,44496,44497,44498,44499,44500,44501,44502,44503,44504,44505,44506,44507,44508,44509,44510,44511,44512,44513,44514,44515,44516,44517,44518,44519,44520,44521,44522,44523,44524,44525,44526,44527,44528,44529,44530,44531,44532,44533,44534,44535,44536,44537,44538,44539,44540,44541,44542,44543,44544,44545,44546,44547,44548,44549,44550,44551,44552,44553,44554,44555,44556,44557,44558,44559,44560,44561,44562,44563,44564,44565,44566,44567,44568,44569,44570,44571,44572,44573,44574,44575,44576,44577,44578,44579,44580,44581,44582,44583,44584,44585,44586,44587,44588,44589,44590,44591,44592,44593,44594,44595,44596,44597,44598,44599,44600,44601,44602,44603,44604,44605,44606,44607,44608,44609,44610,44611,44612,44613,44614,44615,44616,44617,44618,44619,44620,44621,44622,44623,44624,44625,44626,44627,44628,44629,44630,44631,44632,44633,44634,44635,44636,44637,44638,44639,44640,44641,44642,44643,44644,44645,44646,44647,44648,44649,44650,44651,44652,44653,44654,44655,44656,44657,44658,44659,44660,44661,44662,44663,44664,44665,44666,44667,44668,44669,44670,44671,44672,44673,44674,44675,44676,44677,44678,44679,44680,44681,44682,44683,44684,44685,44686,44687,44688,44689,44690,44691,44692,44693,44694,44695,44696,44697,44698,44699,44700,44701,44702,44703,44704,44705,44706,44707,44708,44709,44710,44711,44712,44713,44714,44715,44716,44717,44718,44719,44720,44721,44722,44723,44724,44725,44726,44727,44728,44729,44730,44731,44732,44733,44734,44735,44736,44737,44738,44739,44740,44741,44742,44743,44744,44745,44746,44747,44748,44749,44750,44751,44752,44753,44754,44755,44756,44757,44758,44759,44760,44761,44762,44763,44764,44765,44766,44767,44768,44769,44770,44771,44772,44773,44774,44775,44776,44777,44778,44779,44780,44781,44782,44783,44784,44785,44786,44787,44788,44789,44790,44791,44792,44793,44794,44795,44796,44797,44798,44799,44800,44801,44802,44803,44804,44805,44806,44807,44808,44809,44810,44811,44812,44813,44814,44815,44816,44817,44818,44819,44820,44821,44822,44823,44824,44825,44826,44827,44828,44829,44830,44831,44832,44833,44834,44835,44836,44837,44838,44839,44840,44841,44842,44843,44844,44845,44846,44847,44848,44849,44850,44851,44852,44853,44854,44855,44856,44857,44858,44859,44860,44861,44862,44863,44864,44865,44866,44867,44868,44869,44870,44871,44872,44873,44874,44875,44876,44877,44878,44879,44880,44881,44882,44883,44884,44885,44886,44887,44888,44889,44890,44891,44892,44893,44894,44895,44896,44897,44898,44899,44900,44901,44902,44903,44904,44905,44906,44907,44908,44909,44910,44911,44912,44913,44914,44915,44916,44917,44918,44919,44920,44921,44922,44923,44924,44925,44926,44927,44928,44929,44930,44931,44932,44933,44934,44935,44936,44937,44938,44939,44940,44941,44942,44943,44944,44945,44946,44947,44948,44949,44950,44951,44952,44953,44954,44955,44956,44957,44958,44959,44960,44961,44962,44963,44964,44965,44966,44967,44968,44969,44970,44971,44972,44973,44974,44975,44976,44977,44978,44979,44980,44981,44982,44983,44984,44985,44986,44987,44988,44989,44990,44991,44992,44993,44994,44995,44996,44997,44998,44999,45000,45001,45002,45003,45004,45005,45006,45007,45008,45009,45010,45011,45012,45013,45014,45015,45016,45017,45018,45019,45020,45021,45022,45023,45024,45025,45026,45027,45028,45029,45030,45031,45032,45033,45034,45035,45036,45037,45038,45039,45040,45041,45042,45043,45044,45045,45046,45047,45048,45049,45050,45051,45052,45053,45054,45055,45056,45057,45058,45059,45060,45061,45062,45063,45064,45065,45066,45067,45068,45069,45070,45071,45072,45073,45074,45075,45076,45077,45078,45079,45080,45081,45082,45083,45084,45085,45086,45087,45088,45089,45090,45091,45092,45093,45094,45095,45096,45097,45098,45099,45100,45101,45102,45103,45104,45105,45106,45107,45108,45109,45110,45111,45112,45113,45114,45115,45116,45117,45118,45119,45120,45121,45122,45123,45124,45125,45126,45127,45128,45129,45130,45131,45132,45133,45134,45135,45136,45137,45138,45139,45140,45141,45142,45143,45144,45145,45146,45147,45148,45149,45150,45151,45152,45153,45154,45155,45156,45157,45158,45159,45160,45161,45162,45163,45164,45165,45166,45167,45168,45169,45170,45171,45172,45173,45174,45175,45176,45177,45178,45179,45180,45181,45182,45183,45184,45185,45186,45187,45188,45189,45190,45191,45192,45193,45194,45195,45196,45197,45198,45199,45200,45201,45202,45203,45204,45205,45206,45207,45208,45209,45210,45211,45212,45213,45214,45215,45216,45217,45218,45219,45220,45221,45222,45223,45224,45225,45226,45227,45228,45229,45230,45231,45232,45233,45234,45235,45236,45237,45238,45239,45240,45241,45242,45243,45244,45245,45246,45247,45248,45249,45250,45251,45252,45253,45254,45255,45256,45257,45258,45259,45260,45261,45262,45263,45264,45265,45266,45267,45268,45269,45270,45271,45272,45273,45274,45275,45276,45277,45278,45279,45280,45281,45282,45283,45284,45285,45286,45287,45288,45289,45290,45291,45292,45293,45294,45295,45296,45297,45298,45299,45300,45301,45302,45303,45304,45305,45306,45307,45308,45309,45310,45311,45312,45313,45314,45315,45316,45317,45318,45319,45320,45321,45322,45323,45324,45325,45326,45327,45328,45329,45330,45331,45332,45333,45334,45335,45336,45337,45338,45339,45340,45341,45342,45343,45344,45345,45346,45347,45348,45349,45350,45351,45352,45353,45354,45355,45356,45357,45358,45359,45360,45361,45362,45363,45364,45365,45366,45367,45368,45369,45370,45371,45372,45373,45374,45375,45376,45377,45378,45379,45380,45381,45382,45383,45384,45385,45386,45387,45388,45389,45390,45391,45392,45393,45394,45395,45396,45397,45398,45399,45400,45401,45402,45403,45404,45405,45406,45407,45408,45409,45410,45411,45412,45413,45414,45415,45416,45417,45418,45419,45420,45421,45422,45423,45424,45425,45426,45427,45428,45429,45430,45431,45432,45433,45434,45435,45436,45437,45438,45439,45440,45441,45442,45443,45444,45445,45446,45447,45448,45449,45450,45451,45452,45453,45454,45455,45456,45457,45458,45459,45460,45461,45462,45463,45464,45465,45466,45467,45468,45469,45470,45471,45472,45473,45474,45475,45476,45477,45478,45479,45480,45481,45482,45483,45484,45485,45486,45487,45488,45489,45490,45491,45492,45493,45494,45495,45496,45497,45498,45499,45500,45501,45502,45503,45504,45505,45506,45507,45508,45509,45510,45511,45512,45513,45514,45515,45516,45517,45518,45519,45520,45521,45522,45523,45524,45525,45526,45527,45528,45529,45530,45531,45532,45533,45534,45535,45536,45537,45538,45539,45540,45541,45542,45543,45544,45545,45546,45547,45548,45549,45550,45551,45552,45553,45554,45555,45556,45557,45558,45559,45560,45561,45562,45563,45564,45565,45566,45567,45568,45569,45570,45571,45572,45573,45574,45575,45576,45577,45578,45579,45580,45581,45582,45583,45584,45585,45586,45587,45588,45589,45590,45591,45592,45593,45594,45595,45596,45597,45598,45599,45600,45601,45602,45603,45604,45605,45606,45607,45608,45609,45610,45611,45612,45613,45614,45615,45616,45617,45618,45619,45620,45621,45622,45623,45624,45625,45626,45627,45628,45629,45630,45631,45632,45633,45634,45635,45636,45637,45638,45639,45640,45641,45642,45643,45644,45645,45646,45647,45648,45649,45650,45651,45652,45653,45654,45655,45656,45657,45658,45659,45660,45661,45662,45663,45664,45665,45666,45667,45668,45669,45670,45671,45672,45673,45674,45675,45676,45677,45678,45679,45680,45681,45682,45683,45684,45685,45686,45687,45688,45689,45690,45691,45692,45693,45694,45695,45696,45697,45698,45699,45700,45701,45702,45703,45704,45705,45706,45707,45708,45709,45710,45711,45712,45713,45714,45715,45716,45717,45718,45719,45720,45721,45722,45723,45724,45725,45726,45727,45728,45729,45730,45731,45732,45733,45734,45735,45736,45737,45738,45739,45740,45741,45742,45743,45744,45745,45746,45747,45748,45749,45750,45751,45752,45753,45754,45755,45756,45757,45758,45759,45760,45761,45762,45763,45764,45765,45766,45767,45768,45769,45770,45771,45772,45773,45774,45775,45776,45777,45778,45779,45780,45781,45782,45783,45784,45785,45786,45787,45788,45789,45790,45791,45792,45793,45794,45795,45796,45797,45798,45799,45800,45801,45802,45803,45804,45805,45806,45807,45808,45809,45810,45811,45812,45813,45814,45815,45816,45817,45818,45819,45820,45821,45822,45823,45824,45825,45826,45827,45828,45829,45830,45831,45832,45833,45834,45835,45836,45837,45838,45839,45840,45841,45842,45843,45844,45845,45846,45847,45848,45849,45850,45851,45852,45853,45854,45855,45856,45857,45858,45859,45860,45861,45862,45863,45864,45865,45866,45867,45868,45869,45870,45871,45872,45873,45874,45875,45876,45877,45878,45879,45880,45881,45882,45883,45884,45885,45886,45887,45888,45889,45890,45891,45892,45893,45894,45895,45896,45897,45898,45899,45900,45901,45902,45903,45904,45905,45906,45907,45908,45909,45910,45911,45912,45913,45914,45915,45916,45917,45918,45919,45920,45921,45922,45923,45924,45925,45926,45927,45928,45929,45930,45931,45932,45933,45934,45935,45936,45937,45938,45939,45940,45941,45942,45943,45944,45945,45946,45947,45948,45949,45950,45951,45952,45953,45954,45955,45956,45957,45958,45959,45960,45961,45962,45963,45964,45965,45966,45967,45968,45969,45970,45971,45972,45973,45974,45975,45976,45977,45978,45979,45980,45981,45982,45983,45984,45985,45986,45987,45988,45989,45990,45991,45992,45993,45994,45995,45996,45997,45998,45999,46000,46001,46002,46003,46004,46005,46006,46007,46008,46009,46010,46011,46012,46013,46014,46015,46016,46017,46018,46019,46020,46021,46022,46023,46024,46025,46026,46027,46028,46029,46030,46031,46032,46033,46034,46035,46036,46037,46038,46039,46040,46041,46042,46043,46044,46045,46046,46047,46048,46049,46050,46051,46052,46053,46054,46055,46056,46057,46058,46059,46060,46061,46062,46063,46064,46065,46066,46067,46068,46069,46070,46071,46072,46073,46074,46075,46076,46077,46078,46079,46080,46081,46082,46083,46084,46085,46086,46087,46088,46089,46090,46091,46092,46093,46094,46095,46096,46097,46098,46099,46100,46101,46102,46103,46104,46105,46106,46107,46108,46109,46110,46111,46112,46113,46114,46115,46116,46117,46118,46119,46120,46121,46122,46123,46124,46125,46126,46127,46128,46129,46130,46131,46132,46133,46134,46135,46136,46137,46138,46139,46140,46141,46142,46143,46144,46145,46146,46147,46148,46149,46150,46151,46152,46153,46154,46155,46156,46157,46158,46159,46160,46161,46162,46163,46164,46165,46166,46167,46168,46169,46170,46171,46172,46173,46174,46175,46176,46177,46178,46179,46180,46181,46182,46183,46184,46185,46186,46187,46188,46189,46190,46191,46192,46193,46194,46195,46196,46197,46198,46199,46200,46201,46202,46203,46204,46205,46206,46207,46208,46209,46210,46211,46212,46213,46214,46215,46216,46217,46218,46219,46220,46221,46222,46223,46224,46225,46226,46227,46228,46229,46230,46231,46232,46233,46234,46235,46236,46237,46238,46239,46240,46241,46242,46243,46244,46245,46246,46247,46248,46249,46250,46251,46252,46253,46254,46255,46256,46257,46258,46259,46260,46261,46262,46263,46264,46265,46266,46267,46268,46269,46270,46271,46272,46273,46274,46275,46276,46277,46278,46279,46280,46281,46282,46283,46284,46285,46286,46287,46288,46289,46290,46291,46292,46293,46294,46295,46296,46297,46298,46299,46300,46301,46302,46303,46304,46305,46306,46307,46308,46309,46310,46311,46312,46313,46314,46315,46316,46317,46318,46319,46320,46321,46322,46323,46324,46325,46326,46327,46328,46329,46330,46331,46332,46333,46334,46335,46336,46337,46338,46339,46340,46341,46342,46343,46344,46345,46346,46347,46348,46349,46350,46351,46352,46353,46354,46355,46356,46357,46358,46359,46360,46361,46362,46363,46364,46365,46366,46367,46368,46369,46370,46371,46372,46373,46374,46375,46376,46377,46378,46379,46380,46381,46382,46383,46384,46385,46386,46387,46388,46389,46390,46391,46392,46393,46394,46395,46396,46397,46398,46399,46400,46401,46402,46403,46404,46405,46406,46407,46408,46409,46410,46411,46412,46413,46414,46415,46416,46417,46418,46419,46420,46421,46422,46423,46424,46425,46426,46427,46428,46429,46430,46431,46432,46433,46434,46435,46436,46437,46438,46439,46440,46441,46442,46443,46444,46445,46446,46447,46448,46449,46450,46451,46452,46453,46454,46455,46456,46457,46458,46459,46460,46461,46462,46463,46464,46465,46466,46467,46468,46469,46470,46471,46472,46473,46474,46475,46476,46477,46478,46479,46480,46481,46482,46483,46484,46485,46486,46487,46488,46489,46490,46491,46492,46493,46494,46495,46496,46497,46498,46499,46500,46501,46502,46503,46504,46505,46506,46507,46508,46509,46510,46511,46512,46513,46514,46515,46516,46517,46518,46519,46520,46521,46522,46523,46524,46525,46526,46527,46528,46529,46530,46531,46532,46533,46534,46535,46536,46537,46538,46539,46540,46541,46542,46543,46544,46545,46546,46547,46548,46549,46550,46551,46552,46553,46554,46555,46556,46557,46558,46559,46560,46561,46562,46563,46564,46565,46566,46567,46568,46569,46570,46571,46572,46573,46574,46575,46576,46577,46578,46579,46580,46581,46582,46583,46584,46585,46586,46587,46588,46589,46590,46591,46592,46593,46594,46595,46596,46597,46598,46599,46600,46601,46602,46603,46604,46605,46606,46607,46608,46609,46610,46611,46612,46613,46614,46615,46616,46617,46618,46619,46620,46621,46622,46623,46624,46625,46626,46627,46628,46629,46630,46631,46632,46633,46634,46635,46636,46637,46638,46639,46640,46641,46642,46643,46644,46645,46646,46647,46648,46649,46650,46651,46652,46653,46654,46655,46656,46657,46658,46659,46660,46661,46662,46663,46664,46665,46666,46667,46668,46669,46670,46671,46672,46673,46674,46675,46676,46677,46678,46679,46680,46681,46682,46683,46684,46685,46686,46687,46688,46689,46690,46691,46692,46693,46694,46695,46696,46697,46698,46699,46700,46701,46702,46703,46704,46705,46706,46707,46708,46709,46710,46711,46712,46713,46714,46715,46716,46717,46718,46719,46720,46721,46722,46723,46724,46725,46726,46727,46728,46729,46730,46731,46732,46733,46734,46735,46736,46737,46738,46739,46740,46741,46742,46743,46744,46745,46746,46747,46748,46749,46750,46751,46752,46753,46754,46755,46756,46757,46758,46759,46760,46761,46762,46763,46764,46765,46766,46767,46768,46769,46770,46771,46772,46773,46774,46775,46776,46777,46778,46779,46780,46781,46782,46783,46784,46785,46786,46787,46788,46789,46790,46791,46792,46793,46794,46795,46796,46797,46798,46799,46800,46801,46802,46803,46804,46805,46806,46807,46808,46809,46810,46811,46812,46813,46814,46815,46816,46817,46818,46819,46820,46821,46822,46823,46824,46825,46826,46827,46828,46829,46830,46831,46832,46833,46834,46835,46836,46837,46838,46839,46840,46841,46842,46843,46844,46845,46846,46847,46848,46849,46850,46851,46852,46853,46854,46855,46856,46857,46858,46859,46860,46861,46862,46863,46864,46865,46866,46867,46868,46869,46870,46871,46872,46873,46874,46875,46876,46877,46878,46879,46880,46881,46882,46883,46884,46885,46886,46887,46888,46889,46890,46891,46892,46893,46894,46895,46896,46897,46898,46899,46900,46901,46902,46903,46904,46905,46906,46907,46908,46909,46910,46911,46912,46913,46914,46915,46916,46917,46918,46919,46920,46921,46922,46923,46924,46925,46926,46927,46928,46929,46930,46931,46932,46933,46934,46935,46936,46937,46938,46939,46940,46941,46942,46943,46944,46945,46946,46947,46948,46949,46950,46951,46952,46953,46954,46955,46956,46957,46958,46959,46960,46961,46962,46963,46964,46965,46966,46967,46968,46969,46970,46971,46972,46973,46974,46975,46976,46977,46978,46979,46980,46981,46982,46983,46984,46985,46986,46987,46988,46989,46990,46991,46992,46993,46994,46995,46996,46997,46998,46999,47000,47001,47002,47003,47004,47005,47006,47007,47008,47009,47010,47011,47012,47013,47014,47015,47016,47017,47018,47019,47020,47021,47022,47023,47024,47025,47026,47027,47028,47029,47030,47031,47032,47033,47034,47035,47036,47037,47038,47039,47040,47041,47042,47043,47044,47045,47046,47047,47048,47049,47050,47051,47052,47053,47054,47055,47056,47057,47058,47059,47060,47061,47062,47063,47064,47065,47066,47067,47068,47069,47070,47071,47072,47073,47074,47075,47076,47077,47078,47079,47080,47081,47082,47083,47084,47085,47086,47087,47088,47089,47090,47091,47092,47093,47094,47095,47096,47097,47098,47099,47100,47101,47102,47103,47104,47105,47106,47107,47108,47109,47110,47111,47112,47113,47114,47115,47116,47117,47118,47119,47120,47121,47122,47123,47124,47125,47126,47127,47128,47129,47130,47131,47132,47133,47134,47135,47136,47137,47138,47139,47140,47141,47142,47143,47144,47145,47146,47147,47148,47149,47150,47151,47152,47153,47154,47155,47156,47157,47158,47159,47160,47161,47162,47163,47164,47165,47166,47167,47168,47169,47170,47171,47172,47173,47174,47175,47176,47177,47178,47179,47180,47181,47182,47183,47184,47185,47186,47187,47188,47189,47190,47191,47192,47193,47194,47195,47196,47197,47198,47199,47200,47201,47202,47203,47204,47205,47206,47207,47208,47209,47210,47211,47212,47213,47214,47215,47216,47217,47218,47219,47220,47221,47222,47223,47224,47225,47226,47227,47228,47229,47230,47231,47232,47233,47234,47235,47236,47237,47238,47239,47240,47241,47242,47243,47244,47245,47246,47247,47248,47249,47250,47251,47252,47253,47254,47255,47256,47257,47258,47259,47260,47261,47262,47263,47264,47265,47266,47267,47268,47269,47270,47271,47272,47273,47274,47275,47276,47277,47278,47279,47280,47281,47282,47283,47284,47285,47286,47287,47288,47289,47290,47291,47292,47293,47294,47295,47296,47297,47298,47299,47300,47301,47302,47303,47304,47305,47306,47307,47308,47309,47310,47311,47312,47313,47314,47315,47316,47317,47318,47319,47320,47321,47322,47323,47324,47325,47326,47327,47328,47329,47330,47331,47332,47333,47334,47335,47336,47337,47338,47339,47340,47341,47342,47343,47344,47345,47346,47347,47348,47349,47350,47351,47352,47353,47354,47355,47356,47357,47358,47359,47360,47361,47362,47363,47364,47365,47366,47367,47368,47369,47370,47371,47372,47373,47374,47375,47376,47377,47378,47379,47380,47381,47382,47383,47384,47385,47386,47387,47388,47389,47390,47391,47392,47393,47394,47395,47396,47397,47398,47399,47400,47401,47402,47403,47404,47405,47406,47407,47408,47409,47410,47411,47412,47413,47414,47415,47416,47417,47418,47419,47420,47421,47422,47423,47424,47425,47426,47427,47428,47429,47430,47431,47432,47433,47434,47435,47436,47437,47438,47439,47440,47441,47442,47443,47444,47445,47446,47447,47448,47449,47450,47451,47452,47453,47454,47455,47456,47457,47458,47459,47460,47461,47462,47463,47464,47465,47466,47467,47468,47469,47470,47471,47472,47473,47474,47475,47476,47477,47478,47479,47480,47481,47482,47483,47484,47485,47486,47487,47488,47489,47490,47491,47492,47493,47494,47495,47496,47497,47498,47499,47500,47501,47502,47503,47504,47505,47506,47507,47508,47509,47510,47511,47512,47513,47514,47515,47516,47517,47518,47519,47520,47521,47522,47523,47524,47525,47526,47527,47528,47529,47530,47531,47532,47533,47534,47535,47536,47537,47538,47539,47540,47541,47542,47543,47544,47545,47546,47547,47548,47549,47550,47551,47552,47553,47554,47555,47556,47557,47558,47559,47560,47561,47562,47563,47564,47565,47566,47567,47568,47569,47570,47571,47572,47573,47574,47575,47576,47577,47578,47579,47580,47581,47582,47583,47584,47585,47586,47587,47588,47589,47590,47591,47592,47593,47594,47595,47596,47597,47598,47599,47600,47601,47602,47603,47604,47605,47606,47607,47608,47609,47610,47611,47612,47613,47614,47615,47616,47617,47618,47619,47620,47621,47622,47623,47624,47625,47626,47627,47628,47629,47630,47631,47632,47633,47634,47635,47636,47637,47638,47639,47640,47641,47642,47643,47644,47645,47646,47647,47648,47649,47650,47651,47652,47653,47654,47655,47656,47657,47658,47659,47660,47661,47662,47663,47664,47665,47666,47667,47668,47669,47670,47671,47672,47673,47674,47675,47676,47677,47678,47679,47680,47681,47682,47683,47684,47685,47686,47687,47688,47689,47690,47691,47692,47693,47694,47695,47696,47697,47698,47699,47700,47701,47702,47703,47704,47705,47706,47707,47708,47709,47710,47711,47712,47713,47714,47715,47716,47717,47718,47719,47720,47721,47722,47723,47724,47725,47726,47727,47728,47729,47730,47731,47732,47733,47734,47735,47736,47737,47738,47739,47740,47741,47742,47743,47744,47745,47746,47747,47748,47749,47750,47751,47752,47753,47754,47755,47756,47757,47758,47759,47760,47761,47762,47763,47764,47765,47766,47767,47768,47769,47770,47771,47772,47773,47774,47775,47776,47777,47778,47779,47780,47781,47782,47783,47784,47785,47786,47787,47788,47789,47790,47791,47792,47793,47794,47795,47796,47797,47798,47799,47800,47801,47802,47803,47804,47805,47806,47807,47808,47809,47810,47811,47812,47813,47814,47815,47816,47817,47818,47819,47820,47821,47822,47823,47824,47825,47826,47827,47828,47829,47830,47831,47832,47833,47834,47835,47836,47837,47838,47839,47840,47841,47842,47843,47844,47845,47846,47847,47848,47849,47850,47851,47852,47853,47854,47855,47856,47857,47858,47859,47860,47861,47862,47863,47864,47865,47866,47867,47868,47869,47870,47871,47872,47873,47874,47875,47876,47877,47878,47879,47880,47881,47882,47883,47884,47885,47886,47887,47888,47889,47890,47891,47892,47893,47894,47895,47896,47897,47898,47899,47900,47901,47902,47903,47904,47905,47906,47907,47908,47909,47910,47911,47912,47913,47914,47915,47916,47917,47918,47919,47920,47921,47922,47923,47924,47925,47926,47927,47928,47929,47930,47931,47932,47933,47934,47935,47936,47937,47938,47939,47940,47941,47942,47943,47944,47945,47946,47947,47948,47949,47950,47951,47952,47953,47954,47955,47956,47957,47958,47959,47960,47961,47962,47963,47964,47965,47966,47967,47968,47969,47970,47971,47972,47973,47974,47975,47976,47977,47978,47979,47980,47981,47982,47983,47984,47985,47986,47987,47988,47989,47990,47991,47992,47993,47994,47995,47996,47997,47998,47999,48000,48001,48002,48003,48004,48005,48006,48007,48008,48009,48010,48011,48012,48013,48014,48015,48016,48017,48018,48019,48020,48021,48022,48023,48024,48025,48026,48027,48028,48029,48030,48031,48032,48033,48034,48035,48036,48037,48038,48039,48040,48041,48042,48043,48044,48045,48046,48047,48048,48049,48050,48051,48052,48053,48054,48055,48056,48057,48058,48059,48060,48061,48062,48063,48064,48065,48066,48067,48068,48069,48070,48071,48072,48073,48074,48075,48076,48077,48078,48079,48080,48081,48082,48083,48084,48085,48086,48087,48088,48089,48090,48091,48092,48093,48094,48095,48096,48097,48098,48099,48100,48101,48102,48103,48104,48105,48106,48107,48108,48109,48110,48111,48112,48113,48114,48115,48116,48117,48118,48119,48120,48121,48122,48123,48124,48125,48126,48127,48128,48129,48130,48131,48132,48133,48134,48135,48136,48137,48138,48139,48140,48141,48142,48143,48144,48145,48146,48147,48148,48149,48150,48151,48152,48153,48154,48155,48156,48157,48158,48159,48160,48161,48162,48163,48164,48165,48166,48167,48168,48169,48170,48171,48172,48173,48174,48175,48176,48177,48178,48179,48180,48181,48182,48183,48184,48185,48186,48187,48188,48189,48190,48191,48192,48193,48194,48195,48196,48197,48198,48199,48200,48201,48202,48203,48204,48205,48206,48207,48208,48209,48210,48211,48212,48213,48214,48215,48216,48217,48218,48219,48220,48221,48222,48223,48224,48225,48226,48227,48228,48229,48230,48231,48232,48233,48234,48235,48236,48237,48238,48239,48240,48241,48242,48243,48244,48245,48246,48247,48248,48249,48250,48251,48252,48253,48254,48255,48256,48257,48258,48259,48260,48261,48262,48263,48264,48265,48266,48267,48268,48269,48270,48271,48272,48273,48274,48275,48276,48277,48278,48279,48280,48281,48282,48283,48284,48285,48286,48287,48288,48289,48290,48291,48292,48293,48294,48295,48296,48297,48298,48299,48300,48301,48302,48303,48304,48305,48306,48307,48308,48309,48310,48311,48312,48313,48314,48315,48316,48317,48318,48319,48320,48321,48322,48323,48324,48325,48326,48327,48328,48329,48330,48331,48332,48333,48334,48335,48336,48337,48338,48339,48340,48341,48342,48343,48344,48345,48346,48347,48348,48349,48350,48351,48352,48353,48354,48355,48356,48357,48358,48359,48360,48361,48362,48363,48364,48365,48366,48367,48368,48369,48370,48371,48372,48373,48374,48375,48376,48377,48378,48379,48380,48381,48382,48383,48384,48385,48386,48387,48388,48389,48390,48391,48392,48393,48394,48395,48396,48397,48398,48399,48400,48401,48402,48403,48404,48405,48406,48407,48408,48409,48410,48411,48412,48413,48414,48415,48416,48417,48418,48419,48420,48421,48422,48423,48424,48425,48426,48427,48428,48429,48430,48431,48432,48433,48434,48435,48436,48437,48438,48439,48440,48441,48442,48443,48444,48445,48446,48447,48448,48449,48450,48451,48452,48453,48454,48455,48456,48457,48458,48459,48460,48461,48462,48463,48464,48465,48466,48467,48468,48469,48470,48471,48472,48473,48474,48475,48476,48477,48478,48479,48480,48481,48482,48483,48484,48485,48486,48487,48488,48489,48490,48491,48492,48493,48494,48495,48496,48497,48498,48499,48500,48501,48502,48503,48504,48505,48506,48507,48508,48509,48510,48511,48512,48513,48514,48515,48516,48517,48518,48519,48520,48521,48522,48523,48524,48525,48526,48527,48528,48529,48530,48531,48532,48533,48534,48535,48536,48537,48538,48539,48540,48541,48542,48543,48544,48545,48546,48547,48548,48549,48550,48551,48552,48553,48554,48555,48556,48557,48558,48559,48560,48561,48562,48563,48564,48565,48566,48567,48568,48569,48570,48571,48572,48573,48574,48575,48576,48577,48578,48579,48580,48581,48582,48583,48584,48585,48586,48587,48588,48589,48590,48591,48592,48593,48594,48595,48596,48597,48598,48599,48600,48601,48602,48603,48604,48605,48606,48607,48608,48609,48610,48611,48612,48613,48614,48615,48616,48617,48618,48619,48620,48621,48622,48623,48624,48625,48626,48627,48628,48629,48630,48631,48632,48633,48634,48635,48636,48637,48638,48639,48640,48641,48642,48643,48644,48645,48646,48647,48648,48649,48650,48651,48652,48653,48654,48655,48656,48657,48658,48659,48660,48661,48662,48663,48664,48665,48666,48667,48668,48669,48670,48671,48672,48673,48674,48675,48676,48677,48678,48679,48680,48681,48682,48683,48684,48685,48686,48687,48688,48689,48690,48691,48692,48693,48694,48695,48696,48697,48698,48699,48700,48701,48702,48703,48704,48705,48706,48707,48708,48709,48710,48711,48712,48713,48714,48715,48716,48717,48718,48719,48720,48721,48722,48723,48724,48725,48726,48727,48728,48729,48730,48731,48732,48733,48734,48735,48736,48737,48738,48739,48740,48741,48742,48743,48744,48745,48746,48747,48748,48749,48750,48751,48752,48753,48754,48755,48756,48757,48758,48759,48760,48761,48762,48763,48764,48765,48766,48767,48768,48769,48770,48771,48772,48773,48774,48775,48776,48777,48778,48779,48780,48781,48782,48783,48784,48785,48786,48787,48788,48789,48790,48791,48792,48793,48794,48795,48796,48797,48798,48799,48800,48801,48802,48803,48804,48805,48806,48807,48808,48809,48810,48811,48812,48813,48814,48815,48816,48817,48818,48819,48820,48821,48822,48823,48824,48825,48826,48827,48828,48829,48830,48831,48832,48833,48834,48835,48836,48837,48838,48839,48840,48841,48842,48843,48844,48845,48846,48847,48848,48849,48850,48851,48852,48853,48854,48855,48856,48857,48858,48859,48860,48861,48862,48863,48864,48865,48866,48867,48868,48869,48870,48871,48872,48873,48874,48875,48876,48877,48878,48879,48880,48881,48882,48883,48884,48885,48886,48887,48888,48889,48890,48891,48892,48893,48894,48895,48896,48897,48898,48899,48900,48901,48902,48903,48904,48905,48906,48907,48908,48909,48910,48911,48912,48913,48914,48915,48916,48917,48918,48919,48920,48921,48922,48923,48924,48925,48926,48927,48928,48929,48930,48931,48932,48933,48934,48935,48936,48937,48938,48939,48940,48941,48942,48943,48944,48945,48946,48947,48948,48949,48950,48951,48952,48953,48954,48955,48956,48957,48958,48959,48960,48961,48962,48963,48964,48965,48966,48967,48968,48969,48970,48971,48972,48973,48974,48975,48976,48977,48978,48979,48980,48981,48982,48983,48984,48985,48986,48987,48988,48989,48990,48991,48992,48993,48994,48995,48996,48997,48998,48999,49000,49001,49002,49003,49004,49005,49006,49007,49008,49009,49010,49011,49012,49013,49014,49015,49016,49017,49018,49019,49020,49021,49022,49023,49024,49025,49026,49027,49028,49029,49030,49031,49032,49033,49034,49035,49036,49037,49038,49039,49040,49041,49042,49043,49044,49045,49046,49047,49048,49049,49050,49051,49052,49053,49054,49055,49056,49057,49058,49059,49060,49061,49062,49063,49064,49065,49066,49067,49068,49069,49070,49071,49072,49073,49074,49075,49076,49077,49078,49079,49080,49081,49082,49083,49084,49085,49086,49087,49088,49089,49090,49091,49092,49093,49094,49095,49096,49097,49098,49099,49100,49101,49102,49103,49104,49105,49106,49107,49108,49109,49110,49111,49112,49113,49114,49115,49116,49117,49118,49119,49120,49121,49122,49123,49124,49125,49126,49127,49128,49129,49130,49131,49132,49133,49134,49135,49136,49137,49138,49139,49140,49141,49142,49143,49144,49145,49146,49147,49148,49149,49150,49151,49152,49153,49154,49155,49156,49157,49158,49159,49160,49161,49162,49163,49164,49165,49166,49167,49168,49169,49170,49171,49172,49173,49174,49175,49176,49177,49178,49179,49180,49181,49182,49183,49184,49185,49186,49187,49188,49189,49190,49191,49192,49193,49194,49195,49196,49197,49198,49199,49200,49201,49202,49203,49204,49205,49206,49207,49208,49209,49210,49211,49212,49213,49214,49215,49216,49217,49218,49219,49220,49221,49222,49223,49224,49225,49226,49227,49228,49229,49230,49231,49232,49233,49234,49235,49236,49237,49238,49239,49240,49241,49242,49243,49244,49245,49246,49247,49248,49249,49250,49251,49252,49253,49254,49255,49256,49257,49258,49259,49260,49261,49262,49263,49264,49265,49266,49267,49268,49269,49270,49271,49272,49273,49274,49275,49276,49277,49278,49279,49280,49281,49282,49283,49284,49285,49286,49287,49288,49289,49290,49291,49292,49293,49294,49295,49296,49297,49298,49299,49300,49301,49302,49303,49304,49305,49306,49307,49308,49309,49310,49311,49312,49313,49314,49315,49316,49317,49318,49319,49320,49321,49322,49323,49324,49325,49326,49327,49328,49329,49330,49331,49332,49333,49334,49335,49336,49337,49338,49339,49340,49341,49342,49343,49344,49345,49346,49347,49348,49349,49350,49351,49352,49353,49354,49355,49356,49357,49358,49359,49360,49361,49362,49363,49364,49365,49366,49367,49368,49369,49370,49371,49372,49373,49374,49375,49376,49377,49378,49379,49380,49381,49382,49383,49384,49385,49386,49387,49388,49389,49390,49391,49392,49393,49394,49395,49396,49397,49398,49399,49400,49401,49402,49403,49404,49405,49406,49407,49408,49409,49410,49411,49412,49413,49414,49415,49416,49417,49418,49419,49420,49421,49422,49423,49424,49425,49426,49427,49428,49429,49430,49431,49432,49433,49434,49435,49436,49437,49438,49439,49440,49441,49442,49443,49444,49445,49446,49447,49448,49449,49450,49451,49452,49453,49454,49455,49456,49457,49458,49459,49460,49461,49462,49463,49464,49465,49466,49467,49468,49469,49470,49471,49472,49473,49474,49475,49476,49477,49478,49479,49480,49481,49482,49483,49484,49485,49486,49487,49488,49489,49490,49491,49492,49493,49494,49495,49496,49497,49498,49499,49500,49501,49502,49503,49504,49505,49506,49507,49508,49509,49510,49511,49512,49513,49514,49515,49516,49517,49518,49519,49520,49521,49522,49523,49524,49525,49526,49527,49528,49529,49530,49531,49532,49533,49534,49535,49536,49537,49538,49539,49540,49541,49542,49543,49544,49545,49546,49547,49548,49549,49550,49551,49552,49553,49554,49555,49556,49557,49558,49559,49560,49561,49562,49563,49564,49565,49566,49567,49568,49569,49570,49571,49572,49573,49574,49575,49576,49577,49578,49579,49580,49581,49582,49583,49584,49585,49586,49587,49588,49589,49590,49591,49592,49593,49594,49595,49596,49597,49598,49599,49600,49601,49602,49603,49604,49605,49606,49607,49608,49609,49610,49611,49612,49613,49614,49615,49616,49617,49618,49619,49620,49621,49622,49623,49624,49625,49626,49627,49628,49629,49630,49631,49632,49633,49634,49635,49636,49637,49638,49639,49640,49641,49642,49643,49644,49645,49646,49647,49648,49649,49650,49651,49652,49653,49654,49655,49656,49657,49658,49659,49660,49661,49662,49663,49664,49665,49666,49667,49668,49669,49670,49671,49672,49673,49674,49675,49676,49677,49678,49679,49680,49681,49682,49683,49684,49685,49686,49687,49688,49689,49690,49691,49692,49693,49694,49695,49696,49697,49698,49699,49700,49701,49702,49703,49704,49705,49706,49707,49708,49709,49710,49711,49712,49713,49714,49715,49716,49717,49718,49719,49720,49721,49722,49723,49724,49725,49726,49727,49728,49729,49730,49731,49732,49733,49734,49735,49736,49737,49738,49739,49740,49741,49742,49743,49744,49745,49746,49747,49748,49749,49750,49751,49752,49753,49754,49755,49756,49757,49758,49759,49760,49761,49762,49763,49764,49765,49766,49767,49768,49769,49770,49771,49772,49773,49774,49775,49776,49777,49778,49779,49780,49781,49782,49783,49784,49785,49786,49787,49788,49789,49790,49791,49792,49793,49794,49795,49796,49797,49798,49799,49800,49801,49802,49803,49804,49805,49806,49807,49808,49809,49810,49811,49812,49813,49814,49815,49816,49817,49818,49819,49820,49821,49822,49823,49824,49825,49826,49827,49828,49829,49830,49831,49832,49833,49834,49835,49836,49837,49838,49839,49840,49841,49842,49843,49844,49845,49846,49847,49848,49849,49850,49851,49852,49853,49854,49855,49856,49857,49858,49859,49860,49861,49862,49863,49864,49865,49866,49867,49868,49869,49870,49871,49872,49873,49874,49875,49876,49877,49878,49879,49880,49881,49882,49883,49884,49885,49886,49887,49888,49889,49890,49891,49892,49893,49894,49895,49896,49897,49898,49899,49900,49901,49902,49903,49904,49905,49906,49907,49908,49909,49910,49911,49912,49913,49914,49915,49916,49917,49918,49919,49920,49921,49922,49923,49924,49925,49926,49927,49928,49929,49930,49931,49932,49933,49934,49935,49936,49937,49938,49939,49940,49941,49942,49943,49944,49945,49946,49947,49948,49949,49950,49951,49952,49953,49954,49955,49956,49957,49958,49959,49960,49961,49962,49963,49964,49965,49966,49967,49968,49969,49970,49971,49972,49973,49974,49975,49976,49977,49978,49979,49980,49981,49982,49983,49984,49985,49986,49987,49988,49989,49990,49991,49992,49993,49994,49995,49996,49997,49998,49999,50000,50001,50002,50003,50004,50005,50006,50007,50008,50009,50010,50011,50012,50013,50014,50015,50016,50017,50018,50019,50020,50021,50022,50023,50024,50025,50026,50027,50028,50029,50030,50031,50032,50033,50034,50035,50036,50037,50038,50039,50040,50041,50042,50043,50044,50045,50046,50047,50048,50049,50050,50051,50052,50053,50054,50055,50056,50057,50058,50059,50060,50061,50062,50063,50064,50065,50066,50067,50068,50069,50070,50071,50072,50073,50074,50075,50076,50077,50078,50079,50080,50081,50082,50083,50084,50085,50086,50087,50088,50089,50090,50091,50092,50093,50094,50095,50096,50097,50098,50099,50100,50101,50102,50103,50104,50105,50106,50107,50108,50109,50110,50111,50112,50113,50114,50115,50116,50117,50118,50119,50120,50121,50122,50123,50124,50125,50126,50127,50128,50129,50130,50131,50132,50133,50134,50135,50136,50137,50138,50139,50140,50141,50142,50143,50144,50145,50146,50147,50148,50149,50150,50151,50152,50153,50154,50155,50156,50157,50158,50159,50160,50161,50162,50163,50164,50165,50166,50167,50168,50169,50170,50171,50172,50173,50174,50175,50176,50177,50178,50179,50180,50181,50182,50183,50184,50185,50186,50187,50188,50189,50190,50191,50192,50193,50194,50195,50196,50197,50198,50199,50200,50201,50202,50203,50204,50205,50206,50207,50208,50209,50210,50211,50212,50213,50214,50215,50216,50217,50218,50219,50220,50221,50222,50223,50224,50225,50226,50227,50228,50229,50230,50231,50232,50233,50234,50235,50236,50237,50238,50239,50240,50241,50242,50243,50244,50245,50246,50247,50248,50249,50250,50251,50252,50253,50254,50255,50256,50257,50258,50259,50260,50261,50262,50263,50264,50265,50266,50267,50268,50269,50270,50271,50272,50273,50274,50275,50276,50277,50278,50279,50280,50281,50282,50283,50284,50285,50286,50287,50288,50289,50290,50291,50292,50293,50294,50295,50296,50297,50298,50299,50300,50301,50302,50303,50304,50305,50306,50307,50308,50309,50310,50311,50312,50313,50314,50315,50316,50317,50318,50319,50320,50321,50322,50323,50324,50325,50326,50327,50328,50329,50330,50331,50332,50333,50334,50335,50336,50337,50338,50339,50340,50341,50342,50343,50344,50345,50346,50347,50348,50349,50350,50351,50352,50353,50354,50355,50356,50357,50358,50359,50360,50361,50362,50363,50364,50365,50366,50367,50368,50369,50370,50371,50372,50373,50374,50375,50376,50377,50378,50379,50380,50381,50382,50383,50384,50385,50386,50387,50388,50389,50390,50391,50392,50393,50394,50395,50396,50397,50398,50399,50400,50401,50402,50403,50404,50405,50406,50407,50408,50409,50410,50411,50412,50413,50414,50415,50416,50417,50418,50419,50420,50421,50422,50423,50424,50425,50426,50427,50428,50429,50430,50431,50432,50433,50434,50435,50436,50437,50438,50439,50440,50441,50442,50443,50444,50445,50446,50447,50448,50449,50450,50451,50452,50453,50454,50455,50456,50457,50458,50459,50460,50461,50462,50463,50464,50465,50466,50467,50468,50469,50470,50471,50472,50473,50474,50475,50476,50477,50478,50479,50480,50481,50482,50483,50484,50485,50486,50487,50488,50489,50490,50491,50492,50493,50494,50495,50496,50497,50498,50499,50500,50501,50502,50503,50504,50505,50506,50507,50508,50509,50510,50511,50512,50513,50514,50515,50516,50517,50518,50519,50520,50521,50522,50523,50524,50525,50526,50527,50528,50529,50530,50531,50532,50533,50534,50535,50536,50537,50538,50539,50540,50541,50542,50543,50544,50545,50546,50547,50548,50549,50550,50551,50552,50553,50554,50555,50556,50557,50558,50559,50560,50561,50562,50563,50564,50565,50566,50567,50568,50569,50570,50571,50572,50573,50574,50575,50576,50577,50578,50579,50580,50581,50582,50583,50584,50585,50586,50587,50588,50589,50590,50591,50592,50593,50594,50595,50596,50597,50598,50599,50600,50601,50602,50603,50604,50605,50606,50607,50608,50609,50610,50611,50612,50613,50614,50615,50616,50617,50618,50619,50620,50621,50622,50623,50624,50625,50626,50627,50628,50629,50630,50631,50632,50633,50634,50635,50636,50637,50638,50639,50640,50641,50642,50643,50644,50645,50646,50647,50648,50649,50650,50651,50652,50653,50654,50655,50656,50657,50658,50659,50660,50661,50662,50663,50664,50665,50666,50667,50668,50669,50670,50671,50672,50673,50674,50675,50676,50677,50678,50679,50680,50681,50682,50683,50684,50685,50686,50687,50688,50689,50690,50691,50692,50693,50694,50695,50696,50697,50698,50699,50700,50701,50702,50703,50704,50705,50706,50707,50708,50709,50710,50711,50712,50713,50714,50715,50716,50717,50718,50719,50720,50721,50722,50723,50724,50725,50726,50727,50728,50729,50730,50731,50732,50733,50734,50735,50736,50737,50738,50739,50740,50741,50742,50743,50744,50745,50746,50747,50748,50749,50750,50751,50752,50753,50754,50755,50756,50757,50758,50759,50760,50761,50762,50763,50764,50765,50766,50767,50768,50769,50770,50771,50772,50773,50774,50775,50776,50777,50778,50779,50780,50781,50782,50783,50784,50785,50786,50787,50788,50789,50790,50791,50792,50793,50794,50795,50796,50797,50798,50799,50800,50801,50802,50803,50804,50805,50806,50807,50808,50809,50810,50811,50812,50813,50814,50815,50816,50817,50818,50819,50820,50821,50822,50823,50824,50825,50826,50827,50828,50829,50830,50831,50832,50833,50834,50835,50836,50837,50838,50839,50840,50841,50842,50843,50844,50845,50846,50847,50848,50849,50850,50851,50852,50853,50854,50855,50856,50857,50858,50859,50860,50861,50862,50863,50864,50865,50866,50867,50868,50869,50870,50871,50872,50873,50874,50875,50876,50877,50878,50879,50880,50881,50882,50883,50884,50885,50886,50887,50888,50889,50890,50891,50892,50893,50894,50895,50896,50897,50898,50899,50900,50901,50902,50903,50904,50905,50906,50907,50908,50909,50910,50911,50912,50913,50914,50915,50916,50917,50918,50919,50920,50921,50922,50923,50924,50925,50926,50927,50928,50929,50930,50931,50932,50933,50934,50935,50936,50937,50938,50939,50940,50941,50942,50943,50944,50945,50946,50947,50948,50949,50950,50951,50952,50953,50954,50955,50956,50957,50958,50959,50960,50961,50962,50963,50964,50965,50966,50967,50968,50969,50970,50971,50972,50973,50974,50975,50976,50977,50978,50979,50980,50981,50982,50983,50984,50985,50986,50987,50988,50989,50990,50991,50992,50993,50994,50995,50996,50997,50998,50999,51000,51001,51002,51003,51004,51005,51006,51007,51008,51009,51010,51011,51012,51013,51014,51015,51016,51017,51018,51019,51020,51021,51022,51023,51024,51025,51026,51027,51028,51029,51030,51031,51032,51033,51034,51035,51036,51037,51038,51039,51040,51041,51042,51043,51044,51045,51046,51047,51048,51049,51050,51051,51052,51053,51054,51055,51056,51057,51058,51059,51060,51061,51062,51063,51064,51065,51066,51067,51068,51069,51070,51071,51072,51073,51074,51075,51076,51077,51078,51079,51080,51081,51082,51083,51084,51085,51086,51087,51088,51089,51090,51091,51092,51093,51094,51095,51096,51097,51098,51099,51100,51101,51102,51103,51104,51105,51106,51107,51108,51109,51110,51111,51112,51113,51114,51115,51116,51117,51118,51119,51120,51121,51122,51123,51124,51125,51126,51127,51128,51129,51130,51131,51132,51133,51134,51135,51136,51137,51138,51139,51140,51141,51142,51143,51144,51145,51146,51147,51148,51149,51150,51151,51152,51153,51154,51155,51156,51157,51158,51159,51160,51161,51162,51163,51164,51165,51166,51167,51168,51169,51170,51171,51172,51173,51174,51175,51176,51177,51178,51179,51180,51181,51182,51183,51184,51185,51186,51187,51188,51189,51190,51191,51192,51193,51194,51195,51196,51197,51198,51199,51200,51201,51202,51203,51204,51205,51206,51207,51208,51209,51210,51211,51212,51213,51214,51215,51216,51217,51218,51219,51220,51221,51222,51223,51224,51225,51226,51227,51228,51229,51230,51231,51232,51233,51234,51235,51236,51237,51238,51239,51240,51241,51242,51243,51244,51245,51246,51247,51248,51249,51250,51251,51252,51253,51254,51255,51256,51257,51258,51259,51260,51261,51262,51263,51264,51265,51266,51267,51268,51269,51270,51271,51272,51273,51274,51275,51276,51277,51278,51279,51280,51281,51282,51283,51284,51285,51286,51287,51288,51289,51290,51291,51292,51293,51294,51295,51296,51297,51298,51299,51300,51301,51302,51303,51304,51305,51306,51307,51308,51309,51310,51311,51312,51313,51314,51315,51316,51317,51318,51319,51320,51321,51322,51323,51324,51325,51326,51327,51328,51329,51330,51331,51332,51333,51334,51335,51336,51337,51338,51339,51340,51341,51342,51343,51344,51345,51346,51347,51348,51349,51350,51351,51352,51353,51354,51355,51356,51357,51358,51359,51360,51361,51362,51363,51364,51365,51366,51367,51368,51369,51370,51371,51372,51373,51374,51375,51376,51377,51378,51379,51380,51381,51382,51383,51384,51385,51386,51387,51388,51389,51390,51391,51392,51393,51394,51395,51396,51397,51398,51399,51400,51401,51402,51403,51404,51405,51406,51407,51408,51409,51410,51411,51412,51413,51414,51415,51416,51417,51418,51419,51420,51421,51422,51423,51424,51425,51426,51427,51428,51429,51430,51431,51432,51433,51434,51435,51436,51437,51438,51439,51440,51441,51442,51443,51444,51445,51446,51447,51448,51449,51450,51451,51452,51453,51454,51455,51456,51457,51458,51459,51460,51461,51462,51463,51464,51465,51466,51467,51468,51469,51470,51471,51472,51473,51474,51475,51476,51477,51478,51479,51480,51481,51482,51483,51484,51485,51486,51487,51488,51489,51490,51491,51492,51493,51494,51495,51496,51497,51498,51499,51500,51501,51502,51503,51504,51505,51506,51507,51508,51509,51510,51511,51512,51513,51514,51515,51516,51517,51518,51519,51520,51521,51522,51523,51524,51525,51526,51527,51528,51529,51530,51531,51532,51533,51534,51535,51536,51537,51538,51539,51540,51541,51542,51543,51544,51545,51546,51547,51548,51549,51550,51551,51552,51553,51554,51555,51556,51557,51558,51559,51560,51561,51562,51563,51564,51565,51566,51567,51568,51569,51570,51571,51572,51573,51574,51575,51576,51577,51578,51579,51580,51581,51582,51583,51584,51585,51586,51587,51588,51589,51590,51591,51592,51593,51594,51595,51596,51597,51598,51599,51600,51601,51602,51603,51604,51605,51606,51607,51608,51609,51610,51611,51612,51613,51614,51615,51616,51617,51618,51619,51620,51621,51622,51623,51624,51625,51626,51627,51628,51629,51630,51631,51632,51633,51634,51635,51636,51637,51638,51639,51640,51641,51642,51643,51644,51645,51646,51647,51648,51649,51650,51651,51652,51653,51654,51655,51656,51657,51658,51659,51660,51661,51662,51663,51664,51665,51666,51667,51668,51669,51670,51671,51672,51673,51674,51675,51676,51677,51678,51679,51680,51681,51682,51683,51684,51685,51686,51687,51688,51689,51690,51691,51692,51693,51694,51695,51696,51697,51698,51699,51700,51701,51702,51703,51704,51705,51706,51707,51708,51709,51710,51711,51712,51713,51714,51715,51716,51717,51718,51719,51720,51721,51722,51723,51724,51725,51726,51727,51728,51729,51730,51731,51732,51733,51734,51735,51736,51737,51738,51739,51740,51741,51742,51743,51744,51745,51746,51747,51748,51749,51750,51751,51752,51753,51754,51755,51756,51757,51758,51759,51760,51761,51762,51763,51764,51765,51766,51767,51768,51769,51770,51771,51772,51773,51774,51775,51776,51777,51778,51779,51780,51781,51782,51783,51784,51785,51786,51787,51788,51789,51790,51791,51792,51793,51794,51795,51796,51797,51798,51799,51800,51801,51802,51803,51804,51805,51806,51807,51808,51809,51810,51811,51812,51813,51814,51815,51816,51817,51818,51819,51820,51821,51822,51823,51824,51825,51826,51827,51828,51829,51830,51831,51832,51833,51834,51835,51836,51837,51838,51839,51840,51841,51842,51843,51844,51845,51846,51847,51848,51849,51850,51851,51852,51853,51854,51855,51856,51857,51858,51859,51860,51861,51862,51863,51864,51865,51866,51867,51868,51869,51870,51871,51872,51873,51874,51875,51876,51877,51878,51879,51880,51881,51882,51883,51884,51885,51886,51887,51888,51889,51890,51891,51892,51893,51894,51895,51896,51897,51898,51899,51900,51901,51902,51903,51904,51905,51906,51907,51908,51909,51910,51911,51912,51913,51914,51915,51916,51917,51918,51919,51920,51921,51922,51923,51924,51925,51926,51927,51928,51929,51930,51931,51932,51933,51934,51935,51936,51937,51938,51939,51940,51941,51942,51943,51944,51945,51946,51947,51948,51949,51950,51951,51952,51953,51954,51955,51956,51957,51958,51959,51960,51961,51962,51963,51964,51965,51966,51967,51968,51969,51970,51971,51972,51973,51974,51975,51976,51977,51978,51979,51980,51981,51982,51983,51984,51985,51986,51987,51988,51989,51990,51991,51992,51993,51994,51995,51996,51997,51998,51999,52000,52001,52002,52003,52004,52005,52006,52007,52008,52009,52010,52011,52012,52013,52014,52015,52016,52017,52018,52019,52020,52021,52022,52023,52024,52025,52026,52027,52028,52029,52030,52031,52032,52033,52034,52035,52036,52037,52038,52039,52040,52041,52042,52043,52044,52045,52046,52047,52048,52049,52050,52051,52052,52053,52054,52055,52056,52057,52058,52059,52060,52061,52062,52063,52064,52065,52066,52067,52068,52069,52070,52071,52072,52073,52074,52075,52076,52077,52078,52079,52080,52081,52082,52083,52084,52085,52086,52087,52088,52089,52090,52091,52092,52093,52094,52095,52096,52097,52098,52099,52100,52101,52102,52103,52104,52105,52106,52107,52108,52109,52110,52111,52112,52113,52114,52115,52116,52117,52118,52119,52120,52121,52122,52123,52124,52125,52126,52127,52128,52129,52130,52131,52132,52133,52134,52135,52136,52137,52138,52139,52140,52141,52142,52143,52144,52145,52146,52147,52148,52149,52150,52151,52152,52153,52154,52155,52156,52157,52158,52159,52160,52161,52162,52163,52164,52165,52166,52167,52168,52169,52170,52171,52172,52173,52174,52175,52176,52177,52178,52179,52180,52181,52182,52183,52184,52185,52186,52187,52188,52189,52190,52191,52192,52193,52194,52195,52196,52197,52198,52199,52200,52201,52202,52203,52204,52205,52206,52207,52208,52209,52210,52211,52212,52213,52214,52215,52216,52217,52218,52219,52220,52221,52222,52223,52224,52225,52226,52227,52228,52229,52230,52231,52232,52233,52234,52235,52236,52237,52238,52239,52240,52241,52242,52243,52244,52245,52246,52247,52248,52249,52250,52251,52252,52253,52254,52255,52256,52257,52258,52259,52260,52261,52262,52263,52264,52265,52266,52267,52268,52269,52270,52271,52272,52273,52274,52275,52276,52277,52278,52279,52280,52281,52282,52283,52284,52285,52286,52287,52288,52289,52290,52291,52292,52293,52294,52295,52296,52297,52298,52299,52300,52301,52302,52303,52304,52305,52306,52307,52308,52309,52310,52311,52312,52313,52314,52315,52316,52317,52318,52319,52320,52321,52322,52323,52324,52325,52326,52327,52328,52329,52330,52331,52332,52333,52334,52335,52336,52337,52338,52339,52340,52341,52342,52343,52344,52345,52346,52347,52348,52349,52350,52351,52352,52353,52354,52355,52356,52357,52358,52359,52360,52361,52362,52363,52364,52365,52366,52367,52368,52369,52370,52371,52372,52373,52374,52375,52376,52377,52378,52379,52380,52381,52382,52383,52384,52385,52386,52387,52388,52389,52390,52391,52392,52393,52394,52395,52396,52397,52398,52399,52400,52401,52402,52403,52404,52405,52406,52407,52408,52409,52410,52411,52412,52413,52414,52415,52416,52417,52418,52419,52420,52421,52422,52423,52424,52425,52426,52427,52428,52429,52430,52431,52432,52433,52434,52435,52436,52437,52438,52439,52440,52441,52442,52443,52444,52445,52446,52447,52448,52449,52450,52451,52452,52453,52454,52455,52456,52457,52458,52459,52460,52461,52462,52463,52464,52465,52466,52467,52468,52469,52470,52471,52472,52473,52474,52475,52476,52477,52478,52479,52480,52481,52482,52483,52484,52485,52486,52487,52488,52489,52490,52491,52492,52493,52494,52495,52496,52497,52498,52499,52500,52501,52502,52503,52504,52505,52506,52507,52508,52509,52510,52511,52512,52513,52514,52515,52516,52517,52518,52519,52520,52521,52522,52523,52524,52525,52526,52527,52528,52529,52530,52531,52532,52533,52534,52535,52536,52537,52538,52539,52540,52541,52542,52543,52544,52545,52546,52547,52548,52549,52550,52551,52552,52553,52554,52555,52556,52557,52558,52559,52560,52561,52562,52563,52564,52565,52566,52567,52568,52569,52570,52571,52572,52573,52574,52575,52576,52577,52578,52579,52580,52581,52582,52583,52584,52585,52586,52587,52588,52589,52590,52591,52592,52593,52594,52595,52596,52597,52598,52599,52600,52601,52602,52603,52604,52605,52606,52607,52608,52609,52610,52611,52612,52613,52614,52615,52616,52617,52618,52619,52620,52621,52622,52623,52624,52625,52626,52627,52628,52629,52630,52631,52632,52633,52634,52635,52636,52637,52638,52639,52640,52641,52642,52643,52644,52645,52646,52647,52648,52649,52650,52651,52652,52653,52654,52655,52656,52657,52658,52659,52660,52661,52662,52663,52664,52665,52666,52667,52668,52669,52670,52671,52672,52673,52674,52675,52676,52677,52678,52679,52680,52681,52682,52683,52684,52685,52686,52687,52688,52689,52690,52691,52692,52693,52694,52695,52696,52697,52698,52699,52700,52701,52702,52703,52704,52705,52706,52707,52708,52709,52710,52711,52712,52713,52714,52715,52716,52717,52718,52719,52720,52721,52722,52723,52724,52725,52726,52727,52728,52729,52730,52731,52732,52733,52734,52735,52736,52737,52738,52739,52740,52741,52742,52743,52744,52745,52746,52747,52748,52749,52750,52751,52752,52753,52754,52755,52756,52757,52758,52759,52760,52761,52762,52763,52764,52765,52766,52767,52768,52769,52770,52771,52772,52773,52774,52775,52776,52777,52778,52779,52780,52781,52782,52783,52784,52785,52786,52787,52788,52789,52790,52791,52792,52793,52794,52795,52796,52797,52798,52799,52800,52801,52802,52803,52804,52805,52806,52807,52808,52809,52810,52811,52812,52813,52814,52815,52816,52817,52818,52819,52820,52821,52822,52823,52824,52825,52826,52827,52828,52829,52830,52831,52832,52833,52834,52835,52836,52837,52838,52839,52840,52841,52842,52843,52844,52845,52846,52847,52848,52849,52850,52851,52852,52853,52854,52855,52856,52857,52858,52859,52860,52861,52862,52863,52864,52865,52866,52867,52868,52869,52870,52871,52872,52873,52874,52875,52876,52877,52878,52879,52880,52881,52882,52883,52884,52885,52886,52887,52888,52889,52890,52891,52892,52893,52894,52895,52896,52897,52898,52899,52900,52901,52902,52903,52904,52905,52906,52907,52908,52909,52910,52911,52912,52913,52914,52915,52916,52917,52918,52919,52920,52921,52922,52923,52924,52925,52926,52927,52928,52929,52930,52931,52932,52933,52934,52935,52936,52937,52938,52939,52940,52941,52942,52943,52944,52945,52946,52947,52948,52949,52950,52951,52952,52953,52954,52955,52956,52957,52958,52959,52960,52961,52962,52963,52964,52965,52966,52967,52968,52969,52970,52971,52972,52973,52974,52975,52976,52977,52978,52979,52980,52981,52982,52983,52984,52985,52986,52987,52988,52989,52990,52991,52992,52993,52994,52995,52996,52997,52998,52999,53000,53001,53002,53003,53004,53005,53006,53007,53008,53009,53010,53011,53012,53013,53014,53015,53016,53017,53018,53019,53020,53021,53022,53023,53024,53025,53026,53027,53028,53029,53030,53031,53032,53033,53034,53035,53036,53037,53038,53039,53040,53041,53042,53043,53044,53045,53046,53047,53048,53049,53050,53051,53052,53053,53054,53055,53056,53057,53058,53059,53060,53061,53062,53063,53064,53065,53066,53067,53068,53069,53070,53071,53072,53073,53074,53075,53076,53077,53078,53079,53080,53081,53082,53083,53084,53085,53086,53087,53088,53089,53090,53091,53092,53093,53094,53095,53096,53097,53098,53099,53100,53101,53102,53103,53104,53105,53106,53107,53108,53109,53110,53111,53112,53113,53114,53115,53116,53117,53118,53119,53120,53121,53122,53123,53124,53125,53126,53127,53128,53129,53130,53131,53132,53133,53134,53135,53136,53137,53138,53139,53140,53141,53142,53143,53144,53145,53146,53147,53148,53149,53150,53151,53152,53153,53154,53155,53156,53157,53158,53159,53160,53161,53162,53163,53164,53165,53166,53167,53168,53169,53170,53171,53172,53173,53174,53175,53176,53177,53178,53179,53180,53181,53182,53183,53184,53185,53186,53187,53188,53189,53190,53191,53192,53193,53194,53195,53196,53197,53198,53199,53200,53201,53202,53203,53204,53205,53206,53207,53208,53209,53210,53211,53212,53213,53214,53215,53216,53217,53218,53219,53220,53221,53222,53223,53224,53225,53226,53227,53228,53229,53230,53231,53232,53233,53234,53235,53236,53237,53238,53239,53240,53241,53242,53243,53244,53245,53246,53247,53248,53249,53250,53251,53252,53253,53254,53255,53256,53257,53258,53259,53260,53261,53262,53263,53264,53265,53266,53267,53268,53269,53270,53271,53272,53273,53274,53275,53276,53277,53278,53279,53280,53281,53282,53283,53284,53285,53286,53287,53288,53289,53290,53291,53292,53293,53294,53295,53296,53297,53298,53299,53300,53301,53302,53303,53304,53305,53306,53307,53308,53309,53310,53311,53312,53313,53314,53315,53316,53317,53318,53319,53320,53321,53322,53323,53324,53325,53326,53327,53328,53329,53330,53331,53332,53333,53334,53335,53336,53337,53338,53339,53340,53341,53342,53343,53344,53345,53346,53347,53348,53349,53350,53351,53352,53353,53354,53355,53356,53357,53358,53359,53360,53361,53362,53363,53364,53365,53366,53367,53368,53369,53370,53371,53372,53373,53374,53375,53376,53377,53378,53379,53380,53381,53382,53383,53384,53385,53386,53387,53388,53389,53390,53391,53392,53393,53394,53395,53396,53397,53398,53399,53400,53401,53402,53403,53404,53405,53406,53407,53408,53409,53410,53411,53412,53413,53414,53415,53416,53417,53418,53419,53420,53421,53422,53423,53424,53425,53426,53427,53428,53429,53430,53431,53432,53433,53434,53435,53436,53437,53438,53439,53440,53441,53442,53443,53444,53445,53446,53447,53448,53449,53450,53451,53452,53453,53454,53455,53456,53457,53458,53459,53460,53461,53462,53463,53464,53465,53466,53467,53468,53469,53470,53471,53472,53473,53474,53475,53476,53477,53478,53479,53480,53481,53482,53483,53484,53485,53486,53487,53488,53489,53490,53491,53492,53493,53494,53495,53496,53497,53498,53499,53500,53501,53502,53503,53504,53505,53506,53507,53508,53509,53510,53511,53512,53513,53514,53515,53516,53517,53518,53519,53520,53521,53522,53523,53524,53525,53526,53527,53528,53529,53530,53531,53532,53533,53534,53535,53536,53537,53538,53539,53540,53541,53542,53543,53544,53545,53546,53547,53548,53549,53550,53551,53552,53553,53554,53555,53556,53557,53558,53559,53560,53561,53562,53563,53564,53565,53566,53567,53568,53569,53570,53571,53572,53573,53574,53575,53576,53577,53578,53579,53580,53581,53582,53583,53584,53585,53586,53587,53588,53589,53590,53591,53592,53593,53594,53595,53596,53597,53598,53599,53600,53601,53602,53603,53604,53605,53606,53607,53608,53609,53610,53611,53612,53613,53614,53615,53616,53617,53618,53619,53620,53621,53622,53623,53624,53625,53626,53627,53628,53629,53630,53631,53632,53633,53634,53635,53636,53637,53638,53639,53640,53641,53642,53643,53644,53645,53646,53647,53648,53649,53650,53651,53652,53653,53654,53655,53656,53657,53658,53659,53660,53661,53662,53663,53664,53665,53666,53667,53668,53669,53670,53671,53672,53673,53674,53675,53676,53677,53678,53679,53680,53681,53682,53683,53684,53685,53686,53687,53688,53689,53690,53691,53692,53693,53694,53695,53696,53697,53698,53699,53700,53701,53702,53703,53704,53705,53706,53707,53708,53709,53710,53711,53712,53713,53714,53715,53716,53717,53718,53719,53720,53721,53722,53723,53724,53725,53726,53727,53728,53729,53730,53731,53732,53733,53734,53735,53736,53737,53738,53739,53740,53741,53742,53743,53744,53745,53746,53747,53748,53749,53750,53751,53752,53753,53754,53755,53756,53757,53758,53759,53760,53761,53762,53763,53764,53765,53766,53767,53768,53769,53770,53771,53772,53773,53774,53775,53776,53777,53778,53779,53780,53781,53782,53783,53784,53785,53786,53787,53788,53789,53790,53791,53792,53793,53794,53795,53796,53797,53798,53799,53800,53801,53802,53803,53804,53805,53806,53807,53808,53809,53810,53811,53812,53813,53814,53815,53816,53817,53818,53819,53820,53821,53822,53823,53824,53825,53826,53827,53828,53829,53830,53831,53832,53833,53834,53835,53836,53837,53838,53839,53840,53841,53842,53843,53844,53845,53846,53847,53848,53849,53850,53851,53852,53853,53854,53855,53856,53857,53858,53859,53860,53861,53862,53863,53864,53865,53866,53867,53868,53869,53870,53871,53872,53873,53874,53875,53876,53877,53878,53879,53880,53881,53882,53883,53884,53885,53886,53887,53888,53889,53890,53891,53892,53893,53894,53895,53896,53897,53898,53899,53900,53901,53902,53903,53904,53905,53906,53907,53908,53909,53910,53911,53912,53913,53914,53915,53916,53917,53918,53919,53920,53921,53922,53923,53924,53925,53926,53927,53928,53929,53930,53931,53932,53933,53934,53935,53936,53937,53938,53939,53940,53941,53942,53943,53944,53945,53946,53947,53948,53949,53950,53951,53952,53953,53954,53955,53956,53957,53958,53959,53960,53961,53962,53963,53964,53965,53966,53967,53968,53969,53970,53971,53972,53973,53974,53975,53976,53977,53978,53979,53980,53981,53982,53983,53984,53985,53986,53987,53988,53989,53990,53991,53992,53993,53994,53995,53996,53997,53998,53999,54000,54001,54002,54003,54004,54005,54006,54007,54008,54009,54010,54011,54012,54013,54014,54015,54016,54017,54018,54019,54020,54021,54022,54023,54024,54025,54026,54027,54028,54029,54030,54031,54032,54033,54034,54035,54036,54037,54038,54039,54040,54041,54042,54043,54044,54045,54046,54047,54048,54049,54050,54051,54052,54053,54054,54055,54056,54057,54058,54059,54060,54061,54062,54063,54064,54065,54066,54067,54068,54069,54070,54071,54072,54073,54074,54075,54076,54077,54078,54079,54080,54081,54082,54083,54084,54085,54086,54087,54088,54089,54090,54091,54092,54093,54094,54095,54096,54097,54098,54099,54100,54101,54102,54103,54104,54105,54106,54107,54108,54109,54110,54111,54112,54113,54114,54115,54116,54117,54118,54119,54120,54121,54122,54123,54124,54125,54126,54127,54128,54129,54130,54131,54132,54133,54134,54135,54136,54137,54138,54139,54140,54141,54142,54143,54144,54145,54146,54147,54148,54149,54150,54151,54152,54153,54154,54155,54156,54157,54158,54159,54160,54161,54162,54163,54164,54165,54166,54167,54168,54169,54170,54171,54172,54173,54174,54175,54176,54177,54178,54179,54180,54181,54182,54183,54184,54185,54186,54187,54188,54189,54190,54191,54192,54193,54194,54195,54196,54197,54198,54199,54200,54201,54202,54203,54204,54205,54206,54207,54208,54209,54210,54211,54212,54213,54214,54215,54216,54217,54218,54219,54220,54221,54222,54223,54224,54225,54226,54227,54228,54229,54230,54231,54232,54233,54234,54235,54236,54237,54238,54239,54240,54241,54242,54243,54244,54245,54246,54247,54248,54249,54250,54251,54252,54253,54254,54255,54256,54257,54258,54259,54260,54261,54262,54263,54264,54265,54266,54267,54268,54269,54270,54271,54272,54273,54274,54275,54276,54277,54278,54279,54280,54281,54282,54283,54284,54285,54286,54287,54288,54289,54290,54291,54292,54293,54294,54295,54296,54297,54298,54299,54300,54301,54302,54303,54304,54305,54306,54307,54308,54309,54310,54311,54312,54313,54314,54315,54316,54317,54318,54319,54320,54321,54322,54323,54324,54325,54326,54327,54328,54329,54330,54331,54332,54333,54334,54335,54336,54337,54338,54339,54340,54341,54342,54343,54344,54345,54346,54347,54348,54349,54350,54351,54352,54353,54354,54355,54356,54357,54358,54359,54360,54361,54362,54363,54364,54365,54366,54367,54368,54369,54370,54371,54372,54373,54374,54375,54376,54377,54378,54379,54380,54381,54382,54383,54384,54385,54386,54387,54388,54389,54390,54391,54392,54393,54394,54395,54396,54397,54398,54399,54400,54401,54402,54403,54404,54405,54406,54407,54408,54409,54410,54411,54412,54413,54414,54415,54416,54417,54418,54419,54420,54421,54422,54423,54424,54425,54426,54427,54428,54429,54430,54431,54432,54433,54434,54435,54436,54437,54438,54439,54440,54441,54442,54443,54444,54445,54446,54447,54448,54449,54450,54451,54452,54453,54454,54455,54456,54457,54458,54459,54460,54461,54462,54463,54464,54465,54466,54467,54468,54469,54470,54471,54472,54473,54474,54475,54476,54477,54478,54479,54480,54481,54482,54483,54484,54485,54486,54487,54488,54489,54490,54491,54492,54493,54494,54495,54496,54497,54498,54499,54500,54501,54502,54503,54504,54505,54506,54507,54508,54509,54510,54511,54512,54513,54514,54515,54516,54517,54518,54519,54520,54521,54522,54523,54524,54525,54526,54527,54528,54529,54530,54531,54532,54533,54534,54535,54536,54537,54538,54539,54540,54541,54542,54543,54544,54545,54546,54547,54548,54549,54550,54551,54552,54553,54554,54555,54556,54557,54558,54559,54560,54561,54562,54563,54564,54565,54566,54567,54568,54569,54570,54571,54572,54573,54574,54575,54576,54577,54578,54579,54580,54581,54582,54583,54584,54585,54586,54587,54588,54589,54590,54591,54592,54593,54594,54595,54596,54597,54598,54599,54600,54601,54602,54603,54604,54605,54606,54607,54608,54609,54610,54611,54612,54613,54614,54615,54616,54617,54618,54619,54620,54621,54622,54623,54624,54625,54626,54627,54628,54629,54630,54631,54632,54633,54634,54635,54636,54637,54638,54639,54640,54641,54642,54643,54644,54645,54646,54647,54648,54649,54650,54651,54652,54653,54654,54655,54656,54657,54658,54659,54660,54661,54662,54663,54664,54665,54666,54667,54668,54669,54670,54671,54672,54673,54674,54675,54676,54677,54678,54679,54680,54681,54682,54683,54684,54685,54686,54687,54688,54689,54690,54691,54692,54693,54694,54695,54696,54697,54698,54699,54700,54701,54702,54703,54704,54705,54706,54707,54708,54709,54710,54711,54712,54713,54714,54715,54716,54717,54718,54719,54720,54721,54722,54723,54724,54725,54726,54727,54728,54729,54730,54731,54732,54733,54734,54735,54736,54737,54738,54739,54740,54741,54742,54743,54744,54745,54746,54747,54748,54749,54750,54751,54752,54753,54754,54755,54756,54757,54758,54759,54760,54761,54762,54763,54764,54765,54766,54767,54768,54769,54770,54771,54772,54773,54774,54775,54776,54777,54778,54779,54780,54781,54782,54783,54784,54785,54786,54787,54788,54789,54790,54791,54792,54793,54794,54795,54796,54797,54798,54799,54800,54801,54802,54803,54804,54805,54806,54807,54808,54809,54810,54811,54812,54813,54814,54815,54816,54817,54818,54819,54820,54821,54822,54823,54824,54825,54826,54827,54828,54829,54830,54831,54832,54833,54834,54835,54836,54837,54838,54839,54840,54841,54842,54843,54844,54845,54846,54847,54848,54849,54850,54851,54852,54853,54854,54855,54856,54857,54858,54859,54860,54861,54862,54863,54864,54865,54866,54867,54868,54869,54870,54871,54872,54873,54874,54875,54876,54877,54878,54879,54880,54881,54882,54883,54884,54885,54886,54887,54888,54889,54890,54891,54892,54893,54894,54895,54896,54897,54898,54899,54900,54901,54902,54903,54904,54905,54906,54907,54908,54909,54910,54911,54912,54913,54914,54915,54916,54917,54918,54919,54920,54921,54922,54923,54924,54925,54926,54927,54928,54929,54930,54931,54932,54933,54934,54935,54936,54937,54938,54939,54940,54941,54942,54943,54944,54945,54946,54947,54948,54949,54950,54951,54952,54953,54954,54955,54956,54957,54958,54959,54960,54961,54962,54963,54964,54965,54966,54967,54968,54969,54970,54971,54972,54973,54974,54975,54976,54977,54978,54979,54980,54981,54982,54983,54984,54985,54986,54987,54988,54989,54990,54991,54992,54993,54994,54995,54996,54997,54998,54999,55000,55001,55002,55003,55004,55005,55006,55007,55008,55009,55010,55011,55012,55013,55014,55015,55016,55017,55018,55019,55020,55021,55022,55023,55024,55025,55026,55027,55028,55029,55030,55031,55032,55033,55034,55035,55036,55037,55038,55039,55040,55041,55042,55043,55044,55045,55046,55047,55048,55049,55050,55051,55052,55053,55054,55055,55056,55057,55058,55059,55060,55061,55062,55063,55064,55065,55066,55067,55068,55069,55070,55071,55072,55073,55074,55075,55076,55077,55078,55079,55080,55081,55082,55083,55084,55085,55086,55087,55088,55089,55090,55091,55092,55093,55094,55095,55096,55097,55098,55099,55100,55101,55102,55103,55104,55105,55106,55107,55108,55109,55110,55111,55112,55113,55114,55115,55116,55117,55118,55119,55120,55121,55122,55123,55124,55125,55126,55127,55128,55129,55130,55131,55132,55133,55134,55135,55136,55137,55138,55139,55140,55141,55142,55143,55144,55145,55146,55147,55148,55149,55150,55151,55152,55153,55154,55155,55156,55157,55158,55159,55160,55161,55162,55163,55164,55165,55166,55167,55168,55169,55170,55171,55172,55173,55174,55175,55176,55177,55178,55179,55180,55181,55182,55183,55184,55185,55186,55187,55188,55189,55190,55191,55192,55193,55194,55195,55196,55197,55198,55199,55200,55201,55202,55203,55216,55217,55218,55219,55220,55221,55222,55223,55224,55225,55226,55227,55228,55229,55230,55231,55232,55233,55234,55235,55236,55237,55238,55243,55244,55245,55246,55247,55248,55249,55250,55251,55252,55253,55254,55255,55256,55257,55258,55259,55260,55261,55262,55263,55264,55265,55266,55267,55268,55269,55270,55271,55272,55273,55274,55275,55276,55277,55278,55279,55280,55281,55282,55283,55284,55285,55286,55287,55288,55289,55290,55291,63744,63745,63746,63747,63748,63749,63750,63751,63752,63753,63754,63755,63756,63757,63758,63759,63760,63761,63762,63763,63764,63765,63766,63767,63768,63769,63770,63771,63772,63773,63774,63775,63776,63777,63778,63779,63780,63781,63782,63783,63784,63785,63786,63787,63788,63789,63790,63791,63792,63793,63794,63795,63796,63797,63798,63799,63800,63801,63802,63803,63804,63805,63806,63807,63808,63809,63810,63811,63812,63813,63814,63815,63816,63817,63818,63819,63820,63821,63822,63823,63824,63825,63826,63827,63828,63829,63830,63831,63832,63833,63834,63835,63836,63837,63838,63839,63840,63841,63842,63843,63844,63845,63846,63847,63848,63849,63850,63851,63852,63853,63854,63855,63856,63857,63858,63859,63860,63861,63862,63863,63864,63865,63866,63867,63868,63869,63870,63871,63872,63873,63874,63875,63876,63877,63878,63879,63880,63881,63882,63883,63884,63885,63886,63887,63888,63889,63890,63891,63892,63893,63894,63895,63896,63897,63898,63899,63900,63901,63902,63903,63904,63905,63906,63907,63908,63909,63910,63911,63912,63913,63914,63915,63916,63917,63918,63919,63920,63921,63922,63923,63924,63925,63926,63927,63928,63929,63930,63931,63932,63933,63934,63935,63936,63937,63938,63939,63940,63941,63942,63943,63944,63945,63946,63947,63948,63949,63950,63951,63952,63953,63954,63955,63956,63957,63958,63959,63960,63961,63962,63963,63964,63965,63966,63967,63968,63969,63970,63971,63972,63973,63974,63975,63976,63977,63978,63979,63980,63981,63982,63983,63984,63985,63986,63987,63988,63989,63990,63991,63992,63993,63994,63995,63996,63997,63998,63999,64000,64001,64002,64003,64004,64005,64006,64007,64008,64009,64010,64011,64012,64013,64014,64015,64016,64017,64018,64019,64020,64021,64022,64023,64024,64025,64026,64027,64028,64029,64030,64031,64032,64033,64034,64035,64036,64037,64038,64039,64040,64041,64042,64043,64044,64045,64046,64047,64048,64049,64050,64051,64052,64053,64054,64055,64056,64057,64058,64059,64060,64061,64062,64063,64064,64065,64066,64067,64068,64069,64070,64071,64072,64073,64074,64075,64076,64077,64078,64079,64080,64081,64082,64083,64084,64085,64086,64087,64088,64089,64090,64091,64092,64093,64094,64095,64096,64097,64098,64099,64100,64101,64102,64103,64104,64105,64106,64107,64108,64109,64112,64113,64114,64115,64116,64117,64118,64119,64120,64121,64122,64123,64124,64125,64126,64127,64128,64129,64130,64131,64132,64133,64134,64135,64136,64137,64138,64139,64140,64141,64142,64143,64144,64145,64146,64147,64148,64149,64150,64151,64152,64153,64154,64155,64156,64157,64158,64159,64160,64161,64162,64163,64164,64165,64166,64167,64168,64169,64170,64171,64172,64173,64174,64175,64176,64177,64178,64179,64180,64181,64182,64183,64184,64185,64186,64187,64188,64189,64190,64191,64192,64193,64194,64195,64196,64197,64198,64199,64200,64201,64202,64203,64204,64205,64206,64207,64208,64209,64210,64211,64212,64213,64214,64215,64216,64217,64256,64257,64258,64259,64260,64261,64262,64275,64276,64277,64278,64279,64285,64287,64288,64289,64290,64291,64292,64293,64294,64295,64296,64298,64299,64300,64301,64302,64303,64304,64305,64306,64307,64308,64309,64310,64312,64313,64314,64315,64316,64318,64320,64321,64323,64324,64326,64327,64328,64329,64330,64331,64332,64333,64334,64335,64336,64337,64338,64339,64340,64341,64342,64343,64344,64345,64346,64347,64348,64349,64350,64351,64352,64353,64354,64355,64356,64357,64358,64359,64360,64361,64362,64363,64364,64365,64366,64367,64368,64369,64370,64371,64372,64373,64374,64375,64376,64377,64378,64379,64380,64381,64382,64383,64384,64385,64386,64387,64388,64389,64390,64391,64392,64393,64394,64395,64396,64397,64398,64399,64400,64401,64402,64403,64404,64405,64406,64407,64408,64409,64410,64411,64412,64413,64414,64415,64416,64417,64418,64419,64420,64421,64422,64423,64424,64425,64426,64427,64428,64429,64430,64431,64432,64433,64467,64468,64469,64470,64471,64472,64473,64474,64475,64476,64477,64478,64479,64480,64481,64482,64483,64484,64485,64486,64487,64488,64489,64490,64491,64492,64493,64494,64495,64496,64497,64498,64499,64500,64501,64502,64503,64504,64505,64506,64507,64508,64509,64510,64511,64512,64513,64514,64515,64516,64517,64518,64519,64520,64521,64522,64523,64524,64525,64526,64527,64528,64529,64530,64531,64532,64533,64534,64535,64536,64537,64538,64539,64540,64541,64542,64543,64544,64545,64546,64547,64548,64549,64550,64551,64552,64553,64554,64555,64556,64557,64558,64559,64560,64561,64562,64563,64564,64565,64566,64567,64568,64569,64570,64571,64572,64573,64574,64575,64576,64577,64578,64579,64580,64581,64582,64583,64584,64585,64586,64587,64588,64589,64590,64591,64592,64593,64594,64595,64596,64597,64598,64599,64600,64601,64602,64603,64604,64605,64606,64607,64608,64609,64610,64611,64612,64613,64614,64615,64616,64617,64618,64619,64620,64621,64622,64623,64624,64625,64626,64627,64628,64629,64630,64631,64632,64633,64634,64635,64636,64637,64638,64639,64640,64641,64642,64643,64644,64645,64646,64647,64648,64649,64650,64651,64652,64653,64654,64655,64656,64657,64658,64659,64660,64661,64662,64663,64664,64665,64666,64667,64668,64669,64670,64671,64672,64673,64674,64675,64676,64677,64678,64679,64680,64681,64682,64683,64684,64685,64686,64687,64688,64689,64690,64691,64692,64693,64694,64695,64696,64697,64698,64699,64700,64701,64702,64703,64704,64705,64706,64707,64708,64709,64710,64711,64712,64713,64714,64715,64716,64717,64718,64719,64720,64721,64722,64723,64724,64725,64726,64727,64728,64729,64730,64731,64732,64733,64734,64735,64736,64737,64738,64739,64740,64741,64742,64743,64744,64745,64746,64747,64748,64749,64750,64751,64752,64753,64754,64755,64756,64757,64758,64759,64760,64761,64762,64763,64764,64765,64766,64767,64768,64769,64770,64771,64772,64773,64774,64775,64776,64777,64778,64779,64780,64781,64782,64783,64784,64785,64786,64787,64788,64789,64790,64791,64792,64793,64794,64795,64796,64797,64798,64799,64800,64801,64802,64803,64804,64805,64806,64807,64808,64809,64810,64811,64812,64813,64814,64815,64816,64817,64818,64819,64820,64821,64822,64823,64824,64825,64826,64827,64828,64829,64848,64849,64850,64851,64852,64853,64854,64855,64856,64857,64858,64859,64860,64861,64862,64863,64864,64865,64866,64867,64868,64869,64870,64871,64872,64873,64874,64875,64876,64877,64878,64879,64880,64881,64882,64883,64884,64885,64886,64887,64888,64889,64890,64891,64892,64893,64894,64895,64896,64897,64898,64899,64900,64901,64902,64903,64904,64905,64906,64907,64908,64909,64910,64911,64914,64915,64916,64917,64918,64919,64920,64921,64922,64923,64924,64925,64926,64927,64928,64929,64930,64931,64932,64933,64934,64935,64936,64937,64938,64939,64940,64941,64942,64943,64944,64945,64946,64947,64948,64949,64950,64951,64952,64953,64954,64955,64956,64957,64958,64959,64960,64961,64962,64963,64964,64965,64966,64967,65008,65009,65010,65011,65012,65013,65014,65015,65016,65017,65018,65019,65136,65137,65138,65139,65140,65142,65143,65144,65145,65146,65147,65148,65149,65150,65151,65152,65153,65154,65155,65156,65157,65158,65159,65160,65161,65162,65163,65164,65165,65166,65167,65168,65169,65170,65171,65172,65173,65174,65175,65176,65177,65178,65179,65180,65181,65182,65183,65184,65185,65186,65187,65188,65189,65190,65191,65192,65193,65194,65195,65196,65197,65198,65199,65200,65201,65202,65203,65204,65205,65206,65207,65208,65209,65210,65211,65212,65213,65214,65215,65216,65217,65218,65219,65220,65221,65222,65223,65224,65225,65226,65227,65228,65229,65230,65231,65232,65233,65234,65235,65236,65237,65238,65239,65240,65241,65242,65243,65244,65245,65246,65247,65248,65249,65250,65251,65252,65253,65254,65255,65256,65257,65258,65259,65260,65261,65262,65263,65264,65265,65266,65267,65268,65269,65270,65271,65272,65273,65274,65275,65276,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,65382,65383,65384,65385,65386,65387,65388,65389,65390,65391,65392,65393,65394,65395,65396,65397,65398,65399,65400,65401,65402,65403,65404,65405,65406,65407,65408,65409,65410,65411,65412,65413,65414,65415,65416,65417,65418,65419,65420,65421,65422,65423,65424,65425,65426,65427,65428,65429,65430,65431,65432,65433,65434,65435,65436,65437,65438,65439,65440,65441,65442,65443,65444,65445,65446,65447,65448,65449,65450,65451,65452,65453,65454,65455,65456,65457,65458,65459,65460,65461,65462,65463,65464,65465,65466,65467,65468,65469,65470,65474,65475,65476,65477,65478,65479,65482,65483,65484,65485,65486,65487,65490,65491,65492,65493,65494,65495,65498,65499,65500'; +var arr = str.split(',').map(function(code) { + return parseInt(code, 10); +}); +module.exports = arr; +},{}],"/../../jshint/node_modules/console-browserify/index.js":[function(_dereq_,module,exports){ +(function (global){ +/*global window, global*/ +var util = _dereq_("util") +var assert = _dereq_("assert") +var now = _dereq_("date-now") + +var slice = Array.prototype.slice +var console +var times = {} + +if (typeof global !== "undefined" && global.console) { + console = global.console +} else if (typeof window !== "undefined" && window.console) { + console = window.console +} else { + console = {} +} - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } - throw TypeError('Uncaught, unspecified "error" event.'); +var functions = [ + [log, "log"], + [info, "info"], + [warn, "warn"], + [error, "error"], + [time, "time"], + [timeEnd, "timeEnd"], + [trace, "trace"], + [dir, "dir"], + [consoleAssert, "assert"] +] + +for (var i = 0; i < functions.length; i++) { + var tuple = functions[i] + var f = tuple[0] + var name = tuple[1] + + if (!console[name]) { + console[name] = f } - } +} - handler = this._events[type]; +module.exports = console - if (isUndefined(handler)) - return false; +function log() {} - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - handler.apply(this, args); - } - } else if (isObject(handler)) { - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; +function info() { + console.log.apply(console, arguments) +} - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } +function warn() { + console.log.apply(console, arguments) +} - return true; -}; +function error() { + console.warn.apply(console, arguments) +} -EventEmitter.prototype.addListener = function(type, listener) { - var m; +function time(label) { + times[label] = now() +} - if (!isFunction(listener)) - throw TypeError('listener must be a function'); +function timeEnd(label) { + var time = times[label] + if (!time) { + throw new Error("No such label: " + label) + } - if (!this._events) - this._events = {}; + var duration = now() - time + console.log(label + ": " + duration + "ms") +} - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); +function trace() { + var err = new Error() + err.name = "Trace" + err.message = util.format.apply(null, arguments) + console.error(err.stack) +} - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - var m; - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } +function dir(object) { + console.log(util.inspect(object) + "\n") +} - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } +function consoleAssert(expression) { + if (!expression) { + var arr = slice.call(arguments, 1) + assert.ok(false, util.format.apply(null, arr)) } - } - - return this; -}; +} -EventEmitter.prototype.on = EventEmitter.prototype.addListener; +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"assert":"/../node_modules/assert/assert.js","date-now":"/../../jshint/node_modules/date-now/index.js","util":"/../node_modules/util/util.js"}],"/../../jshint/node_modules/date-now/index.js":[function(_dereq_,module,exports){ +module.exports = now -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); +function now() { + return new Date().getTime() +} - var fired = false; +},{}],"/../../jshint/node_modules/lodash.clone/index.js":[function(_dereq_,module,exports){ +(function (global){ +/** + * lodash (Custom Build) + * Build: `lodash modularize exports="npm" -o ./` + * Copyright jQuery Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ - function g() { - this.removeListener(type, g); +/** Used as the size to enable large array optimizations. */ +var LARGE_ARRAY_SIZE = 200; + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; + +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + mapTag = '[object Map]', + numberTag = '[object Number]', + objectTag = '[object Object]', + promiseTag = '[object Promise]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + symbolTag = '[object Symbol]', + weakMapTag = '[object WeakMap]'; + +var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } +/** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ +var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - g.listener = listener; - this.on(type, g); +/** Used to match `RegExp` flags from their coerced string values. */ +var reFlags = /\w*$/; - return this; -}; +/** Used to detect host constructors (Safari). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; +/** Used to detect unsigned integer values. */ +var reIsUint = /^(?:0|[1-9]\d*)$/; - if (!isFunction(listener)) - throw TypeError('listener must be a function'); +/** Used to identify `toStringTag` values supported by `_.clone`. */ +var cloneableTags = {}; +cloneableTags[argsTag] = cloneableTags[arrayTag] = +cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = +cloneableTags[boolTag] = cloneableTags[dateTag] = +cloneableTags[float32Tag] = cloneableTags[float64Tag] = +cloneableTags[int8Tag] = cloneableTags[int16Tag] = +cloneableTags[int32Tag] = cloneableTags[mapTag] = +cloneableTags[numberTag] = cloneableTags[objectTag] = +cloneableTags[regexpTag] = cloneableTags[setTag] = +cloneableTags[stringTag] = cloneableTags[symbolTag] = +cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = +cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; +cloneableTags[errorTag] = cloneableTags[funcTag] = +cloneableTags[weakMapTag] = false; - if (!this._events || !this._events[type]) - return this; +/** Detect free variable `global` from Node.js. */ +var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } +/** Detect free variable `self`. */ +var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - if (position < 0) - return this; +/** Used as a reference to the global object. */ +var root = freeGlobal || freeSelf || Function('return this')(); - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } +/** Detect free variable `exports`. */ +var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } +/** Detect free variable `module`. */ +var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - return this; -}; +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports = freeModule && freeModule.exports === freeExports; -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; +/** + * Adds the key-value `pair` to `map`. + * + * @private + * @param {Object} map The map to modify. + * @param {Array} pair The key-value pair to add. + * @returns {Object} Returns `map`. + */ +function addMapEntry(map, pair) { + // Don't return `map.set` because it's not chainable in IE 11. + map.set(pair[0], pair[1]); + return map; +} - if (!this._events) - return this; +/** + * Adds `value` to `set`. + * + * @private + * @param {Object} set The set to modify. + * @param {*} value The value to add. + * @returns {Object} Returns `set`. + */ +function addSetEntry(set, value) { + // Don't return `set.add` because it's not chainable in IE 11. + set.add(value); + return set; +} - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } +/** + * A specialized version of `_.forEach` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ +function arrayEach(array, iteratee) { + var index = -1, + length = array ? array.length : 0; - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; } + return array; +} - listeners = this._events[type]; +/** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ +function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); + while (++index < length) { + array[offset + index] = values[index]; } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; + return array; +} -EventEmitter.listenerCount = function(emitter, type) { - var ret; - if (!emitter._events || !emitter._events[type]) - ret = 0; - else if (isFunction(emitter._events[type])) - ret = 1; - else - ret = emitter._events[type].length; - return ret; -}; +/** + * A specialized version of `_.reduce` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the first element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ +function arrayReduce(array, iteratee, accumulator, initAccum) { + var index = -1, + length = array ? array.length : 0; -function isFunction(arg) { - return typeof arg === 'function'; + if (initAccum && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; } -function isNumber(arg) { - return typeof arg === 'number'; -} +/** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ +function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); -function isObject(arg) { - return typeof arg === 'object' && arg !== null; + while (++index < n) { + result[index] = iteratee(index); + } + return result; } -function isUndefined(arg) { - return arg === void 0; +/** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function getValue(object, key) { + return object == null ? undefined : object[key]; } -},{}],"/node_modules/jshint/data/ascii-identifier-data.js":[function(_dereq_,module,exports){ -var identifierStartTable = []; - -for (var i = 0; i < 128; i++) { - identifierStartTable[i] = - i === 36 || // $ - i >= 65 && i <= 90 || // A-Z - i === 95 || // _ - i >= 97 && i <= 122; // a-z +/** + * Checks if `value` is a host object in IE < 9. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a host object, else `false`. + */ +function isHostObject(value) { + // Many host objects are `Object` objects that can coerce to strings + // despite having improperly defined `toString` methods. + var result = false; + if (value != null && typeof value.toString != 'function') { + try { + result = !!(value + ''); + } catch (e) {} + } + return result; } -var identifierPartTable = []; +/** + * Converts `map` to its key-value pairs. + * + * @private + * @param {Object} map The map to convert. + * @returns {Array} Returns the key-value pairs. + */ +function mapToArray(map) { + var index = -1, + result = Array(map.size); -for (var i = 0; i < 128; i++) { - identifierPartTable[i] = - identifierStartTable[i] || // $, _, A-Z, a-z - i >= 48 && i <= 57; // 0-9 + map.forEach(function(value, key) { + result[++index] = [key, value]; + }); + return result; } -module.exports = { - asciiIdentifierStartTable: identifierStartTable, - asciiIdentifierPartTable: identifierPartTable -}; - -},{}],"/node_modules/jshint/lodash.js":[function(_dereq_,module,exports){ -(function (global){ -;(function() { - - var undefined; - - var VERSION = '3.7.0'; - - var FUNC_ERROR_TEXT = 'Expected a function'; - - var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - errorTag = '[object Error]', - funcTag = '[object Function]', - mapTag = '[object Map]', - numberTag = '[object Number]', - objectTag = '[object Object]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - weakMapTag = '[object WeakMap]'; - - var arrayBufferTag = '[object ArrayBuffer]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - - var reIsDeepProp = /\.|\[(?:[^[\]]+|(["'])(?:(?!\1)[^\n\\]|\\.)*?)\1\]/, - reIsPlainProp = /^\w*$/, - rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; - - var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g, - reHasRegExpChars = RegExp(reRegExpChars.source); - - var reEscapeChar = /\\(\\)?/g; - - var reFlags = /\w*$/; - - var reIsHostCtor = /^\[object .+?Constructor\]$/; - - var typedArrayTags = {}; - typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = - typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = - typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = - typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = - typedArrayTags[uint32Tag] = true; - typedArrayTags[argsTag] = typedArrayTags[arrayTag] = - typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = - typedArrayTags[dateTag] = typedArrayTags[errorTag] = - typedArrayTags[funcTag] = typedArrayTags[mapTag] = - typedArrayTags[numberTag] = typedArrayTags[objectTag] = - typedArrayTags[regexpTag] = typedArrayTags[setTag] = - typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; - - var cloneableTags = {}; - cloneableTags[argsTag] = cloneableTags[arrayTag] = - cloneableTags[arrayBufferTag] = cloneableTags[boolTag] = - cloneableTags[dateTag] = cloneableTags[float32Tag] = - cloneableTags[float64Tag] = cloneableTags[int8Tag] = - cloneableTags[int16Tag] = cloneableTags[int32Tag] = - cloneableTags[numberTag] = cloneableTags[objectTag] = - cloneableTags[regexpTag] = cloneableTags[stringTag] = - cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = - cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; - cloneableTags[errorTag] = cloneableTags[funcTag] = - cloneableTags[mapTag] = cloneableTags[setTag] = - cloneableTags[weakMapTag] = false; - - var objectTypes = { - 'function': true, - 'object': true +/** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ +function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); }; +} - var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; +/** + * Converts `set` to an array of its values. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the values. + */ +function setToArray(set) { + var index = -1, + result = Array(set.size); - var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; + set.forEach(function(value) { + result[++index] = value; + }); + return result; +} - var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global; +/** Used for built-in method references. */ +var arrayProto = Array.prototype, + funcProto = Function.prototype, + objectProto = Object.prototype; - var freeSelf = objectTypes[typeof self] && self && self.Object && self; +/** Used to detect overreaching core-js shims. */ +var coreJsData = root['__core-js_shared__']; - var freeWindow = objectTypes[typeof window] && window && window.Object && window; +/** Used to detect methods masquerading as native. */ +var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; +}()); - var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; - var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this; +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; - function baseFindIndex(array, predicate, fromRight) { - var length = array.length, - index = fromRight ? length : -1; +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var objectToString = objectProto.toString; + +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); + +/** Built-in value references. */ +var Buffer = moduleExports ? root.Buffer : undefined, + Symbol = root.Symbol, + Uint8Array = root.Uint8Array, + getPrototype = overArg(Object.getPrototypeOf, Object), + objectCreate = Object.create, + propertyIsEnumerable = objectProto.propertyIsEnumerable, + splice = arrayProto.splice; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeGetSymbols = Object.getOwnPropertySymbols, + nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, + nativeKeys = overArg(Object.keys, Object); + +/* Built-in method references that are verified to be native. */ +var DataView = getNative(root, 'DataView'), + Map = getNative(root, 'Map'), + Promise = getNative(root, 'Promise'), + Set = getNative(root, 'Set'), + WeakMap = getNative(root, 'WeakMap'), + nativeCreate = getNative(Object, 'create'); + +/** Used to detect maps, sets, and weakmaps. */ +var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map), + promiseCtorString = toSource(Promise), + setCtorString = toSource(Set), + weakMapCtorString = toSource(WeakMap); + +/** Used to convert symbols to primitives and strings. */ +var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto ? symbolProto.valueOf : undefined; - while ((fromRight ? index-- : ++index < length)) { - if (predicate(array[index], index, array)) { - return index; - } - } - return -1; +/** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function Hash(entries) { + var index = -1, + length = entries ? entries.length : 0; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); } +} - function baseIndexOf(array, value, fromIndex) { - if (value !== value) { - return indexOfNaN(array, fromIndex); - } - var index = fromIndex - 1, - length = array.length; +/** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ +function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; +} - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; - } +/** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function hashDelete(key) { + return this.has(key) && delete this.__data__[key]; +} - function baseIsFunction(value) { - return typeof value == 'function' || false; +/** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; } + return hasOwnProperty.call(data, key) ? data[key] : undefined; +} - function baseToString(value) { - if (typeof value == 'string') { - return value; - } - return value == null ? '' : (value + ''); - } +/** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function hashHas(key) { + var data = this.__data__; + return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key); +} - function indexOfNaN(array, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 0 : -1); +/** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ +function hashSet(key, value) { + var data = this.__data__; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; +} - while ((fromRight ? index-- : ++index < length)) { - var other = array[index]; - if (other !== other) { - return index; - } - } - return -1; - } +// Add methods to `Hash`. +Hash.prototype.clear = hashClear; +Hash.prototype['delete'] = hashDelete; +Hash.prototype.get = hashGet; +Hash.prototype.has = hashHas; +Hash.prototype.set = hashSet; - function isObjectLike(value) { - return !!value && typeof value == 'object'; +/** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function ListCache(entries) { + var index = -1, + length = entries ? entries.length : 0; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); } +} - var arrayProto = Array.prototype, - objectProto = Object.prototype; +/** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ +function listCacheClear() { + this.__data__ = []; +} - var fnToString = Function.prototype.toString; - - var hasOwnProperty = objectProto.hasOwnProperty; +/** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); - var objToString = objectProto.toString; + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + return true; +} - var reIsNative = RegExp('^' + - escapeRegExp(objToString) - .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' - ); +/** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); - var ArrayBuffer = isNative(ArrayBuffer = root.ArrayBuffer) && ArrayBuffer, - bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice, - floor = Math.floor, - getOwnPropertySymbols = isNative(getOwnPropertySymbols = Object.getOwnPropertySymbols) && getOwnPropertySymbols, - getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, - push = arrayProto.push, - preventExtensions = isNative(Object.preventExtensions = Object.preventExtensions) && preventExtensions, - propertyIsEnumerable = objectProto.propertyIsEnumerable, - Uint8Array = isNative(Uint8Array = root.Uint8Array) && Uint8Array; + return index < 0 ? undefined : data[index][1]; +} - var Float64Array = (function() { - try { - var func = isNative(func = root.Float64Array) && func, - result = new func(new ArrayBuffer(10), 0, 1) && func; - } catch(e) {} - return result; - }()); +/** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; +} - var nativeAssign = (function() { - var object = { '1': 0 }, - func = preventExtensions && isNative(func = Object.assign) && func; +/** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ +function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); - try { func(preventExtensions(object), 'xo'); } catch(e) {} - return !object[1] && func; - }()); + if (index < 0) { + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; +} - var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray, - nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys, - nativeMax = Math.max, - nativeMin = Math.min; +// Add methods to `ListCache`. +ListCache.prototype.clear = listCacheClear; +ListCache.prototype['delete'] = listCacheDelete; +ListCache.prototype.get = listCacheGet; +ListCache.prototype.has = listCacheHas; +ListCache.prototype.set = listCacheSet; - var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY; +/** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function MapCache(entries) { + var index = -1, + length = entries ? entries.length : 0; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} - var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1, - MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, - HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; +/** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ +function mapCacheClear() { + this.__data__ = { + 'hash': new Hash, + 'map': new (Map || ListCache), + 'string': new Hash + }; +} - var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0; +/** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function mapCacheDelete(key) { + return getMapData(this, key)['delete'](key); +} - var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1; +/** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function mapCacheGet(key) { + return getMapData(this, key).get(key); +} - function lodash() { - } +/** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function mapCacheHas(key) { + return getMapData(this, key).has(key); +} - var support = lodash.support = {}; +/** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ +function mapCacheSet(key, value) { + getMapData(this, key).set(key, value); + return this; +} - (function(x) { - var Ctor = function() { this.x = x; }, - object = { '0': x, 'length': x }, - props = []; +// Add methods to `MapCache`. +MapCache.prototype.clear = mapCacheClear; +MapCache.prototype['delete'] = mapCacheDelete; +MapCache.prototype.get = mapCacheGet; +MapCache.prototype.has = mapCacheHas; +MapCache.prototype.set = mapCacheSet; - Ctor.prototype = { 'valueOf': x, 'y': x }; - for (var key in new Ctor) { props.push(key); } +/** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function Stack(entries) { + this.__data__ = new ListCache(entries); +} - support.funcDecomp = /\bthis\b/.test(function() { return this; }); +/** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ +function stackClear() { + this.__data__ = new ListCache; +} - support.funcNames = typeof Function.name == 'string'; +/** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function stackDelete(key) { + return this.__data__['delete'](key); +} - try { - support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1); - } catch(e) { - support.nonEnumArgs = true; - } - }(1, 0)); +/** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function stackGet(key) { + return this.__data__.get(key); +} - function arrayCopy(source, array) { - var index = -1, - length = source.length; +/** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function stackHas(key) { + return this.__data__.has(key); +} - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; +/** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ +function stackSet(key, value) { + var cache = this.__data__; + if (cache instanceof ListCache) { + var pairs = cache.__data__; + if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + return this; } - return array; + cache = this.__data__ = new MapCache(pairs); } + cache.set(key, value); + return this; +} - function arrayEach(array, iteratee) { - var index = -1, - length = array.length; +// Add methods to `Stack`. +Stack.prototype.clear = stackClear; +Stack.prototype['delete'] = stackDelete; +Stack.prototype.get = stackGet; +Stack.prototype.has = stackHas; +Stack.prototype.set = stackSet; - while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; - } - } - return array; - } +/** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ +function arrayLikeKeys(value, inherited) { + // Safari 8.1 makes `arguments.callee` enumerable in strict mode. + // Safari 9 makes `arguments.length` enumerable in strict mode. + var result = (isArray(value) || isArguments(value)) + ? baseTimes(value.length, String) + : []; - function arrayFilter(array, predicate) { - var index = -1, - length = array.length, - resIndex = -1, - result = []; + var length = result.length, + skipIndexes = !!length; - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result[++resIndex] = value; - } + for (var key in value) { + if ((inherited || hasOwnProperty.call(value, key)) && + !(skipIndexes && (key == 'length' || isIndex(key, length)))) { + result.push(key); } - return result; } + return result; +} - function arrayMap(array, iteratee) { - var index = -1, - length = array.length, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; +/** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + object[key] = value; } +} - function arrayMax(array) { - var index = -1, - length = array.length, - result = NEGATIVE_INFINITY; - - while (++index < length) { - var value = array[index]; - if (value > result) { - result = value; - } +/** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; } - return result; } + return -1; +} - function arraySome(array, predicate) { - var index = -1, - length = array.length; +/** + * The base implementation of `_.assign` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ +function baseAssign(object, source) { + return object && copyObject(source, keys(source), object); +} - while (++index < length) { - if (predicate(array[index], index, array)) { - return true; - } - } - return false; +/** + * The base implementation of `_.clone` and `_.cloneDeep` which tracks + * traversed objects. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @param {boolean} [isFull] Specify a clone including symbols. + * @param {Function} [customizer] The function to customize cloning. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The parent object of `value`. + * @param {Object} [stack] Tracks traversed objects and their clone counterparts. + * @returns {*} Returns the cloned value. + */ +function baseClone(value, isDeep, isFull, customizer, key, object, stack) { + var result; + if (customizer) { + result = object ? customizer(value, key, object, stack) : customizer(value); } - - function assignWith(object, source, customizer) { - var props = keys(source); - push.apply(props, getSymbols(source)); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index], - value = object[key], - result = customizer(value, source[key], key, object, source); - - if ((result === result ? (result !== value) : (value === value)) || - (value === undefined && !(key in object))) { - object[key] = result; - } - } - return object; + if (result !== undefined) { + return result; } - - var baseAssign = nativeAssign || function(object, source) { - return source == null - ? object - : baseCopy(source, getSymbols(source), baseCopy(source, keys(source), object)); - }; - - function baseCopy(source, props, object) { - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - object[key] = source[key]; - } - return object; + if (!isObject(value)) { + return value; } - - function baseCallback(func, thisArg, argCount) { - var type = typeof func; - if (type == 'function') { - return thisArg === undefined - ? func - : bindCallback(func, thisArg, argCount); + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return copyArray(value, result); } - if (func == null) { - return identity; - } - if (type == 'object') { - return baseMatches(func); - } - return thisArg === undefined - ? property(func) - : baseMatchesProperty(func, thisArg); - } + } else { + var tag = getTag(value), + isFunc = tag == funcTag || tag == genTag; - function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { - var result; - if (customizer) { - result = object ? customizer(value, key, object) : customizer(value); - } - if (result !== undefined) { - return result; - } - if (!isObject(value)) { - return value; + if (isBuffer(value)) { + return cloneBuffer(value, isDeep); } - var isArr = isArray(value); - if (isArr) { - result = initCloneArray(value); + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + if (isHostObject(value)) { + return object ? value : {}; + } + result = initCloneObject(isFunc ? {} : value); if (!isDeep) { - return arrayCopy(value, result); + return copySymbols(value, baseAssign(result, value)); } } else { - var tag = objToString.call(value), - isFunc = tag == funcTag; - - if (tag == objectTag || tag == argsTag || (isFunc && !object)) { - result = initCloneObject(isFunc ? {} : value); - if (!isDeep) { - return baseAssign(result, value); - } - } else { - return cloneableTags[tag] - ? initCloneByTag(value, tag, isDeep) - : (object ? value : {}); - } - } - stackA || (stackA = []); - stackB || (stackB = []); - - var length = stackA.length; - while (length--) { - if (stackA[length] == value) { - return stackB[length]; + if (!cloneableTags[tag]) { + return object ? value : {}; } + result = initCloneByTag(value, tag, baseClone, isDeep); } - stackA.push(value); - stackB.push(result); + } + // Check for circular references and return its corresponding clone. + stack || (stack = new Stack); + var stacked = stack.get(value); + if (stacked) { + return stacked; + } + stack.set(value, result); - (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) { - result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); - }); - return result; + if (!isArr) { + var props = isFull ? getAllKeys(value) : keys(value); } + arrayEach(props || value, function(subValue, key) { + if (props) { + key = subValue; + subValue = value[key]; + } + // Recursively populate clone (susceptible to call stack limits). + assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack)); + }); + return result; +} - var baseEach = createBaseEach(baseForOwn); +/** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} prototype The object to inherit from. + * @returns {Object} Returns the new object. + */ +function baseCreate(proto) { + return isObject(proto) ? objectCreate(proto) : {}; +} - function baseFilter(collection, predicate) { - var result = []; - baseEach(collection, function(value, index, collection) { - if (predicate(value, index, collection)) { - result.push(value); - } - }); - return result; - } +/** + * The base implementation of `getAllKeys` and `getAllKeysIn` which uses + * `keysFunc` and `symbolsFunc` to get the enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Function} keysFunc The function to get the keys of `object`. + * @param {Function} symbolsFunc The function to get the symbols of `object`. + * @returns {Array} Returns the array of property names and symbols. + */ +function baseGetAllKeys(object, keysFunc, symbolsFunc) { + var result = keysFunc(object); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); +} - var baseFor = createBaseFor(); +/** + * The base implementation of `getTag`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag(value) { + return objectToString.call(value); +} - function baseForIn(object, iteratee) { - return baseFor(object, iteratee, keysIn); +/** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ +function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; } + var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); +} - function baseForOwn(object, iteratee) { - return baseFor(object, iteratee, keys); +/** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); } - - function baseGet(object, path, pathKey) { - if (object == null) { - return; - } - if (pathKey !== undefined && pathKey in toObject(object)) { - path = [pathKey]; + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty.call(object, key) && key != 'constructor') { + result.push(key); } - var index = -1, - length = path.length; - - while (object != null && ++index < length) { - var result = object = object[path[index]]; - } - return result; } + return result; +} - function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) { - if (value === other) { - return value !== 0 || (1 / value == 1 / other); - } - var valType = typeof value, - othType = typeof other; - - if ((valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object') || - value == null || other == null) { - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB); +/** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ +function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); } + var result = new buffer.constructor(buffer.length); + buffer.copy(result); + return result; +} - function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) { - var objIsArr = isArray(object), - othIsArr = isArray(other), - objTag = arrayTag, - othTag = arrayTag; +/** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ +function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; +} - if (!objIsArr) { - objTag = objToString.call(object); - if (objTag == argsTag) { - objTag = objectTag; - } else if (objTag != objectTag) { - objIsArr = isTypedArray(object); - } - } - if (!othIsArr) { - othTag = objToString.call(other); - if (othTag == argsTag) { - othTag = objectTag; - } else if (othTag != objectTag) { - othIsArr = isTypedArray(other); - } - } - var objIsObj = objTag == objectTag, - othIsObj = othTag == objectTag, - isSameTag = objTag == othTag; +/** + * Creates a clone of `dataView`. + * + * @private + * @param {Object} dataView The data view to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned data view. + */ +function cloneDataView(dataView, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; + return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); +} - if (isSameTag && !(objIsArr || objIsObj)) { - return equalByTag(object, other, objTag); - } - if (!isLoose) { - var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), - othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); +/** + * Creates a clone of `map`. + * + * @private + * @param {Object} map The map to clone. + * @param {Function} cloneFunc The function to clone values. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned map. + */ +function cloneMap(map, isDeep, cloneFunc) { + var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map); + return arrayReduce(array, addMapEntry, new map.constructor); +} - if (valWrapped || othWrapped) { - return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isLoose, stackA, stackB); - } - } - if (!isSameTag) { - return false; - } - stackA || (stackA = []); - stackB || (stackB = []); +/** + * Creates a clone of `regexp`. + * + * @private + * @param {Object} regexp The regexp to clone. + * @returns {Object} Returns the cloned regexp. + */ +function cloneRegExp(regexp) { + var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); + result.lastIndex = regexp.lastIndex; + return result; +} - var length = stackA.length; - while (length--) { - if (stackA[length] == object) { - return stackB[length] == other; - } - } - stackA.push(object); - stackB.push(other); +/** + * Creates a clone of `set`. + * + * @private + * @param {Object} set The set to clone. + * @param {Function} cloneFunc The function to clone values. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned set. + */ +function cloneSet(set, isDeep, cloneFunc) { + var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set); + return arrayReduce(array, addSetEntry, new set.constructor); +} - var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB); +/** + * Creates a clone of the `symbol` object. + * + * @private + * @param {Object} symbol The symbol object to clone. + * @returns {Object} Returns the cloned symbol object. + */ +function cloneSymbol(symbol) { + return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; +} - stackA.pop(); - stackB.pop(); +/** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ +function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); +} - return result; +/** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ +function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; } + return array; +} - function baseIsMatch(object, props, values, strictCompareFlags, customizer) { - var index = -1, - length = props.length, - noCustomizer = !customizer; +/** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ +function copyObject(source, props, object, customizer) { + object || (object = {}); - while (++index < length) { - if ((noCustomizer && strictCompareFlags[index]) - ? values[index] !== object[props[index]] - : !(props[index] in object) - ) { - return false; - } - } - index = -1; - while (++index < length) { - var key = props[index], - objValue = object[key], - srcValue = values[index]; + var index = -1, + length = props.length; - if (noCustomizer && strictCompareFlags[index]) { - var result = objValue !== undefined || (key in object); - } else { - result = customizer ? customizer(objValue, srcValue, key) : undefined; - if (result === undefined) { - result = baseIsEqual(srcValue, objValue, customizer, true); - } - } - if (!result) { - return false; - } - } - return true; - } - - function baseMatches(source) { - var props = keys(source), - length = props.length; + while (++index < length) { + var key = props[index]; - if (!length) { - return constant(true); - } - if (length == 1) { - var key = props[0], - value = source[key]; - - if (isStrictComparable(value)) { - return function(object) { - if (object == null) { - return false; - } - return object[key] === value && (value !== undefined || (key in toObject(object))); - }; - } - } - var values = Array(length), - strictCompareFlags = Array(length); + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; - while (length--) { - value = source[props[length]]; - values[length] = value; - strictCompareFlags[length] = isStrictComparable(value); - } - return function(object) { - return object != null && baseIsMatch(toObject(object), props, values, strictCompareFlags); - }; + assignValue(object, key, newValue === undefined ? source[key] : newValue); } + return object; +} - function baseMatchesProperty(path, value) { - var isArr = isArray(path), - isCommon = isKey(path) && isStrictComparable(value), - pathKey = (path + ''); - - path = toPath(path); - return function(object) { - if (object == null) { - return false; - } - var key = pathKey; - object = toObject(object); - if ((isArr || !isCommon) && !(key in object)) { - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - if (object == null) { - return false; - } - key = last(path); - object = toObject(object); - } - return object[key] === value - ? (value !== undefined || (key in object)) - : baseIsEqual(value, object[key], null, true); - }; - } +/** + * Copies own symbol properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ +function copySymbols(source, object) { + return copyObject(source, getSymbols(source), object); +} - function baseMerge(object, source, customizer, stackA, stackB) { - if (!isObject(object)) { - return object; - } - var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source)); - if (!isSrcArr) { - var props = keys(source); - push.apply(props, getSymbols(source)); - } - arrayEach(props || source, function(srcValue, key) { - if (props) { - key = srcValue; - srcValue = source[key]; - } - if (isObjectLike(srcValue)) { - stackA || (stackA = []); - stackB || (stackB = []); - baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); - } - else { - var value = object[key], - result = customizer ? customizer(value, srcValue, key, object, source) : undefined, - isCommon = result === undefined; +/** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ +function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); +} - if (isCommon) { - result = srcValue; - } - if ((isSrcArr || result !== undefined) && - (isCommon || (result === result ? (result !== value) : (value === value)))) { - object[key] = result; - } - } - }); - return object; - } +/** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ +function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; +} - function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { - var length = stackA.length, - srcValue = source[key]; +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; +} - while (length--) { - if (stackA[length] == srcValue) { - object[key] = stackB[length]; - return; - } - } - var value = object[key], - result = customizer ? customizer(value, srcValue, key, object, source) : undefined, - isCommon = result === undefined; +/** + * Creates an array of the own enumerable symbol properties of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ +var getSymbols = nativeGetSymbols ? overArg(nativeGetSymbols, Object) : stubArray; - if (isCommon) { - result = srcValue; - if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) { - result = isArray(value) - ? value - : (getLength(value) ? arrayCopy(value) : []); - } - else if (isPlainObject(srcValue) || isArguments(srcValue)) { - result = isArguments(value) - ? toPlainObject(value) - : (isPlainObject(value) ? value : {}); - } - else { - isCommon = false; +/** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +var getTag = baseGetTag; + +// Fallback for data views, maps, sets, and weak maps in IE 11, +// for data views in Edge < 14, and promises in Node.js. +if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || + (Map && getTag(new Map) != mapTag) || + (Promise && getTag(Promise.resolve()) != promiseTag) || + (Set && getTag(new Set) != setTag) || + (WeakMap && getTag(new WeakMap) != weakMapTag)) { + getTag = function(value) { + var result = objectToString.call(value), + Ctor = result == objectTag ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : undefined; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: return dataViewTag; + case mapCtorString: return mapTag; + case promiseCtorString: return promiseTag; + case setCtorString: return setTag; + case weakMapCtorString: return weakMapTag; } } - stackA.push(srcValue); - stackB.push(result); - - if (isCommon) { - object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); - } else if (result === result ? (result !== value) : (value === value)) { - object[key] = result; - } - } - - function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; - } - - function basePropertyDeep(path) { - var pathKey = (path + ''); - path = toPath(path); - return function(object) { - return baseGet(object, path, pathKey); - }; - } - - function baseSlice(array, start, end) { - var index = -1, - length = array.length; - - start = start == null ? 0 : (+start || 0); - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = (end === undefined || end > length) ? length : (+end || 0); - if (end < 0) { - end += length; - } - length = start > end ? 0 : ((end - start) >>> 0); - start >>>= 0; - - var result = Array(length); - while (++index < length) { - result[index] = array[index + start]; - } return result; - } - - function baseSome(collection, predicate) { - var result; - - baseEach(collection, function(value, index, collection) { - result = predicate(value, index, collection); - return !result; - }); - return !!result; - } - - function baseValues(object, props) { - var index = -1, - length = props.length, - result = Array(length); + }; +} - while (++index < length) { - result[index] = object[props[index]]; - } - return result; +/** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ +function initCloneArray(array) { + var length = array.length, + result = array.constructor(length); + + // Add properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; } + return result; +} - function binaryIndex(array, value, retHighest) { - var low = 0, - high = array ? array.length : low; - - if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { - while (low < high) { - var mid = (low + high) >>> 1, - computed = array[mid]; +/** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ +function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; +} - if (retHighest ? (computed <= value) : (computed < value)) { - low = mid + 1; - } else { - high = mid; - } - } - return high; - } - return binaryIndexBy(array, value, identity, retHighest); - } +/** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {Function} cloneFunc The function to clone values. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ +function initCloneByTag(object, tag, cloneFunc, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return cloneArrayBuffer(object); - function binaryIndexBy(array, value, iteratee, retHighest) { - value = iteratee(value); + case boolTag: + case dateTag: + return new Ctor(+object); - var low = 0, - high = array ? array.length : 0, - valIsNaN = value !== value, - valIsUndef = value === undefined; + case dataViewTag: + return cloneDataView(object, isDeep); - while (low < high) { - var mid = floor((low + high) / 2), - computed = iteratee(array[mid]), - isReflexive = computed === computed; - - if (valIsNaN) { - var setLow = isReflexive || retHighest; - } else if (valIsUndef) { - setLow = isReflexive && (retHighest || computed !== undefined); - } else { - setLow = retHighest ? (computed <= value) : (computed < value); - } - if (setLow) { - low = mid + 1; - } else { - high = mid; - } - } - return nativeMin(high, MAX_ARRAY_INDEX); - } + case float32Tag: case float64Tag: + case int8Tag: case int16Tag: case int32Tag: + case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: + return cloneTypedArray(object, isDeep); - function bindCallback(func, thisArg, argCount) { - if (typeof func != 'function') { - return identity; - } - if (thisArg === undefined) { - return func; - } - switch (argCount) { - case 1: return function(value) { - return func.call(thisArg, value); - }; - case 3: return function(value, index, collection) { - return func.call(thisArg, value, index, collection); - }; - case 4: return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - case 5: return function(value, other, key, object, source) { - return func.call(thisArg, value, other, key, object, source); - }; - } - return function() { - return func.apply(thisArg, arguments); - }; - } + case mapTag: + return cloneMap(object, isDeep, cloneFunc); - function bufferClone(buffer) { - return bufferSlice.call(buffer, 0); - } - if (!bufferSlice) { - bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) { - var byteLength = buffer.byteLength, - floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0, - offset = floatLength * FLOAT64_BYTES_PER_ELEMENT, - result = new ArrayBuffer(byteLength); + case numberTag: + case stringTag: + return new Ctor(object); - if (floatLength) { - var view = new Float64Array(result, 0, floatLength); - view.set(new Float64Array(buffer, 0, floatLength)); - } - if (byteLength != offset) { - view = new Uint8Array(result, offset); - view.set(new Uint8Array(buffer, offset)); - } - return result; - }; - } + case regexpTag: + return cloneRegExp(object); - function createAssigner(assigner) { - return restParam(function(object, sources) { - var index = -1, - length = object == null ? 0 : sources.length, - customizer = length > 2 && sources[length - 2], - guard = length > 2 && sources[2], - thisArg = length > 1 && sources[length - 1]; + case setTag: + return cloneSet(object, isDeep, cloneFunc); - if (typeof customizer == 'function') { - customizer = bindCallback(customizer, thisArg, 5); - length -= 2; - } else { - customizer = typeof thisArg == 'function' ? thisArg : null; - length -= (customizer ? 1 : 0); - } - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - customizer = length < 3 ? null : customizer; - length = 1; - } - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, customizer); - } - } - return object; - }); + case symbolTag: + return cloneSymbol(object); } +} - function createBaseEach(eachFunc, fromRight) { - return function(collection, iteratee) { - var length = collection ? getLength(collection) : 0; - if (!isLength(length)) { - return eachFunc(collection, iteratee); - } - var index = fromRight ? length : -1, - iterable = toObject(collection); +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + length = length == null ? MAX_SAFE_INTEGER : length; + return !!length && + (typeof value == 'number' || reIsUint.test(value)) && + (value > -1 && value % 1 == 0 && value < length); +} - while ((fromRight ? index-- : ++index < length)) { - if (iteratee(iterable[index], index, iterable) === false) { - break; - } - } - return collection; - }; - } +/** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ +function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); +} - function createBaseFor(fromRight) { - return function(object, iteratee, keysFunc) { - var iterable = toObject(object), - props = keysFunc(object), - length = props.length, - index = fromRight ? length : -1; +/** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ +function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); +} - while ((fromRight ? index-- : ++index < length)) { - var key = props[index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; - } +/** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ +function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; - function createFindIndex(fromRight) { - return function(array, predicate, thisArg) { - if (!(array && array.length)) { - return -1; - } - predicate = getCallback(predicate, thisArg, 3); - return baseFindIndex(array, predicate, fromRight); - }; - } + return value === proto; +} - function createForEach(arrayFunc, eachFunc) { - return function(collection, iteratee, thisArg) { - return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) - ? arrayFunc(collection, iteratee) - : eachFunc(collection, bindCallback(iteratee, thisArg, 3)); - }; +/** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to process. + * @returns {string} Returns the source code. + */ +function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} } + return ''; +} - function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) { - var index = -1, - arrLength = array.length, - othLength = other.length, - result = true; +/** + * Creates a shallow clone of `value`. + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) + * and supports cloning arrays, array buffers, booleans, date objects, maps, + * numbers, `Object` objects, regexes, sets, strings, symbols, and typed + * arrays. The own enumerable properties of `arguments` objects are cloned + * as plain objects. An empty object is returned for uncloneable values such + * as error objects, functions, DOM nodes, and WeakMaps. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to clone. + * @returns {*} Returns the cloned value. + * @see _.cloneDeep + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var shallow = _.clone(objects); + * console.log(shallow[0] === objects[0]); + * // => true + */ +function clone(value) { + return baseClone(value, false, true); +} - if (arrLength != othLength && !(isLoose && othLength > arrLength)) { - return false; - } - while (result && ++index < arrLength) { - var arrValue = array[index], - othValue = other[index]; - - result = undefined; - if (customizer) { - result = isLoose - ? customizer(othValue, arrValue, index) - : customizer(arrValue, othValue, index); - } - if (result === undefined) { - if (isLoose) { - var othIndex = othLength; - while (othIndex--) { - othValue = other[othIndex]; - result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB); - if (result) { - break; - } - } - } else { - result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB); - } - } - } - return !!result; - } +/** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ +function eq(value, other) { + return value === other || (value !== value && other !== other); +} - function equalByTag(object, other, tag) { - switch (tag) { - case boolTag: - case dateTag: - return +object == +other; +/** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ +function isArguments(value) { + // Safari 8.1 makes `arguments.callee` enumerable in strict mode. + return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && + (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); +} - case errorTag: - return object.name == other.name && object.message == other.message; +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray = Array.isArray; - case numberTag: - return (object != +object) - ? other != +other - : (object == 0 ? ((1 / object) == (1 / other)) : object == +other); +/** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ +function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); +} - case regexpTag: - case stringTag: - return object == (other + ''); - } - return false; - } +/** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ +function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); +} - function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) { - var objProps = keys(object), - objLength = objProps.length, - othProps = keys(other), - othLength = othProps.length; +/** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ +var isBuffer = nativeIsBuffer || stubFalse; - if (objLength != othLength && !isLoose) { - return false; - } - var skipCtor = isLoose, - index = -1; +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 8-9 which returns 'object' for typed array and other constructors. + var tag = isObject(value) ? objectToString.call(value) : ''; + return tag == funcTag || tag == genTag; +} - while (++index < objLength) { - var key = objProps[index], - result = isLoose ? key in other : hasOwnProperty.call(other, key); +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ +function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} - if (result) { - var objValue = object[key], - othValue = other[key]; +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} - result = undefined; - if (customizer) { - result = isLoose - ? customizer(othValue, objValue, key) - : customizer(objValue, othValue, key); - } - if (result === undefined) { - result = (objValue && objValue === othValue) || equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB); - } - } - if (!result) { - return false; - } - skipCtor || (skipCtor = key == 'constructor'); - } - if (!skipCtor) { - var objCtor = object.constructor, - othCtor = other.constructor; +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} - if (objCtor != othCtor && - ('constructor' in object && 'constructor' in other) && - !(typeof objCtor == 'function' && objCtor instanceof objCtor && - typeof othCtor == 'function' && othCtor instanceof othCtor)) { - return false; - } - } - return true; - } +/** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ +function keys(object) { + return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); +} - function getCallback(func, thisArg, argCount) { - var result = lodash.callback || callback; - result = result === callback ? baseCallback : result; - return argCount ? result(func, thisArg, argCount) : result; - } +/** + * This method returns a new empty array. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {Array} Returns the new empty array. + * @example + * + * var arrays = _.times(2, _.stubArray); + * + * console.log(arrays); + * // => [[], []] + * + * console.log(arrays[0] === arrays[1]); + * // => false + */ +function stubArray() { + return []; +} - function getIndexOf(collection, target, fromIndex) { - var result = lodash.indexOf || indexOf; - result = result === indexOf ? baseIndexOf : result; - return collection ? result(collection, target, fromIndex) : result; - } +/** + * This method returns `false`. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {boolean} Returns `false`. + * @example + * + * _.times(2, _.stubFalse); + * // => [false, false] + */ +function stubFalse() { + return false; +} - var getLength = baseProperty('length'); +module.exports = clone; - var getSymbols = !getOwnPropertySymbols ? constant([]) : function(object) { - return getOwnPropertySymbols(toObject(object)); - }; +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],"/../../jshint/node_modules/lodash.slice/index.js":[function(_dereq_,module,exports){ +/** + * lodash (Custom Build) + * Build: `lodash modularize exports="npm" -o ./` + * Copyright jQuery Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ - function initCloneArray(array) { - var length = array.length, - result = new array.constructor(length); +/** Used as references for various `Number` constants. */ +var INFINITY = 1 / 0, + MAX_SAFE_INTEGER = 9007199254740991, + MAX_INTEGER = 1.7976931348623157e+308, + NAN = 0 / 0; - if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { - result.index = array.index; - result.input = array.input; - } - return result; - } +/** `Object#toString` result references. */ +var funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + symbolTag = '[object Symbol]'; - function initCloneObject(object) { - var Ctor = object.constructor; - if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { - Ctor = Object; - } - return new Ctor; - } +/** Used to match leading and trailing whitespace. */ +var reTrim = /^\s+|\s+$/g; - function initCloneByTag(object, tag, isDeep) { - var Ctor = object.constructor; - switch (tag) { - case arrayBufferTag: - return bufferClone(object); +/** Used to detect bad signed hexadecimal string values. */ +var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - case boolTag: - case dateTag: - return new Ctor(+object); +/** Used to detect binary string values. */ +var reIsBinary = /^0b[01]+$/i; - case float32Tag: case float64Tag: - case int8Tag: case int16Tag: case int32Tag: - case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - var buffer = object.buffer; - return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); +/** Used to detect octal string values. */ +var reIsOctal = /^0o[0-7]+$/i; - case numberTag: - case stringTag: - return new Ctor(object); +/** Used to detect unsigned integer values. */ +var reIsUint = /^(?:0|[1-9]\d*)$/; - case regexpTag: - var result = new Ctor(object.source, reFlags.exec(object)); - result.lastIndex = object.lastIndex; - } - return result; +/** Built-in method references without a dependency on `root`. */ +var freeParseInt = parseInt; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var objectToString = objectProto.toString; + +/** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ +function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + if (start < 0) { + start = -start > length ? 0 : (length + start); } + end = end > length ? length : end; + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; - function isIndex(value, length) { - value = +value; - length = length == null ? MAX_SAFE_INTEGER : length; - return value > -1 && value % 1 == 0 && value < length; + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; } + return result; +} - function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number') { - var length = getLength(object), - prereq = isLength(length) && isIndex(index, length); - } else { - prereq = type == 'string' && index in object; - } - if (prereq) { - var other = object[index]; - return value === value ? (value === other) : (other !== other); - } +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + length = length == null ? MAX_SAFE_INTEGER : length; + return !!length && + (typeof value == 'number' || reIsUint.test(value)) && + (value > -1 && value % 1 == 0 && value < length); +} + +/** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ +function isIterateeCall(value, index, object) { + if (!isObject(object)) { return false; } - - function isKey(value, object) { - var type = typeof value; - if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') { - return true; - } - if (isArray(value)) { - return false; - } - var result = !reIsDeepProp.test(value); - return result || (object != null && value in toObject(object)); + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); } + return false; +} - function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +/** + * Creates a slice of `array` from `start` up to, but not including, `end`. + * + * **Note:** This method is used instead of + * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are + * returned. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ +function slice(array, start, end) { + var length = array ? array.length : 0; + if (!length) { + return []; } - - function isStrictComparable(value) { - return value === value && (value === 0 ? ((1 / value) > 0) : !isObject(value)); + if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { + start = 0; + end = length; } + else { + start = start == null ? 0 : toInteger(start); + end = end === undefined ? length : toInteger(end); + } + return baseSlice(array, start, end); +} - function shimIsPlainObject(value) { - var Ctor, - support = lodash.support; +/** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ +function eq(value, other) { + return value === other || (value !== value && other !== other); +} - if (!(isObjectLike(value) && objToString.call(value) == objectTag) || - (!hasOwnProperty.call(value, 'constructor') && - (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { - return false; - } - var result; - baseForIn(value, function(subValue, key) { - result = key; - }); - return result === undefined || hasOwnProperty.call(value, result); - } +/** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ +function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); +} + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 8-9 which returns 'object' for typed array and other constructors. + var tag = isObject(value) ? objectToString.call(value) : ''; + return tag == funcTag || tag == genTag; +} - function shimKeys(object) { - var props = keysIn(object), - propsLength = props.length, - length = propsLength && object.length, - support = lodash.support; +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ +function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} - var allowIndexes = length && isLength(length) && - (isArray(object) || (support.nonEnumArgs && isArguments(object))); +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} - var index = -1, - result = []; +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} - while (++index < propsLength) { - var key = props[index]; - if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { - result.push(key); - } - } - return result; - } +/** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ +function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && objectToString.call(value) == symbolTag); +} - function toObject(value) { - return isObject(value) ? value : Object(value); +/** + * Converts `value` to a finite number. + * + * @static + * @memberOf _ + * @since 4.12.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted number. + * @example + * + * _.toFinite(3.2); + * // => 3.2 + * + * _.toFinite(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toFinite(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toFinite('3.2'); + * // => 3.2 + */ +function toFinite(value) { + if (!value) { + return value === 0 ? value : 0; } - - function toPath(value) { - if (isArray(value)) { - return value; - } - var result = []; - baseToString(value).replace(rePropName, function(match, number, quote, string) { - result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + var sign = (value < 0 ? -1 : 1); + return sign * MAX_INTEGER; } + return value === value ? value : 0; +} - var findLastIndex = createFindIndex(true); +/** + * Converts `value` to an integer. + * + * **Note:** This method is loosely based on + * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger(3.2); + * // => 3 + * + * _.toInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toInteger(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toInteger('3.2'); + * // => 3 + */ +function toInteger(value) { + var result = toFinite(value), + remainder = result % 1; - function indexOf(array, value, fromIndex) { - var length = array ? array.length : 0; - if (!length) { - return -1; - } - if (typeof fromIndex == 'number') { - fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex; - } else if (fromIndex) { - var index = binaryIndex(array, value), - other = array[index]; + return result === result ? (remainder ? result - remainder : result) : 0; +} - if (value === value ? (value === other) : (other !== other)) { - return index; - } - return -1; - } - return baseIndexOf(array, value, fromIndex || 0); +/** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ +function toNumber(value) { + if (typeof value == 'number') { + return value; } - - function last(array) { - var length = array ? array.length : 0; - return length ? array[length - 1] : undefined; + if (isSymbol(value)) { + return NAN; } - - function slice(array, start, end) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { - start = 0; - end = length; - } - return baseSlice(array, start, end); + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); +} - function unzip(array) { - var index = -1, - length = (array && array.length && arrayMax(arrayMap(array, getLength))) >>> 0, - result = Array(length); +module.exports = slice; - while (++index < length) { - result[index] = arrayMap(array, baseProperty(index)); - } - return result; +},{}],"/../../jshint/node_modules/underscore/underscore.js":[function(_dereq_,module,exports){ +(function (global){ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define('underscore', factory) : + (function() { + var current = global._; + var exports = factory(); + global._ = exports; + exports.noConflict = function() { global._ = current; return exports; }; + })(); +}(this, (function () { + + // Underscore.js 1.10.2 + // https://underscorejs.org + // (c) 2009-2020 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + // Underscore may be freely distributed under the MIT license. + + // Baseline setup + // -------------- + + // Establish the root object, `window` (`self`) in the browser, `global` + // on the server, or `this` in some virtual machines. We use `self` + // instead of `window` for `WebWorker` support. + var root = typeof self == 'object' && self.self === self && self || + typeof global == 'object' && global.global === global && global || + Function('return this')() || + {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype; + var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null; + + // Create quick reference variables for speed access to core prototypes. + var push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeCreate = Object.create; + + // Create references to these builtin functions because we override them. + var _isNaN = root.isNaN, + _isFinite = root.isFinite; + + // Naked function reference for surrogate-prototype-swapping. + var Ctor = function(){}; + + // The Underscore object. All exported functions below are added to it in the + // modules/index-all.js using the mixin function. + function _(obj) { + if (obj instanceof _) return obj; + if (!(this instanceof _)) return new _(obj); + this._wrapped = obj; } - var zip = restParam(unzip); - - var forEach = createForEach(arrayEach, baseEach); + // Current version. + var VERSION = _.VERSION = '1.10.2'; - function includes(collection, target, fromIndex, guard) { - var length = collection ? getLength(collection) : 0; - if (!isLength(length)) { - collection = values(collection); - length = collection.length; - } - if (!length) { - return false; - } - if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) { - fromIndex = 0; - } else { - fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0); + // Internal function that returns an efficient (for current engines) version + // of the passed-in callback, to be repeatedly applied in other Underscore + // functions. + function optimizeCb(func, context, argCount) { + if (context === void 0) return func; + switch (argCount == null ? 3 : argCount) { + case 1: return function(value) { + return func.call(context, value); + }; + // The 2-argument case is omitted because we’re not using it. + case 3: return function(value, index, collection) { + return func.call(context, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(context, accumulator, value, index, collection); + }; } - return (typeof collection == 'string' || !isArray(collection) && isString(collection)) - ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1) - : (getIndexOf(collection, target, fromIndex) > -1); + return function() { + return func.apply(context, arguments); + }; } - function reject(collection, predicate, thisArg) { - var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getCallback(predicate, thisArg, 3); - return func(collection, function(value, index, collection) { - return !predicate(value, index, collection); - }); + // An internal function to generate callbacks that can be applied to each + // element in a collection, returning the desired result — either `identity`, + // an arbitrary callback, a property matcher, or a property accessor. + function baseIteratee(value, context, argCount) { + if (value == null) return identity; + if (isFunction(value)) return optimizeCb(value, context, argCount); + if (isObject(value) && !isArray(value)) return matcher(value); + return property(value); } - function some(collection, predicate, thisArg) { - var func = isArray(collection) ? arraySome : baseSome; - if (thisArg && isIterateeCall(collection, predicate, thisArg)) { - predicate = null; - } - if (typeof predicate != 'function' || thisArg !== undefined) { - predicate = getCallback(predicate, thisArg, 3); - } - return func(collection, predicate); + // External wrapper for our callback generator. Users may customize + // `_.iteratee` if they want additional predicate/iteratee shorthand styles. + // This abstraction hides the internal-only argCount argument. + _.iteratee = iteratee; + function iteratee(value, context) { + return baseIteratee(value, context, Infinity); } - function restParam(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - rest = Array(length); + // The function we actually call internally. It invokes _.iteratee if + // overridden, otherwise baseIteratee. + function cb(value, context, argCount) { + if (_.iteratee !== iteratee) return _.iteratee(value, context); + return baseIteratee(value, context, argCount); + } - while (++index < length) { - rest[index] = args[start + index]; + // Some functions take a variable number of arguments, or a few expected + // arguments at the beginning and then a variable number of values to operate + // on. This helper accumulates all remaining arguments past the function’s + // argument length (or an explicit `startIndex`), into an array that becomes + // the last argument. Similar to ES6’s "rest parameter". + function restArguments(func, startIndex) { + startIndex = startIndex == null ? func.length - 1 : +startIndex; + return function() { + var length = Math.max(arguments.length - startIndex, 0), + rest = Array(length), + index = 0; + for (; index < length; index++) { + rest[index] = arguments[index + startIndex]; } - switch (start) { + switch (startIndex) { case 0: return func.call(this, rest); - case 1: return func.call(this, args[0], rest); - case 2: return func.call(this, args[0], args[1], rest); + case 1: return func.call(this, arguments[0], rest); + case 2: return func.call(this, arguments[0], arguments[1], rest); } - var otherArgs = Array(start + 1); - index = -1; - while (++index < start) { - otherArgs[index] = args[index]; + var args = Array(startIndex + 1); + for (index = 0; index < startIndex; index++) { + args[index] = arguments[index]; } - otherArgs[start] = rest; - return func.apply(this, otherArgs); + args[startIndex] = rest; + return func.apply(this, args); }; } - function clone(value, isDeep, customizer, thisArg) { - if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) { - isDeep = false; - } - else if (typeof isDeep == 'function') { - thisArg = customizer; - customizer = isDeep; - isDeep = false; - } - customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1); - return baseClone(value, isDeep, customizer); + // An internal function for creating a new object that inherits from another. + function baseCreate(prototype) { + if (!isObject(prototype)) return {}; + if (nativeCreate) return nativeCreate(prototype); + Ctor.prototype = prototype; + var result = new Ctor; + Ctor.prototype = null; + return result; } - function isArguments(value) { - var length = isObjectLike(value) ? value.length : undefined; - return isLength(length) && objToString.call(value) == argsTag; + function shallowProperty(key) { + return function(obj) { + return obj == null ? void 0 : obj[key]; + }; } - var isArray = nativeIsArray || function(value) { - return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; - }; + function _has(obj, path) { + return obj != null && hasOwnProperty.call(obj, path); + } - function isEmpty(value) { - if (value == null) { - return true; - } - var length = getLength(value); - if (isLength(length) && (isArray(value) || isString(value) || isArguments(value) || - (isObjectLike(value) && isFunction(value.splice)))) { - return !length; + function deepGet(obj, path) { + var length = path.length; + for (var i = 0; i < length; i++) { + if (obj == null) return void 0; + obj = obj[path[i]]; } - return !keys(value).length; + return length ? obj : void 0; } - var isFunction = !(baseIsFunction(/x/) || (Uint8Array && !baseIsFunction(Uint8Array))) ? baseIsFunction : function(value) { - return objToString.call(value) == funcTag; - }; - - function isObject(value) { - var type = typeof value; - return type == 'function' || (!!value && type == 'object'); + // Helper for collection methods to determine whether a collection + // should be iterated as an array or as an object. + // Related: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength + // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 + var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; + var getLength = shallowProperty('length'); + function isArrayLike(collection) { + var length = getLength(collection); + return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; } - function isNative(value) { - if (value == null) { - return false; - } - if (objToString.call(value) == funcTag) { - return reIsNative.test(fnToString.call(value)); + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles raw objects in addition to array-likes. Treats all + // sparse array-likes as if they were dense. + function each(obj, iteratee, context) { + iteratee = optimizeCb(iteratee, context); + var i, length; + if (isArrayLike(obj)) { + for (i = 0, length = obj.length; i < length; i++) { + iteratee(obj[i], i, obj); + } + } else { + var _keys = keys(obj); + for (i = 0, length = _keys.length; i < length; i++) { + iteratee(obj[_keys[i]], _keys[i], obj); + } } - return isObjectLike(value) && reIsHostCtor.test(value); + return obj; } - function isNumber(value) { - return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag); + // Return the results of applying the iteratee to each element. + function map(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length, + results = Array(length); + for (var index = 0; index < length; index++) { + var currentKey = _keys ? _keys[index] : index; + results[index] = iteratee(obj[currentKey], currentKey, obj); + } + return results; } - var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { - if (!(value && objToString.call(value) == objectTag)) { - return false; - } - var valueOf = value.valueOf, - objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); - - return objProto - ? (value == objProto || getPrototypeOf(value) == objProto) - : shimIsPlainObject(value); - }; + // Create a reducing function iterating left or right. + function createReduce(dir) { + // Wrap code that reassigns argument variables in a separate function than + // the one that accesses `arguments.length` to avoid a perf hit. (#1991) + var reducer = function(obj, iteratee, memo, initial) { + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length, + index = dir > 0 ? 0 : length - 1; + if (!initial) { + memo = obj[_keys ? _keys[index] : index]; + index += dir; + } + for (; index >= 0 && index < length; index += dir) { + var currentKey = _keys ? _keys[index] : index; + memo = iteratee(memo, obj[currentKey], currentKey, obj); + } + return memo; + }; - function isString(value) { - return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag); + return function(obj, iteratee, memo, context) { + var initial = arguments.length >= 3; + return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial); + }; } - function isTypedArray(value) { - return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)]; - } + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. + var reduce = createReduce(1); + + // The right-associative version of reduce, also known as `foldr`. + var reduceRight = createReduce(-1); - function toPlainObject(value) { - return baseCopy(value, keysIn(value)); + // Return the first value which passes a truth test. + function find(obj, predicate, context) { + var keyFinder = isArrayLike(obj) ? findIndex : findKey; + var key = keyFinder(obj, predicate, context); + if (key !== void 0 && key !== -1) return obj[key]; } - var assign = createAssigner(function(object, source, customizer) { - return customizer - ? assignWith(object, source, customizer) - : baseAssign(object, source); - }); + // Return all the elements that pass a truth test. + function filter(obj, predicate, context) { + var results = []; + predicate = cb(predicate, context); + each(obj, function(value, index, list) { + if (predicate(value, index, list)) results.push(value); + }); + return results; + } - function has(object, path) { - if (object == null) { - return false; - } - var result = hasOwnProperty.call(object, path); - if (!result && !isKey(path)) { - path = toPath(path); - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - path = last(path); - result = object != null && hasOwnProperty.call(object, path); - } - return result; + // Return all the elements for which a truth test fails. + function reject(obj, predicate, context) { + return filter(obj, negate(cb(predicate)), context); } - var keys = !nativeKeys ? shimKeys : function(object) { - if (object) { - var Ctor = object.constructor, - length = object.length; - } - if ((typeof Ctor == 'function' && Ctor.prototype === object) || - (typeof object != 'function' && isLength(length))) { - return shimKeys(object); + // Determine whether all of the elements match a truth test. + function every(obj, predicate, context) { + predicate = cb(predicate, context); + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = _keys ? _keys[index] : index; + if (!predicate(obj[currentKey], currentKey, obj)) return false; } - return isObject(object) ? nativeKeys(object) : []; - }; + return true; + } - function keysIn(object) { - if (object == null) { - return []; - } - if (!isObject(object)) { - object = Object(object); + // Determine if at least one element in the object matches a truth test. + function some(obj, predicate, context) { + predicate = cb(predicate, context); + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = _keys ? _keys[index] : index; + if (predicate(obj[currentKey], currentKey, obj)) return true; } - var length = object.length; - length = (length && isLength(length) && - (isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0; + return false; + } - var Ctor = object.constructor, - index = -1, - isProto = typeof Ctor == 'function' && Ctor.prototype === object, - result = Array(length), - skipIndexes = length > 0; + // Determine if the array or object contains a given item (using `===`). + function contains(obj, item, fromIndex, guard) { + if (!isArrayLike(obj)) obj = values(obj); + if (typeof fromIndex != 'number' || guard) fromIndex = 0; + return indexOf(obj, item, fromIndex) >= 0; + } - while (++index < length) { - result[index] = (index + ''); - } - for (var key in object) { - if (!(skipIndexes && isIndex(key, length)) && - !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); + // Invoke a method (with arguments) on every item in a collection. + var invoke = restArguments(function(obj, path, args) { + var contextPath, func; + if (isFunction(path)) { + func = path; + } else if (isArray(path)) { + contextPath = path.slice(0, -1); + path = path[path.length - 1]; + } + return map(obj, function(context) { + var method = func; + if (!method) { + if (contextPath && contextPath.length) { + context = deepGet(context, contextPath); + } + if (context == null) return void 0; + method = context[path]; } - } - return result; - } + return method == null ? method : method.apply(context, args); + }); + }); - var merge = createAssigner(baseMerge); + // Convenience version of a common use case of `map`: fetching a property. + function pluck(obj, key) { + return map(obj, property(key)); + } - function values(object) { - return baseValues(object, keys(object)); + // Convenience version of a common use case of `filter`: selecting only objects + // containing specific `key:value` pairs. + function where(obj, attrs) { + return filter(obj, matcher(attrs)); } - function escapeRegExp(string) { - string = baseToString(string); - return (string && reHasRegExpChars.test(string)) - ? string.replace(reRegExpChars, '\\$&') - : string; + // Convenience version of a common use case of `find`: getting the first object + // containing specific `key:value` pairs. + function findWhere(obj, attrs) { + return find(obj, matcher(attrs)); } - function callback(func, thisArg, guard) { - if (guard && isIterateeCall(func, thisArg, guard)) { - thisArg = null; + // Return the maximum element (or element-based computation). + function max(obj, iteratee, context) { + var result = -Infinity, lastComputed = -Infinity, + value, computed; + if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) { + obj = isArrayLike(obj) ? obj : values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value != null && value > result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + each(obj, function(v, index, list) { + computed = iteratee(v, index, list); + if (computed > lastComputed || computed === -Infinity && result === -Infinity) { + result = v; + lastComputed = computed; + } + }); } - return baseCallback(func, thisArg); + return result; } - function constant(value) { - return function() { - return value; - }; + // Return the minimum element (or element-based computation). + function min(obj, iteratee, context) { + var result = Infinity, lastComputed = Infinity, + value, computed; + if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) { + obj = isArrayLike(obj) ? obj : values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value != null && value < result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + each(obj, function(v, index, list) { + computed = iteratee(v, index, list); + if (computed < lastComputed || computed === Infinity && result === Infinity) { + result = v; + lastComputed = computed; + } + }); + } + return result; } - function identity(value) { - return value; + // Shuffle a collection. + function shuffle(obj) { + return sample(obj, Infinity); } - function property(path) { - return isKey(path) ? baseProperty(path) : basePropertyDeep(path); - } - - // Add functions that return wrapped values when chaining. - lodash.assign = assign; - lodash.callback = callback; - lodash.constant = constant; - lodash.forEach = forEach; - lodash.keys = keys; - lodash.keysIn = keysIn; - lodash.merge = merge; - lodash.property = property; - lodash.reject = reject; - lodash.restParam = restParam; - lodash.slice = slice; - lodash.toPlainObject = toPlainObject; - lodash.unzip = unzip; - lodash.values = values; - lodash.zip = zip; - - lodash.each = forEach; - lodash.extend = assign; - lodash.iteratee = callback; - - // Add functions that return unwrapped values when chaining. - lodash.clone = clone; - lodash.escapeRegExp = escapeRegExp; - lodash.findLastIndex = findLastIndex; - lodash.has = has; - lodash.identity = identity; - lodash.includes = includes; - lodash.indexOf = indexOf; - lodash.isArguments = isArguments; - lodash.isArray = isArray; - lodash.isEmpty = isEmpty; - lodash.isFunction = isFunction; - lodash.isNative = isNative; - lodash.isNumber = isNumber; - lodash.isObject = isObject; - lodash.isPlainObject = isPlainObject; - lodash.isString = isString; - lodash.isTypedArray = isTypedArray; - lodash.last = last; - lodash.some = some; - - lodash.any = some; - lodash.contains = includes; - lodash.include = includes; - - lodash.VERSION = VERSION; - - // Some AMD build optimizers like r.js check for condition patterns like the following: - if (freeExports && freeModule) { - if (moduleExports) { - (freeModule.exports = lodash)._ = lodash; - } - else { - freeExports._ = lodash; - } - } - else { - root._ = lodash; + // Sample **n** random values from a collection using the modern version of the + // [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + // If **n** is not specified, returns a single random element. + // The internal `guard` argument allows it to work with `map`. + function sample(obj, n, guard) { + if (n == null || guard) { + if (!isArrayLike(obj)) obj = values(obj); + return obj[random(obj.length - 1)]; + } + var sample = isArrayLike(obj) ? clone(obj) : values(obj); + var length = getLength(sample); + n = Math.max(Math.min(n, length), 0); + var last = length - 1; + for (var index = 0; index < n; index++) { + var rand = random(index, last); + var temp = sample[index]; + sample[index] = sample[rand]; + sample[rand] = temp; + } + return sample.slice(0, n); } -}.call(this)); - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],"/node_modules/jshint/src/jshint.js":[function(_dereq_,module,exports){ -/*! - * JSHint, by JSHint Community. - * - * This file (and this file only) is licensed under the same slightly modified - * MIT license that JSLint is. It stops evil-doers everywhere: - * - * Copyright (c) 2002 Douglas Crockford (www.JSLint.com) - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * The Software shall be used for Good, not Evil. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -/*jshint quotmark:double */ -/*global console:true */ -/*exported console */ - -var _ = _dereq_("../lodash"); -var events = _dereq_("events"); -var vars = _dereq_("./vars.js"); -var messages = _dereq_("./messages.js"); -var Lexer = _dereq_("./lex.js").Lexer; -var reg = _dereq_("./reg.js"); -var state = _dereq_("./state.js").state; -var style = _dereq_("./style.js"); -var options = _dereq_("./options.js"); -var scopeManager = _dereq_("./scope-manager.js"); -// We build the application inside a function so that we produce only a singleton -// variable. That function will be invoked immediately, and its return value is -// the JSHINT function itself. + // Sort the object's values by a criterion produced by an iteratee. + function sortBy(obj, iteratee, context) { + var index = 0; + iteratee = cb(iteratee, context); + return pluck(map(obj, function(value, key, list) { + return { + value: value, + index: index++, + criteria: iteratee(value, key, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index - right.index; + }), 'value'); + } -var JSHINT = (function() { - "use strict"; + // An internal function used for aggregate "group by" operations. + function group(behavior, partition) { + return function(obj, iteratee, context) { + var result = partition ? [[], []] : {}; + iteratee = cb(iteratee, context); + each(obj, function(value, index) { + var key = iteratee(value, index, obj); + behavior(result, value, key); + }); + return result; + }; + } - var api, // Extension API + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + var groupBy = group(function(result, value, key) { + if (_has(result, key)) result[key].push(value); else result[key] = [value]; + }); - // These are operators that should not be used with the ! operator. - bang = { - "<" : true, - "<=" : true, - "==" : true, - "===": true, - "!==": true, - "!=" : true, - ">" : true, - ">=" : true, - "+" : true, - "-" : true, - "*" : true, - "/" : true, - "%" : true - }, + // Indexes the object's values by a criterion, similar to `groupBy`, but for + // when you know that your index values will be unique. + var indexBy = group(function(result, value, key) { + result[key] = value; + }); - declared, // Globals that were declared using /*global ... */ syntax. + // Counts instances of an object that group by a certain criterion. Pass + // either a string attribute to count by, or a function that returns the + // criterion. + var countBy = group(function(result, value, key) { + if (_has(result, key)) result[key]++; else result[key] = 1; + }); - functionicity = [ - "closure", "exception", "global", "label", - "outer", "unused", "var" - ], + var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g; + // Safely create a real, live array from anything iterable. + function toArray(obj) { + if (!obj) return []; + if (isArray(obj)) return slice.call(obj); + if (isString(obj)) { + // Keep surrogate pair characters together + return obj.match(reStrSymbol); + } + if (isArrayLike(obj)) return map(obj, identity); + return values(obj); + } - functions, // All of the functions + // Return the number of elements in an object. + function size(obj) { + if (obj == null) return 0; + return isArrayLike(obj) ? obj.length : keys(obj).length; + } - inblock, - indent, - lookahead, - lex, - member, - membersOnly, - predefined, // Global variables defined by option + // Split a collection into two arrays: one whose elements all satisfy the given + // predicate, and one whose elements all do not satisfy the predicate. + var partition = group(function(result, value, pass) { + result[pass ? 0 : 1].push(value); + }, true); + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. The **guard** check allows it to work with `map`. + function first(array, n, guard) { + if (array == null || array.length < 1) return n == null ? void 0 : []; + if (n == null || guard) return array[0]; + return initial(array, array.length - n); + } - stack, - urls, + // Returns everything but the last entry of the array. Especially useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. + function initial(array, n, guard) { + return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); + } - extraModules = [], - emitter = new events.EventEmitter(); + // Get the last element of an array. Passing **n** will return the last N + // values in the array. + function last(array, n, guard) { + if (array == null || array.length < 1) return n == null ? void 0 : []; + if (n == null || guard) return array[array.length - 1]; + return rest(array, Math.max(0, array.length - n)); + } - function checkOption(name, t) { - name = name.trim(); + // Returns everything but the first entry of the array. Especially useful on + // the arguments object. Passing an **n** will return the rest N values in the + // array. + function rest(array, n, guard) { + return slice.call(array, n == null || guard ? 1 : n); + } - if (/^[+-]W\d{3}$/g.test(name)) { - return true; - } + // Trim out all falsy values from an array. + function compact(array) { + return filter(array, Boolean); + } - if (options.validNames.indexOf(name) === -1) { - if (t.type !== "jslint" && !_.has(options.removed, name)) { - error("E001", t, name); - return false; + // Internal implementation of a recursive `flatten` function. + function _flatten(input, shallow, strict, output) { + output = output || []; + var idx = output.length; + for (var i = 0, length = getLength(input); i < length; i++) { + var value = input[i]; + if (isArrayLike(value) && (isArray(value) || isArguments(value))) { + // Flatten current level of array or arguments object. + if (shallow) { + var j = 0, len = value.length; + while (j < len) output[idx++] = value[j++]; + } else { + _flatten(value, shallow, strict, output); + idx = output.length; + } + } else if (!strict) { + output[idx++] = value; } } - - return true; - } - - function isString(obj) { - return Object.prototype.toString.call(obj) === "[object String]"; + return output; } - function isIdentifier(tkn, value) { - if (!tkn) - return false; - - if (!tkn.identifier || tkn.value !== value) - return false; - - return true; + // Flatten out an array, either recursively (by default), or just one level. + function flatten(array, shallow) { + return _flatten(array, shallow, false); } - function isReserved(token) { - if (!token.reserved) { - return false; - } - var meta = token.meta; - - if (meta && meta.isFutureReservedWord && state.inES5()) { - // ES3 FutureReservedWord in an ES5 environment. - if (!meta.es5) { - return false; - } + // Return a version of the array that does not contain the specified value(s). + var without = restArguments(function(array, otherArrays) { + return difference(array, otherArrays); + }); - // Some ES5 FutureReservedWord identifiers are active only - // within a strict mode environment. - if (meta.strictOnly) { - if (!state.option.strict && !state.isStrict()) { - return false; + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // The faster algorithm will not work with an iteratee if the iteratee + // is not a one-to-one function, so providing an iteratee will disable + // the faster algorithm. + function uniq(array, isSorted, iteratee, context) { + if (!isBoolean(isSorted)) { + context = iteratee; + iteratee = isSorted; + isSorted = false; + } + if (iteratee != null) iteratee = cb(iteratee, context); + var result = []; + var seen = []; + for (var i = 0, length = getLength(array); i < length; i++) { + var value = array[i], + computed = iteratee ? iteratee(value, i, array) : value; + if (isSorted && !iteratee) { + if (!i || seen !== computed) result.push(value); + seen = computed; + } else if (iteratee) { + if (!contains(seen, computed)) { + seen.push(computed); + result.push(value); } + } else if (!contains(result, value)) { + result.push(value); } + } + return result; + } - if (token.isProperty) { - return false; + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + var union = restArguments(function(arrays) { + return uniq(_flatten(arrays, true, true)); + }); + + // Produce an array that contains every item shared between all the + // passed-in arrays. + function intersection(array) { + var result = []; + var argsLength = arguments.length; + for (var i = 0, length = getLength(array); i < length; i++) { + var item = array[i]; + if (contains(result, item)) continue; + var j; + for (j = 1; j < argsLength; j++) { + if (!contains(arguments[j], item)) break; } + if (j === argsLength) result.push(item); } - - return true; + return result; } - function supplant(str, data) { - return str.replace(/\{([^{}]*)\}/g, function(a, b) { - var r = data[b]; - return typeof r === "string" || typeof r === "number" ? r : a; + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + var difference = restArguments(function(array, rest) { + rest = _flatten(rest, true, true); + return filter(array, function(value){ + return !contains(rest, value); }); - } + }); - function combine(dest, src) { - Object.keys(src).forEach(function(name) { - if (_.has(JSHINT.blacklist, name)) return; - dest[name] = src[name]; - }); - } + // Complement of zip. Unzip accepts an array of arrays and groups + // each array's elements on shared indices. + function unzip(array) { + var length = array && max(array, getLength).length || 0; + var result = Array(length); - function processenforceall() { - if (state.option.enforceall) { - for (var enforceopt in options.bool.enforcing) { - if (state.option[enforceopt] === undefined && - !options.noenforceall[enforceopt]) { - state.option[enforceopt] = true; - } - } - for (var relaxopt in options.bool.relaxing) { - if (state.option[relaxopt] === undefined) { - state.option[relaxopt] = false; - } - } + for (var index = 0; index < length; index++) { + result[index] = pluck(array, index); } + return result; } - function assume() { - processenforceall(); - - /** - * TODO: Remove in JSHint 3 - */ - if (!state.option.esversion && !state.option.moz) { - if (state.option.es3) { - state.option.esversion = 3; - } else if (state.option.esnext) { - state.option.esversion = 6; + // Zip together multiple lists into a single array -- elements that share + // an index go together. + var zip = restArguments(unzip); + + // Converts lists into objects. Pass either a single array of `[key, value]` + // pairs, or two parallel arrays of the same length -- one of keys, and one of + // the corresponding values. Passing by pairs is the reverse of pairs. + function object(list, values) { + var result = {}; + for (var i = 0, length = getLength(list); i < length; i++) { + if (values) { + result[list[i]] = values[i]; } else { - state.option.esversion = 5; + result[list[i][0]] = list[i][1]; } } + return result; + } - if (state.inES5()) { - combine(predefined, vars.ecmaIdentifiers[5]); - } + // Generator function to create the findIndex and findLastIndex functions. + function createPredicateIndexFinder(dir) { + return function(array, predicate, context) { + predicate = cb(predicate, context); + var length = getLength(array); + var index = dir > 0 ? 0 : length - 1; + for (; index >= 0 && index < length; index += dir) { + if (predicate(array[index], index, array)) return index; + } + return -1; + }; + } - if (state.inES6()) { - combine(predefined, vars.ecmaIdentifiers[6]); + // Returns the first index on an array-like that passes a predicate test. + var findIndex = createPredicateIndexFinder(1); + var findLastIndex = createPredicateIndexFinder(-1); + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. + function sortedIndex(array, obj, iteratee, context) { + iteratee = cb(iteratee, context, 1); + var value = iteratee(obj); + var low = 0, high = getLength(array); + while (low < high) { + var mid = Math.floor((low + high) / 2); + if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; } + return low; + } - if (state.option.module) { - if (state.option.strict === true) { - state.option.strict = "global"; + // Generator function to create the indexOf and lastIndexOf functions. + function createIndexFinder(dir, predicateFind, sortedIndex) { + return function(array, item, idx) { + var i = 0, length = getLength(array); + if (typeof idx == 'number') { + if (dir > 0) { + i = idx >= 0 ? idx : Math.max(idx + length, i); + } else { + length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; + } + } else if (sortedIndex && idx && length) { + idx = sortedIndex(array, item); + return array[idx] === item ? idx : -1; } - /** - * TODO: Extend this restriction to *all* ES6-specific options. - */ - if (!state.inES6()) { - warning("W134", state.tokens.next, "module", 6); + if (item !== item) { + idx = predicateFind(slice.call(array, i, length), isNaN); + return idx >= 0 ? idx + i : -1; } - } + for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { + if (array[idx] === item) return idx; + } + return -1; + }; + } - if (state.option.couch) { - combine(predefined, vars.couch); + // Return the position of the first occurrence of an item in an array, + // or -1 if the item is not included in the array. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + var indexOf = createIndexFinder(1, findIndex, sortedIndex); + var lastIndexOf = createIndexFinder(-1, findLastIndex); + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](https://docs.python.org/library/functions.html#range). + function range(start, stop, step) { + if (stop == null) { + stop = start || 0; + start = 0; } - - if (state.option.qunit) { - combine(predefined, vars.qunit); + if (!step) { + step = stop < start ? -1 : 1; } - if (state.option.rhino) { - combine(predefined, vars.rhino); + var length = Math.max(Math.ceil((stop - start) / step), 0); + var range = Array(length); + + for (var idx = 0; idx < length; idx++, start += step) { + range[idx] = start; } - if (state.option.shelljs) { - combine(predefined, vars.shelljs); - combine(predefined, vars.node); - } - if (state.option.typed) { - combine(predefined, vars.typed); - } + return range; + } - if (state.option.phantom) { - combine(predefined, vars.phantom); - if (state.option.strict === true) { - state.option.strict = "global"; - } + // Chunk a single array into multiple arrays, each containing `count` or fewer + // items. + function chunk(array, count) { + if (count == null || count < 1) return []; + var result = []; + var i = 0, length = array.length; + while (i < length) { + result.push(slice.call(array, i, i += count)); } + return result; + } - if (state.option.prototypejs) { - combine(predefined, vars.prototypejs); - } + // Function (ahem) Functions + // ------------------ + + // Determines whether to execute a function as a constructor + // or a normal function with the provided arguments. + function executeBound(sourceFunc, boundFunc, context, callingContext, args) { + if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); + var self = baseCreate(sourceFunc.prototype); + var result = sourceFunc.apply(self, args); + if (isObject(result)) return result; + return self; + } - if (state.option.node) { - combine(predefined, vars.node); - combine(predefined, vars.typed); - if (state.option.strict === true) { - state.option.strict = "global"; - } - } + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if + // available. + var bind = restArguments(function(func, context, args) { + if (!isFunction(func)) throw new TypeError('Bind must be called on a function'); + var bound = restArguments(function(callArgs) { + return executeBound(func, bound, context, this, args.concat(callArgs)); + }); + return bound; + }); - if (state.option.devel) { - combine(predefined, vars.devel); - } + // Partially apply a function by creating a version that has had some of its + // arguments pre-filled, without changing its dynamic `this` context. _ acts + // as a placeholder by default, allowing any combination of arguments to be + // pre-filled. Set `partial.placeholder` for a custom placeholder argument. + var partial = restArguments(function(func, boundArgs) { + var placeholder = partial.placeholder; + var bound = function() { + var position = 0, length = boundArgs.length; + var args = Array(length); + for (var i = 0; i < length; i++) { + args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i]; + } + while (position < arguments.length) args.push(arguments[position++]); + return executeBound(func, bound, this, this, args); + }; + return bound; + }); - if (state.option.dojo) { - combine(predefined, vars.dojo); - } + partial.placeholder = _; - if (state.option.browser) { - combine(predefined, vars.browser); - combine(predefined, vars.typed); + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. + var bindAll = restArguments(function(obj, _keys) { + _keys = _flatten(_keys, false, false); + var index = _keys.length; + if (index < 1) throw new Error('bindAll must be passed function names'); + while (index--) { + var key = _keys[index]; + obj[key] = bind(obj[key], obj); } + }); - if (state.option.browserify) { - combine(predefined, vars.browser); - combine(predefined, vars.typed); - combine(predefined, vars.browserify); - if (state.option.strict === true) { - state.option.strict = "global"; + // Memoize an expensive function by storing its results. + function memoize(func, hasher) { + var memoize = function(key) { + var cache = memoize.cache; + var address = '' + (hasher ? hasher.apply(this, arguments) : key); + if (!_has(cache, address)) cache[address] = func.apply(this, arguments); + return cache[address]; + }; + memoize.cache = {}; + return memoize; + } + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + var delay = restArguments(function(func, wait, args) { + return setTimeout(function() { + return func.apply(null, args); + }, wait); + }); + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + var defer = partial(delay, _, 1); + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. Normally, the throttled function will run + // as much as it can, without ever going more than once per `wait` duration; + // but if you'd like to disable the execution on the leading edge, pass + // `{leading: false}`. To disable execution on the trailing edge, ditto. + function throttle(func, wait, options) { + var timeout, context, args, result; + var previous = 0; + if (!options) options = {}; + + var later = function() { + previous = options.leading === false ? 0 : now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + + var throttled = function() { + var _now = now(); + if (!previous && options.leading === false) previous = _now; + var remaining = wait - (_now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + previous = _now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); } - } + return result; + }; - if (state.option.nonstandard) { - combine(predefined, vars.nonstandard); - } + throttled.cancel = function() { + clearTimeout(timeout); + previous = 0; + timeout = context = args = null; + }; - if (state.option.jasmine) { - combine(predefined, vars.jasmine); - } + return throttled; + } - if (state.option.jquery) { - combine(predefined, vars.jquery); - } + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + function debounce(func, wait, immediate) { + var timeout, result; - if (state.option.mootools) { - combine(predefined, vars.mootools); - } + var later = function(context, args) { + timeout = null; + if (args) result = func.apply(context, args); + }; - if (state.option.worker) { - combine(predefined, vars.worker); - } + var debounced = restArguments(function(args) { + if (timeout) clearTimeout(timeout); + if (immediate) { + var callNow = !timeout; + timeout = setTimeout(later, wait); + if (callNow) result = func.apply(this, args); + } else { + timeout = delay(later, wait, this, args); + } - if (state.option.wsh) { - combine(predefined, vars.wsh); - } + return result; + }); - if (state.option.globalstrict && state.option.strict !== false) { - state.option.strict = "global"; - } + debounced.cancel = function() { + clearTimeout(timeout); + timeout = null; + }; - if (state.option.yui) { - combine(predefined, vars.yui); - } + return debounced; + } - if (state.option.mocha) { - combine(predefined, vars.mocha); - } + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + function wrap(func, wrapper) { + return partial(wrapper, func); } - // Produce an error warning. - function quit(code, line, chr) { - var percentage = Math.floor((line / state.lines.length) * 100); - var message = messages.errors[code].desc; + // Returns a negated version of the passed-in predicate. + function negate(predicate) { + return function() { + return !predicate.apply(this, arguments); + }; + } - throw { - name: "JSHintError", - line: line, - character: chr, - message: message + " (" + percentage + "% scanned).", - raw: message, - code: code + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + function compose() { + var args = arguments; + var start = args.length - 1; + return function() { + var i = start; + var result = args[start].apply(this, arguments); + while (i--) result = args[i].call(this, result); + return result; }; } - function removeIgnoredMessages() { - var ignored = state.ignoredLines; + // Returns a function that will only be executed on and after the Nth call. + function after(times, func) { + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + } - if (_.isEmpty(ignored)) return; - JSHINT.errors = _.reject(JSHINT.errors, function(err) { return ignored[err.line] }); + // Returns a function that will only be executed up to (but not including) the Nth call. + function before(times, func) { + var memo; + return function() { + if (--times > 0) { + memo = func.apply(this, arguments); + } + if (times <= 1) func = null; + return memo; + }; } - function warning(code, t, a, b, c, d) { - var ch, l, w, msg; + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + var once = partial(before, 2); - if (/^W\d{3}$/.test(code)) { - if (state.ignored[code]) - return; + // Object Functions + // ---------------- - msg = messages.warnings[code]; - } else if (/E\d{3}/.test(code)) { - msg = messages.errors[code]; - } else if (/I\d{3}/.test(code)) { - msg = messages.info[code]; - } + // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. + var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); + var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', + 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; - t = t || state.tokens.next || {}; - if (t.id === "(end)") { // `~ - t = state.tokens.curr; - } + function collectNonEnumProps(obj, _keys) { + var nonEnumIdx = nonEnumerableProps.length; + var constructor = obj.constructor; + var proto = isFunction(constructor) && constructor.prototype || ObjProto; - l = t.line || 0; - ch = t.from || 0; + // Constructor is a special case. + var prop = 'constructor'; + if (_has(obj, prop) && !contains(_keys, prop)) _keys.push(prop); - w = { - id: "(error)", - raw: msg.desc, - code: msg.code, - evidence: state.lines[l - 1] || "", - line: l, - character: ch, - scope: JSHINT.scope, - a: a, - b: b, - c: c, - d: d - }; + while (nonEnumIdx--) { + prop = nonEnumerableProps[nonEnumIdx]; + if (prop in obj && obj[prop] !== proto[prop] && !contains(_keys, prop)) { + _keys.push(prop); + } + } + } - w.reason = supplant(msg.desc, w); - JSHINT.errors.push(w); + // Retrieve the names of an object's own properties. + // Delegates to **ECMAScript 5**'s native `Object.keys`. + function keys(obj) { + if (!isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); + var _keys = []; + for (var key in obj) if (_has(obj, key)) _keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, _keys); + return _keys; + } - removeIgnoredMessages(); + // Retrieve all the property names of an object. + function allKeys(obj) { + if (!isObject(obj)) return []; + var _keys = []; + for (var key in obj) _keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, _keys); + return _keys; + } - if (JSHINT.errors.length >= state.option.maxerr) - quit("E043", l, ch); + // Retrieve the values of an object's properties. + function values(obj) { + var _keys = keys(obj); + var length = _keys.length; + var values = Array(length); + for (var i = 0; i < length; i++) { + values[i] = obj[_keys[i]]; + } + return values; + } - return w; + // Returns the results of applying the iteratee to each element of the object. + // In contrast to map it returns an object. + function mapObject(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var _keys = keys(obj), + length = _keys.length, + results = {}; + for (var index = 0; index < length; index++) { + var currentKey = _keys[index]; + results[currentKey] = iteratee(obj[currentKey], currentKey, obj); + } + return results; } - function warningAt(m, l, ch, a, b, c, d) { - return warning(m, { - line: l, - from: ch - }, a, b, c, d); + // Convert an object into a list of `[key, value]` pairs. + // The opposite of object. + function pairs(obj) { + var _keys = keys(obj); + var length = _keys.length; + var pairs = Array(length); + for (var i = 0; i < length; i++) { + pairs[i] = [_keys[i], obj[_keys[i]]]; + } + return pairs; } - function error(m, t, a, b, c, d) { - warning(m, t, a, b, c, d); + // Invert the keys and values of an object. The values must be serializable. + function invert(obj) { + var result = {}; + var _keys = keys(obj); + for (var i = 0, length = _keys.length; i < length; i++) { + result[obj[_keys[i]]] = _keys[i]; + } + return result; } - function errorAt(m, l, ch, a, b, c, d) { - return error(m, { - line: l, - from: ch - }, a, b, c, d); + // Return a sorted list of the function names available on the object. + function functions(obj) { + var names = []; + for (var key in obj) { + if (isFunction(obj[key])) names.push(key); + } + return names.sort(); } - // Tracking of "internal" scripts, like eval containing a static string - function addInternalSrc(elem, src) { - var i; - i = { - id: "(internal)", - elem: elem, - value: src + // An internal function for creating assigner functions. + function createAssigner(keysFunc, defaults) { + return function(obj) { + var length = arguments.length; + if (defaults) obj = Object(obj); + if (length < 2 || obj == null) return obj; + for (var index = 1; index < length; index++) { + var source = arguments[index], + _keys = keysFunc(source), + l = _keys.length; + for (var i = 0; i < l; i++) { + var key = _keys[i]; + if (!defaults || obj[key] === void 0) obj[key] = source[key]; + } + } + return obj; }; - JSHINT.internals.push(i); - return i; } - function doOption() { - var nt = state.tokens.next; - var body = nt.body.match(/(-\s+)?[^\s,:]+(?:\s*:\s*(-\s+)?[^\s,]+)?/g) || []; - - var predef = {}; - if (nt.type === "globals") { - body.forEach(function(g, idx) { - g = g.split(":"); - var key = (g[0] || "").trim(); - var val = (g[1] || "").trim(); + // Extend a given object with all the properties in passed-in object(s). + var extend = createAssigner(allKeys); - if (key === "-" || !key.length) { - // Ignore trailing comma - if (idx > 0 && idx === body.length - 1) { - return; - } - error("E002", nt); - return; - } + // Assigns a given object with all the own properties in the passed-in object(s). + // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) + var extendOwn = createAssigner(keys); - if (key.charAt(0) === "-") { - key = key.slice(1); - val = false; + // Returns the first key on an object that passes a predicate test. + function findKey(obj, predicate, context) { + predicate = cb(predicate, context); + var _keys = keys(obj), key; + for (var i = 0, length = _keys.length; i < length; i++) { + key = _keys[i]; + if (predicate(obj[key], key, obj)) return key; + } + } - JSHINT.blacklist[key] = key; - delete predefined[key]; - } else { - predef[key] = (val === "true"); - } - }); + // Internal pick helper function to determine if `obj` has key `key`. + function keyInObj(value, key, obj) { + return key in obj; + } - combine(predefined, predef); + // Return a copy of the object only containing the whitelisted properties. + var pick = restArguments(function(obj, _keys) { + var result = {}, iteratee = _keys[0]; + if (obj == null) return result; + if (isFunction(iteratee)) { + if (_keys.length > 1) iteratee = optimizeCb(iteratee, _keys[1]); + _keys = allKeys(obj); + } else { + iteratee = keyInObj; + _keys = _flatten(_keys, false, false); + obj = Object(obj); + } + for (var i = 0, length = _keys.length; i < length; i++) { + var key = _keys[i]; + var value = obj[key]; + if (iteratee(value, key, obj)) result[key] = value; + } + return result; + }); - for (var key in predef) { - if (_.has(predef, key)) { - declared[key] = nt; - } - } + // Return a copy of the object without the blacklisted properties. + var omit = restArguments(function(obj, _keys) { + var iteratee = _keys[0], context; + if (isFunction(iteratee)) { + iteratee = negate(iteratee); + if (_keys.length > 1) context = _keys[1]; + } else { + _keys = map(_flatten(_keys, false, false), String); + iteratee = function(value, key) { + return !contains(_keys, key); + }; } + return pick(obj, iteratee, context); + }); - if (nt.type === "exported") { - body.forEach(function(e, idx) { - if (!e.length) { - // Ignore trailing comma - if (idx > 0 && idx === body.length - 1) { - return; - } - error("E002", nt); - return; - } + // Fill in a given object with default properties. + var defaults = createAssigner(allKeys, true); - state.funct["(scope)"].addExported(e); - }); + // Creates an object that inherits from the given prototype object. + // If additional properties are provided then they will be added to the + // created object. + function create(prototype, props) { + var result = baseCreate(prototype); + if (props) extendOwn(result, props); + return result; + } + + // Create a (shallow-cloned) duplicate of an object. + function clone(obj) { + if (!isObject(obj)) return obj; + return isArray(obj) ? obj.slice() : extend({}, obj); + } + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + function tap(obj, interceptor) { + interceptor(obj); + return obj; + } + + // Returns whether an object has a given set of `key:value` pairs. + function isMatch(object, attrs) { + var _keys = keys(attrs), length = _keys.length; + if (object == null) return !length; + var obj = Object(object); + for (var i = 0; i < length; i++) { + var key = _keys[i]; + if (attrs[key] !== obj[key] || !(key in obj)) return false; } + return true; + } - if (nt.type === "members") { - membersOnly = membersOnly || {}; - body.forEach(function(m) { - var ch1 = m.charAt(0); - var ch2 = m.charAt(m.length - 1); + // Internal recursive comparison function for `isEqual`. + function eq(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](https://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) return a !== 0 || 1 / a === 1 / b; + // `null` or `undefined` only equal to itself (strict comparison). + if (a == null || b == null) return false; + // `NaN`s are equivalent, but non-reflexive. + if (a !== a) return b !== b; + // Exhaust primitive checks + var type = typeof a; + if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; + return deepEq(a, b, aStack, bStack); + } - if (ch1 === ch2 && (ch1 === "\"" || ch1 === "'")) { - m = m - .substr(1, m.length - 2) - .replace("\\\"", "\""); - } + // Internal recursive comparison function for `isEqual`. + function deepEq(a, b, aStack, bStack) { + // Unwrap any wrapped objects. + if (a instanceof _) a = a._wrapped; + if (b instanceof _) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className !== toString.call(b)) return false; + switch (className) { + // Strings, numbers, regular expressions, dates, and booleans are compared by value. + case '[object RegExp]': + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return '' + a === '' + b; + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. + // Object(NaN) is equivalent to NaN. + if (+a !== +a) return +b !== +b; + // An `egal` comparison is performed for other numeric values. + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a === +b; + case '[object Symbol]': + return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b); + } + + var areArrays = className === '[object Array]'; + if (!areArrays) { + if (typeof a != 'object' || typeof b != 'object') return false; + + // Objects with different constructors are not equivalent, but `Object`s or `Array`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && + isFunction(bCtor) && bCtor instanceof bCtor) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + } + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - membersOnly[m] = false; - }); + // Initializing stack of traversed objects. + // It's done here since we only need them for objects and arrays comparison. + aStack = aStack || []; + bStack = bStack || []; + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] === a) return bStack[length] === b; } - var numvals = [ - "maxstatements", - "maxparams", - "maxdepth", - "maxcomplexity", - "maxerr", - "maxlen", - "indent" - ]; + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); - if (nt.type === "jshint" || nt.type === "jslint") { - body.forEach(function(g) { - g = g.split(":"); - var key = (g[0] || "").trim(); - var val = (g[1] || "").trim(); + // Recursively compare objects and arrays. + if (areArrays) { + // Compare array lengths to determine if a deep comparison is necessary. + length = a.length; + if (length !== b.length) return false; + // Deep compare the contents, ignoring non-numeric properties. + while (length--) { + if (!eq(a[length], b[length], aStack, bStack)) return false; + } + } else { + // Deep compare objects. + var _keys = keys(a), key; + length = _keys.length; + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (keys(b).length !== length) return false; + while (length--) { + // Deep compare each member + key = _keys[length]; + if (!(_has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return true; + } - if (!checkOption(key, nt)) { - return; - } + // Perform a deep comparison to check if two objects are equal. + function isEqual(a, b) { + return eq(a, b); + } - if (numvals.indexOf(key) >= 0) { - // GH988 - numeric options can be disabled by setting them to `false` - if (val !== "false") { - val = +val; + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + function isEmpty(obj) { + if (obj == null) return true; + if (isArrayLike(obj) && (isArray(obj) || isString(obj) || isArguments(obj))) return obj.length === 0; + return keys(obj).length === 0; + } - if (typeof val !== "number" || !isFinite(val) || val <= 0 || Math.floor(val) !== val) { - error("E032", nt, g[1].trim()); - return; - } - - state.option[key] = val; - } else { - state.option[key] = key === "indent" ? 4 : false; - } + // Is a given value a DOM element? + function isElement(obj) { + return !!(obj && obj.nodeType === 1); + } - return; - } + // Internal function for creating a toString-based type tester. + function tagTester(name) { + return function(obj) { + return toString.call(obj) === '[object ' + name + ']'; + }; + } - if (key === "validthis") { - // `validthis` is valid only within a function scope. + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + var isArray = nativeIsArray || tagTester('Array'); - if (state.funct["(global)"]) - return void error("E009"); + // Is a given variable an object? + function isObject(obj) { + var type = typeof obj; + return type === 'function' || type === 'object' && !!obj; + } - if (val !== "true" && val !== "false") - return void error("E002", nt); + // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError, isMap, isWeakMap, isSet, isWeakSet. + var isArguments = tagTester('Arguments'); + var isFunction = tagTester('Function'); + var isString = tagTester('String'); + var isNumber = tagTester('Number'); + var isDate = tagTester('Date'); + var isRegExp = tagTester('RegExp'); + var isError = tagTester('Error'); + var isSymbol = tagTester('Symbol'); + var isMap = tagTester('Map'); + var isWeakMap = tagTester('WeakMap'); + var isSet = tagTester('Set'); + var isWeakSet = tagTester('WeakSet'); + + // Define a fallback version of the method in browsers (ahem, IE < 9), where + // there isn't any inspectable "Arguments" type. + (function() { + if (!isArguments(arguments)) { + isArguments = function(obj) { + return _has(obj, 'callee'); + }; + } + }()); - state.option.validthis = (val === "true"); - return; - } + // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, + // IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236). + var nodelist = root.document && root.document.childNodes; + if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') { + isFunction = function(obj) { + return typeof obj == 'function' || false; + }; + } - if (key === "quotmark") { - switch (val) { - case "true": - case "false": - state.option.quotmark = (val === "true"); - break; - case "double": - case "single": - state.option.quotmark = val; - break; - default: - error("E002", nt); - } - return; - } + // Is a given object a finite number? + function isFinite(obj) { + return !isSymbol(obj) && _isFinite(obj) && !_isNaN(parseFloat(obj)); + } - if (key === "shadow") { - switch (val) { - case "true": - state.option.shadow = true; - break; - case "outer": - state.option.shadow = "outer"; - break; - case "false": - case "inner": - state.option.shadow = "inner"; - break; - default: - error("E002", nt); - } - return; - } + // Is the given value `NaN`? + function isNaN(obj) { + return isNumber(obj) && _isNaN(obj); + } - if (key === "unused") { - switch (val) { - case "true": - state.option.unused = true; - break; - case "false": - state.option.unused = false; - break; - case "vars": - case "strict": - state.option.unused = val; - break; - default: - error("E002", nt); - } - return; - } + // Is a given value a boolean? + function isBoolean(obj) { + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; + } - if (key === "latedef") { - switch (val) { - case "true": - state.option.latedef = true; - break; - case "false": - state.option.latedef = false; - break; - case "nofunc": - state.option.latedef = "nofunc"; - break; - default: - error("E002", nt); - } - return; - } + // Is a given value equal to null? + function isNull(obj) { + return obj === null; + } - if (key === "ignore") { - switch (val) { - case "line": - state.ignoredLines[nt.line] = true; - removeIgnoredMessages(); - break; - default: - error("E002", nt); - } - return; - } + // Is a given variable undefined? + function isUndefined(obj) { + return obj === void 0; + } - if (key === "strict") { - switch (val) { - case "true": - state.option.strict = true; - break; - case "false": - state.option.strict = false; - break; - case "func": - case "global": - case "implied": - state.option.strict = val; - break; - default: - error("E002", nt); - } - return; - } + // Shortcut function for checking if an object has a given property directly + // on itself (in other words, not on a prototype). + function has(obj, path) { + if (!isArray(path)) { + return _has(obj, path); + } + var length = path.length; + for (var i = 0; i < length; i++) { + var key = path[i]; + if (obj == null || !hasOwnProperty.call(obj, key)) { + return false; + } + obj = obj[key]; + } + return !!length; + } - if (key === "module") { - /** - * TODO: Extend this restriction to *all* "environmental" options. - */ - if (!hasParsedCode(state.funct)) { - error("E055", state.tokens.next, "module"); - } - } + // Utility Functions + // ----------------- - /** - * TODO: Remove in JSHint 3 - */ - var esversions = { - es3 : 3, - es5 : 5, - esnext: 6 - }; - if (_.has(esversions, key)) { - switch (val) { - case "true": - state.option.moz = false; - state.option.esversion = esversions[key]; - break; - case "false": - if (!state.option.moz) { - state.option.esversion = 5; - } - break; - default: - error("E002", nt); - } - return; - } + // Keep the identity function around for default iteratees. + function identity(value) { + return value; + } - if (key === "esversion") { - switch (val) { - case "5": - if (state.inES5(true)) { - warning("I003"); - } - /* falls through */ - case "3": - case "6": - state.option.moz = false; - state.option.esversion = +val; - break; - case "2015": - state.option.moz = false; - state.option.esversion = 6; - break; - default: - error("E002", nt); - } - if (!hasParsedCode(state.funct)) { - error("E055", state.tokens.next, "esversion"); - } - return; - } + // Predicate-generating functions. Often useful outside of Underscore. + function constant(value) { + return function() { + return value; + }; + } - var match = /^([+-])(W\d{3})$/g.exec(key); - if (match) { - // ignore for -W..., unignore for +W... - state.ignored[match[2]] = (match[1] === "-"); - return; - } + function noop(){} - var tn; - if (val === "true" || val === "false") { - if (nt.type === "jslint") { - tn = options.renamed[key] || key; - state.option[tn] = (val === "true"); + // Creates a function that, when passed an object, will traverse that object’s + // properties down the given `path`, specified as an array of keys or indexes. + function property(path) { + if (!isArray(path)) { + return shallowProperty(path); + } + return function(obj) { + return deepGet(obj, path); + }; + } - if (options.inverted[tn] !== undefined) { - state.option[tn] = !state.option[tn]; - } - } else { - state.option[key] = (val === "true"); - } + // Generates a function for a given object that returns a given property. + function propertyOf(obj) { + if (obj == null) { + return function(){}; + } + return function(path) { + return !isArray(path) ? obj[path] : deepGet(obj, path); + }; + } - if (key === "newcap") { - state.option["(explicitNewcap)"] = true; - } - return; - } + // Returns a predicate for checking whether an object has a given set of + // `key:value` pairs. + function matcher(attrs) { + attrs = extendOwn({}, attrs); + return function(obj) { + return isMatch(obj, attrs); + }; + } - error("E002", nt); - }); + // Run a function **n** times. + function times(n, iteratee, context) { + var accum = Array(Math.max(0, n)); + iteratee = optimizeCb(iteratee, context, 1); + for (var i = 0; i < n; i++) accum[i] = iteratee(i); + return accum; + } - assume(); + // Return a random integer between min and max (inclusive). + function random(min, max) { + if (max == null) { + max = min; + min = 0; } + return min + Math.floor(Math.random() * (max - min + 1)); } - // We need a peek function. If it has an argument, it peeks that much farther - // ahead. It is used to distinguish - // for ( var i in ... - // from - // for ( var i = ... + // A (possibly faster) way to get the current timestamp as an integer. + var now = Date.now || function() { + return new Date().getTime(); + }; - function peek(p) { - var i = p || 0, j = lookahead.length, t; + // List of HTML entities for escaping. + var escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + var unescapeMap = invert(escapeMap); - if (i < j) { - return lookahead[i]; + // Functions for escaping and unescaping strings to/from HTML interpolation. + function createEscaper(map) { + var escaper = function(match) { + return map[match]; + }; + // Regexes for identifying a key that needs to be escaped. + var source = '(?:' + keys(map).join('|') + ')'; + var testRegexp = RegExp(source); + var replaceRegexp = RegExp(source, 'g'); + return function(string) { + string = string == null ? '' : '' + string; + return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; + }; + } + var escape = createEscaper(escapeMap); + var unescape = createEscaper(unescapeMap); + + // Traverses the children of `obj` along `path`. If a child is a function, it + // is invoked with its parent as context. Returns the value of the final + // child, or `fallback` if any child is undefined. + function result(obj, path, fallback) { + if (!isArray(path)) path = [path]; + var length = path.length; + if (!length) { + return isFunction(fallback) ? fallback.call(obj) : fallback; } - - while (j <= i) { - t = lookahead[j]; - if (!t) { - t = lookahead[j] = lex.token(); + for (var i = 0; i < length; i++) { + var prop = obj == null ? void 0 : obj[path[i]]; + if (prop === void 0) { + prop = fallback; + i = length; // Ensure we don't continue iterating. } - j += 1; - } - - // Peeking past the end of the program should produce the "(end)" token. - if (!t && state.tokens.next.id === "(end)") { - return state.tokens.next; + obj = isFunction(prop) ? prop.call(obj) : prop; } - - return t; + return obj; } - function peekIgnoreEOL() { - var i = 0; - var t; - do { - t = peek(i++); - } while (t.id === "(endline)"); - return t; + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + function uniqueId(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; } - // Produce the next token. It looks for programming errors. + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + var templateSettings = _.templateSettings = { + evaluate: /<%([\s\S]+?)%>/g, + interpolate: /<%=([\s\S]+?)%>/g, + escape: /<%-([\s\S]+?)%>/g + }; - function advance(id, t) { + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; - switch (state.tokens.curr.id) { - case "(number)": - if (state.tokens.next.id === ".") { - warning("W005", state.tokens.curr); - } - break; - case "-": - if (state.tokens.next.id === "-" || state.tokens.next.id === "--") { - warning("W006"); - } - break; - case "+": - if (state.tokens.next.id === "+" || state.tokens.next.id === "++") { - warning("W007"); - } - break; - } + var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g; - if (id && state.tokens.next.id !== id) { - if (t) { - if (state.tokens.next.id === "(end)") { - error("E019", t, t.id); - } else { - error("E020", state.tokens.next, id, t.id, t.line, state.tokens.next.value); - } - } else if (state.tokens.next.type !== "(identifier)" || state.tokens.next.value !== id) { - warning("W116", state.tokens.next, id, state.tokens.next.value); - } - } + var escapeChar = function(match) { + return '\\' + escapes[match]; + }; - state.tokens.prev = state.tokens.curr; - state.tokens.curr = state.tokens.next; - for (;;) { - state.tokens.next = lookahead.shift() || lex.token(); + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + // NB: `oldSettings` only exists for backwards compatibility. + function template(text, settings, oldSettings) { + if (!settings && oldSettings) settings = oldSettings; + settings = defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset).replace(escapeRegExp, escapeChar); + index = offset + match.length; - if (!state.tokens.next) { // No more tokens left, give up - quit("E041", state.tokens.curr.line); + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } else if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } else if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; } - if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") { - return; - } + // Adobe VMs need the match returned to produce the correct offset. + return match; + }); + source += "';\n"; - if (state.tokens.next.check) { - state.tokens.next.check(); - } + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; - if (state.tokens.next.isSpecial) { - if (state.tokens.next.type === "falls through") { - state.tokens.curr.caseFallsThrough = true; - } else { - doOption(); - } - } else { - if (state.tokens.next.id !== "(endline)") { - break; - } - } + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + 'return __p;\n'; + + var render; + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; } + + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled source as a convenience for precompilation. + var argument = settings.variable || 'obj'; + template.source = 'function(' + argument + '){\n' + source + '}'; + + return template; } - function isInfix(token) { - return token.infix || (!token.identifier && !token.template && !!token.led); + // Add a "chain" function. Start chaining a wrapped Underscore object. + function chain(obj) { + var instance = _(obj); + instance._chain = true; + return instance; } - function isEndOfExpr() { - var curr = state.tokens.curr; - var next = state.tokens.next; - if (next.id === ";" || next.id === "}" || next.id === ":") { - return true; - } - if (isInfix(next) === isInfix(curr) || (curr.id === "yield" && state.inMoz())) { - return curr.line !== startLine(next); - } - return false; + // OOP + // --------------- + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + + // Helper function to continue chaining intermediate results. + function chainResult(instance, obj) { + return instance._chain ? _(obj).chain() : obj; } - function isBeginOfExpr(prev) { - return !prev.left && prev.arity !== "unary"; + // Add your own custom functions to the Underscore object. + function mixin(obj) { + each(functions(obj), function(name) { + var func = _[name] = obj[name]; + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return chainResult(this, func.apply(_, args)); + }; + }); + return _; } - // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it - // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is - // like .nud except that it is only used on the first token of a statement. - // Having .fud makes it much easier to define statement-oriented languages like - // JavaScript. I retained Pratt's nomenclature. + // Add all mutator Array functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + method.apply(obj, arguments); + if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; + return chainResult(this, obj); + }; + }); - // .nud Null denotation - // .fud First null denotation - // .led Left denotation - // lbp Left binding power - // rbp Right binding power + // Add all accessor Array functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + return chainResult(this, method.apply(this._wrapped, arguments)); + }; + }); - // They are elements of the parsing method called Top Down Operator Precedence. + // Extracts the result from a wrapped and chained object. + _.prototype.value = function() { + return this._wrapped; + }; - function expression(rbp, initial) { - var left, isArray = false, isObject = false, isLetExpr = false; + // Provide unwrapping proxy for some methods used in engine operations + // such as arithmetic and JSON stringification. + _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; - state.nameStack.push(); + _.prototype.toString = function() { + return String(this._wrapped); + }; - // if current expression is a let expression - if (!initial && state.tokens.next.value === "let" && peek(0).value === "(") { - if (!state.inMoz()) { - warning("W118", state.tokens.next, "let expressions"); - } - isLetExpr = true; - // create a new block scope we use only for the current expression - state.funct["(scope)"].stack(); - advance("let"); - advance("("); - state.tokens.prev.fud(); - advance(")"); - } + var allExports = ({ + 'default': _, + VERSION: VERSION, + iteratee: iteratee, + restArguments: restArguments, + each: each, + forEach: each, + map: map, + collect: map, + reduce: reduce, + foldl: reduce, + inject: reduce, + reduceRight: reduceRight, + foldr: reduceRight, + find: find, + detect: find, + filter: filter, + select: filter, + reject: reject, + every: every, + all: every, + some: some, + any: some, + contains: contains, + includes: contains, + include: contains, + invoke: invoke, + pluck: pluck, + where: where, + findWhere: findWhere, + max: max, + min: min, + shuffle: shuffle, + sample: sample, + sortBy: sortBy, + groupBy: groupBy, + indexBy: indexBy, + countBy: countBy, + toArray: toArray, + size: size, + partition: partition, + first: first, + head: first, + take: first, + initial: initial, + last: last, + rest: rest, + tail: rest, + drop: rest, + compact: compact, + flatten: flatten, + without: without, + uniq: uniq, + unique: uniq, + union: union, + intersection: intersection, + difference: difference, + unzip: unzip, + zip: zip, + object: object, + findIndex: findIndex, + findLastIndex: findLastIndex, + sortedIndex: sortedIndex, + indexOf: indexOf, + lastIndexOf: lastIndexOf, + range: range, + chunk: chunk, + bind: bind, + partial: partial, + bindAll: bindAll, + memoize: memoize, + delay: delay, + defer: defer, + throttle: throttle, + debounce: debounce, + wrap: wrap, + negate: negate, + compose: compose, + after: after, + before: before, + once: once, + keys: keys, + allKeys: allKeys, + values: values, + mapObject: mapObject, + pairs: pairs, + invert: invert, + functions: functions, + methods: functions, + extend: extend, + extendOwn: extendOwn, + assign: extendOwn, + findKey: findKey, + pick: pick, + omit: omit, + defaults: defaults, + create: create, + clone: clone, + tap: tap, + isMatch: isMatch, + isEqual: isEqual, + isEmpty: isEmpty, + isElement: isElement, + isArray: isArray, + isObject: isObject, + isArguments: isArguments, + isFunction: isFunction, + isString: isString, + isNumber: isNumber, + isDate: isDate, + isRegExp: isRegExp, + isError: isError, + isSymbol: isSymbol, + isMap: isMap, + isWeakMap: isWeakMap, + isSet: isSet, + isWeakSet: isWeakSet, + isFinite: isFinite, + isNaN: isNaN, + isBoolean: isBoolean, + isNull: isNull, + isUndefined: isUndefined, + has: has, + identity: identity, + constant: constant, + noop: noop, + property: property, + propertyOf: propertyOf, + matcher: matcher, + matches: matcher, + times: times, + random: random, + now: now, + escape: escape, + unescape: unescape, + result: result, + uniqueId: uniqueId, + templateSettings: templateSettings, + template: template, + chain: chain, + mixin: mixin + }); - if (state.tokens.next.id === "(end)") - error("E006", state.tokens.curr); + // Add all of the Underscore functions to the wrapper object. + var _$1 = mixin(allExports); + // Legacy Node.js API + _$1._ = _$1; - var isDangerous = - state.option.asi && - state.tokens.prev.line !== startLine(state.tokens.curr) && - _.contains(["]", ")"], state.tokens.prev.id) && - _.contains(["[", "("], state.tokens.curr.id); + return _$1; - if (isDangerous) - warning("W014", state.tokens.curr, state.tokens.curr.id); +}))); - advance(); - if (initial) { - state.funct["(verb)"] = state.tokens.curr.value; - state.tokens.curr.beginsStmt = true; - } +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],"/../../jshint/src/jshint.js":[function(_dereq_,module,exports){ +/*! + * JSHint, by JSHint Community. + * + * This file (and this file only) is licensed under the same slightly modified + * MIT license that JSLint is. It stops evil-doers everywhere: + * + * Copyright (c) 2002 Douglas Crockford (www.JSLint.com) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * The Software shall be used for Good, not Evil. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ - if (initial === true && state.tokens.curr.fud) { - left = state.tokens.curr.fud(); - } else { - if (state.tokens.curr.nud) { - left = state.tokens.curr.nud(); - } else { - error("E030", state.tokens.curr, state.tokens.curr.id); - } +/*jshint quotmark:double */ +/*exported console */ - // TODO: use pratt mechanics rather than special casing template tokens - while ((rbp < state.tokens.next.lbp || state.tokens.next.type === "(template)") && - !isEndOfExpr()) { - isArray = state.tokens.curr.value === "Array"; - isObject = state.tokens.curr.value === "Object"; +/* +_.clone +_.includes +_.isEmpty +_.isNumber +_.reject +_.zip +*/ + +var _ = _dereq_("underscore"); +_.clone = _dereq_("lodash.clone"); +var events = _dereq_("events"); +var vars = _dereq_("./vars.js"); +var messages = _dereq_("./messages.js"); +var Lexer = _dereq_("./lex.js").Lexer; +var reg = _dereq_("./reg.js"); +var state = _dereq_("./state.js").state; +var style = _dereq_("./style.js"); +var options = _dereq_("./options.js"); +var scopeManager = _dereq_("./scope-manager.js"); +var prodParams = _dereq_("./prod-params.js"); - // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object() - // Line breaks in IfStatement heads exist to satisfy the checkJSHint - // "Line too long." error. - if (left && (left.value || (left.first && left.first.value))) { - // If the left.value is not "new", or the left.first.value is a "." - // then safely assume that this is not "new Array()" and possibly - // not "new Object()"... - if (left.value !== "new" || - (left.first && left.first.value && left.first.value === ".")) { - isArray = false; - // ...In the case of Object, if the left.value and state.tokens.curr.value - // are not equal, then safely assume that this not "new Object()" - if (left.value !== state.tokens.curr.value) { - isObject = false; - } - } - } +// We need this module here because environments such as IE and Rhino +// don't necessarilly expose the 'console' API and browserify uses +// it to log things. It's a sad state of affair, really. +var console = _dereq_("console-browserify"); - advance(); +// We build the application inside a function so that we produce only a singleton +// variable. That function will be invoked immediately, and its return value is +// the JSHINT function itself. - if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { - warning("W009", state.tokens.curr); - } +var JSHINT = (function() { + "use strict"; - if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { - warning("W010", state.tokens.curr); - } + var api, // Extension API - if (left && state.tokens.curr.led) { - left = state.tokens.curr.led(left); - } else { - error("E033", state.tokens.curr, state.tokens.curr.id); - } - } - } - if (isLetExpr) { - state.funct["(scope)"].unstack(); - } + // These are operators that should not be used with the ! operator. + bang = { + "<" : true, + "<=" : true, + "==" : true, + "===": true, + "!==": true, + "!=" : true, + ">" : true, + ">=" : true, + "+" : true, + "-" : true, + "*" : true, + "/" : true, + "%" : true + }, - state.nameStack.pop(); + declared, // Globals that were declared using /*global ... */ syntax. - return left; - } + functions, // All of the functions + inblock, + indent, + lookahead, + lex, + member, + membersOnly, + predefined, // Global variables defined by option - // Functions for conformance of style. + extraModules = [], + emitter = new events.EventEmitter(); - function startLine(token) { - return token.startLine || token.line; - } + function checkOption(name, isStable, t) { + var type, validNames; - function nobreaknonadjacent(left, right) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - if (!state.option.laxbreak && left.line !== startLine(right)) { - warning("W014", right, right.value); + if (isStable) { + type = ""; + validNames = options.validNames; + } else { + type = "unstable "; + validNames = options.unstableNames; } - } - function nolinebreak(t) { - t = t || state.tokens.curr; - if (t.line !== startLine(state.tokens.next)) { - warning("E022", t, t.value); + name = name.trim(); + + if (/^[+-]W\d{3}$/g.test(name)) { + return true; } - } - function nobreakcomma(left, right) { - if (left.line !== startLine(right)) { - if (!state.option.laxcomma) { - if (comma.first) { - warning("I001"); - comma.first = false; - } - warning("W014", left, right.value); + if (validNames.indexOf(name) === -1) { + if (t.type !== "jslint" && !_.has(options.removed, name)) { + error("E001", t, type, name); + return false; } } + + return true; } - function comma(opts) { - opts = opts || {}; + function isString(obj) { + return Object.prototype.toString.call(obj) === "[object String]"; + } - if (!opts.peek) { - nobreakcomma(state.tokens.curr, state.tokens.next); - advance(","); - } else { - nobreakcomma(state.tokens.prev, state.tokens.curr); - } + function isIdentifier(tkn, value) { + if (!tkn) + return false; - if (state.tokens.next.identifier && !(opts.property && state.inES5())) { - // Keywords that cannot follow a comma operator. - switch (state.tokens.next.value) { - case "break": - case "case": - case "catch": - case "continue": - case "default": - case "do": - case "else": - case "finally": - case "for": - case "if": - case "in": - case "instanceof": - case "return": - case "switch": - case "throw": - case "try": - case "var": - case "let": - case "while": - case "with": - error("E024", state.tokens.next, state.tokens.next.value); - return false; - } + if (!tkn.identifier || tkn.value !== value) + return false; + + return true; + } + + /** + * ES3 defined a set of "FutureReservedWords" in order "to allow for the + * possibility of future adoption of [proposed] extensions." + * + * ES5 reduced the set of FutureReservedWords, in some cases by using them to + * define new syntactic forms (e.g. `class` and `const`) and in other cases + * by simply allowing their use as Identifiers (e.g. `int` and `goto`). + * Separately, ES5 introduced new restrictions on certain tokens, but limited + * the restriction to strict mode code (e.g. `let` and `yield`). + * + * This function determines if a given token describes a reserved word + * according to the current state of the parser. + * + * @param {number} context - the parsing context; see `prod-params.js` for + * more information + * @param {Token} token + */ + function isReserved(context, token) { + if (!token.reserved) { + return false; } + var meta = token.meta; - if (state.tokens.next.type === "(punctuator)") { - switch (state.tokens.next.value) { - case "}": - case "]": - case ",": - if (opts.allowTrailing) { - return true; + if (meta && meta.isFutureReservedWord) { + if (state.inES5()) { + // ES3 FutureReservedWord in an ES5 environment. + if (!meta.es5) { + return false; } - /* falls through */ - case ")": - error("E024", state.tokens.next, state.tokens.next.value); + if (token.isProperty) { + return false; + } + } + } else if (meta && meta.es5 && !state.inES5()) { + return false; + } + + // Some identifiers are reserved only within a strict mode environment. + if (meta && meta.strictOnly && state.inES5()) { + if (!state.option.strict && !state.isStrict()) { return false; } } - return true; - } - // Functional constructors for making the symbols that will be inherited by - // tokens. + if (token.id === "await" && (!(context & prodParams.async) && !state.option.module)) { + return false; + } - function symbol(s, p) { - var x = state.syntax[s]; - if (!x || typeof x !== "object") { - state.syntax[s] = x = { - id: s, - lbp: p, - value: s - }; + if (token.id === "yield" && (!(context & prodParams.yield))) { + return state.isStrict(); } - return x; - } - - function delim(s) { - var x = symbol(s, 0); - x.delim = true; - return x; - } - function stmt(s, f) { - var x = delim(s); - x.identifier = x.reserved = true; - x.fud = f; - return x; + return true; } - function blockstmt(s, f) { - var x = stmt(s, f); - x.block = true; - return x; + function supplant(str, data) { + return str.replace(/\{([^{}]*)\}/g, function(a, b) { + var r = data[b]; + return typeof r === "string" || typeof r === "number" ? r : a; + }); } - function reserveName(x) { - var c = x.id.charAt(0); - if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) { - x.identifier = x.reserved = true; - } - return x; + function combine(dest, src) { + Object.keys(src).forEach(function(name) { + if (_.has(JSHINT.blacklist, name)) return; + dest[name] = src[name]; + }); } - function prefix(s, f) { - var x = symbol(s, 150); - reserveName(x); - - x.nud = (typeof f === "function") ? f : function() { - this.arity = "unary"; - this.right = expression(150); - - if (this.id === "++" || this.id === "--") { - if (state.option.plusplus) { - warning("W016", this, this.id); - } else if (this.right && (!this.right.identifier || isReserved(this.right)) && - this.right.id !== "." && this.right.id !== "[") { - warning("W017", this); + function processenforceall() { + if (state.option.enforceall) { + for (var enforceopt in options.bool.enforcing) { + if (state.option[enforceopt] === undefined && + !options.noenforceall[enforceopt]) { + state.option[enforceopt] = true; } - - if (this.right && this.right.isMetaProperty) { - error("E031", this); - // detect increment/decrement of a const - // in the case of a.b, right will be the "." punctuator - } else if (this.right && this.right.identifier) { - state.funct["(scope)"].block.modify(this.right.value, this); + } + for (var relaxopt in options.bool.relaxing) { + if (state.option[relaxopt] === undefined) { + state.option[relaxopt] = false; } } - - return this; - }; - - return x; + } } - function type(s, f) { - var x = delim(s); - x.type = s; - x.nud = f; - return x; - } + /** + * Apply all linting options according to the status of the `state` object. + */ + function applyOptions() { + var badESOpt = null; + processenforceall(); - function reserve(name, func) { - var x = type(name, func); - x.identifier = true; - x.reserved = true; - return x; - } + /** + * TODO: Remove in JSHint 3 + */ + badESOpt = state.inferEsVersion(); + if (badESOpt) { + quit("E059", state.tokens.next, "esversion", badESOpt); + } - function FutureReservedWord(name, meta) { - var x = type(name, (meta && meta.nud) || function() { - return this; - }); + if (state.inES5()) { + combine(predefined, vars.ecmaIdentifiers[5]); + } - meta = meta || {}; - meta.isFutureReservedWord = true; + if (state.inES6()) { + combine(predefined, vars.ecmaIdentifiers[6]); + } - x.value = name; - x.identifier = true; - x.reserved = true; - x.meta = meta; + if (state.inES8()) { + combine(predefined, vars.ecmaIdentifiers[8]); + } - return x; - } + /** + * Use `in` to check for the presence of any explicitly-specified value for + * `globalstrict` because both `true` and `false` should trigger an error. + */ + if (state.option.strict === "global" && "globalstrict" in state.option) { + quit("E059", state.tokens.next, "strict", "globalstrict"); + } - function reservevar(s, v) { - return reserve(s, function() { - if (typeof v === "function") { - v(this); + if (state.option.module) { + /** + * TODO: Extend this restriction to *all* ES6-specific options. + */ + if (!state.inES6()) { + warning("W134", state.tokens.next, "module", 6); } - return this; - }); - } + } - function infix(s, f, p, w) { - var x = symbol(s, p); - reserveName(x); - x.infix = true; - x.led = function(left) { - if (!w) { - nobreaknonadjacent(state.tokens.prev, state.tokens.curr); - } - if ((s === "in" || s === "instanceof") && left.id === "!") { - warning("W018", left, "!"); - } - if (typeof f === "function") { - return f(left, this); - } else { - this.left = left; - this.right = expression(p); - return this; + if (state.option.regexpu) { + /** + * TODO: Extend this restriction to *all* ES6-specific options. + */ + if (!state.inES6()) { + warning("W134", state.tokens.next, "regexpu", 6); } - }; - return x; - } + } - function application(s) { - var x = symbol(s, 42); + if (state.option.couch) { + combine(predefined, vars.couch); + } - x.led = function(left) { - nobreaknonadjacent(state.tokens.prev, state.tokens.curr); + if (state.option.qunit) { + combine(predefined, vars.qunit); + } - this.left = left; - this.right = doFunction({ type: "arrow", loneArg: left }); - return this; - }; - return x; - } + if (state.option.rhino) { + combine(predefined, vars.rhino); + } - function relation(s, f) { - var x = symbol(s, 100); + if (state.option.shelljs) { + combine(predefined, vars.shelljs); + combine(predefined, vars.node); + } + if (state.option.typed) { + combine(predefined, vars.typed); + } - x.led = function(left) { - nobreaknonadjacent(state.tokens.prev, state.tokens.curr); - this.left = left; - var right = this.right = expression(100); + if (state.option.phantom) { + combine(predefined, vars.phantom); + } - if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) { - warning("W019", this); - } else if (f) { - f.apply(this, [left, right]); - } + if (state.option.prototypejs) { + combine(predefined, vars.prototypejs); + } - if (!left || !right) { - quit("E041", state.tokens.curr.line); - } + if (state.option.node) { + combine(predefined, vars.node); + combine(predefined, vars.typed); + } - if (left.id === "!") { - warning("W018", left, "!"); - } + if (state.option.devel) { + combine(predefined, vars.devel); + } - if (right.id === "!") { - warning("W018", right, "!"); - } + if (state.option.dojo) { + combine(predefined, vars.dojo); + } - return this; - }; - return x; - } + if (state.option.browser) { + combine(predefined, vars.browser); + combine(predefined, vars.typed); + } - function isPoorRelation(node) { - return node && - ((node.type === "(number)" && +node.value === 0) || - (node.type === "(string)" && node.value === "") || - (node.type === "null" && !state.option.eqnull) || - node.type === "true" || - node.type === "false" || - node.type === "undefined"); - } + if (state.option.browserify) { + combine(predefined, vars.browser); + combine(predefined, vars.typed); + combine(predefined, vars.browserify); + } - var typeofValues = {}; - typeofValues.legacy = [ - // E4X extended the `typeof` operator to return "xml" for the XML and - // XMLList types it introduced. - // Ref: 11.3.2 The typeof Operator - // http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-357.pdf - "xml", - // IE<9 reports "unknown" when the `typeof` operator is applied to an - // object existing across a COM+ bridge. In lieu of official documentation - // (which does not exist), see: - // http://robertnyman.com/2005/12/21/what-is-typeof-unknown/ - "unknown" - ]; - typeofValues.es3 = [ - "undefined", "boolean", "number", "string", "function", "object", - ]; - typeofValues.es3 = typeofValues.es3.concat(typeofValues.legacy); - typeofValues.es6 = typeofValues.es3.concat("symbol"); + if (state.option.nonstandard) { + combine(predefined, vars.nonstandard); + } - // Checks whether the 'typeof' operator is used with the correct - // value. For docs on 'typeof' see: - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof - function isTypoTypeof(left, right, state) { - var values; + if (state.option.jasmine) { + combine(predefined, vars.jasmine); + } - if (state.option.notypeof) - return false; + if (state.option.jquery) { + combine(predefined, vars.jquery); + } - if (!left || !right) - return false; + if (state.option.mootools) { + combine(predefined, vars.mootools); + } - values = state.inES6() ? typeofValues.es6 : typeofValues.es3; + if (state.option.worker) { + combine(predefined, vars.worker); + } - if (right.type === "(identifier)" && right.value === "typeof" && left.type === "(string)") - return !_.contains(values, left.value); + if (state.option.wsh) { + combine(predefined, vars.wsh); + } - return false; - } + if (state.option.yui) { + combine(predefined, vars.yui); + } - function isGlobalEval(left, state) { - var isGlobal = false; - - // permit methods to refer to an "eval" key in their own context - if (left.type === "this" && state.funct["(context)"] === null) { - isGlobal = true; - } - // permit use of "eval" members of objects - else if (left.type === "(identifier)") { - if (state.option.node && left.value === "global") { - isGlobal = true; - } - - else if (state.option.browser && (left.value === "window" || left.value === "document")) { - isGlobal = true; - } + if (state.option.mocha) { + combine(predefined, vars.mocha); } - - return isGlobal; } - function findNativePrototype(left) { - var natives = [ - "Array", "ArrayBuffer", "Boolean", "Collator", "DataView", "Date", - "DateTimeFormat", "Error", "EvalError", "Float32Array", "Float64Array", - "Function", "Infinity", "Intl", "Int16Array", "Int32Array", "Int8Array", - "Iterator", "Number", "NumberFormat", "Object", "RangeError", - "ReferenceError", "RegExp", "StopIteration", "String", "SyntaxError", - "TypeError", "Uint16Array", "Uint32Array", "Uint8Array", "Uint8ClampedArray", - "URIError" - ]; - - function walkPrototype(obj) { - if (typeof obj !== "object") return; - return obj.right === "prototype" ? obj : walkPrototype(obj.left); - } + // Produce an error warning. + function quit(code, token, a, b) { + var percentage = Math.floor((token.line / state.lines.length) * 100); + var message = messages.errors[code].desc; - function walkNative(obj) { - while (!obj.identifier && typeof obj.left === "object") - obj = obj.left; + var exception = { + name: "JSHintError", + line: token.line, + character: token.from, + message: message + " (" + percentage + "% scanned).", + raw: message, + code: code, + a: a, + b: b + }; - if (obj.identifier && natives.indexOf(obj.value) >= 0) - return obj.value; - } + exception.reason = supplant(message, exception) + " (" + percentage + + "% scanned)."; - var prototype = walkPrototype(left); - if (prototype) return walkNative(prototype); + throw exception; } - /** - * Checks the left hand side of an assignment for issues, returns if ok - * @param {token} left - the left hand side of the assignment - * @param {token=} assignToken - the token for the assignment, used for reporting - * @param {object=} options - optional object - * @param {boolean} options.allowDestructuring - whether to allow destructuting binding - * @returns {boolean} Whether the left hand side is OK - */ - function checkLeftSideAssign(left, assignToken, options) { + function removeIgnoredMessages() { + var ignored = state.ignoredLines; - var allowDestructuring = options && options.allowDestructuring; + if (_.isEmpty(ignored)) return; + JSHINT.errors = _.reject(JSHINT.errors, function(err) { return ignored[err.line] }); + } - assignToken = assignToken || left; + function warning(code, t, a, b, c, d) { + var ch, l, w, msg; - if (state.option.freeze) { - var nativeObject = findNativePrototype(left); - if (nativeObject) - warning("W121", left, nativeObject); - } + if (/^W\d{3}$/.test(code)) { + if (state.ignored[code]) + return; - if (left.identifier && !left.isMetaProperty) { - // reassign also calls modify - // but we are specific in order to catch function re-assignment - // and globals re-assignment - state.funct["(scope)"].block.reassign(left.value, left); + msg = messages.warnings[code]; + } else if (/E\d{3}/.test(code)) { + msg = messages.errors[code]; + } else if (/I\d{3}/.test(code)) { + msg = messages.info[code]; } - if (left.id === ".") { - if (!left.left || left.left.value === "arguments" && !state.isStrict()) { - warning("E031", assignToken); - } - - state.nameStack.set(state.tokens.prev); - return true; - } else if (left.id === "{" || left.id === "[") { - if (allowDestructuring && state.tokens.curr.left.destructAssign) { - state.tokens.curr.left.destructAssign.forEach(function(t) { - if (t.id) { - state.funct["(scope)"].block.modify(t.id, t.token); - } - }); - } else { - if (left.id === "{" || !left.left) { - warning("E031", assignToken); - } else if (left.left.value === "arguments" && !state.isStrict()) { - warning("E031", assignToken); - } - } - - if (left.id === "[") { - state.nameStack.set(left.right); - } - - return true; - } else if (left.isMetaProperty) { - error("E031", assignToken); - return true; - } else if (left.identifier && !isReserved(left)) { - if (state.funct["(scope)"].labeltype(left.value) === "exception") { - warning("W022", left); - } - state.nameStack.set(left); - return true; + t = t || state.tokens.next || {}; + if (t.id === "(end)") { // `~ + t = state.tokens.curr; } - if (left === state.syntax["function"]) { - warning("W023", state.tokens.curr); - } + l = t.line; + ch = t.from; - return false; - } + w = { + id: "(error)", + raw: msg.desc, + code: msg.code, + evidence: state.lines[l - 1] || "", + line: l, + character: ch, + scope: JSHINT.scope, + a: a, + b: b, + c: c, + d: d + }; - function assignop(s, f, p) { - var x = infix(s, typeof f === "function" ? f : function(left, that) { - that.left = left; + w.reason = supplant(msg.desc, w); + JSHINT.errors.push(w); - if (left && checkLeftSideAssign(left, that, { allowDestructuring: true })) { - that.right = expression(10); - return that; - } + removeIgnoredMessages(); - error("E031", that); - }, p); + if (JSHINT.errors.length >= state.option.maxerr) + quit("E043", t); - x.exps = true; - x.assign = true; - return x; + return w; } - - function bitwise(s, f, p) { - var x = symbol(s, p); - reserveName(x); - x.led = (typeof f === "function") ? f : function(left) { - if (state.option.bitwise) { - warning("W016", this, this.id); - } - this.left = left; - this.right = expression(p); - return this; - }; - return x; + function warningAt(m, l, ch, a, b, c, d) { + return warning(m, { + line: l, + from: ch + }, a, b, c, d); } - function bitwiseassignop(s) { - return assignop(s, function(left, that) { - if (state.option.bitwise) { - warning("W016", that, that.id); - } - - if (left && checkLeftSideAssign(left, that)) { - that.right = expression(10); - return that; - } - error("E031", that); - }, 20); + function error(m, t, a, b, c, d) { + warning(m, t, a, b, c, d); } - function suffix(s) { - var x = symbol(s, 150); - - x.led = function(left) { - // this = suffix e.g. "++" punctuator - // left = symbol operated e.g. "a" identifier or "a.b" punctuator - if (state.option.plusplus) { - warning("W016", this, this.id); - } else if ((!left.identifier || isReserved(left)) && left.id !== "." && left.id !== "[") { - warning("W017", this); - } - - if (left.isMetaProperty) { - error("E031", this); - // detect increment/decrement of a const - // in the case of a.b, left will be the "." punctuator - } else if (left && left.identifier) { - state.funct["(scope)"].block.modify(left.value, left); - } + function errorAt(m, l, ch, a, b, c, d) { + return error(m, { + line: l, + from: ch + }, a, b, c, d); + } - this.left = left; - return this; - }; - return x; + // Tracking of "internal" scripts, like eval containing a static string + function addEvalCode(elem, token) { + JSHINT.internals.push({ + id: "(internal)", + elem: elem, + token: token, + code: token.value.replace(/([^\\])(\\*)\2\\n/g, "$1\n") + }); } - // fnparam means that this identifier is being defined as a function - // argument (see identifier()) - // prop means that this identifier is that of an object property + /** + * Process an inline linting directive + * + * @param {Token} directiveToken - the directive-bearing comment token + * @param {Token} previous - the token that preceeds the directive + */ + function lintingDirective(directiveToken, previous) { + var body = directiveToken.body.split(",") + .map(function(s) { return s.trim(); }); + var predef = {}; - function optionalidentifier(fnparam, prop, preserve) { - if (!state.tokens.next.identifier) { + if (directiveToken.type === "falls through") { + previous.caseFallsThrough = true; return; } - if (!preserve) { - advance(); - } - - var curr = state.tokens.curr; - var val = state.tokens.curr.value; - - if (!isReserved(curr)) { - return val; - } - - if (prop) { - if (state.inES5()) { - return val; - } - } + if (directiveToken.type === "globals") { + body.forEach(function(item, idx) { + var parts = item.split(":"); + var key = parts[0].trim(); - if (fnparam && val === "undefined") { - return val; - } + if (key === "-" || !key.length) { + // Ignore trailing comma + if (idx > 0 && idx === body.length - 1) { + return; + } + error("E002", directiveToken); + return; + } - warning("W024", state.tokens.curr, state.tokens.curr.id); - return val; - } + if (key.charAt(0) === "-") { + key = key.slice(1); - // fnparam means that this identifier is being defined as a function - // argument - // prop means that this identifier is that of an object property - function identifier(fnparam, prop) { - var i = optionalidentifier(fnparam, prop, false); - if (i) { - return i; - } + JSHINT.blacklist[key] = key; + delete predefined[key]; + } else { + predef[key] = parts.length > 1 && parts[1].trim() === "true"; + } + }); - // parameter destructuring with rest operator - if (state.tokens.next.value === "...") { - if (!state.inES6(true)) { - warning("W119", state.tokens.next, "spread/rest operator", "6"); - } - advance(); + combine(predefined, predef); - if (checkPunctuator(state.tokens.next, "...")) { - warning("E024", state.tokens.next, "..."); - while (checkPunctuator(state.tokens.next, "...")) { - advance(); + for (var key in predef) { + if (_.has(predef, key)) { + declared[key] = directiveToken; } } + } - if (!state.tokens.next.identifier) { - warning("E024", state.tokens.curr, "..."); - return; - } - - return identifier(fnparam, prop); - } else { - error("E030", state.tokens.next, state.tokens.next.value); + if (directiveToken.type === "exported") { + body.forEach(function(e, idx) { + if (!e.length) { + // Ignore trailing comma + if (idx > 0 && idx === body.length - 1) { + return; + } + error("E002", directiveToken); + return; + } - // The token should be consumed after a warning is issued so the parser - // can continue as though an identifier were found. The semicolon token - // should not be consumed in this way so that the parser interprets it as - // a statement delimeter; - if (state.tokens.next.id !== ";") { - advance(); - } + state.funct["(scope)"].addExported(e); + }); } - } + if (directiveToken.type === "members") { + membersOnly = membersOnly || {}; - function reachable(controlToken) { - var i = 0, t; - if (state.tokens.next.id !== ";" || controlToken.inBracelessBlock) { - return; - } - for (;;) { - do { - t = peek(i); - i += 1; - } while (t.id !== "(end)" && t.id === "(comment)"); + body.forEach(function(m) { + var ch1 = m.charAt(0); + var ch2 = m.charAt(m.length - 1); - if (t.reach) { - return; - } - if (t.id !== "(endline)") { - if (t.id === "function") { - if (state.option.latedef === true) { - warning("W026", t); - } - break; + if (ch1 === ch2 && (ch1 === "\"" || ch1 === "'")) { + m = m + .substr(1, m.length - 2) + .replace("\\\"", "\""); } - warning("W027", t, t.value, controlToken.value); - break; - } + membersOnly[m] = false; + }); } - } - function parseFinalSemicolon() { - if (state.tokens.next.id !== ";") { - // don't complain about unclosed templates / strings - if (state.tokens.next.isUnclosed) return advance(); + var numvals = [ + "maxstatements", + "maxparams", + "maxdepth", + "maxcomplexity", + "maxerr", + "maxlen", + "indent" + ]; - var sameLine = startLine(state.tokens.next) === state.tokens.curr.line && - state.tokens.next.id !== "(end)"; - var blockEnd = checkPunctuator(state.tokens.next, "}"); + if (directiveToken.type === "jshint" || directiveToken.type === "jslint" || + directiveToken.type === "jshint.unstable") { + body.forEach(function(item) { + var parts = item.split(":"); + var key = parts[0].trim(); + var val = parts.length > 1 ? parts[1].trim() : ""; + var numberVal; - if (sameLine && !blockEnd) { - errorAt("E058", state.tokens.curr.line, state.tokens.curr.character); - } else if (!state.option.asi) { - // If this is the last statement in a block that ends on - // the same line *and* option lastsemic is on, ignore the warning. - // Otherwise, complain about missing semicolon. - if ((blockEnd && !state.option.lastsemic) || !sameLine) { - warningAt("W033", state.tokens.curr.line, state.tokens.curr.character); + if (!checkOption(key, directiveToken.type !== "jshint.unstable", directiveToken)) { + return; } - } - } else { - advance(";"); - } - } - function statement() { - var i = indent, r, t = state.tokens.next, hasOwnScope = false; + if (numvals.indexOf(key) >= 0) { + // GH988 - numeric options can be disabled by setting them to `false` + if (val !== "false") { + numberVal = +val; - if (t.id === ";") { - advance(";"); - return; - } + if (typeof numberVal !== "number" || !isFinite(numberVal) || + numberVal <= 0 || Math.floor(numberVal) !== numberVal) { + error("E032", directiveToken, val); + return; + } - // Is this a labelled statement? - var res = isReserved(t); + state.option[key] = numberVal; + } else { + state.option[key] = key === "indent" ? 4 : false; + } - // We're being more tolerant here: if someone uses - // a FutureReservedWord as a label, we warn but proceed - // anyway. + return; + } - if (res && t.meta && t.meta.isFutureReservedWord && peek().id === ":") { - warning("W024", t, t.id); - res = false; - } + if (key === "validthis") { + // `validthis` is valid only within a function scope. - if (t.identifier && !res && peek().id === ":") { - advance(); - advance(":"); + if (state.funct["(global)"]) + return void error("E009"); - hasOwnScope = true; - state.funct["(scope)"].stack(); - state.funct["(scope)"].block.addBreakLabel(t.value, { token: state.tokens.curr }); + if (val !== "true" && val !== "false") + return void error("E002", directiveToken); - if (!state.tokens.next.labelled && state.tokens.next.value !== "{") { - warning("W028", state.tokens.next, t.value, state.tokens.next.value); - } + state.option.validthis = (val === "true"); + return; + } - state.tokens.next.label = t.value; - t = state.tokens.next; - } + if (key === "quotmark") { + switch (val) { + case "true": + case "false": + state.option.quotmark = (val === "true"); + break; + case "double": + case "single": + state.option.quotmark = val; + break; + default: + error("E002", directiveToken); + } + return; + } - // Is it a lonely block? + if (key === "shadow") { + switch (val) { + case "true": + state.option.shadow = true; + break; + case "outer": + state.option.shadow = "outer"; + break; + case "false": + case "inner": + state.option.shadow = "inner"; + break; + default: + error("E002", directiveToken); + } + return; + } - if (t.id === "{") { - // Is it a switch case block? - // - // switch (foo) { - // case bar: { <= here. - // ... - // } - // } - var iscase = (state.funct["(verb)"] === "case" && state.tokens.curr.value === ":"); - block(true, true, false, false, iscase); - return; - } + if (key === "unused") { + switch (val) { + case "true": + state.option.unused = true; + break; + case "false": + state.option.unused = false; + break; + case "vars": + case "strict": + state.option.unused = val; + break; + default: + error("E002", directiveToken); + } + return; + } - // Parse the statement. + if (key === "latedef") { + switch (val) { + case "true": + state.option.latedef = true; + break; + case "false": + state.option.latedef = false; + break; + case "nofunc": + state.option.latedef = "nofunc"; + break; + default: + error("E002", directiveToken); + } + return; + } - r = expression(0, true); + if (key === "ignore") { + switch (val) { + case "line": + state.ignoredLines[directiveToken.line] = true; + removeIgnoredMessages(); + break; + default: + error("E002", directiveToken); + } + return; + } - if (r && !(r.identifier && r.value === "function") && - !(r.type === "(punctuator)" && r.left && - r.left.identifier && r.left.value === "function")) { - if (!state.isStrict() && - state.option.strict === "global") { - warning("E007"); - } - } + if (key === "strict") { + switch (val) { + case "true": + state.option.strict = true; + break; + case "false": + state.option.strict = false; + break; + case "global": + case "implied": + state.option.strict = val; + break; + default: + error("E002", directiveToken); + } + return; + } - // Look for the final semicolon. + if (key === "module") { + /** + * TODO: Extend this restriction to *all* "environmental" options. + */ + if (!hasParsedCode(state.funct)) { + error("E055", directiveToken, "module"); + } + } - if (!t.block) { - if (!state.option.expr && (!r || !r.exps)) { - warning("W030", state.tokens.curr); - } else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") { - warning("W031", t); - } - parseFinalSemicolon(); - } + if (key === "esversion") { + switch (val) { + case "3": + case "5": + case "6": + case "7": + case "8": + case "9": + case "10": + state.option.moz = false; + state.option.esversion = +val; + break; + case "2015": + case "2016": + case "2017": + case "2018": + case "2019": + state.option.moz = false; + // Translate specification publication year to version number. + state.option.esversion = +val - 2009; + break; + default: + error("E002", directiveToken); + } + if (!hasParsedCode(state.funct)) { + error("E055", directiveToken, "esversion"); + } + return; + } + var match = /^([+-])(W\d{3})$/g.exec(key); + if (match) { + // ignore for -W..., unignore for +W... + state.ignored[match[2]] = (match[1] === "-"); + return; + } - // Restore the indentation. + var tn; + if (val === "true" || val === "false") { + if (directiveToken.type === "jslint") { + tn = options.renamed[key] || key; + state.option[tn] = (val === "true"); - indent = i; - if (hasOwnScope) { - state.funct["(scope)"].unstack(); - } - return r; - } + if (options.inverted[tn] !== undefined) { + state.option[tn] = !state.option[tn]; + } + } else if (directiveToken.type === "jshint.unstable") { + state.option.unstable[key] = (val === "true"); + } else { + state.option[key] = (val === "true"); + } + return; + } - function statements() { - var a = [], p; + error("E002", directiveToken); + }); - while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") { - if (state.tokens.next.id === ";") { - p = peek(); + applyOptions(); + } + } - if (!p || (p.id !== "(" && p.id !== "[")) { - warning("W032"); + /** + * Return a token beyond the token available in `state.tokens.next`. If no + * such token exists, return the "(end)" token. This function is used to + * determine parsing strategies in cases where the value of the next token + * does not provide sufficient information, as is the case with `for` loops, + * e.g.: + * + * for ( var i in ... + * + * versus: + * + * for ( var i = ... + * + * @param {number} [p] - offset of desired token; defaults to 0 + * + * @returns {token} + */ + function peek(p) { + var i = p || 0, j = lookahead.length, t; + + if (i < j) { + return lookahead[i]; + } + + while (j <= i) { + t = lex.token(); + + // When the lexer is exhausted, this function should produce the "(end)" + // token, even in cases where the requested token is beyond the end of + // the input stream. + if (!t) { + // If the lookahead buffer is empty, the expected "(end)" token was + // already emitted by the most recent invocation of `advance` and is + // available as the next token. + if (!lookahead.length) { + return state.tokens.next; } - advance(";"); - } else { - a.push(statement()); + return lookahead[j - 1]; } + + lookahead[j] = t; + j += 1; } - return a; + + return t; } + function peekIgnoreEOL() { + var i = 0; + var t; + do { + t = peek(i++); + } while (t.id === "(endline)"); + return t; + } - /* - * read all directives - * recognizes a simple form of asi, but always - * warns, if it is used + /** + * Consume the next token. + * + * @param {string} [expected] - the expected value of the next token's `id` + * property (in the case of punctuators) or + * `value` property (in the case of identifiers + * and literals); if unspecified, any token will + * be accepted + * @param {object} [relatedToken] - the token that informed the expected + * value, if any (for example: the opening + * brace when a closing brace is expected); + * used to produce more meaningful errors */ - function directives() { - var i, p, pn; + function advance(expected, relatedToken) { + var nextToken = state.tokens.next; - while (state.tokens.next.id === "(string)") { - p = peek(0); - if (p.id === "(endline)") { - i = 1; - do { - pn = peek(i++); - } while (pn.id === "(endline)"); - if (pn.id === ";") { - p = pn; - } else if (pn.value === "[" || pn.value === ".") { - // string -> [ | . is a valid production - break; - } else if (!state.option.asi || pn.value === "(") { - // string -> ( is not a valid production - warning("W033", state.tokens.next); + if (expected && nextToken.id !== expected) { + if (relatedToken) { + if (nextToken.id === "(end)") { + error("E019", relatedToken, relatedToken.id); + } else { + error("E020", nextToken, expected, relatedToken.id, + relatedToken.line, nextToken.value); } - } else if (p.id === "." || p.id === "[") { - break; - } else if (p.id !== ";") { - warning("W033", p); + } else if (nextToken.type !== "(identifier)" || nextToken.value !== expected) { + error("E021", nextToken, expected, nextToken.value); } + } - advance(); - var directive = state.tokens.curr.value; - if (state.directive[directive] || - (directive === "use strict" && state.option.strict === "implied")) { - warning("W034", state.tokens.curr, directive); + state.tokens.prev = state.tokens.curr; + state.tokens.curr = state.tokens.next; + for (;;) { + state.tokens.next = lookahead.shift() || lex.token(); + + if (!state.tokens.next) { // No more tokens left, give up + quit("E041", state.tokens.curr); } - // there's no directive negation, so always set to true - state.directive[directive] = true; + if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") { + return; + } - if (p.id === ";") { - advance(";"); + if (state.tokens.next.check) { + state.tokens.next.check(); } - } - if (state.isStrict()) { - if (!state.option["(explicitNewcap)"]) { - state.option.newcap = true; + if (state.tokens.next.isSpecial) { + lintingDirective(state.tokens.next, state.tokens.curr); + } else { + if (state.tokens.next.id !== "(endline)") { + break; + } } - state.option.undef = true; } } - - /* - * Parses a single block. A block is a sequence of statements wrapped in - * braces. + /** + * Determine whether a given token is an operator. + * + * @param {token} token * - * ordinary - true for everything but function bodies and try blocks. - * stmt - true if block can be a single statement (e.g. in if/for/while). - * isfunc - true if block is a function body - * isfatarrow - true if its a body of a fat arrow function - * iscase - true if block is a switch case block + * @returns {boolean} */ - function block(ordinary, stmt, isfunc, isfatarrow, iscase) { - var a, - b = inblock, - old_indent = indent, - m, - t, - line, - d; + function isOperator(token) { + return token.first || token.right || token.left || token.id === "yield" || token.id === "await"; + } - inblock = ordinary; + function isEndOfExpr(context, curr, next) { + if (arguments.length <= 1) { + curr = state.tokens.curr; + next = state.tokens.next; + } - t = state.tokens.next; + if (next.id === "in" && context & prodParams.noin) { + return true; + } - var metrics = state.funct["(metrics)"]; - metrics.nestedBlockDepth += 1; - metrics.verifyMaxNestedBlockDepthPerFunction(); + if (next.id === ";" || next.id === "}" || next.id === ":") { + return true; + } - if (state.tokens.next.id === "{") { - advance("{"); + if (next.infix === curr.infix || + // Infix operators which follow `yield` should only be consumed as part + // of the current expression if allowed by the syntactic grammar. In + // effect, this prevents automatic semicolon insertion when `yield` is + // followed by a newline and a comma operator (without enabling it when + // `yield` is followed by a newline and a `[` token). + (curr.id === "yield" && curr.rbp < next.rbp)) { + return !sameLine(curr, next); + } - // create a new block scope - state.funct["(scope)"].stack(); + return false; + } - line = state.tokens.curr.line; - if (state.tokens.next.id !== "}") { - indent += state.option.indent; - while (!ordinary && state.tokens.next.from > indent) { - indent += state.option.indent; - } + /** + * The `expression` function is the heart of JSHint's parsing behaior. It is + * based on the Pratt parser, but it extends that model with a `fud` method. + * Short for "first null denotation," it it similar to the `nud` ("null + * denotation") function, but it is only used on the first token of a + * statement. This simplifies usage in statement-oriented languages like + * JavaScript. + * + * .nud Null denotation + * .fud First null denotation + * .led Left denotation + * lbp Left binding power + * rbp Right binding power + * + * They are elements of the parsing method called Top Down Operator Precedence. + * + * In addition to parsing, this function applies a number of linting patterns. + * + * @param {number} context - the parsing context (a bitfield describing + * conditions of the current parsing operation + * which can influence how the next tokens are + * interpreted); see `prod-params.js` for more + * detail) + * @param {number} rbp - the right-binding power of the token to be consumed + */ + function expression(context, rbp) { + var left, isArray = false, isObject = false; + var initial = context & prodParams.initial; + var curr; - if (isfunc) { - m = {}; - for (d in state.directive) { - if (_.has(state.directive, d)) { - m[d] = state.directive[d]; - } - } - directives(); + context &= ~prodParams.initial; - if (state.option.strict && state.funct["(context)"]["(global)"]) { - if (!m["use strict"] && !state.isStrict()) { - warning("E007"); - } - } - } + state.nameStack.push(); - a = statements(); + if (state.tokens.next.id === "(end)") + error("E006", state.tokens.curr); - metrics.statementCount += a.length; + advance(); - indent -= state.option.indent; - } + if (initial) { + state.funct["(verb)"] = state.tokens.curr.value; + state.tokens.curr.beginsStmt = true; + } - advance("}", t); + curr = state.tokens.curr; - if (isfunc) { - state.funct["(scope)"].validateParams(); - if (m) { - state.directive = m; - } + if (initial && curr.fud && (!curr.useFud || curr.useFud(context))) { + left = state.tokens.curr.fud(context); + } else { + if (state.tokens.curr.nud) { + left = state.tokens.curr.nud(context, rbp); + } else { + error("E030", state.tokens.curr, state.tokens.curr.id); } - state.funct["(scope)"].unstack(); - - indent = old_indent; - } else if (!ordinary) { - if (isfunc) { - state.funct["(scope)"].stack(); - - m = {}; - if (stmt && !isfatarrow && !state.inMoz()) { - error("W118", state.tokens.curr, "function closure expressions"); - } + while (rbp < state.tokens.next.lbp && !isEndOfExpr(context)) { + isArray = state.tokens.curr.value === "Array"; + isObject = state.tokens.curr.value === "Object"; - if (!stmt) { - for (d in state.directive) { - if (_.has(state.directive, d)) { - m[d] = state.directive[d]; + // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object() + // Line breaks in IfStatement heads exist to satisfy the checkJSHint + // "Line too long." error. + if (left && (left.value || (left.first && left.first.value))) { + // If the left.value is not "new", or the left.first.value is a "." + // then safely assume that this is not "new Array()" and possibly + // not "new Object()"... + if (left.value !== "new" || + (left.first && left.first.value && left.first.value === ".")) { + isArray = false; + // ...In the case of Object, if the left.value and state.tokens.curr.value + // are not equal, then safely assume that this not "new Object()" + if (left.value !== state.tokens.curr.value) { + isObject = false; } } } - expression(10); - if (state.option.strict && state.funct["(context)"]["(global)"]) { - if (!m["use strict"] && !state.isStrict()) { - warning("E007"); - } + advance(); + + if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { + warning("W009", state.tokens.curr); } - state.funct["(scope)"].unstack(); - } else { - error("E021", state.tokens.next, "{", state.tokens.next.value); + if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { + warning("W010", state.tokens.curr); + } + + if (left && state.tokens.curr.led) { + left = state.tokens.curr.led(context, left); + } else { + error("E033", state.tokens.curr, state.tokens.curr.id); + } } - } else { + } - // check to avoid let declaration not within a block - // though is fine inside for loop initializer section - state.funct["(noblockscopedvar)"] = state.tokens.next.id !== "for"; - state.funct["(scope)"].stack(); + state.nameStack.pop(); - if (!stmt || state.option.curly) { - warning("W116", state.tokens.next, "{", state.tokens.next.value); - } + return left; + } - state.tokens.next.inBracelessBlock = true; - indent += state.option.indent; - // test indentation only if statement is in new line - a = [statement()]; - indent -= state.option.indent; - state.funct["(scope)"].unstack(); - delete state.funct["(noblockscopedvar)"]; - } + // Functions for conformance of style. - // Don't clear and let it propagate out if it is "break", "return" or similar in switch case - switch (state.funct["(verb)"]) { - case "break": - case "continue": - case "return": - case "throw": - if (iscase) { - break; - } + function sameLine(first, second) { + return first.line === (second.startLine || second.line); + } - /* falls through */ - default: - state.funct["(verb)"] = null; + function nobreaknonadjacent(left, right) { + if (!state.option.laxbreak && !sameLine(left, right)) { + warning("W014", right, right.value); } + } - inblock = b; - if (ordinary && state.option.noempty && (!a || a.length === 0)) { - warning("W035", state.tokens.prev); + function nolinebreak(t) { + t = t; + if (!sameLine(t, state.tokens.next)) { + warning("E022", t, t.value); } - metrics.nestedBlockDepth -= 1; - return a; } + /** + * Validate the comma token in the "current" position of the token stream. + * + * @param {object} [opts] + * @param {boolean} [opts.property] - flag indicating whether the current + * comma token is situated directly within + * an object initializer + * @param {boolean} [opts.allowTrailing] - flag indicating whether the + * current comma token may appear + * directly before a delimiter + * + * @returns {boolean} flag indicating the validity of the current comma + * token; `false` if the token directly causes a syntax + * error, `true` otherwise + */ + function checkComma(opts) { + var prev = state.tokens.prev; + var curr = state.tokens.curr; + opts = opts || {}; - function countMember(m) { - if (membersOnly && typeof membersOnly[m] !== "boolean") { - warning("W036", state.tokens.curr, m); - } - if (typeof member[m] === "number") { - member[m] += 1; - } else { - member[m] = 1; + if (!sameLine(prev, curr)) { + if (!state.option.laxcomma) { + if (checkComma.first) { + warning("I001", curr); + checkComma.first = false; + } + warning("W014", prev, curr.value); + } } - } - - // Build the syntax table by declaring the syntactic elements of the language. - type("(number)", function() { - return this; - }); + if (state.tokens.next.identifier && !(opts.property && state.inES5())) { + // Keywords that cannot follow a comma operator. + switch (state.tokens.next.value) { + case "break": + case "case": + case "catch": + case "continue": + case "default": + case "do": + case "else": + case "finally": + case "for": + case "if": + case "in": + case "instanceof": + case "return": + case "switch": + case "throw": + case "try": + case "var": + case "let": + case "while": + case "with": + error("E024", state.tokens.next, state.tokens.next.value); + return false; + } + } - type("(string)", function() { - return this; - }); + if (state.tokens.next.type === "(punctuator)") { + switch (state.tokens.next.value) { + case "}": + case "]": + case ",": + case ")": + if (opts.allowTrailing) { + return true; + } - state.syntax["(identifier)"] = { - type: "(identifier)", - lbp: 0, - identifier: true, + error("E024", state.tokens.next, state.tokens.next.value); + return false; + } + } + return true; + } - nud: function() { - var v = this.value; + /** + * Factory function for creating "symbols"--objects that will be inherited by + * tokens. The objects created by this function are stored in a symbol table + * and set as the prototype of the tokens generated by the lexer. + * + * Note that this definition of "symbol" describes an implementation detail + * of JSHint and is not related to the ECMAScript value type introduced in + * ES2015. + * + * @param {string} s - the name of the token; for keywords (e.g. `void`) and + * delimiters (e.g.. `[`), this is the token's text + * representation; for literals (e.g. numbers) and other + * "special" tokens (e.g. the end-of-file marker) this is + * a parenthetical value + * @param {number} p - the left-binding power of the token as used by the + * Pratt parsing semantics + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function symbol(s, p) { + var x = state.syntax[s]; + if (!x || typeof x !== "object") { + state.syntax[s] = x = { + id: s, + lbp: p, + // Symbols that accept a right-hand side do so with a binding power + // that is commonly identical to their left-binding power. (This value + // is relevant when determining if the grouping operator is necessary + // to override the precedence of surrounding operators.) Because the + // exponentiation operator's left-binding power and right-binding power + // are distinct, the values must be encoded separately. + rbp: p, + value: s + }; + } + return x; + } - // If this identifier is the lone parameter to a shorthand "fat arrow" - // function definition, i.e. - // - // x => x; - // - // ...it should not be considered as a variable in the current scope. It - // will be added to the scope of the new function when the next token is - // parsed, so it can be safely ignored for now. - if (state.tokens.next.id === "=>") { - return this; - } + /** + * Convenience function for defining delimiter symbols. + * + * @param {string} s - the name of the symbol + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function delim(s) { + var x = symbol(s, 0); + x.delim = true; + return x; + } - if (!state.funct["(comparray)"].check(v)) { - state.funct["(scope)"].block.use(v, state.tokens.curr); - } - return this; - }, + /** + * Convenience function for defining statement-denoting symbols. + * + * @param {string} s - the name of the symbol + * @param {function} f - the first null denotation function for the symbol; + * see the `expression` function for more detail + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function stmt(s, f) { + var x = delim(s); + x.identifier = x.reserved = true; + x.fud = f; + return x; + } - led: function() { - error("E033", state.tokens.next, state.tokens.next.value); + /** + * Convenience function for defining block-statement-denoting symbols. + * + * A block-statement-denoting symbol is one like 'if' or 'for', which will be + * followed by a block and will not have to end with a semicolon. + * + * @param {string} s - the name of the symbol + * @param {function} - the first null denotation function for the symbol; see + * the `expression` function for more detail + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function blockstmt(s, f) { + var x = stmt(s, f); + x.block = true; + return x; + } + /** + * Denote a given JSHint symbol as an identifier and a reserved keyword. + * + * @param {object} - a JSHint symbol value + * + * @returns {object} - the provided object + */ + function reserveName(x) { + var c = x.id.charAt(0); + if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) { + x.identifier = x.reserved = true; } - }; + return x; + } - var baseTemplateSyntax = { - lbp: 0, - identifier: false, - template: true, - }; - state.syntax["(template)"] = _.extend({ - type: "(template)", - nud: doTemplateLiteral, - led: doTemplateLiteral, - noSubst: false - }, baseTemplateSyntax); + /** + * Convenience function for defining "prefix" symbols--operators that accept + * expressions as a right-hand side. + * + * @param {string} s - the name of the symbol + * @param {function} [f] - the first null denotation function for the symbol; + * see the `expression` function for more detail + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function prefix(s, f) { + var x = symbol(s, 150); + reserveName(x); - state.syntax["(template middle)"] = _.extend({ - type: "(template middle)", - middle: true, - noSubst: false - }, baseTemplateSyntax); + x.nud = (typeof f === "function") ? f : function(context) { + this.arity = "unary"; + this.right = expression(context, 150); - state.syntax["(template tail)"] = _.extend({ - type: "(template tail)", - tail: true, - noSubst: false - }, baseTemplateSyntax); + if (this.id === "++" || this.id === "--") { + if (state.option.plusplus) { + warning("W016", this, this.id); + } - state.syntax["(no subst template)"] = _.extend({ - type: "(template)", - nud: doTemplateLiteral, - led: doTemplateLiteral, - noSubst: true, - tail: true // mark as tail, since it's always the last component - }, baseTemplateSyntax); + if (this.right) { + checkLeftSideAssign(context, this.right, this); + } + } - type("(regexp)", function() { - return this; - }); + return this; + }; - // ECMAScript parser + return x; + } - delim("(endline)"); - delim("(begin)"); - delim("(end)").reach = true; - delim("(error)").reach = true; - delim("}").reach = true; - delim(")"); - delim("]"); - delim("\"").reach = true; - delim("'").reach = true; - delim(";"); - delim(":").reach = true; - delim("#"); + /** + * Convenience function for defining "type" symbols--those that describe + * literal values. + * + * @param {string} s - the name of the symbol + * @param {function} f - the first null denotation function for the symbol; + * see the `expression` function for more detail + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function type(s, f) { + var x = symbol(s, 0); + x.type = s; + x.nud = f; + return x; + } - reserve("else"); - reserve("case").reach = true; - reserve("catch"); - reserve("default").reach = true; - reserve("finally"); - reservevar("arguments", function(x) { - if (state.isStrict() && state.funct["(global)"]) { - warning("E008", x); - } - }); - reservevar("eval"); - reservevar("false"); - reservevar("Infinity"); - reservevar("null"); - reservevar("this", function(x) { - if (state.isStrict() && !isMethod() && - !state.option.validthis && ((state.funct["(statement)"] && - state.funct["(name)"].charAt(0) > "Z") || state.funct["(global)"])) { - warning("W040", x); - } - }); - reservevar("true"); - reservevar("undefined"); - - assignop("=", "assign", 20); - assignop("+=", "assignadd", 20); - assignop("-=", "assignsub", 20); - assignop("*=", "assignmult", 20); - assignop("/=", "assigndiv", 20).nud = function() { - error("E014"); - }; - assignop("%=", "assignmod", 20); + /** + * Convenience function for defining JSHint symbols for reserved + * keywords--those that are restricted from use as bindings (and as property + * names in ECMAScript 3 environments). + * + * @param {string} s - the name of the symbol + * @param {function} func - the first null denotation function for the + * symbol; see the `expression` function for more + * detail + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function reserve(name, func) { + var x = type(name, func); + x.identifier = true; + x.reserved = true; + return x; + } - bitwiseassignop("&="); - bitwiseassignop("|="); - bitwiseassignop("^="); - bitwiseassignop("<<="); - bitwiseassignop(">>="); - bitwiseassignop(">>>="); - infix(",", function(left, that) { - var expr; - that.exprs = [left]; + /** + * Convenience function for defining JSHint symbols for keywords that are + * only reserved in some circumstances. + * + * @param {string} name - the name of the symbol + * @param {object} [meta] - a collection of optional arguments + * @param {function} [meta.nud] -the null denotation function for the symbol; + * see the `expression` function for more detail + * @param {boolean} [meta.es5] - `true` if the identifier is reserved + * in ECMAScript 5 or later + * @param {boolean} [meta.strictOnly] - `true` if the identifier is only + * reserved in strict mode code. + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function FutureReservedWord(name, meta) { + var x = type(name, state.syntax["(identifier)"].nud); - if (state.option.nocomma) { - warning("W127"); - } + meta = meta || {}; + meta.isFutureReservedWord = true; - if (!comma({ peek: true })) { - return that; - } - while (true) { - if (!(expr = expression(10))) { - break; - } - that.exprs.push(expr); - if (state.tokens.next.value !== "," || !comma()) { - break; - } - } - return that; - }, 10, true); + x.value = name; + x.identifier = true; + x.reserved = true; + x.meta = meta; - infix("?", function(left, that) { - increaseComplexityCount(); - that.left = left; - that.right = expression(10); - advance(":"); - that["else"] = expression(10); - return that; - }, 30); + return x; + } - var orPrecendence = 40; - infix("||", function(left, that) { - increaseComplexityCount(); - that.left = left; - that.right = expression(orPrecendence); - return that; - }, orPrecendence); - infix("&&", "and", 50); - bitwise("|", "bitor", 70); - bitwise("^", "bitxor", 80); - bitwise("&", "bitand", 90); - relation("==", function(left, right) { - var eqnull = state.option.eqnull && - ((left && left.value) === "null" || (right && right.value) === "null"); + /** + * Convenience function for defining "infix" symbols--operators that require + * operands as both "land-hand side" and "right-hand side". + * + * @param {string} s - the name of the symbol + * @param {function} [f] - a function to be invoked that consumes the + * right-hand side of the operator + * @param {number} p - the left-binding power of the token as used by the + * Pratt parsing semantics + * @param {boolean} [w] - if `true` + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function infix(s, f, p, w) { + var x = symbol(s, p); + reserveName(x); + x.infix = true; + x.led = function(context, left) { + if (!w) { + nobreaknonadjacent(state.tokens.prev, state.tokens.curr); + } + if ((s === "in" || s === "instanceof") && left.id === "!") { + warning("W018", left, "!"); + } + if (typeof f === "function") { + return f(context, left, this); + } else { + this.left = left; + this.right = expression(context, p); + return this; + } + }; + return x; + } - switch (true) { - case !eqnull && state.option.eqeqeq: - this.from = this.character; - warning("W116", this, "===", "=="); - break; - case isPoorRelation(left): - warning("W041", this, "===", left.value); - break; - case isPoorRelation(right): - warning("W041", this, "===", right.value); - break; - case isTypoTypeof(right, left, state): - warning("W122", this, right.value); - break; - case isTypoTypeof(left, right, state): - warning("W122", this, left.value); - break; - } + /** + * Convenience function for defining the `=>` token as used in arrow + * functions. + * + * @param {string} s - the name of the symbol + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function application(s) { + var x = symbol(s, 42); - return this; - }); - relation("===", function(left, right) { - if (isTypoTypeof(right, left, state)) { - warning("W122", this, right.value); - } else if (isTypoTypeof(left, right, state)) { - warning("W122", this, left.value); - } - return this; - }); - relation("!=", function(left, right) { - var eqnull = state.option.eqnull && - ((left && left.value) === "null" || (right && right.value) === "null"); + x.infix = true; + x.led = function(context, left) { + nobreaknonadjacent(state.tokens.prev, state.tokens.curr); - if (!eqnull && state.option.eqeqeq) { - this.from = this.character; - warning("W116", this, "!==", "!="); - } else if (isPoorRelation(left)) { - warning("W041", this, "!==", left.value); - } else if (isPoorRelation(right)) { - warning("W041", this, "!==", right.value); - } else if (isTypoTypeof(right, left, state)) { - warning("W122", this, right.value); - } else if (isTypoTypeof(left, right, state)) { - warning("W122", this, left.value); - } - return this; - }); - relation("!==", function(left, right) { - if (isTypoTypeof(right, left, state)) { - warning("W122", this, right.value); - } else if (isTypoTypeof(left, right, state)) { - warning("W122", this, left.value); - } - return this; - }); - relation("<"); - relation(">"); - relation("<="); - relation(">="); - bitwise("<<", "shiftleft", 120); - bitwise(">>", "shiftright", 120); - bitwise(">>>", "shiftrightunsigned", 120); - infix("in", "in", 120); - infix("instanceof", "instanceof", 120); - infix("+", function(left, that) { - var right; - that.left = left; - that.right = right = expression(130); + this.left = left; + this.right = doFunction(context, { type: "arrow", loneArg: left }); + return this; + }; + return x; + } - if (left && right && left.id === "(string)" && right.id === "(string)") { - left.value += right.value; - left.character = right.character; - if (!state.option.scripturl && reg.javascriptURL.test(left.value)) { - warning("W050", left); + /** + * Convenience function for defining JSHint symbols for relation operators. + * + * @param {string} s - the name of the symbol + * @param {function} [f] - a function to be invoked to enforce any additional + * linting rules. + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function relation(s, f) { + var x = symbol(s, 100); + + x.infix = true; + x.led = function(context, left) { + nobreaknonadjacent(state.tokens.prev, state.tokens.curr); + this.left = left; + var right = this.right = expression(context, 100); + + if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) { + warning("W019", this); + } else if (f) { + f.apply(this, [context, left, right]); } - return left; - } - return that; - }, 130); - prefix("+", "num"); - prefix("+++", function() { - warning("W007"); - this.arity = "unary"; - this.right = expression(150); - return this; - }); - infix("+++", function(left) { - warning("W007"); - this.left = left; - this.right = expression(130); - return this; - }, 130); - infix("-", "sub", 130); - prefix("-", "neg"); - prefix("---", function() { - warning("W006"); - this.arity = "unary"; - this.right = expression(150); - return this; - }); - infix("---", function(left) { - warning("W006"); - this.left = left; - this.right = expression(130); - return this; - }, 130); - infix("*", "mult", 140); - infix("/", "div", 140); - infix("%", "mod", 140); + if (!left || !right) { + quit("E041", state.tokens.curr); + } - suffix("++"); - prefix("++", "preinc"); - state.syntax["++"].exps = true; + if (left.id === "!") { + warning("W018", left, "!"); + } + + if (right.id === "!") { + warning("W018", right, "!"); + } - suffix("--"); - prefix("--", "predec"); - state.syntax["--"].exps = true; - prefix("delete", function() { - var p = expression(10); - if (!p) { return this; - } + }; + return x; + } - if (p.id !== "." && p.id !== "[") { - warning("W051"); - } - this.first = p; + /** + * Determine if a given token marks the beginning of a UnaryExpression. + * + * @param {object} token + * + * @returns {boolean} + */ + function beginsUnaryExpression(token) { + return token.arity === "unary" && token.id !== "++" && token.id !== "--"; + } - // The `delete` operator accepts unresolvable references when not in strict - // mode, so the operand may be undefined. - if (p.identifier && !state.isStrict()) { - p.forgiveUndef = true; - } - return this; - }).exps = true; + var typeofValues = {}; + typeofValues.legacy = [ + // E4X extended the `typeof` operator to return "xml" for the XML and + // XMLList types it introduced. + // Ref: 11.3.2 The typeof Operator + // http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-357.pdf + "xml", + // IE<9 reports "unknown" when the `typeof` operator is applied to an + // object existing across a COM+ bridge. In lieu of official documentation + // (which does not exist), see: + // http://robertnyman.com/2005/12/21/what-is-typeof-unknown/ + "unknown" + ]; + typeofValues.es3 = [ + "undefined", "boolean", "number", "string", "function", "object", + ]; + typeofValues.es3 = typeofValues.es3.concat(typeofValues.legacy); + typeofValues.es6 = typeofValues.es3.concat("symbol", "bigint"); - prefix("~", function() { - if (state.option.bitwise) { - warning("W016", this, "~"); - } - this.arity = "unary"; - this.right = expression(150); - return this; - }); + /** + * Validate comparisons between the result of a `typeof` expression and a + * string literal. + * + * @param {token} [left] - one of the values being compared + * @param {token} [right] - the other value being compared + * @param {object} state - the global state object (see `state.js`) + * + * @returns {boolean} - `false` if the second token describes a `typeof` + * expression and the first token is a string literal + * whose value is never returned by that operator; + * `true` otherwise + */ + function isTypoTypeof(left, right, state) { + var values; - prefix("...", function() { - if (!state.inES6(true)) { - warning("W119", this, "spread/rest operator", "6"); - } + if (state.option.notypeof) + return false; - // TODO: Allow all AssignmentExpression - // once parsing permits. - // - // How to handle eg. number, boolean when the built-in - // prototype of may have an @@iterator definition? - // - // Number.prototype[Symbol.iterator] = function * () { - // yield this.valueOf(); - // }; - // - // var a = [ ...1 ]; - // console.log(a); // [1]; - // - // for (let n of [...10]) { - // console.log(n); - // } - // // 10 - // - // - // Boolean.prototype[Symbol.iterator] = function * () { - // yield this.valueOf(); - // }; - // - // var a = [ ...true ]; - // console.log(a); // [true]; - // - // for (let n of [...false]) { - // console.log(n); - // } - // // false - // - if (!state.tokens.next.identifier && - state.tokens.next.type !== "(string)" && - !checkPunctuators(state.tokens.next, ["[", "("])) { + if (!left || !right) + return false; - error("E030", state.tokens.next, state.tokens.next.value); - } - expression(150); - return this; - }); + values = state.inES6() ? typeofValues.es6 : typeofValues.es3; - prefix("!", function() { - this.arity = "unary"; - this.right = expression(150); + if (right.type === "(identifier)" && right.value === "typeof" && left.type === "(string)") { + if (left.value === "bigint") { + if (!state.option.unstable.bigint) { + warning("W144", left, "BigInt", "bigint"); + } - if (!this.right) { // '!' followed by nothing? Give up. - quit("E041", this.line || 0); - } + return false; + } - if (bang[this.right.id] === true) { - warning("W018", this, "!"); + return !_.includes(values, left.value); } - return this; - }); - prefix("typeof", (function() { - var p = expression(150); - this.first = this.right = p; + return false; + } - if (!p) { // 'typeof' followed by nothing? Give up. - quit("E041", this.line || 0, this.character || 0); - } + /** + * Determine if a given token describes the built-in `eval` function. + * + * @param {token} left + * @param {object} state - the global state object (see `state.js`) + * + * @returns {boolean} + */ + function isGlobalEval(left, state) { + var isGlobal = false; - // The `typeof` operator accepts unresolvable references, so the operand - // may be undefined. - if (p.identifier) { - p.forgiveUndef = true; + // permit methods to refer to an "eval" key in their own context + if (left.type === "this" && state.funct["(context)"] === null) { + isGlobal = true; } - return this; - })); - prefix("new", function() { - var mp = metaProperty("target", function() { - if (!state.inES6(true)) { - warning("W119", state.tokens.prev, "new.target", "6"); + // permit use of "eval" members of objects + else if (left.type === "(identifier)") { + if (state.option.node && left.value === "global") { + isGlobal = true; } - var inFunction, c = state.funct; - while (c) { - inFunction = !c["(global)"]; - if (!c["(arrow)"]) { break; } - c = c["(context)"]; - } - if (!inFunction) { - warning("W136", state.tokens.prev, "new.target"); - } - }); - if (mp) { return mp; } - var c = expression(155), i; - if (c && c.id !== "function") { - if (c.identifier) { - c["new"] = true; - switch (c.value) { - case "Number": - case "String": - case "Boolean": - case "Math": - case "JSON": - warning("W053", state.tokens.prev, c.value); - break; - case "Symbol": - if (state.inES6()) { - warning("W053", state.tokens.prev, c.value); - } - break; - case "Function": - if (!state.option.evil) { - warning("W054"); - } - break; - case "Date": - case "RegExp": - case "this": - break; - default: - if (c.id !== "function") { - i = c.value.substr(0, 1); - if (state.option.newcap && (i < "A" || i > "Z") && - !state.funct["(scope)"].isPredefined(c.value)) { - warning("W055", state.tokens.curr); - } - } - } - } else { - if (c.id !== "." && c.id !== "[" && c.id !== "(") { - warning("W056", state.tokens.curr); - } + else if (state.option.browser && (left.value === "window" || left.value === "document")) { + isGlobal = true; } - } else { - if (!state.option.supernew) - warning("W057", this); - } - if (state.tokens.next.id !== "(" && !state.option.supernew) { - warning("W058", state.tokens.curr, state.tokens.curr.value); } - this.first = this.right = c; - return this; - }); - state.syntax["new"].exps = true; - prefix("void").exps = true; + return isGlobal; + } - infix(".", function(left, that) { - var m = identifier(false, true); + /** + * Determine if a given token describes a property of a built-in object. + * + * @param {token} left + * + * @returns {boolean} + */ + function findNativePrototype(left) { + var natives = [ + "Array", "ArrayBuffer", "Boolean", "Collator", "DataView", "Date", + "DateTimeFormat", "Error", "EvalError", "Float32Array", "Float64Array", + "Function", "Infinity", "Intl", "Int16Array", "Int32Array", "Int8Array", + "Iterator", "Number", "NumberFormat", "Object", "RangeError", + "ReferenceError", "RegExp", "StopIteration", "String", "SyntaxError", + "TypeError", "Uint16Array", "Uint32Array", "Uint8Array", "Uint8ClampedArray", + "URIError" + ]; - if (typeof m === "string") { - countMember(m); + function walkPrototype(obj) { + if (typeof obj !== "object") return; + return obj.right === "prototype" ? obj : walkPrototype(obj.left); } - that.left = left; - that.right = m; + function walkNative(obj) { + while (!obj.identifier && typeof obj.left === "object") + obj = obj.left; - if (m && m === "hasOwnProperty" && state.tokens.next.value === "=") { - warning("W001"); + if (obj.identifier && natives.indexOf(obj.value) >= 0 && + state.funct["(scope)"].isPredefined(obj.value)) { + return obj.value; + } } - if (left && left.value === "arguments" && (m === "callee" || m === "caller")) { - if (state.option.noarg) - warning("W059", left, m); - else if (state.isStrict()) - error("E008"); - } else if (!state.option.evil && left && left.value === "document" && - (m === "write" || m === "writeln")) { - warning("W060", left); - } + var prototype = walkPrototype(left); + if (prototype) return walkNative(prototype); + } - if (!state.option.evil && (m === "eval" || m === "execScript")) { - if (isGlobalEval(left, state)) { - warning("W061"); - } - } + /** + * Determine if the given token is a valid assignment target; emit errors + * and/or warnings as appropriate + * + * @param {number} context - the parsing context; see `prod-params.js` for + * more information + * @param {token} left - the left hand side of the assignment + * @param {token=} assignToken - the token for the assignment, used for + * reporting + * @param {object=} options - optional object + * @param {boolean} options.allowDestructuring - whether to allow + * destructuring binding + * + * @returns {boolean} Whether the left hand side is OK + */ + function checkLeftSideAssign(context, left, assignToken, options) { - return that; - }, 160, true); + var allowDestructuring = options && options.allowDestructuring; - infix("(", function(left, that) { - if (state.option.immed && left && !left.immed && left.id === "function") { - warning("W062"); + assignToken = assignToken || left; + + if (state.option.freeze) { + var nativeObject = findNativePrototype(left); + if (nativeObject) + warning("W121", left, nativeObject); } - var n = 0; - var p = []; + if (left.identifier && !left.isMetaProperty) { + // The `reassign` method also calls `modify`, but we are specific in + // order to catch function re-assignment and globals re-assignment + state.funct["(scope)"].block.reassign(left.value, left); + } - if (left) { - if (left.type === "(identifier)") { - if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { - if ("Array Number String Boolean Date Object Error Symbol".indexOf(left.value) === -1) { - if (left.value === "Math") { - warning("W063", left); - } else if (state.option.newcap) { - warning("W064", left); - } - } - } + if (left.id === ".") { + if (!left.left || left.left.value === "arguments" && !state.isStrict()) { + warning("W143", assignToken); } - } - if (state.tokens.next.id !== ")") { - for (;;) { - p[p.length] = expression(10); - n += 1; - if (state.tokens.next.id !== ",") { - break; + state.nameStack.set(state.tokens.prev); + return true; + } else if (left.id === "{" || left.id === "[") { + if (!allowDestructuring || !left.destructAssign) { + if (left.id === "{" || !left.left) { + warning("E031", assignToken); + } else if (left.left.value === "arguments" && !state.isStrict()) { + warning("W143", assignToken); } - comma(); } - } - - advance(")"); - if (typeof left === "object") { - if (!state.inES5() && left.value === "parseInt" && n === 1) { - warning("W065", state.tokens.curr); + if (left.id === "[") { + state.nameStack.set(left.right); } - if (!state.option.evil) { - if (left.value === "eval" || left.value === "Function" || - left.value === "execScript") { - warning("W061", left); - if (p[0] && [0].id === "(string)") { - addInternalSrc(left, p[0].value); - } - } else if (p[0] && p[0].id === "(string)" && - (left.value === "setTimeout" || - left.value === "setInterval")) { - warning("W066", left); - addInternalSrc(left, p[0].value); + return true; + } else if (left.identifier && !isReserved(context, left) && !left.isMetaProperty) { + if (state.funct["(scope)"].bindingtype(left.value) === "exception") { + warning("W022", left); + } - // window.setTimeout/setInterval - } else if (p[0] && p[0].id === "(string)" && - left.value === "." && - left.left.value === "window" && - (left.right === "setTimeout" || - left.right === "setInterval")) { - warning("W066", left); - addInternalSrc(left, p[0].value); + if (left.value === "eval" && state.isStrict()) { + error("E031", assignToken); + return false; + } else if (left.value === "arguments") { + if (!state.isStrict()) { + warning("W143", assignToken); + } else { + error("E031", assignToken); + return false; } } - if (!left.identifier && left.id !== "." && left.id !== "[" && left.id !== "=>" && - left.id !== "(" && left.id !== "&&" && left.id !== "||" && left.id !== "?" && - !(state.inES6() && left["(name)"])) { - warning("W067", that); - } + state.nameStack.set(left); + return true; } - that.left = left; - return that; - }, 155, true).exps = true; - - prefix("(", function() { - var pn = state.tokens.next, pn1, i = -1; - var ret, triggerFnExpr, first, last; - var parens = 1; - var opening = state.tokens.curr; - var preceeding = state.tokens.prev; - var isNecessary = !state.option.singleGroups; + error("E031", assignToken); - do { - if (pn.value === "(") { - parens += 1; - } else if (pn.value === ")") { - parens -= 1; - } + return false; + } - i += 1; - pn1 = pn; - pn = peek(i); - } while (!(parens === 0 && pn1.value === ")") && pn.value !== ";" && pn.type !== "(end)"); + /** + * Convenience function for defining JSHint symbols for assignment operators. + * + * @param {string} s - the name of the symbol + * @param {function} [f] - a function to be invoked that consumes the + * right-hand side of the operator (see the `infix` + * function) + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function assignop(s, f) { + var x = infix(s, typeof f === "function" ? f : function(context, left, that) { + that.left = left; - if (state.tokens.next.id === "function") { - triggerFnExpr = state.tokens.next.immed = true; - } + checkLeftSideAssign(context, left, that, { allowDestructuring: true }); - // If the balanced grouping operator is followed by a "fat arrow", the - // current token marks the beginning of a "fat arrow" function and parsing - // should proceed accordingly. - if (pn.value === "=>") { - return doFunction({ type: "arrow", parsedOpening: true }); - } + that.right = expression(context, 10); - var exprs = []; + return that; + }, 20); - if (state.tokens.next.id !== ")") { - for (;;) { - exprs.push(expression(10)); + x.exps = true; + x.assign = true; - if (state.tokens.next.id !== ",") { - break; - } + return x; + } - if (state.option.nocomma) { - warning("W127"); - } + /** + * Convenience function for defining JSHint symbols for bitwise operators. + * + * @param {string} s - the name of the symbol + * @param {function} [f] - the left denotation function for the symbol; see + * the `expression` function for more detail + * @param {number} p - the left-binding power of the token as used by the + * Pratt parsing semantics + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function bitwise(s, f, p) { + var x = symbol(s, p); + reserveName(x); + x.infix = true; + x.led = (typeof f === "function") ? f : function(context, left) { + if (state.option.bitwise) { + warning("W016", this, this.id); + } + this.left = left; + this.right = expression(context, p); + return this; + }; + return x; + } - comma(); + /** + * Convenience function for defining JSHint symbols for bitwise assignment + * operators. See the `assignop` function for more detail. + * + * @param {string} s - the name of the symbol + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function bitwiseassignop(s) { + symbol(s, 20).exps = true; + return infix(s, function(context, left, that) { + if (state.option.bitwise) { + warning("W016", that, that.id); } - } - advance(")", this); - if (state.option.immed && exprs[0] && exprs[0].id === "function") { - if (state.tokens.next.id !== "(" && - state.tokens.next.id !== "." && state.tokens.next.id !== "[") { - warning("W068", this); - } - } + checkLeftSideAssign(context, left, that); - if (!exprs.length) { - return; - } - if (exprs.length > 1) { - ret = Object.create(state.syntax[","]); - ret.exprs = exprs; + that.right = expression(context, 10); - first = exprs[0]; - last = exprs[exprs.length - 1]; + return that; + }, 20); + } - if (!isNecessary) { - isNecessary = preceeding.assign || preceeding.delim; - } - } else { - ret = first = last = exprs[0]; + /** + * Convenience function for defining JSHint symbols for those operators which + * have a single operand that appears before them in the source code. + * + * @param {string} s - the name of the symbol + * + * @returns {object} - the object describing the JSHint symbol (provided to + * support cases where further refinement is necessary) + */ + function suffix(s) { + var x = symbol(s, 150); - if (!isNecessary) { - isNecessary = - // Used to distinguish from an ExpressionStatement which may not - // begin with the `{` and `function` tokens - (opening.beginsStmt && (ret.id === "{" || triggerFnExpr || isFunctor(ret))) || - // Used to signal that a function expression is being supplied to - // some other operator. - (triggerFnExpr && - // For parenthesis wrapping a function expression to be considered - // necessary, the grouping operator should be the left-hand-side of - // some other operator--either within the parenthesis or directly - // following them. - (!isEndOfExpr() || state.tokens.prev.id !== "}")) || - // Used to demarcate an arrow function as the left-hand side of some - // operator. - (isFunctor(ret) && !isEndOfExpr()) || - // Used as the return value of a single-statement arrow function - (ret.id === "{" && preceeding.id === "=>") || - // Used to delineate an integer number literal from a dereferencing - // punctuator (otherwise interpreted as a decimal point) - (ret.type === "(number)" && - checkPunctuator(pn, ".") && /^\d+$/.test(ret.value)); + x.led = function(context, left) { + // this = suffix e.g. "++" punctuator + // left = symbol operated e.g. "a" identifier or "a.b" punctuator + if (state.option.plusplus) { + warning("W016", this, this.id); } - } - if (ret) { - // The operator may be necessary to override the default binding power of - // neighboring operators (whenever there is an operator in use within the - // first expression *or* the current group contains multiple expressions) - if (!isNecessary && (first.left || first.right || ret.exprs)) { - isNecessary = - (!isBeginOfExpr(preceeding) && first.lbp <= preceeding.lbp) || - (!isEndOfExpr() && last.lbp < state.tokens.next.lbp); - } + checkLeftSideAssign(context, left, this); - if (!isNecessary) { - warning("W126", opening); - } + this.left = left; + return this; + }; + return x; + } - ret.paren = true; + /** + * Retrieve the value of the current token if it is an identifier and + * optionally advance the parser. + * + * @param {number} context - the parsing context; see `prod-params.js` for + * more information + * @param {boolean} [prop] -`true` if this identifier is that of an object + * property + * @param {boolean} [preserve] - `true` if the token should not be consumed + * + * @returns {string|undefined} - the value of the identifier, if present + */ + function optionalidentifier(context, prop, preserve) { + if (!state.tokens.next.identifier) { + return; } - return ret; - }); - - application("=>"); + if (!preserve) { + advance(); + } - infix("[", function(left, that) { - var e = expression(10), s; - if (e && e.type === "(string)") { - if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) { - if (isGlobalEval(left, state)) { - warning("W061"); - } - } + var curr = state.tokens.curr; + var val = state.tokens.curr.value; - countMember(e.value); - if (!state.option.sub && reg.identifier.test(e.value)) { - s = state.syntax[e.value]; - if (!s || !isReserved(s)) { - warning("W069", state.tokens.prev, e.value); - } - } + if (!isReserved(context, curr)) { + return val; } - advance("]", that); - if (e && e.value === "hasOwnProperty" && state.tokens.next.value === "=") { - warning("W001"); + if (prop) { + if (state.inES5()) { + return val; + } } - that.left = left; - that.right = e; - return that; - }, 160, true); + warning("W024", state.tokens.curr, state.tokens.curr.id); + return val; + } - function comprehensiveArrayExpression() { - var res = {}; - res.exps = true; - state.funct["(comparray)"].stack(); + /** + * Consume the "..." token which designates "spread" and "rest" operations if + * it is present. If the operator is repeated, consume every repetition, and + * issue a single error describing the syntax error. + * + * @param {string} operation - either "spread" or "rest" + * + * @returns {boolean} a value describing whether or not any tokens were + * consumed in this way + */ + function spreadrest(operation) { + if (!checkPunctuator(state.tokens.next, "...")) { + return false; + } - // Handle reversed for expressions, used in spidermonkey - var reversed = false; - if (state.tokens.next.value !== "for") { - reversed = true; - if (!state.inMoz()) { - warning("W116", state.tokens.next, "for", state.tokens.next.value); - } - state.funct["(comparray)"].setState("use"); - res.right = expression(10); + if (!state.inES6(true)) { + warning("W119", state.tokens.next, operation + " operator", "6"); } + advance(); - advance("for"); - if (state.tokens.next.value === "each") { - advance("each"); - if (!state.inMoz()) { - warning("W118", state.tokens.curr, "for each"); + if (checkPunctuator(state.tokens.next, "...")) { + warning("E024", state.tokens.next, "..."); + while (checkPunctuator(state.tokens.next, "...")) { + advance(); } } - advance("("); - state.funct["(comparray)"].setState("define"); - res.left = expression(130); - if (_.contains(["in", "of"], state.tokens.next.value)) { - advance(); - } else { - error("E045", state.tokens.curr); - } - state.funct["(comparray)"].setState("generate"); - expression(10); - advance(")"); - if (state.tokens.next.value === "if") { - advance("if"); - advance("("); - state.funct["(comparray)"].setState("filter"); - res.filter = expression(10); - advance(")"); - } + return true; + } - if (!reversed) { - state.funct["(comparray)"].setState("use"); - res.right = expression(10); + /** + * Ensure that the current token is an identifier and retrieve its value. + * + * @param {number} context - the parsing context; see `prod-params.js` for + * more information + * @param {boolean} [prop] -`true` if this identifier is that of an object + * property + * + * @returns {string|undefined} - the value of the identifier, if present + */ + function identifier(context, prop) { + var i = optionalidentifier(context, prop, false); + if (i) { + return i; } - advance("]"); - state.funct["(comparray)"].unstack(); - return res; + error("E030", state.tokens.next, state.tokens.next.value); + + // The token should be consumed after a warning is issued so the parser + // can continue as though an identifier were found. The semicolon token + // should not be consumed in this way so that the parser interprets it as + // a statement delimiter; + if (state.tokens.next.id !== ";") { + advance(); + } } - prefix("[", function() { - var blocktype = lookupBlockType(); - if (blocktype.isCompArray) { - if (!state.option.esnext && !state.inMoz()) { - warning("W118", state.tokens.curr, "array comprehension"); - } - return comprehensiveArrayExpression(); - } else if (blocktype.isDestAssign) { - this.destructAssign = destructuringPattern({ openingParsed: true, assignment: true }); - return this; + + /** + * Determine if the provided token may be evaluated and emit a linting + * warning if this is note the case. + * + * @param {token} controlToken + */ + function reachable(controlToken) { + var i = 0, t; + if (state.tokens.next.id !== ";" || controlToken.inBracelessBlock) { + return; } - var b = state.tokens.curr.line !== startLine(state.tokens.next); - this.first = []; - if (b) { - indent += state.option.indent; - if (state.tokens.next.from === indent + state.option.indent) { - indent += state.option.indent; + for (;;) { + do { + t = peek(i); + i += 1; + } while (t.id !== "(end)" && t.id === "(comment)"); + + if (t.reach) { + return; } - } - while (state.tokens.next.id !== "(end)") { - while (state.tokens.next.id === ",") { - if (!state.option.elision) { - if (!state.inES5()) { - // Maintain compat with old options --- ES5 mode without - // elision=true will warn once per comma - warning("W070"); - } else { - warning("W128"); - do { - advance(","); - } while (state.tokens.next.id === ","); - continue; + if (t.id !== "(endline)") { + if (t.id === "function") { + if (state.option.latedef === true) { + warning("W026", t); } + break; } - advance(","); - } - if (state.tokens.next.id === "]") { + warning("W027", t, t.value, controlToken.value); break; } + } + } - this.first.push(expression(10)); - if (state.tokens.next.id === ",") { - comma({ allowTrailing: true }); - if (state.tokens.next.id === "]" && !state.inES5()) { - warning("W070", state.tokens.curr); - break; + /** + * Consume the semicolon that delimits the statement currently being parsed, + * emitting relevant warnings/errors as appropriate. + * + * @param {token} stmt - token describing the statement under consideration + */ + function parseFinalSemicolon(stmt) { + if (state.tokens.next.id !== ";") { + // don't complain about unclosed templates / strings + if (state.tokens.next.isUnclosed) return advance(); + + var isSameLine = sameLine(state.tokens.curr, state.tokens.next) && + state.tokens.next.id !== "(end)"; + var blockEnd = checkPunctuator(state.tokens.next, "}"); + + if (isSameLine && !blockEnd && !(stmt.id === "do" && state.inES6(true))) { + errorAt("E058", state.tokens.curr.line, state.tokens.curr.character); + } else if (!state.option.asi) { + + // If this is the last statement in a block that ends on the same line + // *and* option lastsemic is on, ignore the warning. Otherwise, issue + // a warning about missing semicolon. + if (!(blockEnd && isSameLine && state.option.lastsemic)) { + warningAt("W033", state.tokens.curr.line, state.tokens.curr.character); } - } else { - break; } + } else { + advance(";"); } - if (b) { - indent -= state.option.indent; - } - advance("]", this); - return this; - }); + } + /** + * Consume a statement. + * + * @param {number} context - the parsing context; see `prod-params.js` for + * more information + * + * @returns {token} - the token describing the statement + */ + function statement(context) { + var i = indent, r, t = state.tokens.next, hasOwnScope = false; - function isMethod() { - return state.funct["(statement)"] && state.funct["(statement)"].type === "class" || - state.funct["(context)"] && state.funct["(context)"]["(verb)"] === "class"; - } + context |= prodParams.initial; + if (t.id === ";") { + advance(";"); + return; + } - function isPropertyName(token) { - return token.identifier || token.id === "(string)" || token.id === "(number)"; - } + // Is this a labelled statement? + var res = isReserved(context, t); + // We're being more tolerant here: if someone uses + // a FutureReservedWord (that is not meant to start a statement) + // as a label, we warn but proceed anyway. - function propertyName(preserveOrToken) { - var id; - var preserve = true; - if (typeof preserveOrToken === "object") { - id = preserveOrToken; - } else { - preserve = preserveOrToken; - id = optionalidentifier(false, true, preserve); + if (res && t.meta && t.meta.isFutureReservedWord && !t.fud) { + warning("W024", t, t.id); + res = false; } - if (!id) { - if (state.tokens.next.id === "(string)") { - id = state.tokens.next.value; - if (!preserve) { - advance(); - } - } else if (state.tokens.next.id === "(number)") { - id = state.tokens.next.value.toString(); - if (!preserve) { - advance(); - } + if (t.identifier && !res && peek().id === ":") { + advance(); + advance(":"); + + hasOwnScope = true; + state.funct["(scope)"].stack(); + state.funct["(scope)"].block.addLabel(t.value, { token: state.tokens.curr }); + + if (!state.tokens.next.labelled && state.tokens.next.value !== "{") { + warning("W028", state.tokens.next, t.value, state.tokens.next.value); } - } else if (typeof id === "object") { - if (id.id === "(string)" || id.id === "(identifier)") id = id.value; - else if (id.id === "(number)") id = id.value.toString(); - } - if (id === "hasOwnProperty") { - warning("W001"); + t = state.tokens.next; } - return id; - } + // Is it a lonely block? - /** - * @param {Object} [options] - * @param {token} [options.loneArg] The argument to the function in cases - * where it was defined using the - * single-argument shorthand. - * @param {bool} [options.parsedOpening] Whether the opening parenthesis has - * already been parsed. - * @returns {{ arity: number, params: Array.}} - */ - function functionparams(options) { - var next; - var paramsIds = []; - var ident; - var tokens = []; - var t; - var pastDefault = false; - var pastRest = false; - var arity = 0; - var loneArg = options && options.loneArg; + if (t.id === "{") { + // Is it a switch case block? + // + // switch (foo) { + // case bar: { <= here. + // ... + // } + // } + var iscase = (state.funct["(verb)"] === "case" && state.tokens.curr.value === ":"); + block(context, true, true, false, false, iscase); - if (loneArg && loneArg.identifier === true) { - state.funct["(scope)"].addParam(loneArg.value, loneArg); - return { arity: 1, params: [ loneArg.value ] }; + if (hasOwnScope) { + state.funct["(scope)"].unstack(); + } + + return; } - next = state.tokens.next; + // Parse the statement. - if (!options || !options.parsedOpening) { - advance("("); - } + r = expression(context, 0); - if (state.tokens.next.id === ")") { - advance(")"); - return; + if (r && !(r.identifier && r.value === "function") && + !(r.type === "(punctuator)" && r.left && + r.left.identifier && r.left.value === "function")) { + if (!state.isStrict() && state.stmtMissingStrict()) { + warning("E007"); + } } - function addParam(addParamArgs) { - state.funct["(scope)"].addParam.apply(state.funct["(scope)"], addParamArgs); + // Look for the final semicolon. + + if (!t.block) { + if (!state.option.expr && (!r || !r.exps)) { + warning("W030", state.tokens.curr); + } else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") { + warning("W031", t); + } + + parseFinalSemicolon(t); } - for (;;) { - arity++; - // are added to the param scope - var currentParams = []; - if (_.contains(["{", "["], state.tokens.next.id)) { - tokens = destructuringPattern(); - for (t in tokens) { - t = tokens[t]; - if (t.id) { - paramsIds.push(t.id); - currentParams.push([t.id, t.token]); - } - } - } else { - if (checkPunctuator(state.tokens.next, "...")) pastRest = true; - ident = identifier(true); - if (ident) { - paramsIds.push(ident); - currentParams.push([ident, state.tokens.curr]); - } else { - // Skip invalid parameter. - while (!checkPunctuators(state.tokens.next, [",", ")"])) advance(); - } - } + // Restore the indentation. - // It is valid to have a regular argument after a default argument - // since undefined can be used for missing parameters. Still warn as it is - // a possible code smell. - if (pastDefault) { - if (state.tokens.next.id !== "=") { - error("W138", state.tokens.current); - } - } - if (state.tokens.next.id === "=") { - if (!state.inES6()) { - warning("W119", state.tokens.next, "default parameters", "6"); - } - advance("="); - pastDefault = true; - expression(10); - } + indent = i; + if (hasOwnScope) { + state.funct["(scope)"].unstack(); + } + return r; + } - // now we have evaluated the default expression, add the variable to the param scope - currentParams.forEach(addParam); + /** + * Consume a series of statements until encountering either the end of the + * program or a token that interrupts control flow. + * + * @param {number} context - the parsing context; see `prod-params.js` for + * more information + * + * @returns {Array} - the tokens consumed + */ + function statements(context) { + var a = [], p; - if (state.tokens.next.id === ",") { - if (pastRest) { - warning("W131", state.tokens.next); + while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") { + if (state.tokens.next.id === ";") { + p = peek(); + + if (!p || (p.id !== "(" && p.id !== "[")) { + warning("W032"); } - comma(); + + advance(";"); } else { - advance(")", next); - return { arity: arity, params: paramsIds }; + a.push(statement(context)); } } + return a; } - function functor(name, token, overwrites) { - var funct = { - "(name)" : name, - "(breakage)" : 0, - "(loopage)" : 0, - "(tokens)" : {}, - "(properties)": {}, - "(catch)" : false, - "(global)" : false, + /** + * Parse any directives in a directive prologue. + */ + function directives() { + var current = state.tokens.next; + while (state.tokens.next.id === "(string)") { + var next = peekIgnoreEOL(); + if (!isEndOfExpr(0, current, next)) { + break; + } + current = next; - "(line)" : null, - "(character)" : null, - "(metrics)" : null, - "(statement)" : null, - "(context)" : null, - "(scope)" : null, - "(comparray)" : null, - "(generator)" : null, - "(arrow)" : null, - "(params)" : null - }; + advance(); + var directive = state.tokens.curr.value; + if (state.directive[directive] || + (directive === "use strict" && state.option.strict === "implied")) { + warning("W034", state.tokens.curr, directive); + } - if (token) { - _.extend(funct, { - "(line)" : token.line, - "(character)": token.character, - "(metrics)" : createMetrics(token) - }); - } + // From ECMAScript 2016: + // + // > 14.1.2 Static Semantics: Early Errors + // > + // > [...] + // > - It is a Syntax Error if ContainsUseStrict of FunctionBody is true + // > and IsSimpleParameterList of FormalParameters is false. + if (directive === "use strict" && state.inES7() && + !state.funct["(global)"] && state.funct["(hasSimpleParams)"] === false) { + error("E065", state.tokens.curr); + } - _.extend(funct, overwrites); + // there's no directive negation, so always set to true + state.directive[directive] = true; - if (funct["(context)"]) { - funct["(scope)"] = funct["(context)"]["(scope)"]; - funct["(comparray)"] = funct["(context)"]["(comparray)"]; + parseFinalSemicolon(current); } - return funct; - } - - function isFunctor(token) { - return "(scope)" in token; + if (state.isStrict()) { + state.option.undef = true; + } } /** - * Determine if the parser has begun parsing executable code. + * Parses a single block. A block is a sequence of statements wrapped in + * braces. * - * @param {Token} funct - The current "functor" token + * @param {number} context - parsing context + * @param {boolean} ordinary - `true` for everything but function bodies and + * try blocks + * @param {boolean} [stmt] - `true` if block can be a single statement (e.g. + * in if/for/while) + * @param {boolean} [isfunc] - `true` if block is a function body + * @param {boolean} [isfatarrow] - `true` if its a body of a fat arrow + * function + * @param {boolean} [iscase] - `true` if block is a switch case block * - * @returns {boolean} + * @returns {token} - the token describing the block */ - function hasParsedCode(funct) { - return funct["(global)"] && !funct["(verb)"]; - } + function block(context, ordinary, stmt, isfunc, isfatarrow, iscase) { + var a, + b = inblock, + old_indent = indent, + m, + t, + d; - function doTemplateLiteral(left) { - // ASSERT: this.type === "(template)" - // jshint validthis: true - var ctx = this.context; - var noSubst = this.noSubst; - var depth = this.depth; + inblock = ordinary; - if (!noSubst) { - while (!end()) { - if (!state.tokens.next.template || state.tokens.next.depth > depth) { - expression(0); // should probably have different rbp? - } else { - // skip template start / middle - advance(); - } - } - } + t = state.tokens.next; - return { - id: "(template)", - type: "(template)", - tag: left - }; + var metrics = state.funct["(metrics)"]; + metrics.nestedBlockDepth += 1; + metrics.verifyMaxNestedBlockDepthPerFunction(); - function end() { - if (state.tokens.curr.template && state.tokens.curr.tail && - state.tokens.curr.context === ctx) return true; - var complete = (state.tokens.next.template && state.tokens.next.tail && - state.tokens.next.context === ctx); - if (complete) advance(); - return complete || state.tokens.next.isUnclosed; - } - } + if (state.tokens.next.id === "{") { + advance("{"); - /** - * @param {Object} [options] - * @param {token} [options.name] The identifier belonging to the function (if - * any) - * @param {boolean} [options.statement] The statement that triggered creation - * of the current function. - * @param {string} [options.type] If specified, either "generator" or "arrow" - * @param {token} [options.loneArg] The argument to the function in cases - * where it was defined using the - * single-argument shorthand - * @param {bool} [options.parsedOpening] Whether the opening parenthesis has - * already been parsed - * @param {token} [options.classExprBinding] Define a function with this - * identifier in the new function's - * scope, mimicking the bahavior of - * class expression names within - * the body of member functions. - */ - function doFunction(options) { - var f, token, name, statement, classExprBinding, isGenerator, isArrow, ignoreLoopFunc; - var oldOption = state.option; - var oldIgnored = state.ignored; + // create a new block scope + state.funct["(scope)"].stack(); - if (options) { - name = options.name; - statement = options.statement; - classExprBinding = options.classExprBinding; - isGenerator = options.type === "generator"; - isArrow = options.type === "arrow"; - ignoreLoopFunc = options.ignoreLoopFunc; - } - - state.option = Object.create(state.option); - state.ignored = Object.create(state.ignored); + if (state.tokens.next.id !== "}") { + indent += state.option.indent; + while (!ordinary && state.tokens.next.from > indent) { + indent += state.option.indent; + } - state.funct = functor(name || state.nameStack.infer(), state.tokens.next, { - "(statement)": statement, - "(context)": state.funct, - "(arrow)": isArrow, - "(generator)": isGenerator - }); + if (isfunc) { + m = {}; + for (d in state.directive) { + m[d] = state.directive[d]; + } + directives(); - f = state.funct; - token = state.tokens.curr; - token.funct = state.funct; + state.funct["(isStrict)"] = state.isStrict(); - functions.push(state.funct); + if (state.option.strict && state.funct["(context)"]["(global)"]) { + if (!m["use strict"] && !state.isStrict()) { + warning("E007"); + } + } + } - // So that the function is available to itself and referencing itself is not - // seen as a closure, add the function name to a new scope, but do not - // test for unused (unused: false) - // it is a new block scope so that params can override it, it can be block scoped - // but declarations inside the function don't cause already declared error - state.funct["(scope)"].stack("functionouter"); - var internallyAccessibleName = name || classExprBinding; - if (internallyAccessibleName) { - state.funct["(scope)"].block.add(internallyAccessibleName, - classExprBinding ? "class" : "function", state.tokens.curr, false); - } + a = statements(context); - // create the param scope (params added in functionparams) - state.funct["(scope)"].stack("functionparams"); + metrics.statementCount += a.length; - var paramsInfo = functionparams(options); + indent -= state.option.indent; + } else if (isfunc) { + // Ensure property is set for functions with empty bodies. + state.funct["(isStrict)"] = state.isStrict(); + } - if (paramsInfo) { - state.funct["(params)"] = paramsInfo.params; - state.funct["(metrics)"].arity = paramsInfo.arity; - state.funct["(metrics)"].verifyMaxParametersPerFunction(); - } else { - state.funct["(metrics)"].arity = 0; - } + advance("}", t); - if (isArrow) { - if (!state.inES6(true)) { - warning("W119", state.tokens.curr, "arrow function syntax (=>)", "6"); + if (isfunc) { + state.funct["(scope)"].validateParams(isfatarrow); + if (m) { + state.directive = m; + } } - if (!options.loneArg) { - advance("=>"); - } - } + state.funct["(scope)"].unstack(); - block(false, true, true, isArrow); + indent = old_indent; + } else if (!ordinary) { + if (isfunc) { + state.funct["(scope)"].stack(); - if (!state.option.noyield && isGenerator && - state.funct["(generator)"] !== "yielded") { - warning("W124", state.tokens.curr); - } + if (stmt && !isfatarrow && !state.inMoz()) { + error("W118", state.tokens.curr, "function closure expressions"); + } - state.funct["(metrics)"].verifyMaxStatementsPerFunction(); - state.funct["(metrics)"].verifyMaxComplexityPerFunction(); - state.funct["(unusedOption)"] = state.option.unused; - state.option = oldOption; - state.ignored = oldIgnored; - state.funct["(last)"] = state.tokens.curr.line; - state.funct["(lastcharacter)"] = state.tokens.curr.character; + if (isfatarrow) { + state.funct["(scope)"].validateParams(true); + } - // unstack the params scope - state.funct["(scope)"].unstack(); // also does usage and label checks + var expr = expression(context, 10); - // unstack the function outer stack - state.funct["(scope)"].unstack(); + if (state.option.noreturnawait && context & prodParams.async && + expr.identifier && expr.value === "await") { + warning("W146", expr); + } - state.funct = state.funct["(context)"]; + if (state.option.strict && state.funct["(context)"]["(global)"]) { + if (!state.isStrict()) { + warning("E007"); + } + } - if (!ignoreLoopFunc && !state.option.loopfunc && state.funct["(loopage)"]) { - // If the function we just parsed accesses any non-local variables - // trigger a warning. Otherwise, the function is safe even within - // a loop. - if (f["(isCapturing)"]) { - warning("W083", token); + state.funct["(scope)"].unstack(); + } else { + error("E021", state.tokens.next, "{", state.tokens.next.value); } - } - - return f; - } + } else { - function createMetrics(functionStartToken) { - return { - statementCount: 0, - nestedBlockDepth: -1, - ComplexityCount: 1, - arity: 0, + state.funct["(scope)"].stack(); - verifyMaxStatementsPerFunction: function() { - if (state.option.maxstatements && - this.statementCount > state.option.maxstatements) { - warning("W071", functionStartToken, this.statementCount); - } - }, + if (!stmt || state.option.curly) { + warning("W116", state.tokens.next, "{", state.tokens.next.value); + } - verifyMaxParametersPerFunction: function() { - if (_.isNumber(state.option.maxparams) && - this.arity > state.option.maxparams) { - warning("W072", functionStartToken, this.arity); - } - }, + // JSHint observes Annex B of the ECMAScript specification by default, + // where function declarations are permitted in the statement positions + // of IfStatements. + var supportsFnDecl = state.funct["(verb)"] === "if" || + state.tokens.curr.id === "else"; - verifyMaxNestedBlockDepthPerFunction: function() { - if (state.option.maxdepth && - this.nestedBlockDepth > 0 && - this.nestedBlockDepth === state.option.maxdepth + 1) { - warning("W073", null, this.nestedBlockDepth); - } - }, + state.tokens.next.inBracelessBlock = true; + indent += state.option.indent; + // test indentation only if statement is in new line + a = [statement(context)]; + indent -= state.option.indent; - verifyMaxComplexityPerFunction: function() { - var max = state.option.maxcomplexity; - var cc = this.ComplexityCount; - if (max && cc > max) { - warning("W074", functionStartToken, cc); - } + if (a[0] && a[0].declaration && + !(supportsFnDecl && a[0].id === "function")) { + error("E048", a[0], a[0].id[0].toUpperCase() + a[0].id.slice(1)); } - }; - } - - function increaseComplexityCount() { - state.funct["(metrics)"].ComplexityCount += 1; - } - // Parse assignments that were found instead of conditionals. - // For example: if (a = 1) { ... } + state.funct["(scope)"].unstack(); + } - function checkCondAssignment(expr) { - var id, paren; - if (expr) { - id = expr.id; - paren = expr.paren; - if (id === "," && (expr = expr.exprs[expr.exprs.length - 1])) { - id = expr.id; - paren = paren || expr.paren; + // Don't clear and let it propagate out if it is "break", "return" or + // similar in switch case + switch (state.funct["(verb)"]) { + case "break": + case "continue": + case "return": + case "throw": + if (iscase) { + break; } + + /* falls through */ + default: + state.funct["(verb)"] = null; } - switch (id) { - case "=": - case "+=": - case "-=": - case "*=": - case "%=": - case "&=": - case "|=": - case "^=": - case "/=": - if (!paren && !state.option.boss) { - warning("W084"); - } + + inblock = b; + if (ordinary && state.option.noempty && (!a || a.length === 0)) { + warning("W035", state.tokens.prev); } + metrics.nestedBlockDepth -= 1; + return a; } + /** - * @param {object} props Collection of property descriptors for a given - * object. + * Update the global state which tracks all statically-identifiable property + * names, and emit a warning if the `members` linting directive is in use and + * does not include the given name. + * + * @param {string} m - the property name */ - function checkProperties(props) { - // Check for lonely setters if in the ES5 mode. - if (state.inES5()) { - for (var name in props) { - if (props[name] && props[name].setterToken && !props[name].getterToken) { - warning("W078", props[name].setterToken); - } - } + function countMember(m) { + if (membersOnly && typeof membersOnly[m] !== "boolean") { + warning("W036", state.tokens.curr, m); } - } - - function metaProperty(name, c) { - if (checkPunctuator(state.tokens.next, ".")) { - var left = state.tokens.curr.id; - advance("."); - var id = identifier(); - state.tokens.curr.isMetaProperty = true; - if (name !== id) { - error("E057", state.tokens.prev, left, id); - } else { - c(); - } - return state.tokens.curr; + if (typeof member[m] === "number") { + member[m] += 1; + } else { + member[m] = 1; } } - (function(x) { - x.nud = function() { - var b, f, i, p, t, isGeneratorMethod = false, nextVal; - var props = Object.create(null); // All properties, including accessors - - b = state.tokens.curr.line !== startLine(state.tokens.next); - if (b) { - indent += state.option.indent; - if (state.tokens.next.from === indent + state.option.indent) { - indent += state.option.indent; - } - } + // Build the syntax table by declaring the syntactic elements of the language. - var blocktype = lookupBlockType(); - if (blocktype.isDestAssign) { - this.destructAssign = destructuringPattern({ openingParsed: true, assignment: true }); - return this; - } + type("(number)", function() { + if (state.tokens.next.id === ".") { + warning("W005", this); + } - for (;;) { - if (state.tokens.next.id === "}") { - break; - } + return this; + }); - nextVal = state.tokens.next.value; - if (state.tokens.next.identifier && - (peekIgnoreEOL().id === "," || peekIgnoreEOL().id === "}")) { - if (!state.inES6()) { - warning("W104", state.tokens.next, "object short notation", "6"); - } - i = propertyName(true); - saveProperty(props, i, state.tokens.next); + type("(string)", function() { + return this; + }); - expression(10); + state.syntax["(identifier)"] = { + type: "(identifier)", + lbp: 0, + identifier: true, - } else if (peek().id !== ":" && (nextVal === "get" || nextVal === "set")) { - advance(nextVal); + nud: function(context) { + var v = this.value; + // If this identifier is the lone parameter to a shorthand "fat arrow" + // function definition, i.e. + // + // x => x; + // + // ...it should not be considered as a variable in the current scope. It + // will be added to the scope of the new function when the next token is + // parsed, so it can be safely ignored for now. + var isLoneArrowParam = state.tokens.next.id === "=>"; - if (!state.inES5()) { - error("E034"); - } - - i = propertyName(); + if (isReserved(context, this)) { + warning("W024", this, v); + } else if (!isLoneArrowParam && !state.funct["(comparray)"].check(v)) { + state.funct["(scope)"].block.use(v, state.tokens.curr); + } - // ES6 allows for get() {...} and set() {...} method - // definition shorthand syntax, so we don't produce an error - // if linting ECMAScript 6 code. - if (!i && !state.inES6()) { - error("E035"); - } + return this; + }, - // We don't want to save this getter unless it's an actual getter - // and not an ES6 concise method - if (i) { - saveAccessor(nextVal, props, i, state.tokens.curr); - } + led: function() { + /* istanbul ignore next */ + error("E033", state.tokens.next, state.tokens.next.value); + } + }; - t = state.tokens.next; - f = doFunction(); - p = f["(params)"]; + var baseTemplateSyntax = { + identifier: false, + template: true, + }; + state.syntax["(template)"] = _.extend({ + lbp: 155, + type: "(template)", + nud: doTemplateLiteral, + led: doTemplateLiteral, + noSubst: false + }, baseTemplateSyntax); - // Don't warn about getter/setter pairs if this is an ES6 concise method - if (nextVal === "get" && i && p) { - warning("W076", t, p[0], i); - } else if (nextVal === "set" && i && (!p || p.length !== 1)) { - warning("W077", t, i); - } - } else { - if (state.tokens.next.value === "*" && state.tokens.next.type === "(punctuator)") { - if (!state.inES6()) { - warning("W104", state.tokens.next, "generator functions", "6"); - } - advance("*"); - isGeneratorMethod = true; - } else { - isGeneratorMethod = false; - } + state.syntax["(template middle)"] = _.extend({ + lbp: 0, + type: "(template middle)", + noSubst: false + }, baseTemplateSyntax); - if (state.tokens.next.id === "[") { - i = computedPropertyName(); - state.nameStack.set(i); - } else { - state.nameStack.set(state.tokens.next); - i = propertyName(); - saveProperty(props, i, state.tokens.next); + state.syntax["(template tail)"] = _.extend({ + lbp: 0, + type: "(template tail)", + tail: true, + noSubst: false + }, baseTemplateSyntax); - if (typeof i !== "string") { - break; - } - } + state.syntax["(no subst template)"] = _.extend({ + lbp: 155, + type: "(template)", + nud: doTemplateLiteral, + led: doTemplateLiteral, + noSubst: true, + tail: true // mark as tail, since it's always the last component + }, baseTemplateSyntax); - if (state.tokens.next.value === "(") { - if (!state.inES6()) { - warning("W104", state.tokens.curr, "concise methods", "6"); - } - doFunction({ type: isGeneratorMethod ? "generator" : null }); - } else { - advance(":"); - expression(10); - } - } + type("(regexp)", function() { + return this; + }); - countMember(i); + // ECMAScript parser - if (state.tokens.next.id === ",") { - comma({ allowTrailing: true, property: true }); - if (state.tokens.next.id === ",") { - warning("W070", state.tokens.curr); - } else if (state.tokens.next.id === "}" && !state.inES5()) { - warning("W070", state.tokens.curr); - } - } else { - break; - } - } - if (b) { - indent -= state.option.indent; - } - advance("}", this); + delim("(endline)"); + (function(x) { + x.line = x.from = 0; + })(delim("(begin)")); + delim("(end)").reach = true; + delim("(error)").reach = true; + delim("}").reach = true; + delim(")"); + delim("]"); + delim("\"").reach = true; + delim("'").reach = true; + delim(";"); + delim(":").reach = true; + delim("#"); - checkProperties(props); + reserve("else"); + reserve("case").reach = true; + reserve("catch"); + reserve("default").reach = true; + reserve("finally"); + reserve("true", function() { return this; }); + reserve("false", function() { return this; }); + reserve("null", function() { return this; }); + reserve("this", function() { + if (state.isStrict() && !isMethod() && + !state.option.validthis && ((state.funct["(statement)"] && + state.funct["(name)"].charAt(0) > "Z") || state.funct["(global)"])) { + warning("W040", this); + } - return this; - }; - x.fud = function() { - error("E036", state.tokens.curr); - }; - }(delim("{"))); + return this; + }); + reserve("super", function() { + superNud.call(state.tokens.curr, this); - function destructuringPattern(options) { - var isAssignment = options && options.assignment; + return this; + }); - if (!state.inES6()) { - warning("W104", state.tokens.curr, - isAssignment ? "destructuring assignment" : "destructuring binding", "6"); + assignop("=", "assign"); + assignop("+=", "assignadd"); + assignop("-=", "assignsub"); + assignop("*=", "assignmult"); + assignop("/=", "assigndiv").nud = function() { + /* istanbul ignore next */ + error("E014"); + }; + assignop("%=", "assignmod"); + assignop("**=", function(context, left, that) { + if (!state.inES7()) { + warning("W119", that, "Exponentiation operator", "7"); } - return destructuringPatternRecursive(options); - } - - function destructuringPatternRecursive(options) { - var ids; - var identifiers = []; - var openingParsed = options && options.openingParsed; - var isAssignment = options && options.assignment; - var recursiveOptions = isAssignment ? { assignment: isAssignment } : null; - var firstToken = openingParsed ? state.tokens.curr : state.tokens.next; + that.left = left; - var nextInnerDE = function() { - var ident; - if (checkPunctuators(state.tokens.next, ["[", "{"])) { - ids = destructuringPatternRecursive(recursiveOptions); - for (var id in ids) { - id = ids[id]; - identifiers.push({ id: id.id, token: id.token }); - } - } else if (checkPunctuator(state.tokens.next, ",")) { - identifiers.push({ id: null, token: state.tokens.curr }); - } else if (checkPunctuator(state.tokens.next, "(")) { - advance("("); - nextInnerDE(); - advance(")"); - } else { - var is_rest = checkPunctuator(state.tokens.next, "..."); + checkLeftSideAssign(context, left, that); - if (isAssignment) { - var identifierToken = is_rest ? peek(0) : state.tokens.next; - if (!identifierToken.identifier) { - warning("E030", identifierToken, identifierToken.value); - } - var assignTarget = expression(155); - if (assignTarget) { - checkLeftSideAssign(assignTarget); + that.right = expression(context, 10); - // if the target was a simple identifier, add it to the list to return - if (assignTarget.identifier) { - ident = assignTarget.value; - } - } - } else { - ident = identifier(); - } - if (ident) { - identifiers.push({ id: ident, token: state.tokens.curr }); - } - return is_rest; - } - return false; - }; - var assignmentProperty = function() { - var id; - if (checkPunctuator(state.tokens.next, "[")) { - advance("["); - expression(10); - advance("]"); - advance(":"); - nextInnerDE(); - } else if (state.tokens.next.id === "(string)" || - state.tokens.next.id === "(number)") { - advance(); - advance(":"); - nextInnerDE(); - } else { - // this id will either be the property name or the property name and the assigning identifier - id = identifier(); - if (checkPunctuator(state.tokens.next, ":")) { - advance(":"); - nextInnerDE(); - } else if (id) { - // in this case we are assigning (not declaring), so check assignment - if (isAssignment) { - checkLeftSideAssign(state.tokens.curr); - } - identifiers.push({ id: id, token: state.tokens.curr }); - } - } - }; - if (checkPunctuator(firstToken, "[")) { - if (!openingParsed) { - advance("["); - } - if (checkPunctuator(state.tokens.next, "]")) { - warning("W137", state.tokens.curr); - } - var element_after_rest = false; - while (!checkPunctuator(state.tokens.next, "]")) { - if (nextInnerDE() && !element_after_rest && - checkPunctuator(state.tokens.next, ",")) { - warning("W130", state.tokens.next); - element_after_rest = true; - } - if (checkPunctuator(state.tokens.next, "=")) { - if (checkPunctuator(state.tokens.prev, "...")) { - advance("]"); - } else { - advance("="); - } - if (state.tokens.next.id === "undefined") { - warning("W080", state.tokens.prev, state.tokens.prev.value); - } - expression(10); - } - if (!checkPunctuator(state.tokens.next, "]")) { - advance(","); - } - } - advance("]"); - } else if (checkPunctuator(firstToken, "{")) { + return that; + }); - if (!openingParsed) { - advance("{"); - } - if (checkPunctuator(state.tokens.next, "}")) { - warning("W137", state.tokens.curr); - } - while (!checkPunctuator(state.tokens.next, "}")) { - assignmentProperty(); - if (checkPunctuator(state.tokens.next, "=")) { - advance("="); - if (state.tokens.next.id === "undefined") { - warning("W080", state.tokens.prev, state.tokens.prev.value); - } - expression(10); - } - if (!checkPunctuator(state.tokens.next, "}")) { - advance(","); - if (checkPunctuator(state.tokens.next, "}")) { - // Trailing comma - // ObjectBindingPattern: { BindingPropertyList , } - break; - } - } - } - advance("}"); + bitwiseassignop("&="); + bitwiseassignop("|="); + bitwiseassignop("^="); + bitwiseassignop("<<="); + bitwiseassignop(">>="); + bitwiseassignop(">>>="); + infix(",", function(context, left, that) { + if (state.option.nocomma) { + warning("W127", that); } - return identifiers; - } - - function destructuringPatternMatch(tokens, value) { - var first = value.first; - if (!first) - return; + that.left = left; - _.zip(tokens, Array.isArray(first) ? first : [ first ]).forEach(function(val) { - var token = val[0]; - var value = val[1]; - - if (token && value) - token.first = value; - else if (token && token.first && !value) - warning("W080", token.first, token.first.value); - }); - } + if (checkComma()) { + that.right = expression(context, 10); + } else { + that.right = null; + } - function blockVariableStatement(type, statement, context) { - // used for both let and const statements + return that; + }, 10, true); - var prefix = context && context.prefix; - var inexport = context && context.inexport; - var isLet = type === "let"; - var isConst = type === "const"; - var tokens, lone, value, letblock; + infix("?", function(context, left, that) { + increaseComplexityCount(); + that.left = left; + that.right = expression(context & ~prodParams.noin, 10); + advance(":"); + expression(context, 10); + return that; + }, 30); - if (!state.inES6()) { - warning("W104", state.tokens.curr, type, "6"); + var orPrecendence = 40; + infix("||", function(context, left, that) { + increaseComplexityCount(); + that.left = left; + that.right = expression(context, orPrecendence); + return that; + }, orPrecendence); + infix("&&", "and", 50); + // The Exponentiation operator, introduced in ECMAScript 2016 + // + // ExponentiationExpression[Yield] : + // UnaryExpression[?Yield] + // UpdateExpression[?Yield] ** ExponentiationExpression[?Yield] + infix("**", function(context, left, that) { + if (!state.inES7()) { + warning("W119", that, "Exponentiation operator", "7"); } - if (isLet && state.tokens.next.value === "(") { - if (!state.inMoz()) { - warning("W118", state.tokens.next, "let block"); - } - advance("("); - state.funct["(scope)"].stack(); - letblock = true; - } else if (state.funct["(noblockscopedvar)"]) { - error("E048", state.tokens.curr, isConst ? "Const" : "Let"); + // Disallow UnaryExpressions which are not wrapped in parenthesis + if (!left.paren && beginsUnaryExpression(left)) { + error("E024", that, "**"); } - statement.first = []; - for (;;) { - var names = []; - if (_.contains(["{", "["], state.tokens.next.value)) { - tokens = destructuringPattern(); - lone = false; - } else { - tokens = [ { id: identifier(), token: state.tokens.curr } ]; - lone = true; - } - - if (!prefix && isConst && state.tokens.next.id !== "=") { - warning("E012", state.tokens.curr, state.tokens.curr.value); - } - - for (var t in tokens) { - if (tokens.hasOwnProperty(t)) { - t = tokens[t]; - if (state.funct["(scope)"].block.isGlobal()) { - if (predefined[t.id] === false) { - warning("W079", t.token, t.id); - } - } - if (t.id && !state.funct["(noblockscopedvar)"]) { - state.funct["(scope)"].addlabel(t.id, { - type: type, - token: t.token }); - names.push(t.token); - - if (lone && inexport) { - state.funct["(scope)"].setExported(t.token.value, t.token); - } - } - } - } - - if (state.tokens.next.id === "=") { - advance("="); - if (!prefix && state.tokens.next.id === "undefined") { - warning("W080", state.tokens.prev, state.tokens.prev.value); - } - if (!prefix && peek(0).id === "=" && state.tokens.next.identifier) { - warning("W120", state.tokens.next, state.tokens.next.value); - } - // don't accept `in` in expression if prefix is used for ForIn/Of loop. - value = expression(prefix ? 120 : 10); - if (lone) { - tokens[0].first = value; - } else { - destructuringPatternMatch(names, value); - } - } - - statement.first = statement.first.concat(names); + that.left = left; + that.right = expression(context, that.rbp); + return that; + }, 150); + state.syntax["**"].rbp = 140; + bitwise("|", "bitor", 70); + bitwise("^", "bitxor", 80); + bitwise("&", "bitand", 90); + relation("==", function(context, left, right) { + var eqnull = state.option.eqnull && + ((left && left.value) === "null" || (right && right.value) === "null"); - if (state.tokens.next.id !== ",") { + switch (true) { + case !eqnull && state.option.eqeqeq: + this.from = this.character; + warning("W116", this, "===", "=="); + break; + /* istanbul ignore next */ + case isTypoTypeof(right, left, state): + warning("W122", this, right.value); + break; + case isTypoTypeof(left, right, state): + warning("W122", this, left.value); break; - } - comma(); - } - if (letblock) { - advance(")"); - block(true, true); - statement.block = true; - state.funct["(scope)"].unstack(); } - return statement; - } - - var conststatement = stmt("const", function(context) { - return blockVariableStatement("const", this, context); + return this; }); - conststatement.exps = true; + relation("===", function(context, left, right) { + if (isTypoTypeof(right, left, state)) { + warning("W122", this, right.value); + } else if (isTypoTypeof(left, right, state)) { + /* istanbul ignore next */ + warning("W122", this, left.value); + } + return this; + }); + relation("!=", function(context, left, right) { + var eqnull = state.option.eqnull && + ((left && left.value) === "null" || (right && right.value) === "null"); - var letstatement = stmt("let", function(context) { - return blockVariableStatement("let", this, context); + if (!eqnull && state.option.eqeqeq) { + this.from = this.character; + warning("W116", this, "!==", "!="); + } else if (isTypoTypeof(right, left, state)) { + /* istanbul ignore next */ + warning("W122", this, right.value); + } else if (isTypoTypeof(left, right, state)) { + warning("W122", this, left.value); + } + return this; }); - letstatement.exps = true; + relation("!==", function(context, left, right) { + if (isTypoTypeof(right, left, state)) { + warning("W122", this, right.value); + } else if (isTypoTypeof(left, right, state)) { + /* istanbul ignore next */ + warning("W122", this, left.value); + } + return this; + }); + relation("<"); + relation(">"); + relation("<="); + relation(">="); + bitwise("<<", "shiftleft", 120); + bitwise(">>", "shiftright", 120); + bitwise(">>>", "shiftrightunsigned", 120); + infix("in", "in", 120); + infix("instanceof", function(context, left, token) { + var right; + var scope = state.funct["(scope)"]; + token.left = left; + token.right = right = expression(context, 120); - var varstatement = stmt("var", function(context) { - var prefix = context && context.prefix; - var inexport = context && context.inexport; - var tokens, lone, value; + // This condition reflects a syntax error which will be reported by the + // `expression` function. + if (!right) { + return token; + } - // If the `implied` option is set, bindings are set differently. - var implied = context && context.implied; - var report = !(context && context.ignore); + if (right.id === "(number)" || + right.id === "(string)" || + right.value === "null" || + (right.value === "undefined" && !scope.has("undefined")) || + right.arity === "unary" || + right.id === "{" || + (right.id === "[" && !right.right) || + right.id === "(regexp)" || + (right.id === "(template)" && !right.tag)) { + error("E060"); + } - this.first = []; - for (;;) { - var names = []; - if (_.contains(["{", "["], state.tokens.next.value)) { - tokens = destructuringPattern(); - lone = false; - } else { - tokens = [ { id: identifier(), token: state.tokens.curr } ]; - lone = true; - } + if (right.id === "function") { + warning("W139"); + } - if (!(prefix && implied) && report && state.option.varstmt) { - warning("W132", this); + return token; + }, 120); + infix("+", function(context, left, that) { + var next = state.tokens.next; + var right; + that.left = left; + that.right = right = expression(context, 130); + + if (left && right && left.id === "(string)" && right.id === "(string)") { + left.value += right.value; + left.character = right.character; + if (!state.option.scripturl && reg.javascriptURL.test(left.value)) { + warning("W050", left); } + return left; + } - this.first = this.first.concat(names); + if (next.id === "+" || next.id === "++") { + warning("W007", that.right); + } - for (var t in tokens) { - if (tokens.hasOwnProperty(t)) { - t = tokens[t]; - if (!implied && state.funct["(global)"]) { - if (predefined[t.id] === false) { - warning("W079", t.token, t.id); - } else if (state.option.futurehostile === false) { - if ((!state.inES5() && vars.ecmaIdentifiers[5][t.id] === false) || - (!state.inES6() && vars.ecmaIdentifiers[6][t.id] === false)) { - warning("W129", t.token, t.id); - } - } - } - if (t.id) { - if (implied === "for") { + return that; + }, 130); + prefix("+", function(context) { + var next = state.tokens.next; + this.arity = "unary"; + this.right = expression(context, 150); - if (!state.funct["(scope)"].has(t.id)) { - if (report) warning("W088", t.token, t.id); - } - state.funct["(scope)"].block.use(t.id, t.token); - } else { - state.funct["(scope)"].addlabel(t.id, { - type: "var", - token: t.token }); + if (next.id === "+" || next.id === "++") { + warning("W007", this.right); + } - if (lone && inexport) { - state.funct["(scope)"].setExported(t.id, t.token); - } - } - names.push(t.token); - } - } - } + return this; + }); + infix("-", function(context, left, that) { + var next = state.tokens.next; + that.left = left; + that.right = expression(context, 130); - if (state.tokens.next.id === "=") { - state.nameStack.set(state.tokens.curr); + if (next.id === "-" || next.id === "--") { + warning("W006", that.right); + } - advance("="); - if (!prefix && report && !state.funct["(loopage)"] && - state.tokens.next.id === "undefined") { - warning("W080", state.tokens.prev, state.tokens.prev.value); - } - if (peek(0).id === "=" && state.tokens.next.identifier) { - if (!prefix && report && - !state.funct["(params)"] || - state.funct["(params)"].indexOf(state.tokens.next.value) === -1) { - warning("W120", state.tokens.next, state.tokens.next.value); - } - } - // don't accept `in` in expression if prefix is used for ForIn/Of loop. - value = expression(prefix ? 120 : 10); - if (lone) { - tokens[0].first = value; - } else { - destructuringPatternMatch(names, value); - } - } + return that; + }, 130); + prefix("-", function(context) { + var next = state.tokens.next; + this.arity = "unary"; + this.right = expression(context, 150); - if (state.tokens.next.id !== ",") { - break; - } - comma(); + if (next.id === "-" || next.id === "--") { + warning("W006", this.right); } return this; }); - varstatement.exps = true; + infix("*", "mult", 140); + infix("/", "div", 140); + infix("%", "mod", 140); - blockstmt("class", function() { - return classdef.call(this, true); - }); + suffix("++"); + prefix("++", "preinc"); + state.syntax["++"].exps = true; - function classdef(isStatement) { + suffix("--"); + prefix("--", "predec"); + state.syntax["--"].exps = true; - /*jshint validthis:true */ - if (!state.inES6()) { - warning("W104", state.tokens.curr, "class", "6"); + prefix("delete", function(context) { + this.arity = "unary"; + var p = expression(context, 150); + if (!p) { + return this; } - if (isStatement) { - // BindingIdentifier - this.name = identifier(); - state.funct["(scope)"].addlabel(this.name, { - type: "class", - token: state.tokens.curr }); - } else if (state.tokens.next.identifier && state.tokens.next.value !== "extends") { - // BindingIdentifier(opt) - this.name = identifier(); - this.namedExpr = true; - } else { - this.name = state.nameStack.infer(); + if (p.id !== "." && p.id !== "[") { + warning("W051"); } - classtail(this); - return this; - } + this.first = p; - function classtail(c) { - var wasInClassBody = state.inClassBody; - // ClassHeritage(opt) - if (state.tokens.next.value === "extends") { - advance("extends"); - c.heritage = expression(10); + // The `delete` operator accepts unresolvable references when not in strict + // mode, so the operand may be undefined. + if (p.identifier && !state.isStrict()) { + p.forgiveUndef = true; } + return this; + }).exps = true; - state.inClassBody = true; - advance("{"); - // ClassBody(opt) - c.body = classbody(c); - advance("}"); - state.inClassBody = wasInClassBody; - } + prefix("~", function(context) { + if (state.option.bitwise) { + warning("W016", this, "~"); + } + this.arity = "unary"; + this.right = expression(context, 150); + return this; + }); - function classbody(c) { - var name; - var isStatic; - var isGenerator; - var getset; - var props = Object.create(null); - var staticProps = Object.create(null); - var computed; - for (var i = 0; state.tokens.next.id !== "}"; ++i) { - name = state.tokens.next; - isStatic = false; - isGenerator = false; - getset = null; - - // The ES6 grammar for ClassElement includes the `;` token, but it is - // defined only as a placeholder to facilitate future language - // extensions. In ES6 code, it serves no purpose. - if (name.id === ";") { - warning("W032"); - advance(";"); - continue; - } + infix("..."); + + prefix("!", function(context) { + this.arity = "unary"; + this.right = expression(context, 150); + + if (!this.right) { // '!' followed by nothing? Give up. + quit("E041", this); + } + + if (bang[this.right.id] === true) { + warning("W018", this, "!"); + } + return this; + }); - if (name.id === "*") { - isGenerator = true; - advance("*"); - name = state.tokens.next; + prefix("typeof", function(context) { + this.arity = "unary"; + var p = expression(context, 150); + this.first = this.right = p; + + if (!p) { // 'typeof' followed by nothing? Give up. + quit("E041", this); + } + + // The `typeof` operator accepts unresolvable references, so the operand + // may be undefined. + if (p.identifier) { + p.forgiveUndef = true; + } + return this; + }); + prefix("new", function(context) { + var mp = metaProperty(context, "target", function() { + if (!state.inES6(true)) { + warning("W119", state.tokens.prev, "new.target", "6"); } - if (name.id === "[") { - name = computedPropertyName(); - computed = true; - } else if (isPropertyName(name)) { - // Non-Computed PropertyName - advance(); - computed = false; - if (name.identifier && name.value === "static") { - if (checkPunctuator(state.tokens.next, "*")) { - isGenerator = true; - advance("*"); + var inFunction, c = state.funct; + while (c) { + inFunction = !c["(global)"]; + if (!c["(arrow)"]) { break; } + c = c["(context)"]; + } + if (!inFunction) { + warning("W136", state.tokens.prev, "new.target"); + } + }); + if (mp) { return mp; } + + var c = expression(context, 155), i; + if (c && c.id !== "function") { + if (c.identifier) { + switch (c.value) { + case "Number": + case "String": + case "Boolean": + case "Math": + case "JSON": + warning("W053", state.tokens.prev, c.value); + break; + case "Symbol": + if (state.inES6()) { + warning("W053", state.tokens.prev, c.value); } - if (isPropertyName(state.tokens.next) || state.tokens.next.id === "[") { - computed = state.tokens.next.id === "["; - isStatic = true; - name = state.tokens.next; - if (state.tokens.next.id === "[") { - name = computedPropertyName(); - } else advance(); + break; + case "Function": + if (!state.option.evil) { + warning("W054"); } - } - - if (name.identifier && (name.value === "get" || name.value === "set")) { - if (isPropertyName(state.tokens.next) || state.tokens.next.id === "[") { - computed = state.tokens.next.id === "["; - getset = name; - name = state.tokens.next; - if (state.tokens.next.id === "[") { - name = computedPropertyName(); - } else advance(); + break; + case "Date": + case "RegExp": + case "this": + break; + default: + i = c.value.substr(0, 1); + if (state.option.newcap && (i < "A" || i > "Z") && + !state.funct["(scope)"].isPredefined(c.value)) { + warning("W055", state.tokens.curr); } } } else { - warning("W052", state.tokens.next, state.tokens.next.value || state.tokens.next.type); - advance(); - continue; - } - - if (!checkPunctuator(state.tokens.next, "(")) { - // error --- class properties must be methods - error("E054", state.tokens.next, state.tokens.next.value); - while (state.tokens.next.id !== "}" && - !checkPunctuator(state.tokens.next, "(")) { - advance(); - } - if (state.tokens.next.value !== "(") { - doFunction({ statement: c }); + if (c.id !== "." && c.id !== "[" && c.id !== "(") { + /* istanbul ignore next */ + warning("W056", state.tokens.curr); } } + } else { + if (!state.option.supernew) + warning("W057", this); + } + if (state.tokens.next.id !== "(" && !state.option.supernew) { + warning("W058", state.tokens.curr, state.tokens.curr.value); + } + this.first = this.right = c; + return this; + }); + state.syntax["new"].exps = true; - if (!computed) { - // We don't know how to determine if we have duplicate computed property names :( - if (getset) { - saveAccessor( - getset.value, isStatic ? staticProps : props, name.value, name, true, isStatic); - } else { - if (name.value === "constructor") { - state.nameStack.set(c); - } else { - state.nameStack.set(name); - } - saveProperty(isStatic ? staticProps : props, name.value, name, true, isStatic); - } - } - if (getset && name.value === "constructor") { - var propDesc = getset.value === "get" ? "class getter method" : "class setter method"; - error("E049", name, propDesc, "constructor"); - } else if (name.value === "prototype") { - error("E049", name, "class method", "prototype"); - } + // Class statement + blockstmt("class", function(context) { + var className, classNameToken; + var inexport = context & prodParams.export; - propertyName(name); + if (!state.inES6()) { + warning("W104", state.tokens.curr, "class", "6"); + } + state.inClassBody = true; - doFunction({ - statement: c, - type: isGenerator ? "generator" : null, - classExprBinding: c.namedExpr ? c.name : null + // Class Declaration: 'class ' + if (state.tokens.next.identifier && state.tokens.next.value !== "extends") { + classNameToken = state.tokens.next; + className = classNameToken.value; + identifier(context); + // unintialized, so that the 'extends' clause is parsed while the class is in TDZ + state.funct["(scope)"].addbinding(className, { + type: "class", + initialized: false, + token: classNameToken }); } - checkProperties(props); - } + // Class Declaration: 'class extends ' + if (state.tokens.next.value === "extends") { + advance("extends"); + expression(context, 0); + } - blockstmt("function", function(context) { - var inexport = context && context.inexport; - var generator = false; - if (state.tokens.next.value === "*") { - advance("*"); - if (state.inES6({ strict: true })) { - generator = true; - } else { - warning("W119", state.tokens.curr, "function*", "6"); + if (classNameToken) { + this.name = className; + state.funct["(scope)"].initialize(className); + if (inexport) { + state.funct["(scope)"].setExported(className, classNameToken); } } - if (inblock) { - warning("W082", state.tokens.curr); - } - var i = optionalidentifier(); + state.funct["(scope)"].stack(); + classBody(this, context); + return this; + }).exps = true; + + /* + Class expression - state.funct["(scope)"].addlabel(i, { - type: "function", - token: state.tokens.curr }); + The Block- and Expression- handling for "class" are almost identical, except for the ordering of steps. + In an expression:, the name should not be saved into the calling scope, but is still accessible inside the definition, so we open a new scope first, then save the name. We also mark it as used. + */ + prefix("class", function(context) { + var className, classNameToken; - if (i === undefined) { - warning("W025"); - } else if (inexport) { - state.funct["(scope)"].setExported(i, state.tokens.prev); + if (!state.inES6()) { + warning("W104", state.tokens.curr, "class", "6"); } + state.inClassBody = true; - doFunction({ - name: i, - statement: this, - type: generator ? "generator" : null, - ignoreLoopFunc: inblock // a declaration may already have warned - }); - if (state.tokens.next.id === "(" && state.tokens.next.line === state.tokens.curr.line) { - error("E039"); + // Class Declaration: 'class ' + if (state.tokens.next.identifier && state.tokens.next.value !== "extends") { + classNameToken = state.tokens.next; + className = classNameToken.value; + identifier(context); } - return this; - }); - prefix("function", function() { - var generator = false; + // Class Declaration: 'class extends ' + if (state.tokens.next.value === "extends") { + advance("extends"); + expression(context, 0); + } - if (state.tokens.next.value === "*") { - if (!state.inES6()) { - warning("W119", state.tokens.curr, "function*", "6"); - } - advance("*"); - generator = true; + state.funct["(scope)"].stack(); + if (classNameToken) { + this.name = className; + state.funct["(scope)"].addbinding(className, { + type: "class", + initialized: true, + token: classNameToken + }); + state.funct["(scope)"].block.use(className, classNameToken); } - var i = optionalidentifier(); - doFunction({ name: i, type: generator ? "generator" : null }); + classBody(this, context); return this; }); - blockstmt("if", function() { - var t = state.tokens.next; - increaseComplexityCount(); - state.condition = true; - advance("("); - var expr = expression(0); - checkCondAssignment(expr); + function classBody(classToken, context) { + var props = Object.create(null); + var name, accessorType, token, isStatic, inGenerator, hasConstructor; - // When the if is within a for-in loop, check if the condition - // starts with a negation operator - var forinifcheck = null; - if (state.option.forin && state.forinifcheckneeded) { - state.forinifcheckneeded = false; // We only need to analyze the first if inside the loop - forinifcheck = state.forinifchecks[state.forinifchecks.length - 1]; - if (expr.type === "(punctuator)" && expr.value === "!") { - forinifcheck.type = "(negative)"; - } else { - forinifcheck.type = "(positive)"; - } + /* istanbul ignore else */ + if (state.tokens.next.value === "{") { + advance("{"); + } else { + warning("W116", state.tokens.curr, "identifier", state.tokens.next.type); //? + advance(); } - advance(")", t); - state.condition = false; - var s = block(true, true); + while (state.tokens.next.value !== "}") { + isStatic = false; + inGenerator = false; + context &= ~prodParams.preAsync; - // When the if is within a for-in loop and the condition has a negative form, - // check if the body contains nothing but a continue statement - if (forinifcheck && forinifcheck.type === "(negative)") { - if (s && s[0] && s[0].type === "(identifier)" && s[0].value === "continue") { - forinifcheck.type = "(negative-with-continue)"; + if (state.tokens.next.value === "static" && + !checkPunctuator(peek(), "(")) { + isStatic = true; + advance(); } - } - if (state.tokens.next.id === "else") { - advance("else"); - if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") { - statement(); - } else { - block(true, true); - } - } - return this; - }); + if (state.tokens.next.value === "async") { + if (!checkPunctuator(peek(), "(")) { + context |= prodParams.preAsync; + advance(); - blockstmt("try", function() { - var b; + nolinebreak(state.tokens.curr); - function doCatch() { - advance("catch"); - advance("("); + if (checkPunctuator(state.tokens.next, "*")) { + inGenerator = true; + advance("*"); - state.funct["(scope)"].stack("catchparams"); + if (!state.inES9()) { + warning("W119", state.tokens.next, "async generators", "9"); + } + } - if (checkPunctuators(state.tokens.next, ["[", "{"])) { - var tokens = destructuringPattern(); - _.each(tokens, function(token) { - if (token.id) { - state.funct["(scope)"].addParam(token.id, token, "exception"); + if (!state.inES8()) { + warning("W119", state.tokens.curr, "async functions", "8"); } - }); - } else if (state.tokens.next.type !== "(identifier)") { - warning("E030", state.tokens.next, state.tokens.next.value); - } else { - // only advance if we have an identifier so we can continue parsing in the most common error - that no param is given. - state.funct["(scope)"].addParam(identifier(), state.tokens.curr, "exception"); + } } - if (state.tokens.next.value === "if") { - if (!state.inMoz()) { - warning("W118", state.tokens.curr, "catch filter"); - } - advance("if"); - expression(0); + if (state.tokens.next.value === "*") { + inGenerator = true; + advance(); } - advance(")"); + token = state.tokens.next; - block(false); + if ((token.value === "set" || token.value === "get") && !checkPunctuator(peek(), "(")) { + if (inGenerator) { + /* istanbul ignore next */ + error("E024", token, token.value); + } + accessorType = token.value; + advance(); + token = state.tokens.next; - state.funct["(scope)"].unstack(); - } + if (!isStatic && token.value === "constructor") { + error("E049", token, "class " + accessorType + "ter method", token.value); + } else if (isStatic && token.value === "prototype") { + error("E049", token, "static class " + accessorType + "ter method", token.value); + } + } else { + accessorType = null; + } + + switch (token.value) { + case ";": + warning("W032", token); + advance(); + break; + case "constructor": + if (isStatic) { + // treat like a regular method -- static methods can be called 'constructor' + name = propertyName(context); + saveProperty(props, name, token, true, isStatic); + doMethod(classToken, context, name, inGenerator); + } else { + if (inGenerator || context & prodParams.preAsync) { + error("E024", token, token.value); + } else if (hasConstructor) { + /* istanbul ignore next */ + error("E024", token, token.value); + } else { + hasConstructor = !accessorType && !isStatic; + } + advance(); + doMethod(classToken, context, state.nameStack.infer()); + } + break; + case "[": + name = computedPropertyName(context); + doMethod(classToken, context, name, inGenerator); + // We don't check names (via calling saveProperty()) of computed expressions like ["Symbol.iterator"]() + break; + default: + name = propertyName(context); + if (name === undefined) { + error("E024", token, token.value); + advance(); + break; + } + + if (accessorType) { + saveAccessor(accessorType, props, name, token, true, isStatic); + name = state.nameStack.infer(); + } else { + if (isStatic && name === "prototype") { + error("E049", token, "static class method", name); + } - block(true); + saveProperty(props, name, token, true, isStatic); + } - while (state.tokens.next.id === "catch") { - increaseComplexityCount(); - if (b && (!state.inMoz())) { - warning("W118", state.tokens.next, "multiple catch blocks"); + doMethod(classToken, context, name, inGenerator); + break; } - doCatch(); - b = true; } + advance("}"); + checkProperties(props); - if (state.tokens.next.id === "finally") { - advance("finally"); - block(true); - return; - } + state.inClassBody = false; + state.funct["(scope)"].unstack(); + } - if (!b) { - error("E021", state.tokens.next, "catch", state.tokens.next.value); + function doMethod(classToken, context, name, generator) { + if (generator) { + if (!state.inES6()) { + warning("W119", state.tokens.curr, "function*", "6"); + } } - return this; - }); - - blockstmt("while", function() { - var t = state.tokens.next; - state.funct["(breakage)"] += 1; - state.funct["(loopage)"] += 1; - increaseComplexityCount(); - advance("("); - checkCondAssignment(expression(0)); - advance(")", t); - block(true, true); - state.funct["(breakage)"] -= 1; - state.funct["(loopage)"] -= 1; - return this; - }).labelled = true; + if (state.tokens.next.value !== "(") { + error("E054", state.tokens.next, state.tokens.next.value); + advance(); + if (state.tokens.next.value === "{") { + // manually cheating the test "invalidClasses", which asserts this particular behavior when a class is misdefined. + advance(); + if (state.tokens.next.value === "}") { + warning("W116", state.tokens.next, "(", state.tokens.next.value); + advance(); + identifier(context); + advance(); + } + /* istanbul ignore next */ + return; + } else { + while (state.tokens.next.value !== "(") { + advance(); + } + } + } - blockstmt("with", function() { - var t = state.tokens.next; - if (state.isStrict()) { - error("E010", state.tokens.curr); - } else if (!state.option.withstmt) { - warning("W085", state.tokens.curr); + doFunction(context, { name: name, + type: generator ? "generator" : null, + isMethod: true, + statement: classToken }); + } + + prefix("void").exps = true; + + infix(".", function(context, left, that) { + var m = identifier(context, true); + + if (typeof m === "string") { + countMember(m); } - advance("("); - expression(0); - advance(")", t); - block(true, true); + that.left = left; + that.right = m; - return this; - }); + if (m && m === "hasOwnProperty" && state.tokens.next.value === "=") { + warning("W001"); + } - blockstmt("switch", function() { - var t = state.tokens.next; - var g = false; - var noindent = false; + if (left && left.value === "arguments" && (m === "callee" || m === "caller")) { + if (state.option.noarg) + warning("W059", left, m); + else if (state.isStrict()) + error("E008"); + } else if (!state.option.evil && left && left.value === "document" && + (m === "write" || m === "writeln")) { + warning("W060", left); + } - state.funct["(breakage)"] += 1; - advance("("); - checkCondAssignment(expression(0)); - advance(")", t); - t = state.tokens.next; - advance("{"); + if (!state.option.evil && (m === "eval" || m === "execScript")) { + if (isGlobalEval(left, state)) { + warning("W061"); + } + } - if (state.tokens.next.from === indent) - noindent = true; + return that; + }, 160, true); - if (!noindent) - indent += state.option.indent; + infix("(", function(context, left, that) { + if (state.option.immed && left && !left.immed && left.id === "function") { + warning("W062"); + } - this.cases = []; + if (state.option.asi && checkPunctuators(state.tokens.prev, [")", "]"]) && + !sameLine(state.tokens.prev, state.tokens.curr)) { + warning("W014", state.tokens.curr, state.tokens.curr.id); + } - for (;;) { - switch (state.tokens.next.id) { - case "case": - switch (state.funct["(verb)"]) { - case "yield": - case "break": - case "case": - case "continue": - case "return": - case "switch": - case "throw": - break; - default: - // You can tell JSHint that you don't use break intentionally by - // adding a comment /* falls through */ on a line just before - // the next `case`. - if (!state.tokens.curr.caseFallsThrough) { - warning("W086", state.tokens.curr, "case"); - } - } + var n = 0; + var p = []; - advance("case"); - this.cases.push(expression(0)); - increaseComplexityCount(); - g = true; - advance(":"); - state.funct["(verb)"] = "case"; - break; - case "default": - switch (state.funct["(verb)"]) { - case "yield": - case "break": - case "continue": - case "return": - case "throw": - break; - default: - // Do not display a warning if 'default' is the first statement or if - // there is a special /* falls through */ comment. - if (this.cases.length) { - if (!state.tokens.curr.caseFallsThrough) { - warning("W086", state.tokens.curr, "default"); + if (left) { + if (left.type === "(identifier)") { + if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { + if ("Array Number String Boolean Date Object Error Symbol".indexOf(left.value) === -1) { + if (left.value === "Math") { + /* istanbul ignore next */ + warning("W063", left); + } else if (state.option.newcap) { + warning("W064", left); } } } + } + } - advance("default"); - g = true; - advance(":"); - break; - case "}": - if (!noindent) - indent -= state.option.indent; + if (state.tokens.next.id !== ")") { + for (;;) { + spreadrest("spread"); - advance("}", t); - state.funct["(breakage)"] -= 1; - state.funct["(verb)"] = undefined; - return; - case "(end)": - error("E023", state.tokens.next, "}"); - return; - default: - indent += state.option.indent; - if (g) { - switch (state.tokens.curr.id) { - case ",": - error("E040"); - return; - case ":": - g = false; - statements(); - break; - default: - error("E025", state.tokens.curr); - return; - } - } else { - if (state.tokens.curr.id === ":") { - advance(":"); - error("E024", state.tokens.curr, ":"); - statements(); - } else { - error("E021", state.tokens.next, "case", state.tokens.next.value); - return; + p[p.length] = expression(context, 10); + n += 1; + if (state.tokens.next.id !== ",") { + break; + } + advance(","); + checkComma({ allowTrailing: true }); + + if (state.tokens.next.id === ")") { + if (!state.inES8()) { + warning("W119", state.tokens.curr, "Trailing comma in arguments lists", "8"); } + + break; } - indent -= state.option.indent; } } - return this; - }).labelled = true; - - stmt("debugger", function() { - if (!state.option.debug) { - warning("W087", this); - } - return this; - }).exps = true; - (function() { - var x = stmt("do", function() { - state.funct["(breakage)"] += 1; - state.funct["(loopage)"] += 1; - increaseComplexityCount(); + advance(")"); - this.first = block(true, true); - advance("while"); - var t = state.tokens.next; - advance("("); - checkCondAssignment(expression(0)); - advance(")", t); - state.funct["(breakage)"] -= 1; - state.funct["(loopage)"] -= 1; - return this; - }); - x.labelled = true; - x.exps = true; - }()); + if (typeof left === "object") { + if (!state.inES5() && left.value === "parseInt" && n === 1) { + warning("W065", state.tokens.curr); + } + if (!state.option.evil) { + if (left.value === "eval" || left.value === "Function" || + left.value === "execScript") { + warning("W061", left); - blockstmt("for", function() { - var s, t = state.tokens.next; - var letscope = false; - var foreachtok = null; + // This conditional expression was initially implemented with a typo + // which prevented the branch's execution in all cases. While + // enabling the code will produce behavior that is consistent with + // the other forms of code evaluation that follow, such a change is + // also technically incompatable with prior versions of JSHint (due + // to the fact that the behavior was never formally documented). This + // branch should be enabled as part of a major release. + //if (p[0] && p[0].id === "(string)") { + // addEvalCode(left, p[0]); + //} + } else if (p[0] && p[0].id === "(string)" && + (left.value === "setTimeout" || + left.value === "setInterval")) { + warning("W066", left); + addEvalCode(left, p[0]); - if (t.value === "each") { - foreachtok = t; - advance("each"); - if (!state.inMoz()) { - warning("W118", state.tokens.curr, "for each"); + // window.setTimeout/setInterval + } else if (p[0] && p[0].id === "(string)" && + left.value === "." && + left.left.value === "window" && + (left.right === "setTimeout" || + left.right === "setInterval")) { + warning("W066", left); + addEvalCode(left, p[0]); + } + } + if (!left.identifier && left.id !== "." && left.id !== "[" && left.id !== "=>" && + left.id !== "(" && left.id !== "&&" && left.id !== "||" && left.id !== "?" && + left.id !== "async" && !(state.inES6() && left["(name)"])) { + warning("W067", that); } } - increaseComplexityCount(); - advance("("); + that.left = left; + return that; + }, 155, true).exps = true; - // what kind of for(…) statement it is? for(…of…)? for(…in…)? for(…;…;…)? - var nextop; // contains the token of the "in" or "of" operator - var i = 0; - var inof = ["in", "of"]; - var level = 0; // BindingPattern "level" --- level 0 === no BindingPattern - var comma; // First comma punctuator at level 0 - var initializer; // First initializer at level 0 + function peekThroughParens(parens) { + var pn = state.tokens.next; + var i = -1; + var pn1; - // If initial token is a BindingPattern, count it as such. - if (checkPunctuators(state.tokens.next, ["{", "["])) ++level; do { - nextop = peek(i); - ++i; - if (checkPunctuators(nextop, ["{", "["])) ++level; - else if (checkPunctuators(nextop, ["}", "]"])) --level; - if (level < 0) break; - if (level === 0) { - if (!comma && checkPunctuator(nextop, ",")) comma = nextop; - else if (!initializer && checkPunctuator(nextop, "=")) initializer = nextop; - } - } while (level > 0 || !_.contains(inof, nextop.value) && nextop.value !== ";" && - nextop.type !== "(end)"); // Is this a JSCS bug? This looks really weird. - - // if we're in a for (… in|of …) statement - if (_.contains(inof, nextop.value)) { - if (!state.inES6() && nextop.value === "of") { - warning("W104", nextop, "for of", "6"); + if (pn.value === "(") { + parens += 1; + } else if (pn.value === ")") { + parens -= 1; } - var ok = !(initializer || comma); - if (initializer) { - error("W133", comma, nextop.value, "initializer is forbidden"); - } + i += 1; + pn1 = pn; + pn = peek(i); + } while (!(parens === 0 && pn1.value === ")") && pn.type !== "(end)"); - if (comma) { - error("W133", comma, nextop.value, "more than one ForBinding"); - } + return pn; + } - if (state.tokens.next.id === "var") { - advance("var"); - state.tokens.curr.fud({ prefix: true }); - } else if (state.tokens.next.id === "let" || state.tokens.next.id === "const") { - advance(state.tokens.next.id); - // create a new block scope - letscope = true; - state.funct["(scope)"].stack(); - state.tokens.curr.fud({ prefix: true }); - } else { - // Parse as a var statement, with implied bindings. Ignore errors if an error - // was already reported - Object.create(varstatement).fud({ prefix: true, implied: "for", ignore: !ok }); - } - advance(nextop.value); - expression(20); - advance(")", t); + prefix("(", function(context, rbp) { + var ret, triggerFnExpr, first, last; + var opening = state.tokens.curr; + var preceeding = state.tokens.prev; + var isNecessary = !state.option.singleGroups; + var pn = peekThroughParens(1); - if (nextop.value === "in" && state.option.forin) { - state.forinifcheckneeded = true; + if (state.tokens.next.id === "function") { + triggerFnExpr = state.tokens.next.immed = true; + } - if (state.forinifchecks === undefined) { - state.forinifchecks = []; - } + // If the balanced grouping operator is followed by a "fat arrow", the + // current token marks the beginning of a "fat arrow" function and parsing + // should proceed accordingly. + if (pn.value === "=>") { + pn.funct = doFunction(context, { type: "arrow", parsedOpening: true }); + return pn; + } - // Push a new for-in-if check onto the stack. The type will be modified - // when the loop's body is parsed and a suitable if statement exists. - state.forinifchecks.push({ - type: "(none)" - }); - } + // The ECMA262 grammar requires an expression between the "opening + // parenthesis" and "close parenthesis" tokens of the grouping operator. + // However, the "ignore" directive is commonly used to inject values that + // are not included in the token stream. For example: + // + // return ( + // /*jshint ignore:start */ + //
    + // /*jshint ignore:end */ + // ); + // + // The "empty" grouping operator is permitted in order to tolerate this + // pattern. + if (state.tokens.next.id === ")") { + advance(")"); + return; + } - state.funct["(breakage)"] += 1; - state.funct["(loopage)"] += 1; + ret = expression(context, 0); - s = block(true, true); + advance(")", this); - if (nextop.value === "in" && state.option.forin) { - if (state.forinifchecks && state.forinifchecks.length > 0) { - var check = state.forinifchecks.pop(); + if (!ret) { + return; + } - if (// No if statement or not the first statement in loop body - s && s.length > 0 && (typeof s[0] !== "object" || s[0].value !== "if") || - // Positive if statement is not the only one in loop body - check.type === "(positive)" && s.length > 1 || - // Negative if statement but no continue - check.type === "(negative)") { - warning("W089", this); - } - } + ret.paren = true; - // Reset the flag in case no if statement was contained in the loop body - state.forinifcheckneeded = false; + if (state.option.immed && ret && ret.id === "function") { + if (state.tokens.next.id !== "(" && + state.tokens.next.id !== "." && state.tokens.next.id !== "[") { + warning("W068", this); } + } - state.funct["(breakage)"] -= 1; - state.funct["(loopage)"] -= 1; - } else { - if (foreachtok) { - error("E045", foreachtok); - } - if (state.tokens.next.id !== ";") { - if (state.tokens.next.id === "var") { - advance("var"); - state.tokens.curr.fud(); - } else if (state.tokens.next.id === "let") { - advance("let"); - // create a new block scope - letscope = true; - state.funct["(scope)"].stack(); - state.tokens.curr.fud(); - } else { - for (;;) { - expression(0, "for"); - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - } + if (ret.id === ",") { + first = ret.left; + while (first.id === ",") { + first = first.left; } - nolinebreak(state.tokens.curr); - advance(";"); - // start loopage after the first ; as the next two expressions are executed - // on every loop - state.funct["(loopage)"] += 1; - if (state.tokens.next.id !== ";") { - checkCondAssignment(expression(0)); - } - nolinebreak(state.tokens.curr); - advance(";"); - if (state.tokens.next.id === ";") { - error("E021", state.tokens.next, ")", ";"); - } - if (state.tokens.next.id !== ")") { - for (;;) { - expression(0, "for"); - if (state.tokens.next.id !== ",") { - break; - } - comma(); + last = ret.right; + } else { + first = last = ret; + + if (!isNecessary) { + // async functions are identified after parsing due to the complexity + // of disambiguating the `async` keyword. + if (!triggerFnExpr) { + triggerFnExpr = ret.id === "async"; } + + isNecessary = + // Used to distinguish from an ExpressionStatement which may not + // begin with the `{` and `function` tokens + (opening.beginsStmt && (ret.id === "{" || triggerFnExpr)) || + // Used to signal that a function expression is being supplied to + // some other operator. + (triggerFnExpr && + // For parenthesis wrapping a function expression to be considered + // necessary, the grouping operator should be the left-hand-side of + // some other operator--either within the parenthesis or directly + // following them. + (!isEndOfExpr() || state.tokens.prev.id !== "}")) || + // Used to demarcate an arrow function as the left-hand side of some + // operator. + (ret.id === "=>" && !isEndOfExpr()) || + // Used as the return value of a single-statement arrow function + (ret.id === "{" && preceeding.id === "=>") || + // Used to cover a unary expression as the left-hand side of the + // exponentiation operator + (beginsUnaryExpression(ret) && state.tokens.next.id === "**") || + // Used to delineate an integer number literal from a dereferencing + // punctuator (otherwise interpreted as a decimal point) + (ret.type === "(number)" && + checkPunctuator(pn, ".") && /^\d+$/.test(ret.value)) || + // Used to wrap object destructuring assignment + (opening.beginsStmt && ret.id === "=" && ret.left.id === "{"); } - advance(")", t); - state.funct["(breakage)"] += 1; - block(true, true); - state.funct["(breakage)"] -= 1; - state.funct["(loopage)"] -= 1; + } + // The operator may be necessary to override the default binding power of + // neighboring operators (whenever there is an operator in use within the + // first expression *or* the current group contains multiple expressions) + if (!isNecessary && (isOperator(first) || first !== last)) { + isNecessary = + (rbp > first.lbp) || + (rbp > 0 && rbp === first.lbp) || + (!isEndOfExpr() && last.rbp < state.tokens.next.lbp); } - // unstack loop blockscope - if (letscope) { - state.funct["(scope)"].unstack(); + + if (!isNecessary) { + warning("W126", opening); } - return this; - }).labelled = true; + return ret; + }); - stmt("break", function() { - var v = state.tokens.next.value; + application("=>"); - if (!state.option.asi) - nolinebreak(this); + infix("[", function(context, left, that) { + var e, s, canUseDot; - if (state.tokens.next.id !== ";" && !state.tokens.next.reach && - state.tokens.curr.line === startLine(state.tokens.next)) { - if (!state.funct["(scope)"].funct.hasBreakLabel(v)) { - warning("W090", state.tokens.next, v); - } - this.first = state.tokens.next; - advance(); - } else { - if (state.funct["(breakage)"] === 0) - warning("W052", state.tokens.next, this.value); + if (state.option.asi && checkPunctuators(state.tokens.prev, [")", "]"]) && + !sameLine(state.tokens.prev, state.tokens.curr)) { + warning("W014", state.tokens.curr, state.tokens.curr.id); } - reachable(this); - - return this; - }).exps = true; - + e = expression(context & ~prodParams.noin, 10); - stmt("continue", function() { - var v = state.tokens.next.value; + if (e && e.type === "(string)") { + if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) { + if (isGlobalEval(left, state)) { + warning("W061"); + } + } - if (state.funct["(breakage)"] === 0) - warning("W052", state.tokens.next, this.value); - if (!state.funct["(loopage)"]) - warning("W052", state.tokens.next, this.value); + countMember(e.value); + if (!state.option.sub && reg.identifier.test(e.value)) { + s = state.syntax[e.value]; - if (!state.option.asi) - nolinebreak(this); + if (s) { + canUseDot = !isReserved(context, s); + } else { + // This branch exists to preserve legacy behavior with version 2.9.5 + // and earlier. In those releases, `eval` and `arguments` were + // incorrectly interpreted as reserved keywords, so Member + // Expressions such as `object["eval"]` did not trigger warning W069. + // + // TODO: Remove in JSHint 3 + canUseDot = e.value !== "eval" && e.value !== "arguments"; + } - if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { - if (state.tokens.curr.line === startLine(state.tokens.next)) { - if (!state.funct["(scope)"].funct.hasBreakLabel(v)) { - warning("W090", state.tokens.next, v); + if (canUseDot) { + warning("W069", state.tokens.prev, e.value); } - this.first = state.tokens.next; - advance(); } } + advance("]", that); - reachable(this); - - return this; - }).exps = true; + if (e && e.value === "hasOwnProperty" && state.tokens.next.value === "=") { + warning("W001"); + } + that.left = left; + that.right = e; + return that; + }, 160, true); - stmt("return", function() { - if (this.line === startLine(state.tokens.next)) { - if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { - this.first = expression(0); + function comprehensiveArrayExpression(context) { + var res = {}; + res.exps = true; + state.funct["(comparray)"].stack(); - if (this.first && - this.first.type === "(punctuator)" && this.first.value === "=" && - !this.first.paren && !state.option.boss) { - warningAt("W093", this.first.line, this.first.character); - } - } - } else { - if (state.tokens.next.type === "(punctuator)" && - ["[", "{", "+", "-"].indexOf(state.tokens.next.value) > -1) { - nolinebreak(this); // always warn (Line breaking error) + // Handle reversed for expressions, used in spidermonkey + var reversed = false; + if (state.tokens.next.value !== "for") { + reversed = true; + if (!state.inMoz()) { + warning("W116", state.tokens.next, "for", state.tokens.next.value); } + state.funct["(comparray)"].setState("use"); + res.right = expression(context, 10); } - reachable(this); - - return this; - }).exps = true; - - (function(x) { - x.exps = true; - x.lbp = 25; - }(prefix("yield", function() { - var prev = state.tokens.prev; - if (state.inES6(true) && !state.funct["(generator)"]) { - // If it's a yield within a catch clause inside a generator then that's ok - if (!("(catch)" === state.funct["(name)"] && state.funct["(context)"]["(generator)"])) { - error("E046", state.tokens.curr, "yield"); + advance("for"); + if (state.tokens.next.value === "each") { + advance("each"); + if (!state.inMoz()) { + warning("W118", state.tokens.curr, "for each"); } - } else if (!state.inES6()) { - warning("W104", state.tokens.curr, "yield", "6"); } - state.funct["(generator)"] = "yielded"; - var delegatingYield = false; + advance("("); + state.funct["(comparray)"].setState("define"); + res.left = expression(context, 130); + if (_.includes(["in", "of"], state.tokens.next.value)) { + advance(); + } else { + /* istanbul ignore next */ + error("E045", state.tokens.curr); + } + state.funct["(comparray)"].setState("generate"); + expression(context, 10); - if (state.tokens.next.value === "*") { - delegatingYield = true; - advance("*"); + advance(")"); + if (state.tokens.next.value === "if") { + advance("if"); + advance("("); + state.funct["(comparray)"].setState("filter"); + expression(context, 10); + advance(")"); } - if (this.line === startLine(state.tokens.next) || !state.inMoz()) { - if (delegatingYield || - (state.tokens.next.id !== ";" && !state.option.asi && - !state.tokens.next.reach && state.tokens.next.nud)) { + if (!reversed) { + state.funct["(comparray)"].setState("use"); + res.right = expression(context, 10); + } - nobreaknonadjacent(state.tokens.curr, state.tokens.next); - this.first = expression(10); + advance("]"); + state.funct["(comparray)"].unstack(); + return res; + } - if (this.first.type === "(punctuator)" && this.first.value === "=" && - !this.first.paren && !state.option.boss) { - warningAt("W093", this.first.line, this.first.character); - } + prefix("[", function(context) { + var blocktype = lookupBlockType(); + if (blocktype.isCompArray) { + if (!state.option.esnext && !state.inMoz()) { + warning("W118", state.tokens.curr, "array comprehension"); } - - if (state.inMoz() && state.tokens.next.id !== ")" && - (prev.lbp > 30 || (!prev.assign && !isEndOfExpr()) || prev.id === "yield")) { - error("E050", this); + return comprehensiveArrayExpression(context); + } else if (blocktype.isDestAssign) { + this.destructAssign = destructuringPattern(context, { + openingParsed: true, + assignment: true + }); + return this; + } + var b = !sameLine(state.tokens.curr, state.tokens.next); + this.first = []; + if (b) { + indent += state.option.indent; + if (state.tokens.next.from === indent + state.option.indent) { + /* istanbul ignore next */ + indent += state.option.indent; } - } else if (!state.option.asi) { - nolinebreak(this); // always warn (Line breaking error) } - return this; - }))); - - - stmt("throw", function() { - nolinebreak(this); - this.first = expression(20); - - reachable(this); - - return this; - }).exps = true; - - stmt("import", function() { - if (!state.inES6()) { - warning("W119", state.tokens.curr, "import", "6"); - } - - if (state.tokens.next.type === "(string)") { - // ModuleSpecifier :: StringLiteral - advance("(string)"); - return this; - } - - if (state.tokens.next.identifier) { - // ImportClause :: ImportedDefaultBinding - this.name = identifier(); - // Import bindings are immutable (see ES6 8.1.1.5.5) - state.funct["(scope)"].addlabel(this.name, { - type: "const", - token: state.tokens.curr }); - - if (state.tokens.next.value === ",") { - // ImportClause :: ImportedDefaultBinding , NameSpaceImport - // ImportClause :: ImportedDefaultBinding , NamedImports + while (state.tokens.next.id !== "(end)") { + while (state.tokens.next.id === ",") { + if (!state.option.elision) { + if (!state.inES5()) { + // Maintain compat with old options --- ES5 mode without + // elision=true will warn once per comma + warning("W070"); + } else { + warning("W128"); + do { + advance(","); + } while (state.tokens.next.id === ","); + continue; + } + } advance(","); - // At this point, we intentionally fall through to continue matching - // either NameSpaceImport or NamedImports. - // Discussion: - // https://github.com/jshint/jshint/pull/2144#discussion_r23978406 - } else { - advance("from"); - advance("(string)"); - return this; } - } - if (state.tokens.next.id === "*") { - // ImportClause :: NameSpaceImport - advance("*"); - advance("as"); - if (state.tokens.next.identifier) { - this.name = identifier(); - // Import bindings are immutable (see ES6 8.1.1.5.5) - state.funct["(scope)"].addlabel(this.name, { - type: "const", - token: state.tokens.curr }); + if (state.tokens.next.id === "]") { + break; } - } else { - // ImportClause :: NamedImports - advance("{"); - for (;;) { - if (state.tokens.next.value === "}") { - advance("}"); - break; - } - var importName; - if (state.tokens.next.type === "default") { - importName = "default"; - advance("default"); - } else { - importName = identifier(); - } - if (state.tokens.next.value === "as") { - advance("as"); - importName = identifier(); - } - // Import bindings are immutable (see ES6 8.1.1.5.5) - state.funct["(scope)"].addlabel(importName, { - type: "const", - token: state.tokens.curr }); + spreadrest("spread"); - if (state.tokens.next.value === ",") { - advance(","); - } else if (state.tokens.next.value === "}") { - advance("}"); - break; - } else { - error("E024", state.tokens.next, state.tokens.next.value); + this.first.push(expression(context, 10)); + if (state.tokens.next.id === ",") { + advance(","); + checkComma({ allowTrailing: true }); + if (state.tokens.next.id === "]" && !state.inES5()) { + warning("W070", state.tokens.curr); break; } + } else { + if (state.option.trailingcomma && state.inES5()) { + warningAt("W140", state.tokens.curr.line, state.tokens.curr.character); + } + break; } } - - // FromClause - advance("from"); - advance("(string)"); + if (b) { + indent -= state.option.indent; + } + advance("]", this); return this; - }).exps = true; + }); - stmt("export", function() { - var ok = true; - var token; - var identifier; - if (!state.inES6()) { - warning("W119", state.tokens.curr, "export", "6"); - ok = false; - } + function isMethod() { + return !!state.funct["(method)"]; + } - if (!state.funct["(scope)"].block.isGlobal()) { - error("E053", state.tokens.curr); - ok = false; + function propertyName(context, preserveOrToken) { + var id; + var preserve = true; + if (typeof preserveOrToken === "object") { + /* istanbul ignore next */ + id = preserveOrToken; + } else { + preserve = preserveOrToken; + id = optionalidentifier(context, true, preserve); } - if (state.tokens.next.value === "*") { - // ExportDeclaration :: export * FromClause - advance("*"); - advance("from"); - advance("(string)"); - return this; + if (!id) { + if (state.tokens.next.id === "(string)") { + id = state.tokens.next.value; + if (!preserve) { + advance(); + } + } else if (state.tokens.next.id === "(number)") { + id = state.tokens.next.value.toString(); + if (!preserve) { + advance(); + } + } + /* istanbul ignore next */ + } else if (typeof id === "object") { + if (id.id === "(string)" || id.id === "(identifier)") id = id.value; + else if (id.id === "(number)") id = id.value.toString(); } - if (state.tokens.next.type === "default") { - // ExportDeclaration :: - // export default [lookahead  { function, class }] AssignmentExpression[In] ; - // export default HoistableDeclaration - // export default ClassDeclaration - state.nameStack.set(state.tokens.next); - advance("default"); - var exportType = state.tokens.next.id; - if (exportType === "function" || exportType === "class") { - this.block = true; - } + if (id === "hasOwnProperty") { + warning("W001"); + } - token = peek(); + return id; + } - expression(10); + /** + * @param {Number} context The parsing context + * @param {Object} [options] + * @param {token} [options.loneArg] The argument to the function in cases + * where it was defined using the + * single-argument shorthand. + * @param {bool} [options.parsedOpening] Whether the opening parenthesis has + * already been parsed. + * + * @returns {{ arity: number, params: Array., isSimple: boolean }} + */ + function functionparams(context, options) { + var next; + var paramsIds = []; + var ident; + var tokens = []; + var t; + var pastDefault = false; + var pastRest = false; + var arity = 0; + var loneArg = options && options.loneArg; + var hasDestructuring = false; - identifier = token.value; + if (loneArg && loneArg.identifier === true) { + state.funct["(scope)"].addParam(loneArg.value, loneArg); + return { arity: 1, params: [ loneArg.value ], isSimple: true }; + } - if (this.block) { - state.funct["(scope)"].addlabel(identifier, { - type: exportType, - token: token }); + next = state.tokens.next; - state.funct["(scope)"].setExported(identifier, token); - } + if (!options || !options.parsedOpening) { + advance("("); + } - return this; + if (state.tokens.next.id === ")") { + advance(")"); + return; } - if (state.tokens.next.value === "{") { - // ExportDeclaration :: export ExportClause - advance("{"); - var exportedTokens = []; - for (;;) { - if (!state.tokens.next.identifier) { - error("E030", state.tokens.next, state.tokens.next.value); - } - advance(); + function addParam(addParamArgs) { + state.funct["(scope)"].addParam.apply(state.funct["(scope)"], addParamArgs); + } - exportedTokens.push(state.tokens.curr); + for (;;) { + arity++; + // are added to the param scope + var currentParams = []; - if (state.tokens.next.value === "as") { - advance("as"); - if (!state.tokens.next.identifier) { - error("E030", state.tokens.next, state.tokens.next.value); + if (_.includes(["{", "["], state.tokens.next.id)) { + hasDestructuring = true; + tokens = destructuringPattern(context); + for (t in tokens) { + t = tokens[t]; + if (t.id) { + paramsIds.push(t.id); + currentParams.push([t.id, t.token]); } - advance(); } + } else { + pastRest = spreadrest("rest"); + ident = identifier(context); - if (state.tokens.next.value === ",") { - advance(","); - } else if (state.tokens.next.value === "}") { - advance("}"); - break; + if (ident) { + paramsIds.push(ident); + currentParams.push([ident, state.tokens.curr]); } else { - error("E024", state.tokens.next, state.tokens.next.value); - break; + // Skip invalid parameter. + while (!checkPunctuators(state.tokens.next, [",", ")"])) advance(); } } - if (state.tokens.next.value === "from") { - // ExportDeclaration :: export ExportClause FromClause - advance("from"); - advance("(string)"); - } else if (ok) { - exportedTokens.forEach(function(token) { - state.funct["(scope)"].setExported(token.value, token); - }); + + // It is valid to have a regular argument after a default argument + // since undefined can be used for missing parameters. Still warn as it is + // a possible code smell. + if (pastDefault) { + if (state.tokens.next.id !== "=") { + error("W138", state.tokens.curr); + } } - return this; - } + if (state.tokens.next.id === "=") { + if (!state.inES6()) { + warning("W119", state.tokens.next, "default parameters", "6"); + } - if (state.tokens.next.id === "var") { - // ExportDeclaration :: export VariableStatement - advance("var"); - state.tokens.curr.fud({ inexport:true }); - } else if (state.tokens.next.id === "let") { - // ExportDeclaration :: export VariableStatement - advance("let"); - state.tokens.curr.fud({ inexport:true }); - } else if (state.tokens.next.id === "const") { - // ExportDeclaration :: export VariableStatement - advance("const"); - state.tokens.curr.fud({ inexport:true }); - } else if (state.tokens.next.id === "function") { - // ExportDeclaration :: export Declaration - this.block = true; - advance("function"); - state.syntax["function"].fud({ inexport:true }); - } else if (state.tokens.next.id === "class") { - // ExportDeclaration :: export Declaration - this.block = true; - advance("class"); - var classNameToken = state.tokens.next; - state.syntax["class"].fud(); - state.funct["(scope)"].setExported(classNameToken.value, classNameToken); - } else { - error("E024", state.tokens.next, state.tokens.next.value); - } - - return this; - }).exps = true; - - // Future Reserved Words - - FutureReservedWord("abstract"); - FutureReservedWord("boolean"); - FutureReservedWord("byte"); - FutureReservedWord("char"); - FutureReservedWord("class", { es5: true, nud: classdef }); - FutureReservedWord("double"); - FutureReservedWord("enum", { es5: true }); - FutureReservedWord("export", { es5: true }); - FutureReservedWord("extends", { es5: true }); - FutureReservedWord("final"); - FutureReservedWord("float"); - FutureReservedWord("goto"); - FutureReservedWord("implements", { es5: true, strictOnly: true }); - FutureReservedWord("import", { es5: true }); - FutureReservedWord("int"); - FutureReservedWord("interface", { es5: true, strictOnly: true }); - FutureReservedWord("long"); - FutureReservedWord("native"); - FutureReservedWord("package", { es5: true, strictOnly: true }); - FutureReservedWord("private", { es5: true, strictOnly: true }); - FutureReservedWord("protected", { es5: true, strictOnly: true }); - FutureReservedWord("public", { es5: true, strictOnly: true }); - FutureReservedWord("short"); - FutureReservedWord("static", { es5: true, strictOnly: true }); - FutureReservedWord("super", { es5: true }); - FutureReservedWord("synchronized"); - FutureReservedWord("transient"); - FutureReservedWord("volatile"); - - // this function is used to determine whether a squarebracket or a curlybracket - // expression is a comprehension array, destructuring assignment or a json value. + if (pastRest) { + error("E062", state.tokens.next); + } - var lookupBlockType = function() { - var pn, pn1, prev; - var i = -1; - var bracketStack = 0; - var ret = {}; - if (checkPunctuators(state.tokens.curr, ["[", "{"])) { - bracketStack += 1; - } - do { - prev = i === -1 ? state.tokens.curr : pn; - pn = i === -1 ? state.tokens.next : peek(i); - pn1 = peek(i + 1); - i = i + 1; - if (checkPunctuators(pn, ["[", "{"])) { - bracketStack += 1; - } else if (checkPunctuators(pn, ["]", "}"])) { - bracketStack -= 1; - } - if (bracketStack === 1 && pn.identifier && pn.value === "for" && - !checkPunctuator(prev, ".")) { - ret.isCompArray = true; - ret.notJson = true; - break; + advance("="); + pastDefault = true; + expression(context, 10); } - if (bracketStack === 0 && checkPunctuators(pn, ["}", "]"])) { - if (pn1.value === "=") { - ret.isDestAssign = true; - ret.notJson = true; - break; - } else if (pn1.value === ".") { - ret.notJson = true; - break; + + // now we have evaluated the default expression, add the variable to the param scope + currentParams.forEach(addParam); + if (state.tokens.next.id === ",") { + if (pastRest) { + warning("W131", state.tokens.next); } + advance(","); + checkComma({ allowTrailing: true }); } - if (checkPunctuator(pn, ";")) { - ret.isBlock = true; - ret.notJson = true; - } - } while (bracketStack > 0 && pn.id !== "(end)"); - return ret; - }; - function saveProperty(props, name, tkn, isClass, isStatic) { - var msg = ["key", "class method", "static class method"]; - msg = msg[(isClass || false) + (isStatic || false)]; - if (tkn.identifier) { - name = tkn.value; - } + if (state.tokens.next.id === ")") { + if (state.tokens.curr.id === "," && !state.inES8()) { + warning("W119", state.tokens.curr, "Trailing comma in function parameters", "8"); + } - if (props[name] && name !== "__proto__") { - warning("W075", state.tokens.next, msg, name); - } else { - props[name] = Object.create(null); + advance(")", next); + return { + arity: arity, + params: paramsIds, + isSimple: !hasDestructuring && !pastRest && !pastDefault + }; + } } - - props[name].basic = true; - props[name].basictkn = tkn; } /** - * @param {string} accessorType - Either "get" or "set" - * @param {object} props - a collection of all properties of the object to - * which the current accessor is being assigned - * @param {object} tkn - the identifier token representing the accessor name - * @param {boolean} isClass - whether the accessor is part of an ES6 Class - * definition - * @param {boolean} isStatic - whether the accessor is a static method + * Factory function for creating objects used to track statistics of function + * literals. + * + * @param {string} name - the identifier name to associate with the function + * @param {object} [token] - token responsible for creating the function + * object + * @param {object} [overwrites] - a collection of properties that should + * override the corresponding default value of + * the new "functor" object */ - function saveAccessor(accessorType, props, name, tkn, isClass, isStatic) { - var flagName = accessorType === "get" ? "getterToken" : "setterToken"; - var msg = ""; + function functor(name, token, overwrites) { + var funct = { + "(name)" : name, + "(breakage)" : 0, + "(loopage)" : 0, + // The strictness of the function body is tracked via a dedicated + // property (as opposed to via the global `state` object) so that the + // value can be referenced after the body has been fully parsed (i.e. + // when validating the identifier used in function declarations and + // function expressions). + "(isStrict)" : "unknown", - if (isClass) { - if (isStatic) { - msg += "static "; - } - msg += accessorType + "ter method"; - } else { - msg = "key"; - } + "(global)" : false, - state.tokens.curr.accessorType = accessorType; - state.nameStack.set(tkn); + "(line)" : null, + "(character)" : null, + "(metrics)" : null, + "(statement)" : null, + "(context)" : null, + "(scope)" : null, + "(comparray)" : null, + "(yielded)" : null, + "(arrow)" : null, + "(async)" : null, + "(params)" : null + }; - if (props[name]) { - if ((props[name].basic || props[name][flagName]) && name !== "__proto__") { - warning("W075", state.tokens.next, msg, name); - } - } else { - props[name] = Object.create(null); + if (token) { + _.extend(funct, { + "(line)" : token.line, + "(character)": token.character, + "(metrics)" : createMetrics(token) + }); } - props[name][flagName] = tkn; - } + _.extend(funct, overwrites); - function computedPropertyName() { - advance("["); - if (!state.inES6()) { - warning("W119", state.tokens.curr, "computed property names", "6"); + if (funct["(context)"]) { + funct["(scope)"] = funct["(context)"]["(scope)"]; + funct["(comparray)"] = funct["(context)"]["(comparray)"]; } - var value = expression(10); - advance("]"); - return value; + + return funct; } /** - * Test whether a given token is a punctuator matching one of the specified values - * @param {Token} token - * @param {Array.} values + * Determine if the parser has begun parsing executable code. + * + * @param {Token} funct - The current "functor" token + * * @returns {boolean} */ - function checkPunctuators(token, values) { - if (token.type === "(punctuator)") { - return _.contains(values, token.value); - } - return false; + function hasParsedCode(funct) { + return funct["(global)"] && !funct["(verb)"]; } /** - * Test whether a given token is a punctuator matching the specified value - * @param {Token} token - * @param {string} value - * @returns {boolean} + * This function is used as both a null-denotation method *and* a + * left-denotation method, meaning the first parameter is overloaded. */ - function checkPunctuator(token, value) { - return token.type === "(punctuator)" && token.value === value; - } + function doTemplateLiteral(context, leftOrRbp) { + // ASSERT: this.type === "(template)" + // jshint validthis: true + var ctx = this.context; + var noSubst = this.noSubst; + var depth = this.depth; + var left = typeof leftOrRbp === "number" ? null : leftOrRbp; - // Check whether this function has been reached for a destructuring assign with undeclared values - function destructuringAssignOrJsonValue() { - // lookup for the assignment (ECMAScript 6 only) - // if it has semicolons, it is a block, so go parse it as a block - // or it's not a block, but there are assignments, check for undeclared variables + if (!noSubst) { + while (!end()) { + if (!state.tokens.next.template || state.tokens.next.depth > depth) { + expression(context, 0); // should probably have different rbp? + } else { + // skip template start / middle + advance(); + } + } + } - var block = lookupBlockType(); - if (block.notJson) { - if (!state.inES6() && block.isDestAssign) { - warning("W104", state.tokens.curr, "destructuring assignment", "6"); + return { + id: "(template)", + type: "(template)", + tag: left + }; + + function end() { + if (state.tokens.curr.template && state.tokens.curr.tail && + state.tokens.curr.context === ctx) { + /* istanbul ignore next */ + return true; } - statements(); - // otherwise parse json value - } else { - state.option.laxbreak = true; - state.jsonMode = true; - jsonValue(); + var complete = (state.tokens.next.template && state.tokens.next.tail && + state.tokens.next.context === ctx); + if (complete) advance(); + return complete || state.tokens.next.isUnclosed; } } - // array comprehension parsing function - // parses and defines the three states of the list comprehension in order - // to avoid defining global variables, but keeping them to the list comprehension scope - // only. The order of the states are as follows: - // * "use" which will be the returned iterative part of the list comprehension - // * "define" which will define the variables local to the list comprehension - // * "filter" which will help filter out values + /** + * Parse a function literal. + * + * @param {Number} context The parsing context + * @param {Object} [options] + * @param {string} [options.name] The identifier belonging to the function (if + * any) + * @param {token} [options.statement] The statement that triggered creation + * of the current function. + * @param {string} [options.type] If specified, either "generator" or "arrow" + * @param {token} [options.loneArg] The argument to the function in cases + * where it was defined using the + * single-argument shorthand + * @param {bool} [options.parsedOpening] Whether the opening parenthesis has + * already been parsed + * @param {string} [options.classExprBinding] Define a function with this + * identifier in the new function's + * scope, mimicking the bahavior of + * class expression names within + * the body of member functions. + */ + function doFunction(context, options) { + var f, token, name, statement, classExprBinding, isGenerator, isArrow, + isMethod, ignoreLoopFunc; + var oldOption = state.option; + var oldIgnored = state.ignored; + var isAsync = context & prodParams.preAsync; - var arrayComprehension = function() { - var CompArray = function() { - this.mode = "use"; - this.variables = []; - }; - var _carrays = []; - var _current; - function declare(v) { - var l = _current.variables.filter(function(elt) { - // if it has, change its undef state - if (elt.value === v) { - elt.undef = false; - return v; - } - }).length; - return l !== 0; - } - function use(v) { - var l = _current.variables.filter(function(elt) { - // and if it has been defined - if (elt.value === v && !elt.undef) { - if (elt.unused === true) { - elt.unused = false; - } - return v; - } - }).length; - // otherwise we warn about it - return (l === 0); + if (options) { + name = options.name; + statement = options.statement; + classExprBinding = options.classExprBinding; + isGenerator = options.type === "generator"; + isArrow = options.type === "arrow"; + isMethod = options.isMethod; + ignoreLoopFunc = options.ignoreLoopFunc; } - return { stack: function() { - _current = new CompArray(); - _carrays.push(_current); - }, - unstack: function() { - _current.variables.filter(function(v) { - if (v.unused) - warning("W098", v.token, v.raw_text || v.value); - if (v.undef) - state.funct["(scope)"].block.use(v.value, v.token); - }); - _carrays.splice(-1, 1); - _current = _carrays[_carrays.length - 1]; - }, - setState: function(s) { - if (_.contains(["use", "define", "generate", "filter"], s)) - _current.mode = s; - }, - check: function(v) { - if (!_current) { - return; - } - // When we are in "use" state of the list comp, we enqueue that var - if (_current && _current.mode === "use") { - if (use(v)) { - _current.variables.push({ - funct: state.funct, - token: state.tokens.curr, - value: v, - undef: true, - unused: false - }); - } - return true; - // When we are in "define" state of the list comp, - } else if (_current && _current.mode === "define") { - // check if the variable has been used previously - if (!declare(v)) { - _current.variables.push({ - funct: state.funct, - token: state.tokens.curr, - value: v, - undef: false, - unused: true - }); - } - return true; - // When we are in the "generate" state of the list comp, - } else if (_current && _current.mode === "generate") { - state.funct["(scope)"].block.use(v, state.tokens.curr); - return true; - // When we are in "filter" state, - } else if (_current && _current.mode === "filter") { - // we check whether current variable has been declared - if (use(v)) { - // if not we warn about it - state.funct["(scope)"].block.use(v, state.tokens.curr); - } - return true; - } - return false; - } - }; - }; - - // Parse JSON + context &= ~prodParams.noin; + context &= ~prodParams.tryClause; - function jsonValue() { - function jsonObject() { - var o = {}, t = state.tokens.next; - advance("{"); - if (state.tokens.next.id !== "}") { - for (;;) { - if (state.tokens.next.id === "(end)") { - error("E026", state.tokens.next, t.line); - } else if (state.tokens.next.id === "}") { - warning("W094", state.tokens.curr); - break; - } else if (state.tokens.next.id === ",") { - error("E028", state.tokens.next); - } else if (state.tokens.next.id !== "(string)") { - warning("W095", state.tokens.next, state.tokens.next.value); - } - if (o[state.tokens.next.value] === true) { - warning("W075", state.tokens.next, "key", state.tokens.next.value); - } else if ((state.tokens.next.value === "__proto__" && - !state.option.proto) || (state.tokens.next.value === "__iterator__" && - !state.option.iterator)) { - warning("W096", state.tokens.next, state.tokens.next.value); - } else { - o[state.tokens.next.value] = true; - } - advance(); - advance(":"); - jsonValue(); - if (state.tokens.next.id !== ",") { - break; - } - advance(","); - } - } - advance("}"); + if (isAsync) { + context |= prodParams.async; + } else { + context &= ~prodParams.async; } - function jsonArray() { - var t = state.tokens.next; - advance("["); - if (state.tokens.next.id !== "]") { - for (;;) { - if (state.tokens.next.id === "(end)") { - error("E027", state.tokens.next, t.line); - } else if (state.tokens.next.id === "]") { - warning("W094", state.tokens.curr); - break; - } else if (state.tokens.next.id === ",") { - error("E028", state.tokens.next); - } - jsonValue(); - if (state.tokens.next.id !== ",") { - break; - } - advance(","); - } - } - advance("]"); + if (isGenerator) { + context |= prodParams.yield; + } else if (!isArrow) { + context &= ~prodParams.yield; } + context &= ~prodParams.preAsync; - switch (state.tokens.next.id) { - case "{": - jsonObject(); - break; - case "[": - jsonArray(); - break; - case "true": - case "false": - case "null": - case "(number)": - case "(string)": - advance(); - break; - case "-": - advance("-"); - advance("(number)"); - break; - default: - error("E003", state.tokens.next); + state.option = Object.create(state.option); + state.ignored = Object.create(state.ignored); + + state.funct = functor(name || state.nameStack.infer(), state.tokens.next, { + "(statement)": statement, + "(context)": state.funct, + "(arrow)": isArrow, + "(method)": isMethod, + "(async)": isAsync + }); + + f = state.funct; + token = state.tokens.curr; + + functions.push(state.funct); + + // So that the function is available to itself and referencing itself is not + // seen as a closure, add the function name to a new scope, but do not + // test for unused (unused: false) + // it is a new block scope so that params can override it, it can be block scoped + // but declarations inside the function don't cause already declared error + state.funct["(scope)"].stack("functionouter"); + var internallyAccessibleName = !isMethod && (name || classExprBinding); + if (internallyAccessibleName) { + state.funct["(scope)"].block.add(internallyAccessibleName, + classExprBinding ? "class" : "function", state.tokens.curr, false); } - } - var escapeRegex = function(str) { - return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); - }; + if (!isArrow) { + state.funct["(scope)"].funct.add("arguments", "var", token, false); + } - // The actual JSHINT function itself. - var itself = function(s, o, g) { - var i, k, x, reIgnoreStr, reIgnore; - var optionKeys; - var newOptionObj = {}; - var newIgnoredObj = {}; + // create the param scope (params added in functionparams) + state.funct["(scope)"].stack("functionparams"); - o = _.clone(o); - state.reset(); + var paramsInfo = functionparams(context, options); - if (o && o.scope) { - JSHINT.scope = o.scope; + if (paramsInfo) { + state.funct["(params)"] = paramsInfo.params; + state.funct["(hasSimpleParams)"] = paramsInfo.isSimple; + state.funct["(metrics)"].arity = paramsInfo.arity; + state.funct["(metrics)"].verifyMaxParametersPerFunction(); } else { - JSHINT.errors = []; - JSHINT.undefs = []; - JSHINT.internals = []; - JSHINT.blacklist = {}; - JSHINT.scope = "(main)"; + state.funct["(params)"] = []; + state.funct["(metrics)"].arity = 0; + state.funct["(hasSimpleParams)"] = true; } - predefined = Object.create(null); - combine(predefined, vars.ecmaIdentifiers[3]); - combine(predefined, vars.reservedVars); - - combine(predefined, g || {}); + if (isArrow) { + context &= ~prodParams.yield; - declared = Object.create(null); - var exported = Object.create(null); // Variables that live outside the current file + if (!state.inES6(true)) { + warning("W119", state.tokens.curr, "arrow function syntax (=>)", "6"); + } - function each(obj, cb) { - if (!obj) - return; + if (!options.loneArg) { + advance("=>"); + } + } - if (!Array.isArray(obj) && typeof obj === "object") - obj = Object.keys(obj); + block(context, false, true, true, isArrow); - obj.forEach(cb); + if (!state.option.noyield && isGenerator && !state.funct["(yielded)"]) { + warning("W124", state.tokens.curr); } - if (o) { - each(o.predef || null, function(item) { - var slice, prop; - - if (item[0] === "-") { - slice = item.slice(1); - JSHINT.blacklist[slice] = slice; - // remove from predefined if there - delete predefined[slice]; - } else { - prop = Object.getOwnPropertyDescriptor(o.predef, item); - predefined[item] = prop ? prop.value : false; - } - }); + state.funct["(metrics)"].verifyMaxStatementsPerFunction(); + state.funct["(metrics)"].verifyMaxComplexityPerFunction(); + state.funct["(unusedOption)"] = state.option.unused; + state.option = oldOption; + state.ignored = oldIgnored; + state.funct["(last)"] = state.tokens.curr.line; + state.funct["(lastcharacter)"] = state.tokens.curr.character; - each(o.exported || null, function(item) { - exported[item] = true; - }); + // unstack the params scope + state.funct["(scope)"].unstack(); // also does usage and label checks - delete o.predef; - delete o.exported; + // unstack the function outer stack + state.funct["(scope)"].unstack(); - optionKeys = Object.keys(o); - for (x = 0; x < optionKeys.length; x++) { - if (/^-W\d{3}$/g.test(optionKeys[x])) { - newIgnoredObj[optionKeys[x].slice(1)] = true; - } else { - var optionKey = optionKeys[x]; - newOptionObj[optionKey] = o[optionKey]; - if ((optionKey === "esversion" && o[optionKey] === 5) || - (optionKey === "es5" && o[optionKey])) { - warning("I003"); - } + state.funct = state.funct["(context)"]; - if (optionKeys[x] === "newcap" && o[optionKey] === false) - newOptionObj["(explicitNewcap)"] = true; - } + if (!ignoreLoopFunc && !state.option.loopfunc && state.funct["(loopage)"]) { + // If the function we just parsed accesses any non-local variables + // trigger a warning. Otherwise, the function is safe even within + // a loop. + if (f["(outerMutables)"]) { + warning("W083", token, f["(outerMutables)"].join(", ")); } } - state.option = newOptionObj; - state.ignored = newIgnoredObj; + return f; + } - state.option.indent = state.option.indent || 4; - state.option.maxerr = state.option.maxerr || 50; + function createMetrics(functionStartToken) { + return { + statementCount: 0, + nestedBlockDepth: -1, + ComplexityCount: 1, + arity: 0, - indent = 1; + verifyMaxStatementsPerFunction: function() { + if (state.option.maxstatements && + this.statementCount > state.option.maxstatements) { + warning("W071", functionStartToken, this.statementCount); + } + }, - var scopeManagerInst = scopeManager(state, predefined, exported, declared); - scopeManagerInst.on("warning", function(ev) { - warning.apply(null, [ ev.code, ev.token].concat(ev.data)); - }); + verifyMaxParametersPerFunction: function() { + if (_.isNumber(state.option.maxparams) && + this.arity > state.option.maxparams) { + warning("W072", functionStartToken, this.arity); + } + }, - scopeManagerInst.on("error", function(ev) { - error.apply(null, [ ev.code, ev.token ].concat(ev.data)); - }); + verifyMaxNestedBlockDepthPerFunction: function() { + if (state.option.maxdepth && + this.nestedBlockDepth > 0 && + this.nestedBlockDepth === state.option.maxdepth + 1) { + warning("W073", null, this.nestedBlockDepth); + } + }, - state.funct = functor("(global)", null, { - "(global)" : true, - "(scope)" : scopeManagerInst, - "(comparray)" : arrayComprehension(), - "(metrics)" : createMetrics(state.tokens.next) - }); + verifyMaxComplexityPerFunction: function() { + var max = state.option.maxcomplexity; + var cc = this.ComplexityCount; + if (max && cc > max) { + warning("W074", functionStartToken, cc); + } + } + }; + } - functions = [state.funct]; - urls = []; - stack = null; - member = {}; - membersOnly = null; - inblock = false; - lookahead = []; + function increaseComplexityCount() { + state.funct["(metrics)"].ComplexityCount += 1; + } - if (!isString(s) && !Array.isArray(s)) { - errorAt("E004", 0); - return false; + // Parse assignments that were found instead of conditionals. + // For example: if (a = 1) { ... } + + function checkCondAssignment(token) { + if (!token || token.paren) { + return; } - api = { - get isJSON() { - return state.jsonMode; - }, + if (token.id === ",") { + checkCondAssignment(token.right); + return; + } - getOption: function(name) { - return state.option[name] || null; - }, + switch (token.id) { + case "=": + case "+=": + case "-=": + case "*=": + case "%=": + case "&=": + case "|=": + case "^=": + case "/=": + if (!state.option.boss) { + warning("W084", token); + } + } + } - getCache: function(name) { - return state.cache[name]; - }, + /** + * Validate the properties defined within an object literal or class body. + * See the `saveAccessor` and `saveProperty` functions for more detail. + * + * @param {object} props - Collection of objects describing the properties + * encountered + */ + function checkProperties(props) { + // Check for lonely setters if in the ES5 mode. + if (state.inES5()) { + for (var name in props) { + if (props[name] && props[name].setterToken && !props[name].getterToken && + !props[name].static) { + warning("W078", props[name].setterToken); + } + } + } + } - setCache: function(name, value) { - state.cache[name] = value; - }, + function metaProperty(context, name, c) { + if (checkPunctuator(state.tokens.next, ".")) { + var left = state.tokens.curr.id; + advance("."); + var id = identifier(context); + state.tokens.curr.isMetaProperty = true; + if (name !== id) { + error("E057", state.tokens.prev, left, id); + } else { + c(); + } + return state.tokens.curr; + } + } - warn: function(code, data) { - warningAt.apply(null, [ code, data.line, data.char ].concat(data.data)); - }, +//object literals + (function(x) { + x.nud = function(context) { + var b, f, i, params, t, isGeneratorMethod = false, nextVal; + var props = Object.create(null); // All properties, including accessors + var isAsyncMethod = false; - on: function(names, listener) { - names.split(" ").forEach(function(name) { - emitter.on(name, listener); - }.bind(this)); + b = !sameLine(state.tokens.curr, state.tokens.next); + if (b) { + indent += state.option.indent; + if (state.tokens.next.from === indent + state.option.indent) { + /* istanbul ignore next */ + indent += state.option.indent; + } } - }; - emitter.removeAllListeners(); - (extraModules || []).forEach(function(func) { - func(api); - }); + var blocktype = lookupBlockType(); + if (blocktype.isDestAssign) { + this.destructAssign = destructuringPattern(context, { + openingParsed: true, + assignment: true + }); + return this; + } + state.inObjectBody = true; + for (;;) { + if (state.tokens.next.id === "}") { + break; + } - state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"]; + nextVal = state.tokens.next.value; + if (state.tokens.next.identifier && + (peekIgnoreEOL().id === "," || peekIgnoreEOL().id === "}")) { + if (!state.inES6()) { + warning("W104", state.tokens.next, "object short notation", "6"); + } + i = propertyName(context, true); + saveProperty(props, i, state.tokens.next); - if (o && o.ignoreDelimiters) { + expression(context, 10); - if (!Array.isArray(o.ignoreDelimiters)) { - o.ignoreDelimiters = [o.ignoreDelimiters]; - } + } else if (peek().id !== ":" && (nextVal === "get" || nextVal === "set")) { + advance(nextVal); - o.ignoreDelimiters.forEach(function(delimiterPair) { - if (!delimiterPair.start || !delimiterPair.end) - return; + if (!state.inES5()) { + error("E034"); + } - reIgnoreStr = escapeRegex(delimiterPair.start) + - "[\\s\\S]*?" + - escapeRegex(delimiterPair.end); + if (state.tokens.next.id === "[") { + i = computedPropertyName(context); + } else { + i = propertyName(context); - reIgnore = new RegExp(reIgnoreStr, "ig"); + // ES6 allows for get() {...} and set() {...} method + // definition shorthand syntax, so we don't produce an error + // if linting ECMAScript 6 code. + if (!i && !state.inES6()) { + error("E035"); + } + } - s = s.replace(reIgnore, function(match) { - return match.replace(/./g, " "); - }); - }); - } + // We don't want to save this getter unless it's an actual getter + // and not an ES6 concise method + if (i) { + saveAccessor(nextVal, props, i, state.tokens.curr); + } - lex = new Lexer(s); + t = state.tokens.next; + f = doFunction(context, { isMethod: true }); + params = f["(params)"]; - lex.on("warning", function(ev) { - warningAt.apply(null, [ ev.code, ev.line, ev.character].concat(ev.data)); - }); + // Don't warn about getter/setter pairs if this is an ES6 concise method + if (nextVal === "get" && i && params.length) { + warning("W076", t, params[0], i); + } else if (nextVal === "set" && i && f["(metrics)"].arity !== 1) { + warning("W077", t, i); + } - lex.on("error", function(ev) { - errorAt.apply(null, [ ev.code, ev.line, ev.character ].concat(ev.data)); - }); + } else if (spreadrest("spread")) { + if (!state.inES9()) { + warning("W119", state.tokens.next, "object spread property", "9"); + } - lex.on("fatal", function(ev) { - quit("E041", ev.line, ev.from); - }); + expression(context, 10); + } else { + if (state.tokens.next.id === "async" && !checkPunctuators(peek(), ["(", ":"])) { + if (!state.inES8()) { + warning("W119", state.tokens.next, "async functions", "8"); + } - lex.on("Identifier", function(ev) { - emitter.emit("Identifier", ev); - }); + isAsyncMethod = true; + advance(); - lex.on("String", function(ev) { - emitter.emit("String", ev); - }); + nolinebreak(state.tokens.curr); + } else { + isAsyncMethod = false; + } - lex.on("Number", function(ev) { - emitter.emit("Number", ev); - }); + if (state.tokens.next.value === "*" && state.tokens.next.type === "(punctuator)") { + if (isAsyncMethod && !state.inES9()) { + warning("W119", state.tokens.next, "async generators", "9"); + } else if (!state.inES6()) { + warning("W104", state.tokens.next, "generator functions", "6"); + } - lex.start(); + advance("*"); + isGeneratorMethod = true; + } else { + isGeneratorMethod = false; + } - // Check options - for (var name in o) { - if (_.has(o, name)) { - checkOption(name, state.tokens.curr); - } - } + if (state.tokens.next.id === "[") { + i = computedPropertyName(context); + state.nameStack.set(i); + } else { + state.nameStack.set(state.tokens.next); + i = propertyName(context); + saveProperty(props, i, state.tokens.next); - assume(); + if (typeof i !== "string") { + break; + } + } - // combine the passed globals after we've assumed all our options - combine(predefined, g || {}); + if (state.tokens.next.value === "(") { + if (!state.inES6()) { + warning("W104", state.tokens.curr, "concise methods", "6"); + } - //reset values - comma.first = true; + doFunction(isAsyncMethod ? context | prodParams.preAsync : context, { + isMethod: true, + type: isGeneratorMethod ? "generator" : null + }); + } else { + advance(":"); + expression(context, 10); + } + } - try { - advance(); - switch (state.tokens.next.id) { - case "{": - case "[": - destructuringAssignOrJsonValue(); - break; - default: - directives(); + countMember(i); - if (state.directive["use strict"]) { - if (state.option.strict !== "global") { - warning("W097", state.tokens.prev); + if (state.tokens.next.id === ",") { + advance(","); + checkComma({ allowTrailing: true, property: true }); + if (state.tokens.next.id === ",") { + /* istanbul ignore next */ + warning("W070", state.tokens.curr); + } else if (state.tokens.next.id === "}" && !state.inES5()) { + warning("W070", state.tokens.curr); + } + } else { + if (state.option.trailingcomma && state.inES5()) { + warningAt("W140", state.tokens.curr.line, state.tokens.curr.character); } + break; } - - statements(); } - - if (state.tokens.next.id !== "(end)") { - quit("E041", state.tokens.curr.line); + if (b) { + indent -= state.option.indent; } + advance("}", this); - state.funct["(scope)"].unstack(); + checkProperties(props); + state.inObjectBody = false; - } catch (err) { - if (err && err.name === "JSHintError") { - var nt = state.tokens.next || {}; - JSHINT.errors.push({ - scope : "(main)", - raw : err.raw, - code : err.code, - reason : err.message, - line : err.line || nt.line, - character : err.character || nt.from - }, null); - } else { - throw err; - } - } + return this; + }; + x.fud = function() { + /* istanbul ignore next */ + error("E036", state.tokens.curr); + }; + }(delim("{"))); - // Loop over the listed "internals", and check them as well. + function destructuringPattern(context, options) { + var isAssignment = options && options.assignment; - if (JSHINT.scope === "(main)") { - o = o || {}; + context &= ~prodParams.noin; - for (i = 0; i < JSHINT.internals.length; i += 1) { - k = JSHINT.internals[i]; - o.scope = k.elem; - itself(k.value, o, g); - } + if (!state.inES6()) { + warning("W104", state.tokens.curr, + isAssignment ? "destructuring assignment" : "destructuring binding", "6"); } - return JSHINT.errors.length === 0; - }; + return destructuringPatternRecursive(context, options); + } - // Modules. - itself.addModule = function(func) { - extraModules.push(func); - }; + function destructuringPatternRecursive(context, options) { + var ids, idx; + var identifiers = []; + var openingParsed = options && options.openingParsed; + var isAssignment = options && options.assignment; + var recursiveOptions = isAssignment ? { assignment: isAssignment } : null; + var firstToken = openingParsed ? state.tokens.curr : state.tokens.next; - itself.addModule(style.register); + var nextInnerDE = function() { + var ident; + if (checkPunctuators(state.tokens.next, ["[", "{"])) { + ids = destructuringPatternRecursive(context, recursiveOptions); + for (idx = 0; idx < ids.length; idx++) { + identifiers.push({ id: ids[idx].id, token: ids[idx].token }); + } + } else if (checkPunctuator(state.tokens.next, ",")) { + identifiers.push({ id: null, token: state.tokens.curr }); + } else if (checkPunctuator(state.tokens.next, "(")) { + advance("("); + nextInnerDE(); + advance(")"); + } else { + if (isAssignment) { + var assignTarget = expression(context, 20); + if (assignTarget) { + checkLeftSideAssign(context, assignTarget); - // Data summary. - itself.data = function() { - var data = { - functions: [], - options: state.option + // if the target was a simple identifier, add it to the list to return + if (assignTarget.identifier) { + ident = assignTarget.value; + } + } + } else { + ident = identifier(context); + } + if (ident) { + identifiers.push({ id: ident, token: state.tokens.curr }); + } + } }; - var fu, f, i, j, n, globals; + var assignmentProperty = function(context) { + var id, expr; - if (itself.errors.length) { - data.errors = itself.errors; - } + if (checkPunctuator(state.tokens.next, "[")) { + advance("["); + expression(context, 10); + advance("]"); + advance(":"); + nextInnerDE(); + } else if (state.tokens.next.id === "(string)" || + state.tokens.next.id === "(number)") { + advance(); + advance(":"); + nextInnerDE(); + } else { + // this id will either be the property name or the property name and the assigning identifier + var isRest = spreadrest("rest"); - if (state.jsonMode) { - data.json = true; - } + if (isRest) { + if (!state.inES9()) { + warning("W119", state.tokens.next, "object rest property", "9"); + } - var impliedGlobals = state.funct["(scope)"].getImpliedGlobals(); - if (impliedGlobals.length > 0) { - data.implieds = impliedGlobals; - } + // Due to visual symmetry with the array rest property (and the early + // design of the language feature), developers may mistakenly assume + // any expression is valid in this position. If the next token is not + // an identifier, attempt to parse an expression and issue an error. + // order to recover more gracefully from this condition. + if (state.tokens.next.type === "(identifier)") { + id = identifier(context); + } else { + expr = expression(context, 10); + error("E030", expr, expr.value); + } + } else { + id = identifier(context); + } - if (urls.length > 0) { - data.urls = urls; - } + if (!isRest && checkPunctuator(state.tokens.next, ":")) { + advance(":"); + nextInnerDE(); + } else if (id) { + // in this case we are assigning (not declaring), so check assignment + if (isAssignment) { + checkLeftSideAssign(context, state.tokens.curr); + } + identifiers.push({ id: id, token: state.tokens.curr }); + } - globals = state.funct["(scope)"].getUsedOrDefinedGlobals(); - if (globals.length > 0) { - data.globals = globals; - } + if (isRest && checkPunctuator(state.tokens.next, ",")) { + warning("W130", state.tokens.next); + } + } + }; - for (i = 1; i < functions.length; i += 1) { - f = functions[i]; - fu = {}; + var id, value; + if (checkPunctuator(firstToken, "[")) { + if (!openingParsed) { + advance("["); + } + if (checkPunctuator(state.tokens.next, "]")) { + warning("W137", state.tokens.curr); + } + var element_after_rest = false; + while (!checkPunctuator(state.tokens.next, "]")) { + var isRest = spreadrest("rest"); - for (j = 0; j < functionicity.length; j += 1) { - fu[functionicity[j]] = []; + nextInnerDE(); + + if (isRest && !element_after_rest && + checkPunctuator(state.tokens.next, ",")) { + warning("W130", state.tokens.next); + element_after_rest = true; + } + if (!isRest && checkPunctuator(state.tokens.next, "=")) { + if (checkPunctuator(state.tokens.prev, "...")) { + /* istanbul ignore next */ + advance("]"); + } else { + advance("="); + } + id = state.tokens.prev; + value = expression(context, 10); + if (value && value.identifier && value.value === "undefined") { + warning("W080", id, id.value); + } + } + if (!checkPunctuator(state.tokens.next, "]")) { + advance(","); + } } + advance("]"); + } else if (checkPunctuator(firstToken, "{")) { - for (j = 0; j < functionicity.length; j += 1) { - if (fu[functionicity[j]].length === 0) { - delete fu[functionicity[j]]; + if (!openingParsed) { + advance("{"); + } + if (checkPunctuator(state.tokens.next, "}")) { + warning("W137", state.tokens.curr); + } + while (!checkPunctuator(state.tokens.next, "}")) { + assignmentProperty(context); + if (checkPunctuator(state.tokens.next, "=")) { + advance("="); + id = state.tokens.prev; + value = expression(context, 10); + if (value && value.identifier && value.value === "undefined") { + warning("W080", id, id.value); + } + } + if (!checkPunctuator(state.tokens.next, "}")) { + advance(","); + if (checkPunctuator(state.tokens.next, "}")) { + // Trailing comma + // ObjectBindingPattern: { BindingPropertyList , } + break; + } } } + advance("}"); + } + return identifiers; + } - fu.name = f["(name)"]; - fu.param = f["(params)"]; - fu.line = f["(line)"]; - fu.character = f["(character)"]; - fu.last = f["(last)"]; - fu.lastcharacter = f["(lastcharacter)"]; + function destructuringPatternMatch(tokens, value) { + var first = value.first; - fu.metrics = { - complexity: f["(metrics)"].ComplexityCount, - parameters: f["(metrics)"].arity, - statements: f["(metrics)"].statementCount - }; + if (!first) + return; - data.functions.push(fu); + _.zip(tokens, Array.isArray(first) ? first : [ first ]).forEach(function(val) { + var token = val[0]; + var value = val[1]; + + if (token && value) + token.first = value; + else if (token && token.first && !value) + /* istanbul ignore next */ + warning("W080", token.first, token.first.value); + }); + } + + function blockVariableStatement(type, statement, context) { + // used for both let and const statements + + var noin = context & prodParams.noin; + var inexport = context & prodParams.export; + var isLet = type === "let"; + var isConst = type === "const"; + var tokens, lone, value, letblock; + + if (!state.inES6()) { + warning("W104", state.tokens.curr, type, "6"); } - var unuseds = state.funct["(scope)"].getUnuseds(); - if (unuseds.length > 0) { - data.unused = unuseds; + if (isLet && isMozillaLet()) { + advance("("); + state.funct["(scope)"].stack(); + letblock = true; + statement.declaration = false; } - for (n in member) { - if (typeof member[n] === "number") { - data.member = member; - break; + statement.first = []; + for (;;) { + var names = []; + if (_.includes(["{", "["], state.tokens.next.value)) { + tokens = destructuringPattern(context); + lone = false; + } else { + tokens = [ { id: identifier(context), token: state.tokens.curr } ]; + lone = true; } - } - return data; - }; + // A `const` declaration without an initializer is permissible within the + // head of for-in and for-of statements. If this binding list is being + // parsed as part of a `for` statement of any kind, allow the initializer + // to be omitted. Although this may erroneously allow such forms from + // "C-style" `for` statements (i.e. `for (const x;;) {}`, the `for` + // statement logic includes dedicated logic to issue the error for such + // cases. + if (!noin && isConst && state.tokens.next.id !== "=") { + warning("E012", state.tokens.curr, state.tokens.curr.value); + } - itself.jshint = itself; + for (var t in tokens) { + if (tokens.hasOwnProperty(t)) { + t = tokens[t]; - return itself; -}()); + // It is a Syntax Error if the BoundNames of BindingList contains + // "let". + if (t.id === "let") { + /* istanbul ignore next */ + warning("W024", t.token, t.id); + } -// Make JSHINT a Node module, if possible. -if (typeof exports === "object" && exports) { - exports.JSHINT = JSHINT; -} + if (state.funct["(scope)"].block.isGlobal()) { + if (predefined[t.id] === false) { + warning("W079", t.token, t.id); + } + } + if (t.id) { + state.funct["(scope)"].addbinding(t.id, { + type: type, + token: t.token }); + names.push(t.token); + } + } + } -},{"../lodash":"/node_modules/jshint/lodash.js","./lex.js":"/node_modules/jshint/src/lex.js","./messages.js":"/node_modules/jshint/src/messages.js","./options.js":"/node_modules/jshint/src/options.js","./reg.js":"/node_modules/jshint/src/reg.js","./scope-manager.js":"/node_modules/jshint/src/scope-manager.js","./state.js":"/node_modules/jshint/src/state.js","./style.js":"/node_modules/jshint/src/style.js","./vars.js":"/node_modules/jshint/src/vars.js","events":"/node_modules/browserify/node_modules/events/events.js"}],"/node_modules/jshint/src/lex.js":[function(_dereq_,module,exports){ -/* - * Lexical analysis and token construction. - */ + if (state.tokens.next.id === "=") { + statement.hasInitializer = true; -"use strict"; + advance("="); + if (!noin && peek(0).id === "=" && state.tokens.next.identifier) { + warning("W120", state.tokens.next, state.tokens.next.value); + } + var id = state.tokens.prev; + value = expression(context, 10); + if (value) { + if (value.identifier && value.value === "undefined") { + warning("W080", id, id.value); + } + if (!lone) { + destructuringPatternMatch(names, value); + } + } + } -var _ = _dereq_("../lodash"); -var events = _dereq_("events"); -var reg = _dereq_("./reg.js"); -var state = _dereq_("./state.js").state; + // Bindings are not immediately initialized in for-in and for-of + // statements. As with `const` initializers (described above), the `for` + // statement parsing logic includes + if (state.tokens.next.value !== "in" && state.tokens.next.value !== "of") { + for (t in tokens) { + if (tokens.hasOwnProperty(t)) { + t = tokens[t]; + state.funct["(scope)"].initialize(t.id); -var unicodeData = _dereq_("../data/ascii-identifier-data.js"); -var asciiIdentifierStartTable = unicodeData.asciiIdentifierStartTable; -var asciiIdentifierPartTable = unicodeData.asciiIdentifierPartTable; + if (lone && inexport) { + state.funct["(scope)"].setExported(t.token.value, t.token); + } + } + } + } -// Some of these token types are from JavaScript Parser API -// while others are specific to JSHint parser. -// JS Parser API: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API + statement.first = statement.first.concat(names); -var Token = { - Identifier: 1, - Punctuator: 2, - NumericLiteral: 3, - StringLiteral: 4, - Comment: 5, - Keyword: 6, - NullLiteral: 7, - BooleanLiteral: 8, - RegExp: 9, - TemplateHead: 10, - TemplateMiddle: 11, - TemplateTail: 12, - NoSubstTemplate: 13 -}; + if (state.tokens.next.id !== ",") { + break; + } -var Context = { - Block: 1, - Template: 2 -}; + statement.hasComma = true; + advance(","); + checkComma(); + } + if (letblock) { + advance(")"); + block(context, true, true); + statement.block = true; + state.funct["(scope)"].unstack(); + } -// Object that handles postponed lexing verifications that checks the parsed -// environment state. + return statement; + } -function asyncTrigger() { - var _checks = []; + var conststatement = stmt("const", function(context) { + return blockVariableStatement("const", this, context); + }); + conststatement.exps = true; + conststatement.declaration = true; - return { - push: function(fn) { - _checks.push(fn); - }, - check: function() { - for (var check = 0; check < _checks.length; ++check) { - _checks[check](); - } + /** + * Determine if the current `let` token designates the beginning of a "let + * block" or "let expression" as implemented in the Mozilla SpiderMonkey + * engine. + * + * This function will only return `true` if Mozilla extensions have been + * enabled. It would be preferable to detect the language feature regardless + * of the parser's state because this would allow JSHint to instruct users to + * enable the `moz` option where necessary. This is not possible because the + * language extension is not compatible with standard JavaScript. For + * example, the following program code may describe a "let block" or a + * function invocation: + * + * let(x) + * { + * typeof x; + * } + * + * @returns {boolean} + */ + function isMozillaLet() { + return state.tokens.next.id === "(" && state.inMoz(); + } + var letstatement = stmt("let", function(context) { + return blockVariableStatement("let", this, context); + }); + letstatement.nud = function(context, rbp) { + if (isMozillaLet()) { + // create a new block scope we use only for the current expression + state.funct["(scope)"].stack(); + advance("("); + state.tokens.prev.fud(context); + advance(")"); + expression(context, rbp); + state.funct["(scope)"].unstack(); + } else { + this.exps = false; + return state.syntax["(identifier)"].nud.apply(this, arguments); + } + }; + letstatement.meta = { es5: true, isFutureReservedWord: false, strictOnly: true }; + letstatement.exps = true; + letstatement.declaration = true; + letstatement.useFud = function(context) { + var next = state.tokens.next; + var nextIsBindingName; - _checks.splice(0, _checks.length); + if (this.line !== next.line && !state.inES6()) { + return false; } + + // JSHint generally interprets `let` as a reserved word even though it is + // not considered as such by the ECMAScript specification because doing so + // simplifies parsing logic. It is special-cased here so that code such as + // + // let + // let + // + // is correctly interpreted as an invalid LexicalBinding. (Without this + // consideration, the code above would be parsed as two + // IdentifierReferences.) + nextIsBindingName = next.identifier && (!isReserved(context, next) || + next.id === "let"); + + return nextIsBindingName || checkPunctuators(next, ["{", "["]) || + isMozillaLet(); }; -} -/* - * Lexer for JSHint. - * - * This object does a char-by-char scan of the provided source code - * and produces a sequence of tokens. - * - * var lex = new Lexer("var i = 0;"); - * lex.start(); - * lex.token(); // returns the next token - * - * You have to use the token() method to move the lexer forward - * but you don't have to use its return value to get tokens. In addition - * to token() method returning the next token, the Lexer object also - * emits events. - * - * lex.on("Identifier", function(data) { - * if (data.name.indexOf("_") >= 0) { - * // Produce a warning. - * } - * }); - * - * Note that the token() method returns tokens in a JSLint-compatible - * format while the event emitter uses a slightly modified version of - * Mozilla's JavaScript Parser API. Eventually, we will move away from - * JSLint format. - */ -function Lexer(source) { - var lines = source; + var varstatement = stmt("var", function(context) { + var noin = context & prodParams.noin; + var inexport = context & prodParams.export; + var tokens, lone, value, id; - if (typeof lines === "string") { - lines = lines - .replace(/\r\n/g, "\n") - .replace(/\r/g, "\n") - .split("\n"); - } + this.first = []; + for (;;) { + var names = []; + if (_.includes(["{", "["], state.tokens.next.value)) { + tokens = destructuringPattern(context); + lone = false; + } else { + tokens = []; + id = identifier(context); - // If the first line is a shebang (#!), make it a blank and move on. - // Shebangs are used by Node scripts. + if (id) { + tokens.push({ id: id, token: state.tokens.curr }); + } - if (lines[0] && lines[0].substr(0, 2) === "#!") { - if (lines[0].indexOf("node") !== -1) { - state.option.node = true; - } - lines[0] = ""; - } + lone = true; + } - this.emitter = new events.EventEmitter(); - this.source = source; - this.setLines(lines); - this.prereg = true; + if (state.option.varstmt) { + warning("W132", this); + } - this.line = 0; - this.char = 1; - this.from = 1; - this.input = ""; - this.inComment = false; - this.context = []; - this.templateStarts = []; - for (var i = 0; i < state.option.indent; i += 1) { - state.tab += " "; - } + for (var t in tokens) { + if (tokens.hasOwnProperty(t)) { + t = tokens[t]; + if (state.funct["(global)"] && !state.impliedClosure()) { + if (predefined[t.id] === false) { + warning("W079", t.token, t.id); + } else if (state.option.futurehostile === false) { + if ((!state.inES5() && vars.ecmaIdentifiers[5][t.id] === false) || + (!state.inES6() && vars.ecmaIdentifiers[6][t.id] === false)) { + warning("W129", t.token, t.id); + } + } + } + if (t.id) { + state.funct["(scope)"].addbinding(t.id, { + type: "var", + token: t.token }); - // Blank out non-multi-line-commented lines when ignoring linter errors - this.ignoreLinterErrors = false; -} + if (lone && inexport) { + state.funct["(scope)"].setExported(t.id, t.token); + } + names.push(t.token); + } + } + } -Lexer.prototype = { - _lines: [], + if (state.tokens.next.id === "=") { + this.hasInitializer = true; - inContext: function(ctxType) { - return this.context.length > 0 && this.context[this.context.length - 1].type === ctxType; - }, + state.nameStack.set(state.tokens.curr); - pushContext: function(ctxType) { - this.context.push({ type: ctxType }); - }, + advance("="); + if (peek(0).id === "=" && state.tokens.next.identifier) { + if (!noin && + !state.funct["(params)"] || + state.funct["(params)"].indexOf(state.tokens.next.value) === -1) { + warning("W120", state.tokens.next, state.tokens.next.value); + } + } + id = state.tokens.prev; + value = expression(context, 10); + if (value) { + if (!state.funct["(loopage)"] && value.identifier && + value.value === "undefined") { + warning("W080", id, id.value); + } + if (!lone) { + destructuringPatternMatch(names, value); + } + } + } - popContext: function() { - return this.context.pop(); - }, + this.first = this.first.concat(names); - isContext: function(context) { - return this.context.length > 0 && this.context[this.context.length - 1] === context; - }, + if (state.tokens.next.id !== ",") { + break; + } + this.hasComma = true; + advance(","); + checkComma(); + } - currentContext: function() { - return this.context.length > 0 && this.context[this.context.length - 1]; - }, + return this; + }); + varstatement.exps = true; - getLines: function() { - this._lines = state.lines; - return this._lines; - }, + blockstmt("function", function(context) { + var inexport = context & prodParams.export; + var generator = false; + var isAsync = context & prodParams.preAsync; + var labelType = ""; - setLines: function(val) { - this._lines = val; - state.lines = this._lines; - }, + if (isAsync) { + labelType = "async "; + } - /* - * Return the next i character without actually moving the - * char pointer. - */ - peek: function(i) { - return this.input.charAt(i || 0); - }, + if (state.tokens.next.value === "*") { + if (isAsync && !state.inES9()) { + warning("W119", state.tokens.prev, "async generators", "9"); + } else if (!isAsync && !state.inES6(true)) { + warning("W119", state.tokens.next, "function*", "6"); + } - /* - * Move the char pointer forward i times. - */ - skip: function(i) { - i = i || 1; - this.char += i; - this.input = this.input.slice(i); - }, + advance("*"); + labelType += "generator "; + generator = true; + } - /* - * Subscribe to a token event. The API for this method is similar - * Underscore.js i.e. you can subscribe to multiple events with - * one call: - * - * lex.on("Identifier Number", function(data) { - * // ... - * }); - */ - on: function(names, listener) { - names.split(" ").forEach(function(name) { - this.emitter.on(name, listener); - }.bind(this)); - }, + labelType += "function"; - /* - * Trigger a token event. All arguments will be passed to each - * listener. - */ - trigger: function() { - this.emitter.emit.apply(this.emitter, Array.prototype.slice.call(arguments)); - }, - - /* - * Postpone a token event. the checking condition is set as - * last parameter, and the trigger function is called in a - * stored callback. To be later called using the check() function - * by the parser. This avoids parser's peek() to give the lexer - * a false context. - */ - triggerAsync: function(type, args, checks, fn) { - checks.push(function() { - if (fn()) { - this.trigger(type, args); - } - }.bind(this)); - }, - - /* - * Extract a punctuator out of the next sequence of characters - * or return 'null' if its not possible. - * - * This method's implementation was heavily influenced by the - * scanPunctuator function in the Esprima parser's source code. - */ - scanPunctuator: function() { - var ch1 = this.peek(); - var ch2, ch3, ch4; + if (inblock) { + warning("W082", state.tokens.curr); + } + var nameToken = optionalidentifier(context) ? state.tokens.curr : null; - switch (ch1) { - // Most common single-character punctuators - case ".": - if ((/^[0-9]$/).test(this.peek(1))) { - return null; + if (!nameToken) { + if (!inexport) { + warning("W025"); } - if (this.peek(1) === "." && this.peek(2) === ".") { - return { - type: Token.Punctuator, - value: "..." - }; - } - /* falls through */ - case "(": - case ")": - case ";": - case ",": - case "[": - case "]": - case ":": - case "~": - case "?": - return { - type: Token.Punctuator, - value: ch1 - }; - - // A block/object opener - case "{": - this.pushContext(Context.Block); - return { - type: Token.Punctuator, - value: ch1 - }; + } else { + state.funct["(scope)"].addbinding(nameToken.value, { + type: labelType, + token: state.tokens.curr, + initialized: true }); - // A block/object closer - case "}": - if (this.inContext(Context.Block)) { - this.popContext(); + if (inexport) { + state.funct["(scope)"].setExported(nameToken.value, state.tokens.prev); } - return { - type: Token.Punctuator, - value: ch1 - }; + } - // A pound sign (for Node shebangs) - case "#": - return { - type: Token.Punctuator, - value: ch1 - }; + var f = doFunction(context, { + name: nameToken && nameToken.value, + statement: this, + type: generator ? "generator" : null, + ignoreLoopFunc: inblock // a declaration may already have warned + }); - // We're at the end of input - case "": - return null; + // If the function declaration is strict because the surrounding code is + // strict, the invalid name will trigger E008 when the scope manager + // attempts to create a binding in the strict environment record. An error + // should only be signaled here when the function itself enables strict + // mode (the scope manager will not report an error because a declaration + // does not introduce a binding into the function's environment record). + var enablesStrictMode = f["(isStrict)"] && !state.isStrict(); + if (nameToken && (f["(name)"] === "arguments" || f["(name)"] === "eval") && + enablesStrictMode) { + error("E008", nameToken); } - // Peek more characters + if (state.tokens.next.id === "(" && state.tokens.next.line === state.tokens.curr.line) { + /* istanbul ignore next */ + error("E039"); + } + return this; + }).declaration = true; - ch2 = this.peek(1); - ch3 = this.peek(2); - ch4 = this.peek(3); + prefix("function", function(context) { + var generator = false; + var isAsync = context & prodParams.preAsync; - // 4-character punctuator: >>>= + if (state.tokens.next.value === "*") { + if (isAsync && !state.inES9()) { + warning("W119", state.tokens.prev, "async generators", "9"); + } else if (!isAsync && !state.inES6(true)) { + warning("W119", state.tokens.curr, "function*", "6"); + } - if (ch1 === ">" && ch2 === ">" && ch3 === ">" && ch4 === "=") { - return { - type: Token.Punctuator, - value: ">>>=" - }; + advance("*"); + generator = true; } - // 3-character punctuators: === !== >>> <<= >>= + // This context modification restricts the use of `await` as the optional + // BindingIdentifier in async function expressions. + var nameToken = optionalidentifier(isAsync ? context | prodParams.async : context) ? + state.tokens.curr : null; - if (ch1 === "=" && ch2 === "=" && ch3 === "=") { - return { - type: Token.Punctuator, - value: "===" - }; - } + var f = doFunction(context, { + name: nameToken && nameToken.value, + type: generator ? "generator" : null + }); - if (ch1 === "!" && ch2 === "=" && ch3 === "=") { - return { - type: Token.Punctuator, - value: "!==" - }; + if (generator && nameToken && nameToken.value === "yield") { + error("E024", nameToken, "yield"); } - if (ch1 === ">" && ch2 === ">" && ch3 === ">") { - return { - type: Token.Punctuator, - value: ">>>" - }; + if (nameToken && (f["(name)"] === "arguments" || f["(name)"] === "eval") && + f["(isStrict)"]) { + error("E008", nameToken); } - if (ch1 === "<" && ch2 === "<" && ch3 === "=") { - return { - type: Token.Punctuator, - value: "<<=" - }; - } + return this; + }); - if (ch1 === ">" && ch2 === ">" && ch3 === "=") { - return { - type: Token.Punctuator, - value: ">>=" - }; - } + blockstmt("if", function(context) { + var t = state.tokens.next; + increaseComplexityCount(); + advance("("); + var expr = expression(context, 0); - // Fat arrow punctuator - if (ch1 === "=" && ch2 === ">") { - return { - type: Token.Punctuator, - value: ch1 + ch2 - }; + if (!expr) { + quit("E041", this); } - // 2-character punctuators: <= >= == != ++ -- << >> && || - // += -= *= %= &= |= ^= (but not /=, see below) - if (ch1 === ch2 && ("+-<>&|".indexOf(ch1) >= 0)) { - return { - type: Token.Punctuator, - value: ch1 + ch2 - }; - } + checkCondAssignment(expr); - if ("<>=!+-*%&|^".indexOf(ch1) >= 0) { - if (ch2 === "=") { - return { - type: Token.Punctuator, - value: ch1 + ch2 - }; + // When the if is within a for-in loop, check if the condition + // starts with a negation operator + var forinifcheck = null; + if (state.option.forin && state.forinifcheckneeded) { + state.forinifcheckneeded = false; // We only need to analyze the first if inside the loop + forinifcheck = state.forinifchecks[state.forinifchecks.length - 1]; + if (expr.type === "(punctuator)" && expr.value === "!") { + forinifcheck.type = "(negative)"; + } else { + forinifcheck.type = "(positive)"; } - - return { - type: Token.Punctuator, - value: ch1 - }; } - // Special case: /=. + advance(")", t); + var s = block(context, true, true); - if (ch1 === "/") { - if (ch2 === "=") { - return { - type: Token.Punctuator, - value: "/=" - }; + // When the if is within a for-in loop and the condition has a negative form, + // check if the body contains nothing but a continue statement + if (forinifcheck && forinifcheck.type === "(negative)") { + if (s && s[0] && s[0].type === "(identifier)" && s[0].value === "continue") { + forinifcheck.type = "(negative-with-continue)"; } - - return { - type: Token.Punctuator, - value: "/" - }; } - return null; - }, - - /* - * Extract a comment out of the next sequence of characters and/or - * lines or return 'null' if its not possible. Since comments can - * span across multiple lines this method has to move the char - * pointer. - * - * In addition to normal JavaScript comments (// and /*) this method - * also recognizes JSHint- and JSLint-specific comments such as - * /*jshint, /*jslint, /*globals and so on. - */ - scanComments: function() { - var ch1 = this.peek(); - var ch2 = this.peek(1); - var rest = this.input.substr(2); - var startLine = this.line; - var startChar = this.char; - var self = this; + if (state.tokens.next.id === "else") { + advance("else"); + if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") { + statement(context); + } else { + block(context, true, true); + } + } + return this; + }); - // Create a comment token object and make sure it - // has all the data JSHint needs to work with special - // comments. + blockstmt("try", function(context) { + var b; + var hasParameter = false; - function commentToken(label, body, opt) { - var special = ["jshint", "jslint", "members", "member", "globals", "global", "exported"]; - var isSpecial = false; - var value = label + body; - var commentType = "plain"; - opt = opt || {}; + function catchParameter() { + advance("("); - if (opt.isMultiline) { - value += "*/"; + if (checkPunctuators(state.tokens.next, ["[", "{"])) { + var tokens = destructuringPattern(context); + _.each(tokens, function(token) { + if (token.id) { + state.funct["(scope)"].addParam(token.id, token, "exception"); + } + }); + } else if (state.tokens.next.type !== "(identifier)") { + warning("E030", state.tokens.next, state.tokens.next.value); + } else { + // only advance if an identifier is present. This allows JSHint to + // recover from the case where no value is specified. + state.funct["(scope)"].addParam(identifier(context), state.tokens.curr, "exception"); } - body = body.replace(/\n/g, " "); - - if (label === "/*" && reg.fallsThrough.test(body)) { - isSpecial = true; - commentType = "falls through"; + if (state.tokens.next.value === "if") { + if (!state.inMoz()) { + warning("W118", state.tokens.curr, "catch filter"); + } + advance("if"); + expression(context, 0); } - special.forEach(function(str) { - if (isSpecial) { - return; - } + advance(")"); + } - // Don't recognize any special comments other than jshint for single-line - // comments. This introduced many problems with legit comments. - if (label === "//" && str !== "jshint") { - return; - } - - if (body.charAt(str.length) === " " && body.substr(0, str.length) === str) { - isSpecial = true; - label = label + str; - body = body.substr(str.length); - } - - if (!isSpecial && body.charAt(0) === " " && body.charAt(str.length + 1) === " " && - body.substr(1, str.length) === str) { - isSpecial = true; - label = label + " " + str; - body = body.substr(str.length + 1); - } - - if (!isSpecial) { - return; - } - - switch (str) { - case "member": - commentType = "members"; - break; - case "global": - commentType = "globals"; - break; - default: - var options = body.split(":").map(function(v) { - return v.replace(/^\s+/, "").replace(/\s+$/, ""); - }); - - if (options.length === 2) { - switch (options[0]) { - case "ignore": - switch (options[1]) { - case "start": - self.ignoringLinterErrors = true; - isSpecial = false; - break; - case "end": - self.ignoringLinterErrors = false; - isSpecial = false; - break; - } - } - } - - commentType = str; - } - }); - - return { - type: Token.Comment, - commentType: commentType, - value: value, - body: body, - isSpecial: isSpecial, - isMultiline: opt.isMultiline || false, - isMalformed: opt.isMalformed || false - }; - } + block(context | prodParams.tryClause, true); - // End of unbegun comment. Raise an error and skip that input. - if (ch1 === "*" && ch2 === "/") { - this.trigger("error", { - code: "E018", - line: startLine, - character: startChar - }); + while (state.tokens.next.id === "catch") { + increaseComplexityCount(); + if (b && (!state.inMoz())) { + warning("W118", state.tokens.next, "multiple catch blocks"); + } + advance("catch"); + if (state.tokens.next.id !== "{") { + state.funct["(scope)"].stack("catchparams"); + hasParameter = true; + catchParameter(); + } else if (!state.inES10()) { + warning("W119", state.tokens.curr, "optional catch binding", "10"); + } + block(context, false); - this.skip(2); - return null; + if (hasParameter) { + state.funct["(scope)"].unstack(); + hasParameter = false; + } + b = true; } - // Comments must start either with // or /* - if (ch1 !== "/" || (ch2 !== "*" && ch2 !== "/")) { - return null; + if (state.tokens.next.id === "finally") { + advance("finally"); + block(context, true); + return; } - // One-line comment - if (ch2 === "/") { - this.skip(this.input.length); // Skip to the EOL. - return commentToken("//", rest); + if (!b) { + error("E021", state.tokens.next, "catch", state.tokens.next.value); } - var body = ""; - - /* Multi-line comment */ - if (ch2 === "*") { - this.inComment = true; - this.skip(2); - - while (this.peek() !== "*" || this.peek(1) !== "/") { - if (this.peek() === "") { // End of Line - body += "\n"; - - // If we hit EOF and our comment is still unclosed, - // trigger an error and end the comment implicitly. - if (!this.nextLine()) { - this.trigger("error", { - code: "E017", - line: startLine, - character: startChar - }); - - this.inComment = false; - return commentToken("/*", body, { - isMultiline: true, - isMalformed: true - }); - } - } else { - body += this.peek(); - this.skip(); - } - } - - this.skip(2); - this.inComment = false; - return commentToken("/*", body, { isMultiline: true }); - } - }, + return this; + }); - /* - * Extract a keyword out of the next sequence of characters or - * return 'null' if its not possible. - */ - scanKeyword: function() { - var result = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input); - var keywords = [ - "if", "in", "do", "var", "for", "new", - "try", "let", "this", "else", "case", - "void", "with", "enum", "while", "break", - "catch", "throw", "const", "yield", "class", - "super", "return", "typeof", "delete", - "switch", "export", "import", "default", - "finally", "extends", "function", "continue", - "debugger", "instanceof" - ]; + blockstmt("while", function(context) { + var t = state.tokens.next; + state.funct["(breakage)"] += 1; + state.funct["(loopage)"] += 1; + increaseComplexityCount(); + advance("("); + checkCondAssignment(expression(context, 0)); + advance(")", t); + block(context, true, true); + state.funct["(breakage)"] -= 1; + state.funct["(loopage)"] -= 1; + return this; + }).labelled = true; - if (result && keywords.indexOf(result[0]) >= 0) { - return { - type: Token.Keyword, - value: result[0] - }; + blockstmt("with", function(context) { + var t = state.tokens.next; + if (state.isStrict()) { + error("E010", state.tokens.curr); + } else if (!state.option.withstmt) { + warning("W085", state.tokens.curr); } - return null; - }, + advance("("); + expression(context, 0); + advance(")", t); + block(context, true, true); - /* - * Extract a JavaScript identifier out of the next sequence of - * characters or return 'null' if its not possible. In addition, - * to Identifier this method can also produce BooleanLiteral - * (true/false) and NullLiteral (null). - */ - scanIdentifier: function() { - var id = ""; - var index = 0; - var type, char; + return this; + }); - function isNonAsciiIdentifierStart(code) { - return code > 256; - } + blockstmt("switch", function(context) { + var t = state.tokens.next; + var g = false; + var noindent = false; + var seenCase = false; - function isNonAsciiIdentifierPart(code) { - return code > 256; - } + state.funct["(breakage)"] += 1; + advance("("); + checkCondAssignment(expression(context, 0)); + advance(")", t); + t = state.tokens.next; + advance("{"); + state.funct["(scope)"].stack(); - function isHexDigit(str) { - return (/^[0-9a-fA-F]$/).test(str); - } + if (state.tokens.next.from === indent) + noindent = true; - var readUnicodeEscapeSequence = function() { - /*jshint validthis:true */ - index += 1; + if (!noindent) + indent += state.option.indent; - if (this.peek(index) !== "u") { - return null; - } + for (;;) { + switch (state.tokens.next.id) { + case "case": + switch (state.funct["(verb)"]) { + case "yield": + case "break": + case "case": + case "continue": + case "return": + case "switch": + case "throw": + break; + case "default": + if (state.option.leanswitch) { + warning("W145", state.tokens.next); + } - var ch1 = this.peek(index + 1); - var ch2 = this.peek(index + 2); - var ch3 = this.peek(index + 3); - var ch4 = this.peek(index + 4); - var code; + break; + default: + // You can tell JSHint that you don't use break intentionally by + // adding a comment /* falls through */ on a line just before + // the next `case`. + if (!state.tokens.curr.caseFallsThrough) { + warning("W086", state.tokens.curr, "case"); + } + } - if (isHexDigit(ch1) && isHexDigit(ch2) && isHexDigit(ch3) && isHexDigit(ch4)) { - code = parseInt(ch1 + ch2 + ch3 + ch4, 16); + advance("case"); + expression(context, 0); + seenCase = true; + increaseComplexityCount(); + g = true; + advance(":"); + state.funct["(verb)"] = "case"; + break; + case "default": + switch (state.funct["(verb)"]) { + case "yield": + case "break": + case "continue": + case "return": + case "throw": + break; + case "case": + if (state.option.leanswitch) { + warning("W145", state.tokens.curr); + } - if (asciiIdentifierPartTable[code] || isNonAsciiIdentifierPart(code)) { - index += 5; - return "\\u" + ch1 + ch2 + ch3 + ch4; + break; + default: + // Do not display a warning if 'default' is the first statement or if + // there is a special /* falls through */ comment. + if (seenCase && !state.tokens.curr.caseFallsThrough) { + warning("W086", state.tokens.curr, "default"); + } } - return null; - } + advance("default"); + g = true; + advance(":"); + state.funct["(verb)"] = "default"; + break; + case "}": + if (!noindent) + indent -= state.option.indent; - return null; - }.bind(this); + advance("}", t); + state.funct["(scope)"].unstack(); + state.funct["(breakage)"] -= 1; + state.funct["(verb)"] = undefined; + return; + /* istanbul ignore next */ + case "(end)": + error("E023", state.tokens.next, "}"); + return; + default: + indent += state.option.indent; + if (g) { + switch (state.tokens.curr.id) { + /* istanbul ignore next */ + case ",": + error("E040"); + return; + case ":": + g = false; + statements(context); + break; + /* istanbul ignore next */ + default: + error("E025", state.tokens.curr); + return; + } + } else { + /* istanbul ignore else */ + if (state.tokens.curr.id === ":") { + advance(":"); + error("E024", state.tokens.curr, ":"); + statements(context); + } else { + error("E021", state.tokens.next, "case", state.tokens.next.value); + return; + } + } + indent -= state.option.indent; + } + } + }).labelled = true; - var getIdentifierStart = function() { - /*jshint validthis:true */ - var chr = this.peek(index); - var code = chr.charCodeAt(0); + stmt("debugger", function() { + if (!state.option.debug) { + warning("W087", this); + } + return this; + }).exps = true; - if (code === 92) { - return readUnicodeEscapeSequence(); - } + (function() { + var x = stmt("do", function(context) { + state.funct["(breakage)"] += 1; + state.funct["(loopage)"] += 1; + increaseComplexityCount(); - if (code < 128) { - if (asciiIdentifierStartTable[code]) { - index += 1; - return chr; - } + this.first = block(context, true, true); + advance("while"); + var t = state.tokens.next; + advance("("); + checkCondAssignment(expression(context, 0)); + advance(")", t); + state.funct["(breakage)"] -= 1; + state.funct["(loopage)"] -= 1; + return this; + }); + x.labelled = true; + x.exps = true; + }()); - return null; + blockstmt("for", function(context) { + var s, t = state.tokens.next; + var letscope = false; + var isAsync = false; + var foreachtok = null; + + if (t.value === "each") { + foreachtok = t; + advance("each"); + if (!state.inMoz()) { + warning("W118", state.tokens.curr, "for each"); } + } - if (isNonAsciiIdentifierStart(code)) { - index += 1; - return chr; + if (state.tokens.next.identifier && state.tokens.next.value === "await") { + advance("await"); + isAsync = true; + + if (!(context & prodParams.async)) { + error("E024", state.tokens.curr, "await"); + } else if (!state.inES9()) { + warning("W119", state.tokens.curr, "asynchronous iteration", "9"); } + } - return null; - }.bind(this); + increaseComplexityCount(); + advance("("); - var getIdentifierPart = function() { - /*jshint validthis:true */ - var chr = this.peek(index); - var code = chr.charCodeAt(0); + // what kind of for(…) statement it is? for(…of…)? for(…in…)? for(…;…;…)? + var nextop; // contains the token of the "in" or "of" operator + var comma; // First comma punctuator at level 0 + var initializer; // First initializer at level 0 + var bindingPower; + var targets; + var target; + var decl; + var afterNext = peek(); - if (code === 92) { - return readUnicodeEscapeSequence(); - } + var headContext = context | prodParams.noin; - if (code < 128) { - if (asciiIdentifierPartTable[code]) { - index += 1; - return chr; + if (state.tokens.next.id === "var") { + advance("var"); + decl = state.tokens.curr.fud(headContext); + comma = decl.hasComma ? decl : null; + initializer = decl.hasInitializer ? decl : null; + } else if (state.tokens.next.id === "const" || + // The "let" keyword only signals a lexical binding if it is followed by + // an identifier, `{`, or `[`. Otherwise, it should be parsed as an + // IdentifierReference (i.e. in a subsquent branch). + (state.tokens.next.id === "let" && + ((afterNext.identifier && afterNext.id !== "in") || + checkPunctuators(afterNext, ["{", "["])))) { + advance(state.tokens.next.id); + // create a new block scope + letscope = true; + state.funct["(scope)"].stack(); + decl = state.tokens.curr.fud(headContext); + comma = decl.hasComma ? decl : null; + initializer = decl.hasInitializer ? decl : null; + } else if (!checkPunctuator(state.tokens.next, ";")) { + targets = []; + + while (state.tokens.next.value !== "in" && + state.tokens.next.value !== "of" && + !checkPunctuator(state.tokens.next, ";")) { + + if (checkPunctuators(state.tokens.next, ["{", "["])) { + destructuringPattern(headContext, { assignment: true }) + .forEach(function(elem) { + this.push(elem.token); + }, targets); + if (checkPunctuator(state.tokens.next, "=")) { + advance("="); + initializer = state.tokens.curr; + expression(headContext, 10); + } + } else { + target = expression(headContext, 10); + + if (target) { + if (target.type === "(identifier)") { + targets.push(target); + } else if (checkPunctuator(target, "=")) { + initializer = target; + targets.push(target); + } + } } - return null; - } + if (checkPunctuator(state.tokens.next, ",")) { + advance(","); - if (isNonAsciiIdentifierPart(code)) { - index += 1; - return chr; + if (!comma) { + comma = state.tokens.curr; + } + } } - return null; - }.bind(this); + //checkLeftSideAssign(target, nextop); - function removeEscapeSequences(id) { - return id.replace(/\\u([0-9a-fA-F]{4})/g, function(m0, codepoint) { - return String.fromCharCode(parseInt(codepoint, 16)); - }); + // In the event of a syntax error, do not issue warnings regarding the + // implicit creation of bindings. + if (!initializer && !comma) { + targets.forEach(function(token) { + if (!state.funct["(scope)"].has(token.value)) { + warning("W088", token, token.value); + } + }); + } } - char = getIdentifierStart(); - if (char === null) { - return null; + nextop = state.tokens.next; + + if (isAsync && nextop.value !== "of") { + error("E066", nextop); } - id = char; - for (;;) { - char = getIdentifierPart(); + // if we're in a for (… in|of …) statement + if (_.includes(["in", "of"], nextop.value)) { + if (nextop.value === "of") { + bindingPower = 20; - if (char === null) { - break; + if (!state.inES6()) { + warning("W104", nextop, "for of", "6"); + } + } else { + bindingPower = 0; + } + if (comma) { + error("W133", comma, nextop.value, "more than one ForBinding"); + } + if (initializer) { + error("W133", initializer, nextop.value, "initializer is forbidden"); + } + if (target && !comma && !initializer) { + checkLeftSideAssign(context, target, nextop); } - id += char; - } - - switch (id) { - case "true": - case "false": - type = Token.BooleanLiteral; - break; - case "null": - type = Token.NullLiteral; - break; - default: - type = Token.Identifier; - } - - return { - type: type, - value: removeEscapeSequences(id), - text: id, - tokenLength: id.length - }; - }, + advance(nextop.value); - /* - * Extract a numeric literal out of the next sequence of - * characters or return 'null' if its not possible. This method - * supports all numeric literals described in section 7.8.3 - * of the EcmaScript 5 specification. - * - * This method's implementation was heavily influenced by the - * scanNumericLiteral function in the Esprima parser's source code. - */ - scanNumericLiteral: function() { - var index = 0; - var value = ""; - var length = this.input.length; - var char = this.peek(index); - var bad; - var isAllowedDigit = isDecimalDigit; - var base = 10; - var isLegacy = false; + // The binding power is variable because for-in statements accept any + // Expression in this position, while for-of statements are limited to + // AssignmentExpressions. For example: + // + // for ( LeftHandSideExpression in Expression ) Statement + // for ( LeftHandSideExpression of AssignmentExpression ) Statement + expression(context, bindingPower); + advance(")", t); - function isDecimalDigit(str) { - return (/^[0-9]$/).test(str); - } + if (nextop.value === "in" && state.option.forin) { + state.forinifcheckneeded = true; - function isOctalDigit(str) { - return (/^[0-7]$/).test(str); - } + if (state.forinifchecks === undefined) { + state.forinifchecks = []; + } - function isBinaryDigit(str) { - return (/^[01]$/).test(str); - } + // Push a new for-in-if check onto the stack. The type will be modified + // when the loop's body is parsed and a suitable if statement exists. + state.forinifchecks.push({ + type: "(none)" + }); + } - function isHexDigit(str) { - return (/^[0-9a-fA-F]$/).test(str); - } + state.funct["(breakage)"] += 1; + state.funct["(loopage)"] += 1; - function isIdentifierStart(ch) { - return (ch === "$") || (ch === "_") || (ch === "\\") || - (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z"); - } + s = block(context, true, true); - // Numbers must start either with a decimal digit or a point. + if (nextop.value === "in" && state.option.forin) { + if (state.forinifchecks && state.forinifchecks.length > 0) { + var check = state.forinifchecks.pop(); - if (char !== "." && !isDecimalDigit(char)) { - return null; - } + if (// No if statement or not the first statement in loop body + s && s.length > 0 && (typeof s[0] !== "object" || s[0].value !== "if") || + // Positive if statement is not the only one in loop body + check.type === "(positive)" && s.length > 1 || + // Negative if statement but no continue + check.type === "(negative)") { + warning("W089", this); + } + } - if (char !== ".") { - value = this.peek(index); - index += 1; - char = this.peek(index); + // Reset the flag in case no if statement was contained in the loop body + state.forinifcheckneeded = false; + } - if (value === "0") { - // Base-16 numbers. - if (char === "x" || char === "X") { - isAllowedDigit = isHexDigit; - base = 16; + state.funct["(breakage)"] -= 1; + state.funct["(loopage)"] -= 1; - index += 1; - value += char; + } else { + if (foreachtok) { + error("E045", foreachtok); + } + nolinebreak(state.tokens.curr); + advance(";"); + if (decl) { + if (decl.value === "const" && !decl.hasInitializer) { + warning("E012", decl, decl.first[0].value); } - // Base-8 numbers. - if (char === "o" || char === "O") { - isAllowedDigit = isOctalDigit; - base = 8; + decl.first.forEach(function(token) { + state.funct["(scope)"].initialize(token.value); + }); + } - if (!state.inES6(true)) { - this.trigger("warning", { - code: "W119", - line: this.line, - character: this.char, - data: [ "Octal integer literal", "6" ] - }); + // start loopage after the first ; as the next two expressions are executed + // on every loop + state.funct["(loopage)"] += 1; + if (state.tokens.next.id !== ";") { + checkCondAssignment(expression(context, 0)); + } + nolinebreak(state.tokens.curr); + advance(";"); + if (state.tokens.next.id === ";") { + error("E021", state.tokens.next, ")", ";"); + } + if (state.tokens.next.id !== ")") { + for (;;) { + expression(context, 0); + if (state.tokens.next.id !== ",") { + break; } - - index += 1; - value += char; + advance(","); + checkComma(); } + } + advance(")", t); + state.funct["(breakage)"] += 1; + block(context, true, true); + state.funct["(breakage)"] -= 1; + state.funct["(loopage)"] -= 1; + } - // Base-2 numbers. - if (char === "b" || char === "B") { - isAllowedDigit = isBinaryDigit; - base = 2; + // unstack loop blockscope + if (letscope) { + state.funct["(scope)"].unstack(); + } + return this; + }).labelled = true; - if (!state.inES6(true)) { - this.trigger("warning", { - code: "W119", - line: this.line, - character: this.char, - data: [ "Binary integer literal", "6" ] - }); - } - index += 1; - value += char; - } + stmt("break", function() { + var v = state.tokens.next.value; - // Legacy base-8 numbers. - if (isOctalDigit(char)) { - isAllowedDigit = isOctalDigit; - base = 8; - isLegacy = true; - bad = false; + if (!state.option.asi) + nolinebreak(this); - index += 1; - value += char; - } + if (state.tokens.next.identifier && + sameLine(state.tokens.curr, state.tokens.next)) { + if (!state.funct["(scope)"].funct.hasLabel(v)) { + warning("W090", state.tokens.next, v); + } + this.first = state.tokens.next; + advance(); + } else { + if (state.funct["(breakage)"] === 0) + warning("W052", state.tokens.next, this.value); + } - // Decimal numbers that start with '0' such as '09' are illegal - // but we still parse them and return as malformed. + reachable(this); - if (!isOctalDigit(char) && isDecimalDigit(char)) { - index += 1; - value += char; - } - } + return this; + }).exps = true; - while (index < length) { - char = this.peek(index); - if (isLegacy && isDecimalDigit(char)) { - // Numbers like '019' (note the 9) are not valid octals - // but we still parse them and mark as malformed. - bad = true; - } else if (!isAllowedDigit(char)) { - break; + stmt("continue", function() { + var v = state.tokens.next.value; + + if (state.funct["(breakage)"] === 0 || !state.funct["(loopage)"]) { + warning("W052", state.tokens.next, this.value); + } + + if (!state.option.asi) + nolinebreak(this); + + if (state.tokens.next.identifier) { + if (sameLine(state.tokens.curr, state.tokens.next)) { + if (!state.funct["(scope)"].funct.hasLabel(v)) { + warning("W090", state.tokens.next, v); } - value += char; - index += 1; + this.first = state.tokens.next; + advance(); } + } - if (isAllowedDigit !== isDecimalDigit) { - if (!isLegacy && value.length <= 2) { // 0x - return { - type: Token.NumericLiteral, - value: value, - isMalformed: true - }; - } + reachable(this); - if (index < length) { - char = this.peek(index); - if (isIdentifierStart(char)) { - return null; - } + return this; + }).exps = true; + + + stmt("return", function(context) { + if (sameLine(this, state.tokens.next)) { + if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { + this.first = expression(context, 0); + + if (this.first && + this.first.type === "(punctuator)" && this.first.value === "=" && + !this.first.paren && !state.option.boss) { + warning("W093", this.first); } - return { - type: Token.NumericLiteral, - value: value, - base: base, - isLegacy: isLegacy, - isMalformed: false - }; + if (state.option.noreturnawait && context & prodParams.async && + !(context & prodParams.tryClause) && + this.first.identifier && this.first.value === "await") { + warning("W146", this.first); + } + } + } else { + if (state.tokens.next.type === "(punctuator)" && + ["[", "{", "+", "-"].indexOf(state.tokens.next.value) > -1) { + nolinebreak(this); // always warn (Line breaking error) } } - // Decimal digits. + reachable(this); - if (char === ".") { - value += char; - index += 1; + return this; + }).exps = true; - while (index < length) { - char = this.peek(index); - if (!isDecimalDigit(char)) { - break; - } - value += char; - index += 1; + prefix("await", function(context) { + if (context & prodParams.async) { + // If the parameters of the current function scope have not been defined, + // it is because the current expression is contained within the parameter + // list. + if (!state.funct["(params)"]) { + error("E024", this, "await"); } + + expression(context, 10); + return this; + } else { + this.exps = false; + return state.syntax["(identifier)"].nud.apply(this, arguments); } + }).exps = true; - // Exponent part. + (function(asyncSymbol) { + asyncSymbol.meta = { es5: true, isFutureReservedWord: true, strictOnly: true }; + asyncSymbol.isFunc = function() { + var next = state.tokens.next; + var afterParens; - if (char === "e" || char === "E") { - value += char; - index += 1; - char = this.peek(index); + if (this.line !== next.line) { + return false; + } - if (char === "+" || char === "-") { - value += this.peek(index); - index += 1; + if (next.id === "function") { + return true; } - char = this.peek(index); - if (isDecimalDigit(char)) { - value += char; - index += 1; + if (next.id === "(") { + afterParens = peekThroughParens(0); - while (index < length) { - char = this.peek(index); - if (!isDecimalDigit(char)) { - break; - } - value += char; - index += 1; - } - } else { - return null; + return afterParens.id === "=>"; } - } - if (index < length) { - char = this.peek(index); - if (isIdentifierStart(char)) { - return null; + if (next.identifier) { + return peek().id === "=>"; } - } - return { - type: Token.NumericLiteral, - value: value, - base: base, - isMalformed: !isFinite(value) + return false; }; - }, + asyncSymbol.useFud = asyncSymbol.isFunc; + // async function declaration + asyncSymbol.fud = function(context) { + if (!state.inES8()) { + warning("W119", this, "async functions", "8"); + } + context |= prodParams.preAsync; + context |= prodParams.initial; + this.func = expression(context, 0); + this.block = this.func.block; + this.exps = this.func.exps; + return this; + }; + asyncSymbol.exps = true; + delete asyncSymbol.reserved; + }(prefix("async", function(context, rbp) { + if (this.isFunc(context)) { + if (!state.inES8()) { + warning("W119", this, "async functions", "8"); + } + context |= prodParams.preAsync; + this.func = expression(context, rbp); + this.identifier = false; + return this; + } - // Assumes previously parsed character was \ (=== '\\') and was not skipped. - scanEscapeSequence: function(checks) { - var allowNewLine = false; - var jump = 1; - this.skip(); - var char = this.peek(); + this.exps = false; + return state.syntax["(identifier)"].nud.apply(this, arguments); + }))); - switch (char) { - case "'": - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\'" ] - }, checks, function() {return state.jsonMode; }); - break; - case "b": - char = "\\b"; - break; - case "f": - char = "\\f"; - break; - case "n": - char = "\\n"; - break; - case "r": - char = "\\r"; - break; - case "t": - char = "\\t"; - break; - case "0": - char = "\\0"; + (function(yieldSymbol) { + yieldSymbol.rbp = yieldSymbol.lbp = 25; + yieldSymbol.exps = true; + })(prefix("yield", function(context) { + if (state.inMoz()) { + return mozYield.call(this, context); + } - // Octal literals fail in strict mode. - // Check if the number is between 00 and 07. - var n = parseInt(this.peek(1), 10); - this.triggerAsync("warning", { - code: "W115", - line: this.line, - character: this.char - }, checks, - function() { return n >= 0 && n <= 7 && state.isStrict(); }); - break; - case "u": - var hexCode = this.input.substr(1, 4); - var code = parseInt(hexCode, 16); - if (isNaN(code)) { - this.trigger("warning", { - code: "W052", - line: this.line, - character: this.char, - data: [ "u" + hexCode ] - }); - } - char = String.fromCharCode(code); - jump = 5; - break; - case "v": - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\v" ] - }, checks, function() { return state.jsonMode; }); + if (!(context & prodParams.yield)) { + this.exps = false; + return state.syntax["(identifier)"].nud.apply(this, arguments); + } - char = "\v"; - break; - case "x": - var x = parseInt(this.input.substr(1, 2), 16); - - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\x-" ] - }, checks, function() { return state.jsonMode; }); + var prev = state.tokens.prev; - char = String.fromCharCode(x); - jump = 3; - break; - case "\\": - char = "\\\\"; - break; - case "\"": - char = "\\\""; - break; - case "/": - break; - case "": - allowNewLine = true; - char = ""; - break; + // If the parameters of the current function scope have not been defined, + // it is because the current expression is contained within the parameter + // list. + if (!state.funct["(params)"]) { + error("E024", this, "yield"); } - return { char: char, jump: jump, allowNewLine: allowNewLine }; - }, + if (!this.beginsStmt && prev.lbp > 30 && !checkPunctuators(prev, ["("])) { + error("E061", this); + } - /* - * Extract a template literal out of the next sequence of characters - * and/or lines or return 'null' if its not possible. Since template - * literals can span across multiple lines, this method has to move - * the char pointer. - */ - scanTemplateLiteral: function(checks) { - var tokenType; - var value = ""; - var ch; - var startLine = this.line; - var startChar = this.char; - var depth = this.templateStarts.length; + if (!state.inES6()) { + warning("W104", state.tokens.curr, "yield", "6"); + } + state.funct["(yielded)"] = true; - if (!state.inES6(true)) { - // Only lex template strings in ESNext mode. - return null; - } else if (this.peek() === "`") { - // Template must start with a backtick. - tokenType = Token.TemplateHead; - this.templateStarts.push({ line: this.line, char: this.char }); - depth = this.templateStarts.length; - this.skip(1); - this.pushContext(Context.Template); - } else if (this.inContext(Context.Template) && this.peek() === "}") { - // If we're in a template context, and we have a '}', lex a TemplateMiddle. - tokenType = Token.TemplateMiddle; - } else { - // Go lex something else. - return null; + if (state.tokens.next.value === "*") { + advance("*"); } - while (this.peek() !== "`") { - while ((ch = this.peek()) === "") { - value += "\n"; - if (!this.nextLine()) { - // Unclosed template literal --- point to the starting "`" - var startPos = this.templateStarts.pop(); - this.trigger("error", { - code: "E052", - line: startPos.line, - character: startPos.char - }); - return { - type: tokenType, - value: value, - startLine: startLine, - startChar: startChar, - isUnclosed: true, - depth: depth, - context: this.popContext() - }; - } - } + // Parse operand + if (state.tokens.curr.value === "*" || sameLine(state.tokens.curr, state.tokens.next)) { + if (state.tokens.next.nud) { - if (ch === '$' && this.peek(1) === '{') { - value += '${'; - this.skip(2); - return { - type: tokenType, - value: value, - startLine: startLine, - startChar: startChar, - isUnclosed: false, - depth: depth, - context: this.currentContext() - }; - } else if (ch === '\\') { - var escape = this.scanEscapeSequence(checks); - value += escape.char; - this.skip(escape.jump); - } else if (ch !== '`') { - // Otherwise, append the value and continue. - value += ch; - this.skip(1); + nobreaknonadjacent(state.tokens.curr, state.tokens.next); + this.first = expression(context, 10); + + if (this.first.type === "(punctuator)" && this.first.value === "=" && + !this.first.paren && !state.option.boss) { + warning("W093", this.first); + } + } else if (state.tokens.next.led) { + if (state.tokens.next.id !== ",") { + error("W017", state.tokens.next); + } } } - // Final value is either NoSubstTemplate or TemplateTail - tokenType = tokenType === Token.TemplateHead ? Token.NoSubstTemplate : Token.TemplateTail; - this.skip(1); - this.templateStarts.pop(); - - return { - type: tokenType, - value: value, - startLine: startLine, - startChar: startChar, - isUnclosed: false, - depth: depth, - context: this.popContext() - }; - }, + return this; + })); - /* - * Extract a string out of the next sequence of characters and/or - * lines or return 'null' if its not possible. Since strings can - * span across multiple lines this method has to move the char - * pointer. - * - * This method recognizes pseudo-multiline JavaScript strings: - * - * var str = "hello\ - * world"; + /** + * Parsing logic for non-standard Mozilla implementation of `yield` + * expressions. */ - scanStringLiteral: function(checks) { - /*jshint loopfunc:true */ - var quote = this.peek(); - - // String must start with a quote. - if (quote !== "\"" && quote !== "'") { - return null; + var mozYield = function(context) { + var prev = state.tokens.prev; + if (state.inES6(true) && !(context & prodParams.yield)) { + error("E046", state.tokens.curr, "yield"); } + state.funct["(yielded)"] = true; + var delegatingYield = false; - // In JSON strings must always use double quotes. - this.triggerAsync("warning", { - code: "W108", - line: this.line, - character: this.char // +1? - }, checks, function() { return state.jsonMode && quote !== "\""; }); - - var value = ""; - var startLine = this.line; - var startChar = this.char; - var allowNewLine = false; - - this.skip(); - - while (this.peek() !== quote) { - if (this.peek() === "") { // End Of Line - - // If an EOL is not preceded by a backslash, show a warning - // and proceed like it was a legit multi-line string where - // author simply forgot to escape the newline symbol. - // - // Another approach is to implicitly close a string on EOL - // but it generates too many false positives. - - if (!allowNewLine) { - this.trigger("warning", { - code: "W112", - line: this.line, - character: this.char - }); - } else { - allowNewLine = false; + if (state.tokens.next.value === "*") { + delegatingYield = true; + advance("*"); + } - // Otherwise show a warning if multistr option was not set. - // For JSON, show warning no matter what. + if (sameLine(this, state.tokens.next)) { + if (delegatingYield || + (state.tokens.next.id !== ";" && !state.option.asi && + !state.tokens.next.reach && state.tokens.next.nud)) { - this.triggerAsync("warning", { - code: "W043", - line: this.line, - character: this.char - }, checks, function() { return !state.option.multistr; }); + nobreaknonadjacent(state.tokens.curr, state.tokens.next); + this.first = expression(context, 10); - this.triggerAsync("warning", { - code: "W042", - line: this.line, - character: this.char - }, checks, function() { return state.jsonMode && state.option.multistr; }); + if (this.first.type === "(punctuator)" && this.first.value === "=" && + !this.first.paren && !state.option.boss) { + warning("W093", this.first); } + } + if (state.tokens.next.id !== ")" && + (prev.lbp > 30 || (!prev.assign && !isEndOfExpr()))) { + error("E050", this); + } + } else if (!state.option.asi) { + nolinebreak(this); // always warn (Line breaking error) + } + return this; + }; - // If we get an EOF inside of an unclosed string, show an - // error and implicitly close it at the EOF point. - - if (!this.nextLine()) { - this.trigger("error", { - code: "E029", - line: startLine, - character: startChar - }); - - return { - type: Token.StringLiteral, - value: value, - startLine: startLine, - startChar: startChar, - isUnclosed: true, - quote: quote - }; - } + stmt("throw", function(context) { + nolinebreak(this); + this.first = expression(context, 20); - } else { // Any character other than End Of Line + reachable(this); - allowNewLine = false; - var char = this.peek(); - var jump = 1; // A length of a jump, after we're done - // parsing this character. + return this; + }).exps = true; - if (char < " ") { - // Warn about a control character in a string. - this.trigger("warning", { - code: "W113", - line: this.line, - character: this.char, - data: [ "" ] - }); - } + stmt("import", function(context) { + if (!state.funct["(scope)"].block.isGlobal()) { + error("E053", state.tokens.curr, "Import"); + } - // Special treatment for some escaped characters. - if (char === "\\") { - var parsed = this.scanEscapeSequence(checks); - char = parsed.char; - jump = parsed.jump; - allowNewLine = parsed.allowNewLine; - } + if (!state.inES6()) { + warning("W119", state.tokens.curr, "import", "6"); + } - value += char; - this.skip(jump); - } + if (state.tokens.next.type === "(string)") { + // ModuleSpecifier :: StringLiteral + advance("(string)"); + return this; } - this.skip(); - return { - type: Token.StringLiteral, - value: value, - startLine: startLine, - startChar: startChar, - isUnclosed: false, - quote: quote - }; - }, - - /* - * Extract a regular expression out of the next sequence of - * characters and/or lines or return 'null' if its not possible. - * - * This method is platform dependent: it accepts almost any - * regular expression values but then tries to compile and run - * them using system's RegExp object. This means that there are - * rare edge cases where one JavaScript engine complains about - * your regular expression while others don't. - */ - scanRegExp: function() { - var index = 0; - var length = this.input.length; - var char = this.peek(); - var value = char; - var body = ""; - var flags = []; - var malformed = false; - var isCharSet = false; - var terminated; + if (state.tokens.next.identifier) { + // ImportClause :: ImportedDefaultBinding + this.name = identifier(context); + // Import bindings are immutable (see ES6 8.1.1.5.5) + state.funct["(scope)"].addbinding(this.name, { + type: "import", + initialized: true, + token: state.tokens.curr }); - var scanUnexpectedChars = function() { - // Unexpected control character - if (char < " ") { - malformed = true; - this.trigger("warning", { - code: "W048", - line: this.line, - character: this.char - }); + if (state.tokens.next.value === ",") { + // ImportClause :: ImportedDefaultBinding , NameSpaceImport + // ImportClause :: ImportedDefaultBinding , NamedImports + advance(","); + // At this point, we intentionally fall through to continue matching + // either NameSpaceImport or NamedImports. + // Discussion: + // https://github.com/jshint/jshint/pull/2144#discussion_r23978406 + } else { + advance("from"); + advance("(string)"); + return this; } + } - // Unexpected escaped character - if (char === "<") { - malformed = true; - this.trigger("warning", { - code: "W049", - line: this.line, - character: this.char, - data: [ char ] - }); + if (state.tokens.next.id === "*") { + // ImportClause :: NameSpaceImport + advance("*"); + advance("as"); + if (state.tokens.next.identifier) { + this.name = identifier(context); + // Import bindings are immutable (see ES6 8.1.1.5.5) + state.funct["(scope)"].addbinding(this.name, { + type: "import", + initialized: true, + token: state.tokens.curr }); } - }.bind(this); + } else { + // ImportClause :: NamedImports + advance("{"); + for (;;) { + if (state.tokens.next.value === "}") { + advance("}"); + break; + } + var importName; + if (state.tokens.next.type === "default") { + importName = "default"; + advance("default"); + } else { + importName = identifier(context); + } + if (state.tokens.next.value === "as") { + advance("as"); + importName = identifier(context); + } - // Regular expressions must start with '/' - if (!this.prereg || char !== "/") { - return null; + // Import bindings are immutable (see ES6 8.1.1.5.5) + state.funct["(scope)"].addbinding(importName, { + type: "import", + initialized: true, + token: state.tokens.curr }); + + if (state.tokens.next.value === ",") { + advance(","); + } else if (state.tokens.next.value === "}") { + advance("}"); + break; + } else { + error("E024", state.tokens.next, state.tokens.next.value); + break; + } + } } - index += 1; - terminated = false; + // FromClause + advance("from"); + advance("(string)"); - // Try to get everything in between slashes. A couple of - // cases aside (see scanUnexpectedChars) we don't really - // care whether the resulting expression is valid or not. - // We will check that later using the RegExp object. + // Support for ES2015 modules was released without warning for `import` + // declarations that lack bindings. Issuing a warning would therefor + // constitute a breaking change. + // TODO: enable this warning in JSHint 3 + // if (hasBindings) { + // warning("W142", this, "import", moduleSpecifier); + // } - while (index < length) { - char = this.peek(index); - value += char; - body += char; + return this; + }).exps = true; - if (isCharSet) { - if (char === "]") { - if (this.peek(index - 1) !== "\\" || this.peek(index - 2) === "\\") { - isCharSet = false; - } - } + stmt("export", function(context) { + var ok = true; + var token; + var identifier; + var moduleSpecifier; + context = context | prodParams.export; - if (char === "\\") { - index += 1; - char = this.peek(index); - body += char; - value += char; + if (!state.inES6()) { + warning("W119", state.tokens.curr, "export", "6"); + ok = false; + } - scanUnexpectedChars(); - } + if (!state.funct["(scope)"].block.isGlobal()) { + error("E053", state.tokens.curr, "Export"); + ok = false; + } - index += 1; - continue; - } + if (state.tokens.next.value === "*") { + // ExportDeclaration :: export * FromClause + advance("*"); + advance("from"); + advance("(string)"); + return this; + } - if (char === "\\") { - index += 1; - char = this.peek(index); - body += char; - value += char; + if (state.tokens.next.type === "default") { + // ExportDeclaration :: + // export default [lookahead ∉ { function, class }] AssignmentExpression[In] ; + // export default HoistableDeclaration + // export default ClassDeclaration - scanUnexpectedChars(); + // because the 'name' of a default-exported function is, confusingly, 'default' + // see https://bocoup.com/blog/whats-in-a-function-name + state.nameStack.set(state.tokens.next); - if (char === "/") { - index += 1; - continue; + advance("default"); + var exportType = state.tokens.next.id; + if (exportType === "function") { + this.block = true; + advance("function"); + state.syntax["function"].fud(context); + } else if (exportType === "async" && peek().id === "function") { + this.block = true; + advance("async"); + advance("function"); + state.syntax["function"].fud(context | prodParams.preAsync); + } else if (exportType === "class") { + this.block = true; + advance("class"); + state.syntax["class"].fud(context); + } else { + token = expression(context, 10); + if (token.identifier) { + identifier = token.value; + state.funct["(scope)"].setExported(identifier, token); + } + } + return this; + } + if (state.tokens.next.value === "{") { + // ExportDeclaration :: export ExportClause + advance("{"); + var exportedTokens = []; + while (!checkPunctuator(state.tokens.next, "}")) { + if (!state.tokens.next.identifier) { + /* istanbul ignore next */ + error("E030", state.tokens.next, state.tokens.next.value); } + advance(); - if (char === "[") { - index += 1; - continue; + exportedTokens.push(state.tokens.curr); + + if (state.tokens.next.value === "as") { + advance("as"); + if (!state.tokens.next.identifier) { + /* istanbul ignore next */ + error("E030", state.tokens.next, state.tokens.next.value); + } + advance(); } - } - if (char === "[") { - isCharSet = true; - index += 1; - continue; + if (!checkPunctuator(state.tokens.next, "}")) { + advance(","); + } + } + advance("}"); + if (state.tokens.next.value === "from") { + // ExportDeclaration :: export ExportClause FromClause + advance("from"); + moduleSpecifier = state.tokens.next; + advance("(string)"); + } else if (ok) { + exportedTokens.forEach(function(token) { + state.funct["(scope)"].setExported(token.value, token); + }); } - if (char === "/") { - body = body.substr(0, body.length - 1); - terminated = true; - index += 1; - break; + if (exportedTokens.length === 0) { + if (moduleSpecifier) { + warning("W142", this, "export", moduleSpecifier.value); + } else { + warning("W141", this, "export"); + } } - index += 1; + return this; + } else if (state.tokens.next.id === "var") { + // ExportDeclaration :: export VariableStatement + advance("var"); + state.tokens.curr.fud(context); + } else if (state.tokens.next.id === "let") { + // ExportDeclaration :: export VariableStatement + advance("let"); + state.tokens.curr.fud(context); + } else if (state.tokens.next.id === "const") { + // ExportDeclaration :: export VariableStatement + advance("const"); + state.tokens.curr.fud(context); + } else if (state.tokens.next.id === "function") { + // ExportDeclaration :: export Declaration + this.block = true; + advance("function"); + state.syntax["function"].fud(context); + } else if (state.tokens.next.id === "async" && peek().id === "function") { + // ExportDeclaration :: export Declaration + this.block = true; + advance("async"); + advance("function"); + state.syntax["function"].fud(context | prodParams.preAsync); + } else if (state.tokens.next.id === "class") { + // ExportDeclaration :: export Declaration + this.block = true; + advance("class"); + state.syntax["class"].fud(context); + } else { + /* istanbul ignore next */ + error("E024", state.tokens.next, state.tokens.next.value); } - // A regular expression that was never closed is an - // error from which we cannot recover. + return this; + }).exps = true; - if (!terminated) { - this.trigger("error", { - code: "E015", - line: this.line, - character: this.from - }); + /** + * Determine if SuperCall or SuperProperty may be used in the current context + * (as described by the provided "functor" object). + * + * @param {string} type - one of "property" or "call" + * @param {object} funct - a "functor" object describing the current function + * context + * + * @returns {boolean} + */ + function supportsSuper(type, funct) { + if (type === "call" && funct["(async)"]) { + return false; + } - return void this.trigger("fatal", { - line: this.line, - from: this.from - }); + if (type === "property" && funct["(method)"]) { + return true; } - // Parse flags (if any). - - while (index < length) { - char = this.peek(index); - if (!/[gim]/.test(char)) { - break; - } - flags.push(char); - value += char; - index += 1; + if (type === "call" && funct["(statement)"] && + funct["(statement)"].id === "class") { + return true; } - // Check regular expression for correctness. - - try { - new RegExp(body, flags.join("")); - } catch (err) { - malformed = true; - this.trigger("error", { - code: "E016", - line: this.line, - character: this.char, - data: [ err.message ] // Platform dependent! - }); + if (funct["(arrow)"]) { + return supportsSuper(type, funct["(context)"]); } - return { - type: Token.RegExp, - value: value, - flags: flags, - isMalformed: malformed - }; - }, - - /* - * Scan for any occurrence of non-breaking spaces. Non-breaking spaces - * can be mistakenly typed on OS X with option-space. Non UTF-8 web - * pages with non-breaking pages produce syntax errors. - */ - scanNonBreakingSpaces: function() { - return state.option.nonbsp ? - this.input.search(/(\u00A0)/) : -1; - }, - - /* - * Scan for characters that get silently deleted by one or more browsers. - */ - scanUnsafeChars: function() { - return this.input.search(reg.unsafeChars); - }, - - /* - * Produce the next raw token or return 'null' if no tokens can be matched. - * This method skips over all space characters. - */ - next: function(checks) { - this.from = this.char; + return false; + } - // Move to the next non-space character. - var start; - if (/\s/.test(this.peek())) { - start = this.char; + var superNud = function() { + var next = state.tokens.next; - while (/\s/.test(this.peek())) { - this.from += 1; - this.skip(); + if (checkPunctuators(next, ["[", "."])) { + if (!supportsSuper("property", state.funct)) { + error("E063", this); + } + } else if (checkPunctuator(next, "(")) { + if (!supportsSuper("call", state.funct)) { + error("E064", this); } + } else { + error("E024", next, next.value || next.id); } - // Methods that work with multi-line structures and move the - // character pointer. - - var match = this.scanComments() || - this.scanStringLiteral(checks) || - this.scanTemplateLiteral(checks); + return this; + }; - if (match) { - return match; - } + // Future Reserved Words - // Methods that don't move the character pointer. + FutureReservedWord("abstract"); + FutureReservedWord("boolean"); + FutureReservedWord("byte"); + FutureReservedWord("char"); + FutureReservedWord("double"); + FutureReservedWord("enum", { es5: true }); + FutureReservedWord("export", { es5: true }); + FutureReservedWord("extends", { es5: true }); + FutureReservedWord("final"); + FutureReservedWord("float"); + FutureReservedWord("goto"); + FutureReservedWord("implements", { es5: true, strictOnly: true }); + FutureReservedWord("import", { es5: true }); + FutureReservedWord("int"); + FutureReservedWord("interface", { es5: true, strictOnly: true }); + FutureReservedWord("long"); + FutureReservedWord("native"); + FutureReservedWord("package", { es5: true, strictOnly: true }); + FutureReservedWord("private", { es5: true, strictOnly: true }); + FutureReservedWord("protected", { es5: true, strictOnly: true }); + FutureReservedWord("public", { es5: true, strictOnly: true }); + FutureReservedWord("short"); + FutureReservedWord("static", { es5: true, strictOnly: true }); + FutureReservedWord("synchronized"); + FutureReservedWord("transient"); + FutureReservedWord("volatile"); - match = - this.scanRegExp() || - this.scanPunctuator() || - this.scanKeyword() || - this.scanIdentifier() || - this.scanNumericLiteral(); + // this function is used to determine whether a squarebracket or a curlybracket + // expression is a comprehension array, destructuring assignment or a json value. - if (match) { - this.skip(match.tokenLength || match.value.length); - return match; + var lookupBlockType = function() { + var pn, pn1, prev; + var i = -1; + var bracketStack = 0; + var ret = {}; + if (checkPunctuators(state.tokens.curr, ["[", "{"])) { + bracketStack += 1; } + do { + prev = i === -1 ? state.tokens.curr : pn; + pn = i === -1 ? state.tokens.next : peek(i); + pn1 = peek(i + 1); + i = i + 1; + if (checkPunctuators(pn, ["[", "{"])) { + bracketStack += 1; + } else if (checkPunctuators(pn, ["]", "}"])) { + bracketStack -= 1; + } + if (bracketStack === 1 && pn.identifier && pn.value === "for" && + !checkPunctuator(prev, ".")) { + ret.isCompArray = true; + ret.notJson = true; + break; + } + if (bracketStack === 0 && checkPunctuators(pn, ["}", "]"])) { + if (pn1.value === "=") { + ret.isDestAssign = true; + ret.notJson = true; + break; + } else if (pn1.value === ".") { + ret.notJson = true; + break; + } + } + if (checkPunctuator(pn, ";")) { + ret.notJson = true; + } + } while (bracketStack > 0 && pn.id !== "(end)"); + return ret; + }; - // No token could be matched, give up. - - return null; - }, - - /* - * Switch to the next line and reset all char pointers. Once - * switched, this method also checks for other minor warnings. + /** + * Update an object used to track property names within object initializers + * and class bodies. Produce warnings in response to duplicated names. + * + * @param {object} props - a collection of all properties of the object or + * class to which the current property is being + * assigned + * @param {string} name - the property name + * @param {object} tkn - the token defining the property + * @param {boolean} [isClass] - whether the accessor is part of an ES6 Class + * definition + * @param {boolean} [isStatic] - whether the accessor is a static method + * @param {boolean} [isComputed] - whether the property is a computed expression like [Symbol.iterator] */ - nextLine: function() { - var char; - - if (this.line >= this.getLines().length) { - return false; + function saveProperty(props, name, tkn, isClass, isStatic, isComputed) { + if (tkn.identifier) { + name = tkn.value; + } + var key = name; + if (isClass && isStatic) { + key = "static " + name; } - this.input = this.getLines()[this.line]; - this.line += 1; - this.char = 1; - this.from = 1; - - var inputTrimmed = this.input.trim(); + if (props[key] && name !== "__proto__" && !isComputed) { + var msg = ["key", "class method", "static class method"]; + msg = msg[(isClass || false) + (isStatic || false)]; + warning("W075", state.tokens.next, msg, name); + } else { + props[key] = Object.create(null); + } - var startsWith = function() { - return _.some(arguments, function(prefix) { - return inputTrimmed.indexOf(prefix) === 0; - }); - }; + props[key].basic = true; + props[key].basictkn = tkn; + } - var endsWith = function() { - return _.some(arguments, function(suffix) { - return inputTrimmed.indexOf(suffix, inputTrimmed.length - suffix.length) !== -1; - }); - }; + /** + * Update an object used to track property names within object initializers + * and class bodies. Produce warnings in response to duplicated names. + * + * @param {string} accessorType - Either "get" or "set" + * @param {object} props - a collection of all properties of the object or + * class to which the current accessor is being + * assigned + * @param {object} tkn - the identifier token representing the accessor name + * @param {boolean} [isClass] - whether the accessor is part of an ES6 Class + * definition + * @param {boolean} [isStatic] - whether the accessor is a static method + */ + function saveAccessor(accessorType, props, name, tkn, isClass, isStatic) { + var flagName = accessorType === "get" ? "getterToken" : "setterToken"; + var key = name; + state.tokens.curr.accessorType = accessorType; + state.nameStack.set(tkn); + if (isClass && isStatic) { + key = "static " + name; + } - // If we are ignoring linter errors, replace the input with empty string - // if it doesn't already at least start or end a multi-line comment - if (this.ignoringLinterErrors === true) { - if (!startsWith("/*", "//") && !(this.inComment && endsWith("*/"))) { - this.input = ""; + if (props[key]) { + if ((props[key].basic || props[key][flagName]) && name !== "__proto__") { + var msg = ""; + if (isClass) { + if (isStatic) { + msg += "static "; + } + msg += accessorType + "ter method"; + } else { + msg = "key"; + } + warning("W075", state.tokens.next, msg, name); } + } else { + props[key] = Object.create(null); } - char = this.scanNonBreakingSpaces(); - if (char >= 0) { - this.trigger("warning", { code: "W125", line: this.line, character: char + 1 }); + props[key][flagName] = tkn; + if (isStatic) { + props[key].static = true; } + } - this.input = this.input.replace(/\t/g, state.tab); - char = this.scanUnsafeChars(); + /** + * Parse a computed property name within object initializers and class bodies + * as introduced by ES2015. For example: + * + * void { + * [object.method()]: null + * }; + * + * @param {number} context - the parsing context + * + * @returns {object} - the token value that describes the expression which + * defines the property name + */ + function computedPropertyName(context) { + advance("["); - if (char >= 0) { - this.trigger("warning", { code: "W100", line: this.line, character: char }); + // Explicitly reclassify token as a delimeter to prevent its later + // interpretation as an "infix" operator. + state.tokens.curr.delim = true; + state.tokens.curr.lbp = 0; + + if (!state.inES6()) { + warning("W119", state.tokens.curr, "computed property names", "6"); } + var value = expression(context & ~prodParams.noin, 10); + advance("]"); + return value; + } - // If there is a limit on line length, warn when lines get too - // long. + /** + * Test whether a given token is a punctuator whose `value` property matches + * one of the specified values. This function explicitly verifies the token's + * `type` property so that like-valued string literals (e.g. `";"`) do not + * produce false positives. + * + * @param {Token} token + * @param {Array.} values + * + * @returns {boolean} + */ + function checkPunctuators(token, values) { + if (token.type === "(punctuator)") { + return _.includes(values, token.value); + } + return false; + } - if (!this.ignoringLinterErrors && state.option.maxlen && - state.option.maxlen < this.input.length) { - var inComment = this.inComment || - startsWith.call(inputTrimmed, "//") || - startsWith.call(inputTrimmed, "/*"); + /** + * Test whether a given token is a punctuator whose `value` property matches + * the specified value. This function explicitly verifies the token's `type` + * property so that like-valued string literals (e.g. `";"`) do not produce + * false positives. + * + * @param {Token} token + * @param {string} value + * + * @returns {boolean} + */ + function checkPunctuator(token, value) { + return token.type === "(punctuator)" && token.value === value; + } - var shouldTriggerError = !inComment || !reg.maxlenException.test(inputTrimmed); + // Check whether this function has been reached for a destructuring assign with undeclared values + function destructuringAssignOrJsonValue(context) { + // lookup for the assignment (ECMAScript 6 only) + // if it has semicolons, it is a block, so go parse it as a block + // or it's not a block, but there are assignments, check for undeclared variables - if (shouldTriggerError) { - this.trigger("warning", { code: "W101", line: this.line, character: this.input.length }); + var block = lookupBlockType(); + if (block.notJson) { + if (!state.inES6() && block.isDestAssign) { + /* istanbul ignore next */ + warning("W104", state.tokens.curr, "destructuring assignment", "6"); } + statements(context); + // otherwise parse json value + } else { + state.option.laxbreak = true; + state.jsonMode = true; + jsonValue(); } + } - return true; - }, - - /* - * This is simply a synonym for nextLine() method with a friendlier - * public name. - */ - start: function() { - this.nextLine(); - }, - - /* - * Produce the next token. This function is called by advance() to get - * the next token. It returns a token in a JSLint-compatible format. + /** + * Parse and define the three states of a list comprehension in order to + * avoid defining global variables, but keeping them to the list + * comprehension scope only. The order of the states are as follows: + * + * - "use" - which will be the returned iterative part of the list + * comprehension + * - "define" - which will define the variables local to the list + * comprehension + * - "filter" - which will help filter out values */ - token: function() { - /*jshint loopfunc:true */ - var checks = asyncTrigger(); - var token; - - - function isReserved(token, isProperty) { - if (!token.reserved) { - return false; - } - var meta = token.meta; - - if (meta && meta.isFutureReservedWord && state.inES5()) { - // ES3 FutureReservedWord in an ES5 environment. - if (!meta.es5) { + var arrayComprehension = function() { + var CompArray = function() { + this.mode = "use"; + this.variables = []; + }; + var _carrays = []; + var _current; + function declare(v) { + var l = _current.variables.filter(function(elt) { + // if it has, change its undef state + if (elt.value === v) { + elt.undef = false; + return v; + } + }).length; + return l !== 0; + } + function use(v) { + var l = _current.variables.filter(function(elt) { + // and if it has been defined + if (elt.value === v && !elt.undef) { + if (elt.unused === true) { + elt.unused = false; + } + return v; + } + }).length; + // otherwise we warn about it + return (l === 0); + } + return { stack: function() { + _current = new CompArray(); + _carrays.push(_current); + }, + unstack: function() { + _current.variables.filter(function(v) { + if (v.unused) + warning("W098", v.token, v.token.raw_text || v.value); + if (v.undef) + state.funct["(scope)"].block.use(v.value, v.token); + }); + _carrays.splice(-1, 1); + _current = _carrays[_carrays.length - 1]; + }, + setState: function(s) { + if (_.includes(["use", "define", "generate", "filter"], s)) + _current.mode = s; + }, + check: function(v) { + if (!_current) { + return; + } + // When we are in "use" state of the list comp, we enqueue that var + if (_current && _current.mode === "use") { + if (use(v)) { + _current.variables.push({ + token: state.tokens.curr, + value: v, + undef: true, + unused: false + }); + } + return true; + // When we are in "define" state of the list comp, + } else if (_current && _current.mode === "define") { + // check if the variable has been used previously + if (!declare(v)) { + _current.variables.push({ + token: state.tokens.curr, + value: v, + undef: false, + unused: true + }); + } + return true; + // When we are in the "generate" state of the list comp, + } else if (_current && _current.mode === "generate") { + state.funct["(scope)"].block.use(v, state.tokens.curr); + return true; + // When we are in "filter" state, + } else if (_current && _current.mode === "filter") { + // we check whether current variable has been declared + if (use(v)) { + // if not we warn about it + /* istanbul ignore next */ + state.funct["(scope)"].block.use(v, state.tokens.curr); + } + return true; + } + /* istanbul ignore next */ return false; } + }; + }; - // Some ES5 FutureReservedWord identifiers are active only - // within a strict mode environment. - if (meta.strictOnly) { - if (!state.option.strict && !state.isStrict()) { - return false; + + /** + * Parse input according to the JSON format. + * + * http://json.org/ + */ + function jsonValue() { + function jsonObject() { + var o = {}, t = state.tokens.next; + advance("{"); + if (state.tokens.next.id !== "}") { + for (;;) { + if (state.tokens.next.id === "(end)") { + error("E026", state.tokens.next, t.line); + } else if (state.tokens.next.id === "}") { + warning("W094", state.tokens.curr); + break; + } else if (state.tokens.next.id === ",") { + error("E028", state.tokens.next); + } else if (state.tokens.next.id !== "(string)") { + warning("W095", state.tokens.next, state.tokens.next.value); + } + if (o[state.tokens.next.value] === true) { + warning("W075", state.tokens.next, "key", state.tokens.next.value); + } else if ((state.tokens.next.value === "__proto__" && + !state.option.proto) || (state.tokens.next.value === "__iterator__" && + !state.option.iterator)) { + warning("W096", state.tokens.next, state.tokens.next.value); + } else { + o[state.tokens.next.value] = true; + } + advance(); + advance(":"); + jsonValue(); + if (state.tokens.next.id !== ",") { + break; } + advance(","); } + } + advance("}"); + } - if (isProperty) { - return false; + function jsonArray() { + var t = state.tokens.next; + advance("["); + if (state.tokens.next.id !== "]") { + for (;;) { + if (state.tokens.next.id === "(end)") { + error("E027", state.tokens.next, t.line); + } else if (state.tokens.next.id === "]") { + warning("W094", state.tokens.curr); + break; + } else if (state.tokens.next.id === ",") { + error("E028", state.tokens.next); + } + jsonValue(); + if (state.tokens.next.id !== ",") { + break; + } + advance(","); } } + advance("]"); + } - return true; + switch (state.tokens.next.id) { + case "{": + jsonObject(); + break; + case "[": + jsonArray(); + break; + case "true": + case "false": + case "null": + case "(number)": + case "(string)": + advance(); + break; + case "-": + advance("-"); + advance("(number)"); + break; + default: + error("E003", state.tokens.next); } + } - // Produce a token object. - var create = function(type, value, isProperty, token) { - /*jshint validthis:true */ - var obj; + /** + * Lint dynamically-evaluated code, appending any resulting errors/warnings + * into the global `errors` array. + * + * @param {array} internals - collection of "internals" objects describing + * string tokens that contain evaluated code + * @param {object} options - linting options to apply + * @param {object} globals - globally-defined bindings for the evaluated code + */ + function lintEvalCode(internals, options, globals) { + var priorErrorCount, idx, jdx, internal; - if (type !== "(endline)" && type !== "(end)") { - this.prereg = false; - } + for (idx = 0; idx < internals.length; idx += 1) { + internal = internals[idx]; + options.scope = internal.elem; + priorErrorCount = JSHINT.errors.length; - if (type === "(punctuator)") { - switch (value) { - case ".": - case ")": - case "~": - case "#": - case "]": - case "++": - case "--": - this.prereg = false; - break; - default: - this.prereg = true; - } + itself(internal.code, options, globals); - obj = Object.create(state.syntax[value] || state.syntax["(error)"]); + for (jdx = priorErrorCount; jdx < JSHINT.errors.length; jdx += 1) { + JSHINT.errors[jdx].line += internal.token.line - 1; } + } + } - if (type === "(identifier)") { - if (value === "return" || value === "case" || value === "typeof") { - this.prereg = true; - } + var escapeRegex = function(str) { + return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); + }; - if (_.has(state.syntax, value)) { - obj = Object.create(state.syntax[value] || state.syntax["(error)"]); + // The actual JSHINT function itself. + var itself = function(s, o, g) { + var x, reIgnoreStr, reIgnore; + var optionKeys, newOptionObj, newIgnoredObj; - // If this can't be a reserved keyword, reset the object. - if (!isReserved(obj, isProperty && type === "(identifier)")) { - obj = null; - } - } - } + o = _.clone(o); + state.reset(); + newOptionObj = state.option; + newIgnoredObj = state.ignored; - if (!obj) { - obj = Object.create(state.syntax[type]); - } + if (o && o.scope) { + JSHINT.scope = o.scope; + } else { + JSHINT.errors = []; + JSHINT.internals = []; + JSHINT.blacklist = {}; + JSHINT.scope = "(main)"; + } - obj.identifier = (type === "(identifier)"); - obj.type = obj.type || type; - obj.value = value; - obj.line = this.line; - obj.character = this.char; - obj.from = this.from; - if (obj.identifier && token) obj.raw_text = token.text || token.value; - if (token && token.startLine && token.startLine !== this.line) { - obj.startLine = token.startLine; - } - if (token && token.context) { - // Context of current token - obj.context = token.context; - } - if (token && token.depth) { - // Nested template depth - obj.depth = token.depth; - } - if (token && token.isUnclosed) { - // Mark token as unclosed string / template literal - obj.isUnclosed = token.isUnclosed; - } + predefined = Object.create(null); + combine(predefined, vars.ecmaIdentifiers[3]); + combine(predefined, vars.reservedVars); - if (isProperty && obj.identifier) { - obj.isProperty = isProperty; - } + declared = Object.create(null); + var exported = Object.create(null); // Variables that live outside the current file - obj.check = checks.check; + function each(obj, cb) { + if (!obj) + return; - return obj; - }.bind(this); + if (!Array.isArray(obj) && typeof obj === "object") + obj = Object.keys(obj); - for (;;) { - if (!this.input.length) { - if (this.nextLine()) { - return create("(endline)", ""); - } + obj.forEach(cb); + } - if (this.exhausted) { - return null; - } + if (o) { - this.exhausted = true; - return create("(end)", ""); - } + each([o.predef, o.globals], function(dict) { + each(dict, function(item) { + var slice, prop; - token = this.next(checks); + if (item[0] === "-") { + slice = item.slice(1); + JSHINT.blacklist[slice] = slice; + // remove from predefined if there + delete predefined[slice]; + } else { + prop = Object.getOwnPropertyDescriptor(dict, item); + predefined[item] = prop ? prop.value : false; + } + }); + }); - if (!token) { - if (this.input.length) { - // Unexpected character. - this.trigger("error", { - code: "E024", - line: this.line, - character: this.char, - data: [ this.peek() ] - }); + each(o.exported || null, function(item) { + exported[item] = true; + }); - this.input = ""; - } + delete o.predef; + delete o.exported; - continue; + optionKeys = Object.keys(o); + for (x = 0; x < optionKeys.length; x++) { + if (/^-W\d{3}$/g.test(optionKeys[x])) { + newIgnoredObj[optionKeys[x].slice(1)] = true; + } else { + var optionKey = optionKeys[x]; + newOptionObj[optionKey] = o[optionKey]; + } } + } - switch (token.type) { - case Token.StringLiteral: - this.triggerAsync("String", { - line: this.line, - char: this.char, - from: this.from, - startLine: token.startLine, - startChar: token.startChar, - value: token.value, - quote: token.quote - }, checks, function() { return true; }); - - return create("(string)", token.value, null, token); - - case Token.TemplateHead: - this.trigger("TemplateHead", { - line: this.line, - char: this.char, - from: this.from, - startLine: token.startLine, - startChar: token.startChar, - value: token.value - }); - return create("(template)", token.value, null, token); + state.option = newOptionObj; + state.ignored = newIgnoredObj; - case Token.TemplateMiddle: - this.trigger("TemplateMiddle", { - line: this.line, - char: this.char, - from: this.from, - startLine: token.startLine, - startChar: token.startChar, - value: token.value - }); - return create("(template middle)", token.value, null, token); + state.option.indent = state.option.indent || 4; + state.option.maxerr = state.option.maxerr || 50; - case Token.TemplateTail: - this.trigger("TemplateTail", { - line: this.line, - char: this.char, - from: this.from, - startLine: token.startLine, - startChar: token.startChar, - value: token.value - }); - return create("(template tail)", token.value, null, token); + indent = 1; - case Token.NoSubstTemplate: - this.trigger("NoSubstTemplate", { - line: this.line, - char: this.char, - from: this.from, - startLine: token.startLine, - startChar: token.startChar, - value: token.value - }); - return create("(no subst template)", token.value, null, token); + var scopeManagerInst = scopeManager(state, predefined, exported, declared); + scopeManagerInst.on("warning", function(ev) { + warning.apply(null, [ ev.code, ev.token].concat(ev.data)); + }); - case Token.Identifier: - this.triggerAsync("Identifier", { - line: this.line, - char: this.char, - from: this.form, - name: token.value, - raw_name: token.text, - isProperty: state.tokens.curr.id === "." - }, checks, function() { return true; }); + scopeManagerInst.on("error", function(ev) { + /* istanbul ignore next */ + error.apply(null, [ ev.code, ev.token ].concat(ev.data)); + }); - /* falls through */ - case Token.Keyword: - case Token.NullLiteral: - case Token.BooleanLiteral: - return create("(identifier)", token.value, state.tokens.curr.id === ".", token); + state.funct = functor("(global)", null, { + "(global)" : true, + "(scope)" : scopeManagerInst, + "(comparray)" : arrayComprehension(), + "(metrics)" : createMetrics(state.tokens.next) + }); - case Token.NumericLiteral: - if (token.isMalformed) { - this.trigger("warning", { - code: "W045", - line: this.line, - character: this.char, - data: [ token.value ] - }); - } + functions = [state.funct]; + member = {}; + membersOnly = null; + inblock = false; + lookahead = []; - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "0x-" ] - }, checks, function() { return token.base === 16 && state.jsonMode; }); + if (!isString(s) && !Array.isArray(s)) { + errorAt("E004", 0); + return false; + } - this.triggerAsync("warning", { - code: "W115", - line: this.line, - character: this.char - }, checks, function() { - return state.isStrict() && token.base === 8 && token.isLegacy; - }); + api = { + get isJSON() { + /* istanbul ignore next */ + return state.jsonMode; + }, - this.trigger("Number", { - line: this.line, - char: this.char, - from: this.from, - value: token.value, - base: token.base, - isMalformed: token.malformed - }); + getOption: function(name) { + return state.option[name] || null; + }, - return create("(number)", token.value); + getCache: function(name) { + return state.cache[name]; + }, - case Token.RegExp: - return create("(regexp)", token.value); + setCache: function(name, value) { + state.cache[name] = value; + }, - case Token.Comment: - state.tokens.curr.comment = true; + warn: function(code, data) { + warningAt.apply(null, [ code, data.line, data.char ].concat(data.data)); + }, - if (token.isSpecial) { - return { - id: '(comment)', - value: token.value, - body: token.body, - type: token.commentType, - isSpecial: token.isSpecial, - line: this.line, - character: this.char, - from: this.from - }; - } + on: function(names, listener) { + names.split(" ").forEach(function(name) { + emitter.on(name, listener); + }.bind(this)); + } + }; - break; + emitter.removeAllListeners(); + (extraModules || []).forEach(function(func) { + func(api); + }); - case "": - break; + state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"]; + if (o && o.ignoreDelimiters) { - default: - return create("(punctuator)", token.value); + if (!Array.isArray(o.ignoreDelimiters)) { + /* istanbul ignore next */ + o.ignoreDelimiters = [o.ignoreDelimiters]; } - } - } -}; -exports.Lexer = Lexer; -exports.Context = Context; + o.ignoreDelimiters.forEach(function(delimiterPair) { + if (!delimiterPair.start || !delimiterPair.end) + return; -},{"../data/ascii-identifier-data.js":"/node_modules/jshint/data/ascii-identifier-data.js","../lodash":"/node_modules/jshint/lodash.js","./reg.js":"/node_modules/jshint/src/reg.js","./state.js":"/node_modules/jshint/src/state.js","events":"/node_modules/browserify/node_modules/events/events.js"}],"/node_modules/jshint/src/messages.js":[function(_dereq_,module,exports){ -"use strict"; + reIgnoreStr = escapeRegex(delimiterPair.start) + + "[\\s\\S]*?" + + escapeRegex(delimiterPair.end); -var _ = _dereq_("../lodash"); + reIgnore = new RegExp(reIgnoreStr, "ig"); -var errors = { - // JSHint options - E001: "Bad option: '{a}'.", - E002: "Bad option value.", + s = s.replace(reIgnore, function(match) { + return match.replace(/./g, " "); + }); + }); + } - // JSHint input - E003: "Expected a JSON value.", - E004: "Input is neither a string nor an array of strings.", - E005: "Input is empty.", - E006: "Unexpected early end of program.", + lex = new Lexer(s); - // Strict mode - E007: "Missing \"use strict\" statement.", - E008: "Strict violation.", - E009: "Option 'validthis' can't be used in a global scope.", - E010: "'with' is not allowed in strict mode.", + lex.on("warning", function(ev) { + warningAt.apply(null, [ ev.code, ev.line, ev.character].concat(ev.data)); + }); - // Constants - E011: "'{a}' has already been declared.", - E012: "const '{a}' is initialized to 'undefined'.", - E013: "Attempting to override '{a}' which is a constant.", + lex.on("error", function(ev) { + errorAt.apply(null, [ ev.code, ev.line, ev.character ].concat(ev.data)); + }); - // Regular expressions - E014: "A regular expression literal can be confused with '/='.", - E015: "Unclosed regular expression.", - E016: "Invalid regular expression.", + lex.on("fatal", function(ev) { + quit("E041", ev); + }); - // Tokens - E017: "Unclosed comment.", - E018: "Unbegun comment.", - E019: "Unmatched '{a}'.", - E020: "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", - E021: "Expected '{a}' and instead saw '{b}'.", - E022: "Line breaking error '{a}'.", - E023: "Missing '{a}'.", - E024: "Unexpected '{a}'.", - E025: "Missing ':' on a case clause.", - E026: "Missing '}' to match '{' from line {a}.", - E027: "Missing ']' to match '[' from line {a}.", - E028: "Illegal comma.", - E029: "Unclosed string.", + lex.on("Identifier", function(ev) { + emitter.emit("Identifier", ev); + }); - // Everything else - E030: "Expected an identifier and instead saw '{a}'.", - E031: "Bad assignment.", // FIXME: Rephrase - E032: "Expected a small integer or 'false' and instead saw '{a}'.", - E033: "Expected an operator and instead saw '{a}'.", - E034: "get/set are ES5 features.", - E035: "Missing property name.", - E036: "Expected to see a statement and instead saw a block.", - E037: null, - E038: null, - E039: "Function declarations are not invocable. Wrap the whole function invocation in parens.", - E040: "Each value should have its own case label.", - E041: "Unrecoverable syntax error.", - E042: "Stopping.", - E043: "Too many errors.", - E044: null, - E045: "Invalid for each loop.", - E046: "A yield statement shall be within a generator function (with syntax: `function*`)", - E047: null, - E048: "{a} declaration not directly within block.", - E049: "A {a} cannot be named '{b}'.", - E050: "Mozilla requires the yield expression to be parenthesized here.", - E051: null, - E052: "Unclosed template literal.", - E053: "Export declaration must be in global scope.", - E054: "Class properties must be methods. Expected '(' but instead saw '{a}'.", - E055: "The '{a}' option cannot be set after any executable code.", - E056: "'{a}' was used before it was declared, which is illegal for '{b}' variables.", - E057: "Invalid meta property: '{a}.{b}'.", - E058: "Missing semicolon." -}; + lex.on("String", function(ev) { + emitter.emit("String", ev); + }); -var warnings = { - W001: "'hasOwnProperty' is a really bad name.", - W002: "Value of '{a}' may be overwritten in IE 8 and earlier.", - W003: "'{a}' was used before it was defined.", - W004: "'{a}' is already defined.", - W005: "A dot following a number can be confused with a decimal point.", - W006: "Confusing minuses.", - W007: "Confusing plusses.", - W008: "A leading decimal point can be confused with a dot: '{a}'.", - W009: "The array literal notation [] is preferable.", - W010: "The object literal notation {} is preferable.", - W011: null, - W012: null, - W013: null, - W014: "Bad line breaking before '{a}'.", - W015: null, - W016: "Unexpected use of '{a}'.", - W017: "Bad operand.", - W018: "Confusing use of '{a}'.", - W019: "Use the isNaN function to compare with NaN.", - W020: "Read only.", - W021: "Reassignment of '{a}', which is is a {b}. " + - "Use 'var' or 'let' to declare bindings that may change.", - W022: "Do not assign to the exception parameter.", - W023: "Expected an identifier in an assignment and instead saw a function invocation.", - W024: "Expected an identifier and instead saw '{a}' (a reserved word).", - W025: "Missing name in function declaration.", - W026: "Inner functions should be listed at the top of the outer function.", - W027: "Unreachable '{a}' after '{b}'.", - W028: "Label '{a}' on {b} statement.", - W030: "Expected an assignment or function call and instead saw an expression.", - W031: "Do not use 'new' for side effects.", - W032: "Unnecessary semicolon.", - W033: "Missing semicolon.", - W034: "Unnecessary directive \"{a}\".", - W035: "Empty block.", - W036: "Unexpected /*member '{a}'.", - W037: "'{a}' is a statement label.", - W038: "'{a}' used out of scope.", - W039: "'{a}' is not allowed.", - W040: "Possible strict violation.", - W041: "Use '{a}' to compare with '{b}'.", - W042: "Avoid EOL escaping.", - W043: "Bad escaping of EOL. Use option multistr if needed.", - W044: "Bad or unnecessary escaping.", /* TODO(caitp): remove W044 */ - W045: "Bad number '{a}'.", - W046: "Don't use extra leading zeros '{a}'.", - W047: "A trailing decimal point can be confused with a dot: '{a}'.", - W048: "Unexpected control character in regular expression.", - W049: "Unexpected escaped character '{a}' in regular expression.", - W050: "JavaScript URL.", - W051: "Variables should not be deleted.", - W052: "Unexpected '{a}'.", - W053: "Do not use {a} as a constructor.", - W054: "The Function constructor is a form of eval.", - W055: "A constructor name should start with an uppercase letter.", - W056: "Bad constructor.", - W057: "Weird construction. Is 'new' necessary?", - W058: "Missing '()' invoking a constructor.", - W059: "Avoid arguments.{a}.", - W060: "document.write can be a form of eval.", - W061: "eval can be harmful.", - W062: "Wrap an immediate function invocation in parens " + - "to assist the reader in understanding that the expression " + - "is the result of a function, and not the function itself.", - W063: "Math is not a function.", - W064: "Missing 'new' prefix when invoking a constructor.", - W065: "Missing radix parameter.", - W066: "Implied eval. Consider passing a function instead of a string.", - W067: "Bad invocation.", - W068: "Wrapping non-IIFE function literals in parens is unnecessary.", - W069: "['{a}'] is better written in dot notation.", - W070: "Extra comma. (it breaks older versions of IE)", - W071: "This function has too many statements. ({a})", - W072: "This function has too many parameters. ({a})", - W073: "Blocks are nested too deeply. ({a})", - W074: "This function's cyclomatic complexity is too high. ({a})", - W075: "Duplicate {a} '{b}'.", - W076: "Unexpected parameter '{a}' in get {b} function.", - W077: "Expected a single parameter in set {a} function.", - W078: "Setter is defined without getter.", - W079: "Redefinition of '{a}'.", - W080: "It's not necessary to initialize '{a}' to 'undefined'.", - W081: null, - W082: "Function declarations should not be placed in blocks. " + - "Use a function expression or move the statement to the top of " + - "the outer function.", - W083: "Don't make functions within a loop.", - W084: "Assignment in conditional expression", - W085: "Don't use 'with'.", - W086: "Expected a 'break' statement before '{a}'.", - W087: "Forgotten 'debugger' statement?", - W088: "Creating global 'for' variable. Should be 'for (var {a} ...'.", - W089: "The body of a for in should be wrapped in an if statement to filter " + - "unwanted properties from the prototype.", - W090: "'{a}' is not a statement label.", - W091: null, - W093: "Did you mean to return a conditional instead of an assignment?", - W094: "Unexpected comma.", - W095: "Expected a string and instead saw {a}.", - W096: "The '{a}' key may produce unexpected results.", - W097: "Use the function form of \"use strict\".", - W098: "'{a}' is defined but never used.", - W099: null, - W100: "This character may get silently deleted by one or more browsers.", - W101: "Line is too long.", - W102: null, - W103: "The '{a}' property is deprecated.", - W104: "'{a}' is available in ES{b} (use 'esversion: {b}') or Mozilla JS extensions (use moz).", - W105: "Unexpected {a} in '{b}'.", - W106: "Identifier '{a}' is not in camel case.", - W107: "Script URL.", - W108: "Strings must use doublequote.", - W109: "Strings must use singlequote.", - W110: "Mixed double and single quotes.", - W112: "Unclosed string.", - W113: "Control character in string: {a}.", - W114: "Avoid {a}.", - W115: "Octal literals are not allowed in strict mode.", - W116: "Expected '{a}' and instead saw '{b}'.", - W117: "'{a}' is not defined.", - W118: "'{a}' is only available in Mozilla JavaScript extensions (use moz option).", - W119: "'{a}' is only available in ES{b} (use 'esversion: {b}').", - W120: "You might be leaking a variable ({a}) here.", - W121: "Extending prototype of native object: '{a}'.", - W122: "Invalid typeof value '{a}'", - W123: "'{a}' is already defined in outer scope.", - W124: "A generator function shall contain a yield statement.", - W125: "This line contains non-breaking spaces: http://jshint.com/doc/options/#nonbsp", - W126: "Unnecessary grouping operator.", - W127: "Unexpected use of a comma operator.", - W128: "Empty array elements require elision=true.", - W129: "'{a}' is defined in a future version of JavaScript. Use a " + - "different variable name to avoid migration issues.", - W130: "Invalid element after rest element.", - W131: "Invalid parameter after rest parameter.", - W132: "`var` declarations are forbidden. Use `let` or `const` instead.", - W133: "Invalid for-{a} loop left-hand-side: {b}.", - W134: "The '{a}' option is only available when linting ECMAScript {b} code.", - W135: "{a} may not be supported by non-browser environments.", - W136: "'{a}' must be in function scope.", - W137: "Empty destructuring.", - W138: "Regular parameters should not come after default parameters." -}; + lex.on("Number", function(ev) { + emitter.emit("Number", ev); + }); -var info = { - I001: "Comma warnings can be turned off with 'laxcomma'.", - I002: null, - I003: "ES5 option is now set per default" -}; + // Check options + var name; + for (name in o) { + if (_.has(o, name)) { + checkOption(name, true, state.tokens.curr); + } + } + if (o) { + for (name in o.unstable) { + if (_.has(o.unstable, name)) { + checkOption(name, false, state.tokens.curr); + } + } + } -exports.errors = {}; -exports.warnings = {}; -exports.info = {}; + try { + applyOptions(); -_.each(errors, function(desc, code) { - exports.errors[code] = { code: code, desc: desc }; -}); + // combine the passed globals after we've assumed all our options + combine(predefined, g || {}); -_.each(warnings, function(desc, code) { - exports.warnings[code] = { code: code, desc: desc }; -}); + //reset values + checkComma.first = true; -_.each(info, function(desc, code) { - exports.info[code] = { code: code, desc: desc }; -}); + advance(); + switch (state.tokens.next.id) { + case "{": + case "[": + destructuringAssignOrJsonValue(0); + break; + default: + directives(); -},{"../lodash":"/node_modules/jshint/lodash.js"}],"/node_modules/jshint/src/name-stack.js":[function(_dereq_,module,exports){ -"use strict"; + if (state.directive["use strict"]) { + if (!state.allowsGlobalUsd()) { + warning("W097", state.tokens.prev); + } + } -function NameStack() { - this._stack = []; -} + statements(0); + } -Object.defineProperty(NameStack.prototype, "length", { - get: function() { - return this._stack.length; - } -}); + if (state.tokens.next.id !== "(end)") { + quit("E041", state.tokens.curr); + } -/** - * Create a new entry in the stack. Useful for tracking names across - * expressions. - */ -NameStack.prototype.push = function() { - this._stack.push(null); -}; + state.funct["(scope)"].unstack(); -/** - * Discard the most recently-created name on the stack. - */ -NameStack.prototype.pop = function() { - this._stack.pop(); -}; + } catch (err) { + if (err && err.name === "JSHintError") { + var nt = state.tokens.next || {}; + JSHINT.errors.push({ + scope : "(main)", + raw : err.raw, + code : err.code, + reason : err.reason, + line : err.line || nt.line, + character : err.character || nt.from + }); + } else { + /* istanbul ignore next */ + throw err; + } + } -/** - * Update the most recent name on the top of the stack. - * - * @param {object} token The token to consider as the source for the most - * recent name. - */ -NameStack.prototype.set = function(token) { - this._stack[this.length - 1] = token; -}; + // Loop over the listed "internals", and check them as well. + if (JSHINT.scope === "(main)") { + lintEvalCode(JSHINT.internals, o || {}, g); + } -/** - * Generate a string representation of the most recent name. - * - * @returns {string} - */ -NameStack.prototype.infer = function() { - var nameToken = this._stack[this.length - 1]; - var prefix = ""; - var type; + return JSHINT.errors.length === 0; + }; - // During expected operation, the topmost entry on the stack will only - // reflect the current function's name when the function is declared without - // the `function` keyword (i.e. for in-line accessor methods). In other - // cases, the `function` expression itself will introduce an empty entry on - // the top of the stack, and this should be ignored. - if (!nameToken || nameToken.type === "class") { - nameToken = this._stack[this.length - 2]; - } + // Modules. + itself.addModule = function(func) { + extraModules.push(func); + }; - if (!nameToken) { - return "(empty)"; - } + itself.addModule(style.register); - type = nameToken.type; + // Data summary. + itself.data = function() { + var data = { + functions: [], + options: state.option + }; - if (type !== "(string)" && type !== "(number)" && type !== "(identifier)" && type !== "default") { - return "(expression)"; - } + var fu, f, i, n, globals; - if (nameToken.accessorType) { - prefix = nameToken.accessorType + " "; - } + if (itself.errors.length) { + data.errors = itself.errors; + } - return prefix + nameToken.value; -}; + if (state.jsonMode) { + /* istanbul ignore next */ + data.json = true; + } -module.exports = NameStack; + var impliedGlobals = state.funct["(scope)"].getImpliedGlobals(); + if (impliedGlobals.length > 0) { + data.implieds = impliedGlobals; + } -},{}],"/node_modules/jshint/src/options.js":[function(_dereq_,module,exports){ -"use strict"; + globals = state.funct["(scope)"].getUsedOrDefinedGlobals(); + if (globals.length > 0) { + data.globals = globals; + } -// These are the JSHint boolean options. -exports.bool = { - enforcing: { + for (i = 1; i < functions.length; i += 1) { + f = functions[i]; + fu = {}; - /** - * This option prohibits the use of bitwise operators such as `^` (XOR), - * `|` (OR) and others. Bitwise operators are very rare in JavaScript - * programs and quite often `&` is simply a mistyped `&&`. - */ - bitwise : true, + fu.name = f["(name)"]; + fu.param = f["(params)"]; + fu.line = f["(line)"]; + fu.character = f["(character)"]; + fu.last = f["(last)"]; + fu.lastcharacter = f["(lastcharacter)"]; - /** - * - * This options prohibits overwriting prototypes of native objects such as - * `Array`, `Date` and so on. - * - * // jshint freeze:true - * Array.prototype.count = function (value) { return 4; }; - * // -> Warning: Extending prototype of native object: 'Array'. - */ - freeze : true, + fu.metrics = { + complexity: f["(metrics)"].ComplexityCount, + parameters: f["(metrics)"].arity, + statements: f["(metrics)"].statementCount + }; - /** - * This option allows you to force all variable names to use either - * camelCase style or UPPER_CASE with underscores. - * - * @deprecated JSHint is limiting its scope to issues of code correctness. - * If you would like to enforce rules relating to code style, - * check out [the JSCS - * project](https://github.com/jscs-dev/node-jscs). - */ - camelcase : true, + data.functions.push(fu); + } - /** - * This option requires you to always put curly braces around blocks in - * loops and conditionals. JavaScript allows you to omit curly braces when - * the block consists of only one statement, for example: - * - * while (day) - * shuffle(); - * - * However, in some circumstances, it can lead to bugs (you'd think that - * `sleep()` is a part of the loop while in reality it is not): - * - * while (day) - * shuffle(); - * sleep(); - */ - curly : true, + var unuseds = state.funct["(scope)"].getUnuseds(); + if (unuseds.length > 0) { + data.unused = unuseds; + } - /** - * This options prohibits the use of `==` and `!=` in favor of `===` and - * `!==`. The former try to coerce values before comparing them which can - * lead to some unexpected results. The latter don't do any coercion so - * they are generally safer. If you would like to learn more about type - * coercion in JavaScript, we recommend [Truth, Equality and - * JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/) - * by Angus Croll. - */ - eqeqeq : true, + for (n in member) { + if (typeof member[n] === "number") { + data.member = member; + break; + } + } - /** - * This option enables warnings about the use of identifiers which are - * defined in future versions of JavaScript. Although overwriting them has - * no effect in contexts where they are not implemented, this practice can - * cause issues when migrating codebases to newer versions of the language. - */ - futurehostile: true, + return data; + }; - /** - * This option suppresses warnings about invalid `typeof` operator values. - * This operator has only [a limited set of possible return - * values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof). - * By default, JSHint warns when you compare its result with an invalid - * value which often can be a typo. - * - * // 'fuction' instead of 'function' - * if (typeof a == "fuction") { // Invalid typeof value 'fuction' - * // ... - * } - * - * Do not use this option unless you're absolutely sure you don't want - * these checks. - */ - notypeof : true, + itself.jshint = itself; - /** - * This option tells JSHint that your code needs to adhere to ECMAScript 3 - * specification. Use this option if you need your program to be executable - * in older browsers—such as Internet Explorer 6/7/8/9—and other legacy - * JavaScript environments. - * - * @deprecated Use `esversion: 3` instead. - */ - es3 : true, + return itself; +}()); - /** - * This option enables syntax first defined in [the ECMAScript 5.1 - * specification](http://es5.github.io/). This includes allowing reserved - * keywords as object properties. - * - * @deprecated Use `esversion: 5` instead. - */ - es5 : true, +// Make JSHINT a Node module, if possible. +if (typeof exports === "object" && exports) { + exports.JSHINT = JSHINT; +} - /** - * This option requires all `for in` loops to filter object's items. The - * for in statement allows for looping through the names of all of the - * properties of an object including those inherited through the prototype - * chain. This behavior can lead to unexpected items in your object so it - * is generally safer to always filter inherited properties out as shown in - * the example: - * - * for (key in obj) { - * if (obj.hasOwnProperty(key)) { - * // We are sure that obj[key] belongs to the object and was not inherited. - * } - * } - * - * For more in-depth understanding of `for in` loops in JavaScript, read - * [Exploring JavaScript for-in - * loops](http://javascriptweblog.wordpress.com/2011/01/04/exploring-javascript-for-in-loops/) - * by Angus Croll. - */ - forin : true, +},{"./lex.js":"/../../jshint/src/lex.js","./messages.js":"/../../jshint/src/messages.js","./options.js":"/../../jshint/src/options.js","./prod-params.js":"/../../jshint/src/prod-params.js","./reg.js":"/../../jshint/src/reg.js","./scope-manager.js":"/../../jshint/src/scope-manager.js","./state.js":"/../../jshint/src/state.js","./style.js":"/../../jshint/src/style.js","./vars.js":"/../../jshint/src/vars.js","console-browserify":"/../../jshint/node_modules/console-browserify/index.js","events":"/../node_modules/events/events.js","lodash.clone":"/../../jshint/node_modules/lodash.clone/index.js","underscore":"/../../jshint/node_modules/underscore/underscore.js"}],"/../../jshint/src/lex.js":[function(_dereq_,module,exports){ +/* + * Lexical analysis and token construction. + */ - /** - * This option suppresses warnings about declaring variables inside of - * control - * structures while accessing them later from the outside. Even though - * JavaScript has only two real scopes—global and function—such practice - * leads to confusion among people new to the language and hard-to-debug - * bugs. This is why, by default, JSHint warns about variables that are - * used outside of their intended scope. - * - * function test() { - * if (true) { - * var x = 0; - * } - * - * x += 1; // Default: 'x' used out of scope. - * // No warning when funcscope:true - * } - */ - funcscope : true, +"use strict"; - /** - * This option prohibits the use of immediate function invocations without - * wrapping them in parentheses. Wrapping parentheses assists readers of - * your code in understanding that the expression is the result of a - * function, and not the function itself. - * - * @deprecated JSHint is limiting its scope to issues of code correctness. - * If you would like to enforce rules relating to code style, - * check out [the JSCS - * project](https://github.com/jscs-dev/node-jscs). - */ - immed : true, +var _ = _dereq_("underscore"); +var events = _dereq_("events"); +var reg = _dereq_("./reg.js"); +var state = _dereq_("./state.js").state; - /** - * This option suppresses warnings about the `__iterator__` property. This - * property is not supported by all browsers so use it carefully. - */ - iterator : true, +var unicodeData = _dereq_("../data/ascii-identifier-data.js"); +var asciiIdentifierStartTable = unicodeData.asciiIdentifierStartTable; +var asciiIdentifierPartTable = unicodeData.asciiIdentifierPartTable; +var nonAsciiIdentifierStartTable = _dereq_("../data/non-ascii-identifier-start.js"); +var nonAsciiIdentifierPartTable = _dereq_("../data/non-ascii-identifier-part-only.js"); +// Loading of this module is deferred as an optimization for ES2015 input +var es5IdentifierNames; - /** - * This option requires you to capitalize names of constructor functions. - * Capitalizing functions that are intended to be used with `new` operator - * is just a convention that helps programmers to visually distinguish - * constructor functions from other types of functions to help spot - * mistakes when using `this`. - * - * Not doing so won't break your code in any browsers or environments but - * it will be a bit harder to figure out—by reading the code—if the - * function was supposed to be used with or without new. And this is - * important because when the function that was intended to be used with - * `new` is used without it, `this` will point to the global object instead - * of a new object. - * - * @deprecated JSHint is limiting its scope to issues of code correctness. - * If you would like to enforce rules relating to code style, - * check out [the JSCS - * project](https://github.com/jscs-dev/node-jscs). - */ - newcap : true, +// Some of these token types are from JavaScript Parser API +// while others are specific to JSHint parser. +// JS Parser API: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API - /** - * This option prohibits the use of `arguments.caller` and - * `arguments.callee`. Both `.caller` and `.callee` make quite a few - * optimizations impossible so they were deprecated in future versions of - * JavaScript. In fact, ECMAScript 5 forbids the use of `arguments.callee` - * in strict mode. - */ - noarg : true, +var Token = { + Identifier: 1, + Punctuator: 2, + NumericLiteral: 3, + StringLiteral: 4, + Comment: 5, + Keyword: 6, + RegExp: 9, + TemplateHead: 10, + TemplateMiddle: 11, + TemplateTail: 12, + NoSubstTemplate: 13 +}; - /** - * This option prohibits the use of the comma operator. When misused, the - * comma operator can obscure the value of a statement and promote - * incorrect code. - */ - nocomma : true, +var Context = { + Block: 1, + Template: 2 +}; - /** - * This option warns when you have an empty block in your code. JSLint was - * originally warning for all empty blocks and we simply made it optional. - * There were no studies reporting that empty blocks in JavaScript break - * your code in any way. - * - * @deprecated JSHint is limiting its scope to issues of code correctness. - * If you would like to enforce rules relating to code style, - * check out [the JSCS - * project](https://github.com/jscs-dev/node-jscs). - */ - noempty : true, +function isHex(str) { + return /^[0-9a-fA-F]+$/.test(str); +} - /** - * This option warns about "non-breaking whitespace" characters. These - * characters can be entered with option-space on Mac computers and have a - * potential of breaking non-UTF8 web pages. - */ - nonbsp : true, +function isHexDigit(str) { + return str.length === 1 && isHex(str); +} - /** - * This option prohibits the use of constructor functions for side-effects. - * Some people like to call constructor functions without assigning its - * result to any variable: - * - * new MyConstructor(); - * - * There is no advantage in this approach over simply calling - * `MyConstructor` since the object that the operator `new` creates isn't - * used anywhere so you should generally avoid constructors like this one. - */ - nonew : true, +// Object that handles postponed lexing verifications that checks the parsed +// environment state. - /** - * This option prohibits the use of explicitly undeclared variables. This - * option is very useful for spotting leaking and mistyped variables. - * - * // jshint undef:true - * - * function test() { - * var myVar = 'Hello, World'; - * console.log(myvar); // Oops, typoed here. JSHint with undef will complain - * } - * - * If your variable is defined in another file, you can use the `global` - * directive to tell JSHint about it. - */ - undef : true, +function asyncTrigger() { + var _checks = []; - /** - * This option prohibits the use of the grouping operator when it is not - * strictly required. Such usage commonly reflects a misunderstanding of - * unary operators, for example: - * - * // jshint singleGroups: true - * - * delete(obj.attr); // Warning: Unnecessary grouping operator. - */ - singleGroups: false, + return { + push: function(fn) { + _checks.push(fn); + }, - /** - * When set to true, the use of VariableStatements are forbidden. - * For example: - * - * // jshint varstmt: true - * - * var a; // Warning: `var` declarations are forbidden. Use `let` or `const` instead. - */ - varstmt: false, + check: function() { + for (var check = 0; check < _checks.length; ++check) { + _checks[check](); + } - /** - * This option is a short hand for the most strict JSHint configuration as - * available in JSHint version 2.6.3. It enables all enforcing options and - * disables all relaxing options that were defined in that release. - * - * @deprecated The option cannot be maintained without automatically opting - * users in to new features. This can lead to unexpected - * warnings/errors in when upgrading between minor versions of - * JSHint. - */ - enforceall : false - }, - relaxing: { + _checks.splice(0, _checks.length); + } + }; +} - /** - * This option suppresses warnings about missing semicolons. There is a lot - * of FUD about semicolon spread by quite a few people in the community. - * The common myths are that semicolons are required all the time (they are - * not) and that they are unreliable. JavaScript has rules about semicolons - * which are followed by *all* browsers so it is up to you to decide - * whether you should or should not use semicolons in your code. - * - * For more information about semicolons in JavaScript read [An Open Letter - * to JavaScript Leaders Regarding - * Semicolons](http://blog.izs.me/post/2353458699/an-open-letter-to-javascript-leaders-regarding) - * by Isaac Schlueter and [JavaScript Semicolon - * Insertion](http://inimino.org/~inimino/blog/javascript_semicolons). - */ - asi : true, +/* + * Lexer for JSHint. + * + * This object does a char-by-char scan of the provided source code + * and produces a sequence of tokens. + * + * var lex = new Lexer("var i = 0;"); + * lex.start(); + * lex.token(); // returns the next token + * + * You have to use the token() method to move the lexer forward + * but you don't have to use its return value to get tokens. In addition + * to token() method returning the next token, the Lexer object also + * emits events. + * + * lex.on("Identifier", function(data) { + * if (data.name.indexOf("_") >= 0) { + * // Produce a warning. + * } + * }); + * + * Note that the token() method returns tokens in a JSLint-compatible + * format while the event emitter uses a slightly modified version of + * Mozilla's JavaScript Parser API. Eventually, we will move away from + * JSLint format. + */ +function Lexer(source) { + var lines = source; - /** - * This option suppresses warnings about multi-line strings. Multi-line - * strings can be dangerous in JavaScript because all hell breaks loose if - * you accidentally put a whitespace in between the escape character (`\`) - * and a new line. - * - * Note that even though this option allows correct multi-line strings, it - * still warns about multi-line strings without escape characters or with - * anything in between the escape character and a whitespace. - * - * // jshint multistr:true - * - * var text = "Hello\ - * World"; // All good. - * - * text = "Hello - * World"; // Warning, no escape character. - * - * text = "Hello\ - * World"; // Warning, there is a space after \ - * - * @deprecated JSHint is limiting its scope to issues of code correctness. - * If you would like to enforce rules relating to code style, - * check out [the JSCS - * project](https://github.com/jscs-dev/node-jscs). - */ - multistr : true, - - /** - * This option suppresses warnings about the `debugger` statements in your - * code. - */ - debug : true, + if (typeof lines === "string") { + lines = lines + .replace(/\r\n/g, "\n") + .replace(/\r/g, "\n") + .split("\n"); + } - /** - * This option suppresses warnings about the use of assignments in cases - * where comparisons are expected. More often than not, code like `if (a = - * 10) {}` is a typo. However, it can be useful in cases like this one: - * - * for (var i = 0, person; person = people[i]; i++) {} - * - * You can silence this error on a per-use basis by surrounding the assignment - * with parenthesis, such as: - * - * for (var i = 0, person; (person = people[i]); i++) {} - */ - boss : true, + // If the first line is a shebang (#!), make it a blank and move on. + // Shebangs are used by Node scripts. - /** - * This option suppresses warnings about the use of `eval`. The use of - * `eval` is discouraged because it can make your code vulnerable to - * various injection attacks and it makes it hard for JavaScript - * interpreter to do certain optimizations. - */ - evil : true, + if (lines[0] && lines[0].substr(0, 2) === "#!") { + if (lines[0].indexOf("node") !== -1) { + state.option.node = true; + } + lines[0] = ""; + } - /** - * This option suppresses warnings about the use of global strict mode. - * Global strict mode can break third-party widgets so it is not - * recommended. - * - * For more info about strict mode see the `strict` option. - * - * @deprecated Use `strict: "global"`. - */ - globalstrict: true, + this.emitter = new events.EventEmitter(); + this.source = source; + this.setLines(lines); + this.prereg = true; - /** - * This option prohibits the use of unary increment and decrement - * operators. Some people think that `++` and `--` reduces the quality of - * their coding styles and there are programming languages—such as - * Python—that go completely without these operators. - */ - plusplus : true, + this.line = 0; + this.char = 1; + this.from = 1; + this.input = ""; + this.inComment = false; + this.context = []; + this.templateStarts = []; - /** - * This option suppresses warnings about the `__proto__` property. - */ - proto : true, + for (var i = 0; i < state.option.indent; i += 1) { + state.tab += " "; + } +} - /** - * This option suppresses warnings about the use of script-targeted - * URLs—such as `javascript:...`. - */ - scripturl : true, +Lexer.prototype = { + _lines: [], - /** - * This option suppresses warnings about using `[]` notation when it can be - * expressed in dot notation: `person['name']` vs. `person.name`. - * - * @deprecated JSHint is limiting its scope to issues of code correctness. - * If you would like to enforce rules relating to code style, - * check out [the JSCS - * project](https://github.com/jscs-dev/node-jscs). - */ - sub : true, + inContext: function(ctxType) { + return this.context.length > 0 && this.context[this.context.length - 1].type === ctxType; + }, - /** - * This option suppresses warnings about "weird" constructions like - * `new function () { ... }` and `new Object;`. Such constructions are - * sometimes used to produce singletons in JavaScript: - * - * var singleton = new function() { - * var privateVar; - * - * this.publicMethod = function () {} - * this.publicMethod2 = function () {} - * }; - */ - supernew : true, + pushContext: function(ctxType) { + this.context.push({ type: ctxType }); + }, - /** - * This option suppresses most of the warnings about possibly unsafe line - * breakings in your code. It doesn't suppress warnings about comma-first - * coding style. To suppress those you have to use `laxcomma` (see below). - * - * @deprecated JSHint is limiting its scope to issues of code correctness. - * If you would like to enforce rules relating to code style, - * check out [the JSCS - * project](https://github.com/jscs-dev/node-jscs). - */ - laxbreak : true, + popContext: function() { + return this.context.pop(); + }, - /** - * This option suppresses warnings about comma-first coding style: - * - * var obj = { - * name: 'Anton' - * , handle: 'valueof' - * , role: 'SW Engineer' - * }; - * - * @deprecated JSHint is limiting its scope to issues of code correctness. - * If you would like to enforce rules relating to code style, - * check out [the JSCS - * project](https://github.com/jscs-dev/node-jscs). - */ - laxcomma : true, + currentContext: function() { + return this.context.length > 0 && this.context[this.context.length - 1]; + }, - /** - * This option suppresses warnings about possible strict violations when - * the code is running in strict mode and you use `this` in a - * non-constructor function. You should use this option—in a function scope - * only—when you are positive that your use of `this` is valid in the - * strict mode (for example, if you call your function using - * `Function.call`). - * - * **Note:** This option can be used only inside of a function scope. - * JSHint will fail with an error if you will try to set this option - * globally. - */ - validthis : true, + getLines: function() { + this._lines = state.lines; + return this._lines; + }, - /** - * This option suppresses warnings about the use of the `with` statement. - * The semantics of the `with` statement can cause confusion among - * developers and accidental definition of global variables. - * - * More info: - * - * * [with Statement Considered - * Harmful](http://yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/) - */ - withstmt : true, + setLines: function(val) { + this._lines = val; + state.lines = this._lines; + }, - /** - * This options tells JSHint that your code uses Mozilla JavaScript - * extensions. Unless you develop specifically for the Firefox web browser - * you don't need this option. - * - * More info: - * - * * [New in JavaScript - * 1.7](https://developer.mozilla.org/en-US/docs/JavaScript/New_in_JavaScript/1.7) - */ - moz : true, + /* + * Return the next i character without actually moving the + * char pointer. + */ + peek: function(i) { + return this.input.charAt(i || 0); + }, - /** - * This option suppresses warnings about generator functions with no - * `yield` statement in them. - */ - noyield : true, + /* + * Move the char pointer forward i times. + */ + skip: function(i) { + i = i || 1; + this.char += i; + this.input = this.input.slice(i); + }, - /** - * This option suppresses warnings about `== null` comparisons. Such - * comparisons are often useful when you want to check if a variable is - * `null` or `undefined`. - */ - eqnull : true, + /* + * Subscribe to a token event. The API for this method is similar + * Underscore.js i.e. you can subscribe to multiple events with + * one call: + * + * lex.on("Identifier Number", function(data) { + * // ... + * }); + */ + on: function(names, listener) { + names.split(" ").forEach(function(name) { + this.emitter.on(name, listener); + }.bind(this)); + }, - /** - * This option suppresses warnings about missing semicolons, but only when - * the semicolon is omitted for the last statement in a one-line block: - * - * var name = (function() { return 'Anton' }()); - * - * This is a very niche use case that is useful only when you use automatic - * JavaScript code generators. - */ - lastsemic : true, + /* + * Trigger a token event. All arguments will be passed to each + * listener. + */ + trigger: function() { + this.emitter.emit.apply(this.emitter, Array.prototype.slice.call(arguments)); + }, - /** - * This option suppresses warnings about functions inside of loops. - * Defining functions inside of loops can lead to bugs such as this one: - * - * var nums = []; - * - * for (var i = 0; i < 10; i++) { - * nums[i] = function (j) { - * return i + j; - * }; - * } - * - * nums[0](2); // Prints 12 instead of 2 - * - * To fix the code above you need to copy the value of `i`: - * - * var nums = []; - * - * for (var i = 0; i < 10; i++) { - * (function (i) { - * nums[i] = function (j) { - * return i + j; - * }; - * }(i)); - * } - */ - loopfunc : true, + /* + * Postpone a token event. the checking condition is set as + * last parameter, and the trigger function is called in a + * stored callback. To be later called using the check() function + * by the parser. This avoids parser's peek() to give the lexer + * a false context. + */ + triggerAsync: function(type, args, checks, fn) { + checks.push(function() { + if (fn()) { + this.trigger(type, args); + } + }.bind(this)); + }, - /** - * This option suppresses warnings about the use of expressions where - * normally you would expect to see assignments or function calls. Most of - * the time, such code is a typo. However, it is not forbidden by the spec - * and that's why this warning is optional. - */ - expr : true, + /* + * Extract a punctuator out of the next sequence of characters + * or return 'null' if its not possible. + * + * This method's implementation was heavily influenced by the + * scanPunctuator function in the Esprima parser's source code. + */ + scanPunctuator: function() { + var ch1 = this.peek(); + var ch2, ch3, ch4; - /** - * This option tells JSHint that your code uses ECMAScript 6 specific - * syntax. Note that these features are not finalized yet and not all - * browsers implement them. - * - * More info: - * - * * [Specification for ECMAScript - * 6](http://www.ecma-international.org/ecma-262/6.0/index.html) - * - * @deprecated Use `esversion: 6` instead. - */ - esnext : true, + switch (ch1) { + // Most common single-character punctuators + case ".": + if ((/^[0-9]$/).test(this.peek(1))) { + return null; + } + if (this.peek(1) === "." && this.peek(2) === ".") { + return { + type: Token.Punctuator, + value: "..." + }; + } + /* falls through */ + case "(": + case ")": + case ";": + case ",": + case "[": + case "]": + case ":": + case "~": + case "?": + return { + type: Token.Punctuator, + value: ch1 + }; - /** - * This option tells JSHint that your code uses ES3 array elision elements, - * or empty elements (for example, `[1, , , 4, , , 7]`). - */ - elision : true, - }, + // A block/object opener + case "{": + this.pushContext(Context.Block); + return { + type: Token.Punctuator, + value: ch1 + }; - // Third party globals - environments: { + // A block/object closer + case "}": + if (this.inContext(Context.Block)) { + this.popContext(); + } + return { + type: Token.Punctuator, + value: ch1 + }; - /** - * This option defines globals exposed by the - * [MooTools](http://mootools.net/) JavaScript framework. - */ - mootools : true, + // A pound sign (for Node shebangs) + case "#": + return { + type: Token.Punctuator, + value: ch1 + }; - /** - * This option defines globals exposed by - * [CouchDB](http://couchdb.apache.org/). CouchDB is a document-oriented - * database that can be queried and indexed in a MapReduce fashion using - * JavaScript. - */ - couch : true, + // We're at the end of input + case "": + return null; + } - /** - * This option defines globals exposed by [the Jasmine unit testing - * framework](https://jasmine.github.io/). - */ - jasmine : true, + // Peek more characters - /** - * This option defines globals exposed by the [jQuery](http://jquery.com/) - * JavaScript library. - */ - jquery : true, + ch2 = this.peek(1); + ch3 = this.peek(2); + ch4 = this.peek(3); - /** - * This option defines globals available when your code is running inside - * of the Node runtime environment. [Node.js](http://nodejs.org/) is a - * server-side JavaScript environment that uses an asynchronous - * event-driven model. This option also skips some warnings that make sense - * in the browser environments but don't make sense in Node such as - * file-level `use strict` pragmas and `console.log` statements. - */ - node : true, + // 4-character punctuator: >>>= - /** - * This option defines globals exposed by [the QUnit unit testing - * framework](http://qunitjs.com/). - */ - qunit : true, + if (ch1 === ">" && ch2 === ">" && ch3 === ">" && ch4 === "=") { + return { + type: Token.Punctuator, + value: ">>>=" + }; + } - /** - * This option defines globals available when your code is running inside - * of the Rhino runtime environment. [Rhino](http://www.mozilla.org/rhino/) - * is an open-source implementation of JavaScript written entirely in Java. - */ - rhino : true, + // 3-character punctuators: === !== >>> <<= >>= - /** - * This option defines globals exposed by [the ShellJS - * library](http://documentup.com/arturadib/shelljs). - */ - shelljs : true, + if (ch1 === "=" && ch2 === "=" && ch3 === "=") { + return { + type: Token.Punctuator, + value: "===" + }; + } - /** - * This option defines globals exposed by the - * [Prototype](http://www.prototypejs.org/) JavaScript framework. - */ - prototypejs : true, + if (ch1 === "!" && ch2 === "=" && ch3 === "=") { + return { + type: Token.Punctuator, + value: "!==" + }; + } - /** - * This option defines globals exposed by the [YUI](http://yuilibrary.com/) - * JavaScript framework. - */ - yui : true, + if (ch1 === ">" && ch2 === ">" && ch3 === ">") { + return { + type: Token.Punctuator, + value: ">>>" + }; + } - /** - * This option defines globals exposed by the "BDD" and "TDD" UIs of the - * [Mocha unit testing framework](http://mochajs.org/). - */ - mocha : true, + if (ch1 === "<" && ch2 === "<" && ch3 === "=") { + return { + type: Token.Punctuator, + value: "<<=" + }; + } - /** - * This option informs JSHint that the input code describes an ECMAScript 6 - * module. All module code is interpreted as strict mode code. - */ - module : true, + if (ch1 === ">" && ch2 === ">" && ch3 === "=") { + return { + type: Token.Punctuator, + value: ">>=" + }; + } - /** - * This option defines globals available when your code is running as a - * script for the [Windows Script - * Host](http://en.wikipedia.org/wiki/Windows_Script_Host). - */ - wsh : true, + // Fat arrow punctuator + if (ch1 === "=" && ch2 === ">") { + return { + type: Token.Punctuator, + value: ch1 + ch2 + }; + } - /** - * This option defines globals available when your code is running inside - * of a Web Worker. [Web - * Workers](https://developer.mozilla.org/en/Using_web_workers) provide a - * simple means for web content to run scripts in background threads. - */ - worker : true, + // 2-character punctuators: ++ -- << >> && || ** + if (ch1 === ch2 && ("+-<>&|*".indexOf(ch1) >= 0)) { + if (ch1 === "*" && ch3 === "=") { + return { + type: Token.Punctuator, + value: ch1 + ch2 + ch3 + }; + } - /** - * This option defines non-standard but widely adopted globals such as - * `escape` and `unescape`. - */ - nonstandard : true, - - /** - * This option defines globals exposed by modern browsers: all the way from - * good old `document` and `navigator` to the HTML5 `FileReader` and other - * new developments in the browser world. - * - * **Note:** This option doesn't expose variables like `alert` or - * `console`. See option `devel` for more information. - */ - browser : true, - - /** - * This option defines globals available when using [the Browserify - * tool](http://browserify.org/) to build a project. - */ - browserify : true, - - /** - * This option defines globals that are usually used for logging poor-man's - * debugging: `console`, `alert`, etc. It is usually a good idea to not - * ship them in production because, for example, `console.log` breaks in - * legacy versions of Internet Explorer. - */ - devel : true, + return { + type: Token.Punctuator, + value: ch1 + ch2 + }; + } - /** - * This option defines globals exposed by the [Dojo - * Toolkit](http://dojotoolkit.org/). - */ - dojo : true, + // <= >= != += -= *= %= &= |= ^= /= + if ("<>=!+-*%&|^/".indexOf(ch1) >= 0) { + if (ch2 === "=") { + return { + type: Token.Punctuator, + value: ch1 + ch2 + }; + } - /** - * This option defines globals for typed array constructors. - * - * More info: - * - * * [JavaScript typed - * arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays) - */ - typed : true, + return { + type: Token.Punctuator, + value: ch1 + }; + } - /** - * This option defines globals available when your core is running inside - * of the PhantomJS runtime environment. [PhantomJS](http://phantomjs.org/) - * is a headless WebKit scriptable with a JavaScript API. It has fast and - * native support for various web standards: DOM handling, CSS selector, - * JSON, Canvas, and SVG. - */ - phantom : true + return null; }, - // Obsolete options - obsolete: { - onecase : true, // if one case switch statements should be allowed - regexp : true, // if the . should not be allowed in regexp literals - regexdash : true // if unescaped first/last dash (-) inside brackets - // should be tolerated - } -}; - -// These are the JSHint options that can take any value -// (we use this object to detect invalid options) -exports.val = { - - /** - * This option lets you set the maximum length of a line. - * - * @deprecated JSHint is limiting its scope to issues of code correctness. If - * you would like to enforce rules relating to code style, check - * out [the JSCS project](https://github.com/jscs-dev/node-jscs). - */ - maxlen : false, - - /** - * This option sets a specific tab width for your code. + /* + * Extract a comment out of the next sequence of characters and/or + * lines or return 'null' if its not possible. Since comments can + * span across multiple lines this method has to move the char + * pointer. * - * @deprecated JSHint is limiting its scope to issues of code correctness. If - * you would like to enforce rules relating to code style, check - * out [the JSCS project](https://github.com/jscs-dev/node-jscs). + * In addition to normal JavaScript comments (// and /*) this method + * also recognizes JSHint- and JSLint-specific comments such as + * /*jshint, /*jslint, /*globals and so on. */ - indent : false, + scanComments: function(checks) { + var ch1 = this.peek(); + var ch2 = this.peek(1); + var rest = this.input.substr(2); + var startLine = this.line; + var startChar = this.char; + var self = this; - /** - * This options allows you to set the maximum amount of warnings JSHint will - * produce before giving up. Default is 50. - */ - maxerr : false, + // Create a comment token object and make sure it + // has all the data JSHint needs to work with special + // comments. - /** - * This option allows you to control which variables JSHint considers to be - * implicitly defined in the environment. Configure it with an array of - * string values. Prefixing a variable name with a hyphen (-) character will - * remove that name from the collection of predefined variables. - * - * JSHint will consider variables declared in this way to be read-only. - * - * This option cannot be specified in-line; it may only be used via the - * JavaScript API or from an external configuration file. - */ - predef : false, + function commentToken(label, body, opt) { + var special = [ + "jshint", "jshint.unstable", "jslint", "members", "member", "globals", + "global", "exported" + ]; + var isSpecial = false; + var value = label + body; + var commentType = "plain"; + opt = opt || {}; - /** - * This option can be used to specify a white list of global variables that - * are not formally defined in the source code. This is most useful when - * combined with the `undef` option in order to suppress warnings for - * project-specific global variables. - * - * Setting an entry to `true` enables reading and writing to that variable. - * Setting it to `false` will trigger JSHint to consider that variable - * read-only. - * - * See also the "environment" options: a set of options to be used as short - * hand for enabling global variables defined in common JavaScript - * environments. - * - * To configure `globals` within an individual file, see [Inline - * Configuration](http://jshint.com/docs/#inline-configuration). - */ - globals : false, + if (opt.isMultiline) { + value += "*/"; + } - /** - * This option enforces the consistency of quotation marks used throughout - * your code. It accepts three values: `true` if you don't want to enforce - * one particular style but want some consistency, `"single"` if you want to - * allow only single quotes and `"double"` if you want to allow only double - * quotes. - * - * @deprecated JSHint is limiting its scope to issues of code correctness. If - * you would like to enforce rules relating to code style, check - * out [the JSCS project](https://github.com/jscs-dev/node-jscs). - */ - quotmark : false, + body = body.replace(/\n/g, " "); - scope : false, + if (label === "/*" && reg.fallsThrough.test(body)) { + isSpecial = true; + commentType = "falls through"; + } - /** - * This option lets you set the max number of statements allowed per function: - * - * // jshint maxstatements:4 - * - * function main() { - * var i = 0; - * var j = 0; - * - * // Function declarations count as one statement. Their bodies - * // don't get taken into account for the outer function. - * function inner() { - * var i2 = 1; - * var j2 = 1; - * - * return i2 + j2; - * } - * - * j = i + j; - * return j; // JSHint: Too many statements per function. (5) - * } - */ - maxstatements: false, + special.forEach(function(str) { + if (isSpecial) { + return; + } - /** - * This option lets you control how nested do you want your blocks to be: - * - * // jshint maxdepth:2 - * - * function main(meaning) { - * var day = true; - * - * if (meaning === 42) { - * while (day) { - * shuffle(); - * - * if (tired) { // JSHint: Blocks are nested too deeply (3). - * sleep(); - * } - * } - * } - * } - */ - maxdepth : false, + // Don't recognize any special comments other than jshint for single-line + // comments. This introduced many problems with legit comments. + if (label === "//" && str !== "jshint" && str !== "jshint.unstable") { + return; + } - /** - * This option lets you set the max number of formal parameters allowed per - * function: - * - * // jshint maxparams:3 - * - * function login(request, onSuccess) { - * // ... - * } - * - * // JSHint: Too many parameters per function (4). - * function logout(request, isManual, whereAmI, onSuccess) { - * // ... - * } - */ - maxparams : false, + if (body.charAt(str.length) === " " && body.substr(0, str.length) === str) { + isSpecial = true; + label = label + str; + body = body.substr(str.length); + } - /** - * This option lets you control cyclomatic complexity throughout your code. - * Cyclomatic complexity measures the number of linearly independent paths - * through a program's source code. Read more about [cyclomatic complexity on - * Wikipedia](http://en.wikipedia.org/wiki/Cyclomatic_complexity). - */ - maxcomplexity: false, + if (!isSpecial && body.charAt(0) === " " && body.charAt(str.length + 1) === " " && + body.substr(1, str.length) === str) { + isSpecial = true; + label = label + " " + str; + body = body.substr(str.length + 1); + } - /** - * This option suppresses warnings about variable shadowing i.e. declaring a - * variable that had been already declared somewhere in the outer scope. - * - * - "inner" - check for variables defined in the same scope only - * - "outer" - check for variables defined in outer scopes as well - * - false - same as inner - * - true - allow variable shadowing - */ - shadow : false, + // To handle rarer case when special word is separated from label by + // multiple spaces or tabs + var strIndex = body.indexOf(str); + if (!isSpecial && strIndex >= 0 && body.charAt(strIndex + str.length) === " ") { + var isAllWhitespace = body.substr(0, strIndex).trim().length === 0; + if (isAllWhitespace) { + isSpecial = true; + body = body.substr(str.length + strIndex); + } + } - /** - * This option requires the code to run in ECMAScript 5's strict mode. - * [Strict mode](https://developer.mozilla.org/en/JavaScript/Strict_mode) - * is a way to opt in to a restricted variant of JavaScript. Strict mode - * eliminates some JavaScript pitfalls that didn't cause errors by changing - * them to produce errors. It also fixes mistakes that made it difficult - * for the JavaScript engines to perform certain optimizations. - * - * - "func" - there must be a `"use strict";` directive at function level - * - "global" - there must be a `"use strict";` directive at global level - * - "implied" - lint the code as if there is the `"use strict";` directive - * - false - disable warnings about strict mode - * - true - same as `"func"`, but environment options have precedence over - * this (e.g. `node`, `module`, `browserify` and `phantomjs` can - * set `strict: global`) - */ - strict : true, + if (!isSpecial) { + return; + } - /** - * This option warns when you define and never use your variables. It is very - * useful for general code cleanup, especially when used in addition to - * `undef`. - * - * // jshint unused:true - * - * function test(a, b) { - * var c, d = 2; - * - * return a + d; - * } - * - * test(1, 2); - * - * // Line 3: 'b' was defined but never used. - * // Line 4: 'c' was defined but never used. - * - * In addition to that, this option will warn you about unused global - * variables declared via the `global` directive. - * - * This can be set to `vars` to only check for variables, not function - * parameters, or `strict` to check all variables and parameters. The - * default (true) behavior is to allow unused parameters that are followed by - * a used parameter. - */ - unused : true, + switch (str) { + case "member": + commentType = "members"; + break; + case "global": + commentType = "globals"; + break; + default: + var options = body.split(":").map(function(v) { + return v.replace(/^\s+/, "").replace(/\s+$/, ""); + }); - /** - * This option prohibits the use of a variable before it was defined. - * JavaScript has function scope only and, in addition to that, all variables - * are always moved—or hoisted— to the top of the function. This behavior can - * lead to some very nasty bugs and that's why it is safer to always use - * variable only after they have been explicitly defined. - * - * Setting this option to "nofunc" will allow function declarations to be - * ignored. - * - * For more in-depth understanding of scoping and hoisting in JavaScript, - * read [JavaScript Scoping and - * Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) - * by Ben Cherry. - */ - latedef : false, + if (options.length === 2) { + switch (options[0]) { + case "ignore": + switch (options[1]) { + case "start": + self.ignoringLinterErrors = true; + isSpecial = false; + break; + case "end": + self.ignoringLinterErrors = false; + isSpecial = false; + break; + } + } + } - ignore : false, // start/end ignoring lines of code, bypassing the lexer - // start - start ignoring lines, including the current line - // end - stop ignoring lines, starting on the next line - // line - ignore warnings / errors for just a single line - // (this option does not bypass the lexer) + commentType = str; + } + }); - ignoreDelimiters: false, // array of start/end delimiters used to ignore - // certain chunks from code + return { + type: Token.Comment, + commentType: commentType, + value: value, + body: body, + isSpecial: isSpecial, + isMalformed: opt.isMalformed || false + }; + } - /** - * This option is used to specify the ECMAScript version to which the code - * must adhere. It can assume one of the following values: - * - `3` - If you need your program to be executable - * in older browsers—such as Internet Explorer 6/7/8/9—and other legacy - * JavaScript environments - * - `5` - To enable syntax first defined in [the ECMAScript 5.1 - * specification](http://www.ecma-international.org/ecma-262/5.1/index.html). - * This includes allowing reserved keywords as object properties. - * - `6` - To tell JSHint that your code uses [ECMAScript - * 6](http://www.ecma-international.org/ecma-262/6.0/index.html) specific - * syntax. Note that not all browsers implement them. - */ - esversion: 5 -}; + // End of unbegun comment. Raise an error and skip that input. + if (ch1 === "*" && ch2 === "/") { + this.trigger("error", { + code: "E018", + line: startLine, + character: startChar + }); -// These are JSHint boolean options which are shared with JSLint -// where the definition in JSHint is opposite JSLint -exports.inverted = { - bitwise : true, - forin : true, - newcap : true, - plusplus: true, - regexp : true, - undef : true, + this.skip(2); + return null; + } - // Inverted and renamed, use JSHint name here - eqeqeq : true, - strict : true -}; + // Comments must start either with // or /* + if (ch1 !== "/" || (ch2 !== "*" && ch2 !== "/")) { + return null; + } -exports.validNames = Object.keys(exports.val) - .concat(Object.keys(exports.bool.relaxing)) - .concat(Object.keys(exports.bool.enforcing)) - .concat(Object.keys(exports.bool.obsolete)) - .concat(Object.keys(exports.bool.environments)); + // One-line comment + if (ch2 === "/") { + this.skip(this.input.length); // Skip to the EOL. + return commentToken("//", rest); + } -// These are JSHint boolean options which are shared with JSLint -// where the name has been changed but the effect is unchanged -exports.renamed = { - eqeq : "eqeqeq", - windows: "wsh", - sloppy : "strict" -}; + var body = ""; -exports.removed = { - nomen: true, - onevar: true, - passfail: true, - white: true, - gcl: true, - smarttabs: true, - trailing: true -}; + /* Multi-line comment */ + if (ch2 === "*") { + this.inComment = true; + this.skip(2); -// Add options here which should not be automatically enforced by -// `enforceall`. -exports.noenforceall = { - varstmt: true, - strict: true -}; + while (this.peek() !== "*" || this.peek(1) !== "/") { + if (this.peek() === "") { // End of Line + body += "\n"; -},{}],"/node_modules/jshint/src/reg.js":[function(_dereq_,module,exports){ -/* - * Regular expressions. Some of these are stupidly long. - */ + // If we hit EOF and our comment is still unclosed, + // trigger an error and end the comment implicitly. + if (!this.nextLine(checks)) { + this.trigger("error", { + code: "E017", + line: startLine, + character: startChar + }); -/*jshint maxlen:1000 */ + this.inComment = false; + return commentToken("/*", body, { + isMultiline: true, + isMalformed: true + }); + } + } else { + body += this.peek(); + this.skip(); + } + } -"use strict"; + this.skip(2); + this.inComment = false; + return commentToken("/*", body, { isMultiline: true }); + } + }, -// Unsafe comment or string (ax) -exports.unsafeString = - /@cc|<\/?|script|\]\s*\]|<\s*!|</i; + /* + * Extract a keyword out of the next sequence of characters or + * return 'null' if its not possible. + */ + scanKeyword: function() { + var result = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input); + var keywords = [ + "if", "in", "do", "var", "for", "new", + "try", "let", "this", "else", "case", + "void", "with", "enum", "while", "break", + "catch", "throw", "const", "yield", "class", + "super", "return", "typeof", "delete", + "switch", "export", "import", "default", + "finally", "extends", "function", "continue", + "debugger", "instanceof", "true", "false", "null", "async", "await" + ]; -// Unsafe characters that are silently deleted by one or more browsers (cx) -exports.unsafeChars = - /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; + if (result && keywords.indexOf(result[0]) >= 0) { + return { + type: Token.Keyword, + value: result[0] + }; + } -// Characters in strings that need escaping (nx and nxg) -exports.needEsc = - /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; + return null; + }, -exports.needEscGlobal = - /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + /* + * Extract a JavaScript identifier out of the next sequence of + * characters or return 'null' if its not possible. + */ + scanIdentifier: function(checks) { + var id = ""; + var index = 0; + var char, value; -// Star slash (lx) -exports.starSlash = /\*\//; - -// Identifier (ix) -exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; - -// JavaScript URL (jx) -exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i; - -// Catches /* falls through */ comments (ft) -exports.fallsThrough = /^\s*falls?\sthrough\s*$/; - -// very conservative rule (eg: only one space between the start of the comment and the first character) -// to relax the maxlen option -exports.maxlenException = /^(?:(?:\/\/|\/\*|\*) ?)?[^ ]+$/; + function isNonAsciiIdentifierStart(code) { + return nonAsciiIdentifierStartTable.indexOf(code) > -1; + } -},{}],"/node_modules/jshint/src/scope-manager.js":[function(_dereq_,module,exports){ -"use strict"; + function isNonAsciiIdentifierPart(code) { + return isNonAsciiIdentifierStart(code) || nonAsciiIdentifierPartTable.indexOf(code) > -1; + } -var _ = _dereq_("../lodash"); -var events = _dereq_("events"); + var readUnicodeEscapeSequence = function() { + /*jshint validthis:true */ + index += 1; -// Used to denote membership in lookup tables (a primitive value such as `true` -// would be silently rejected for the property name "__proto__" in some -// environments) -var marker = {}; + if (this.peek(index) !== "u") { + return null; + } -/** - * Creates a scope manager that handles variables and labels, storing usages - * and resolving when variables are used and undefined - */ -var scopeManager = function(state, predefined, exported, declared) { + var sequence = this.peek(index + 1) + this.peek(index + 2) + + this.peek(index + 3) + this.peek(index + 4); + var code; - var _current; - var _scopeStack = []; + if (isHex(sequence)) { + code = parseInt(sequence, 16); - function _newScope(type) { - _current = { - "(labels)": Object.create(null), - "(usages)": Object.create(null), - "(breakLabels)": Object.create(null), - "(parent)": _current, - "(type)": type, - "(params)": (type === "functionparams" || type === "catchparams") ? [] : null - }; - _scopeStack.push(_current); - } + if (asciiIdentifierPartTable[code] || isNonAsciiIdentifierPart(code)) { + index += 5; + return "\\u" + sequence; + } - _newScope("global"); - _current["(predefined)"] = predefined; + return null; + } - var _currentFunctBody = _current; // this is the block after the params = function + return null; + }.bind(this); - var usedPredefinedAndGlobals = Object.create(null); - var impliedGlobals = Object.create(null); - var unuseds = []; - var emitter = new events.EventEmitter(); + var getIdentifierStart = function() { + /*jshint validthis:true */ + var chr = this.peek(index); + var code = chr.charCodeAt(0); - function warning(code, token) { - emitter.emit("warning", { - code: code, - token: token, - data: _.slice(arguments, 2) - }); - } + if (code === 92) { + return readUnicodeEscapeSequence(); + } - function error(code, token) { - emitter.emit("warning", { - code: code, - token: token, - data: _.slice(arguments, 2) - }); - } + if (code < 128) { + if (asciiIdentifierStartTable[code]) { + index += 1; + return chr; + } - function _setupUsages(labelName) { - if (!_current["(usages)"][labelName]) { - _current["(usages)"][labelName] = { - "(modified)": [], - "(reassigned)": [], - "(tokens)": [] - }; - } - } + return null; + } - var _getUnusedOption = function(unused_opt) { - if (unused_opt === undefined) { - unused_opt = state.option.unused; - } + if (isNonAsciiIdentifierStart(code)) { + index += 1; + return chr; + } - if (unused_opt === true) { - unused_opt = "last-param"; - } + return null; + }.bind(this); - return unused_opt; - }; + var getIdentifierPart = function() { + /*jshint validthis:true */ + var chr = this.peek(index); + var code = chr.charCodeAt(0); - var _warnUnused = function(name, tkn, type, unused_opt) { - var line = tkn.line; - var chr = tkn.from; - var raw_name = tkn.raw_text || name; + if (code === 92) { + return readUnicodeEscapeSequence(); + } - unused_opt = _getUnusedOption(unused_opt); + if (code < 128) { + if (asciiIdentifierPartTable[code]) { + index += 1; + return chr; + } - var warnable_types = { - "vars": ["var"], - "last-param": ["var", "param"], - "strict": ["var", "param", "last-param"] - }; + return null; + } - if (unused_opt) { - if (warnable_types[unused_opt] && warnable_types[unused_opt].indexOf(type) !== -1) { - warning("W098", { line: line, from: chr }, raw_name); + if (isNonAsciiIdentifierPart(code)) { + index += 1; + return chr; } - } - // inconsistent - see gh-1894 - if (unused_opt || type === "var") { - unuseds.push({ - name: name, - line: line, - character: chr + return null; + }.bind(this); + + function removeEscapeSequences(id) { + return id.replace(/\\u([0-9a-fA-F]{4})/g, function(m0, codepoint) { + return String.fromCharCode(parseInt(codepoint, 16)); }); } - }; - /** - * Checks the current scope for unused identifiers - */ - function _checkForUnused() { - // function params are handled specially - // assume that parameters are the only thing declared in the param scope - if (_current["(type)"] === "functionparams") { - _checkParams(); - return; - } - var curentLabels = _current["(labels)"]; - for (var labelName in curentLabels) { - if (curentLabels[labelName]) { - if (curentLabels[labelName]["(type)"] !== "exception" && - curentLabels[labelName]["(unused)"]) { - _warnUnused(labelName, curentLabels[labelName]["(token)"], "var"); - } - } + char = getIdentifierStart(); + if (char === null) { + return null; } - } - /** - * Checks the current scope for unused parameters - * Must be called in a function parameter scope - */ - function _checkParams() { - var params = _current["(params)"]; - - if (!params) { - return; - } + id = char; + for (;;) { + char = getIdentifierPart(); - var param = params.pop(); - var unused_opt; + if (char === null) { + break; + } - while (param) { - var label = _current["(labels)"][param]; + id += char; + } - unused_opt = _getUnusedOption(state.funct["(unusedOption)"]); + value = removeEscapeSequences(id); - // 'undefined' is a special case for (function(window, undefined) { ... })(); - // patterns. - if (param === "undefined") - return; + if (!state.inES6(true)) { + es5IdentifierNames = _dereq_("../data/es5-identifier-names.js"); - if (label["(unused)"]) { - _warnUnused(param, label["(token)"], "param", state.funct["(unusedOption)"]); - } else if (unused_opt === "last-param") { - return; + if (!es5IdentifierNames.test(value)) { + this.triggerAsync( + "warning", + { + code: "W119", + line: this.line, + character: this.char, + data: ["unicode 8", "6"] + }, + checks, + function() { return true; } + ); } - - param = params.pop(); } - } - /** - * Finds the relevant label's scope, searching from nearest outwards - * @returns {Object} the scope the label was found in + return { + type: Token.Identifier, + value: value, + text: id, + tokenLength: id.length + }; + }, + + /* + * Extract a numeric literal out of the next sequence of + * characters or return 'null' if its not possible. This method + * supports all numeric literals described in section 7.8.3 + * of the EcmaScript 5 specification. + * + * This method's implementation was heavily influenced by the + * scanNumericLiteral function in the Esprima parser's source code. */ - function _getLabel(labelName) { - for (var i = _scopeStack.length - 1 ; i >= 0; --i) { - var scopeLabels = _scopeStack[i]["(labels)"]; - if (scopeLabels[labelName]) { - return scopeLabels; - } + scanNumericLiteral: function(checks) { + var index = 0; + var value = ""; + var length = this.input.length; + var char = this.peek(index); + var isAllowedDigit = isDecimalDigit; + var base = 10; + var isLegacy = false; + + function isDecimalDigit(str) { + return (/^[0-9]$/).test(str); } - } - function usedSoFarInCurrentFunction(labelName) { - // used so far in this whole function and any sub functions - for (var i = _scopeStack.length - 1; i >= 0; i--) { - var current = _scopeStack[i]; - if (current["(usages)"][labelName]) { - return current["(usages)"][labelName]; - } - if (current === _currentFunctBody) { - break; - } + function isOctalDigit(str) { + return (/^[0-7]$/).test(str); } - return false; - } - function _checkOuterShadow(labelName, token) { + function isBinaryDigit(str) { + return (/^[01]$/).test(str); + } - // only check if shadow is outer - if (state.option.shadow !== "outer") { - return; + function isIdentifierStart(ch) { + return (ch === "$") || (ch === "_") || (ch === "\\") || + (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z"); } - var isGlobal = _currentFunctBody["(type)"] === "global", - isNewFunction = _current["(type)"] === "functionparams"; + // Numbers must start either with a decimal digit or a point. - var outsideCurrentFunction = !isGlobal; - for (var i = 0; i < _scopeStack.length; i++) { - var stackItem = _scopeStack[i]; + if (char !== "." && !isDecimalDigit(char)) { + return null; + } - if (!isNewFunction && _scopeStack[i + 1] === _currentFunctBody) { - outsideCurrentFunction = false; - } - if (outsideCurrentFunction && stackItem["(labels)"][labelName]) { - warning("W123", token, labelName); - } - if (stackItem["(breakLabels)"][labelName]) { - warning("W123", token, labelName); - } - } - } - - function _latedefWarning(type, labelName, token) { - if (state.option.latedef) { - // if either latedef is strict and this is a function - // or this is not a function - if ((state.option.latedef === true && type === "function") || - type !== "function") { - warning("W003", token, labelName); - } - } - } - - var scopeManagerInst = { - - on: function(names, listener) { - names.split(" ").forEach(function(name) { - emitter.on(name, listener); - }); - }, - - isPredefined: function(labelName) { - return !this.has(labelName) && _.has(_scopeStack[0]["(predefined)"], labelName); - }, - - /** - * Tell the manager we are entering a new block of code - * @param {string} [type] - The type of the block. Valid values are - * "functionparams", "catchparams" and - * "functionouter" - */ - stack: function(type) { - var previousScope = _current; - _newScope(type); - - if (!type && previousScope["(type)"] === "functionparams") { - - _current["(isFuncBody)"] = true; - _current["(context)"] = _currentFunctBody; - _currentFunctBody = _current; - } - }, - - unstack: function() { - // jshint proto: true - var subScope = _scopeStack.length > 1 ? _scopeStack[_scopeStack.length - 2] : null; - var isUnstackingFunctionBody = _current === _currentFunctBody, - isUnstackingFunctionParams = _current["(type)"] === "functionparams", - isUnstackingFunctionOuter = _current["(type)"] === "functionouter"; - - var i, j; - var currentUsages = _current["(usages)"]; - var currentLabels = _current["(labels)"]; - var usedLabelNameList = Object.keys(currentUsages); - - if (currentUsages.__proto__ && usedLabelNameList.indexOf("__proto__") === -1) { - usedLabelNameList.push("__proto__"); - } - - for (i = 0; i < usedLabelNameList.length; i++) { - var usedLabelName = usedLabelNameList[i]; + if (char !== ".") { + value = this.peek(index); + index += 1; + char = this.peek(index); - var usage = currentUsages[usedLabelName]; - var usedLabel = currentLabels[usedLabelName]; - if (usedLabel) { - var usedLabelType = usedLabel["(type)"]; + if (value === "0") { + // Base-16 numbers. + if (char === "x" || char === "X") { + isAllowedDigit = isHexDigit; + base = 16; - if (usedLabel["(useOutsideOfScope)"] && !state.option.funcscope) { - var usedTokens = usage["(tokens)"]; - if (usedTokens) { - for (j = 0; j < usedTokens.length; j++) { - // Keep the consistency of https://github.com/jshint/jshint/issues/2409 - if (usedLabel["(function)"] === usedTokens[j]["(function)"]) { - error("W038", usedTokens[j], usedLabelName); - } - } - } - } + index += 1; + value += char; + } - // mark the label used - _current["(labels)"][usedLabelName]["(unused)"] = false; + // Base-8 numbers. + if (char === "o" || char === "O") { + isAllowedDigit = isOctalDigit; + base = 8; - // check for modifying a const - if (usedLabelType === "const" && usage["(modified)"]) { - for (j = 0; j < usage["(modified)"].length; j++) { - error("E013", usage["(modified)"][j], usedLabelName); - } + if (!state.inES6(true)) { + this.triggerAsync( + "warning", + { + code: "W119", + line: this.line, + character: this.char, + data: [ "Octal integer literal", "6" ] + }, + checks, + function() { return true; } + ); } - // check for re-assigning a function declaration - if ((usedLabelType === "function" || usedLabelType === "class") && - usage["(reassigned)"]) { - for (j = 0; j < usage["(reassigned)"].length; j++) { - error("W021", usage["(reassigned)"][j], usedLabelName, usedLabelType); - } - } - continue; + index += 1; + value += char; } - if (isUnstackingFunctionOuter) { - state.funct["(isCapturing)"] = true; - } + // Base-2 numbers. + if (char === "b" || char === "B") { + isAllowedDigit = isBinaryDigit; + base = 2; - if (subScope) { - // not exiting the global scope, so copy the usage down in case its an out of scope usage - if (!subScope["(usages)"][usedLabelName]) { - subScope["(usages)"][usedLabelName] = usage; - if (isUnstackingFunctionBody) { - subScope["(usages)"][usedLabelName]["(onlyUsedSubFunction)"] = true; - } - } else { - var subScopeUsage = subScope["(usages)"][usedLabelName]; - subScopeUsage["(modified)"] = subScopeUsage["(modified)"].concat(usage["(modified)"]); - subScopeUsage["(tokens)"] = subScopeUsage["(tokens)"].concat(usage["(tokens)"]); - subScopeUsage["(reassigned)"] = - subScopeUsage["(reassigned)"].concat(usage["(reassigned)"]); - subScopeUsage["(onlyUsedSubFunction)"] = false; + if (!state.inES6(true)) { + this.triggerAsync( + "warning", + { + code: "W119", + line: this.line, + character: this.char, + data: [ "Binary integer literal", "6" ] + }, + checks, + function() { return true; } + ); } - } else { - // this is exiting global scope, so we finalise everything here - we are at the end of the file - if (typeof _current["(predefined)"][usedLabelName] === "boolean") { - // remove the declared token, so we know it is used - delete declared[usedLabelName]; + index += 1; + value += char; + } - // note it as used so it can be reported - usedPredefinedAndGlobals[usedLabelName] = marker; + // Legacy base-8 numbers. + if (isOctalDigit(char)) { + isAllowedDigit = isOctalDigit; + base = 8; + isLegacy = true; - // check for re-assigning a read-only (set to false) predefined - if (_current["(predefined)"][usedLabelName] === false && usage["(reassigned)"]) { - for (j = 0; j < usage["(reassigned)"].length; j++) { - warning("W020", usage["(reassigned)"][j]); - } - } - } - else { - // label usage is not predefined and we have not found a declaration - // so report as undeclared - if (usage["(tokens)"]) { - for (j = 0; j < usage["(tokens)"].length; j++) { - var undefinedToken = usage["(tokens)"][j]; - // if its not a forgiven undefined (e.g. typof x) - if (!undefinedToken.forgiveUndef) { - // if undef is on and undef was on when the token was defined - if (state.option.undef && !undefinedToken.ignoreUndef) { - warning("W117", undefinedToken, usedLabelName); - } - if (impliedGlobals[usedLabelName]) { - impliedGlobals[usedLabelName].line.push(undefinedToken.line); - } else { - impliedGlobals[usedLabelName] = { - name: usedLabelName, - line: [undefinedToken.line] - }; - } - } - } - } - } + index += 1; + value += char; } - } - // if exiting the global scope, we can warn about declared globals that haven't been used yet - if (!subScope) { - Object.keys(declared) - .forEach(function(labelNotUsed) { - _warnUnused(labelNotUsed, declared[labelNotUsed], "var"); - }); - } + // Decimal numbers that start with '0' such as '09' are illegal + // but we still parse them and return as malformed. - // if we have a sub scope we can copy too and we are still within the function boundary - if (subScope && !isUnstackingFunctionBody && - !isUnstackingFunctionParams && !isUnstackingFunctionOuter) { - var labelNames = Object.keys(currentLabels); - for (i = 0; i < labelNames.length; i++) { - - var defLabelName = labelNames[i]; - - // if its function scoped and - // not already defined (caught with shadow, shouldn't also trigger out of scope) - if (!currentLabels[defLabelName]["(blockscoped)"] && - currentLabels[defLabelName]["(type)"] !== "exception" && - !this.funct.has(defLabelName, { excludeCurrent: true })) { - subScope["(labels)"][defLabelName] = currentLabels[defLabelName]; - // we do not warn about out of scope usages in the global scope - if (_currentFunctBody["(type)"] !== "global") { - subScope["(labels)"][defLabelName]["(useOutsideOfScope)"] = true; - } - delete currentLabels[defLabelName]; - } + if (!isOctalDigit(char) && isDecimalDigit(char)) { + index += 1; + value += char; } } - _checkForUnused(); + while (index < length) { + char = this.peek(index); - _scopeStack.pop(); - if (isUnstackingFunctionBody) { - _currentFunctBody = _scopeStack[_.findLastIndex(_scopeStack, function(scope) { - // if function or if global (which is at the bottom so it will only return true if we call back) - return scope["(isFuncBody)"] || scope["(type)"] === "global"; - })]; + // Numbers like '019' (note the 9) are not valid octals + // but we still parse them and mark as malformed. + if (!(isLegacy && isDecimalDigit(char)) && !isAllowedDigit(char)) { + break; + } + value += char; + index += 1; } - _current = subScope; - }, + var isBigInt = this.peek(index) === 'n'; + + if (isAllowedDigit !== isDecimalDigit || isBigInt) { + if (isBigInt) { + if (!state.option.unstable.bigint) { + this.triggerAsync( + "warning", + { + code: "W144", + line: this.line, + character: this.char, + data: [ "BigInt", "bigint" ] + }, + checks, + function() { return true; } + ); + } - /** - * Add a param to the current scope - * @param {string} labelName - * @param {Token} token - * @param {string} [type="param"] param type - */ - addParam: function(labelName, token, type) { - type = type || "param"; + value += char; + index += 1; + } else if (!isLegacy && value.length <= 2) { // 0x + return { + type: Token.NumericLiteral, + value: value, + isMalformed: true + }; + } - if (type === "exception") { - // if defined in the current function - var previouslyDefinedLabelType = this.funct.labeltype(labelName); - if (previouslyDefinedLabelType && previouslyDefinedLabelType !== "exception") { - // and has not been used yet in the current function scope - if (!state.option.node) { - warning("W002", state.tokens.next, labelName); + if (index < length) { + char = this.peek(index); + if (isIdentifierStart(char)) { + return null; } } - } - - // The variable was declared in the current scope - if (_.has(_current["(labels)"], labelName)) { - _current["(labels)"][labelName].duplicated = true; - // The variable was declared in an outer scope - } else { - // if this scope has the variable defined, it's a re-definition error - _checkOuterShadow(labelName, token, type); + return { + type: Token.NumericLiteral, + value: value, + base: base, + isLegacy: isLegacy, + isMalformed: false + }; + } + } - _current["(labels)"][labelName] = { - "(type)" : type, - "(token)": token, - "(unused)": true }; + // Decimal digits. - _current["(params)"].push(labelName); - } + if (char === ".") { + value += char; + index += 1; - if (_.has(_current["(usages)"], labelName)) { - var usage = _current["(usages)"][labelName]; - // if its in a sub function it is not necessarily an error, just latedef - if (usage["(onlyUsedSubFunction)"]) { - _latedefWarning(type, labelName, token); - } else { - // this is a clear illegal usage for block scoped variables - warning("E056", token, labelName, type); + while (index < length) { + char = this.peek(index); + if (!isDecimalDigit(char)) { + break; } + value += char; + index += 1; } - }, + } - validateParams: function() { - // This method only concerns errors for function parameters - if (_currentFunctBody["(type)"] === "global") { - return; - } + // Exponent part. - var isStrict = state.isStrict(); - var currentFunctParamScope = _currentFunctBody["(parent)"]; + if (char === "e" || char === "E") { + value += char; + index += 1; + char = this.peek(index); - if (!currentFunctParamScope["(params)"]) { - return; + if (char === "+" || char === "-") { + value += this.peek(index); + index += 1; } - currentFunctParamScope["(params)"].forEach(function(labelName) { - var label = currentFunctParamScope["(labels)"][labelName]; + char = this.peek(index); + if (isDecimalDigit(char)) { + value += char; + index += 1; - if (label && label.duplicated) { - if (isStrict) { - warning("E011", label["(token)"], labelName); - } else if (state.option.shadow !== true) { - warning("W004", label["(token)"], labelName); + while (index < length) { + char = this.peek(index); + if (!isDecimalDigit(char)) { + break; } + value += char; + index += 1; } - }); - }, - - getUsedOrDefinedGlobals: function() { - // jshint proto: true - var list = Object.keys(usedPredefinedAndGlobals); + } else { + return null; + } + } - // If `__proto__` is used as a global variable name, its entry in the - // lookup table may not be enumerated by `Object.keys` (depending on the - // environment). - if (usedPredefinedAndGlobals.__proto__ === marker && - list.indexOf("__proto__") === -1) { - list.push("__proto__"); + if (index < length) { + char = this.peek(index); + if (isIdentifierStart(char)) { + return null; } + } - return list; - }, + return { + type: Token.NumericLiteral, + value: value, + base: base, + isMalformed: !isFinite(value) + }; + }, - /** - * Gets an array of implied globals - * @returns {Array.<{ name: string, line: Array.}>} - */ - getImpliedGlobals: function() { - // jshint proto: true - var values = _.values(impliedGlobals); - var hasProto = false; - // If `__proto__` is an implied global variable, its entry in the lookup - // table may not be enumerated by `_.values` (depending on the - // environment). - if (impliedGlobals.__proto__) { - hasProto = values.some(function(value) { - return value.name === "__proto__"; - }); + // Assumes previously parsed character was \ (=== '\\') and was not skipped. + scanEscapeSequence: function(checks) { + var allowNewLine = false; + var jump = 1; + this.skip(); + var char = this.peek(); - if (!hasProto) { - values.push(impliedGlobals.__proto__); - } + switch (char) { + case "'": + this.triggerAsync("warning", { + code: "W114", + line: this.line, + character: this.char, + data: [ "\\'" ] + }, checks, function() {return state.jsonMode; }); + break; + case "b": + char = "\\b"; + break; + case "f": + char = "\\f"; + break; + case "n": + char = "\\n"; + break; + case "r": + char = "\\r"; + break; + case "t": + char = "\\t"; + break; + case "0": + char = "\\0"; + + // Octal literals fail in strict mode. + // Check if the number is between 00 and 07. + var n = parseInt(this.peek(1), 10); + this.triggerAsync("warning", { + code: "W115", + line: this.line, + character: this.char + }, checks, + function() { return n >= 0 && n <= 7 && state.isStrict(); }); + break; + case "1": + case "2": + case "3": + case "4": + case "5": + case "6": + case "7": + char = "\\" + char; + this.triggerAsync("warning", { + code: "W115", + line: this.line, + character: this.char + }, checks, + function() { return state.isStrict(); }); + break; + case "u": + var sequence = this.input.substr(1, 4); + var code = parseInt(sequence, 16); + if (!isHex(sequence)) { + // This condition unequivocally describes a syntax error. + // TODO: Re-factor as an "error" (not a "warning"). + this.trigger("warning", { + code: "W052", + line: this.line, + character: this.char, + data: [ "u" + sequence ] + }); } + char = String.fromCharCode(code); + jump = 5; + break; + case "v": + this.triggerAsync("warning", { + code: "W114", + line: this.line, + character: this.char, + data: [ "\\v" ] + }, checks, function() { return state.jsonMode; }); - return values; - }, + char = "\v"; + break; + case "x": + var x = parseInt(this.input.substr(1, 2), 16); - /** - * Returns a list of unused variables - * @returns {Array} - */ - getUnuseds: function() { - return unuseds; - }, + this.triggerAsync("warning", { + code: "W114", + line: this.line, + character: this.char, + data: [ "\\x-" ] + }, checks, function() { return state.jsonMode; }); - has: function(labelName) { - return Boolean(_getLabel(labelName)); - }, + char = String.fromCharCode(x); + jump = 3; + break; + case "\\": + char = "\\\\"; + break; + case "\"": + char = "\\\""; + break; + case "/": + break; + case "": + allowNewLine = true; + char = ""; + break; + } + + return { char: char, jump: jump, allowNewLine: allowNewLine }; + }, + + /* + * Extract a template literal out of the next sequence of characters + * and/or lines or return 'null' if its not possible. Since template + * literals can span across multiple lines, this method has to move + * the char pointer. + */ + scanTemplateLiteral: function(checks) { + var tokenType; + var value = ""; + var ch; + var startLine = this.line; + var startChar = this.char; + var depth = this.templateStarts.length; - labeltype: function(labelName) { - // returns a labels type or null if not present - var scopeLabels = _getLabel(labelName); - if (scopeLabels) { - return scopeLabels[labelName]["(type)"]; + if (this.peek() === "`") { + if (!state.inES6(true)) { + this.triggerAsync( + "warning", + { + code: "W119", + line: this.line, + character: this.char, + data: ["template literal syntax", "6"] + }, + checks, + function() { return true; } + ); } + // Template must start with a backtick. + tokenType = Token.TemplateHead; + this.templateStarts.push({ line: this.line, char: this.char }); + depth = this.templateStarts.length; + this.skip(1); + this.pushContext(Context.Template); + } else if (this.inContext(Context.Template) && this.peek() === "}") { + // If we're in a template context, and we have a '}', lex a TemplateMiddle. + tokenType = Token.TemplateMiddle; + } else { + // Go lex something else. return null; - }, + } - /** - * for the exported options, indicating a variable is used outside the file - */ - addExported: function(labelName) { - var globalLabels = _scopeStack[0]["(labels)"]; - if (_.has(declared, labelName)) { - // remove the declared token, so we know it is used - delete declared[labelName]; - } else if (_.has(globalLabels, labelName)) { - globalLabels[labelName]["(unused)"] = false; - } else { - for (var i = 1; i < _scopeStack.length; i++) { - var scope = _scopeStack[i]; - // if `scope.(type)` is not defined, it is a block scope - if (!scope["(type)"]) { - if (_.has(scope["(labels)"], labelName) && - !scope["(labels)"][labelName]["(blockscoped)"]) { - scope["(labels)"][labelName]["(unused)"] = false; - return; - } - } else { - break; - } + while (this.peek() !== "`") { + while ((ch = this.peek()) === "") { + value += "\n"; + if (!this.nextLine(checks)) { + // Unclosed template literal --- point to the starting "`" + var startPos = this.templateStarts.pop(); + this.trigger("error", { + code: "E052", + line: startPos.line, + character: startPos.char + }); + return { + type: tokenType, + value: value, + startLine: startLine, + startChar: startChar, + isUnclosed: true, + depth: depth, + context: this.popContext() + }; } - exported[labelName] = true; } - }, - /** - * Mark an indentifier as es6 module exported - */ - setExported: function(labelName, token) { - this.block.use(labelName, token); - }, + if (ch === '$' && this.peek(1) === '{') { + value += '${'; + this.skip(2); + return { + type: tokenType, + value: value, + startLine: startLine, + startChar: startChar, + isUnclosed: false, + depth: depth, + context: this.currentContext() + }; + } else if (ch === '\\') { + var escape = this.scanEscapeSequence(checks); + value += escape.char; + this.skip(escape.jump); + } else if (ch !== '`') { + // Otherwise, append the value and continue. + value += ch; + this.skip(1); + } + } - /** - * adds an indentifier to the relevant current scope and creates warnings/errors as necessary - * @param {string} labelName - * @param {Object} opts - * @param {String} opts.type - the type of the label e.g. "param", "var", "let, "const", "function" - * @param {Token} opts.token - the token pointing at the declaration - */ - addlabel: function(labelName, opts) { + // Final value is either NoSubstTemplate or TemplateTail + tokenType = tokenType === Token.TemplateHead ? Token.NoSubstTemplate : Token.TemplateTail; + this.skip(1); + this.templateStarts.pop(); - var type = opts.type; - var token = opts.token; - var isblockscoped = type === "let" || type === "const" || type === "class"; - var isexported = (isblockscoped ? _current : _currentFunctBody)["(type)"] === "global" && - _.has(exported, labelName); + return { + type: tokenType, + value: value, + startLine: startLine, + startChar: startChar, + isUnclosed: false, + depth: depth, + context: this.popContext() + }; + }, - // outer shadow check (inner is only on non-block scoped) - _checkOuterShadow(labelName, token, type); + /* + * Extract a string out of the next sequence of characters and/or + * lines or return 'null' if its not possible. Since strings can + * span across multiple lines this method has to move the char + * pointer. + * + * This method recognizes pseudo-multiline JavaScript strings: + * + * var str = "hello\ + * world"; + */ + scanStringLiteral: function(checks) { + /*jshint loopfunc:true */ + var quote = this.peek(); - // if is block scoped (let or const) - if (isblockscoped) { + // String must start with a quote. + if (quote !== "\"" && quote !== "'") { + return null; + } - var declaredInCurrentScope = _current["(labels)"][labelName]; - // for block scoped variables, params are seen in the current scope as the root function - // scope, so check these too. - if (!declaredInCurrentScope && _current === _currentFunctBody && - _current["(type)"] !== "global") { - declaredInCurrentScope = !!_currentFunctBody["(parent)"]["(labels)"][labelName]; - } + // In JSON strings must always use double quotes. + this.triggerAsync("warning", { + code: "W108", + line: this.line, + character: this.char // +1? + }, checks, function() { return state.jsonMode && quote !== "\""; }); - // if its not already defined (which is an error, so ignore) and is used in TDZ - if (!declaredInCurrentScope && _current["(usages)"][labelName]) { - var usage = _current["(usages)"][labelName]; - // if its in a sub function it is not necessarily an error, just latedef - if (usage["(onlyUsedSubFunction)"]) { - _latedefWarning(type, labelName, token); - } else { - // this is a clear illegal usage for block scoped variables - warning("E056", token, labelName, type); - } - } + var value = ""; + var startLine = this.line; + var startChar = this.char; + var allowNewLine = false; - // if this scope has the variable defined, its a re-definition error - if (declaredInCurrentScope) { - warning("E011", token, labelName); - } - else if (state.option.shadow === "outer") { + this.skip(); - // if shadow is outer, for block scope we want to detect any shadowing within this function - if (scopeManagerInst.funct.has(labelName)) { - warning("W004", token, labelName); - } - } + while (this.peek() !== quote) { + if (this.peek() === "") { // End Of Line + + // If an EOL is not preceded by a backslash, show a warning + // and proceed like it was a legit multi-line string where + // author simply forgot to escape the newline symbol. + // + // Another approach is to implicitly close a string on EOL + // but it generates too many false positives. - scopeManagerInst.block.add(labelName, type, token, !isexported); + if (!allowNewLine) { + // This condition unequivocally describes a syntax error. + // TODO: Emit error E029 and remove W112. + this.trigger("warning", { + code: "W112", + line: this.line, + character: this.char + }); + } else { + allowNewLine = false; - } else { + // Otherwise show a warning if multistr option was not set. + // For JSON, show warning no matter what. - var declaredInCurrentFunctionScope = scopeManagerInst.funct.has(labelName); + this.triggerAsync("warning", { + code: "W043", + line: this.line, + character: this.char + }, checks, function() { return !state.option.multistr; }); - // check for late definition, ignore if already declared - if (!declaredInCurrentFunctionScope && usedSoFarInCurrentFunction(labelName)) { - _latedefWarning(type, labelName, token); + this.triggerAsync("warning", { + code: "W042", + line: this.line, + character: this.char + }, checks, function() { return state.jsonMode && state.option.multistr; }); } - // defining with a var or a function when a block scope variable of the same name - // is in scope is an error - if (scopeManagerInst.funct.has(labelName, { onlyBlockscoped: true })) { - warning("E011", token, labelName); - } else if (state.option.shadow !== true) { - // now since we didn't get any block scope variables, test for var/function - // shadowing - if (declaredInCurrentFunctionScope && labelName !== "__proto__") { + // If we get an EOF inside of an unclosed string, show an + // error and implicitly close it at the EOF point. - // see https://github.com/jshint/jshint/issues/2400 - if (_currentFunctBody["(type)"] !== "global") { - warning("W004", token, labelName); - } - } + if (!this.nextLine(checks)) { + return { + type: Token.StringLiteral, + value: value, + startLine: startLine, + startChar: startChar, + isUnclosed: true, + quote: quote + }; } - scopeManagerInst.funct.add(labelName, type, token, !isexported); + } else { // Any character other than End Of Line - if (_currentFunctBody["(type)"] === "global") { - usedPredefinedAndGlobals[labelName] = marker; - } - } - }, + allowNewLine = false; + var char = this.peek(); + var jump = 1; // A length of a jump, after we're done + // parsing this character. - funct: { - /** - * Returns the label type given certain options - * @param labelName - * @param {Object=} options - * @param {Boolean=} options.onlyBlockscoped - only include block scoped labels - * @param {Boolean=} options.excludeParams - exclude the param scope - * @param {Boolean=} options.excludeCurrent - exclude the current scope - * @returns {String} - */ - labeltype: function(labelName, options) { - var onlyBlockscoped = options && options.onlyBlockscoped; - var excludeParams = options && options.excludeParams; - var currentScopeIndex = _scopeStack.length - (options && options.excludeCurrent ? 2 : 1); - for (var i = currentScopeIndex; i >= 0; i--) { - var current = _scopeStack[i]; - if (current["(labels)"][labelName] && - (!onlyBlockscoped || current["(labels)"][labelName]["(blockscoped)"])) { - return current["(labels)"][labelName]["(type)"]; - } - var scopeCheck = excludeParams ? _scopeStack[ i - 1 ] : current; - if (scopeCheck && scopeCheck["(type)"] === "functionparams") { - return null; - } + if (char < " ") { + // Warn about a control character in a string. + this.triggerAsync( + "warning", + { + code: "W113", + line: this.line, + character: this.char, + data: [ "" ] + }, + checks, + function() { return true; } + ); } - return null; - }, - /** - * Returns if a break label exists in the function scope - * @param {string} labelName - * @returns {boolean} - */ - hasBreakLabel: function(labelName) { - for (var i = _scopeStack.length - 1; i >= 0; i--) { - var current = _scopeStack[i]; - if (current["(breakLabels)"][labelName]) { - return true; - } - if (current["(type)"] === "functionparams") { - return false; - } + // Special treatment for some escaped characters. + if (char === "\\") { + var parsed = this.scanEscapeSequence(checks); + char = parsed.char; + jump = parsed.jump; + allowNewLine = parsed.allowNewLine; } - return false; - }, - /** - * Returns if the label is in the current function scope - * See scopeManager.funct.labelType for options - */ - has: function(labelName, options) { - return Boolean(this.labeltype(labelName, options)); - }, - /** - * Adds a new function scoped variable - * see block.add for block scoped - */ - add: function(labelName, type, tok, unused) { - _current["(labels)"][labelName] = { - "(type)" : type, - "(token)": tok, - "(blockscoped)": false, - "(function)": _currentFunctBody, - "(unused)": unused }; + // If char is the empty string, end of the line has been reached. In + // this case, `this.char` should not be incremented so that warnings + // and errors reported in the subsequent loop iteration have the + // correct character column offset. + if (char !== "") { + value += char; + this.skip(jump); + } } - }, + } - block: { + this.skip(); + return { + type: Token.StringLiteral, + value: value, + startLine: startLine, + startChar: startChar, + isUnclosed: false, + quote: quote + }; + }, - /** - * is the current block global? - * @returns Boolean - */ - isGlobal: function() { - return _current["(type)"] === "global"; - }, + /* + * Extract a regular expression out of the next sequence of + * characters and/or lines or return 'null' if its not possible. + * + * This method is platform dependent: it accepts almost any + * regular expression values but then tries to compile and run + * them using system's RegExp object. This means that there are + * rare edge cases where one JavaScript engine complains about + * your regular expression while others don't. + */ + scanRegExp: function(checks) { + var index = 0; + var length = this.input.length; + var char = this.peek(); + var value = char; + var body = ""; + var groupReferences = []; + var allFlags = ""; + var es5Flags = ""; + var malformed = false; + var isCharSet = false; + var isCharSetRange = false; + var isGroup = false; + var isQuantifiable = false; + var hasInvalidQuantifier = false; + var escapedChars = ""; + var hasUFlag = function() { return allFlags.indexOf("u") > -1; }; + var escapeSequence; + var groupCount = 0; + var terminated, malformedDesc; + + var scanRegexpEscapeSequence = function() { + var next, sequence; + index += 1; + char = this.peek(index); - use: function(labelName, token) { + if (reg.nonzeroDigit.test(char)) { + sequence = char; + next = this.peek(index + 1); + while (reg.nonzeroDigit.test(next) || next === "0") { + index += 1; + char = next; + sequence += char; + body += char; + value += char; + next = this.peek(index + 1); + } + groupReferences.push(Number(sequence)); + return sequence; + } - // if resolves to current function params, then do not store usage just resolve - // this is because function(a) { var a; a = a; } will resolve to the param, not - // to the unset var - // first check the param is used - var paramScope = _currentFunctBody["(parent)"]; - if (paramScope && paramScope["(labels)"][labelName] && - paramScope["(labels)"][labelName]["(type)"] === "param") { + escapedChars += char; - // then check its not declared by a block scope variable - if (!scopeManagerInst.funct.has(labelName, - { excludeParams: true, onlyBlockscoped: true })) { - paramScope["(labels)"][labelName]["(unused)"] = false; - } + if (char === "u" && this.peek(index + 1) === "{") { + var x = index + 2; + sequence = "u{"; + next = this.peek(x); + while (isHex(next)) { + sequence += next; + x += 1; + next = this.peek(x); } - if (token && (state.ignored.W117 || state.option.undef === false)) { - token.ignoreUndef = true; + if (next !== "}") { + this.triggerAsync( + "error", + { + code: "E016", + line: this.line, + character: this.char, + data: [ "Invalid Unicode escape sequence" ] + }, + checks, + hasUFlag + ); + } else if (sequence.length > 2) { + sequence += "}"; + body += sequence; + value += sequence; + index = x + 1; + return sequence; } + } - _setupUsages(labelName); + // Unexpected control character + if (char < " ") { + malformed = true; + this.triggerAsync( + "warning", + { + code: "W048", + line: this.line, + character: this.char + }, + checks, + function() { return true; } + ); + } - if (token) { - token["(function)"] = _currentFunctBody; - _current["(usages)"][labelName]["(tokens)"].push(token); - } - }, + // Unexpected escaped character + if (char === "<") { + malformed = true; + this.triggerAsync( + "warning", + { + code: "W049", + line: this.line, + character: this.char, + data: [ char ] + }, + checks, + function() { return true; } + ); + } else if (char === "0" && reg.decimalDigit.test(this.peek(index + 1))) { + this.triggerAsync( + "error", + { + code: "E016", + line: this.line, + character: this.char, + data: [ "Invalid decimal escape sequence" ] + }, + checks, + hasUFlag + ); + } - reassign: function(labelName, token) { + index += 1; + body += char; + value += char; - this.modify(labelName, token); + return char; + }.bind(this); - _current["(usages)"][labelName]["(reassigned)"].push(token); - }, + var checkQuantifier = function() { + var lookahead = index; + var lowerBound = ""; + var upperBound = ""; + var next; - modify: function(labelName, token) { + next = this.peek(lookahead + 1); - _setupUsages(labelName); + while (reg.decimalDigit.test(next)) { + lookahead += 1; + lowerBound += next; + next = this.peek(lookahead + 1); + } - _current["(usages)"][labelName]["(modified)"].push(token); - }, + if (!lowerBound) { + return false; + } - /** - * Adds a new variable - */ - add: function(labelName, type, tok, unused) { - _current["(labels)"][labelName] = { - "(type)" : type, - "(token)": tok, - "(blockscoped)": true, - "(unused)": unused }; - }, + if (next === "}") { + return true; + } - addBreakLabel: function(labelName, opts) { - var token = opts.token; - if (scopeManagerInst.funct.hasBreakLabel(labelName)) { - warning("E011", token, labelName); - } - else if (state.option.shadow === "outer") { - if (scopeManagerInst.funct.has(labelName)) { - warning("W004", token, labelName); - } else { - _checkOuterShadow(labelName, token); - } - } - _current["(breakLabels)"][labelName] = token; + if (next !== ",") { + return false; } - } - }; - return scopeManagerInst; -}; -module.exports = scopeManager; + lookahead += 1; + next = this.peek(lookahead + 1); -},{"../lodash":"/node_modules/jshint/lodash.js","events":"/node_modules/browserify/node_modules/events/events.js"}],"/node_modules/jshint/src/state.js":[function(_dereq_,module,exports){ -"use strict"; -var NameStack = _dereq_("./name-stack.js"); + while (reg.decimalDigit.test(next)) { + lookahead += 1; + upperBound += next; + next = this.peek(lookahead + 1); + } -var state = { - syntax: {}, + if (next !== "}") { + return false; + } - /** - * Determine if the code currently being linted is strict mode code. - * - * @returns {boolean} - */ - isStrict: function() { - return this.directive["use strict"] || this.inClassBody || - this.option.module || this.option.strict === "implied"; - }, + if (upperBound) { + return Number(lowerBound) <= Number(upperBound); + } - // Assumption: chronologically ES3 < ES5 < ES6 < Moz + return true; + }.bind(this); - inMoz: function() { - return this.option.moz; - }, + var translateUFlag = function(body) { + // The BMP character to use as a replacement for astral symbols when + // translating an ES6 "u"-flagged pattern to an ES5-compatible + // approximation. + // Note: replacing with '\uFFFF' enables false positives in unlikely + // scenarios. For example, `[\u{1044f}-\u{10440}]` is an invalid pattern + // that would not be detected by this substitution. + var astralSubstitute = "\uFFFF"; + + return body + // Replace every Unicode escape sequence with the equivalent BMP + // character or a constant ASCII code point in the case of astral + // symbols. (See the above note on `astralSubstitute` for more + // information.) + .replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g, function($0, $1, $2) { + var codePoint = parseInt($1 || $2, 16); + var literal; + + if (codePoint > 0x10FFFF) { + malformed = true; + this.trigger("error", { + code: "E016", + line: this.line, + character: this.char, + data: [ char ] + }); - /** - * @param {boolean} strict - When `true`, only consider ES6 when in - * "esversion: 6" code and *not* in "moz". - */ - inES6: function() { - return this.option.moz || this.option.esversion >= 6; - }, + return; + } + literal = String.fromCharCode(codePoint); - /** - * @param {boolean} strict - When `true`, return `true` only when - * esversion is exactly 5 - */ - inES5: function(strict) { - if (strict) { - return (!this.option.esversion || this.option.esversion === 5) && !this.option.moz; - } - return !this.option.esversion || this.option.esversion >= 5 || this.option.moz; - }, + if (reg.regexpSyntaxChars.test(literal)) { + return $0; + } + if (codePoint <= 0xFFFF) { + return String.fromCharCode(codePoint); + } + return astralSubstitute; + }.bind(this)) + // Replace each paired surrogate with a single ASCII symbol to avoid + // throwing on regular expressions that are only valid in combination + // with the "u" flag. + .replace( + /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, + astralSubstitute + ); + }.bind(this); - reset: function() { - this.tokens = { - prev: null, - next: null, - curr: null - }; + // Regular expressions must start with '/' + if (!this.prereg || char !== "/") { + return null; + } - this.option = {}; - this.funct = null; - this.ignored = {}; - this.directive = {}; - this.jsonMode = false; - this.jsonWarnings = []; - this.lines = []; - this.tab = ""; - this.cache = {}; // Node.JS doesn't have Map. Sniff. - this.ignoredLines = {}; - this.forinifcheckneeded = false; - this.nameStack = new NameStack(); - this.inClassBody = false; - } -}; + index += 1; + terminated = false; -exports.state = state; + // Try to get everything in between slashes. A couple of + // cases aside (see scanRegexpEscapeSequence) we don't really + // care whether the resulting expression is valid or not. + // We will check that later using the RegExp object. -},{"./name-stack.js":"/node_modules/jshint/src/name-stack.js"}],"/node_modules/jshint/src/style.js":[function(_dereq_,module,exports){ -"use strict"; + while (index < length) { + // Because an iteration of this loop may terminate in a number of + // distinct locations, `isCharSetRange` is re-set at the onset of + // iteration. + isCharSetRange &= char === "-"; + char = this.peek(index); + value += char; + body += char; -exports.register = function(linter) { - // Check for properties named __proto__. This special property was - // deprecated and then re-introduced for ES6. + if (isCharSet) { + if (char === "]") { + if (this.peek(index - 1) !== "\\" || this.peek(index - 2) === "\\") { + isCharSet = false; + } + } else if (char === "-") { + isCharSetRange = true; + } + } - linter.on("Identifier", function style_scanProto(data) { - if (linter.getOption("proto")) { - return; - } + if (char === "\\") { + escapeSequence = scanRegexpEscapeSequence(); + + if (isCharSet && (this.peek(index) === "-" || isCharSetRange) && + reg.regexpCharClasses.test(escapeSequence)) { + this.triggerAsync( + "error", + { + code: "E016", + line: this.line, + character: this.char, + data: [ "Character class used in range" ] + }, + checks, + hasUFlag + ); + } - if (data.name === "__proto__") { - linter.warn("W103", { - line: data.line, - char: data.char, - data: [ data.name, "6" ] - }); - } - }); + continue; + } - // Check for properties named __iterator__. This is a special property - // available only in browsers with JavaScript 1.7 implementation, but - // it is deprecated for ES6 + if (isCharSet) { + index += 1; + continue; + } - linter.on("Identifier", function style_scanIterator(data) { - if (linter.getOption("iterator")) { - return; - } + if (char === "{" && !hasInvalidQuantifier) { + hasInvalidQuantifier = !checkQuantifier(); + } - if (data.name === "__iterator__") { - linter.warn("W103", { - line: data.line, - char: data.char, - data: [ data.name ] - }); - } - }); + if (char === "[") { + isCharSet = true; + index += 1; + continue; + } else if (char === "(") { + isGroup = true; - // Check that all identifiers are using camelCase notation. - // Exceptions: names like MY_VAR and _myVar. + if (this.peek(index + 1) === "?" && + (this.peek(index + 2) === "=" || this.peek(index + 2) === "!")) { + isQuantifiable = true; + } + } else if (char === ")") { + if (isQuantifiable) { + isQuantifiable = false; + + if (reg.regexpQuantifiers.test(this.peek(index + 1))) { + this.triggerAsync( + "error", + { + code: "E016", + line: this.line, + character: this.char, + data: [ "Quantified quantifiable" ] + }, + checks, + hasUFlag + ); + } + } else { + groupCount += 1; + } - linter.on("Identifier", function style_scanCamelCase(data) { - if (!linter.getOption("camelcase")) { - return; - } + isGroup = false; + } else if (char === "/") { + body = body.substr(0, body.length - 1); + terminated = true; + index += 1; + break; + } - if (data.name.replace(/^_+|_+$/g, "").indexOf("_") > -1 && !data.name.match(/^[A-Z0-9_]*$/)) { - linter.warn("W106", { - line: data.line, - char: data.from, - data: [ data.name ] - }); + index += 1; } - }); - // Enforce consistency in style of quoting. + // A regular expression that was never closed is an + // error from which we cannot recover. - linter.on("String", function style_scanQuotes(data) { - var quotmark = linter.getOption("quotmark"); - var code; + if (!terminated) { + this.trigger("error", { + code: "E015", + line: this.line, + character: this.from + }); - if (!quotmark) { - return; + return void this.trigger("fatal", { + line: this.line, + from: this.from + }); } - // If quotmark is set to 'single' warn about all double-quotes. + // Parse flags (if any). - if (quotmark === "single" && data.quote !== "'") { - code = "W109"; - } + while (index < length) { + char = this.peek(index); + if (!/[gimyus]/.test(char)) { + break; + } + if (char === "y") { + if (!state.inES6(true)) { + this.triggerAsync( + "warning", + { + code: "W119", + line: this.line, + character: this.char, + data: [ "Sticky RegExp flag", "6" ] + }, + checks, + function() { return true; } + ); + } + } else if (char === "u") { + if (!state.inES6(true)) { + this.triggerAsync( + "warning", + { + code: "W119", + line: this.line, + character: this.char, + data: [ "Unicode RegExp flag", "6" ] + }, + checks, + function() { return true; } + ); + } - // If quotmark is set to 'double' warn about all single-quotes. + var hasInvalidEscape = (function(groupReferences, groupCount, escapedChars, reg) { + var hasInvalidGroup = groupReferences.some(function(groupReference) { + if (groupReference > groupCount) { + return true; + } + }); - if (quotmark === "double" && data.quote !== "\"") { - code = "W108"; - } + if (hasInvalidGroup) { + return true; + } - // If quotmark is set to true, remember the first quotation style - // and then warn about all others. + return !escapedChars.split("").every(function(escapedChar) { + return escapedChar === "u" || + escapedChar === "/" || + escapedChar === "0" || + reg.regexpControlEscapes.test(escapedChar) || + reg.regexpCharClasses.test(escapedChar) || + reg.regexpSyntaxChars.test(escapedChar); + }); + }(groupReferences, groupCount, escapedChars, reg)); - if (quotmark === true) { - if (!linter.getCache("quotmark")) { - linter.setCache("quotmark", data.quote); - } + if (hasInvalidEscape) { + malformedDesc = "Invalid escape"; + } else if (hasInvalidQuantifier) { + malformedDesc = "Invalid quantifier"; + } - if (linter.getCache("quotmark") !== data.quote) { - code = "W110"; + body = translateUFlag(body); + } else if (char === "s") { + if (!state.inES9()) { + this.triggerAsync( + "warning", + { + code: "W119", + line: this.line, + character: this.char, + data: [ "DotAll RegExp flag", "9" ] + }, + checks, + function() { return true; } + ); + } + if (value.indexOf("s") > -1) { + malformedDesc = "Duplicate RegExp flag"; + } + } else { + es5Flags += char; } - } - if (code) { - linter.warn(code, { - line: data.line, - char: data.char, - }); - } - }); - - linter.on("Number", function style_scanNumbers(data) { - if (data.value.charAt(0) === ".") { - // Warn about a leading decimal point. - linter.warn("W008", { - line: data.line, - char: data.char, - data: [ data.value ] - }); - } + if (allFlags.indexOf(char) > -1) { + malformedDesc = "Duplicate RegExp flag"; + } + allFlags += char; - if (data.value.substr(data.value.length - 1) === ".") { - // Warn about a trailing decimal point. - linter.warn("W047", { - line: data.line, - char: data.char, - data: [ data.value ] - }); + value += char; + allFlags += char; + index += 1; } - if (/^00+/.test(data.value)) { - // Multiple leading zeroes. - linter.warn("W046", { - line: data.line, - char: data.char, - data: [ data.value ] - }); + if (allFlags.indexOf("u") === -1) { + this.triggerAsync("warning", { + code: "W147", + line: this.line, + character: this.char + }, checks, function() { return state.option.regexpu; }); } - }); - - // Warn about script URLs. - linter.on("String", function style_scanJavaScriptURLs(data) { - var re = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i; + // Check regular expression for correctness. - if (linter.getOption("scripturl")) { - return; + try { + new RegExp(body, es5Flags); + } catch (err) { + /** + * Because JSHint relies on the current engine's RegExp parser to + * validate RegExp literals, the description (exposed as the "data" + * property on the error object) is platform dependent. + */ + malformedDesc = err.message; } - if (re.test(data.value)) { - linter.warn("W107", { - line: data.line, - char: data.char + if (malformedDesc) { + malformed = true; + this.trigger("error", { + code: "E016", + line: this.line, + character: this.char, + data: [ malformedDesc ] + }); + } else if (allFlags.indexOf("s") > -1 && !reg.regexpDot.test(body)) { + this.trigger("warning", { + code: "W148", + line: this.line, + character: this.char }); } - }); -}; -},{}],"/node_modules/jshint/src/vars.js":[function(_dereq_,module,exports){ -// jshint -W001 + return { + type: Token.RegExp, + value: value, + isMalformed: malformed + }; + }, -"use strict"; + /* + * Scan for any occurrence of non-breaking spaces. Non-breaking spaces + * can be mistakenly typed on OS X with option-space. Non UTF-8 web + * pages with non-breaking pages produce syntax errors. + */ + scanNonBreakingSpaces: function() { + return state.option.nonbsp ? + this.input.search(/(\u00A0)/) : -1; + }, -// Identifiers provided by the ECMAScript standard. + /* + * Produce the next raw token or return 'null' if no tokens can be matched. + * This method skips over all space characters. + */ + next: function(checks) { + this.from = this.char; -exports.reservedVars = { - arguments : false, - NaN : false -}; + // Move to the next non-space character. + while (reg.whitespace.test(this.peek())) { + this.from += 1; + this.skip(); + } -exports.ecmaIdentifiers = { - 3: { - Array : false, - Boolean : false, - Date : false, - decodeURI : false, - decodeURIComponent : false, - encodeURI : false, - encodeURIComponent : false, - Error : false, - "eval" : false, - EvalError : false, - Function : false, - hasOwnProperty : false, - isFinite : false, - isNaN : false, - Math : false, - Number : false, - Object : false, - parseInt : false, - parseFloat : false, - RangeError : false, - ReferenceError : false, - RegExp : false, - String : false, - SyntaxError : false, - TypeError : false, - URIError : false + // Methods that work with multi-line structures and move the + // character pointer. + + var match = this.scanComments(checks) || + this.scanStringLiteral(checks) || + this.scanTemplateLiteral(checks); + + if (match) { + return match; + } + + // Methods that don't move the character pointer. + + match = + this.scanRegExp(checks) || + this.scanPunctuator() || + this.scanKeyword() || + this.scanIdentifier(checks) || + this.scanNumericLiteral(checks); + + if (match) { + this.skip(match.tokenLength || match.value.length); + return match; + } + + // No token could be matched, give up. + + return null; }, - 5: { - JSON : false + + /* + * Switch to the next line and reset all char pointers. Once + * switched, this method also checks for other minor warnings. + */ + nextLine: function(checks) { + var char; + + if (this.line >= this.getLines().length) { + return false; + } + + this.input = this.getLines()[this.line]; + this.line += 1; + this.char = 1; + this.from = 1; + + var inputTrimmed = this.input.trim(); + + var startsWith = function() { + return _.some(arguments, function(prefix) { + return inputTrimmed.indexOf(prefix) === 0; + }); + }; + + var endsWith = function() { + return _.some(arguments, function(suffix) { + return inputTrimmed.indexOf(suffix, inputTrimmed.length - suffix.length) !== -1; + }); + }; + + // If we are ignoring linter errors, replace the input with empty string + // if it doesn't already at least start or end a multi-line comment + if (this.ignoringLinterErrors === true) { + if (!startsWith("/*", "//") && !(this.inComment && endsWith("*/"))) { + this.input = ""; + } + } + + char = this.scanNonBreakingSpaces(); + if (char >= 0) { + this.triggerAsync( + "warning", + { code: "W125", line: this.line, character: char + 1 }, + checks, + function() { return true; } + ); + } + + this.input = this.input.replace(/\t/g, state.tab); + + // If there is a limit on line length, warn when lines get too + // long. + + if (!this.ignoringLinterErrors && state.option.maxlen && + state.option.maxlen < this.input.length) { + var inComment = this.inComment || + startsWith.call(inputTrimmed, "//") || + startsWith.call(inputTrimmed, "/*"); + + var shouldTriggerError = !inComment || !reg.maxlenException.test(inputTrimmed); + + if (shouldTriggerError) { + this.triggerAsync( + "warning", + { code: "W101", line: this.line, character: this.input.length }, + checks, + function() { return true; } + ); + } + } + + return true; }, - 6: { - Map : false, - Promise : false, - Proxy : false, - Reflect : false, - Set : false, - Symbol : false, - WeakMap : false, - WeakSet : false - } -}; -// Global variables commonly provided by a web browser environment. + /* + * Produce the next token. This function is called by advance() to get + * the next token. It returns a token in a JSLint-compatible format. + */ + token: function() { + /*jshint loopfunc:true */ + var checks = asyncTrigger(); + var token; -exports.browser = { - Audio : false, - Blob : false, - addEventListener : false, - applicationCache : false, - atob : false, - blur : false, - btoa : false, - cancelAnimationFrame : false, - CanvasGradient : false, - CanvasPattern : false, - CanvasRenderingContext2D: false, - CSS : false, - clearInterval : false, - clearTimeout : false, - close : false, - closed : false, - Comment : false, - CustomEvent : false, - DOMParser : false, - defaultStatus : false, - Document : false, - document : false, - DocumentFragment : false, - Element : false, - ElementTimeControl : false, - Event : false, - event : false, - fetch : false, - FileReader : false, - FormData : false, - focus : false, - frames : false, - getComputedStyle : false, - HTMLElement : false, - HTMLAnchorElement : false, - HTMLBaseElement : false, - HTMLBlockquoteElement: false, - HTMLBodyElement : false, - HTMLBRElement : false, - HTMLButtonElement : false, - HTMLCanvasElement : false, - HTMLCollection : false, - HTMLDirectoryElement : false, - HTMLDivElement : false, - HTMLDListElement : false, - HTMLFieldSetElement : false, - HTMLFontElement : false, - HTMLFormElement : false, - HTMLFrameElement : false, - HTMLFrameSetElement : false, - HTMLHeadElement : false, - HTMLHeadingElement : false, - HTMLHRElement : false, - HTMLHtmlElement : false, - HTMLIFrameElement : false, - HTMLImageElement : false, - HTMLInputElement : false, - HTMLIsIndexElement : false, - HTMLLabelElement : false, - HTMLLayerElement : false, - HTMLLegendElement : false, - HTMLLIElement : false, - HTMLLinkElement : false, - HTMLMapElement : false, - HTMLMenuElement : false, - HTMLMetaElement : false, - HTMLModElement : false, - HTMLObjectElement : false, - HTMLOListElement : false, - HTMLOptGroupElement : false, - HTMLOptionElement : false, - HTMLParagraphElement : false, - HTMLParamElement : false, - HTMLPreElement : false, - HTMLQuoteElement : false, - HTMLScriptElement : false, - HTMLSelectElement : false, - HTMLStyleElement : false, - HTMLTableCaptionElement: false, - HTMLTableCellElement : false, - HTMLTableColElement : false, - HTMLTableElement : false, - HTMLTableRowElement : false, - HTMLTableSectionElement: false, - HTMLTemplateElement : false, - HTMLTextAreaElement : false, - HTMLTitleElement : false, - HTMLUListElement : false, - HTMLVideoElement : false, - history : false, - Image : false, - Intl : false, - length : false, - localStorage : false, - location : false, - matchMedia : false, - MessageChannel : false, - MessageEvent : false, - MessagePort : false, + // Produce a token object. + var create = function(type, value, isProperty, token) { + /*jshint validthis:true */ + var obj; + + if (type !== "(endline)" && type !== "(end)") { + this.prereg = false; + } + + if (type === "(punctuator)") { + switch (value) { + case ".": + case ")": + case "~": + case "#": + case "]": + case "}": + case "++": + case "--": + this.prereg = false; + break; + default: + this.prereg = true; + } + + obj = Object.create(state.syntax[value] || state.syntax["(error)"]); + } + + if (type === "(identifier)") { + if (value === "return" || value === "case" || value === "yield" || + value === "typeof" || value === "instanceof" || value === "void" || + value === "await") { + this.prereg = true; + } + + if (_.has(state.syntax, value)) { + obj = Object.create(state.syntax[value] || state.syntax["(error)"]); + } + } + + if (type === "(template)" || type === "(template middle)") { + this.prereg = true; + } + + if (!obj) { + obj = Object.create(state.syntax[type]); + } + + obj.identifier = (type === "(identifier)"); + obj.type = obj.type || type; + obj.value = value; + obj.line = this.line; + obj.character = this.char; + obj.from = this.from; + if (obj.identifier && token) obj.raw_text = token.text || token.value; + if (token && token.startLine && token.startLine !== this.line) { + obj.startLine = token.startLine; + } + if (token && token.context) { + // Context of current token + obj.context = token.context; + } + if (token && token.depth) { + // Nested template depth + obj.depth = token.depth; + } + if (token && token.isUnclosed) { + // Mark token as unclosed string / template literal + obj.isUnclosed = token.isUnclosed; + } + + if (isProperty && obj.identifier) { + obj.isProperty = isProperty; + } + + obj.check = checks.check; + + return obj; + }.bind(this); + + for (;;) { + if (!this.input.length) { + if (this.nextLine(checks)) { + return create("(endline)", ""); + } + + if (this.exhausted) { + return null; + } + + this.exhausted = true; + return create("(end)", ""); + } + + token = this.next(checks); + + if (!token) { + if (this.input.length) { + // Unexpected character. + this.trigger("error", { + code: "E024", + line: this.line, + character: this.char, + data: [ this.peek() ] + }); + + this.input = ""; + } + + continue; + } + + switch (token.type) { + case Token.StringLiteral: + this.triggerAsync("String", { + line: this.line, + char: this.char, + from: this.from, + startLine: token.startLine, + startChar: token.startChar, + value: token.value, + quote: token.quote + }, checks, function() { return true; }); + + return create("(string)", token.value, null, token); + + case Token.TemplateHead: + this.trigger("TemplateHead", { + line: this.line, + char: this.char, + from: this.from, + startLine: token.startLine, + startChar: token.startChar, + value: token.value + }); + return create("(template)", token.value, null, token); + + case Token.TemplateMiddle: + this.trigger("TemplateMiddle", { + line: this.line, + char: this.char, + from: this.from, + startLine: token.startLine, + startChar: token.startChar, + value: token.value + }); + return create("(template middle)", token.value, null, token); + + case Token.TemplateTail: + this.trigger("TemplateTail", { + line: this.line, + char: this.char, + from: this.from, + startLine: token.startLine, + startChar: token.startChar, + value: token.value + }); + return create("(template tail)", token.value, null, token); + + case Token.NoSubstTemplate: + this.trigger("NoSubstTemplate", { + line: this.line, + char: this.char, + from: this.from, + startLine: token.startLine, + startChar: token.startChar, + value: token.value + }); + return create("(no subst template)", token.value, null, token); + + case Token.Identifier: + this.triggerAsync("Identifier", { + line: this.line, + char: this.char, + from: this.from, + name: token.value, + raw_name: token.text, + isProperty: state.tokens.curr.id === "." + }, checks, function() { return true; }); + + /* falls through */ + case Token.Keyword: + return create("(identifier)", token.value, state.tokens.curr.id === ".", token); + + case Token.NumericLiteral: + if (token.isMalformed) { + // This condition unequivocally describes a syntax error. + // TODO: Re-factor as an "error" (not a "warning"). + this.trigger("warning", { + code: "W045", + line: this.line, + character: this.char, + data: [ token.value ] + }); + } + + this.triggerAsync("warning", { + code: "W114", + line: this.line, + character: this.char, + data: [ "0x-" ] + }, checks, function() { return token.base === 16 && state.jsonMode; }); + + this.triggerAsync("warning", { + code: "W115", + line: this.line, + character: this.char + }, checks, function() { + return state.isStrict() && token.base === 8 && token.isLegacy; + }); + + this.trigger("Number", { + line: this.line, + char: this.char, + from: this.from, + value: token.value, + base: token.base, + isMalformed: token.isMalformed + }); + + return create("(number)", token.value); + + case Token.RegExp: + return create("(regexp)", token.value); + + case Token.Comment: + if (token.isSpecial) { + return { + id: '(comment)', + value: token.value, + body: token.body, + type: token.commentType, + isSpecial: token.isSpecial, + line: this.line, + character: this.char, + from: this.from + }; + } + + break; + + default: + return create("(punctuator)", token.value); + } + } + } +}; + +exports.Lexer = Lexer; +exports.Context = Context; + +},{"../data/ascii-identifier-data.js":"/../../jshint/data/ascii-identifier-data.js","../data/es5-identifier-names.js":"/../../jshint/data/es5-identifier-names.js","../data/non-ascii-identifier-part-only.js":"/../../jshint/data/non-ascii-identifier-part-only.js","../data/non-ascii-identifier-start.js":"/../../jshint/data/non-ascii-identifier-start.js","./reg.js":"/../../jshint/src/reg.js","./state.js":"/../../jshint/src/state.js","events":"/../node_modules/events/events.js","underscore":"/../../jshint/node_modules/underscore/underscore.js"}],"/../../jshint/src/messages.js":[function(_dereq_,module,exports){ +"use strict"; + +var _ = _dereq_("underscore"); + +var errors = { + // JSHint options + E001: "Bad {a}option: '{b}'.", + E002: "Bad option value.", + + // JSHint input + E003: "Expected a JSON value.", + E004: "Input is neither a string nor an array of strings.", + E005: "Input is empty.", + E006: "Unexpected early end of program.", + + // Strict mode + E007: "Missing \"use strict\" statement.", + E008: "Strict violation.", + E009: "Option 'validthis' can't be used in a global scope.", + E010: "'with' is not allowed in strict mode.", + + // Constants + E011: "'{a}' has already been declared.", + E012: "const '{a}' is initialized to 'undefined'.", + E013: "Attempting to override '{a}' which is a constant.", + + // Regular expressions + E014: "A regular expression literal can be confused with '/='.", + E015: "Unclosed regular expression.", + E016: "Invalid regular expression.", + + // Tokens + E017: "Unclosed comment.", + E018: "Unbegun comment.", + E019: "Unmatched '{a}'.", + E020: "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", + E021: "Expected '{a}' and instead saw '{b}'.", + E022: "Line breaking error '{a}'.", + E023: "Missing '{a}'.", + E024: "Unexpected '{a}'.", + E025: "Missing ':' on a case clause.", + E026: "Missing '}' to match '{' from line {a}.", + E027: "Missing ']' to match '[' from line {a}.", + E028: "Illegal comma.", + E029: "Unclosed string.", + + // Everything else + E030: "Expected an identifier and instead saw '{a}'.", + E031: "Bad assignment.", // FIXME: Rephrase + E032: "Expected a small integer or 'false' and instead saw '{a}'.", + E033: "Expected an operator and instead saw '{a}'.", + E034: "get/set are ES5 features.", + E035: "Missing property name.", + E036: "Expected to see a statement and instead saw a block.", + E037: null, + E038: null, + E039: "Function declarations are not invocable. Wrap the whole function invocation in parens.", + E040: "Each value should have its own case label.", + E041: "Unrecoverable syntax error.", + E042: "Stopping.", + E043: "Too many errors.", + E044: null, + E045: "Invalid for each loop.", + E046: "Yield expressions may only occur within generator functions.", + E047: null, + E048: "{a} declaration not directly within block.", + E049: "A {a} cannot be named '{b}'.", + E050: "Mozilla requires the yield expression to be parenthesized here.", + E051: null, + E052: "Unclosed template literal.", + E053: "{a} declarations are only allowed at the top level of module scope.", + E054: "Class properties must be methods. Expected '(' but instead saw '{a}'.", + E055: "The '{a}' option cannot be set after any executable code.", + E056: "'{a}' was used before it was declared, which is illegal for '{b}' variables.", + E057: "Invalid meta property: '{a}.{b}'.", + E058: "Missing semicolon.", + E059: "Incompatible values for the '{a}' and '{b}' linting options.", + E060: "Non-callable values cannot be used as the second operand to instanceof.", + E061: "Invalid position for 'yield' expression (consider wrapping in parenthesis).", + E062: "Rest parameter does not a support default value.", + E063: "Super property may only be used within method bodies.", + E064: "Super call may only be used within class method bodies.", + E065: "Functions defined outside of strict mode with non-simple parameter lists may not " + + "enable strict mode.", + E066: "Asynchronous iteration is only available with for-of loops." +}; + +var warnings = { + W001: "'hasOwnProperty' is a really bad name.", + W002: "Value of '{a}' may be overwritten in IE 8 and earlier.", + W003: "'{a}' was used before it was defined.", + W004: "'{a}' is already defined.", + W005: "A dot following a number can be confused with a decimal point.", + W006: "Confusing minuses.", + W007: "Confusing plusses.", + W008: "A leading decimal point can be confused with a dot: '{a}'.", + W009: "The array literal notation [] is preferable.", + W010: "The object literal notation {} is preferable.", + W011: null, + W012: null, + W013: null, + W014: "Misleading line break before '{a}'; readers may interpret this as an expression boundary.", + W015: null, + W016: "Unexpected use of '{a}'.", + W017: "Bad operand.", + W018: "Confusing use of '{a}'.", + W019: "Use the isNaN function to compare with NaN.", + W020: "Read only.", + W021: "Reassignment of '{a}', which is a {b}. " + + "Use 'var' or 'let' to declare bindings that may change.", + W022: "Do not assign to the exception parameter.", + W023: null, + W024: "Expected an identifier and instead saw '{a}' (a reserved word).", + W025: "Missing name in function declaration.", + W026: "Inner functions should be listed at the top of the outer function.", + W027: "Unreachable '{a}' after '{b}'.", + W028: "Label '{a}' on {b} statement.", + W030: "Expected an assignment or function call and instead saw an expression.", + W031: "Do not use 'new' for side effects.", + W032: "Unnecessary semicolon.", + W033: "Missing semicolon.", + W034: "Unnecessary directive \"{a}\".", + W035: "Empty block.", + W036: "Unexpected /*member '{a}'.", + W037: "'{a}' is a statement label.", + W038: "'{a}' used out of scope.", + W039: null, + W040: "If a strict mode function is executed using function invocation, " + + "its 'this' value will be undefined.", + W041: null, + W042: "Avoid EOL escaping.", + W043: "Bad escaping of EOL. Use option multistr if needed.", + W044: "Bad or unnecessary escaping.", /* TODO(caitp): remove W044 */ + W045: "Bad number '{a}'.", + W046: "Don't use extra leading zeros '{a}'.", + W047: "A trailing decimal point can be confused with a dot: '{a}'.", + W048: "Unexpected control character in regular expression.", + W049: "Unexpected escaped character '{a}' in regular expression.", + W050: "JavaScript URL.", + W051: "Variables should not be deleted.", + W052: "Unexpected '{a}'.", + W053: "Do not use {a} as a constructor.", + W054: "The Function constructor is a form of eval.", + W055: "A constructor name should start with an uppercase letter.", + W056: "Bad constructor.", + W057: "Weird construction. Is 'new' necessary?", + W058: "Missing '()' invoking a constructor.", + W059: "Avoid arguments.{a}.", + W060: "document.write can be a form of eval.", + W061: "eval can be harmful.", + W062: "Wrap an immediate function invocation in parens " + + "to assist the reader in understanding that the expression " + + "is the result of a function, and not the function itself.", + W063: "Math is not a function.", + W064: "Missing 'new' prefix when invoking a constructor.", + W065: "Missing radix parameter.", + W066: "Implied eval. Consider passing a function instead of a string.", + W067: "Bad invocation.", + W068: "Wrapping non-IIFE function literals in parens is unnecessary.", + W069: "['{a}'] is better written in dot notation.", + W070: "Extra comma. (it breaks older versions of IE)", + W071: "This function has too many statements. ({a})", + W072: "This function has too many parameters. ({a})", + W073: "Blocks are nested too deeply. ({a})", + W074: "This function's cyclomatic complexity is too high. ({a})", + W075: "Duplicate {a} '{b}'.", + W076: "Unexpected parameter '{a}' in get {b} function.", + W077: "Expected a single parameter in set {a} function.", + W078: "Setter is defined without getter.", + W079: "Redefinition of '{a}'.", + W080: "It's not necessary to initialize '{a}' to 'undefined'.", + W081: null, + W082: "Function declarations should not be placed in blocks. " + + "Use a function expression or move the statement to the top of " + + "the outer function.", + W083: "Functions declared within loops referencing an outer scoped " + + "variable may lead to confusing semantics. ({a})", + W084: "Assignment in conditional expression", + W085: "Don't use 'with'.", + W086: "Expected a 'break' statement before '{a}'.", + W087: "Forgotten 'debugger' statement?", + W088: "Creating global 'for' variable. Should be 'for (var {a} ...'.", + W089: "The body of a for in should be wrapped in an if statement to filter " + + "unwanted properties from the prototype.", + W090: "'{a}' is not a statement label.", + W091: null, + W093: "Did you mean to return a conditional instead of an assignment?", + W094: "Unexpected comma.", + W095: "Expected a string and instead saw {a}.", + W096: "The '{a}' key may produce unexpected results.", + W097: "Use the function form of \"use strict\".", + W098: "'{a}' is defined but never used.", + W099: null, + W100: null, + W101: "Line is too long.", + W102: null, + W103: "The '{a}' property is deprecated.", + W104: "'{a}' is available in ES{b} (use 'esversion: {b}') or Mozilla JS extensions (use moz).", + W105: null, + W106: "Identifier '{a}' is not in camel case.", + W107: "Script URL.", + W108: "Strings must use doublequote.", + W109: "Strings must use singlequote.", + W110: "Mixed double and single quotes.", + W112: "Unclosed string.", + W113: "Control character in string: {a}.", + W114: "Avoid {a}.", + W115: "Octal literals are not allowed in strict mode.", + W116: "Expected '{a}' and instead saw '{b}'.", + W117: "'{a}' is not defined.", + W118: "'{a}' is only available in Mozilla JavaScript extensions (use moz option).", + W119: "'{a}' is only available in ES{b} (use 'esversion: {b}').", + W120: "You might be leaking a variable ({a}) here.", + W121: "Extending prototype of native object: '{a}'.", + W122: "Invalid typeof value '{a}'", + W123: "'{a}' is already defined in outer scope.", + W124: "A generator function should contain at least one yield expression.", + W125: "This line contains non-breaking spaces: http://jshint.com/docs/options/#nonbsp", + W126: "Unnecessary grouping operator.", + W127: "Unexpected use of a comma operator.", + W128: "Empty array elements require elision=true.", + W129: "'{a}' is defined in a future version of JavaScript. Use a " + + "different variable name to avoid migration issues.", + W130: "Invalid element after rest element.", + W131: "Invalid parameter after rest parameter.", + W132: "`var` declarations are forbidden. Use `let` or `const` instead.", + W133: "Invalid for-{a} loop left-hand-side: {b}.", + W134: "The '{a}' option is only available when linting ECMAScript {b} code.", + W135: "{a} may not be supported by non-browser environments.", + W136: "'{a}' must be in function scope.", + W137: "Empty destructuring: this is unnecessary and can be removed.", + W138: "Regular parameters should not come after default parameters.", + W139: "Function expressions should not be used as the second operand to instanceof.", + W140: "Missing comma.", + W141: "Empty {a}: this is unnecessary and can be removed.", + W142: "Empty {a}: consider replacing with `import '{b}';`.", + W143: "Assignment to properties of a mapped arguments object may cause " + + "unexpected changes to formal parameters.", + W144: "'{a}' is a non-standard language feature. Enable it using the '{b}' unstable option.", + W145: "Superfluous 'case' clause.", + W146: "Unnecessary `await` expression.", + W147: "Regular expressions should include the 'u' flag.", + W148: "Unnecessary RegExp 's' flag." +}; + +var info = { + I001: "Comma warnings can be turned off with 'laxcomma'.", + I002: null, + I003: "ES5 option is now set per default" +}; + +exports.errors = {}; +exports.warnings = {}; +exports.info = {}; + +_.each(errors, function(desc, code) { + exports.errors[code] = { code: code, desc: desc }; +}); + +_.each(warnings, function(desc, code) { + exports.warnings[code] = { code: code, desc: desc }; +}); + +_.each(info, function(desc, code) { + exports.info[code] = { code: code, desc: desc }; +}); + +},{"underscore":"/../../jshint/node_modules/underscore/underscore.js"}],"/../../jshint/src/name-stack.js":[function(_dereq_,module,exports){ +/** + * The NameStack class is used to approximate function name inference as + * introduced by ECMAScript 2015. In that edition, the `name` property of + * function objects is set according to the function's syntactic form. For + * certain forms, this value depends on values available to the runtime during + * execution. For example: + * + * var fnName = function() {}; + * + * In the program code above, the function object's `name` property is set to + * `"fnName"` during execution. + * + * This general "name inference" behavior extends to a number of additional + * syntactic forms, not all of which can be implemented statically. `NameStack` + * is a support class representing a "best-effort" attempt to implement the + * specified behavior in cases where this may be done statically. + * + * For more information on this behavior, see the following blog post: + * https://bocoup.com/blog/whats-in-a-function-name + */ +"use strict"; + +function NameStack() { + this._stack = []; +} + +Object.defineProperty(NameStack.prototype, "length", { + get: function() { + return this._stack.length; + } +}); + +/** + * Create a new entry in the stack. Useful for tracking names across + * expressions. + */ +NameStack.prototype.push = function() { + this._stack.push(null); +}; + +/** + * Discard the most recently-created name on the stack. + */ +NameStack.prototype.pop = function() { + this._stack.pop(); +}; + +/** + * Update the most recent name on the top of the stack. + * + * @param {object} token The token to consider as the source for the most + * recent name. + */ +NameStack.prototype.set = function(token) { + this._stack[this.length - 1] = token; +}; + +/** + * Generate a string representation of the most recent name. + * + * @returns {string} + */ +NameStack.prototype.infer = function() { + var nameToken = this._stack[this.length - 1]; + var prefix = ""; + var type; + + // During expected operation, the topmost entry on the stack will only + // reflect the current function's name when the function is declared without + // the `function` keyword (i.e. for in-line accessor methods). In other + // cases, the `function` expression itself will introduce an empty entry on + // the top of the stack, and this should be ignored. + if (!nameToken || nameToken.type === "class") { + nameToken = this._stack[this.length - 2]; + } + + if (!nameToken) { + return "(empty)"; + } + + type = nameToken.type; + + if (type !== "(string)" && type !== "(number)" && type !== "(identifier)" && type !== "default") { + return "(expression)"; + } + + if (nameToken.accessorType) { + prefix = nameToken.accessorType + " "; + } + + return prefix + nameToken.value; +}; + +module.exports = NameStack; + +},{}],"/../../jshint/src/options.js":[function(_dereq_,module,exports){ +"use strict"; + +// These are the JSHint boolean options. +exports.bool = { + enforcing: { + + /** + * This option prohibits the use of bitwise operators such as `^` (XOR), + * `|` (OR) and others. Bitwise operators are very rare in JavaScript + * programs and quite often `&` is simply a mistyped `&&`. + */ + bitwise : true, + + /** + * + * This options prohibits overwriting prototypes of native objects such as + * `Array`, `Date` and so on. + * + * // jshint freeze:true + * Array.prototype.count = function (value) { return 4; }; + * // -> Warning: Extending prototype of native object: 'Array'. + */ + freeze : true, + + /** + * This option allows you to force all variable names to use either + * camelCase style or UPPER_CASE with underscores. + * + * @deprecated JSHint is limiting its scope to issues of code correctness. + * If you would like to enforce rules relating to code style, + * check out [the JSCS + * project](https://github.com/jscs-dev/node-jscs). + */ + camelcase : true, + + /** + * This option requires you to always put curly braces around blocks in + * loops and conditionals. JavaScript allows you to omit curly braces when + * the block consists of only one statement, for example: + * + * while (day) + * shuffle(); + * + * However, in some circumstances, it can lead to bugs (you'd think that + * `sleep()` is a part of the loop while in reality it is not): + * + * while (day) + * shuffle(); + * sleep(); + */ + curly : true, + + /** + * This options prohibits the use of `==` and `!=` in favor of `===` and + * `!==`. The former try to coerce values before comparing them which can + * lead to some unexpected results. The latter don't do any coercion so + * they are generally safer. If you would like to learn more about type + * coercion in JavaScript, we recommend [Truth, Equality and + * JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/) + * by Angus Croll. + */ + eqeqeq : true, + + /** + * This option enables warnings about the use of identifiers which are + * defined in future versions of JavaScript. Although overwriting them has + * no effect in contexts where they are not implemented, this practice can + * cause issues when migrating codebases to newer versions of the language. + */ + futurehostile: true, + + /** + * This option tells JSHint that your code needs to adhere to ECMAScript 3 + * specification. Use this option if you need your program to be executable + * in older browsers—such as Internet Explorer 6/7/8/9—and other legacy + * JavaScript environments. + * + * @deprecated Use `esversion: 3` instead. + */ + es3 : true, + + /** + * This option enables syntax first defined in [the ECMAScript 5.1 + * specification](http://es5.github.io/). This includes allowing reserved + * keywords as object properties. + * + * @deprecated Use `esversion: 5` instead. + */ + es5 : true, + + /** + * This option requires all `for in` loops to filter object's items. The + * for in statement allows for looping through the names of all of the + * properties of an object including those inherited through the prototype + * chain. This behavior can lead to unexpected items in your object so it + * is generally safer to always filter inherited properties out as shown in + * the example: + * + * for (key in obj) { + * if (obj.hasOwnProperty(key)) { + * // We are sure that obj[key] belongs to the object and was not inherited. + * } + * } + * + * For more in-depth understanding of `for in` loops in JavaScript, read + * [Exploring JavaScript for-in + * loops](http://javascriptweblog.wordpress.com/2011/01/04/exploring-javascript-for-in-loops/) + * by Angus Croll. + */ + forin : true, + + /** + * This option prohibits the use of immediate function invocations without + * wrapping them in parentheses. Wrapping parentheses assists readers of + * your code in understanding that the expression is the result of a + * function, and not the function itself. + * + * @deprecated JSHint is limiting its scope to issues of code correctness. + * If you would like to enforce rules relating to code style, + * check out [the JSCS + * project](https://github.com/jscs-dev/node-jscs). + */ + immed : true, + + /** + * This option prohibits unnecessary clauses within `switch` statements, + * e.g. + * + * switch (x) { + * case 1: + * default: + * z(); + * } + * + * While clauses like these are techincally valid, they do not effect + * program behavior and may indicate an erroneous refactoring. + */ + leanswitch : true, + + /** + * This option requires you to capitalize names of constructor functions. + * Capitalizing functions that are intended to be used with `new` operator + * is just a convention that helps programmers to visually distinguish + * constructor functions from other types of functions to help spot + * mistakes when using `this`. + * + * Not doing so won't break your code in any browsers or environments but + * it will be a bit harder to figure out—by reading the code—if the + * function was supposed to be used with or without new. And this is + * important because when the function that was intended to be used with + * `new` is used without it, `this` will point to the global object instead + * of a new object. + * + * @deprecated JSHint is limiting its scope to issues of code correctness. + * If you would like to enforce rules relating to code style, + * check out [the JSCS + * project](https://github.com/jscs-dev/node-jscs). + */ + newcap : true, + + /** + * This option prohibits the use of `arguments.caller` and + * `arguments.callee`. Both `.caller` and `.callee` make quite a few + * optimizations impossible so they were deprecated in future versions of + * JavaScript. In fact, ECMAScript 5 forbids the use of `arguments.callee` + * in strict mode. + */ + noarg : true, + + /** + * This option prohibits the use of the comma operator. When misused, the + * comma operator can obscure the value of a statement and promote + * incorrect code. + */ + nocomma : true, + + /** + * This option warns when you have an empty block in your code. JSLint was + * originally warning for all empty blocks and we simply made it optional. + * There were no studies reporting that empty blocks in JavaScript break + * your code in any way. + * + * @deprecated JSHint is limiting its scope to issues of code correctness. + * If you would like to enforce rules relating to code style, + * check out [the JSCS + * project](https://github.com/jscs-dev/node-jscs). + */ + noempty : true, + + /** + * This option warns about "non-breaking whitespace" characters. These + * characters can be entered with option-space on Mac computers and have a + * potential of breaking non-UTF8 web pages. + */ + nonbsp : true, + + /** + * This option prohibits the use of constructor functions for side-effects. + * Some people like to call constructor functions without assigning its + * result to any variable: + * + * new MyConstructor(); + * + * There is no advantage in this approach over simply calling + * `MyConstructor` since the object that the operator `new` creates isn't + * used anywhere so you should generally avoid constructors like this one. + */ + nonew : true, + + + /** + * Async functions resolve on their return value. In most cases, this makes + * returning the result of an AwaitExpression (which is itself a Promise + * instance) unnecessary. For clarity, it's often preferable to return the + * result of the asynchronous operation directly. The notable exception is + * within the `try` clause of a TryStatement--for more, see "await vs + * return vs return await": + * + * https://jakearchibald.com/2017/await-vs-return-vs-return-await/ + */ + noreturnawait: true, + + /** + * This option enables warnings for regular expressions which do not + * include the "u" flag. The "u" flag extends support for Unicode and also + * enables more strict parsing rules. JSHint will enforce these rules even + * if it is executed in a JavaScript engine which does not support the "u" + * flag. + */ + regexpu : true, + + /** + * This option prohibits the use of explicitly undeclared variables. This + * option is very useful for spotting leaking and mistyped variables. + * + * // jshint undef:true + * + * function test() { + * var myVar = 'Hello, World'; + * console.log(myvar); // Oops, typoed here. JSHint with undef will complain + * } + * + * If your variable is defined in another file, you can use the `global` + * directive to tell JSHint about it. + */ + undef : true, + + /** + * This option prohibits the use of the grouping operator when it is not + * strictly required. Such usage commonly reflects a misunderstanding of + * unary operators, for example: + * + * // jshint singleGroups: true + * + * delete(obj.attr); // Warning: Unnecessary grouping operator. + */ + singleGroups: false, + + /** + * When set to true, the use of VariableStatements are forbidden. + * For example: + * + * // jshint varstmt: true + * + * var a; // Warning: `var` declarations are forbidden. Use `let` or `const` instead. + */ + varstmt: false, + + /** + * This option is a short hand for the most strict JSHint configuration as + * available in JSHint version 2.6.3. It enables all enforcing options and + * disables all relaxing options that were defined in that release. + * + * @deprecated The option cannot be maintained without automatically opting + * users in to new features. This can lead to unexpected + * warnings/errors in when upgrading between minor versions of + * JSHint. + */ + enforceall : false, + + /** + * This option warns when a comma is not placed after the last element in an + * array or object literal. Due to bugs in old versions of IE, trailing + * commas used to be discouraged, but since ES5 their semantics were + * standardized. (See + * [#11.1.4](http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.4) and + * [#11.1.5](http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5).) + * Now, they help to prevent the same [visual + * ambiguities](http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.2) + * that the strict usage of semicolons helps prevent. + * + * For example, this code might have worked last Tuesday: + * + * [ + * b + c + * ].forEach(print); + * + * But if one adds an element to the array and forgets to compensate for the + * missing comma, no syntax error is thrown, and a linter cannot determine + * if this was a mistake or an intentional function invocation. + * + * [ + * b + c + * (d + e) + * ].forEach(print); + * + * If one always appends a list item with a comma, this ambiguity cannot + * occur: + * + * [ + * b + c, + * ].forEach(print); + * + * [ + * b + c, + * (d + e), + * ].forEach(print); + */ + trailingcomma: false + }, + relaxing: { + + /** + * This option suppresses warnings about missing semicolons. There is a lot + * of FUD about semicolon spread by quite a few people in the community. + * The common myths are that semicolons are required all the time (they are + * not) and that they are unreliable. JavaScript has rules about semicolons + * which are followed by *all* browsers so it is up to you to decide + * whether you should or should not use semicolons in your code. + * + * For more information about semicolons in JavaScript read [An Open Letter + * to JavaScript Leaders Regarding + * Semicolons](http://blog.izs.me/post/2353458699/an-open-letter-to-javascript-leaders-regarding) + * by Isaac Schlueter and [JavaScript Semicolon + * Insertion](http://inimino.org/~inimino/blog/javascript_semicolons). + */ + asi : true, + + /** + * This option suppresses warnings about multi-line strings. Multi-line + * strings can be dangerous in JavaScript because all hell breaks loose if + * you accidentally put a whitespace in between the escape character (`\`) + * and a new line. + * + * Note that even though this option allows correct multi-line strings, it + * still warns about multi-line strings without escape characters or with + * anything in between the escape character and a whitespace. + * + * // jshint multistr:true + * + * var text = "Hello\ + * World"; // All good. + * + * text = "Hello + * World"; // Warning, no escape character. + * + * text = "Hello\ + * World"; // Warning, there is a space after \ + * + * @deprecated JSHint is limiting its scope to issues of code correctness. + * If you would like to enforce rules relating to code style, + * check out [the JSCS + * project](https://github.com/jscs-dev/node-jscs). + */ + multistr : true, + + /** + * This option suppresses warnings about the `debugger` statements in your + * code. + */ + debug : true, + + /** + * This option suppresses warnings about the use of assignments in cases + * where comparisons are expected. More often than not, code like `if (a = + * 10) {}` is a typo. However, it can be useful in cases like this one: + * + * for (var i = 0, person; person = people[i]; i++) {} + * + * You can silence this error on a per-use basis by surrounding the assignment + * with parenthesis, such as: + * + * for (var i = 0, person; (person = people[i]); i++) {} + */ + boss : true, + + /** + * This option suppresses warnings about the use of `eval`. The use of + * `eval` is discouraged because it can make your code vulnerable to + * various injection attacks and it makes it hard for JavaScript + * interpreter to do certain optimizations. + */ + evil : true, + + /** + * This option suppresses warnings about declaring variables inside + * of control structures while accessing them later from the outside. + * Even though identifiers declared with `var` have two real scopes—global + * and function—such practice leads to confusion among people new to + * the language and hard-to-debug bugs. This is why, by default, JSHint + * warns about variables that are used outside of their intended scope. + * + * function test() { + * if (true) { + * var x = 0; + * } + * + * x += 1; // Default: 'x' used out of scope. + * // No warning when funcscope:true + * } + */ + funcscope : true, + + /** + * This option suppresses warnings about the use of global strict mode. + * Global strict mode can break third-party widgets so it is not + * recommended. + * + * For more info about strict mode see the `strict` option. + * + * @deprecated Use `strict: "global"`. + */ + globalstrict: true, + + /** + * This option suppresses warnings about the `__iterator__` property. This + * property is not supported by all browsers so use it carefully. + */ + iterator : true, + + /** + * This option suppresses warnings about invalid `typeof` operator values. + * This operator has only [a limited set of possible return + * values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof). + * By default, JSHint warns when you compare its result with an invalid + * value which often can be a typo. + * + * // 'fuction' instead of 'function' + * if (typeof a == "fuction") { // Invalid typeof value 'fuction' + * // ... + * } + * + * Do not use this option unless you're absolutely sure you don't want + * these checks. + */ + notypeof : true, + + /** + * This option prohibits the use of unary increment and decrement + * operators. Some people think that `++` and `--` reduces the quality of + * their coding styles and there are programming languages—such as + * Python—that go completely without these operators. + */ + plusplus : true, + + /** + * This option suppresses warnings about the `__proto__` property. + */ + proto : true, + + /** + * This option suppresses warnings about the use of script-targeted + * URLs—such as `javascript:...`. + */ + scripturl : true, + + /** + * This option suppresses warnings about using `[]` notation when it can be + * expressed in dot notation: `person['name']` vs. `person.name`. + * + * @deprecated JSHint is limiting its scope to issues of code correctness. + * If you would like to enforce rules relating to code style, + * check out [the JSCS + * project](https://github.com/jscs-dev/node-jscs). + */ + sub : true, + + /** + * This option suppresses warnings about "weird" constructions like + * `new function () { ... }` and `new Object;`. Such constructions are + * sometimes used to produce singletons in JavaScript: + * + * var singleton = new function() { + * var privateVar; + * + * this.publicMethod = function () {} + * this.publicMethod2 = function () {} + * }; + */ + supernew : true, + + /** + * This option suppresses most of the warnings about possibly unsafe line + * breakings in your code. It doesn't suppress warnings about comma-first + * coding style. To suppress those you have to use `laxcomma` (see below). + * + * @deprecated JSHint is limiting its scope to issues of code correctness. + * If you would like to enforce rules relating to code style, + * check out [the JSCS + * project](https://github.com/jscs-dev/node-jscs). + */ + laxbreak : true, + + /** + * This option suppresses warnings about comma-first coding style: + * + * var obj = { + * name: 'Anton' + * , handle: 'valueof' + * , role: 'SW Engineer' + * }; + * + * @deprecated JSHint is limiting its scope to issues of code correctness. + * If you would like to enforce rules relating to code style, + * check out [the JSCS + * project](https://github.com/jscs-dev/node-jscs). + */ + laxcomma : true, + + /** + * This option suppresses warnings about possible strict violations when + * the code is running in strict mode and you use `this` in a + * non-constructor function. You should use this option—in a function scope + * only—when you are positive that your use of `this` is valid in the + * strict mode (for example, if you call your function using + * `Function.call`). + * + * **Note:** This option can be used only inside of a function scope. + * JSHint will fail with an error if you will try to set this option + * globally. + */ + validthis : true, + + /** + * This option suppresses warnings about the use of the `with` statement. + * The semantics of the `with` statement can cause confusion among + * developers and accidental definition of global variables. + * + * More info: + * + * * [with Statement Considered + * Harmful](http://yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/) + */ + withstmt : true, + + /** + * This options tells JSHint that your code uses Mozilla JavaScript + * extensions. Unless you develop specifically for the Firefox web browser + * you don't need this option. + * + * More info: + * + * * [New in JavaScript + * 1.7](https://developer.mozilla.org/en-US/docs/JavaScript/New_in_JavaScript/1.7) + */ + moz : true, + + /** + * This option suppresses warnings about generator functions with no + * `yield` statement in them. + */ + noyield : true, + + /** + * This option suppresses warnings about `== null` comparisons. Such + * comparisons are often useful when you want to check if a variable is + * `null` or `undefined`. + */ + eqnull : true, + + /** + * This option suppresses warnings about missing semicolons, but only when + * the semicolon is omitted for the last statement in a one-line block: + * + * var name = (function() { return 'Anton' }()); + * + * This is a very niche use case that is useful only when you use automatic + * JavaScript code generators. + */ + lastsemic : true, + + /** + * This option suppresses warnings about functions inside of loops. + * Defining functions inside of loops can lead to bugs such as this one: + * + * var nums = []; + * + * for (var i = 0; i < 10; i++) { + * nums[i] = function (j) { + * return i + j; + * }; + * } + * + * nums[0](2); // Prints 12 instead of 2 + * + * To fix the code above you need to copy the value of `i`: + * + * var nums = []; + * + * for (var i = 0; i < 10; i++) { + * (function (i) { + * nums[i] = function (j) { + * return i + j; + * }; + * }(i)); + * } + */ + loopfunc : true, + + /** + * This option suppresses warnings about the use of expressions where + * normally you would expect to see assignments or function calls. Most of + * the time, such code is a typo. However, it is not forbidden by the spec + * and that's why this warning is optional. + */ + expr : true, + + /** + * This option tells JSHint that your code uses ECMAScript 6 specific + * syntax. Note that not all browsers implement these features. + * + * More info: + * + * * [Specification for ECMAScript + * 6](http://www.ecma-international.org/ecma-262/6.0/index.html) + * + * @deprecated Use `esversion: 6` instead. + */ + esnext : true, + + /** + * This option tells JSHint that your code uses ES3 array elision elements, + * or empty elements (for example, `[1, , , 4, , , 7]`). + */ + elision : true, + }, + + // Third party globals + environments: { + + /** + * This option defines globals exposed by the + * [MooTools](http://mootools.net/) JavaScript framework. + */ + mootools : true, + + /** + * This option defines globals exposed by + * [CouchDB](http://couchdb.apache.org/). CouchDB is a document-oriented + * database that can be queried and indexed in a MapReduce fashion using + * JavaScript. + */ + couch : true, + + /** + * This option defines globals exposed by [the Jasmine unit testing + * framework](https://jasmine.github.io/). + */ + jasmine : true, + + /** + * This option defines globals exposed by the [jQuery](http://jquery.com/) + * JavaScript library. + */ + jquery : true, + + /** + * This option defines globals available when your code is running inside + * of the Node runtime environment. [Node.js](http://nodejs.org/) is a + * server-side JavaScript environment that uses an asynchronous + * event-driven model. This option also skips some warnings that make sense + * in the browser environments but don't make sense in Node such as + * file-level `use strict` pragmas and `console.log` statements. + */ + node : true, + + /** + * This option defines globals exposed by [the QUnit unit testing + * framework](http://qunitjs.com/). + */ + qunit : true, + + /** + * This option defines globals available when your code is running inside + * of the Rhino runtime environment. [Rhino](http://www.mozilla.org/rhino/) + * is an open-source implementation of JavaScript written entirely in Java. + */ + rhino : true, + + /** + * This option defines globals exposed by [the ShellJS + * library](http://documentup.com/arturadib/shelljs). + */ + shelljs : true, + + /** + * This option defines globals exposed by the + * [Prototype](http://www.prototypejs.org/) JavaScript framework. + */ + prototypejs : true, + + /** + * This option defines globals exposed by the [YUI](http://yuilibrary.com/) + * JavaScript framework. + */ + yui : true, + + /** + * This option defines globals exposed by the "BDD" and "TDD" UIs of the + * [Mocha unit testing framework](http://mochajs.org/). + */ + mocha : true, + + /** + * This option informs JSHint that the input code describes an ECMAScript 6 + * module. All module code is interpreted as strict mode code. + */ + module : true, + + /** + * This option defines globals available when your code is running as a + * script for the [Windows Script + * Host](http://en.wikipedia.org/wiki/Windows_Script_Host). + */ + wsh : true, + + /** + * This option defines globals available when your code is running inside + * of a Web Worker. [Web + * Workers](https://developer.mozilla.org/en/Using_web_workers) provide a + * simple means for web content to run scripts in background threads. + */ + worker : true, + + /** + * This option defines non-standard but widely adopted globals such as + * `escape` and `unescape`. + */ + nonstandard : true, + + /** + * This option defines globals exposed by modern browsers: all the way from + * good old `document` and `navigator` to the HTML5 `FileReader` and other + * new developments in the browser world. + * + * **Note:** This option doesn't expose variables like `alert` or + * `console`. See option `devel` for more information. + */ + browser : true, + + /** + * This option defines globals available when using [the Browserify + * tool](http://browserify.org/) to build a project. + */ + browserify : true, + + /** + * This option defines globals that are usually used for logging poor-man's + * debugging: `console`, `alert`, etc. It is usually a good idea to not + * ship them in production because, for example, `console.log` breaks in + * legacy versions of Internet Explorer. + */ + devel : true, + + /** + * This option defines globals exposed by the [Dojo + * Toolkit](http://dojotoolkit.org/). + */ + dojo : true, + + /** + * This option defines globals for typed array constructors. + * + * More info: + * + * * [JavaScript typed + * arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays) + */ + typed : true, + + /** + * This option defines globals available when your core is running inside + * of the PhantomJS runtime environment. [PhantomJS](http://phantomjs.org/) + * is a headless WebKit scriptable with a JavaScript API. It has fast and + * native support for various web standards: DOM handling, CSS selector, + * JSON, Canvas, and SVG. + */ + phantom : true + }, + + // Obsolete options + obsolete: { + onecase : true, // if one case switch statements should be allowed + regexp : true, // if the . should not be allowed in regexp literals + regexdash : true // if unescaped first/last dash (-) inside brackets + // should be tolerated + } +}; + +// These are the JSHint options that can take any value +// (we use this object to detect invalid options) +exports.val = { + + /** + * This option lets you set the maximum length of a line. + * + * @deprecated JSHint is limiting its scope to issues of code correctness. If + * you would like to enforce rules relating to code style, check + * out [the JSCS project](https://github.com/jscs-dev/node-jscs). + */ + maxlen : false, + + /** + * This option sets a specific tab width for your code. + * + * @deprecated JSHint is limiting its scope to issues of code correctness. If + * you would like to enforce rules relating to code style, check + * out [the JSCS project](https://github.com/jscs-dev/node-jscs). + */ + indent : false, + + /** + * This options allows you to set the maximum amount of warnings JSHint will + * produce before giving up. Default is 50. + */ + maxerr : false, + + /** + * This option allows you to control which variables JSHint considers to be + * implicitly defined in the environment. Configure it with an array of + * string values. Prefixing a variable name with a hyphen (-) character will + * remove that name from the collection of predefined variables. + * + * JSHint will consider variables declared in this way to be read-only. + * + * This option cannot be specified in-line; it may only be used via the + * JavaScript API or from an external configuration file. + */ + predef : false, + + /** + * This option can be used to specify a white list of global variables that + * are not formally defined in the source code. This is most useful when + * combined with the `undef` option in order to suppress warnings for + * project-specific global variables. + * + * Setting an entry to `true` enables reading and writing to that variable. + * Setting it to `false` will trigger JSHint to consider that variable + * read-only. + * + * See also the "environment" options: a set of options to be used as short + * hand for enabling global variables defined in common JavaScript + * environments. + * + * To configure `globals` within an individual file, see [Inline + * Configuration](http://jshint.com/docs/#inline-configuration). + */ + globals : false, + + /** + * This option enforces the consistency of quotation marks used throughout + * your code. It accepts three values: `true` if you don't want to enforce + * one particular style but want some consistency, `"single"` if you want to + * allow only single quotes and `"double"` if you want to allow only double + * quotes. + * + * @deprecated JSHint is limiting its scope to issues of code correctness. If + * you would like to enforce rules relating to code style, check + * out [the JSCS project](https://github.com/jscs-dev/node-jscs). + */ + quotmark : false, + + scope : false, + + /** + * This option lets you set the max number of statements allowed per function: + * + * // jshint maxstatements:4 + * + * function main() { + * var i = 0; + * var j = 0; + * + * // Function declarations count as one statement. Their bodies + * // don't get taken into account for the outer function. + * function inner() { + * var i2 = 1; + * var j2 = 1; + * + * return i2 + j2; + * } + * + * j = i + j; + * return j; // JSHint: Too many statements per function. (5) + * } + */ + maxstatements: false, + + /** + * This option lets you control how nested do you want your blocks to be: + * + * // jshint maxdepth:2 + * + * function main(meaning) { + * var day = true; + * + * if (meaning === 42) { + * while (day) { + * shuffle(); + * + * if (tired) { // JSHint: Blocks are nested too deeply (3). + * sleep(); + * } + * } + * } + * } + */ + maxdepth : false, + + /** + * This option lets you set the max number of formal parameters allowed per + * function: + * + * // jshint maxparams:3 + * + * function login(request, onSuccess) { + * // ... + * } + * + * // JSHint: Too many parameters per function (4). + * function logout(request, isManual, whereAmI, onSuccess) { + * // ... + * } + */ + maxparams : false, + + /** + * This option lets you control cyclomatic complexity throughout your code. + * Cyclomatic complexity measures the number of linearly independent paths + * through a program's source code. Read more about [cyclomatic complexity on + * Wikipedia](http://en.wikipedia.org/wiki/Cyclomatic_complexity). + */ + maxcomplexity: false, + + /** + * This option suppresses warnings about variable shadowing i.e. declaring a + * variable that had been already declared somewhere in the outer scope. + * + * - "inner" - check for variables defined in the same scope only + * - "outer" - check for variables defined in outer scopes as well + * - false - same as inner + * - true - allow variable shadowing + */ + shadow : false, + + /** + * This option requires the code to run in ECMAScript 5's strict mode. + * [Strict mode](https://developer.mozilla.org/en/JavaScript/Strict_mode) + * is a way to opt in to a restricted variant of JavaScript. Strict mode + * eliminates some JavaScript pitfalls that didn't cause errors by changing + * them to produce errors. It also fixes mistakes that made it difficult + * for the JavaScript engines to perform certain optimizations. + * + * - "global" - there must be a `"use strict";` directive at global level + * - "implied" - lint the code as if there is the `"use strict";` directive + * - false - disable warnings about strict mode + * - true - there must be a `"use strict";` directive at function level; + * this is preferable for scripts intended to be loaded in web + * browsers directly because enabling strict mode globally + * could adversely effect other scripts running on the same + * page + */ + strict : true, + + /** + * This option warns when you define and never use your variables. It is very + * useful for general code cleanup, especially when used in addition to + * `undef`. + * + * // jshint unused:true + * + * function test(a, b) { + * var c, d = 2; + * + * return a + d; + * } + * + * test(1, 2); + * + * // Line 3: 'b' was defined but never used. + * // Line 4: 'c' was defined but never used. + * + * In addition to that, this option will warn you about unused global + * variables declared via the `global` directive. + * + * When set to `true`, unused parameters that are followed by a used + * parameter will not produce warnings. This option can be set to `vars` to + * only check for variables, not function parameters, or `strict` to check + * all variables and parameters. + */ + unused : true, + + /** + * This option prohibits the use of a variable before it was defined. + * JavaScript has function scope only and, in addition to that, all variables + * are always moved—or hoisted— to the top of the function. This behavior can + * lead to some very nasty bugs and that's why it is safer to always use + * variable only after they have been explicitly defined. + * + * Setting this option to "nofunc" will allow function declarations to be + * ignored. + * + * For more in-depth understanding of scoping and hoisting in JavaScript, + * read [JavaScript Scoping and + * Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) + * by Ben Cherry. + */ + latedef : false, + + ignore : false, // start/end ignoring lines of code, bypassing the lexer + // start - start ignoring lines, including the current line + // end - stop ignoring lines, starting on the next line + // line - ignore warnings / errors for just a single line + // (this option does not bypass the lexer) + + ignoreDelimiters: false, // array of start/end delimiters used to ignore + // certain chunks from code + + /** + * This option is used to specify the ECMAScript version to which the code + * must adhere. It can assume one of the following values: + * - `3` - If you need your program to be executable + * in older browsers—such as Internet Explorer 6/7/8/9—and other legacy + * JavaScript environments + * - `5` - To enable syntax first defined in [the ECMAScript 5.1 + * specification](http://www.ecma-international.org/ecma-262/5.1/index.html). + * This includes allowing reserved keywords as object properties. + * - `6` - To tell JSHint that your code uses [ECMAScript + * 6](http://www.ecma-international.org/ecma-262/6.0/index.html) specific + * syntax. Note that not all browsers implement them. + * - `7` - To enable language features introduced by [ECMAScript + * 7](https://www.ecma-international.org/ecma-262/7.0/index.html). Notable + * additions: the exponentiation operator. + * - `8` - To enable language features introduced by [ECMAScript + * 8](https://www.ecma-international.org/ecma-262/8.0/index.html). Notable + * additions: async functions, shared memory, and atomics + * - `9` - To enable language features introduced by [ECMAScript + * 9](https://www.ecma-international.org/ecma-262/9.0/index.html). Notable + * additions: asynchronous iteration, rest/spread properties, and various + * RegExp extensions + * - `10` - To enable language features introduced by ECMAScript + * 10](https://www.ecma-international.org/ecma-262/10.0/index.html). + * Notable additions: optional catch bindings. + */ + esversion: 5 +}; + +/** + * Unstable options allow control for parsing and linting of proposed additions + * to the JavaScript language. Just like the language features they describe, + * the presence and behavior of these options is volatile; JSHint reserves the + * right to remove or modify them between major version releases. + */ +exports.unstable = { + /** + * [The BigInt proposal](https://github.com/tc39/proposal-bigint) extends the + * language's grammer for numeric literals to support integer values of + * arbitrary precision. It also introduces a new value of the `typeof` + * operator, "bigint". + * + * Mathematical operations which use both BigInt and traditional ECMAScript + * Number values may not have the intended effect. Due to the weakly-typed + * nature of the language, JSHint is unable to identify such cases. + */ + bigint: true +}; + +// These are JSHint boolean options which are shared with JSLint +// where the definition in JSHint is opposite JSLint +exports.inverted = { + bitwise : true, + forin : true, + newcap : true, + plusplus: true, + regexp : true, + undef : true, + + // Inverted and renamed, use JSHint name here + eqeqeq : true, + strict : true +}; + +exports.validNames = Object.keys(exports.val) + .concat(Object.keys(exports.bool.relaxing)) + .concat(Object.keys(exports.bool.enforcing)) + .concat(Object.keys(exports.bool.obsolete)) + .concat(Object.keys(exports.bool.environments)) + .concat(["unstable"]); + +exports.unstableNames = Object.keys(exports.unstable); + +// These are JSHint boolean options which are shared with JSLint +// where the name has been changed but the effect is unchanged +exports.renamed = { + eqeq : "eqeqeq", + windows: "wsh", + sloppy : "strict" +}; + +exports.removed = { + nomen: true, + onevar: true, + passfail: true, + white: true, + gcl: true, + smarttabs: true, + trailing: true +}; + +// Add options here which should not be automatically enforced by +// `enforceall`. +exports.noenforceall = { + varstmt: true, + strict: true, + regexpu: true +}; + +},{}],"/../../jshint/src/prod-params.js":[function(_dereq_,module,exports){ +/** + * This module defines a set of enum-like values intended for use as bit + * "flags" during parsing. The ECMAScript grammar defines a number of such + * "production parameters" to control how certain forms are parsed in context. + * JSHint implements additional parameters to facilitate detection of lint + * warnings. + * + * An equivalent implementation which described the context in terms of a + * "lookup table" object would be more idiomatic for a JavaScript project like + * JSHint. However, because the number of contexts scales with the number of + * expressions in the input program, this would have non-negligible impact on + * the process's memory footprint. + */ +module.exports = { + /** + * Enabled when parsing expressions within ES2015 "export" declarations, + * allowing otherwise-unreferenced bindings to be considered "used". + */ + export: 1, + + /** + * Enabled when parsing expressions within the head of `for` statements, + * allowing to distinguish between `for-in` and "C-style" `for` statements. + */ + noin: 2, + + /** + * Enabled when the expression begins the statement, allowing the parser to + * correctly select between the null denotation ("nud") and first null + * denotation ("fud") parsing strategy. + */ + initial: 4, + + preAsync: 8, + + async: 16, + + /** + * Enabled when any exception thrown by the expression will be caught by a + * TryStatement. + */ + tryClause: 32, + + /** + * Enabled when parsing the body of a generator function. + */ + yield: 64 +}; + +},{}],"/../../jshint/src/reg.js":[function(_dereq_,module,exports){ +/* + * Regular expressions. Some of these are stupidly long. + */ + +/*jshint maxlen:1000 */ + +"use strict"; + +// Unsafe comment or string (ax) +exports.unsafeString = + /@cc|<\/?|script|\]\s*\]|<\s*!|</i; + +// Characters in strings that need escaping (nx and nxg) +exports.needEsc = + /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; + +exports.needEscGlobal = + /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + +// Star slash (lx) +exports.starSlash = /\*\//; + +// Identifier (ix) +exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; + +// JavaScript URL (jx) +exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i; + +// Catches /* falls through */ comments (ft) +exports.fallsThrough = /^\s*falls?\sthrough\s*$/; + +// very conservative rule (eg: only one space between the start of the comment and the first character) +// to relax the maxlen option +exports.maxlenException = /^(?:(?:\/\/|\/\*|\*) ?)?[^ ]+$/; + +// Node.js releases prior to version 8 include a version of the V8 engine which +// incorrectly interprets the character class escape `\s`. The following +// regular expression may be replaced with `/\s/` when JSHint removes support +// for Node.js versions prior to 8. +// Source: +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp +exports.whitespace = /[ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/; + +exports.nonzeroDigit = /^[1-9]$/; + +exports.decimalDigit = /^[0-9]$/; + +exports.regexpSyntaxChars = /[\^$\\.*+?()[\]{}|]/; + +exports.regexpQuantifiers = /[*+?{]/; + +exports.regexpControlEscapes = /[fnrtv]/; + +exports.regexpCharClasses = /[dDsSwW]/; + +// Identifies the "dot" atom in regular expressions +exports.regexpDot = /(^|[^\\])(\\\\)*\./; + +},{}],"/../../jshint/src/scope-manager.js":[function(_dereq_,module,exports){ +"use strict"; + +var _ = _dereq_("underscore"); +_.slice = _dereq_("lodash.slice"); +var events = _dereq_("events"); + +// Used to denote membership in lookup tables (a primitive value such as `true` +// would be silently rejected for the property name "__proto__" in some +// environments) +var marker = {}; + +/** + * A factory function for creating scope managers. A scope manager tracks + * bindings, detecting when variables are referenced (through "usages"). + * + * @param {object} state - the global state object (see `state.js`) + * @param {Array} predefined - a set of binding names for built-in bindings + * provided by the environment + * @param {object} exported - a hash for binding names that are intended to be + * referenced in contexts beyond the current program + * code + * @param {object} declared - a hash for binding names that were defined as + * global bindings via linting configuration + * + * @returns {object} - a scope manager + */ +var scopeManager = function(state, predefined, exported, declared) { + + var _current; + var _scopeStack = []; + + function _newScope(type) { + _current = { + "(bindings)": Object.create(null), + "(usages)": Object.create(null), + "(labels)": Object.create(null), + "(parent)": _current, + "(type)": type, + "(params)": (type === "functionparams" || type === "catchparams") ? [] : null + }; + _scopeStack.push(_current); + } + + _newScope("global"); + _current["(predefined)"] = predefined; + + var _currentFunctBody = _current; // this is the block after the params = function + + var usedPredefinedAndGlobals = Object.create(null); + var impliedGlobals = Object.create(null); + var unuseds = []; + var emitter = new events.EventEmitter(); + + function warning(code, token) { + emitter.emit("warning", { + code: code, + token: token, + data: _.slice(arguments, 2) + }); + } + + function error(code, token) { + emitter.emit("warning", { + code: code, + token: token, + data: _.slice(arguments, 2) + }); + } + + function _setupUsages(bindingName) { + if (!_current["(usages)"][bindingName]) { + _current["(usages)"][bindingName] = { + "(modified)": [], + "(reassigned)": [], + "(tokens)": [] + }; + } + } + + var _getUnusedOption = function(unused_opt) { + if (unused_opt === undefined) { + unused_opt = state.option.unused; + } + + if (unused_opt === true) { + unused_opt = "last-param"; + } + + return unused_opt; + }; + + var _warnUnused = function(name, tkn, type, unused_opt) { + var line = tkn.line; + var chr = tkn.from; + var raw_name = tkn.raw_text || name; + + unused_opt = _getUnusedOption(unused_opt); + + var warnable_types = { + "vars": ["var"], + "last-param": ["var", "param"], + "strict": ["var", "param", "last-param"] + }; + + if (unused_opt) { + if (warnable_types[unused_opt] && warnable_types[unused_opt].indexOf(type) !== -1) { + warning("W098", { line: line, from: chr }, raw_name); + } + } + + // inconsistent - see gh-1894 + if (unused_opt || type === "var") { + unuseds.push({ + name: name, + line: line, + character: chr + }); + } + }; + + /** + * Check the current scope for unused identifiers + */ + function _checkForUnused() { + // function parameters are validated by a dedicated function + // assume that parameters are the only thing declared in the param scope + if (_current["(type)"] === "functionparams") { + _checkParams(); + return; + } + var currentBindings = _current["(bindings)"]; + for (var bindingName in currentBindings) { + if (currentBindings[bindingName]["(type)"] !== "exception" && + currentBindings[bindingName]["(unused)"]) { + _warnUnused(bindingName, currentBindings[bindingName]["(token)"], "var"); + } + } + } + + /** + * Check the current scope for unused parameters and issue warnings as + * necessary. This function may only be invoked when the current scope is a + * "function parameter" scope. + */ + function _checkParams() { + var params = _current["(params)"]; + + if (!params) { + /* istanbul ignore next */ + return; + } + + var param = params.pop(); + var unused_opt; + + while (param) { + var binding = _current["(bindings)"][param]; + + unused_opt = _getUnusedOption(state.funct["(unusedOption)"]); + + // 'undefined' is a special case for the common pattern where `undefined` + // is used as a formal parameter name to defend against global + // re-assignment, e.g. + // + // (function(window, undefined) { + // })(); + if (param === "undefined") + return; + + if (binding["(unused)"]) { + _warnUnused(param, binding["(token)"], "param", state.funct["(unusedOption)"]); + } else if (unused_opt === "last-param") { + return; + } + + param = params.pop(); + } + } + + /** + * Find the relevant binding's scope. The owning scope is located by first + * inspecting the current scope and then moving "downward" through the stack + * of scopes. + * + * @param {string} bindingName - the value of the identifier + * + * @returns {Object} - the scope in which the binding was found + */ + function _getBinding(bindingName) { + for (var i = _scopeStack.length - 1 ; i >= 0; --i) { + var scopeBindings = _scopeStack[i]["(bindings)"]; + if (scopeBindings[bindingName]) { + return scopeBindings; + } + } + } + + /** + * Determine if a given binding name has been referenced within the current + * function or any function defined within. + * + * @param {string} bindingName - the value of the identifier + * + * @returns {boolean} + */ + function usedSoFarInCurrentFunction(bindingName) { + for (var i = _scopeStack.length - 1; i >= 0; i--) { + var current = _scopeStack[i]; + if (current["(usages)"][bindingName]) { + return current["(usages)"][bindingName]; + } + if (current === _currentFunctBody) { + break; + } + } + return false; + } + + function _checkOuterShadow(bindingName, token) { + + // only check if shadow is outer + if (state.option.shadow !== "outer") { + return; + } + + var isGlobal = _currentFunctBody["(type)"] === "global", + isNewFunction = _current["(type)"] === "functionparams"; + + var outsideCurrentFunction = !isGlobal; + for (var i = 0; i < _scopeStack.length; i++) { + var stackItem = _scopeStack[i]; + + if (!isNewFunction && _scopeStack[i + 1] === _currentFunctBody) { + outsideCurrentFunction = false; + } + if (outsideCurrentFunction && stackItem["(bindings)"][bindingName]) { + warning("W123", token, bindingName); + } + if (stackItem["(labels)"][bindingName]) { + warning("W123", token, bindingName); + } + } + } + + function _latedefWarning(type, bindingName, token) { + var isFunction; + + if (state.option.latedef) { + isFunction = type === "function" || type === "generator function" || + type === "async function"; + + // if either latedef is strict and this is a function + // or this is not a function + if ((state.option.latedef === true && isFunction) || !isFunction) { + warning("W003", token, bindingName); + } + } + } + + var scopeManagerInst = { + + on: function(names, listener) { + names.split(" ").forEach(function(name) { + emitter.on(name, listener); + }); + }, + + isPredefined: function(bindingName) { + return !this.has(bindingName) && _.has(_scopeStack[0]["(predefined)"], bindingName); + }, + + /** + * Create a new scope within the current scope. As the topmost value, the + * new scope will be interpreted as the current scope until it is + * exited--see the `unstack` method. + * + * @param {string} [type] - The type of the scope. Valid values are + * "functionparams", "catchparams" and + * "functionouter" + */ + stack: function(type) { + var previousScope = _current; + _newScope(type); + + if (!type && previousScope["(type)"] === "functionparams") { + + _current["(isFuncBody)"] = true; + _currentFunctBody = _current; + } + }, + + /** + * Valldate all binding references and declarations in the current scope + * and set the next scope on the stack as the active scope. + */ + unstack: function() { + // jshint proto: true + var subScope = _scopeStack.length > 1 ? _scopeStack[_scopeStack.length - 2] : null; + var isUnstackingFunctionBody = _current === _currentFunctBody, + isUnstackingFunctionParams = _current["(type)"] === "functionparams", + isUnstackingFunctionOuter = _current["(type)"] === "functionouter"; + + var i, j, isImmutable, isFunction; + var currentUsages = _current["(usages)"]; + var currentBindings = _current["(bindings)"]; + var usedBindingNameList = Object.keys(currentUsages); + + /* istanbul ignore if */ + if (currentUsages.__proto__ && usedBindingNameList.indexOf("__proto__") === -1) { + usedBindingNameList.push("__proto__"); + } + + for (i = 0; i < usedBindingNameList.length; i++) { + var usedBindingName = usedBindingNameList[i]; + + var usage = currentUsages[usedBindingName]; + var usedBinding = currentBindings[usedBindingName]; + if (usedBinding) { + var usedBindingType = usedBinding["(type)"]; + isImmutable = usedBindingType === "const" || usedBindingType === "import"; + + if (usedBinding["(useOutsideOfScope)"] && !state.option.funcscope) { + var usedTokens = usage["(tokens)"]; + for (j = 0; j < usedTokens.length; j++) { + // Keep the consistency of https://github.com/jshint/jshint/issues/2409 + if (usedBinding["(function)"] === usedTokens[j]["(function)"]) { + error("W038", usedTokens[j], usedBindingName); + } + } + } + + // mark the binding used + _current["(bindings)"][usedBindingName]["(unused)"] = false; + + // check for modifying a const + if (isImmutable && usage["(modified)"]) { + for (j = 0; j < usage["(modified)"].length; j++) { + error("E013", usage["(modified)"][j], usedBindingName); + } + } + + isFunction = usedBindingType === "function" || + usedBindingType === "generator function" || + usedBindingType === "async function"; + + // check for re-assigning a function declaration + if ((isFunction || usedBindingType === "class") && usage["(reassigned)"]) { + for (j = 0; j < usage["(reassigned)"].length; j++) { + if (!usage["(reassigned)"][j].ignoreW021) { + warning("W021", usage["(reassigned)"][j], usedBindingName, usedBindingType); + } + } + } + continue; + } + + if (subScope) { + var bindingType = this.bindingtype(usedBindingName); + isImmutable = bindingType === "const" || + (bindingType === null && _scopeStack[0]["(predefined)"][usedBindingName] === false); + if (isUnstackingFunctionOuter && !isImmutable) { + if (!state.funct["(outerMutables)"]) { + state.funct["(outerMutables)"] = []; + } + state.funct["(outerMutables)"].push(usedBindingName); + } + + // not exiting the global scope, so copy the usage down in case its an out of scope usage + if (!subScope["(usages)"][usedBindingName]) { + subScope["(usages)"][usedBindingName] = usage; + if (isUnstackingFunctionBody) { + subScope["(usages)"][usedBindingName]["(onlyUsedSubFunction)"] = true; + } + } else { + var subScopeUsage = subScope["(usages)"][usedBindingName]; + subScopeUsage["(modified)"] = subScopeUsage["(modified)"].concat(usage["(modified)"]); + subScopeUsage["(tokens)"] = subScopeUsage["(tokens)"].concat(usage["(tokens)"]); + subScopeUsage["(reassigned)"] = + subScopeUsage["(reassigned)"].concat(usage["(reassigned)"]); + } + } else { + // this is exiting global scope, so we finalise everything here - we are at the end of the file + if (typeof _current["(predefined)"][usedBindingName] === "boolean") { + + // remove the declared token, so we know it is used + delete declared[usedBindingName]; + + // note it as used so it can be reported + usedPredefinedAndGlobals[usedBindingName] = marker; + + // check for re-assigning a read-only (set to false) predefined + if (_current["(predefined)"][usedBindingName] === false && usage["(reassigned)"]) { + for (j = 0; j < usage["(reassigned)"].length; j++) { + if (!usage["(reassigned)"][j].ignoreW020) { + warning("W020", usage["(reassigned)"][j]); + } + } + } + } + else { + // binding usage is not predefined and we have not found a declaration + // so report as undeclared + for (j = 0; j < usage["(tokens)"].length; j++) { + var undefinedToken = usage["(tokens)"][j]; + // if its not a forgiven undefined (e.g. typof x) + if (!undefinedToken.forgiveUndef) { + // if undef is on and undef was on when the token was defined + if (state.option.undef && !undefinedToken.ignoreUndef) { + warning("W117", undefinedToken, usedBindingName); + } + if (impliedGlobals[usedBindingName]) { + impliedGlobals[usedBindingName].line.push(undefinedToken.line); + } else { + impliedGlobals[usedBindingName] = { + name: usedBindingName, + line: [undefinedToken.line] + }; + } + } + } + } + } + } + + // if exiting the global scope, we can warn about declared globals that haven't been used yet + if (!subScope) { + Object.keys(declared) + .forEach(function(bindingNotUsed) { + _warnUnused(bindingNotUsed, declared[bindingNotUsed], "var"); + }); + } + + // If this is not a function boundary, transfer function-scoped bindings to + // the parent block (a rough simulation of variable hoisting). Previously + // existing bindings in the parent block should take precedence so that + // prior usages are not discarded. + if (subScope && !isUnstackingFunctionBody && + !isUnstackingFunctionParams && !isUnstackingFunctionOuter) { + var bindingNames = Object.keys(currentBindings); + for (i = 0; i < bindingNames.length; i++) { + + var defBindingName = bindingNames[i]; + var defBinding = currentBindings[defBindingName]; + + if (!defBinding["(blockscoped)"] && defBinding["(type)"] !== "exception") { + var shadowed = subScope["(bindings)"][defBindingName]; + + // Do not overwrite a binding if it exists in the parent scope + // because it is shared by adjacent blocks. Copy the `unused` + // property so that any references found within the current block + // are counted toward that higher-level declaration. + if (shadowed) { + shadowed["(unused)"] &= defBinding["(unused)"]; + + // "Hoist" the variable to the parent block, decorating the binding + // so that future references, though technically valid, can be + // reported as "out-of-scope" in the absence of the `funcscope` + // option. + } else { + defBinding["(useOutsideOfScope)"] = + // Do not warn about out-of-scope usages in the global scope + _currentFunctBody["(type)"] !== "global" && + // When a higher scope contains a binding for the binding, the + // binding is a re-declaration and should not prompt "used + // out-of-scope" warnings. + !this.funct.has(defBindingName, { excludeCurrent: true }); + + subScope["(bindings)"][defBindingName] = defBinding; + } + + delete currentBindings[defBindingName]; + } + } + } + + _checkForUnused(); + + _scopeStack.pop(); + if (isUnstackingFunctionBody) { + _currentFunctBody = _scopeStack[_.findLastIndex(_scopeStack, function(scope) { + // if function or if global (which is at the bottom so it will only return true if we call back) + return scope["(isFuncBody)"] || scope["(type)"] === "global"; + })]; + } + + _current = subScope; + }, + + /** + * Add a function parameter to the current scope. + * + * @param {string} bindingName - the value of the identifier + * @param {Token} token + * @param {string} [type] - binding type; defaults to "param" + */ + addParam: function(bindingName, token, type) { + type = type || "param"; + + if (type === "exception") { + // if defined in the current function + var previouslyDefinedBindingType = this.funct.bindingtype(bindingName); + if (previouslyDefinedBindingType && previouslyDefinedBindingType !== "exception") { + // and has not been used yet in the current function scope + if (!state.option.node) { + warning("W002", state.tokens.next, bindingName); + } + } + + if (state.isStrict() && (bindingName === "arguments" || bindingName === "eval")) { + warning("E008", token); + } + } + + // The variable was declared in the current scope + if (_.has(_current["(bindings)"], bindingName)) { + _current["(bindings)"][bindingName].duplicated = true; + + // The variable was declared in an outer scope + } else { + // if this scope has the variable defined, it's a re-definition error + _checkOuterShadow(bindingName, token); + + _current["(bindings)"][bindingName] = { + "(type)" : type, + "(token)": token, + "(unused)": true }; + + _current["(params)"].push(bindingName); + } + + if (_.has(_current["(usages)"], bindingName)) { + var usage = _current["(usages)"][bindingName]; + // if its in a sub function it is not necessarily an error, just latedef + if (usage["(onlyUsedSubFunction)"]) { + _latedefWarning(type, bindingName, token); + } else { + // this is a clear illegal usage for block scoped variables + warning("E056", token, bindingName, type); + } + } + }, + + validateParams: function(isArrow) { + var isStrict = state.isStrict(); + var currentFunctParamScope = _currentFunctBody["(parent)"]; + // From ECMAScript 2017: + // + // > 14.1.2Static Semantics: Early Errors + // > + // > [...] + // > - It is a Syntax Error if IsSimpleParameterList of + // > FormalParameterList is false and BoundNames of FormalParameterList + // > contains any duplicate elements. + var isSimple = state.funct['(hasSimpleParams)']; + // Method definitions are defined in terms of UniqueFormalParameters, so + // they cannot support duplicate parameter names regardless of strict + // mode. + var isMethod = state.funct["(method)"]; + + if (!currentFunctParamScope["(params)"]) { + /* istanbul ignore next */ + return; + } + + currentFunctParamScope["(params)"].forEach(function(bindingName) { + var binding = currentFunctParamScope["(bindings)"][bindingName]; + + if (binding.duplicated) { + if (isStrict || isArrow || isMethod || !isSimple) { + warning("E011", binding["(token)"], bindingName); + } else if (state.option.shadow !== true) { + warning("W004", binding["(token)"], bindingName); + } + } + + if (isStrict && (bindingName === "arguments" || bindingName === "eval")) { + warning("E008", binding["(token)"]); + } + }); + }, + + getUsedOrDefinedGlobals: function() { + // jshint proto: true + var list = Object.keys(usedPredefinedAndGlobals); + + // If `__proto__` is used as a global variable name, its entry in the + // lookup table may not be enumerated by `Object.keys` (depending on the + // environment). + /* istanbul ignore if */ + if (usedPredefinedAndGlobals.__proto__ === marker && + list.indexOf("__proto__") === -1) { + list.push("__proto__"); + } + + return list; + }, + + /** + * Get an array of implied globals + * + * @returns {Array.<{ name: string, line: Array.}>} + */ + getImpliedGlobals: function() { + // jshint proto: true + var values = _.values(impliedGlobals); + var hasProto = false; + + // If `__proto__` is an implied global variable, its entry in the lookup + // table may not be enumerated by `_.values` (depending on the + // environment). + if (impliedGlobals.__proto__) { + hasProto = values.some(function(value) { + return value.name === "__proto__"; + }); + + /* istanbul ignore if */ + if (!hasProto) { + values.push(impliedGlobals.__proto__); + } + } + + return values; + }, + + /** + * Get an array of objects describing unused bindings. + * + * @returns {Array} + */ + getUnuseds: function() { + return unuseds; + }, + + /** + * Determine if a given name has been defined in the current scope or any + * lower scope. + * + * @param {string} bindingName - the value of the identifier + * + * @return {boolean} + */ + has: function(bindingName) { + return Boolean(_getBinding(bindingName)); + }, + + /** + * Retrieve binding described by `bindingName` or null + * + * @param {string} bindingName - the value of the identifier + * + * @returns {string|null} - the type of the binding or `null` if no such + * binding exists + */ + bindingtype: function(bindingName) { + var scopeBindings = _getBinding(bindingName); + if (scopeBindings) { + return scopeBindings[bindingName]["(type)"]; + } + return null; + }, + + /** + * For the exported options, indicating a variable is used outside the file + * + * @param {string} bindingName - the value of the identifier + */ + addExported: function(bindingName) { + var globalBindings = _scopeStack[0]["(bindings)"]; + if (_.has(declared, bindingName)) { + // remove the declared token, so we know it is used + delete declared[bindingName]; + } else if (_.has(globalBindings, bindingName)) { + globalBindings[bindingName]["(unused)"] = false; + } else { + for (var i = 1; i < _scopeStack.length; i++) { + var scope = _scopeStack[i]; + // if `scope.(type)` is not defined, it is a block scope + if (!scope["(type)"]) { + if (_.has(scope["(bindings)"], bindingName) && + !scope["(bindings)"][bindingName]["(blockscoped)"]) { + scope["(bindings)"][bindingName]["(unused)"] = false; + return; + } + } else { + /* istanbul ignore next */ + break; + } + } + exported[bindingName] = true; + } + }, + + /** + * Mark a binding as "exported" by an ES2015 module + * + * @param {string} bindingName - the value of the identifier + * @param {object} token + */ + setExported: function(bindingName, token) { + this.block.use(bindingName, token); + }, + + /** + * Mark a binding as "initialized." This is necessary to enforce the + * "temporal dead zone" (TDZ) of block-scoped bindings which are not + * hoisted. + * + * @param {string} bindingName - the value of the identifier + */ + initialize: function(bindingName) { + if (_current["(bindings)"][bindingName]) { + _current["(bindings)"][bindingName]["(initialized)"] = true; + } + }, + + /** + * Create a new binding and add it to the current scope. Delegates to the + * internal `block.add` or `func.add` methods depending on the type. + * Produces warnings and errors as necessary. + * + * @param {string} bindingName + * @param {Object} opts + * @param {String} opts.type - the type of the binding e.g. "param", "var", + * "let, "const", "import", "function", + * "generator function", "async function", + * "async generator function" + * @param {object} opts.token - the token pointing at the declaration + * @param {boolean} opts.initialized - whether the binding should be + * created in an "initialized" state. + */ + addbinding: function(bindingName, opts) { + + var type = opts.type; + var token = opts.token; + var isblockscoped = type === "let" || type === "const" || + type === "class" || type === "import" || type === "generator function" || + type === "async function" || type === "async generator function"; + var ishoisted = type === "function" || type === "generator function" || + type === "async function" || type === "import"; + var isexported = (isblockscoped ? _current : _currentFunctBody)["(type)"] === "global" && + _.has(exported, bindingName); + + // outer shadow check (inner is only on non-block scoped) + _checkOuterShadow(bindingName, token); + + if (state.isStrict() && (bindingName === "arguments" || bindingName === "eval")) { + warning("E008", token); + } + + if (isblockscoped) { + + var declaredInCurrentScope = _current["(bindings)"][bindingName]; + // for block scoped variables, params are seen in the current scope as the root function + // scope, so check these too. + if (!declaredInCurrentScope && _current === _currentFunctBody && + _current["(type)"] !== "global") { + declaredInCurrentScope = !!_currentFunctBody["(parent)"]["(bindings)"][bindingName]; + } + + // if its not already defined (which is an error, so ignore) and is used in TDZ + if (!declaredInCurrentScope && _current["(usages)"][bindingName]) { + var usage = _current["(usages)"][bindingName]; + // if its in a sub function it is not necessarily an error, just latedef + if (usage["(onlyUsedSubFunction)"] || ishoisted) { + _latedefWarning(type, bindingName, token); + } else if (!ishoisted) { + // this is a clear illegal usage for block scoped variables + warning("E056", token, bindingName, type); + } + } + + // If this scope has already declared a binding with the same name, + // then this represents a redeclaration error if: + // + // 1. it is a "hoisted" block-scoped binding within a block. For + // instance: generator functions may be redeclared in the global + // scope but not within block statements + // 2. this is not a "hoisted" block-scoped binding + if (declaredInCurrentScope && + (!ishoisted || (_current["(type)"] !== "global" || type === "import"))) { + warning("E011", token, bindingName); + } + else if (state.option.shadow === "outer") { + + // if shadow is outer, for block scope we want to detect any shadowing within this function + if (scopeManagerInst.funct.has(bindingName)) { + warning("W004", token, bindingName); + } + } + + scopeManagerInst.block.add( + bindingName, type, token, !isexported, opts.initialized + ); + + } else { + + var declaredInCurrentFunctionScope = scopeManagerInst.funct.has(bindingName); + + // check for late definition, ignore if already declared + if (!declaredInCurrentFunctionScope && usedSoFarInCurrentFunction(bindingName)) { + _latedefWarning(type, bindingName, token); + } + + // defining with a var or a function when a block scope variable of the same name + // is in scope is an error + if (scopeManagerInst.funct.has(bindingName, { onlyBlockscoped: true })) { + warning("E011", token, bindingName); + } else if (state.option.shadow !== true) { + // now since we didn't get any block scope variables, test for var/function + // shadowing + if (declaredInCurrentFunctionScope && bindingName !== "__proto__") { + + // see https://github.com/jshint/jshint/issues/2400 + if (_currentFunctBody["(type)"] !== "global") { + warning("W004", token, bindingName); + } + } + } + + scopeManagerInst.funct.add(bindingName, type, token, !isexported); + + if (_currentFunctBody["(type)"] === "global" && !state.impliedClosure()) { + usedPredefinedAndGlobals[bindingName] = marker; + } + } + }, + + funct: { + /** + * Return the type of the provided binding given certain options + * + * @param {string} bindingName + * @param {Object=} [options] + * @param {boolean} [options.onlyBlockscoped] - only include block scoped + * bindings + * @param {boolean} [options.excludeParams] - exclude the param scope + * @param {boolean} [options.excludeCurrent] - exclude the current scope + * + * @returns {String} + */ + bindingtype: function(bindingName, options) { + var onlyBlockscoped = options && options.onlyBlockscoped; + var excludeParams = options && options.excludeParams; + var currentScopeIndex = _scopeStack.length - (options && options.excludeCurrent ? 2 : 1); + for (var i = currentScopeIndex; i >= 0; i--) { + var current = _scopeStack[i]; + if (current["(bindings)"][bindingName] && + (!onlyBlockscoped || current["(bindings)"][bindingName]["(blockscoped)"])) { + return current["(bindings)"][bindingName]["(type)"]; + } + var scopeCheck = excludeParams ? _scopeStack[ i - 1 ] : current; + if (scopeCheck && scopeCheck["(type)"] === "functionparams") { + return null; + } + } + return null; + }, + + /** + * Determine whether a `break` statement label exists in the function + * scope. + * + * @param {string} labelName - the value of the identifier + * + * @returns {boolean} + */ + hasLabel: function(labelName) { + for (var i = _scopeStack.length - 1; i >= 0; i--) { + var current = _scopeStack[i]; + + if (current["(labels)"][labelName]) { + return true; + } + if (current["(type)"] === "functionparams") { + return false; + } + } + return false; + }, + + /** + * Determine if a given name has been defined in the current function + * scope. + * + * @param {string} bindingName - the value of the identifier + * @param {object} options - options as supported by the + * `funct.bindingtype` method + * + * @return {boolean} + */ + has: function(bindingName, options) { + return Boolean(this.bindingtype(bindingName, options)); + }, + + /** + * Create a new function-scoped binding and add it to the current scope. + * See the `block.add` method for coresponding logic to create + * block-scoped bindings. + * + * @param {string} bindingName - the value of the identifier + * @param {string} type - the type of the binding; either "function" or + * "var" + * @param {object} tok - the token that triggered the definition + * @param {boolean} unused - `true` if the binding has not been + * referenced + */ + add: function(bindingName, type, tok, unused) { + _current["(bindings)"][bindingName] = { + "(type)" : type, + "(token)": tok, + "(blockscoped)": false, + "(function)": _currentFunctBody, + "(unused)": unused }; + } + }, + + block: { + + /** + * Determine whether the current block scope is the global scope. + * + * @returns Boolean + */ + isGlobal: function() { + return _current["(type)"] === "global"; + }, + + /** + * Resolve a reference to a binding and mark the corresponding binding as + * "used." + * + * @param {string} bindingName - the value of the identifier + * @param {object} token - the token value that triggered the reference + */ + use: function(bindingName, token) { + // If the name resolves to a parameter of the current function, then do + // not store usage. This is because in cases such as the following: + // + // function(a) { + // var a; + // a = a; + // } + // + // the usage of `a` will resolve to the parameter, not to the unset + // variable binding. + var paramScope = _currentFunctBody["(parent)"]; + if (paramScope && paramScope["(bindings)"][bindingName] && + paramScope["(bindings)"][bindingName]["(type)"] === "param") { + + // then check its not declared by a block scope variable + if (!scopeManagerInst.funct.has(bindingName, + { excludeParams: true, onlyBlockscoped: true })) { + paramScope["(bindings)"][bindingName]["(unused)"] = false; + } + } + + if (token && (state.ignored.W117 || state.option.undef === false)) { + token.ignoreUndef = true; + } + + _setupUsages(bindingName); + + _current["(usages)"][bindingName]["(onlyUsedSubFunction)"] = false; + + if (token) { + token["(function)"] = _currentFunctBody; + _current["(usages)"][bindingName]["(tokens)"].push(token); + } + + // Block-scoped bindings can't be used within their initializer due to + // "temporal dead zone" (TDZ) restrictions. + var binding = _current["(bindings)"][bindingName]; + if (binding && binding["(blockscoped)"] && !binding["(initialized)"]) { + error("E056", token, bindingName, binding["(type)"]); + } + }, + + reassign: function(bindingName, token) { + token.ignoreW020 = state.ignored.W020; + token.ignoreW021 = state.ignored.W021; + + this.modify(bindingName, token); + + _current["(usages)"][bindingName]["(reassigned)"].push(token); + }, + + modify: function(bindingName, token) { + + _setupUsages(bindingName); + + _current["(usages)"][bindingName]["(onlyUsedSubFunction)"] = false; + _current["(usages)"][bindingName]["(modified)"].push(token); + }, + + /** + * Create a new block-scoped binding and add it to the current scope. See + * the `funct.add` method for coresponding logic to create + * function-scoped bindings. + * + * @param {string} bindingName - the value of the identifier + * @param {string} type - the type of the binding; one of "class", + * "const", "function", "import", or "let" + * @param {object} tok - the token that triggered the definition + * @param {boolean} unused - `true` if the binding has not been + * referenced + * @param {boolean} initialized - `true` if the binding has been + * initialized (as is the case with + * bindings created via `import` + * declarations) + */ + add: function(bindingName, type, tok, unused, initialized) { + _current["(bindings)"][bindingName] = { + "(type)" : type, + "(token)": tok, + "(initialized)": !!initialized, + "(blockscoped)": true, + "(unused)": unused }; + }, + + addLabel: function(labelName, opts) { + var token = opts.token; + if (scopeManagerInst.funct.hasLabel(labelName)) { + warning("E011", token, labelName); + } + else if (state.option.shadow === "outer") { + if (scopeManagerInst.funct.has(labelName)) { + warning("W004", token, labelName); + } else { + _checkOuterShadow(labelName, token); + } + } + _current["(labels)"][labelName] = token; + } + } + }; + return scopeManagerInst; +}; + +module.exports = scopeManager; + +},{"events":"/../node_modules/events/events.js","lodash.slice":"/../../jshint/node_modules/lodash.slice/index.js","underscore":"/../../jshint/node_modules/underscore/underscore.js"}],"/../../jshint/src/state.js":[function(_dereq_,module,exports){ +"use strict"; +var NameStack = _dereq_("./name-stack.js"); + +var state = { + syntax: {}, + + /** + * Determine if the code currently being linted is strict mode code. + * + * @returns {boolean} + */ + isStrict: function() { + return this.directive["use strict"] || this.inClassBody || + this.option.module || this.option.strict === "implied"; + }, + + /** + * Determine if the current state warrants a warning for statements outside + * of strict mode code. + * + * While emitting warnings based on function scope would be more intuitive + * (and less noisy), JSHint observes statement-based semantics in order to + * preserve legacy behavior. + * + * This method does not take the state of the parser into account, making no + * distinction between global code and function code. Because the "missing + * 'use strict'" warning is *also* reported at function boundaries, this + * function interprets `strict` option values `true` and `undefined` as + * equivalent. + */ + stmtMissingStrict: function() { + if (this.option.strict === "global") { + return true; + } + + if (this.option.strict === false) { + return false; + } + + if (this.option.globalstrict) { + return true; + } + + return false; + }, + + allowsGlobalUsd: function() { + return this.option.strict === "global" || this.option.globalstrict || + this.option.module || this.impliedClosure(); + }, + + /** + * Determine if the current configuration describes an environment that is + * wrapped in an immediately-invoked function expression prior to evaluation. + * + * @returns {boolean} + */ + impliedClosure: function() { + return this.option.node || this.option.phantom || this.option.browserify; + }, + + // Assumption: chronologically ES3 < ES5 < ES6 < Moz + + inMoz: function() { + return this.option.moz; + }, + + /** + * Determine if constructs introduced in ECMAScript 10 should be accepted. + * + * @returns {boolean} + */ + inES10: function() { + return this.esVersion >= 10; + }, + + /** + * Determine if constructs introduced in ECMAScript 9 should be accepted. + * + * @returns {boolean} + */ + inES9: function() { + return this.esVersion >= 9; + }, + + /** + * Determine if constructs introduced in ECMAScript 8 should be accepted. + * + * @returns {boolean} + */ + inES8: function() { + return this.esVersion >= 8; + }, + + /** + * Determine if constructs introduced in ECMAScript 7 should be accepted. + * + * @returns {boolean} + */ + inES7: function() { + return this.esVersion >= 7; + }, + + /** + * Determine if constructs introduced in ECMAScript 6 should be accepted. + * + * @param {boolean} strict - When `true`, do not interpret the `moz` option + * as ECMAScript 6 + * + * @returns {boolean} + */ + inES6: function(strict) { + if (!strict && this.option.moz) { + return true; + } + + return this.esVersion >= 6; + }, + + /** + * Determine if constructs introduced in ECMAScript 5 should be accepted. + * + * @returns {boolean} + */ + inES5: function() { + return !this.esVersion || this.esVersion >= 5 || this.option.moz; + }, + + /** + * Determine the current version of the input language by inspecting the + * value of all ECMAScript-version-related options. This logic is necessary + * to ensure compatibility with deprecated options `es3`, `es5`, and + * `esnext`, and it may be drastically simplified when those options are + * removed. + * + * @returns {string|null} - the name of any incompatible option detected, + * `null` otherwise + */ + inferEsVersion: function() { + var badOpt = null; + + if (this.option.esversion) { + if (this.option.es3) { + badOpt = "es3"; + } else if (this.option.es5) { + badOpt = "es5"; + } else if (this.option.esnext) { + badOpt = "esnext"; + } + + if (badOpt) { + return badOpt; + } + + if (this.option.esversion === 2015) { + this.esVersion = 6; + } else { + this.esVersion = this.option.esversion; + } + } else if (this.option.es3) { + this.esVersion = 3; + } else if (this.option.esnext) { + this.esVersion = 6; + } + + return null; + }, + + reset: function() { + this.tokens = { + prev: null, + next: null, + curr: null + }; + + this.option = { unstable: {} }; + this.esVersion = 5; + this.funct = null; + this.ignored = {}; + this.directive = Object.create(null); + this.jsonMode = false; + this.lines = []; + this.tab = ""; + this.cache = {}; // Node.JS doesn't have Map. Sniff. + this.ignoredLines = {}; + this.forinifcheckneeded = false; + this.nameStack = new NameStack(); + this.inClassBody = false; + } +}; + +exports.state = state; + +},{"./name-stack.js":"/../../jshint/src/name-stack.js"}],"/../../jshint/src/style.js":[function(_dereq_,module,exports){ +"use strict"; + +exports.register = function(linter) { + // Check for properties named __proto__. This special property was + // deprecated and then re-introduced for ES6. + + linter.on("Identifier", function style_scanProto(data) { + if (linter.getOption("proto")) { + return; + } + + if (data.name === "__proto__") { + linter.warn("W103", { + line: data.line, + char: data.char, + data: [ data.name, "6" ] + }); + } + }); + + // Check for properties named __iterator__. This is a special property + // available only in browsers with JavaScript 1.7 implementation, but + // it is deprecated for ES6 + + linter.on("Identifier", function style_scanIterator(data) { + if (linter.getOption("iterator")) { + return; + } + + if (data.name === "__iterator__") { + linter.warn("W103", { + line: data.line, + char: data.char, + data: [ data.name ] + }); + } + }); + + // Check that all identifiers are using camelCase notation. + // Exceptions: names like MY_VAR and _myVar. + + linter.on("Identifier", function style_scanCamelCase(data) { + if (!linter.getOption("camelcase")) { + return; + } + + if (data.name.replace(/^_+|_+$/g, "").indexOf("_") > -1 && !data.name.match(/^[A-Z0-9_]*$/)) { + linter.warn("W106", { + line: data.line, + char: data.char, + data: [ data.name ] + }); + } + }); + + // Enforce consistency in style of quoting. + + linter.on("String", function style_scanQuotes(data) { + var quotmark = linter.getOption("quotmark"); + var code; + + if (!quotmark) { + return; + } + + // If quotmark is set to 'single' warn about all double-quotes. + + if (quotmark === "single" && data.quote !== "'") { + code = "W109"; + } + + // If quotmark is set to 'double' warn about all single-quotes. + + if (quotmark === "double" && data.quote !== "\"") { + code = "W108"; + } + + // If quotmark is set to true, remember the first quotation style + // and then warn about all others. + + if (quotmark === true) { + if (!linter.getCache("quotmark")) { + linter.setCache("quotmark", data.quote); + } + + if (linter.getCache("quotmark") !== data.quote) { + code = "W110"; + } + } + + if (code) { + linter.warn(code, { + line: data.line, + char: data.char, + }); + } + }); + + linter.on("Number", function style_scanNumbers(data) { + if (data.value.charAt(0) === ".") { + // Warn about a leading decimal point. + linter.warn("W008", { + line: data.line, + char: data.char, + data: [ data.value ] + }); + } + + if (data.value.substr(data.value.length - 1) === ".") { + // Warn about a trailing decimal point. + linter.warn("W047", { + line: data.line, + char: data.char, + data: [ data.value ] + }); + } + + if (/^00+/.test(data.value)) { + // Multiple leading zeroes. + linter.warn("W046", { + line: data.line, + char: data.char, + data: [ data.value ] + }); + } + }); + + // Warn about script URLs. + + linter.on("String", function style_scanJavaScriptURLs(data) { + var re = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i; + + if (linter.getOption("scripturl")) { + return; + } + + if (re.test(data.value)) { + linter.warn("W107", { + line: data.line, + char: data.char + }); + } + }); +}; + +},{}],"/../../jshint/src/vars.js":[function(_dereq_,module,exports){ +// jshint -W001 + +"use strict"; + +// Identifiers provided by the ECMAScript standard. + +exports.reservedVars = { + NaN : false, + undefined : false +}; + +exports.ecmaIdentifiers = { + 3: { + Array : false, + Boolean : false, + Date : false, + decodeURI : false, + decodeURIComponent : false, + encodeURI : false, + encodeURIComponent : false, + Error : false, + "eval" : false, + EvalError : false, + Function : false, + hasOwnProperty : false, + Infinity : false, + isFinite : false, + isNaN : false, + Math : false, + Number : false, + Object : false, + parseInt : false, + parseFloat : false, + RangeError : false, + ReferenceError : false, + RegExp : false, + String : false, + SyntaxError : false, + TypeError : false, + URIError : false + }, + 5: { + JSON : false + }, + 6: { + ArrayBuffer : false, + DataView : false, + Float32Array : false, + Float64Array : false, + Int8Array : false, + Int16Array : false, + Int32Array : false, + Map : false, + Promise : false, + Proxy : false, + Reflect : false, + Set : false, + Symbol : false, + Uint8Array : false, + Uint16Array : false, + Uint32Array : false, + Uint8ClampedArray : false, + WeakMap : false, + WeakSet : false + }, + 8: { + Atomics : false, + SharedArrayBuffer : false + } +}; + +// Global variables commonly provided by a web browser environment. + +exports.browser = { + Audio : false, + Blob : false, + addEventListener : false, // EventTarget + applicationCache : false, + atob : false, // WindowOrWorkerGlobalScope + blur : false, + btoa : false, // WindowOrWorkerGlobalScope + cancelAnimationFrame : false, + CanvasGradient : false, + CanvasPattern : false, + CanvasRenderingContext2D: false, + CSS : false, + CSSImportRule : false, + CSSGroupingRule : false, + CSSMarginRule : false, + CSSMediaRule : false, + CSSNamespaceRule : false, + CSSPageRule : false, + CSSRule : false, + CSSRuleList : false, + CSSStyleDeclaration : false, + CSSStyleRule : false, + CSSStyleSheet : false, + clearInterval : false, // WindowOrWorkerGlobalScope + clearTimeout : false, // WindowOrWorkerGlobalScope + close : false, + closed : false, + Comment : false, + CompositionEvent : false, + createImageBitmap : false, // WindowOrWorkerGlobalScope + CustomEvent : false, + DOMParser : false, + defaultStatus : false, + dispatchEvent : false, // EventTarget + Document : false, + document : false, + DocumentFragment : false, + Element : false, + ElementTimeControl : false, + Event : false, + event : false, + fetch : false, + File : false, + FileList : false, + FileReader : false, + FormData : false, + focus : false, + frames : false, + getComputedStyle : false, + Headers : false, + HTMLAnchorElement : false, + HTMLAreaElement : false, + HTMLAudioElement : false, + HTMLBaseElement : false, + HTMLBlockquoteElement: false, + HTMLBodyElement : false, + HTMLBRElement : false, + HTMLButtonElement : false, + HTMLCanvasElement : false, + HTMLCollection : false, + HTMLDataElement : false, + HTMLDataListElement : false, + HTMLDetailsElement : false, + HTMLDialogElement : false, + HTMLDirectoryElement : false, + HTMLDivElement : false, + HTMLDListElement : false, + HTMLElement : false, + HTMLEmbedElement : false, + HTMLFieldSetElement : false, + HTMLFontElement : false, + HTMLFormElement : false, + HTMLFrameElement : false, + HTMLFrameSetElement : false, + HTMLHeadElement : false, + HTMLHeadingElement : false, + HTMLHRElement : false, + HTMLHtmlElement : false, + HTMLIFrameElement : false, + HTMLImageElement : false, + HTMLInputElement : false, +/* HTMLIsIndexElement was removed from the WHATWG HTML spec; + see https://github.com/whatwg/html/pull/1095. + HTMLIsIndexElement has been removed from browsers; see: + • Chromium Removal: https://codereview.chromium.org/96653004/ + • Gecko Removal: https://bugzilla.mozilla.org/show_bug.cgi?id=1266495 + • WebKit Removal: https://bugs.webkit.org/show_bug.cgi?id=7139. + See also the discussion at https://github.com/jshint/jshint/pull/3222. */ + HTMLIsIndexElement : false, + HTMLLabelElement : false, + HTMLLayerElement : false, + HTMLLegendElement : false, + HTMLLIElement : false, + HTMLLinkElement : false, + HTMLMapElement : false, + HTMLMarqueeElement : false, + HTMLMediaElement : false, + HTMLMenuElement : false, + HTMLMetaElement : false, + HTMLMeterElement : false, + HTMLModElement : false, + HTMLObjectElement : false, + HTMLOListElement : false, + HTMLOptGroupElement : false, + HTMLOptionElement : false, + HTMLParagraphElement : false, + HTMLParamElement : false, + HTMLPictureElement : false, + HTMLPreElement : false, + HTMLProgressElement : false, + HTMLQuoteElement : false, + HTMLScriptElement : false, + HTMLSelectElement : false, + HTMLSlotElement : false, + HTMLSourceElement : false, + HTMLStyleElement : false, + HTMLTableCaptionElement: false, + HTMLTableCellElement : false, + HTMLTableColElement : false, + HTMLTableElement : false, + HTMLTableRowElement : false, + HTMLTableSectionElement: false, + HTMLTemplateElement : false, + HTMLTextAreaElement : false, + HTMLTimeElement : false, + HTMLTitleElement : false, + HTMLTrackElement : false, + HTMLUListElement : false, + HTMLVideoElement : false, + history : false, + Image : false, + IntersectionObserver : false, + Intl : false, + length : false, + localStorage : false, + location : false, + matchMedia : false, + MediaList : false, + MediaRecorder : false, + MessageChannel : false, + MessageEvent : false, + MessagePort : false, MouseEvent : false, moveBy : false, moveTo : false, @@ -11826,23 +16281,29 @@ exports.browser = { openDatabase : false, opener : false, Option : false, + origin : false, // WindowOrWorkerGlobalScope parent : false, performance : false, print : false, + queueMicrotask : false, // WindowOrWorkerGlobalScope Range : false, requestAnimationFrame : false, - removeEventListener : false, + removeEventListener : false, // EventTarget + Request : false, resizeBy : false, resizeTo : false, + Response : false, screen : false, scroll : false, scrollBy : false, scrollTo : false, sessionStorage : false, - setInterval : false, - setTimeout : false, + setInterval : false, // WindowOrWorkerGlobalScope + setTimeout : false, // WindowOrWorkerGlobalScope SharedWorker : false, status : false, + Storage : false, + StyleSheet : false, SVGAElement : false, SVGAltGlyphDefElement: false, SVGAltGlyphElement : false, @@ -12020,6 +16481,7 @@ exports.browser = { Window : false, Worker : false, XDomainRequest : false, + XMLDocument : false, XMLHttpRequest : false, XMLSerializer : false, XPathEvaluator : false, @@ -12030,346 +16492,2305 @@ exports.browser = { XPathResult : false }; -exports.devel = { - alert : false, - confirm: false, - console: false, - Debug : false, - opera : false, - prompt : false -}; +exports.devel = { + alert : false, + confirm: false, + console: false, + Debug : false, + opera : false, + prompt : false +}; + +exports.worker = { + addEventListener : true, // EventTarget + atob : true, // WindowOrWorkerGlobalScope + btoa : true, // WindowOrWorkerGlobalScope + clearInterval : true, // WindowOrWorkerGlobalScope + clearTimeout : true, // WindowOrWorkerGlobalScope + createImageBitmap : true, // WindowOrWorkerGlobalScope + dispatchEvent : true, // EventTarget + importScripts : true, + onmessage : true, + origin : true, // WindowOrWorkerGlobalScope + postMessage : true, + queueMicrotask : true, // WindowOrWorkerGlobalScope + removeEventListener : true, // EventTarget + self : true, + setInterval : true, // WindowOrWorkerGlobalScope + setTimeout : true, // WindowOrWorkerGlobalScope + FileReaderSync : true +}; + +// Widely adopted global names that are not part of ECMAScript standard +exports.nonstandard = { + escape : false, + unescape: false +}; + +// Globals provided by popular JavaScript environments. + +exports.couch = { + "require" : false, + respond : false, + getRow : false, + emit : false, + send : false, + start : false, + sum : false, + log : false, + exports : false, + module : false, + provides : false +}; + +exports.node = { + __filename : false, + __dirname : false, + arguments : false, + GLOBAL : false, + global : false, + module : false, + require : false, + + // These globals are writeable because Node allows the following + // usage pattern: var Buffer = require("buffer").Buffer; + + Buffer : true, + console : true, + exports : true, + process : true, + setTimeout : true, + clearTimeout : true, + setInterval : true, + clearInterval : true, + setImmediate : true, // v0.9.1+ + clearImmediate: true // v0.9.1+ +}; + +exports.browserify = { + __filename : false, + __dirname : false, + global : false, + module : false, + require : false, + Buffer : true, + exports : true, + process : true +}; + +exports.phantom = { + phantom : true, + require : true, + WebPage : true, + console : true, // in examples, but undocumented + exports : true // v1.7+ +}; + +exports.qunit = { + asyncTest : false, + deepEqual : false, + equal : false, + expect : false, + module : false, + notDeepEqual : false, + notEqual : false, + notOk : false, + notPropEqual : false, + notStrictEqual : false, + ok : false, + propEqual : false, + QUnit : false, + raises : false, + start : false, + stop : false, + strictEqual : false, + test : false, + "throws" : false +}; + +exports.rhino = { + arguments : false, + defineClass : false, + deserialize : false, + gc : false, + help : false, + importClass : false, + importPackage: false, + "java" : false, + load : false, + loadClass : false, + Packages : false, + print : false, + quit : false, + readFile : false, + readUrl : false, + runCommand : false, + seal : false, + serialize : false, + spawn : false, + sync : false, + toint32 : false, + version : false +}; + +exports.shelljs = { + target : false, + echo : false, + exit : false, + cd : false, + pwd : false, + ls : false, + find : false, + cp : false, + rm : false, + mv : false, + mkdir : false, + test : false, + cat : false, + sed : false, + grep : false, + which : false, + dirs : false, + pushd : false, + popd : false, + env : false, + exec : false, + chmod : false, + config : false, + error : false, + tempdir : false +}; + +exports.typed = { + ArrayBuffer : false, + ArrayBufferView : false, + DataView : false, + Float32Array : false, + Float64Array : false, + Int16Array : false, + Int32Array : false, + Int8Array : false, + Uint16Array : false, + Uint32Array : false, + Uint8Array : false, + Uint8ClampedArray : false +}; + +exports.wsh = { + ActiveXObject : true, + Enumerator : true, + GetObject : true, + ScriptEngine : true, + ScriptEngineBuildVersion : true, + ScriptEngineMajorVersion : true, + ScriptEngineMinorVersion : true, + VBArray : true, + WSH : true, + WScript : true, + XDomainRequest : true +}; + +// Globals provided by popular JavaScript libraries. + +exports.dojo = { + dojo : false, + dijit : false, + dojox : false, + define : false, + "require": false +}; + +exports.jquery = { + "$" : false, + jQuery : false +}; + +exports.mootools = { + "$" : false, + "$$" : false, + Asset : false, + Browser : false, + Chain : false, + Class : false, + Color : false, + Cookie : false, + Core : false, + Document : false, + DomReady : false, + DOMEvent : false, + DOMReady : false, + Drag : false, + Element : false, + Elements : false, + Event : false, + Events : false, + Fx : false, + Group : false, + Hash : false, + HtmlTable : false, + IFrame : false, + IframeShim : false, + InputValidator: false, + instanceOf : false, + Keyboard : false, + Locale : false, + Mask : false, + MooTools : false, + Native : false, + Options : false, + OverText : false, + Request : false, + Scroller : false, + Slick : false, + Slider : false, + Sortables : false, + Spinner : false, + Swiff : false, + Tips : false, + Type : false, + typeOf : false, + URI : false, + Window : false +}; + +exports.prototypejs = { + "$" : false, + "$$" : false, + "$A" : false, + "$F" : false, + "$H" : false, + "$R" : false, + "$break" : false, + "$continue" : false, + "$w" : false, + Abstract : false, + Ajax : false, + Class : false, + Enumerable : false, + Element : false, + Event : false, + Field : false, + Form : false, + Hash : false, + Insertion : false, + ObjectRange : false, + PeriodicalExecuter: false, + Position : false, + Prototype : false, + Selector : false, + Template : false, + Toggle : false, + Try : false, + Autocompleter : false, + Builder : false, + Control : false, + Draggable : false, + Draggables : false, + Droppables : false, + Effect : false, + Sortable : false, + SortableObserver : false, + Sound : false, + Scriptaculous : false +}; + +exports.yui = { + YUI : false, + Y : false, + YUI_config: false +}; + +exports.mocha = { + // Global (for config etc.) + mocha : false, + // BDD + describe : false, + xdescribe : false, + it : false, + xit : false, + context : false, + xcontext : false, + before : false, + after : false, + beforeEach : false, + afterEach : false, + // TDD + suite : false, + test : false, + setup : false, + teardown : false, + suiteSetup : false, + suiteTeardown : false +}; + +exports.jasmine = { + jasmine : false, + describe : false, + xdescribe : false, + it : false, + xit : false, + beforeEach : false, + afterEach : false, + setFixtures : false, + loadFixtures: false, + spyOn : false, + expect : false, + // Jasmine 1.3 + runs : false, + waitsFor : false, + waits : false, + // Jasmine 2.1 + beforeAll : false, + afterAll : false, + fail : false, + fdescribe : false, + fit : false, + pending : false, + // Jasmine 2.6 + spyOnProperty: false +}; + +},{}],"/../node_modules/assert/assert.js":[function(_dereq_,module,exports){ +(function (global){ +'use strict'; + +var objectAssign = _dereq_('object-assign'); + +// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js +// original notice: + +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +function compare(a, b) { + if (a === b) { + return 0; + } + + var x = a.length; + var y = b.length; + + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i]; + y = b[i]; + break; + } + } + + if (x < y) { + return -1; + } + if (y < x) { + return 1; + } + return 0; +} +function isBuffer(b) { + if (global.Buffer && typeof global.Buffer.isBuffer === 'function') { + return global.Buffer.isBuffer(b); + } + return !!(b != null && b._isBuffer); +} + +// based on node assert, original notice: +// NB: The URL to the CommonJS spec is kept just for tradition. +// node-assert has evolved a lot since then, both in API and behavior. + +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Originally from narwhal.js (http://narwhaljs.org) +// Copyright (c) 2009 Thomas Robinson <280north.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the 'Software'), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +var util = _dereq_('util/'); +var hasOwn = Object.prototype.hasOwnProperty; +var pSlice = Array.prototype.slice; +var functionsHaveNames = (function () { + return function foo() {}.name === 'foo'; +}()); +function pToString (obj) { + return Object.prototype.toString.call(obj); +} +function isView(arrbuf) { + if (isBuffer(arrbuf)) { + return false; + } + if (typeof global.ArrayBuffer !== 'function') { + return false; + } + if (typeof ArrayBuffer.isView === 'function') { + return ArrayBuffer.isView(arrbuf); + } + if (!arrbuf) { + return false; + } + if (arrbuf instanceof DataView) { + return true; + } + if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) { + return true; + } + return false; +} +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = module.exports = ok; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) + +var regex = /\s*function\s+([^\(\s]*)\s*/; +// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js +function getName(func) { + if (!util.isFunction(func)) { + return; + } + if (functionsHaveNames) { + return func.name; + } + var str = func.toString(); + var match = str.match(regex); + return match && match[1]; +} +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } else { + // non v8 browsers so we can have a stacktrace + var err = new Error(); + if (err.stack) { + var out = err.stack; + + // try to strip useless frames + var fn_name = getName(stackStartFunction); + var idx = out.indexOf('\n' + fn_name); + if (idx >= 0) { + // once we have located the function frame + // we need to strip out everything before it (and its line) + var next_line = out.indexOf('\n', idx + 1); + out = out.substring(next_line + 1); + } + + this.stack = out; + } + } +}; + +// assert.AssertionError instanceof Error +util.inherits(assert.AssertionError, Error); + +function truncate(s, n) { + if (typeof s === 'string') { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } +} +function inspect(something) { + if (functionsHaveNames || !util.isFunction(something)) { + return util.inspect(something); + } + var rawname = getName(something); + var name = rawname ? ': ' + rawname : ''; + return '[Function' + name + ']'; +} +function getMessage(self) { + return truncate(inspect(self.actual), 128) + ' ' + + self.operator + ' ' + + truncate(inspect(self.expected), 128); +} + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); +} +assert.ok = ok; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected, false)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } +}; + +assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { + if (!_deepEqual(actual, expected, true)) { + fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual); + } +}; + +function _deepEqual(actual, expected, strict, memos) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + } else if (isBuffer(actual) && isBuffer(expected)) { + return compare(actual, expected) === 0; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); + + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; + + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if ((actual === null || typeof actual !== 'object') && + (expected === null || typeof expected !== 'object')) { + return strict ? actual === expected : actual == expected; + + // If both values are instances of typed arrays, wrap their underlying + // ArrayBuffers in a Buffer each to increase performance + // This optimization requires the arrays to have the same type as checked by + // Object.prototype.toString (aka pToString). Never perform binary + // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their + // bit patterns are not identical. + } else if (isView(actual) && isView(expected) && + pToString(actual) === pToString(expected) && + !(actual instanceof Float32Array || + actual instanceof Float64Array)) { + return compare(new Uint8Array(actual.buffer), + new Uint8Array(expected.buffer)) === 0; + + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else if (isBuffer(actual) !== isBuffer(expected)) { + return false; + } else { + memos = memos || {actual: [], expected: []}; + + var actualIndex = memos.actual.indexOf(actual); + if (actualIndex !== -1) { + if (actualIndex === memos.expected.indexOf(expected)) { + return true; + } + } + + memos.actual.push(actual); + memos.expected.push(expected); + + return objEquiv(actual, expected, strict, memos); + } +} + +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv(a, b, strict, actualVisitedObjects) { + if (a === null || a === undefined || b === null || b === undefined) + return false; + // if one is a primitive, the other must be same + if (util.isPrimitive(a) || util.isPrimitive(b)) + return a === b; + if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) + return false; + var aIsArgs = isArguments(a); + var bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) + return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b, strict); + } + var ka = objectKeys(a); + var kb = objectKeys(b); + var key, i; + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length !== kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] !== kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) + return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected, false)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +}; + +assert.notDeepStrictEqual = notDeepStrictEqual; +function notDeepStrictEqual(actual, expected, message) { + if (_deepEqual(actual, expected, true)) { + fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual); + } +} + + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } +}; + +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } + + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } + + try { + if (actual instanceof expected) { + return true; + } + } catch (e) { + // Ignore. The instanceof check doesn't work for arrow functions. + } + + if (Error.isPrototypeOf(expected)) { + return false; + } + + return expected.call({}, actual) === true; +} + +function _tryBlock(block) { + var error; + try { + block(); + } catch (e) { + error = e; + } + return error; +} + +function _throws(shouldThrow, block, expected, message) { + var actual; + + if (typeof block !== 'function') { + throw new TypeError('"block" argument must be a function'); + } + + if (typeof expected === 'string') { + message = expected; + expected = null; + } + + actual = _tryBlock(block); + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); + } + + var userProvidedMessage = typeof message === 'string'; + var isUnwantedException = !shouldThrow && util.isError(actual); + var isUnexpectedException = !shouldThrow && actual && !expected; + + if ((isUnwantedException && + userProvidedMessage && + expectedException(actual, expected)) || + isUnexpectedException) { + fail(actual, expected, 'Got unwanted exception' + message); + } + + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } +} + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws(true, block, error, message); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { + _throws(false, block, error, message); +}; + +assert.ifError = function(err) { if (err) throw err; }; + +// Expose a strict only variant of assert +function strict(value, message) { + if (!value) fail(value, true, message, '==', strict); +} +assert.strict = objectAssign(strict, assert, { + equal: assert.strictEqual, + deepEqual: assert.deepStrictEqual, + notEqual: assert.notStrictEqual, + notDeepEqual: assert.notDeepStrictEqual +}); +assert.strict.strict = assert.strict; + +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + if (hasOwn.call(obj, key)) keys.push(key); + } + return keys; +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"object-assign":"/../node_modules/object-assign/index.js","util/":"/../node_modules/assert/node_modules/util/util.js"}],"/../node_modules/assert/node_modules/inherits/inherits_browser.js":[function(_dereq_,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],"/../node_modules/assert/node_modules/util/support/isBufferBrowser.js":[function(_dereq_,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; +} +},{}],"/../node_modules/assert/node_modules/util/util.js":[function(_dereq_,module,exports){ +(function (process,global){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; + + +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global.process)) { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } + + if (process.noDeprecation === true) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +}; + + +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; + + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); +} +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } +} + + +function stylizeNoColor(str, styleType) { + return str; +} + + +function arrayToHash(array) { + var hash = {}; + + array.forEach(function(val, idx) { + hash[val] = true; + }); + + return hash; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); + + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } + + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +exports.isBuffer = _dereq_('./support/isBuffer'); + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} + + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} + + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = _dereq_('inherits'); + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; + +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./support/isBuffer":"/../node_modules/assert/node_modules/util/support/isBufferBrowser.js","_process":"/../node_modules/process/browser.js","inherits":"/../node_modules/assert/node_modules/inherits/inherits_browser.js"}],"/../node_modules/events/events.js":[function(_dereq_,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var objectCreate = Object.create || objectCreatePolyfill +var objectKeys = Object.keys || objectKeysPolyfill +var bind = Function.prototype.bind || functionBindPolyfill + +function EventEmitter() { + if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) { + this._events = objectCreate(null); + this._eventsCount = 0; + } + + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; -exports.worker = { - importScripts : true, - postMessage : true, - self : true, - FileReaderSync : true -}; +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; -// Widely adopted global names that are not part of ECMAScript standard -exports.nonstandard = { - escape : false, - unescape: false +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +var defaultMaxListeners = 200; + +var hasDefineProperty; +try { + var o = {}; + if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 }); + hasDefineProperty = o.x === 0; +} catch (err) { hasDefineProperty = false } +if (hasDefineProperty) { + Object.defineProperty(EventEmitter, 'defaultMaxListeners', { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + // check whether the input is a positive number (whose value is zero or + // greater and not a NaN). + if (typeof arg !== 'number' || arg < 0 || arg !== arg) + throw new TypeError('"defaultMaxListeners" must be a positive number'); + defaultMaxListeners = arg; + } + }); +} else { + EventEmitter.defaultMaxListeners = defaultMaxListeners; +} + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== 'number' || n < 0 || isNaN(n)) + throw new TypeError('"n" argument must be a positive number'); + this._maxListeners = n; + return this; }; -// Globals provided by popular JavaScript environments. +function $getMaxListeners(that) { + if (that._maxListeners === undefined) + return EventEmitter.defaultMaxListeners; + return that._maxListeners; +} -exports.couch = { - "require" : false, - respond : false, - getRow : false, - emit : false, - send : false, - start : false, - sum : false, - log : false, - exports : false, - module : false, - provides : false +EventEmitter.prototype.getMaxListeners = function getMaxListeners() { + return $getMaxListeners(this); }; -exports.node = { - __filename : false, - __dirname : false, - GLOBAL : false, - global : false, - module : false, - require : false, +// These standalone emit* functions are used to optimize calling of event +// handlers for fast cases because emit() itself often has a variable number of +// arguments and can be deoptimized because of that. These functions always have +// the same number of arguments and thus do not get deoptimized, so the code +// inside them can execute faster. +function emitNone(handler, isFn, self) { + if (isFn) + handler.call(self); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self); + } +} +function emitOne(handler, isFn, self, arg1) { + if (isFn) + handler.call(self, arg1); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1); + } +} +function emitTwo(handler, isFn, self, arg1, arg2) { + if (isFn) + handler.call(self, arg1, arg2); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1, arg2); + } +} +function emitThree(handler, isFn, self, arg1, arg2, arg3) { + if (isFn) + handler.call(self, arg1, arg2, arg3); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1, arg2, arg3); + } +} - // These globals are writeable because Node allows the following - // usage pattern: var Buffer = require("buffer").Buffer; +function emitMany(handler, isFn, self, args) { + if (isFn) + handler.apply(self, args); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].apply(self, args); + } +} - Buffer : true, - console : true, - exports : true, - process : true, - setTimeout : true, - clearTimeout : true, - setInterval : true, - clearInterval : true, - setImmediate : true, // v0.9.1+ - clearImmediate: true // v0.9.1+ -}; +EventEmitter.prototype.emit = function emit(type) { + var er, handler, len, args, i, events; + var doError = (type === 'error'); -exports.browserify = { - __filename : false, - __dirname : false, - global : false, - module : false, - require : false, - Buffer : true, - exports : true, - process : true -}; + events = this._events; + if (events) + doError = (doError && events.error == null); + else if (!doError) + return false; -exports.phantom = { - phantom : true, - require : true, - WebPage : true, - console : true, // in examples, but undocumented - exports : true // v1.7+ -}; + // If there is no 'error' event listener then throw. + if (doError) { + if (arguments.length > 1) + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } else { + // At least give some kind of context to the user + var err = new Error('Unhandled "error" event. (' + er + ')'); + err.context = er; + throw err; + } + return false; + } -exports.qunit = { - asyncTest : false, - deepEqual : false, - equal : false, - expect : false, - module : false, - notDeepEqual : false, - notEqual : false, - notPropEqual : false, - notStrictEqual : false, - ok : false, - propEqual : false, - QUnit : false, - raises : false, - start : false, - stop : false, - strictEqual : false, - test : false, - "throws" : false + handler = events[type]; + + if (!handler) + return false; + + var isFn = typeof handler === 'function'; + len = arguments.length; + switch (len) { + // fast cases + case 1: + emitNone(handler, isFn, this); + break; + case 2: + emitOne(handler, isFn, this, arguments[1]); + break; + case 3: + emitTwo(handler, isFn, this, arguments[1], arguments[2]); + break; + case 4: + emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]); + break; + // slower + default: + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + emitMany(handler, isFn, this, args); + } + + return true; }; -exports.rhino = { - defineClass : false, - deserialize : false, - gc : false, - help : false, - importClass : false, - importPackage: false, - "java" : false, - load : false, - loadClass : false, - Packages : false, - print : false, - quit : false, - readFile : false, - readUrl : false, - runCommand : false, - seal : false, - serialize : false, - spawn : false, - sync : false, - toint32 : false, - version : false +function _addListener(target, type, listener, prepend) { + var m; + var events; + var existing; + + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + + events = target._events; + if (!events) { + events = target._events = objectCreate(null); + target._eventsCount = 0; + } else { + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (events.newListener) { + target.emit('newListener', type, + listener.listener ? listener.listener : listener); + + // Re-assign `events` because a newListener handler could have caused the + // this._events to be assigned to a new object + events = target._events; + } + existing = events[type]; + } + + if (!existing) { + // Optimize the case of one listener. Don't need the extra array object. + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === 'function') { + // Adding the second element, need to change to array. + existing = events[type] = + prepend ? [listener, existing] : [existing, listener]; + } else { + // If we've already got an array, just append. + if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); + } + } + + // Check for listener leak + if (!existing.warned) { + m = $getMaxListeners(target); + if (m && m > 0 && existing.length > m) { + existing.warned = true; + var w = new Error('Possible EventEmitter memory leak detected. ' + + existing.length + ' "' + String(type) + '" listeners ' + + 'added. Use emitter.setMaxListeners() to ' + + 'increase limit.'); + w.name = 'MaxListenersExceededWarning'; + w.emitter = target; + w.type = type; + w.count = existing.length; + if (typeof console === 'object' && console.warn) { + console.warn('%s: %s', w.name, w.message); + } + } + } + } + + return target; +} + +EventEmitter.prototype.addListener = function addListener(type, listener) { + return _addListener(this, type, listener, false); }; -exports.shelljs = { - target : false, - echo : false, - exit : false, - cd : false, - pwd : false, - ls : false, - find : false, - cp : false, - rm : false, - mv : false, - mkdir : false, - test : false, - cat : false, - sed : false, - grep : false, - which : false, - dirs : false, - pushd : false, - popd : false, - env : false, - exec : false, - chmod : false, - config : false, - error : false, - tempdir : false +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.prependListener = + function prependListener(type, listener) { + return _addListener(this, type, listener, true); + }; + +function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + switch (arguments.length) { + case 0: + return this.listener.call(this.target); + case 1: + return this.listener.call(this.target, arguments[0]); + case 2: + return this.listener.call(this.target, arguments[0], arguments[1]); + case 3: + return this.listener.call(this.target, arguments[0], arguments[1], + arguments[2]); + default: + var args = new Array(arguments.length); + for (var i = 0; i < args.length; ++i) + args[i] = arguments[i]; + this.listener.apply(this.target, args); + } + } +} + +function _onceWrap(target, type, listener) { + var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; + var wrapped = bind.call(onceWrapper, state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; +} + +EventEmitter.prototype.once = function once(type, listener) { + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + this.on(type, _onceWrap(this, type, listener)); + return this; }; -exports.typed = { - ArrayBuffer : false, - ArrayBufferView : false, - DataView : false, - Float32Array : false, - Float64Array : false, - Int16Array : false, - Int32Array : false, - Int8Array : false, - Uint16Array : false, - Uint32Array : false, - Uint8Array : false, - Uint8ClampedArray : false -}; +EventEmitter.prototype.prependOnceListener = + function prependOnceListener(type, listener) { + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + this.prependListener(type, _onceWrap(this, type, listener)); + return this; + }; + +// Emits a 'removeListener' event if and only if the listener was removed. +EventEmitter.prototype.removeListener = + function removeListener(type, listener) { + var list, events, position, i, originalListener; + + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + + events = this._events; + if (!events) + return this; + + list = events[type]; + if (!list) + return this; + + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) + this._events = objectCreate(null); + else { + delete events[type]; + if (events.removeListener) + this.emit('removeListener', type, list.listener || listener); + } + } else if (typeof list !== 'function') { + position = -1; + + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; + break; + } + } + + if (position < 0) + return this; + + if (position === 0) + list.shift(); + else + spliceOne(list, position); + + if (list.length === 1) + events[type] = list[0]; + + if (events.removeListener) + this.emit('removeListener', type, originalListener || listener); + } + + return this; + }; + +EventEmitter.prototype.removeAllListeners = + function removeAllListeners(type) { + var listeners, events, i; + + events = this._events; + if (!events) + return this; + + // not listening for removeListener, no need to emit + if (!events.removeListener) { + if (arguments.length === 0) { + this._events = objectCreate(null); + this._eventsCount = 0; + } else if (events[type]) { + if (--this._eventsCount === 0) + this._events = objectCreate(null); + else + delete events[type]; + } + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + var keys = objectKeys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = objectCreate(null); + this._eventsCount = 0; + return this; + } + + listeners = events[type]; + + if (typeof listeners === 'function') { + this.removeListener(type, listeners); + } else if (listeners) { + // LIFO order + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } + } + + return this; + }; -exports.wsh = { - ActiveXObject : true, - Enumerator : true, - GetObject : true, - ScriptEngine : true, - ScriptEngineBuildVersion : true, - ScriptEngineMajorVersion : true, - ScriptEngineMinorVersion : true, - VBArray : true, - WSH : true, - WScript : true, - XDomainRequest : true -}; +function _listeners(target, type, unwrap) { + var events = target._events; -// Globals provided by popular JavaScript libraries. + if (!events) + return []; -exports.dojo = { - dojo : false, - dijit : false, - dojox : false, - define : false, - "require": false + var evlistener = events[type]; + if (!evlistener) + return []; + + if (typeof evlistener === 'function') + return unwrap ? [evlistener.listener || evlistener] : [evlistener]; + + return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); +} + +EventEmitter.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); }; -exports.jquery = { - "$" : false, - jQuery : false +EventEmitter.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); }; -exports.mootools = { - "$" : false, - "$$" : false, - Asset : false, - Browser : false, - Chain : false, - Class : false, - Color : false, - Cookie : false, - Core : false, - Document : false, - DomReady : false, - DOMEvent : false, - DOMReady : false, - Drag : false, - Element : false, - Elements : false, - Event : false, - Events : false, - Fx : false, - Group : false, - Hash : false, - HtmlTable : false, - IFrame : false, - IframeShim : false, - InputValidator: false, - instanceOf : false, - Keyboard : false, - Locale : false, - Mask : false, - MooTools : false, - Native : false, - Options : false, - OverText : false, - Request : false, - Scroller : false, - Slick : false, - Slider : false, - Sortables : false, - Spinner : false, - Swiff : false, - Tips : false, - Type : false, - typeOf : false, - URI : false, - Window : false +EventEmitter.listenerCount = function(emitter, type) { + if (typeof emitter.listenerCount === 'function') { + return emitter.listenerCount(type); + } else { + return listenerCount.call(emitter, type); + } }; -exports.prototypejs = { - "$" : false, - "$$" : false, - "$A" : false, - "$F" : false, - "$H" : false, - "$R" : false, - "$break" : false, - "$continue" : false, - "$w" : false, - Abstract : false, - Ajax : false, - Class : false, - Enumerable : false, - Element : false, - Event : false, - Field : false, - Form : false, - Hash : false, - Insertion : false, - ObjectRange : false, - PeriodicalExecuter: false, - Position : false, - Prototype : false, - Selector : false, - Template : false, - Toggle : false, - Try : false, - Autocompleter : false, - Builder : false, - Control : false, - Draggable : false, - Draggables : false, - Droppables : false, - Effect : false, - Sortable : false, - SortableObserver : false, - Sound : false, - Scriptaculous : false +EventEmitter.prototype.listenerCount = listenerCount; +function listenerCount(type) { + var events = this._events; + + if (events) { + var evlistener = events[type]; + + if (typeof evlistener === 'function') { + return 1; + } else if (evlistener) { + return evlistener.length; + } + } + + return 0; +} + +EventEmitter.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; }; -exports.yui = { - YUI : false, - Y : false, - YUI_config: false +// About 1.5x faster than the two-arg version of Array#splice(). +function spliceOne(list, index) { + for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) + list[i] = list[k]; + list.pop(); +} + +function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) + copy[i] = arr[i]; + return copy; +} + +function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; +} + +function objectCreatePolyfill(proto) { + var F = function() {}; + F.prototype = proto; + return new F; +} +function objectKeysPolyfill(obj) { + var keys = []; + for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) { + keys.push(k); + } + return k; +} +function functionBindPolyfill(context) { + var fn = this; + return function () { + return fn.apply(context, arguments); + }; +} + +},{}],"/../node_modules/object-assign/index.js":[function(_dereq_,module,exports){ +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ + +'use strict'; +/* eslint-disable no-unused-vars */ +var getOwnPropertySymbols = Object.getOwnPropertySymbols; +var hasOwnProperty = Object.prototype.hasOwnProperty; +var propIsEnumerable = Object.prototype.propertyIsEnumerable; + +function toObject(val) { + if (val === null || val === undefined) { + throw new TypeError('Object.assign cannot be called with null or undefined'); + } + + return Object(val); +} + +function shouldUseNative() { + try { + if (!Object.assign) { + return false; + } + + // Detect buggy property enumeration order in older V8 versions. + + // https://bugs.chromium.org/p/v8/issues/detail?id=4118 + var test1 = new String('abc'); // eslint-disable-line no-new-wrappers + test1[5] = 'de'; + if (Object.getOwnPropertyNames(test1)[0] === '5') { + return false; + } + + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test2 = {}; + for (var i = 0; i < 10; i++) { + test2['_' + String.fromCharCode(i)] = i; + } + var order2 = Object.getOwnPropertyNames(test2).map(function (n) { + return test2[n]; + }); + if (order2.join('') !== '0123456789') { + return false; + } + + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test3 = {}; + 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { + test3[letter] = letter; + }); + if (Object.keys(Object.assign({}, test3)).join('') !== + 'abcdefghijklmnopqrst') { + return false; + } + + return true; + } catch (err) { + // We don't expect any of the above to throw, but better to be safe. + return false; + } +} + +module.exports = shouldUseNative() ? Object.assign : function (target, source) { + var from; + var to = toObject(target); + var symbols; + + for (var s = 1; s < arguments.length; s++) { + from = Object(arguments[s]); + + for (var key in from) { + if (hasOwnProperty.call(from, key)) { + to[key] = from[key]; + } + } + + if (getOwnPropertySymbols) { + symbols = getOwnPropertySymbols(from); + for (var i = 0; i < symbols.length; i++) { + if (propIsEnumerable.call(from, symbols[i])) { + to[symbols[i]] = from[symbols[i]]; + } + } + } + } + + return to; }; -exports.mocha = { - // Global (for config etc.) - mocha : false, - // BDD - describe : false, - xdescribe : false, - it : false, - xit : false, - context : false, - xcontext : false, - before : false, - after : false, - beforeEach : false, - afterEach : false, - // TDD - suite : false, - test : false, - setup : false, - teardown : false, - suiteSetup : false, - suiteTeardown : false +},{}],"/../node_modules/process/browser.js":[function(_dereq_,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } }; -exports.jasmine = { - jasmine : false, - describe : false, - xdescribe : false, - it : false, - xit : false, - beforeEach : false, - afterEach : false, - setFixtures : false, - loadFixtures: false, - spyOn : false, - expect : false, - // Jasmine 1.3 - runs : false, - waitsFor : false, - waits : false, - // Jasmine 2.1 - beforeAll : false, - afterAll : false, - fail : false, - fdescribe : false, - fit : false, - pending : false +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); }; -},{}]},{},["/node_modules/jshint/src/jshint.js"]); +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],"/../node_modules/util/node_modules/inherits/inherits_browser.js":[function(_dereq_,module,exports){ +arguments[4]["/../node_modules/assert/node_modules/inherits/inherits_browser.js"][0].apply(exports,arguments) +},{}],"/../node_modules/util/support/isBufferBrowser.js":[function(_dereq_,module,exports){ +arguments[4]["/../node_modules/assert/node_modules/util/support/isBufferBrowser.js"][0].apply(exports,arguments) +},{}],"/../node_modules/util/util.js":[function(_dereq_,module,exports){ +arguments[4]["/../node_modules/assert/node_modules/util/util.js"][0].apply(exports,arguments) +},{"./support/isBuffer":"/../node_modules/util/support/isBufferBrowser.js","_process":"/../node_modules/process/browser.js","inherits":"/../node_modules/util/node_modules/inherits/inherits_browser.js"}]},{},["/../../jshint/src/jshint.js"]); }); \ No newline at end of file From b42368c580a79694c21990516f47dab32f1cb4a4 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 6 Apr 2020 00:50:03 +0900 Subject: [PATCH 0327/1293] fix typo --- lib/ace/keyboard/textinput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 6b62c626690..7aef4913022 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -88,7 +88,7 @@ var TextInput = function(parentNode, host) { if (ignoreFocusEvents) return; isFocused = true; if (useragent.isEdge) { - // on edge focus event nnis fired even if document itself is not focused + // on edge focus event is fired even if document itself is not focused try { if (!document.hasFocus()) return; From 13bf55ef553e76d21e2ebf47167fadbf881e5312 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 3 Apr 2020 23:57:42 +0400 Subject: [PATCH 0328/1293] changes from cloud9 --- lib/ace/edit_session.js | 5 +- lib/ace/editor.js | 2 +- lib/ace/ext/code_lens.js | 19 +- lib/ace/ext/code_lens_test.js | 14 +- lib/ace/keyboard/textinput.js | 76 ++-- lib/ace/lib/dom.js | 7 +- lib/ace/mode/_test/highlight_rules_test.js | 2 +- lib/ace/test/mockdom.js | 398 +++++++++++++++------ lib/ace/test/mockdom_test.js | 80 +++++ lib/ace/virtual_renderer.js | 7 + 10 files changed, 437 insertions(+), 173 deletions(-) create mode 100644 lib/ace/test/mockdom_test.js diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 25b95427075..3e48a10bab0 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -898,7 +898,8 @@ EditSession.$uid = 0; this.$modeId = mode.$id; if (this.$mode === mode) return; - + + var oldMode = this.$mode; this.$mode = mode; this.$stopWorker(); @@ -936,7 +937,7 @@ EditSession.$uid = 0; this.$options.wrapMethod.set.call(this, this.$wrapMethod); this.$setFolding(mode.foldingRules); this.bgTokenizer.start(0); - this._emit("changeMode"); + this._emit("changeMode", {oldMode: oldMode, mode: mode}); } }; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 3578da8d171..9a82056df01 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -167,7 +167,7 @@ Editor.$uid = 0; }; this.endOperation = function(e) { - if (this.curOp) { + if (this.curOp && this.session) { if (e && e.returnValue === false || !this.session) return (this.curOp = null); if (e == true && this.curOp.command && this.curOp.command.name == "mouse") diff --git a/lib/ace/ext/code_lens.js b/lib/ace/ext/code_lens.js index 0247a6e2bf9..fd9215050d1 100644 --- a/lib/ace/ext/code_lens.js +++ b/lib/ace/ext/code_lens.js @@ -151,12 +151,14 @@ exports.setLenses = function(session, lenses) { function attachToEditor(editor) { editor.codeLensProviders = []; editor.renderer.on("afterRender", renderWidgets); - editor.$codeLensClickHandler = function(e) { - var command = e.target.lensCommand; - if (command) - editor.execCommand(command.id, command.arguments); - }; - event.addListener(editor.container, "click", editor.$codeLensClickHandler, editor); + if (!editor.$codeLensClickHandler) { + editor.$codeLensClickHandler = function(e) { + var command = e.target.lensCommand; + if (command) + editor.execCommand(command.id, command.arguments); + }; + event.addListener(editor.container, "click", editor.$codeLensClickHandler, editor); + } editor.$updateLenses = function() { var session = editor.session; if (!session) return; @@ -169,8 +171,9 @@ function attachToEditor(editor) { var providersToWaitNum = editor.codeLensProviders.length; var lenses = []; editor.codeLensProviders.forEach(function(provider) { - provider.provideCodeLenses(session, function(currentLenses) { - currentLenses.forEach(function(lens) { + provider.provideCodeLenses(session, function(err, payload) { + if (err) return; + payload.forEach(function(lens) { lenses.push(lens); }); providersToWaitNum--; diff --git a/lib/ace/ext/code_lens_test.js b/lib/ace/ext/code_lens_test.js index 4d03c240cce..d9526bb24ad 100644 --- a/lib/ace/ext/code_lens_test.js +++ b/lib/ace/ext/code_lens_test.js @@ -83,7 +83,7 @@ module.exports = { codeLens.registerCodeLensProvider(editor, { provideCodeLenses: function(session, callback) { - callback([{ + callback(null, [{ start: { row: 1 }, @@ -146,7 +146,7 @@ module.exports = { codeLens.registerCodeLensProvider(editor, { provideCodeLenses: function(session, callback) { setTimeout(function() { - callback([{ + callback(null, [{ start: { row: 1 }, command: { title: "code lens" } }]); @@ -170,7 +170,7 @@ module.exports = { new Promise(function(resolve) { codeLens.registerCodeLensProvider(editor, { provideCodeLenses: function(session, callback) { - callback([{ + callback(null, [{ start: { row: 1 }, command: { title: "1" } }]); @@ -179,7 +179,7 @@ module.exports = { codeLens.registerCodeLensProvider(editor, { provideCodeLenses: function(session, callback) { setTimeout(function() { - callback([{ + callback(null, [{ start: { row: 2 }, command: { title: "2" } }]); @@ -203,7 +203,7 @@ module.exports = { editor.session.setValue("a\nb\nc"); codeLens.registerCodeLensProvider(editor, { provideCodeLenses: function(session, callback) { - callback([{ + callback(null, [{ start: { row: 1 }, command: { title: "1" } }]); @@ -211,7 +211,7 @@ module.exports = { }); codeLens.registerCodeLensProvider(editor, { provideCodeLenses: function(session, callback) { - callback([{ + callback(null, [{ start: { row: 1 }, command: { title: "2" } }]); @@ -227,7 +227,7 @@ module.exports = { editor.session.setValue("a\nb"); codeLens.registerCodeLensProvider(editor, { provideCodeLenses: function(session, callback) { - callback([{ + callback(null, [{ start: { row: 1 }, command: { title: session.doc.$lines[0] } }]); diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 3ce3e3f6cf1..a721397015c 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -147,9 +147,11 @@ var TextInput = function(parentNode, host) { }; host.on("beforeEndOperation", function() { - if (host.curOp && host.curOp.command.name == "insertstring") + var curOp = host.curOp; + var commandName = curOp && curOp.command && curOp.command.name; + if (commandName == "insertstring") return; - if (inComposition) { + if (inComposition && commandName) { // exit composition from commands other than insertstring lastValue = text.value = ""; onCompositionEnd(); @@ -186,38 +188,44 @@ var TextInput = function(parentNode, host) { // see https://github.com/ajaxorg/ace/issues/2114 inComposition = true; - var selection = host.selection; - var range = selection.getRange(); - var row = selection.cursor.row; - var selectionStart = range.start.column; - var selectionEnd = range.end.column; - var line = host.session.getLine(row); - - if (range.start.row != row) { - var prevLine = host.session.getLine(row - 1); - selectionStart = range.start.row < row - 1 ? 0 : selectionStart; - selectionEnd += prevLine.length + 1; - line = prevLine + "\n" + line; - } - else if (range.end.row != row) { - var nextLine = host.session.getLine(row + 1); - selectionEnd = range.end.row > row + 1 ? nextLine.length : selectionEnd; - selectionEnd += line.length + 1; - line = line + "\n" + nextLine; - } - else if (isMobile) { - line = "\n" + line; - selectionEnd += 1; - selectionStart += 1; - } + var selectionStart = 0; + var selectionEnd = 0; + var line = ""; + + if (host.session) { + var selection = host.selection; + var range = selection.getRange(); + var row = selection.cursor.row; + selectionStart = range.start.column; + selectionEnd = range.end.column; + line = host.session.getLine(row); + + if (range.start.row != row) { + var prevLine = host.session.getLine(row - 1); + selectionStart = range.start.row < row - 1 ? 0 : selectionStart; + selectionEnd += prevLine.length + 1; + line = prevLine + "\n" + line; + } + else if (range.end.row != row) { + var nextLine = host.session.getLine(row + 1); + selectionEnd = range.end.row > row + 1 ? nextLine.length : selectionEnd; + selectionEnd += line.length + 1; + line = line + "\n" + nextLine; + } + else if (isMobile) { + line = "\n" + line; + selectionEnd += 1; + selectionStart += 1; + } - if (line.length > MAX_LINE_LENGTH) { - if (selectionStart < MAX_LINE_LENGTH && selectionEnd < MAX_LINE_LENGTH) { - line = line.slice(0, MAX_LINE_LENGTH); - } else { - line = "\n"; - selectionStart = 0; - selectionEnd = 1; + if (line.length > MAX_LINE_LENGTH) { + if (selectionStart < MAX_LINE_LENGTH && selectionEnd < MAX_LINE_LENGTH) { + line = line.slice(0, MAX_LINE_LENGTH); + } else { + line = "\n"; + selectionStart = 0; + selectionEnd = 1; + } } } @@ -246,6 +254,7 @@ var TextInput = function(parentNode, host) { } inComposition = false; }; + this.resetSelection = resetSelection; if (isFocused) host.onFocus(); @@ -469,6 +478,7 @@ var TextInput = function(parentNode, host) { return; setTimeout(onCompositionUpdate, 0); + host._signal("compositionStart"); host.on("mousedown", cancelComposition); var range = host.getSelectionRange(); diff --git a/lib/ace/lib/dom.js b/lib/ace/lib/dom.js index 33c62a41735..e34cdfdc889 100644 --- a/lib/ace/lib/dom.js +++ b/lib/ace/lib/dom.js @@ -42,8 +42,11 @@ exports.buildDom = function buildDom(arr, parent, refs) { return txt; } - if (!Array.isArray(arr)) + if (!Array.isArray(arr)) { + if (arr && arr.appendChild && parent) + parent.appendChild(arr); return arr; + } if (typeof arr[0] != "string" || !arr[0]) { var els = []; for (var i = 0; i < arr.length; i++) { @@ -65,7 +68,7 @@ exports.buildDom = function buildDom(arr, parent, refs) { var val = options[n]; if (n === "class") { el.className = Array.isArray(val) ? val.join(" ") : val; - } else if (typeof val == "function" || n == "value") { + } else if (typeof val == "function" || n == "value" || n[0] == "$") { el[n] = val; } else if (n === "ref") { if (refs) refs[val] = el; diff --git a/lib/ace/mode/_test/highlight_rules_test.js b/lib/ace/mode/_test/highlight_rules_test.js index c35cbf04097..e48042f6c62 100644 --- a/lib/ace/mode/_test/highlight_rules_test.js +++ b/lib/ace/mode/_test/highlight_rules_test.js @@ -56,7 +56,7 @@ function checkModes() { jsFileList(cwd + "../../snippets").forEach(function(snippetFileName) { if (!snippets["ace/snippets/" + snippetFileName]) - throw new Error(snippetFileName + " is not used"); + throw new Error("Snippet file " + snippetFileName + " is not used"); delete snippets["ace/snippets/" + snippetFileName]; }) ; if (Object.keys(snippets).length) { diff --git a/lib/ace/test/mockdom.js b/lib/ace/test/mockdom.js index e63f6106820..39d27094fdf 100644 --- a/lib/ace/test/mockdom.js +++ b/lib/ace/test/mockdom.js @@ -12,6 +12,7 @@ var WINDOW_WIDTH = 1024; function Style() { } +Style.prototype.getPropertyValue = function() { return ""; }; Style.prototype.__defineGetter__("cssText", function() { var cssText = ""; Object.keys(this).forEach(function(key) { @@ -70,14 +71,22 @@ var initializers = { this.select = function() { this.setSelectionRange(0, Infinity); }; + }, + style: function() { + this.sheet = { + insertRule: function() {}, + cssRules: [] + }; } }; +function getItem(i) { return this[i]; } + function Node(name) { this.localName = name; this.value = ""; - this.tagName = name && name.toUpperCase(); this.children = this.childNodes = []; + this.childNodes.item = getItem; this.ownerDocument = window.document || this; this.$attributes = {}; this.style = new Style(); @@ -112,8 +121,8 @@ function Node(name) { if (!document.contains(document.activeElement)) document.activeElement = document.body; }; - this.remove = function() { - this.parentNode && this.parentNode.removeChild(this); + this.remove = function() { + this.parentNode && this.parentNode.removeChild(this); }; this.replaceChild = function(node, oldNode) { this.insertBefore(node, oldNode); @@ -143,31 +152,36 @@ function Node(name) { return node; }; - this.querySelectorAll = function(s) { - var tests = []; - s.replace(/([#.])?([\w-]+)|\[([\w-]+)(?:=([\w-]+))?\]/g, function(_, hash, name, attr, attrValue) { - if (hash == "#") { - tests.push(function(node) { return node.id == name; }); - } - else if (hash == ".") { - var re = new RegExp("\\b" + name + "\\b"); - return tests.push(function(node) { return re.test(node.className); }); - } - else if (name) { - return tests.push(function(node) { return node.localName == name; }); - } - else if (attr) { - return tests.push(function(node) { - return node.getAttribute(attr) == attrValue; - }); - } - return _; - }); + this.hasChildNodes = function() { + return this.childNodes.length > 0; + }; + this.__defineGetter__("childElementCount", function() { + return this.childNodes.length; + }); + this.hasAttributes = function() { + return Object.keys(this.$attributes).length > 0; + }; + this.querySelectorAll = function(selector) { + var parts = selector.split(/((?:[^\s>"[]|"[^"]+"?|\[[^\]]*\]?)+)/); + for (var i = 1; i < parts.length; i += 2) { + parts[i] = parseSimpleSelector(parts[i]); + if (/^ +$/.test(parts[i + 1])) parts[i + 1] = " "; + } + var nodes = []; - walk(this, function(node) { - if (tests.every(function(t) {return t(node);})) - nodes.push(node); - }); + function search(root, parts) { + var operator = parts[0]; + var tests = parts[1]; + var iterator = operator == ">" ? walkShallow : walk; + iterator(root, function(node) { + var isAMatch = tests.every(function(t) {return t(node);}); + if (isAMatch) { + if (parts.length > 3) search(node, parts.slice(2)); + else nodes.push(node); + } + }); + } + search(this, parts); return nodes; }; this.querySelector = function(s) { @@ -188,19 +202,30 @@ function Node(name) { return node; }); }; + this.removeAttribute = function(a) { + delete this.$attributes[a]; + }; this.setAttribute = function(a, v) { this.$attributes[a] = v; }; this.getAttribute = function(a, v) { return String(this.$attributes[a] || ""); }; + this.__defineGetter__("nodeName", function() { + return this.localName; + }); + this.__defineGetter__("tagName", function() { + return this.localName; + }); this.__defineGetter__("attributes", function() { var style = this.style.cssText; if (style) this.$attributes.style = style; - return Object.keys(this.$attributes).map(function(key) { + var attributes = Object.keys(this.$attributes).map(function(key) { return new Attr(key, this.$attributes[key]); }, this); + attributes.item = getItem; + return attributes; }); this.__defineGetter__("classList", function() { return this.$classList || (this.$classList = new ClassList(this)); @@ -246,103 +271,94 @@ function Node(name) { }).join(""); }); this.__defineGetter__("outerHTML", function() { - var attributes = this.attributes.map(function(attr) { + var attributes = this.attributes.map(function(attr) { return attr.name + "=" + JSON.stringify(attr.value); }, this).join(" "); return "<" + this.localName + (attributes ? " " + attributes : "") + ">" + this.innerHTML + ""; }); + this.__format = function(indent) { + if (!indent) indent = ""; + var attributes = this.attributes.map(function(attr) { + return attr.name + "=" + JSON.stringify(attr.value); + }, this).join(" "); + return indent + "<" + this.localName + (attributes ? " " + attributes : "") + ">" + + this.children.map(function(ch) { + return "__format" in ch ? "\n" + ch.__format(indent + " ") : escapeHTML(ch.data); + }).join("") + + "\n" + indent + ""; + }; this.__defineSetter__("innerHTML", function(v) { removeAllChildren(this); - this.insertAdjacentHTML("beforeend", v); + setInnerHTML(v, this); }); - this.insertAdjacentHTML = function(position, markup) { - if (position != "beforeend") throw new Error("mock not implemented"); - var root = this; - var tagRe = /<(\/?[\w:\-]+)|&(?:(#?\w+);)|$/g; - var skipped = ""; - - for (var m, lastIndex = 0; m = tagRe.exec(markup);) { - skipped += markup.substring(lastIndex, m.index); - if (m[2]) { - if (m[2] == "gt") { - skipped += ">"; - } else if (m[2] == "lt") { - skipped += "<"; - } else if (m[2] == "amp") { - skipped += "&"; - } - lastIndex = tagRe.lastIndex ; - } else { - if (skipped) { - root.appendChild(document.createTextNode(skipped)); - skipped = ""; - } - var end = markup.indexOf(">", tagRe.lastIndex); - var selfClosing = markup[end - 1] === "/" ? 1 : 0; - var attributes = markup.slice(tagRe.lastIndex, end - selfClosing).trim(); - - tagRe.lastIndex = lastIndex = end < 0 ? markup.length : end + 1; - - if (!m[1]) { - return; - } - if (m[1][0] !== "/") { - var tagName = m[1]; - if (/:/.test(tagName)) { - var i = tagName.indexOf(":"); - var prefix = tagName.slice(0, i); - tagName = tagName.slice(i+1); - root = root.appendChild(document.createElement(tagName)); - root.prefix = prefix; - } else { - root = root.appendChild(document.createElement(tagName)); - } - attributes && attributes.replace(/([\w:-]+)\s*=\s*(?:"([^"]*)"|'([^"]*)'|(\w+))/g, function(_, key, v1,v2,v3) { - root.setAttribute(key, v1 || v2 || v3 || key); - }); - } - if (m[1][0] === "/" || selfClosing) { - if (root != this) - root = root.parentNode; - } - } - } + this.insertAdjacentHTML = function(position, markup) { + var element = document.createDocumentFragment(); + setInnerHTML(markup, element); + this.insertAdjacentElement(position, element); + }; + this.insertAdjacentElement = function(position, element) { + position = position.toLowerCase(); + if (position === "beforeend") this.appendChild(element); + if (position === "afterend") this.parentElement.insertBefore(element, this.nextSibling); + if (position === "afterbegin") this.insertBefore(element, this.firstChild); + if (position === "beforebegin") this.parentElement.insertBefore(element, this); }; this.getBoundingClientRect = function(v) { - var w = 0; - var h = 0; + var width = 0; + var height = 0; var top = 0; var left = 0; if (this == document.documentElement) { - w = WINDOW_WIDTH; - h = WINDOW_HEIGHT; + width = WINDOW_WIDTH; + height = WINDOW_HEIGHT; } else if (!document.contains(this) || this.style.display == "none") { - w = h = 0; + width = height = 0; } else if (this.style.width == "auto" || this.localName == "span") { - w = this.textContent.length * CHAR_WIDTH; - h = CHAR_HEIGHT; - } - else if (this.style.width) { - w = parseFloat(this.style.width) || 0; - h = parseFloat(this.style.height) || 0; - top = parseFloat(this.style.top) || 0; - left = parseFloat(this.style.left) || 0; + width = this.textContent.length * CHAR_WIDTH; + var node = this; + while (node) { + if (node.style.fontSize) { + height = parseInt(node.style.fontSize); + break; + } + node = node.parentNode; + } + if (!height) height = CHAR_HEIGHT; } - else if (this.style.right) { + else if (this.parentNode) { var rect = this.parentNode.getBoundingClientRect(); - w = rect.width - (parseFloat(this.style.left) || 0) - (parseFloat(this.style.right) || 0); - h = parseFloat(this.style.height) || rect.height; - top = rect.top; - left = rect.left + (parseFloat(this.style.left) || 0); - } - else if (this.localName == "div") { - w = WINDOW_WIDTH; + + left = parseCssLength(this.style.top || "0", rect.width); + top = parseCssLength(this.style.left || "0", rect.height); + var right = parseCssLength(this.style.right || "0", rect.width); + var bottom = parseCssLength(this.style.bottom || "0", rect.width); + + if (this.style.width) + width = parseCssLength(this.style.width || "100%", rect.width); + else + width = rect.width - right - left; + + if (this.style.width) + height = parseCssLength(this.style.height || "100%", rect.height); + else + height = rect.height - top - bottom; + + top += rect.top; + bottom += rect.bottom; } - return {top: top, left: left, width: w, height: h, right: 0}; + return {top: top, left: left, width: width, height: height, right: left + width, bottom: top + height}; }; + function parseCssLength(styleString, parentSize) { + // TODO support calc + var size = parseFloat(styleString) || 0; + if (/%/.test(styleString)) + size = parentSize * size / 100; + return size; + } + this.__defineGetter__("clientHeight", function() { return this.getBoundingClientRect().height; }); @@ -432,6 +448,120 @@ function Node(name) { } }).call(Node.prototype); +function parseSimpleSelector(selector) { + var tests = []; + selector.replace( + /([#.])?([\w-]+)|\[\s*([\w-]+)\s*(?:=\s*([\w-]+)\s*)?\]|\*|./g, + function(_, hash, name, attr, attrValue) { + if (hash == "#") { + tests.push(function(node) { return node.id == name; }); + } + else if (hash == ".") { + var re = new RegExp("(^|\\s)" + name + "($|\\s)"); + tests.push(function(node) { return re.test(node.className); }); + } + else if (name) { + tests.push(function(node) { return node.localName == name; }); + } + else if (attr) { + tests.push(function(node) { + return node.getAttribute(attr) == attrValue; + }); + } + else if (_ == "*") { + tests.push(function(node) { + return true; + }); + } + else { + throw new Error("Error parsing selector " + selector + "|" + _); + } + } + ); + return tests; +} + +function setInnerHTML(markup, parent, strict) { + var root = parent; + var tagRe = /<(\/?[\w:\-]+|!)|&(?:(#?\w+);)|$/g; + var skipped = ""; + + for (var m, lastIndex = 0; m = tagRe.exec(markup);) { + skipped += markup.substring(lastIndex, m.index); + var encoded = m[2]; + if (encoded) { + if (encoded == "gt") { + skipped += ">"; + } else if (encoded == "lt") { + skipped += "<"; + } else if (encoded == "amp") { + skipped += "&"; + } + lastIndex = tagRe.lastIndex; + } else { + if (m[1] == "!") { + skipped += parseDocType(markup, tagRe, strict); + lastIndex = tagRe.lastIndex; + continue; + } + if (skipped) { + root.appendChild(document.createTextNode(skipped)); + skipped = ""; + } + var end = markup.indexOf(">", tagRe.lastIndex); + var selfClosing = markup[end - 1] === "/" ? 1 : 0; + var attributes = markup.slice(tagRe.lastIndex, end - selfClosing).trim(); + + tagRe.lastIndex = lastIndex = end < 0 ? markup.length : end + 1; + + if (!m[1]) { + if (strict && root != parent) + throw new Error("Invalid XML message:"); + return; + } + if (m[1][0] !== "/") { + var tagName = m[1]; + if (/:/.test(tagName)) { + var i = tagName.indexOf(":"); + var prefix = tagName.slice(0, i); + tagName = tagName.slice(i+1); + root = root.appendChild(document.createElement(tagName)); + root.prefix = prefix; + } else { + root = root.appendChild(document.createElement(tagName)); + } + attributes && attributes.replace(/([\w:-]+)\s*=\s*(?:"([^"]*)"|'([^"]*)'|(\w+))/g, function(_, key, v1,v2,v3) { + root.setAttribute(key, v1 || v2 || v3 || key); + }); + } + if (m[1][0] === "/" || selfClosing) { + if (root != parent) + root = root.parentNode; + } + } + } + if (strict && root != parent) + throw new Error("Invalid XML message:"); +} +function parseDocType(markup, tagRe, strict) { + var start = tagRe.lastIndex; + var end = -1; + var text = ""; + if (markup[start] == "-" && markup[start + 1] == "-") { + end = markup.indexOf("-->", start + 2); + if (end != -1) end += 3; + } else if (strict && markup.substr(start, 7) == "[CDATA[") { + end = markup.indexOf("]]>", start); + text = markup.slice(start + 7, end); + end += 3; + } else { + end = markup.indexOf(">", start); + if (end != -1) end += 1; + } + if (end == -1) end = markup.length; + tagRe.lastIndex = end; + return text; +} function Event(type, options) { this.type = type; @@ -465,9 +595,17 @@ function Event(type, options) { }).call(Event.prototype); function walk(node, fn) { - var ch = node.children || []; - for (var i = 0; i < ch.length; i++) { - var result = fn(ch[i]) || walk(ch[i], fn); + var children = node.children || []; + for (var i = 0; i < children.length; i++) { + var result = fn(children[i]) || walk(children[i], fn); + if (result) + return result; + } +} +function walkShallow(node, fn) { + var children = node.children || []; + for (var i = 0; i < children.length; i++) { + var result = fn(children[i]); if (result) return result; } @@ -489,9 +627,12 @@ function TextNode(value) { }).call(TextNode.prototype); var window = {}; +window.navigator = {userAgent: "node", platform: "win", appName: ""}; window.HTMLDocument = window.XMLDocument = window.Document = function() { - var document = window.document = new Node("#document"); - document.navigator = {}; + var document = this; + if (!window.document) window.document = document; + Node.call(this, "#document"); + document.navigator = window.navigator; document.styleSheets = []; document.createElementNS = function(ns, t) { return new Node(t); @@ -517,12 +658,15 @@ window.HTMLDocument = window.XMLDocument = window.Document = function() { document.documentElement.appendChild(document.body); return document; }; +window.Document.prototype = Node.prototype; window.DOMParser = function() { this.parseFromString = function(str, mode) { - var document = new window.Document(); - if (mode == "text/xml") { - document.innerHTML = str.replace(/<\?([^?]|\?[^>])+\?>/g, "").trim(); + var document = new window.Document({}); + if (mode == "text/xml" || mode == "application/xml") { + var markup = str.replace(/<\?([^?]|\?[^>])+\?>/g, "").trim(); + document.innerHTML = ""; + setInnerHTML(markup, document, true); document.documentElement = document.firstChild; } else { document.body.innerHTML = str; @@ -532,7 +676,7 @@ window.DOMParser = function() { }; var document = new window.Document(); -window.document = document; +window.__defineGetter__("document", function() {return document;}); window.document.defaultView = window; window.setTimeout = setTimeout; @@ -540,9 +684,9 @@ window.clearTimeout = clearTimeout; window.getComputedStyle = function(node) { return node.style; }; -window.addEventListener = document.addEventListener; -window.removeEventListener = document.removeEventListener; -window.dispatchEvent = document.dispatchEvent; +window.addEventListener = document.addEventListener.bind(window); +window.removeEventListener = document.removeEventListener.bind(window); +window.dispatchEvent = document.dispatchEvent.bind(window); window.name = "nodejs"; window.focus = function() {}; @@ -550,27 +694,43 @@ window.Node = window.Element = Node; window.Text = window.TextNode = TextNode; window.Attr = Attr; window.window = window; -window.CustomEvent = window.Event = Event; +window.CustomEvent = window.Event = window.KeyboardEvent = Event; window.requestAnimationFrame = function(callback) { return setTimeout(function() { callback(); }); }; +/*global Buffer*/ +if (typeof Buffer != undefined) { + window.btoa = function(str) { + return Buffer.from(str.toString(), "binary").toString("base64"); + }; + window.atob = function(str) { + return Buffer.from(str, "base64").toString("binary"); + }; +} + var addedProperties = []; exports.load = function() { if (typeof global == "undefined") return; window.window = global; Object.keys(window).forEach(function(i) { - if (!global[i]) { + if (!global[i]) { addedProperties.push(i); - global[i] = window[i]; + global.__defineGetter__(i, function() { + return window[i]; + }); + global.__defineSetter__(i, function() { + }); } }); }; exports.loadInBrowser = function(global) { delete global.ResizeObserver; + global.__origRoot__ = global.document.documentElement; + global.__origBody__ = global.document.body; Object.keys(window).forEach(function(i) { if (i != "document" && i != "window") { delete global[i]; diff --git a/lib/ace/test/mockdom_test.js b/lib/ace/test/mockdom_test.js new file mode 100644 index 00000000000..2b41e38fb0f --- /dev/null +++ b/lib/ace/test/mockdom_test.js @@ -0,0 +1,80 @@ +/*global CustomEvent*/ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var assert = require("./assertions"); + +module.exports = { + "test: getBoundingClientRect" : function() { + var span = document.createElement("span"); + span.textContent = "xxx"; + + assert.equal(span.clientWidth, 0); + assert.equal(span.clientHeight, 0); + + document.body.appendChild(span); + assert.equal(span.clientWidth, 6 * 3); + assert.equal(span.clientHeight, 10); + + var div = document.createElement("div"); + document.body.appendChild(div); + div.style.position = "absolute"; + div.style.top = "20px"; + div.style.left = "40px"; + div.style.bottom = "20px"; + div.style.right = "12.5%"; + var rect = div.getBoundingClientRect(); + assert.deepEqual(rect, { top: 40, left: 20, width: 876, height: 708, right: 896, bottom: 748 }); + + div.style.width = "40px"; + rect = div.getBoundingClientRect(); + assert.equal(rect.width, 40); + assert.equal(rect.right, 60); + + div.style.height = "150%"; + rect = div.getBoundingClientRect(); + assert.equal(rect.height, 1152); + }, + + "test: eventListener" : function() { + var div = document.createElement("div"); + document.body.appendChild(div); + + var windowMousedown = 0; + window.addEventListener("mousedown", function onWindowMousedown() { + windowMousedown++; + window.removeEventListener("mousedown", onWindowMousedown); + }); + + var divMousedown = 0; + div.addEventListener("mousedown", function() { + divMousedown++; + }); + + div.dispatchEvent(new CustomEvent("mousedown")); + assert.equal(divMousedown, 1); + assert.equal(windowMousedown, 0); + + var event = new CustomEvent("mousedown", {bubbles: true}); + div.dispatchEvent(event); + assert.equal(divMousedown, 2); + assert.equal(windowMousedown, 1); + + var event = new CustomEvent("mousedown", {bubbles: true}); + div.dispatchEvent(event); + assert.equal(divMousedown, 3); + assert.equal(windowMousedown, 1); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 79ff3f6543e..aa376b7d0f2 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -1376,6 +1376,8 @@ var VirtualRenderer = function(container, theme) { // trick session to think it's already scrolled to not loose toValue _self.session.$scrollTop = toValue; this.$timer = setInterval(function() { + if (!_self.session) + return clearInterval(_self.$timer); if (steps.length) { _self.session.setScrollTop(steps.shift()); _self.session.$scrollTop = toValue; @@ -1584,6 +1586,8 @@ var VirtualRenderer = function(container, theme) { dom.removeCssClass(this.textarea, "ace_composition"); this.textarea.style.cssText = this.$composition.cssText; + var cursor = this.session.selection.cursor; + this.removeExtraToken(cursor.row, cursor.column); this.$composition = null; this.$cursorLayer.element.style.display = ""; }; @@ -1613,6 +1617,9 @@ var VirtualRenderer = function(container, theme) { this.updateLines(row, row); }; + this.removeExtraToken = function(row, column) { + this.updateLines(row, row); + }; /** * [Sets a new theme for the editor. `theme` should exist, and be a directory path, like `ace/theme/textmate`.]{: #VirtualRenderer.setTheme} From edf5cfde5e8cc7e6c4a57d2774aaeb444163aa4c Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 6 Apr 2020 16:41:57 +0400 Subject: [PATCH 0329/1293] handle firefox sending extra compositionStart event after long press on mac --- demo/kitchen-sink/dev_util.js | 1 + lib/ace/keyboard/textinput.js | 6 ++++-- lib/ace/keyboard/textinput_test.js | 22 ++++++++++++++++++++++ lib/ace/virtual_renderer.js | 3 ++- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/demo/kitchen-sink/dev_util.js b/demo/kitchen-sink/dev_util.js index 2dd54067c65..393cf3cac50 100644 --- a/demo/kitchen-sink/dev_util.js +++ b/demo/kitchen-sink/dev_util.js @@ -337,6 +337,7 @@ exports.textInputDebugger = { if (ignoreEvents) return; var data = { _: e.type, + data: e.data, inputType: e.inputType, range: [text.selectionStart, text.selectionEnd], value: text.value, diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index ee2e9fa2b9b..af70a3f0dd9 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -477,6 +477,9 @@ var TextInput = function(parentNode, host) { if (commandMode) return; + if (e.data) + inComposition.useTextareaForIME = false; + setTimeout(onCompositionUpdate, 0); host._signal("compositionStart"); host.on("mousedown", cancelComposition); @@ -489,8 +492,7 @@ var TextInput = function(parentNode, host) { host.onCompositionStart(inComposition); if (inComposition.useTextareaForIME) { - text.value = ""; - lastValue = ""; + lastValue = text.value = ""; lastSelectionStart = 0; lastSelectionEnd = 0; } diff --git a/lib/ace/keyboard/textinput_test.js b/lib/ace/keyboard/textinput_test.js index fd2a398d70b..555497937bb 100644 --- a/lib/ace/keyboard/textinput_test.js +++ b/lib/ace/keyboard/textinput_test.js @@ -72,6 +72,8 @@ function sendEvent(type, data) { data.modifier && data.modifier.split("-").map(function(m) { if (m) event[m + "Key"] = true; }); + if (data.data) + event.data = data.data; if (/input|select|composition/.test(type) || data.key && /Esc/.test(data.key.key)) { if (data.value != null) @@ -590,6 +592,26 @@ module.exports = { assert.equal(editor.getValue(), "开iird"); }, + "test: mac pressAndHold on firefox": function() { + editor.setOption("useTextareaForIME", true); + [ + { _: "keydown", range: [0,0], value: "\n\n", key: { code: "KeyA", key: "a", keyCode: 65}}, + { _: "keypress", range: [0,0], value: "\n\n", key: { code: "KeyA", key: "a", keyCode: 97}}, + { _: "input", inputType: "insertText", range: [1,1], value: "a\n\n"}, + { _: "keydown", range: [1,1], value: "a\n\n", key: { code: "KeyA", key: "a", keyCode: 65}}, + { _: "keyup", range: [1,1], value: "a\n\n", key: { code: "KeyA", key: "a", keyCode: 65}}, + { _: "keydown", range: [1,1], value: "a\n\n", key: { code: "Digit1", key: "1", keyCode: 49}}, + { _: "keyup", range: [1,1], value: "a\n\n", key: { code: "Digit1", key: "1", keyCode: 49}}, + { _: "compositionstart", data: "a", range: [0,1], value: "a\n\n"}, + { _: "compositionupdate", range: [0,1], value: "a\n\n"}, + { _: "compositionend", range: [1,1], value: "à\n\n"}, + { _: "input", inputType: "insertCompositionText", range: [1,1], value: "à\n\n"} + ].forEach(function(data, i) { + sendEvent(data._, data); + }); + assert.equal(editor.getValue(), "à"); + }, + "test: contextmenu": function() { var value = "juhu\nkinners\n"; editor.setValue(value); diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index aa376b7d0f2..c68e77c01a9 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -1549,7 +1549,8 @@ var VirtualRenderer = function(container, theme) { if (!composition.cssText) { composition.cssText = this.textarea.style.cssText; } - composition.useTextareaForIME = this.$useTextareaForIME; + if (composition.useTextareaForIME == undefined) + composition.useTextareaForIME = this.$useTextareaForIME; if (this.$useTextareaForIME) { dom.addCssClass(this.textarea, "ace_composition"); From a27d843e6d94d10d93679b6b38ad9e9d1eaf71a8 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Thu, 9 Apr 2020 02:43:46 +0300 Subject: [PATCH 0330/1293] Indent-based folding and matching for Visual Basic Mode --- demo/kitchen-sink/docs/vbscript.vbs | 2 +- lib/ace/mode/folding/vbscript.js | 346 +++++++++++++++++++++++ lib/ace/mode/folding/vbscript_test.js | 90 ++++++ lib/ace/mode/vbscript.js | 147 +++++++++- lib/ace/mode/vbscript_highlight_rules.js | 4 +- 5 files changed, 584 insertions(+), 5 deletions(-) create mode 100644 lib/ace/mode/folding/vbscript.js create mode 100644 lib/ace/mode/folding/vbscript_test.js diff --git a/demo/kitchen-sink/docs/vbscript.vbs b/demo/kitchen-sink/docs/vbscript.vbs index ace5c9f9c71..f2fcd38b18a 100644 --- a/demo/kitchen-sink/docs/vbscript.vbs +++ b/demo/kitchen-sink/docs/vbscript.vbs @@ -2,7 +2,7 @@ myfilename = "C:\Wikipedia - VBScript - Example - Hello World.txt" MakeHelloWorldFile myfilename Sub MakeHelloWorldFile (FileName) -'Create a new file in C: drive or overwrite existing file + 'Create a new file in C: drive or overwrite existing file Set FSO = CreateObject("Scripting.FileSystemObject") If FSO.FileExists(FileName) Then Answer = MsgBox ("File " & FileName & " exists ... OK to overwrite?", vbOKCancel) diff --git a/lib/ace/mode/folding/vbscript.js b/lib/ace/mode/folding/vbscript.js new file mode 100644 index 00000000000..5f2534640dc --- /dev/null +++ b/lib/ace/mode/folding/vbscript.js @@ -0,0 +1,346 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../../lib/oop"); +var BaseFoldMode = require("./fold_mode").FoldMode; +var Range = require("../../range").Range; +var TokenIterator = require("../../token_iterator").TokenIterator; + + +var FoldMode = exports.FoldMode = function() {}; + +oop.inherits(FoldMode, BaseFoldMode); + +(function() { + this.indentKeywords = { + "class": 1, + "function": 1, + "sub": 1, + "if": 1, + "select": 1, + "do": 1, + "for": 1, + "while": 1, + "with": 1, + "property": 1, + "else": 0, + "elseif": 0, + "end": -1, + "loop": -1, + "next": -1, + "wend": -1 + }; + + this.getFoldWidgetRange = function(session, foldStyle, row) { + var range = this.indentationBlock(session, row); + if (range) + return range; + + var re = /\S/; + var line = session.getLine(row); + var startLevel = line.search(re); + if (startLevel == -1) + return; + + var startColumn = line.length; + var maxRow = session.getLength(); + var startRow = row; + var endRow = row; + + while (++row < maxRow) { + line = session.getLine(row); + var level = line.search(re); + + if (level == -1) + continue; + + endRow = row; + } + + if (endRow > startRow) { + var endColumn = session.getLine(endRow).length; + return new Range(startRow, startColumn, endRow, endColumn); + } + }; + + // must return "" if there's no fold, to enable caching + this.getFoldWidget = function(session, foldStyle, row) { + var line = session.getLine(row); + var indent = line.search(/\S/); + var next = session.getLine(row + 1); + var prev = session.getLine(row - 1); + var prevIndent = prev.search(/\S/); + var nextIndent = next.search(/\S/); + + if (indent == -1) { + session.foldWidgets[row - 1] = prevIndent!= -1 && prevIndent < nextIndent ? "start" : ""; + return ""; + } + + if (prevIndent!= -1 && prevIndent < indent) + session.foldWidgets[row - 1] = "start"; + else + session.foldWidgets[row - 1] = ""; + + if (indent < nextIndent) + return "start"; + else + return ""; + }; + + this.vbsBlock = function(session, row, column, tokenRange) { + var stream = new TokenIterator(session, row, column); + + var endOpenings = { + "class": 1, + "function": 1, + "sub": 1, + "if": 1, + "select": 1, + "with": 1, + "property": 1 + }; + + var token = stream.getCurrentToken(); + if (!token || (token.type != "keyword.control.asp" && token.type != "storage.type.function.asp")) + return; + + var startTokenValue = token.value.toLowerCase(); + var val = token.value.toLowerCase(); + + var stack = [val]; + var dir = this.indentKeywords[val]; + + if (!dir) + return; + + var firstRange = stream.getCurrentTokenRange(); + var modifiers = ''; + switch (val) { + case "property": + case "sub": + case "function": + modifiers = "(?:(?:Private|Public(?:\\s+Default)?)\\s+)?"; + case "if": + case "select": + case "do": + case "for": + case "class": + case "while": + case "with": + var line = session.getLine(row); + var singleLineCondition = /^\s*(If)\s+(.)*\s+Then\s+(\S)+/i.test(line); + if (singleLineCondition) + return; + var checkToken = new RegExp("^\\s*"+ modifiers + val, "i"); + var endTest = /^\s*End\s(If|Sub|Select|Function|Class|With|Property)\s*/i.test(line); + if (!checkToken.test(line) && !endTest) { + return; + } + if (endTest) { + var tokenRange = stream.getCurrentTokenRange(); + stream.step = stream.stepBackward; + stream.step(); + stream.step(); + token = stream.getCurrentToken(); + if (token) { + val = token.value.toLowerCase(); + if (val == "end") { + firstRange = stream.getCurrentTokenRange(); + firstRange = new Range(firstRange.start.row, firstRange.start.column, tokenRange.start.row, tokenRange.end.column); + } + } + dir = -1; + } + break; + case "end": + var tokenPos = stream.getCurrentTokenPosition(); + firstRange = stream.getCurrentTokenRange(); + stream.step = stream.stepForward; + stream.step(); + stream.step(); + token = stream.getCurrentToken(); + if (token) { + val = token.value.toLowerCase(); + if (val in endOpenings) { + startTokenValue = val; + var nextTokenPos = stream.getCurrentTokenPosition(); + var endColumn = nextTokenPos.column + val.length; + firstRange = new Range(tokenPos.row, tokenPos.column, nextTokenPos.row, endColumn); + } + } + stream.step = stream.stepBackward; + stream.step(); + stream.step(); + break; + } + + var ranges = []; + ranges.push(firstRange); + + stream.step = dir === -1 ? stream.stepBackward : stream.stepForward; + while(token = stream.step()) { + modifiers = ''; + var outputRange = null; + var ignore = false; + if (token.type != "keyword.control.asp" && token.type != "storage.type.function.asp") + continue; + val = token.value.toLowerCase(); + var level = dir * this.indentKeywords[val]; + + switch (val) { + case "property": + case "sub": + case "function": + modifiers = "(?:(?:Private|Public(?:\\sDefault)?)\\s+)?"; + case "if": + case "select": + case "do": + case "for": + case "class": + case "while": + case "with": + var line = session.getLine(stream.getCurrentTokenRow()); + var singleLineCondition = /^\s*(If)\s+(.)*\s+Then\s+(\S)+/i.test(line); + if (singleLineCondition) { + level = 0; + ignore = true; + } + var checkToken = new RegExp("^\\s*" + modifiers + val, "i"); + if (!checkToken.test(line)) { + level = 0; + ignore = true; + } + break; + } + + if (level > 0) { + stack.unshift(val); + } else if (level <= 0 && ignore === false) { + stack.shift(); + if (!stack.length) { + if (val != "elseif" && val != "else") { + switch (val) { + case "end": + var tokenPos = stream.getCurrentTokenPosition(); + outputRange = stream.getCurrentTokenRange(); + stream.step(); + stream.step(); + token = stream.getCurrentToken(); + if (token) { + val = token.value.toLowerCase(); + if (val in endOpenings) { + if (val != startTokenValue) + ranges.shift(); + var nextTokenPos = stream.getCurrentTokenPosition(); + var endColumn = nextTokenPos.column + val.length; + outputRange = new Range(tokenPos.row, tokenPos.column, nextTokenPos.row, endColumn); + } else { + ranges.shift(); + } + } else { + ranges.shift(); + } + stream.step = stream.stepBackward; + stream.step(); + stream.step(); + token = stream.getCurrentToken(); + val = token.value.toLowerCase(); + break; + case "select": + case "sub": + case "if": + case "function": + case "class": + case "with": + case "property": + if (val != startTokenValue) + ranges.shift(); + break; + case "do": + if (startTokenValue != "loop") + ranges.shift(); + break; + case "loop": + if (startTokenValue != "do") + ranges.shift(); + break; + case "for": + if (startTokenValue != "next") + ranges.shift(); + break; + case "next": + if (startTokenValue != "for") + ranges.shift(); + break; + case "while": + if (startTokenValue != "wend") + ranges.shift(); + break; + case "wend": + if (startTokenValue != "while") + ranges.shift(); + break; + } + break; + } + } + + if (level === 0){ + stack.unshift(val); + } + } + } + + if (!token) + return null; + + if (tokenRange) { + if (!outputRange) { + ranges.push(stream.getCurrentTokenRange()); + } else { + ranges.push(outputRange); + } + return ranges; + } + + if (!outputRange) { + return stream.getCurrentTokenRange(); + } else { + return outputRange; + } + }; + +}).call(FoldMode.prototype); + +}); diff --git a/lib/ace/mode/folding/vbscript_test.js b/lib/ace/mode/folding/vbscript_test.js new file mode 100644 index 00000000000..795e4c05d8a --- /dev/null +++ b/lib/ace/mode/folding/vbscript_test.js @@ -0,0 +1,90 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") + require("amd-loader"); + +define(function(require, exports, module) { +"use strict"; + +var VBScriptMode = require("../vbscript").Mode; +var EditSession = require("../../edit_session").EditSession; +var assert = require("../../test/assertions"); + +module.exports = { + setUp : function() { + this.mode = new VBScriptMode(); + }, + + "test: visual basic script indentation based folding": function() { + var session = new EditSession([ + 'Sub MakeHelloWorldFile (FileName)', + ' \'Create a new file in C: drive or overwrite existing file', + ' Set FSO = CreateObject("Scripting.FileSystemObject")', + ' If FSO.FileExists(FileName) Then ', + ' Answer = MsgBox ("File " & FileName & " exists ... OK to overwrite?", vbOKCancel)', + ' \'If button selected is not OK, then quit now', + ' \'vbOK is a language constant', + ' If Answer <> vbOK Then Exit Sub', + ' Else', + ' \'Confirm OK to create', + ' Answer = MsgBox ("File " & FileName & " ... OK to create?", vbOKCancel)', + ' If Answer <> vbOK Then Exit Sub', + ' End If', + ' \'Create new file (or replace an existing file)', + ' Set FileObject = FSO.CreateTextFile (FileName)', + ' FileObject.WriteLine "Time ... " & Now()', + ' FileObject.WriteLine "Hello World"', + ' FileObject.Close()', + ' MsgBox "File " & FileName & " ... updated."', + 'End Sub', + ]); + + session.setFoldStyle("markbegin"); + session.setMode(this.mode); + + assert.equal(session.getFoldWidget(0), "start"); + assert.equal(session.getFoldWidget(1), ""); + assert.equal(session.getFoldWidget(2), ""); + assert.equal(session.getFoldWidget(3), "start"); + assert.equal(session.getFoldWidget(4), ""); + assert.equal(session.getFoldWidget(8), "start"); + assert.equal(session.getFoldWidget(9), ""); + + assert.range(session.getFoldWidgetRange(0), 0, 33, 18, 46); + assert.range(session.getFoldWidgetRange(3), 3, 36, 7, 37); + assert.range(session.getFoldWidgetRange(10), 10, 77, 19, 7); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) + require("asyncjs").test.testcase(module.exports).exec(); diff --git a/lib/ace/mode/vbscript.js b/lib/ace/mode/vbscript.js index 569e2e80fea..33ef967f200 100644 --- a/lib/ace/mode/vbscript.js +++ b/lib/ace/mode/vbscript.js @@ -43,17 +43,160 @@ define(function(require, exports, module) { var oop = require("../lib/oop"); var TextMode = require("./text").Mode; var VBScriptHighlightRules = require("./vbscript_highlight_rules").VBScriptHighlightRules; +var FoldMode = require("./folding/vbscript").FoldMode; +var Range = require("../range").Range; var Mode = function() { this.HighlightRules = VBScriptHighlightRules; + this.foldingRules = new FoldMode(); this.$behaviour = this.$defaultBehaviour; }; oop.inherits(Mode, TextMode); (function() { - + this.lineCommentStart = ["'", "REM"]; - + + var indentKeywords = { + "class": 1, + "function": 1, + "sub": 1, + "if": 1, + "select": 1, + "do": 1, + "for": 1, + "while": 1, + "with": 1, + "property": 1, + "else": 1, + "elseif": 1, + "end": -1, + "loop": -1, + "next": -1, + "wend": -1 + }; + + var outdentKeywords = [ + "else", + "elseif", + "end", + "loop", + "next", + "wend" + ]; + + function getNetIndentLevel(tokens, line) { + var level = 0; + var modifiers = ''; + // Support single-line blocks by decrementing the indent level if + // an ending token is found + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + if (token.type == "keyword.control.asp" || token.type == "storage.type.function.asp") { + var val = token.value.toLowerCase(); + if (val in indentKeywords) { + switch (val) { + case "property": + case "sub": + case "function": + modifiers = "(?:(?:Private|Public(?:\\s+Default)?)\\s+)?"; + case "select": + case "do": + case "for": + case "class": + case "while": + case "with": + var checkToken = new RegExp("^\\s*" + modifiers + val,"i"); + if (checkToken.test(line)) { + level += indentKeywords[val]; + } + break; + case "if": + var singleLineCondition = /^\s*(If)\s+(.)*\s+Then\s+(\S)+/i.test(line); + if (!singleLineCondition) + level += indentKeywords[val]; + break; + default: + level += indentKeywords[val]; + break; + } + } + } + } + // Limit the level to +/- 1 since usually users only indent one level + // at a time regardless of the logical nesting level + if (level < 0) { + return -1; + } else if (level > 0) { + return 1; + } else { + return 0; + } + } + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + var level = 0; + + var tokenizedLine = this.getTokenizer().getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + + if (state == "start") { + level = getNetIndentLevel(tokens, line); + } + if (level > 0) { + return indent + tab; + } else if (level < 0 && indent.substr(indent.length - tab.length) == tab) { + // Don't do a next-line outdent if we're going to do a real outdent of this line + if (!this.checkOutdent(state, line, "\n")) { + return indent.substr(0, indent.length - tab.length); + } + } + return indent; + }; + + this.checkOutdent = function(state, line, input) { + if (input != "\n" && input != "\r" && input != "\r\n") + return false; + + var tokens = this.getTokenizer().getLineTokens(line.trim(), state).tokens; + + if (!tokens || !tokens.length) + return false; + var val = tokens[0].value.toLowerCase(); + return ((tokens[0].type == "keyword.control.asp" || tokens[0].type == "storage.type.function.asp") && outdentKeywords.indexOf(val) != -1); + }; + + this.getMatching = function(session, row, column, tokenRange = true) { + if (row == undefined) { + var pos = session.selection.lead; + column = pos.column; + row = pos.row; + } + + var startToken = session.getTokenAt(row, column); + if (startToken) { + var val = startToken.value.toLowerCase(); + if (val in indentKeywords) + return this.foldingRules.vbsBlock(session, row, column, tokenRange); + } + }; + + this.autoOutdent = function(state, session, row) { + var line = session.getLine(row); + var column = line.match(/^\s*/)[0].length; + if (!column || !row) return; + + var startRange = this.getMatching(session, row, column + 1, false); + if (!startRange || startRange.start.row == row) + return; + var indent = this.$getIndent(session.getLine(startRange.start.row)); + if (indent.length != column) { + session.replace(new Range(row, 0, row, column), indent); + session.outdentRows(new Range(row + 1, 0, row + 1, 0)); + } + }; + this.$id = "ace/mode/vbscript"; }).call(Mode.prototype); diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index abe00b01e42..9fd20ee9287 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -42,8 +42,8 @@ var VBScriptHighlightRules = function() { var keywordMapper = this.createKeywordMapper({ "keyword.control.asp": "If|Then|Else|ElseIf|End|While|Wend|For|To|Each|Case|Select|Return" - + "|Continue|Do|Until|Loop|Next|With|Exit|Function|Property|Type|Enum|Sub|IIf", - "storage.type.asp": "Dim|Call|Class|Const|Dim|Redim|Set|Let|Get|New|Randomize|Option|Explicit", + + "|Continue|Do|Until|Loop|Next|With|Exit|Function|Property|Type|Enum|Sub|IIf|Class", + "storage.type.asp": "Dim|Call|Const|Redim|Set|Let|Get|New|Randomize|Option|Explicit", "storage.modifier.asp": "Private|Public|Default", "keyword.operator.asp": "Mod|And|Not|Or|Xor|as", "constant.language.asp": "Empty|False|Nothing|Null|True", From a1cf896cac10baa618c7e685f43d922068961329 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Thu, 9 Apr 2020 22:21:51 +0300 Subject: [PATCH 0331/1293] refactored default arguments; block-based folding implemented; reused `indentKeywords` from folding rules; added some tests for indent/outdent/matchings --- lib/ace/mode/folding/vbscript.js | 100 ++++++-------- lib/ace/mode/folding/vbscript_test.js | 6 +- lib/ace/mode/vbscript.js | 30 +--- lib/ace/mode/vbscript_test.js | 190 ++++++++++++++++++++++++++ 4 files changed, 242 insertions(+), 84 deletions(-) create mode 100644 lib/ace/mode/vbscript_test.js diff --git a/lib/ace/mode/folding/vbscript.js b/lib/ace/mode/folding/vbscript.js index 5f2534640dc..870f31e7cef 100644 --- a/lib/ace/mode/folding/vbscript.js +++ b/lib/ace/mode/folding/vbscript.js @@ -53,69 +53,40 @@ oop.inherits(FoldMode, BaseFoldMode); "while": 1, "with": 1, "property": 1, - "else": 0, - "elseif": 0, + "else": 1, + "elseif": 1, "end": -1, "loop": -1, "next": -1, "wend": -1 }; - this.getFoldWidgetRange = function(session, foldStyle, row) { - var range = this.indentationBlock(session, row); - if (range) - return range; - - var re = /\S/; + this.getFoldWidgetRange = function (session, foldStyle, row) { var line = session.getLine(row); - var startLevel = line.search(re); - if (startLevel == -1) - return; - - var startColumn = line.length; - var maxRow = session.getLength(); - var startRow = row; - var endRow = row; - - while (++row < maxRow) { - line = session.getLine(row); - var level = line.search(re); + var match = /(\w+)\b/i.exec(line); + var keyword = match && match[1].toLowerCase(); - if (level == -1) - continue; - - endRow = row; - } - - if (endRow > startRow) { - var endColumn = session.getLine(endRow).length; - return new Range(startRow, startColumn, endRow, endColumn); + if (keyword && this.indentKeywords.hasOwnProperty(keyword)) { + return this.vbsBlock(session, row, match.index + 1); } }; + // must return "" if there's no fold, to enable caching this.getFoldWidget = function(session, foldStyle, row) { var line = session.getLine(row); - var indent = line.search(/\S/); - var next = session.getLine(row + 1); - var prev = session.getLine(row - 1); - var prevIndent = prev.search(/\S/); - var nextIndent = next.search(/\S/); - - if (indent == -1) { - session.foldWidgets[row - 1] = prevIndent!= -1 && prevIndent < nextIndent ? "start" : ""; - return ""; + var match = /^\s*(\w+)\b/i.exec(line); + var keyword = match && match[1].toLowerCase(); + + if (keyword && this.indentKeywords.hasOwnProperty(keyword)) { + if (this.indentKeywords[keyword] == -1) + return ""; + if (keyword == "if" && !/then\s*$/i.test(line)) + return ""; + return "start"; } - if (prevIndent!= -1 && prevIndent < indent) - session.foldWidgets[row - 1] = "start"; - else - session.foldWidgets[row - 1] = ""; - - if (indent < nextIndent) - return "start"; - else - return ""; + return ""; }; this.vbsBlock = function(session, row, column, tokenRange) { @@ -128,7 +99,9 @@ oop.inherits(FoldMode, BaseFoldMode); "if": 1, "select": 1, "with": 1, - "property": 1 + "property": 1, + "else": 1, + "elseif": 1 }; var token = stream.getCurrentToken(); @@ -204,7 +177,8 @@ oop.inherits(FoldMode, BaseFoldMode); stream.step(); break; } - + var startColumn = dir === -1 ? session.getLine(row - 1).length : session.getLine(row).length; + var startRow = row; var ranges = []; ranges.push(firstRange); @@ -242,6 +216,11 @@ oop.inherits(FoldMode, BaseFoldMode); ignore = true; } break; + case "else": + case "elseif": + level = 0; + ignore = true; + break; } if (level > 0) { @@ -249,7 +228,6 @@ oop.inherits(FoldMode, BaseFoldMode); } else if (level <= 0 && ignore === false) { stack.shift(); if (!stack.length) { - if (val != "elseif" && val != "else") { switch (val) { case "end": var tokenPos = stream.getCurrentTokenPosition(); @@ -260,8 +238,14 @@ oop.inherits(FoldMode, BaseFoldMode); if (token) { val = token.value.toLowerCase(); if (val in endOpenings) { - if (val != startTokenValue) - ranges.shift(); + if ((startTokenValue == "else" || startTokenValue == "elseif")) { + if (val !== "if") { + ranges.shift(); + } + } else { + if (val != startTokenValue) + ranges.shift(); + } var nextTokenPos = stream.getCurrentTokenPosition(); var endColumn = nextTokenPos.column + val.length; outputRange = new Range(tokenPos.row, tokenPos.column, nextTokenPos.row, endColumn); @@ -313,7 +297,6 @@ oop.inherits(FoldMode, BaseFoldMode); break; } break; - } } if (level === 0){ @@ -334,11 +317,12 @@ oop.inherits(FoldMode, BaseFoldMode); return ranges; } - if (!outputRange) { - return stream.getCurrentTokenRange(); - } else { - return outputRange; - } + var row = stream.getCurrentTokenRow(); + if (dir === -1) { + var endColumn = session.getLine(row).length; + return new Range(row, endColumn, startRow - 1, startColumn); + } else + return new Range(startRow, startColumn, row - 1, session.getLine(row - 1).length); }; }).call(FoldMode.prototype); diff --git a/lib/ace/mode/folding/vbscript_test.js b/lib/ace/mode/folding/vbscript_test.js index 795e4c05d8a..4739ba9627c 100644 --- a/lib/ace/mode/folding/vbscript_test.js +++ b/lib/ace/mode/folding/vbscript_test.js @@ -64,7 +64,7 @@ module.exports = { ' FileObject.WriteLine "Hello World"', ' FileObject.Close()', ' MsgBox "File " & FileName & " ... updated."', - 'End Sub', + 'End Sub' ]); session.setFoldStyle("markbegin"); @@ -79,8 +79,8 @@ module.exports = { assert.equal(session.getFoldWidget(9), ""); assert.range(session.getFoldWidgetRange(0), 0, 33, 18, 46); - assert.range(session.getFoldWidgetRange(3), 3, 36, 7, 37); - assert.range(session.getFoldWidgetRange(10), 10, 77, 19, 7); + assert.range(session.getFoldWidgetRange(3), 3, 36, 11, 37); + assert.range(session.getFoldWidgetRange(12), 3, 36, 11, 37); } }; diff --git a/lib/ace/mode/vbscript.js b/lib/ace/mode/vbscript.js index 33ef967f200..9cfb247e117 100644 --- a/lib/ace/mode/vbscript.js +++ b/lib/ace/mode/vbscript.js @@ -50,6 +50,7 @@ var Mode = function() { this.HighlightRules = VBScriptHighlightRules; this.foldingRules = new FoldMode(); this.$behaviour = this.$defaultBehaviour; + this.indentKeywords = this.foldingRules.indentKeywords; }; oop.inherits(Mode, TextMode); @@ -57,25 +58,6 @@ oop.inherits(Mode, TextMode); this.lineCommentStart = ["'", "REM"]; - var indentKeywords = { - "class": 1, - "function": 1, - "sub": 1, - "if": 1, - "select": 1, - "do": 1, - "for": 1, - "while": 1, - "with": 1, - "property": 1, - "else": 1, - "elseif": 1, - "end": -1, - "loop": -1, - "next": -1, - "wend": -1 - }; - var outdentKeywords = [ "else", "elseif", @@ -85,7 +67,7 @@ oop.inherits(Mode, TextMode); "wend" ]; - function getNetIndentLevel(tokens, line) { + function getNetIndentLevel(tokens, line, indentKeywords) { var level = 0; var modifiers = ''; // Support single-line blocks by decrementing the indent level if @@ -142,7 +124,7 @@ oop.inherits(Mode, TextMode); var tokens = tokenizedLine.tokens; if (state == "start") { - level = getNetIndentLevel(tokens, line); + level = getNetIndentLevel(tokens, line, this.indentKeywords); } if (level > 0) { return indent + tab; @@ -167,17 +149,19 @@ oop.inherits(Mode, TextMode); return ((tokens[0].type == "keyword.control.asp" || tokens[0].type == "storage.type.function.asp") && outdentKeywords.indexOf(val) != -1); }; - this.getMatching = function(session, row, column, tokenRange = true) { + this.getMatching = function(session, row, column, tokenRange) { if (row == undefined) { var pos = session.selection.lead; column = pos.column; row = pos.row; } + if (tokenRange == undefined) + tokenRange = true; var startToken = session.getTokenAt(row, column); if (startToken) { var val = startToken.value.toLowerCase(); - if (val in indentKeywords) + if (val in this.indentKeywords) return this.foldingRules.vbsBlock(session, row, column, tokenRange); } }; diff --git a/lib/ace/mode/vbscript_test.js b/lib/ace/mode/vbscript_test.js new file mode 100644 index 00000000000..23c85680760 --- /dev/null +++ b/lib/ace/mode/vbscript_test.js @@ -0,0 +1,190 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { + "use strict"; + + var EditSession = require("../edit_session").EditSession; + var VBScriptMode = require("./vbscript").Mode; + var assert = require("../test/assertions"); + + module.exports = { + setUp : function() { + this.mode = new VBScriptMode(); + }, + + "test: getNextLineIndent": function() { + assert.equal(this.mode.getNextLineIndent("start", "Class ClassName", " "), " "); + assert.equal(this.mode.getNextLineIndent("start", " Public Default Function FunctionName(param)", " "), " "); + assert.equal(this.mode.getNextLineIndent("start", " If Answer <> vbOK Then Exit Sub", " "), " "); + assert.equal(this.mode.getNextLineIndent("start", " If Condition Then", " "), " "); + }, + + "test: checkOutdent": function() { + assert.ok(this.mode.checkOutdent("start", " End If", "\n")); + assert.ok(this.mode.checkOutdent("start", " Loop", "\n")); + assert.equal(this.mode.checkOutdent("start", " Class blabla", "\n"), false); + assert.equal(this.mode.checkOutdent("start", "", "\r"), false); + }, + + "test: auto outdent" : function() { + var session = new EditSession(["Class ClassName", " some code", " End Class"]); + session.setMode(this.mode); + this.mode.autoOutdent("start", session, 2); + assert.equal("End Class", session.getLine(2)); + }, + + "test: opening/ending tags matching": function() { + var session = new EditSession([ + 'Sub Name(attr)', + ' If Condition Then ', + ' some code', + ' Else', + ' another code', + ' End If', + 'End Sub' + ]); + + session.setMode(this.mode); + + var ranges = this.mode.getMatching(session, 0, 0); + assert.range(ranges[0], 0, 0, 0, 3); + assert.range(ranges[1], 6, 0, 6, 7); + + ranges = this.mode.getMatching(session, 6, 1); + assert.range(ranges[1], 0, 0, 0, 3); + assert.range(ranges[0], 6, 0, 6, 7); + + ranges = this.mode.getMatching(session, 1, 4); + assert.range(ranges[0], 1, 3, 1, 5); + assert.range(ranges[1], 5, 3, 5, 9); + + ranges = this.mode.getMatching(session, 5, 8); + assert.range(ranges[1], 1, 3, 1, 5); + assert.range(ranges[0], 5, 3, 5, 9); + }, + + "test: single line condition couldn't have closing tag": function() { + var session = new EditSession([ + 'Sub Name(attr)', + ' If Condition Then ', + ' If Condition Then Exit Sub', + ' End If', + 'End Sub' + ]); + + session.setMode(this.mode); + + var ranges = this.mode.getMatching(session, 2, 8); + assert.equal(ranges, undefined); + + ranges = this.mode.getMatching(session, 1, 4); + assert.range(ranges[0], 1, 3, 1, 5); + assert.range(ranges[1], 3, 3, 3, 9); + + ranges = this.mode.getMatching(session, 3, 4); + assert.range(ranges[1], 1, 3, 1, 5); + assert.range(ranges[0], 3, 3, 3, 9); + + ranges = this.mode.getMatching(session, 4, 1); + assert.range(ranges[1], 0, 0, 0, 3); + assert.range(ranges[0], 4, 0, 4, 7); + }, + + "test: private and public properties/subs/functions should return matching tag": function() { + var session = new EditSession([ + 'Class ClassName', + ' Public Property Get PropertyName', + ' some code', + ' End Property', + '', + ' Private Function FunctionName(value1, value2)', + ' some code', + ' End Function', + 'End Class' + ]); + + session.setMode(this.mode); + + var ranges = this.mode.getMatching(session, 1, 11); + assert.range(ranges[0], 1, 10, 1, 18); + assert.range(ranges[1], 3, 3, 3, 15); + + ranges = this.mode.getMatching(session, 3, 5); + assert.range(ranges[1], 1, 10, 1, 18); + assert.range(ranges[0], 3, 3, 3, 15); + + ranges = this.mode.getMatching(session, 5, 14); + assert.range(ranges[0], 5, 11, 5, 19); + assert.range(ranges[1], 7, 3, 7, 15); + + ranges = this.mode.getMatching(session, 7, 4); + assert.range(ranges[1], 5, 11, 5, 19); + assert.range(ranges[0], 7, 3, 7, 15); + }, + + "test: wrong closing/opening tag": function() { + var session = new EditSession([ + 'Class ClassName', + ' Public Property Get PropertyName', + ' some code', + ' End Class', + '', + ' Private Property FunctionName(value1, value2)', + ' some code', + ' End AnyWord', + 'End Class' + ]); + + session.setMode(this.mode); + + var ranges = this.mode.getMatching(session, 1, 11); + assert.equal(ranges.length, 1); + assert.range(ranges[0], 3, 3, 3, 12); + + ranges = this.mode.getMatching(session, 7, 4); + assert.equal(ranges.length, 1); + assert.range(ranges[0], 5, 11, 5, 19); + + ranges = this.mode.getMatching(session, 0, 3); + assert.range(ranges[0], 0, 0, 0, 5); + assert.range(ranges[1], 8, 0, 8, 9); + } + }; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} From 02c7932e9aa516a7490f0c415bc4ac9f5035cffc Mon Sep 17 00:00:00 2001 From: mkslanc Date: Fri, 10 Apr 2020 03:31:31 +0300 Subject: [PATCH 0332/1293] bug with wrong matching for elseif/else tags fixed --- lib/ace/mode/folding/vbscript.js | 6 ++++-- lib/ace/mode/vbscript_test.js | 22 +++++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/ace/mode/folding/vbscript.js b/lib/ace/mode/folding/vbscript.js index 870f31e7cef..c43a08d273d 100644 --- a/lib/ace/mode/folding/vbscript.js +++ b/lib/ace/mode/folding/vbscript.js @@ -216,10 +216,12 @@ oop.inherits(FoldMode, BaseFoldMode); ignore = true; } break; - case "else": case "elseif": + case "else": level = 0; - ignore = true; + if (startTokenValue != "elseif") { + ignore = true; + } break; } diff --git a/lib/ace/mode/vbscript_test.js b/lib/ace/mode/vbscript_test.js index 23c85680760..ac5d4547ab0 100644 --- a/lib/ace/mode/vbscript_test.js +++ b/lib/ace/mode/vbscript_test.js @@ -70,6 +70,10 @@ define(function(require, exports, module) { 'Sub Name(attr)', ' If Condition Then ', ' some code', + ' ElseIf condition2', + ' another code', + ' ElseIf condition3', + ' another code', ' Else', ' another code', ' End If', @@ -80,19 +84,27 @@ define(function(require, exports, module) { var ranges = this.mode.getMatching(session, 0, 0); assert.range(ranges[0], 0, 0, 0, 3); - assert.range(ranges[1], 6, 0, 6, 7); + assert.range(ranges[1], 10, 0, 10, 7); - ranges = this.mode.getMatching(session, 6, 1); + ranges = this.mode.getMatching(session, 10, 1); assert.range(ranges[1], 0, 0, 0, 3); - assert.range(ranges[0], 6, 0, 6, 7); + assert.range(ranges[0], 10, 0, 10, 7); ranges = this.mode.getMatching(session, 1, 4); assert.range(ranges[0], 1, 3, 1, 5); - assert.range(ranges[1], 5, 3, 5, 9); + assert.range(ranges[1], 9, 3, 9, 9); - ranges = this.mode.getMatching(session, 5, 8); + ranges = this.mode.getMatching(session, 9, 8); assert.range(ranges[1], 1, 3, 1, 5); + assert.range(ranges[0], 9, 3, 9, 9); + + ranges = this.mode.getMatching(session, 3, 4); + assert.range(ranges[0], 3, 3, 3, 9); + assert.range(ranges[1], 5, 3, 5, 9); + + ranges = this.mode.getMatching(session, 5, 4); assert.range(ranges[0], 5, 3, 5, 9); + assert.range(ranges[1], 7, 3, 7, 7); }, "test: single line condition couldn't have closing tag": function() { From a2881dbe490ca5b4a68948f7f261b854aab5f864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Jos=C3=A9=20Pereira?= Date: Sat, 11 Apr 2020 23:29:26 -0300 Subject: [PATCH 0333/1293] qml: Add qml types in highlight MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Patrick José Pereira --- lib/ace/mode/qml_highlight_rules.js | 143 +++++++++++++++++++++++++++- 1 file changed, 140 insertions(+), 3 deletions(-) diff --git a/lib/ace/mode/qml_highlight_rules.js b/lib/ace/mode/qml_highlight_rules.js index 47556ebc23a..99390151e92 100644 --- a/lib/ace/mode/qml_highlight_rules.js +++ b/lib/ace/mode/qml_highlight_rules.js @@ -35,15 +35,149 @@ define(function(require, exports, module) { var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var QmlHighlightRules = function() { + // see: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects + var keywordMapper = this.createKeywordMapper({ + "variable.language": + "Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|" + // Constructors + "Namespace|QName|XML|XMLList|" + // E4X + "ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|" + + "Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|" + + "Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|" + // Errors + "SyntaxError|TypeError|URIError|" + + "decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|" + // Non-constructor functions + "isNaN|parseFloat|parseInt|" + + "JSON|Math|" + // Other + "this|arguments|prototype|window|document" , // Pseudo + "keyword": + "const|yield|import|get|set|async|await|" + + "break|case|catch|continue|default|delete|do|else|finally|for|function|" + + "if|in|of|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|" + + // invalid or reserved + "__parent__|__count__|escape|unescape|with|__proto__|" + + "class|enum|extends|super|export|implements|private|public|interface|package|protected|static|" + + // qml + "readonly|string|int|bool|date|color|url|real|double|var|variant|" + + "height|width|anchors|parent|" + + "Abstract3DSeries|AbstractActionInput|AbstractAnimation|AbstractAxis|AbstractAxis3D|AbstractAxisInput|" + + "AbstractBarSeries|AbstractButton|AbstractClipAnimator|AbstractClipBlendNode|AbstractDataProxy|AbstractGraph3D|" + + "AbstractInputHandler3D|AbstractPhysicalDevice|AbstractRayCaster|AbstractSeries|AbstractSkeleton|AbstractTextureImage|" + + "Accelerometer|AccelerometerReading|Accessible|Action|ActionGroup|ActionInput|" + + "AdditiveClipBlend|Address|Affector|Age|AlphaCoverage|AlphaTest|" + + "Altimeter|AltimeterReading|AmbientLightReading|AmbientLightSensor|AmbientTemperatureReading|AmbientTemperatureSensor|" + + "AnalogAxisInput|AnchorAnimation|AnchorChanges|AngleDirection|AnimatedImage|AnimatedSprite|" + + "Animation|AnimationController|AnimationGroup|Animator|ApplicationWindow|ApplicationWindowStyle|" + + "AreaSeries|Armature|AttenuationModelInverse|AttenuationModelLinear|Attractor|Attribute|" + + "Audio|AudioCategory|AudioEngine|AudioListener|AudioSample|AuthenticationDialogRequest|" + + "Axis|AxisAccumulator|AxisSetting|BackspaceKey|Bar3DSeries|BarCategoryAxis|" + + "BarDataProxy|BarSeries|BarSet|Bars3D|BaseKey|Behavior|" + + "Binding|Blend|BlendEquation|BlendEquationArguments|BlendedClipAnimator|BlitFramebuffer|" + + "BluetoothDiscoveryModel|BluetoothService|BluetoothSocket|BorderImage|BorderImageMesh|BoxPlotSeries|" + + "BoxSet|BrightnessContrast|Buffer|BusyIndicator|BusyIndicatorStyle|Button|" + + "ButtonAxisInput|ButtonGroup|ButtonStyle|Calendar|CalendarStyle|Camera|" + + "Camera3D|CameraCapabilities|CameraCapture|CameraExposure|CameraFlash|CameraFocus|" + + "CameraImageProcessing|CameraLens|CameraRecorder|CameraSelector|CandlestickSeries|CandlestickSet|" + + "Canvas|Canvas3D|Canvas3DAbstractObject|Canvas3DActiveInfo|Canvas3DBuffer|Canvas3DContextAttributes|" + + "Canvas3DFrameBuffer|Canvas3DProgram|Canvas3DRenderBuffer|Canvas3DShader|Canvas3DShaderPrecisionFormat|Canvas3DTexture|" + + "Canvas3DTextureProvider|Canvas3DUniformLocation|CanvasGradient|CanvasImageData|CanvasPixelArray|Category|" + + "CategoryAxis|CategoryAxis3D|CategoryModel|CategoryRange|ChangeLanguageKey|ChartView|" + + "CheckBox|CheckBoxStyle|CheckDelegate|CircularGauge|CircularGaugeStyle|ClearBuffers|" + + "ClipAnimator|ClipPlane|CloseEvent|ColorAnimation|ColorDialog|ColorDialogRequest|" + + "ColorGradient|ColorGradientStop|ColorMask|ColorOverlay|Colorize|Column|" + + "ColumnLayout|ComboBox|ComboBoxStyle|Compass|CompassReading|Component|Component3D|" + + "ComputeCommand|ConeGeometry|ConeMesh|ConicalGradient|Connections|ContactDetail|" + + "ContactDetails|Container|Context2D|Context3D|ContextMenuRequest|Control|" + + "CoordinateAnimation|CuboidGeometry|CuboidMesh|CullFace|CumulativeDirection|" + + "Custom3DItem|Custom3DLabel|Custom3DVolume|CustomParticle|CylinderGeometry|CylinderMesh|" + + "Date|DateTimeAxis|DelayButton|DelayButtonStyle|DelegateChoice|DelegateChooser|DelegateModel|" + + "DelegateModelGroup|DepthTest|Desaturate|Dial|DialStyle|Dialog|DialogButtonBox|DiffuseMapMaterial|" + + "DiffuseSpecularMapMaterial|DiffuseSpecularMaterial|Direction|DirectionalBlur|DirectionalLight|DispatchCompute|" + + "Displace|DistanceReading|DistanceSensor|Dithering|DoubleValidator|Drag|DragEvent|DragHandler|Drawer|DropArea|" + + "DropShadow|DwmFeatures|DynamicParameter|EditorialModel|Effect|EllipseShape|Emitter|EnterKey|EnterKeyAction|" + + "Entity|EntityLoader|EnvironmentLight|EventConnection|EventPoint|EventTouchPoint|ExclusiveGroup|ExtendedAttributes|" + + "ExtrudedTextGeometry|ExtrudedTextMesh|FastBlur|FileDialog|FileDialogRequest|FillerKey|FilterKey|FinalState|" + + "FirstPersonCameraController|Flickable|Flipable|Flow|FocusScope|FolderListModel|FontDialog|FontLoader|" + + "FontMetrics|FormValidationMessageRequest|ForwardRenderer|Frame|FrameAction|FrameGraphNode|Friction|" + + "FrontFace|FrustumCulling|FullScreenRequest|GLStateDumpExt|GammaAdjust|Gauge|GaugeStyle|GaussianBlur|" + + "GeocodeModel|Geometry|GeometryRenderer|GestureEvent|Glow|GoochMaterial|Gradient|GradientStop|GraphicsApiFilter|" + + "GraphicsInfo|Gravity|Grid|GridLayout|GridMesh|GridView|GroupBox|GroupGoal|Gyroscope|GyroscopeReading|HBarModelMapper|" + + "HBoxPlotModelMapper|HCandlestickModelMapper|HPieModelMapper|HXYModelMapper|HandlerPoint|HandwritingInputPanel|" + + "HandwritingModeKey|HeightMapSurfaceDataProxy|HideKeyboardKey|HistoryState|HolsterReading|HolsterSensor|HorizontalBarSeries|" + + "|HorizontalPercentBarSeries|HorizontalStackedBarSeries|HoverHandler|HueSaturation|HumidityReading|HumiditySensor|" + + "IRProximityReading|IRProximitySensor|Icon|Image|ImageModel|ImageParticle|InnerShadow|InputChord|InputContext|InputEngine|" + + "InputHandler3D|InputMethod|InputModeKey|InputPanel|InputSequence|InputSettings|Instantiator|IntValidator|InvokedServices|" + + "Item|ItemDelegate|ItemGrabResult|ItemModelBarDataProxy|ItemModelScatterDataProxy|ItemModelSurfaceDataProxy|ItemParticle|" + + "ItemSelectionModel|IviApplication|IviSurface|JavaScriptDialogRequest|Joint|JumpList|JumpListCategory|JumpListDestination|" + + "JumpListLink|JumpListSeparator|Key|KeyEvent|KeyIcon|KeyNavigation|KeyPanel|KeyboardColumn|KeyboardDevice|KeyboardHandler|" + + "KeyboardLayout|KeyboardLayoutLoader|KeyboardRow|KeyboardStyle|KeyframeAnimation|Keys|Label|Layer|LayerFilter|Layout|" + + "LayoutMirroring|Legend|LerpBlend|LevelAdjust|LevelOfDetail|LevelOfDetailBoundingSphere|LevelOfDetailLoader|" + + "LevelOfDetailSwitch|LidReading|LidSensor|Light|Light3D|LightReading|LightSensor|LineSeries|LineShape|LineWidth|" + + "LinearGradient|ListElement|ListModel|ListView|Loader|Locale|Location|LogValueAxis|LogValueAxis3DFormatter|LoggingCategory|" + + "LogicalDevice|Magnetometer|MagnetometerReading|Map|MapCircle|MapCircleObject|MapCopyrightNotice|MapGestureArea|MapIconObject|" + + "MapItemGroup|MapItemView|MapObjectView|MapParameter|MapPinchEvent|MapPolygon|MapPolygonObject|MapPolyline|MapPolylineObject|" + + "MapQuickItem|MapRectangle|MapRoute|MapRouteObject|MapType|Margins|MaskShape|MaskedBlur|Material|Matrix4x4|MediaPlayer|" + + "MemoryBarrier|Menu|MenuBar|MenuBarItem|MenuBarStyle|MenuItem|MenuSeparator|MenuStyle|Mesh|MessageDialog|ModeKey|MorphTarget|" + + "MorphingAnimation|MouseArea|MouseDevice|MouseEvent|MouseHandler|MultiPointHandler|MultiPointTouchArea|MultiSampleAntiAliasing|" + + "Navigator|NdefFilter|NdefMimeRecord|NdefRecord|NdefTextRecord|NdefUriRecord|NearField|NoDepthMask|NoDraw|Node|NodeInstantiator|" + + "NormalDiffuseMapAlphaMaterial|NormalDiffuseMapMaterial|NormalDiffuseSpecularMapMaterial|Number|NumberAnimation|NumberKey|Object3D|" + + "ObjectModel|ObjectPicker|OpacityAnimator|OpacityMask|OpenGLInfo|OrbitCameraController|OrientationReading|OrientationSensor|Overlay|" + + "Package|Page|PageIndicator|Pane|ParallelAnimation|Parameter|ParentAnimation|ParentChange|Particle|ParticleGroup|ParticlePainter|" + + "ParticleSystem|Path|PathAngleArc|PathAnimation|PathArc|PathAttribute|PathCubic|PathCurve|PathElement|PathInterpolator|PathLine|" + + "PathMove|PathPercent|PathQuad|PathSvg|PathView|PauseAnimation|PerVertexColorMaterial|PercentBarSeries|PhongAlphaMaterial|" + + "PhongMaterial|PickEvent|PickLineEvent|PickPointEvent|PickTriangleEvent|PickingSettings|Picture|PieMenu|PieMenuStyle|PieSeries|" + + "PieSlice|PinchArea|PinchEvent|PinchHandler|Place|PlaceAttribute|PlaceSearchModel|PlaceSearchSuggestionModel|PlaneGeometry|" + + "PlaneMesh|PlayVariation|Playlist|PlaylistItem|Plugin|PluginParameter|PointDirection|PointHandler|PointLight|PointSize|" + + "PointerDevice|PointerDeviceHandler|PointerEvent|PointerHandler|PolarChartView|PolygonOffset|Popup|Position|PositionSource|" + + "Positioner|PressureReading|PressureSensor|Product|ProgressBar|ProgressBarStyle|PropertyAction|PropertyAnimation|PropertyChanges|" + + "ProximityFilter|ProximityReading|ProximitySensor|QAbstractState|QAbstractTransition|QSignalTransition|" + + "QVirtualKeyboardSelectionListModel|Qt|QtMultimedia|QtObject|QtPositioning|QuaternionAnimation|QuotaRequest|RadialBlur|" + + "RadialGradient|Radio|RadioButton|RadioButtonStyle|RadioData|RadioDelegate|RangeSlider|Ratings|RayCaster|Rectangle|" + + "RectangleShape|RectangularGlow|RecursiveBlur|RegExpValidator|RegisterProtocolHandlerRequest|RenderCapture|" + + "RenderCaptureReply|RenderPass|RenderPassFilter|RenderSettings|RenderState|RenderStateSet|RenderSurfaceSelector|" + + "RenderTarget|RenderTargetOutput|RenderTargetSelector|Repeater|ReviewModel|Rotation|RotationAnimation|RotationAnimator|" + + "RotationReading|RotationSensor|RoundButton|Route|RouteLeg|RouteManeuver|RouteModel|RouteQuery|RouteSegment|Row|" + + "RowLayout|Scale|ScaleAnimator|Scatter3D|Scatter3DSeries|ScatterDataProxy|ScatterSeries|Scene2D|Scene3D|SceneLoader|" + + "ScissorTest|Screen|ScreenRayCaster|ScriptAction|ScrollBar|ScrollIndicator|ScrollView|ScrollViewStyle|ScxmlStateMachine|" + + "SeamlessCubemap|SelectionListItem|Sensor|SensorGesture|SensorGlobal|SensorReading|SequentialAnimation|Settings|" + + "SettingsStore|ShaderEffect|ShaderEffectSource|ShaderProgram|ShaderProgramBuilder|Shape|ShellSurface|ShellSurfaceItem|" + + "ShiftHandler|ShiftKey|Shortcut|SignalSpy|SignalTransition|SinglePointHandler|Skeleton|SkeletonLoader|Slider|SliderStyle|" + + "SmoothedAnimation|SortPolicy|Sound|SoundEffect|SoundInstance|SpaceKey|SphereGeometry|SphereMesh|SpinBox|SpinBoxStyle|" + + "SplineSeries|SplitView|SpotLight|SpringAnimation|Sprite|SpriteGoal|SpriteSequence|Stack|StackLayout|StackView|" + + "StackViewDelegate|StackedBarSeries|State|StateChangeScript|StateGroup|StateMachine|StateMachineLoader|StatusBar|" + + "StatusBarStyle|StatusIndicator|StatusIndicatorStyle|StencilMask|StencilOperation|StencilOperationArguments|StencilTest|" + + "StencilTestArguments|Store|String|Supplier|Surface3D|Surface3DSeries|SurfaceDataProxy|SwipeDelegate|SwipeView|Switch|" + + "SwitchDelegate|SwitchStyle|SymbolModeKey|SystemPalette|Tab|TabBar|TabButton|TabView|TabViewStyle|TableView|TableViewColumn|" + + "TableViewStyle|TapHandler|TapReading|TapSensor|TargetDirection|TaskbarButton|Technique|TechniqueFilter|TestCase|Text|TextArea|" + + "TextAreaStyle|TextEdit|TextField|TextFieldStyle|TextInput|TextMetrics|TextureImage|TextureImageFactory|Theme3D|ThemeColor|" + + "ThresholdMask|ThumbnailToolBar|ThumbnailToolButton|TiltReading|TiltSensor|TimeoutTransition|Timer|ToggleButton|" + + "ToggleButtonStyle|ToolBar|ToolBarStyle|ToolButton|ToolSeparator|ToolTip|Torch|TorusGeometry|TorusMesh|TouchEventSequence|" + + "TouchInputHandler3D|TouchPoint|Trace|TraceCanvas|TraceInputArea|TraceInputKey|TraceInputKeyPanel|TrailEmitter|Transaction|" + + "Transform|Transition|Translate|TreeView|TreeViewStyle|Tumbler|TumblerColumn|TumblerStyle|Turbulence|UniformAnimator|User|" + + "VBarModelMapper|VBoxPlotModelMapper|VCandlestickModelMapper|VPieModelMapper|VXYModelMapper|ValueAxis|ValueAxis3D|" + + "ValueAxis3DFormatter|Vector3dAnimation|VertexBlendAnimation|Video|VideoOutput|ViewTransition|Viewport|" + + "VirtualKeyboardSettings|Wander|WavefrontMesh|WaylandClient|WaylandCompositor|WaylandHardwareLayer|" + + "WaylandOutput|WaylandQuickItem|WaylandSeat|WaylandSurface|WaylandView|Waypoint|" + + "WebChannel|WebEngine|WebEngineAction|WebEngineCertificateError|WebEngineDownloadItem|WebEngineHistory|" + + "WebEngineHistoryListModel|WebEngineLoadRequest|WebEngineNavigationRequest|WebEngineNewViewRequest|WebEngineProfile|WebEngineScript|" + + "WebEngineSettings|WebEngineView|WebSocket|WebSocketServer|WebView|WebViewLoadRequest|" + + "WheelEvent|Window|WlShell|WlShellSurface|WorkerScript|XAnimator|" + + "XYPoint|XYSeries|XdgDecorationManagerV1|XdgPopup|XdgPopupV5|XdgPopupV6|" + + "XdgShell|XdgShellV5|XdgShellV6|XdgSurface|XdgSurfaceV5|XdgSurfaceV6|" + + "XdgToplevel|XdgToplevelV6|XmlListModel|XmlRole|YAnimator|ZoomBlur", + "storage.type": + "const|let|var|function|" + // js + "property|", // qml + "constant.language": + "null|Infinity|NaN|undefined", + "support.function": + "print|console\\.log", + "constant.language.boolean": "true|false" + }, "identifier"); // regexp must not have capturing parentheses. Use (?:) instead. // regexps are ordered -> the first match is used this.$rules = { "start" : [ { - token : "variable", // single line - regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)' - }, { token : "string", // single line regex : '"', next : "string" @@ -75,6 +209,9 @@ define(function(require, exports, module) { }, { token : "text", regex : "\\s+" + }, { + token : keywordMapper, + regex : "\\b\\w+\\b" } ], "string" : [ From 777b6885c1887d84d94ffc292f8cefe8c5dee34b Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 12 Apr 2020 16:23:42 +0400 Subject: [PATCH 0334/1293] do not exit composition after empty commands --- lib/ace/autocomplete.js | 2 ++ lib/ace/keyboard/textinput.js | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index e3349775314..078cd6dbf47 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -172,6 +172,7 @@ var Autocomplete = function() { if (!data) return false; + this.editor.startOperation({command: {name: "insertMatch"}}); if (data.completer && data.completer.insertMatch) { data.completer.insertMatch(this.editor, data); } else { @@ -189,6 +190,7 @@ var Autocomplete = function() { this.editor.execCommand("insertstring", data.value || data); } this.detach(); + this.editor.endOperation(); }; diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index ee2e9fa2b9b..c8c33e19112 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -151,7 +151,8 @@ var TextInput = function(parentNode, host) { var commandName = curOp && curOp.command && curOp.command.name; if (commandName == "insertstring") return; - if (inComposition && commandName) { + var isUserAction = commandName && (curOp.docChanged || curOp.selectionChanged); + if (inComposition && isUserAction) { // exit composition from commands other than insertstring lastValue = text.value = ""; onCompositionEnd(); From 42780fc9a16d3672c9d06bb4eb652852d5cde0cf Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 12 Apr 2020 16:28:32 +0400 Subject: [PATCH 0335/1293] remove unnesseary call to textinput destroy --- lib/ace/editor.js | 1 - lib/ace/keyboard/textinput.js | 6 ------ 2 files changed, 7 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 9a82056df01..556f8692afa 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -2737,7 +2737,6 @@ Editor.$uid = 0; this.$toDestroy = null; } this.renderer.destroy(); - this.textInput.destroy(); this._signal("destroy", this); if (this.session) this.session.destroy(); diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index c8c33e19112..125426b3c67 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -733,12 +733,6 @@ var TextInput = function(parentNode, host) { document.removeEventListener("selectionchange", detectArrowKeys); }); } - - this.destroy = function() { - if (text.parentElement) - text.parentElement.removeChild(text); - host = text = parentNode = null; - }; }; exports.TextInput = TextInput; From d90bdc782745ed38585549d577752f3f83e4eb34 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 14 Apr 2020 00:15:22 +0400 Subject: [PATCH 0336/1293] fix gboard backspace deleting right char at the file start --- lib/ace/keyboard/textinput.js | 6 +++++- lib/ace/keyboard/textinput_test.js | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index ee2e9fa2b9b..39a7e577338 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -212,7 +212,7 @@ var TextInput = function(parentNode, host) { selectionEnd += line.length + 1; line = line + "\n" + nextLine; } - else if (isMobile) { + else if (isMobile && row > 0) { line = "\n" + line; selectionEnd += 1; selectionStart += 1; @@ -741,4 +741,8 @@ var TextInput = function(parentNode, host) { }; exports.TextInput = TextInput; +exports.$setUserAgentForTests = function(_isMobile, _isIOS) { + isMobile = _isMobile; + isIOS = _isIOS; +}; }); diff --git a/lib/ace/keyboard/textinput_test.js b/lib/ace/keyboard/textinput_test.js index fd2a398d70b..4a80b637848 100644 --- a/lib/ace/keyboard/textinput_test.js +++ b/lib/ace/keyboard/textinput_test.js @@ -40,6 +40,7 @@ define(function(require, exports, module) { require("../test/mockdom"); var assert = require("../test/assertions"); var clipboard = require("../clipboard"); +var setUserAgentForTests = require("./textinput").$setUserAgentForTests; var ace = require("../ace"); var editor, changes, textarea, copiedValue; @@ -97,6 +98,7 @@ module.exports = { setUp: function() { if (editor) this.tearDown(); + setUserAgentForTests(false, false); editor = ace.edit(null); document.body.appendChild(editor.container); editor.container.style.height = "200px"; @@ -156,6 +158,30 @@ module.exports = { assert.equal(editor.getValue(), "x x"); }, + "test: mobile text deletion at the line start": function() { + setUserAgentForTests(true, false); + editor.destroy(); + editor = ace.edit(editor.container); + textarea = editor.textInput.getElement(); + editor.resize(true); + editor.focus(); + editor.setValue("\nxy", 1); + editor.execCommand("gotoleft"); + editor.resize(true); + [ + { _: "keydown", range: [2,2], value: "\nxy\n\n"}, + { _: "input", range: [1,1], value: "\ny\n\n"}, + { _: "keyup", range: [1,1], value: "\ny\n\n"}, + { _: "keydown", range: [1,1], value: "\ny\n\n"}, + { _: "input", range: [0,0], value: "y\n\n"}, + { _: "keyup", range: [0,0], value: "y\n\n"} + ].forEach(function(data) { + sendEvent(data._, data); + }); + editor.resize(true); + assert.equal(editor.getValue(), "y"); + }, + "test: composition with visible textarea": function() { var data = [ // select ll From e1d9586aef7926ac74e091ebc013a606778ac626 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 15 Apr 2020 00:17:30 +0400 Subject: [PATCH 0337/1293] release v1.4.10 --- ChangeLog.txt | 4 ++++ build | 2 +- lib/ace/config.js | 2 +- package.json | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 32702197942..0c823853b4c 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,7 @@ +2020.04.15 Version 1.4.10 +* added workaround for chrome bug causing memory leak after calling editor.destroy +* added code folding support for vbscript mode + 2020.04.01 Version 1.4.9 * added option to disable autoindent * added new language modes diff --git a/build b/build index bd7ce25eaba..2ea299a2bee 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit bd7ce25eaba22b54e3f7e5f46b8596bb90d4a341 +Subproject commit 2ea299a2bee97fdf58fc90cb76eec6c45535a63f diff --git a/lib/ace/config.js b/lib/ace/config.js index a5b1ceca964..ac6d8938441 100644 --- a/lib/ace/config.js +++ b/lib/ace/config.js @@ -220,6 +220,6 @@ function deHyphenate(str) { return str.replace(/-(.)/g, function(m, m1) { return m1.toUpperCase(); }); } -exports.version = "1.4.9"; +exports.version = "1.4.10"; }); diff --git a/package.json b/package.json index 11089e90963..8fa740bfca0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.4.9", + "version": "1.4.10", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" From 9ba2927c5c560e42c2c3d82ef16d0d3e0e48764b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aldo=20Rom=C3=A1n?= Date: Thu, 16 Apr 2020 11:25:24 +0200 Subject: [PATCH 0338/1293] Fix typing in Editor `blur` event Fixes #4263 --- ace.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ace.d.ts b/ace.d.ts index 34fb6665a93..16f084d8ebc 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -746,7 +746,7 @@ export namespace Ace { setFontSize(size: string): void; focus(): void; isFocused(): boolean; - flur(): void; + blur(): void; getSelectedText(): string; getCopyText(): string; execCommand(command: string | string[], args?: any): boolean; From b7bcaa882fb024ec15b82ad4dc5ac98ac61cf82b Mon Sep 17 00:00:00 2001 From: jaml Date: Sat, 18 Apr 2020 14:33:07 +0200 Subject: [PATCH 0339/1293] Add `src-noconflict/ace` to TypeScript module declarations --- Makefile.dryice.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 5fc94bd974e..5ad19197be0 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -119,14 +119,18 @@ function buildTypes() { fs.readdirSync(BUILD_DIR + '/src-noconflict/snippets').forEach(function(path) { paths.push("snippets/" + path); }); - - var pathModules = paths.map(function(path) { - if (/^(mode|theme|ext|keybinding)-|^snippets\//.test(path)) { + + var moduleNameRegex = /^(mode|theme|ext|keybinding)-|^snippets\//; + + var pathModules = [ + "declare module 'ace-builds/webpack-resolver';", + "declare module 'ace-builds/src-noconflict/ace';" + ].concat(paths.map(function(path) { + if (moduleNameRegex.test(path)) { var moduleName = path.split('.')[0]; return "declare module 'ace-builds/src-noconflict/" + moduleName + "';"; } - }).filter(Boolean).join('\n') - + "\ndeclare module 'ace-builds/webpack-resolver';\n"; + }).filter(Boolean)).join("\n") + "\n"; fs.writeFileSync(BUILD_DIR + '/ace.d.ts', moduleRef + '\n' + definitions); fs.writeFileSync(BUILD_DIR + '/ace-modules.d.ts', pathModules); From 51defca5668a0737f05ca091d109ac48d90a4767 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 24 Nov 2019 22:35:23 +0400 Subject: [PATCH 0340/1293] remove unused es5-shim --- lib/ace/lib/es5-shim.js | 1062 --------------------------------- lib/ace/lib/fixoldbrowsers.js | 3 - lib/ace/lib/regexp.js | 113 ---- lib/ace/worker/worker.js | 1 - 4 files changed, 1179 deletions(-) delete mode 100644 lib/ace/lib/es5-shim.js delete mode 100644 lib/ace/lib/regexp.js diff --git a/lib/ace/lib/es5-shim.js b/lib/ace/lib/es5-shim.js deleted file mode 100644 index 054699006d9..00000000000 --- a/lib/ace/lib/es5-shim.js +++ /dev/null @@ -1,1062 +0,0 @@ -// https://github.com/kriskowal/es5-shim -// Copyright 2009-2012 by contributors, MIT License - -define(function(require, exports, module) { - -/* - * Brings an environment as close to ECMAScript 5 compliance - * as is possible with the facilities of erstwhile engines. - * - * Annotated ES5: http://es5.github.com/ (specific links below) - * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf - * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/ - */ - -// -// Function -// ======== -// - -// ES-5 15.3.4.5 -// http://es5.github.com/#x15.3.4.5 - -function Empty() {} - -if (!Function.prototype.bind) { - Function.prototype.bind = function bind(that) { // .length is 1 - // 1. Let Target be the this value. - var target = this; - // 2. If IsCallable(Target) is false, throw a TypeError exception. - if (typeof target != "function") { - throw new TypeError("Function.prototype.bind called on incompatible " + target); - } - // 3. Let A be a new (possibly empty) internal list of all of the - // argument values provided after thisArg (arg1, arg2 etc), in order. - // XXX slicedArgs will stand in for "A" if used - var args = slice.call(arguments, 1); // for normal call - // 4. Let F be a new native ECMAScript object. - // 11. Set the [[Prototype]] internal property of F to the standard - // built-in Function prototype object as specified in 15.3.3.1. - // 12. Set the [[Call]] internal property of F as described in - // 15.3.4.5.1. - // 13. Set the [[Construct]] internal property of F as described in - // 15.3.4.5.2. - // 14. Set the [[HasInstance]] internal property of F as described in - // 15.3.4.5.3. - var bound = function () { - - if (this instanceof bound) { - // 15.3.4.5.2 [[Construct]] - // When the [[Construct]] internal method of a function object, - // F that was created using the bind function is called with a - // list of arguments ExtraArgs, the following steps are taken: - // 1. Let target be the value of F's [[TargetFunction]] - // internal property. - // 2. If target has no [[Construct]] internal method, a - // TypeError exception is thrown. - // 3. Let boundArgs be the value of F's [[BoundArgs]] internal - // property. - // 4. Let args be a new list containing the same values as the - // list boundArgs in the same order followed by the same - // values as the list ExtraArgs in the same order. - // 5. Return the result of calling the [[Construct]] internal - // method of target providing args as the arguments. - - var result = target.apply( - this, - args.concat(slice.call(arguments)) - ); - if (Object(result) === result) { - return result; - } - return this; - - } else { - // 15.3.4.5.1 [[Call]] - // When the [[Call]] internal method of a function object, F, - // which was created using the bind function is called with a - // this value and a list of arguments ExtraArgs, the following - // steps are taken: - // 1. Let boundArgs be the value of F's [[BoundArgs]] internal - // property. - // 2. Let boundThis be the value of F's [[BoundThis]] internal - // property. - // 3. Let target be the value of F's [[TargetFunction]] internal - // property. - // 4. Let args be a new list containing the same values as the - // list boundArgs in the same order followed by the same - // values as the list ExtraArgs in the same order. - // 5. Return the result of calling the [[Call]] internal method - // of target providing boundThis as the this value and - // providing args as the arguments. - - // equiv: target.call(this, ...boundArgs, ...args) - return target.apply( - that, - args.concat(slice.call(arguments)) - ); - - } - - }; - if(target.prototype) { - Empty.prototype = target.prototype; - bound.prototype = new Empty(); - // Clean up dangling references. - Empty.prototype = null; - } - // XXX bound.length is never writable, so don't even try - // - // 15. If the [[Class]] internal property of Target is "Function", then - // a. Let L be the length property of Target minus the length of A. - // b. Set the length own property of F to either 0 or L, whichever is - // larger. - // 16. Else set the length own property of F to 0. - // 17. Set the attributes of the length own property of F to the values - // specified in 15.3.5.1. - - // TODO - // 18. Set the [[Extensible]] internal property of F to true. - - // TODO - // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). - // 20. Call the [[DefineOwnProperty]] internal method of F with - // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: - // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and - // false. - // 21. Call the [[DefineOwnProperty]] internal method of F with - // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, - // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, - // and false. - - // TODO - // NOTE Function objects created using Function.prototype.bind do not - // have a prototype property or the [[Code]], [[FormalParameters]], and - // [[Scope]] internal properties. - // XXX can't delete prototype in pure-js. - - // 22. Return F. - return bound; - }; -} - -// Shortcut to an often accessed properties, in order to avoid multiple -// dereference that costs universally. -// _Please note: Shortcuts are defined after `Function.prototype.bind` as we -// us it in defining shortcuts. -var call = Function.prototype.call; -var prototypeOfArray = Array.prototype; -var prototypeOfObject = Object.prototype; -var slice = prototypeOfArray.slice; -// Having a toString local variable name breaks in Opera so use _toString. -var _toString = call.bind(prototypeOfObject.toString); -var owns = call.bind(prototypeOfObject.hasOwnProperty); - -// If JS engine supports accessors creating shortcuts. -var defineGetter; -var defineSetter; -var lookupGetter; -var lookupSetter; -var supportsAccessors; -if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) { - defineGetter = call.bind(prototypeOfObject.__defineGetter__); - defineSetter = call.bind(prototypeOfObject.__defineSetter__); - lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); - lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); -} - -// -// Array -// ===== -// - -// ES5 15.4.4.12 -// http://es5.github.com/#x15.4.4.12 -// Default value for second param -// [bugfix, ielt9, old browsers] -// IE < 9 bug: [1,2].splice(0).join("") == "" but should be "12" -if ([1,2].splice(0).length != 2) { - if(function() { // test IE < 9 to splice bug - see issue #138 - function makeArray(l) { - var a = new Array(l+2); - a[0] = a[1] = 0; - return a; - } - var array = [], lengthBefore; - - array.splice.apply(array, makeArray(20)); - array.splice.apply(array, makeArray(26)); - - lengthBefore = array.length; //46 - array.splice(5, 0, "XXX"); // add one element - - lengthBefore + 1 == array.length - - if (lengthBefore + 1 == array.length) { - return true;// has right splice implementation without bugs - } - // else { - // IE8 bug - // } - }()) {//IE 6/7 - var array_splice = Array.prototype.splice; - Array.prototype.splice = function(start, deleteCount) { - if (!arguments.length) { - return []; - } else { - return array_splice.apply(this, [ - start === void 0 ? 0 : start, - deleteCount === void 0 ? (this.length - start) : deleteCount - ].concat(slice.call(arguments, 2))) - } - }; - } else {//IE8 - // taken from http://docs.sencha.com/ext-js/4-1/source/Array2.html - Array.prototype.splice = function(pos, removeCount){ - var length = this.length; - if (pos > 0) { - if (pos > length) - pos = length; - } else if (pos == void 0) { - pos = 0; - } else if (pos < 0) { - pos = Math.max(length + pos, 0); - } - - if (!(pos+removeCount < length)) - removeCount = length - pos; - - var removed = this.slice(pos, pos+removeCount); - var insert = slice.call(arguments, 2); - var add = insert.length; - - // we try to use Array.push when we can for efficiency... - if (pos === length) { - if (add) { - this.push.apply(this, insert); - } - } else { - var remove = Math.min(removeCount, length - pos); - var tailOldPos = pos + remove; - var tailNewPos = tailOldPos + add - remove; - var tailCount = length - tailOldPos; - var lengthAfterRemove = length - remove; - - if (tailNewPos < tailOldPos) { // case A - for (var i = 0; i < tailCount; ++i) { - this[tailNewPos+i] = this[tailOldPos+i]; - } - } else if (tailNewPos > tailOldPos) { // case B - for (i = tailCount; i--; ) { - this[tailNewPos+i] = this[tailOldPos+i]; - } - } // else, add == remove (nothing to do) - - if (add && pos === lengthAfterRemove) { - this.length = lengthAfterRemove; // truncate array - this.push.apply(this, insert); - } else { - this.length = lengthAfterRemove + add; // reserves space - for (i = 0; i < add; ++i) { - this[pos+i] = insert[i]; - } - } - } - return removed; - }; - } -} - -// ES5 15.4.3.2 -// http://es5.github.com/#x15.4.3.2 -// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray -if (!Array.isArray) { - Array.isArray = function isArray(obj) { - return _toString(obj) == "[object Array]"; - }; -} - -// The IsCallable() check in the Array functions -// has been replaced with a strict check on the -// internal class of the object to trap cases where -// the provided function was actually a regular -// expression literal, which in V8 and -// JavaScriptCore is a typeof "function". Only in -// V8 are regular expression literals permitted as -// reduce parameters, so it is desirable in the -// general case for the shim to match the more -// strict and common behavior of rejecting regular -// expressions. - -// ES5 15.4.4.18 -// http://es5.github.com/#x15.4.4.18 -// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach - -// Check failure of by-index access of string characters (IE < 9) -// and failure of `0 in boxedString` (Rhino) -var boxedString = Object("a"), - splitString = boxedString[0] != "a" || !(0 in boxedString); - -if (!Array.prototype.forEach) { - Array.prototype.forEach = function forEach(fun /*, thisp*/) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - thisp = arguments[1], - i = -1, - length = self.length >>> 0; - - // If no callback function or if callback is not a callable function - if (_toString(fun) != "[object Function]") { - throw new TypeError(); // TODO message - } - - while (++i < length) { - if (i in self) { - // Invoke the callback function with call, passing arguments: - // context, property value, property key, thisArg object - // context - fun.call(thisp, self[i], i, object); - } - } - }; -} - -// ES5 15.4.4.19 -// http://es5.github.com/#x15.4.4.19 -// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map -if (!Array.prototype.map) { - Array.prototype.map = function map(fun /*, thisp*/) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0, - result = Array(length), - thisp = arguments[1]; - - // If no callback function or if callback is not a callable function - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - - for (var i = 0; i < length; i++) { - if (i in self) - result[i] = fun.call(thisp, self[i], i, object); - } - return result; - }; -} - -// ES5 15.4.4.20 -// http://es5.github.com/#x15.4.4.20 -// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter -if (!Array.prototype.filter) { - Array.prototype.filter = function filter(fun /*, thisp */) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0, - result = [], - value, - thisp = arguments[1]; - - // If no callback function or if callback is not a callable function - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - - for (var i = 0; i < length; i++) { - if (i in self) { - value = self[i]; - if (fun.call(thisp, value, i, object)) { - result.push(value); - } - } - } - return result; - }; -} - -// ES5 15.4.4.16 -// http://es5.github.com/#x15.4.4.16 -// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every -if (!Array.prototype.every) { - Array.prototype.every = function every(fun /*, thisp */) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0, - thisp = arguments[1]; - - // If no callback function or if callback is not a callable function - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - - for (var i = 0; i < length; i++) { - if (i in self && !fun.call(thisp, self[i], i, object)) { - return false; - } - } - return true; - }; -} - -// ES5 15.4.4.17 -// http://es5.github.com/#x15.4.4.17 -// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some -if (!Array.prototype.some) { - Array.prototype.some = function some(fun /*, thisp */) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0, - thisp = arguments[1]; - - // If no callback function or if callback is not a callable function - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - - for (var i = 0; i < length; i++) { - if (i in self && fun.call(thisp, self[i], i, object)) { - return true; - } - } - return false; - }; -} - -// ES5 15.4.4.21 -// http://es5.github.com/#x15.4.4.21 -// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce -if (!Array.prototype.reduce) { - Array.prototype.reduce = function reduce(fun /*, initial*/) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0; - - // If no callback function or if callback is not a callable function - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - - // no value to return if no initial value and an empty array - if (!length && arguments.length == 1) { - throw new TypeError("reduce of empty array with no initial value"); - } - - var i = 0; - var result; - if (arguments.length >= 2) { - result = arguments[1]; - } else { - do { - if (i in self) { - result = self[i++]; - break; - } - - // if array contains no values, no initial value to return - if (++i >= length) { - throw new TypeError("reduce of empty array with no initial value"); - } - } while (true); - } - - for (; i < length; i++) { - if (i in self) { - result = fun.call(void 0, result, self[i], i, object); - } - } - - return result; - }; -} - -// ES5 15.4.4.22 -// http://es5.github.com/#x15.4.4.22 -// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight -if (!Array.prototype.reduceRight) { - Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0; - - // If no callback function or if callback is not a callable function - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - - // no value to return if no initial value, empty array - if (!length && arguments.length == 1) { - throw new TypeError("reduceRight of empty array with no initial value"); - } - - var result, i = length - 1; - if (arguments.length >= 2) { - result = arguments[1]; - } else { - do { - if (i in self) { - result = self[i--]; - break; - } - - // if array contains no values, no initial value to return - if (--i < 0) { - throw new TypeError("reduceRight of empty array with no initial value"); - } - } while (true); - } - - do { - if (i in this) { - result = fun.call(void 0, result, self[i], i, object); - } - } while (i--); - - return result; - }; -} - -// ES5 15.4.4.14 -// http://es5.github.com/#x15.4.4.14 -// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf -if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) { - Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) { - var self = splitString && _toString(this) == "[object String]" ? - this.split("") : - toObject(this), - length = self.length >>> 0; - - if (!length) { - return -1; - } - - var i = 0; - if (arguments.length > 1) { - i = toInteger(arguments[1]); - } - - // handle negative indices - i = i >= 0 ? i : Math.max(0, length + i); - for (; i < length; i++) { - if (i in self && self[i] === sought) { - return i; - } - } - return -1; - }; -} - -// ES5 15.4.4.15 -// http://es5.github.com/#x15.4.4.15 -// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf -if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) { - Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) { - var self = splitString && _toString(this) == "[object String]" ? - this.split("") : - toObject(this), - length = self.length >>> 0; - - if (!length) { - return -1; - } - var i = length - 1; - if (arguments.length > 1) { - i = Math.min(i, toInteger(arguments[1])); - } - // handle negative indices - i = i >= 0 ? i : length - Math.abs(i); - for (; i >= 0; i--) { - if (i in self && sought === self[i]) { - return i; - } - } - return -1; - }; -} - -// -// Object -// ====== -// - -// ES5 15.2.3.2 -// http://es5.github.com/#x15.2.3.2 -if (!Object.getPrototypeOf) { - // https://github.com/kriskowal/es5-shim/issues#issue/2 - // http://ejohn.org/blog/objectgetprototypeof/ - // recommended by fschaefer on github - Object.getPrototypeOf = function getPrototypeOf(object) { - return object.__proto__ || ( - object.constructor ? - object.constructor.prototype : - prototypeOfObject - ); - }; -} - -// ES5 15.2.3.3 -// http://es5.github.com/#x15.2.3.3 -if (!Object.getOwnPropertyDescriptor) { - var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " + - "non-object: "; - Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { - if ((typeof object != "object" && typeof object != "function") || object === null) - throw new TypeError(ERR_NON_OBJECT + object); - // If object does not owns property return undefined immediately. - if (!owns(object, property)) - return; - - var descriptor, getter, setter; - - // If object has a property then it's for sure both `enumerable` and - // `configurable`. - descriptor = { enumerable: true, configurable: true }; - - // If JS engine supports accessor properties then property may be a - // getter or setter. - if (supportsAccessors) { - // Unfortunately `__lookupGetter__` will return a getter even - // if object has own non getter property along with a same named - // inherited getter. To avoid misbehavior we temporary remove - // `__proto__` so that `__lookupGetter__` will return getter only - // if it's owned by an object. - var prototype = object.__proto__; - object.__proto__ = prototypeOfObject; - - var getter = lookupGetter(object, property); - var setter = lookupSetter(object, property); - - // Once we have getter and setter we can put values back. - object.__proto__ = prototype; - - if (getter || setter) { - if (getter) descriptor.get = getter; - if (setter) descriptor.set = setter; - - // If it was accessor property we're done and return here - // in order to avoid adding `value` to the descriptor. - return descriptor; - } - } - - // If we got this far we know that object has an own property that is - // not an accessor so we set it as a value and return descriptor. - descriptor.value = object[property]; - return descriptor; - }; -} - -// ES5 15.2.3.4 -// http://es5.github.com/#x15.2.3.4 -if (!Object.getOwnPropertyNames) { - Object.getOwnPropertyNames = function getOwnPropertyNames(object) { - return Object.keys(object); - }; -} - -// ES5 15.2.3.5 -// http://es5.github.com/#x15.2.3.5 -if (!Object.create) { - var createEmpty; - if (Object.prototype.__proto__ === null) { - createEmpty = function () { - return { "__proto__": null }; - }; - } else { - // In old IE __proto__ can't be used to manually set `null` - createEmpty = function () { - var empty = {}; - for (var i in empty) - empty[i] = null; - empty.constructor = - empty.hasOwnProperty = - empty.propertyIsEnumerable = - empty.isPrototypeOf = - empty.toLocaleString = - empty.toString = - empty.valueOf = - empty.__proto__ = null; - return empty; - } - } - - Object.create = function create(prototype, properties) { - var object; - if (prototype === null) { - object = createEmpty(); - } else { - if (typeof prototype != "object") - throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'"); - var Type = function () {}; - Type.prototype = prototype; - object = new Type(); - // IE has no built-in implementation of `Object.getPrototypeOf` - // neither `__proto__`, but this manually setting `__proto__` will - // guarantee that `Object.getPrototypeOf` will work as expected with - // objects created using `Object.create` - object.__proto__ = prototype; - } - if (properties !== void 0) - Object.defineProperties(object, properties); - return object; - }; -} - -// ES5 15.2.3.6 -// http://es5.github.com/#x15.2.3.6 - -// Patch for WebKit and IE8 standard mode -// Designed by hax -// related issue: https://github.com/kriskowal/es5-shim/issues#issue/5 -// IE8 Reference: -// http://msdn.microsoft.com/en-us/library/dd282900.aspx -// http://msdn.microsoft.com/en-us/library/dd229916.aspx -// WebKit Bugs: -// https://bugs.webkit.org/show_bug.cgi?id=36423 - -function doesDefinePropertyWork(object) { - try { - Object.defineProperty(object, "sentinel", {}); - return "sentinel" in object; - } catch (exception) { - // returns falsy - } -} - -// check whether defineProperty works if it's given. Otherwise, -// shim partially. -if (Object.defineProperty) { - var definePropertyWorksOnObject = doesDefinePropertyWork({}); - var definePropertyWorksOnDom = typeof document == "undefined" || - doesDefinePropertyWork(document.createElement("div")); - if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { - var definePropertyFallback = Object.defineProperty; - } -} - -if (!Object.defineProperty || definePropertyFallback) { - var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: "; - var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: " - var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + - "on this javascript engine"; - - Object.defineProperty = function defineProperty(object, property, descriptor) { - if ((typeof object != "object" && typeof object != "function") || object === null) - throw new TypeError(ERR_NON_OBJECT_TARGET + object); - if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) - throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); - - // make a valiant attempt to use the real defineProperty - // for I8's DOM elements. - if (definePropertyFallback) { - try { - return definePropertyFallback.call(Object, object, property, descriptor); - } catch (exception) { - // try the shim if the real one doesn't work - } - } - - // If it's a data property. - if (owns(descriptor, "value")) { - // fail silently if "writable", "enumerable", or "configurable" - // are requested but not supported - /* - // alternate approach: - if ( // can't implement these features; allow false but not true - !(owns(descriptor, "writable") ? descriptor.writable : true) || - !(owns(descriptor, "enumerable") ? descriptor.enumerable : true) || - !(owns(descriptor, "configurable") ? descriptor.configurable : true) - ) - throw new RangeError( - "This implementation of Object.defineProperty does not " + - "support configurable, enumerable, or writable." - ); - */ - - if (supportsAccessors && (lookupGetter(object, property) || - lookupSetter(object, property))) - { - // As accessors are supported only on engines implementing - // `__proto__` we can safely override `__proto__` while defining - // a property to make sure that we don't hit an inherited - // accessor. - var prototype = object.__proto__; - object.__proto__ = prototypeOfObject; - // Deleting a property anyway since getter / setter may be - // defined on object itself. - delete object[property]; - object[property] = descriptor.value; - // Setting original `__proto__` back now. - object.__proto__ = prototype; - } else { - object[property] = descriptor.value; - } - } else { - if (!supportsAccessors) - throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); - // If we got that far then getters and setters can be defined !! - if (owns(descriptor, "get")) - defineGetter(object, property, descriptor.get); - if (owns(descriptor, "set")) - defineSetter(object, property, descriptor.set); - } - - return object; - }; -} - -// ES5 15.2.3.7 -// http://es5.github.com/#x15.2.3.7 -if (!Object.defineProperties) { - Object.defineProperties = function defineProperties(object, properties) { - for (var property in properties) { - if (owns(properties, property)) - Object.defineProperty(object, property, properties[property]); - } - return object; - }; -} - -// ES5 15.2.3.8 -// http://es5.github.com/#x15.2.3.8 -if (!Object.seal) { - Object.seal = function seal(object) { - // this is misleading and breaks feature-detection, but - // allows "securable" code to "gracefully" degrade to working - // but insecure code. - return object; - }; -} - -// ES5 15.2.3.9 -// http://es5.github.com/#x15.2.3.9 -if (!Object.freeze) { - Object.freeze = function freeze(object) { - // this is misleading and breaks feature-detection, but - // allows "securable" code to "gracefully" degrade to working - // but insecure code. - return object; - }; -} - -// detect a Rhino bug and patch it -try { - Object.freeze(function () {}); -} catch (exception) { - Object.freeze = (function freeze(freezeObject) { - return function freeze(object) { - if (typeof object == "function") { - return object; - } else { - return freezeObject(object); - } - }; - })(Object.freeze); -} - -// ES5 15.2.3.10 -// http://es5.github.com/#x15.2.3.10 -if (!Object.preventExtensions) { - Object.preventExtensions = function preventExtensions(object) { - // this is misleading and breaks feature-detection, but - // allows "securable" code to "gracefully" degrade to working - // but insecure code. - return object; - }; -} - -// ES5 15.2.3.11 -// http://es5.github.com/#x15.2.3.11 -if (!Object.isSealed) { - Object.isSealed = function isSealed(object) { - return false; - }; -} - -// ES5 15.2.3.12 -// http://es5.github.com/#x15.2.3.12 -if (!Object.isFrozen) { - Object.isFrozen = function isFrozen(object) { - return false; - }; -} - -// ES5 15.2.3.13 -// http://es5.github.com/#x15.2.3.13 -if (!Object.isExtensible) { - Object.isExtensible = function isExtensible(object) { - // 1. If Type(O) is not Object throw a TypeError exception. - if (Object(object) === object) { - throw new TypeError(); // TODO message - } - // 2. Return the Boolean value of the [[Extensible]] internal property of O. - var name = ''; - while (owns(object, name)) { - name += '?'; - } - object[name] = true; - var returnValue = owns(object, name); - delete object[name]; - return returnValue; - }; -} - -// ES5 15.2.3.14 -// http://es5.github.com/#x15.2.3.14 -if (!Object.keys) { - // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation - var hasDontEnumBug = true, - dontEnums = [ - "toString", - "toLocaleString", - "valueOf", - "hasOwnProperty", - "isPrototypeOf", - "propertyIsEnumerable", - "constructor" - ], - dontEnumsLength = dontEnums.length; - - for (var key in {"toString": null}) { - hasDontEnumBug = false; - } - - Object.keys = function keys(object) { - - if ( - (typeof object != "object" && typeof object != "function") || - object === null - ) { - throw new TypeError("Object.keys called on a non-object"); - } - - var keys = []; - for (var name in object) { - if (owns(object, name)) { - keys.push(name); - } - } - - if (hasDontEnumBug) { - for (var i = 0, ii = dontEnumsLength; i < ii; i++) { - var dontEnum = dontEnums[i]; - if (owns(object, dontEnum)) { - keys.push(dontEnum); - } - } - } - return keys; - }; - -} - -// -// most of es5-shim Date section is removed since ace doesn't need it, it is too intrusive and it causes problems for users -// ==== -// - -// ES5 15.9.4.4 -// http://es5.github.com/#x15.9.4.4 -if (!Date.now) { - Date.now = function now() { - return new Date().getTime(); - }; -} - - -// -// String -// ====== -// - -// ES5 15.5.4.20 -// http://es5.github.com/#x15.5.4.20 -var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u2000\u2001\u2002\u2003" + - "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + - "\u2029\uFEFF"; -if (!String.prototype.trim) { - // http://blog.stevenlevithan.com/archives/faster-trim-javascript - // http://perfectionkills.com/whitespace-deviations/ - ws = "[" + ws + "]"; - var trimBeginRegexp = new RegExp("^" + ws + ws + "*"), - trimEndRegexp = new RegExp(ws + ws + "*$"); - String.prototype.trim = function trim() { - return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, ""); - }; -} - -// -// Util -// ====== -// - -// ES5 9.4 -// http://es5.github.com/#x9.4 -// http://jsperf.com/to-integer - -function toInteger(n) { - n = +n; - if (n !== n) { // isNaN - n = 0; - } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - return n; -} - -function isPrimitive(input) { - var type = typeof input; - return ( - input === null || - type === "undefined" || - type === "boolean" || - type === "number" || - type === "string" - ); -} - -function toPrimitive(input) { - var val, valueOf, toString; - if (isPrimitive(input)) { - return input; - } - valueOf = input.valueOf; - if (typeof valueOf === "function") { - val = valueOf.call(input); - if (isPrimitive(val)) { - return val; - } - } - toString = input.toString; - if (typeof toString === "function") { - val = toString.call(input); - if (isPrimitive(val)) { - return val; - } - } - throw new TypeError(); -} - -// ES5 9.9 -// http://es5.github.com/#x9.9 -var toObject = function (o) { - if (o == null) { // this matches both null and undefined - throw new TypeError("can't convert "+o+" to object"); - } - return Object(o); -}; - -}); diff --git a/lib/ace/lib/fixoldbrowsers.js b/lib/ace/lib/fixoldbrowsers.js index df0802b4312..1d61b12f3f6 100644 --- a/lib/ace/lib/fixoldbrowsers.js +++ b/lib/ace/lib/fixoldbrowsers.js @@ -13,9 +13,6 @@ define(function(require, exports, module) { "use strict"; -require("./regexp"); -require("./es5-shim"); - /*global Element*/ if (typeof Element != "undefined" && !Element.prototype.remove) { Object.defineProperty(Element.prototype, "remove", { diff --git a/lib/ace/lib/regexp.js b/lib/ace/lib/regexp.js deleted file mode 100644 index 369f74fc203..00000000000 --- a/lib/ace/lib/regexp.js +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Based on code from: - * - * XRegExp 1.5.0 - * (c) 2007-2010 Steven Levithan - * MIT License - * - * Provides an augmented, extensible, cross-browser implementation of regular expressions, - * including support for additional syntax, flags, and methods - */ - -define(function(require, exports, module) { -"use strict"; - - //--------------------------------- - // Private variables - //--------------------------------- - - var real = { - exec: RegExp.prototype.exec, - test: RegExp.prototype.test, - match: String.prototype.match, - replace: String.prototype.replace, - split: String.prototype.split - }, - compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups - compliantLastIndexIncrement = function () { - var x = /^/g; - real.test.call(x, ""); - return !x.lastIndex; - }(); - - if (compliantLastIndexIncrement && compliantExecNpcg) - return; - - //--------------------------------- - // Overriden native methods - //--------------------------------- - - // Adds named capture support (with backreferences returned as `result.name`), and fixes two - // cross-browser issues per ES3: - // - Captured values for nonparticipating capturing groups should be returned as `undefined`, - // rather than the empty string. - // - `lastIndex` should not be incremented after zero-length matches. - RegExp.prototype.exec = function (str) { - var match = real.exec.apply(this, arguments), - name, r2; - if ( typeof(str) == 'string' && match) { - // Fix browsers whose `exec` methods don't consistently return `undefined` for - // nonparticipating capturing groups - if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) { - r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", "")); - // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed - // matching due to characters outside the match - real.replace.call(str.slice(match.index), r2, function () { - for (var i = 1; i < arguments.length - 2; i++) { - if (arguments[i] === undefined) - match[i] = undefined; - } - }); - } - // Attach named capture properties - if (this._xregexp && this._xregexp.captureNames) { - for (var i = 1; i < match.length; i++) { - name = this._xregexp.captureNames[i - 1]; - if (name) - match[name] = match[i]; - } - } - // Fix browsers that increment `lastIndex` after zero-length matches - if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index)) - this.lastIndex--; - } - return match; - }; - - // Don't override `test` if it won't change anything - if (!compliantLastIndexIncrement) { - // Fix browser bug in native method - RegExp.prototype.test = function (str) { - // Use the native `exec` to skip some processing overhead, even though the overriden - // `exec` would take care of the `lastIndex` fix - var match = real.exec.call(this, str); - // Fix browsers that increment `lastIndex` after zero-length matches - if (match && this.global && !match[0].length && (this.lastIndex > match.index)) - this.lastIndex--; - return !!match; - }; - } - - //--------------------------------- - // Private helper functions - //--------------------------------- - - function getNativeFlags (regex) { - return (regex.global ? "g" : "") + - (regex.ignoreCase ? "i" : "") + - (regex.multiline ? "m" : "") + - (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3 - (regex.sticky ? "y" : ""); - } - - function indexOf (array, item, from) { - if (Array.prototype.indexOf) // Use the native array method if available - return array.indexOf(item, from); - for (var i = from || 0; i < array.length; i++) { - if (array[i] === item) - return i; - } - return -1; - } - -}); diff --git a/lib/ace/worker/worker.js b/lib/ace/worker/worker.js index 1ce9362befe..e4ac2023079 100644 --- a/lib/ace/worker/worker.js +++ b/lib/ace/worker/worker.js @@ -209,7 +209,6 @@ window.onmessage = function(e) { } else if (msg.init) { window.initBaseUrls(msg.tlns); - require("ace/lib/es5-shim"); sender = window.sender = window.initSender(); var clazz = require(msg.module)[msg.classname]; main = window.main = new clazz(sender); From 3aef3b0645254b81f72838c575ce8ed838b4e5d4 Mon Sep 17 00:00:00 2001 From: skacurt Date: Mon, 4 May 2020 00:42:29 +0300 Subject: [PATCH 0341/1293] [vbscript] ignore comments while looking for statement body --- lib/ace/mode/folding/vbscript.js | 6 +++--- lib/ace/mode/folding/vbscript_test.js | 6 +++--- lib/ace/mode/vbscript.js | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/ace/mode/folding/vbscript.js b/lib/ace/mode/folding/vbscript.js index c43a08d273d..c614f61ea46 100644 --- a/lib/ace/mode/folding/vbscript.js +++ b/lib/ace/mode/folding/vbscript.js @@ -81,7 +81,7 @@ oop.inherits(FoldMode, BaseFoldMode); if (keyword && this.indentKeywords.hasOwnProperty(keyword)) { if (this.indentKeywords[keyword] == -1) return ""; - if (keyword == "if" && !/then\s*$/i.test(line)) + if (keyword == "if" && !/then\s*('|$)/i.test(line)) return ""; return "start"; } @@ -132,7 +132,7 @@ oop.inherits(FoldMode, BaseFoldMode); case "while": case "with": var line = session.getLine(row); - var singleLineCondition = /^\s*(If)\s+(.)*\s+Then\s+(\S)+/i.test(line); + var singleLineCondition = /^\s*If\s+.*\s+Then(?!')\s+(?!')\S/i.test(line); if (singleLineCondition) return; var checkToken = new RegExp("^\\s*"+ modifiers + val, "i"); @@ -205,7 +205,7 @@ oop.inherits(FoldMode, BaseFoldMode); case "while": case "with": var line = session.getLine(stream.getCurrentTokenRow()); - var singleLineCondition = /^\s*(If)\s+(.)*\s+Then\s+(\S)+/i.test(line); + var singleLineCondition = /^\s*If\s+.*\s+Then(?!')\s+(?!')\S/i.test(line); if (singleLineCondition) { level = 0; ignore = true; diff --git a/lib/ace/mode/folding/vbscript_test.js b/lib/ace/mode/folding/vbscript_test.js index 4739ba9627c..abde0d415fa 100644 --- a/lib/ace/mode/folding/vbscript_test.js +++ b/lib/ace/mode/folding/vbscript_test.js @@ -48,7 +48,7 @@ module.exports = { 'Sub MakeHelloWorldFile (FileName)', ' \'Create a new file in C: drive or overwrite existing file', ' Set FSO = CreateObject("Scripting.FileSystemObject")', - ' If FSO.FileExists(FileName) Then ', + ' If FSO.FileExists(FileName) Then \'comment ', ' Answer = MsgBox ("File " & FileName & " exists ... OK to overwrite?", vbOKCancel)', ' \'If button selected is not OK, then quit now', ' \'vbOK is a language constant', @@ -79,8 +79,8 @@ module.exports = { assert.equal(session.getFoldWidget(9), ""); assert.range(session.getFoldWidgetRange(0), 0, 33, 18, 46); - assert.range(session.getFoldWidgetRange(3), 3, 36, 11, 37); - assert.range(session.getFoldWidgetRange(12), 3, 36, 11, 37); + assert.range(session.getFoldWidgetRange(3), 3, 45, 11, 37); + assert.range(session.getFoldWidgetRange(12), 3, 45, 11, 37); } }; diff --git a/lib/ace/mode/vbscript.js b/lib/ace/mode/vbscript.js index 9cfb247e117..4afa3f0432f 100644 --- a/lib/ace/mode/vbscript.js +++ b/lib/ace/mode/vbscript.js @@ -94,7 +94,7 @@ oop.inherits(Mode, TextMode); } break; case "if": - var singleLineCondition = /^\s*(If)\s+(.)*\s+Then\s+(\S)+/i.test(line); + var singleLineCondition = /^\s*If\s+.*\s+Then(?!')\s+(?!')\S/i.test(line); if (!singleLineCondition) level += indentKeywords[val]; break; From 13e486b71fbdd2a4b40544e4ac4cbf159ac0fadb Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 2 May 2020 19:13:13 +0400 Subject: [PATCH 0342/1293] fix touch selection not working with scrollMargin --- lib/ace/mouse/mouse_handler_test.js | 42 +++++++++++++++++++++++------ lib/ace/mouse/touch_handler.js | 10 ++++--- lib/ace/test/all_browser.js | 1 + lib/ace/test/mockdom.js | 13 ++++++--- lib/ace/test/mockdom_test.js | 33 ++++++++++++++++------- 5 files changed, 75 insertions(+), 24 deletions(-) diff --git a/lib/ace/mouse/mouse_handler_test.js b/lib/ace/mouse/mouse_handler_test.js index 78f1ac61ead..39538fff562 100644 --- a/lib/ace/mouse/mouse_handler_test.js +++ b/lib/ace/mouse/mouse_handler_test.js @@ -52,11 +52,19 @@ var MouseEvent = function(type, opts){ opts.button || 0, opts.relatedTarget); return e; }; -var sendTouchEvent = function(type, opts, editor) { +function sendTouchEvent(type, opts, editor) { var e = new window.Event("touch" + type, {bubbles: true, cancelable: true}); Object.defineProperties(e, Object.getOwnPropertyDescriptors(opts)); editor.container.dispatchEvent(e); -}; +} + +function touchPos(row, column) { + var pos = editor.renderer.textToScreenCoordinates(row, column); + var h = editor.renderer.lineHeight / 2; + return {clientX: pos.pageX, clientY: pos.pageY + h}; +} + +var editor; module.exports = { @@ -69,6 +77,7 @@ module.exports = { this.editor.container.style.left = "50px"; this.editor.container.style.top = "10px"; document.body.appendChild(this.editor.container); + editor = this.editor; next(); }, @@ -176,12 +185,6 @@ module.exports = { window.editor = editor; window.sendTouchEvent = sendTouchEvent; - function touchPos(row, column) { - var pos = editor.renderer.textToScreenCoordinates(row, column); - var h = editor.renderer.lineHeight / 2; - return {clientX: pos.pageX, clientY: pos.pageY + h}; - } - // single tap moves cursor sendTouchEvent("start", {touches: [touchPos(2, 1)]}, editor); sendTouchEvent("end", {touches: [touchPos(2, 1)]}, editor); @@ -239,6 +242,29 @@ module.exports = { }, 2); }, + "test: touch selection with scrollMargin" : function() { + editor.renderer.setScrollMargin(50, 50, 0, 15); + editor.setValue("Juhu Kinners!"); + editor.renderer.$loop._flush(); + + var pos = editor.renderer.textToScreenCoordinates(0, 0); + + assert.equal(pos.pageY - editor.container.getBoundingClientRect().top, 50); + + sendTouchEvent("start", {touches: [touchPos(0, 0)]}, editor); + sendTouchEvent("move", {touches: [touchPos(0, 5)]}, editor); + editor.renderer.$loop._flush(); + sendTouchEvent("end", {touches: [touchPos(0, 5)]}, editor); + editor.renderer.$loop._flush(); + + sendTouchEvent("start", {touches: [touchPos(0, 12)]}, editor); + sendTouchEvent("move", {touches: [touchPos(0, 8)]}, editor); + editor.renderer.$loop._flush(); + sendTouchEvent("end", {touches: [touchPos(0, 8)]}, editor); + + assert.equal(editor.getSelectedText(), "Kin"); + }, + tearDown : function() { document.body.removeChild(this.editor.container); } diff --git a/lib/ace/mouse/touch_handler.js b/lib/ace/mouse/touch_handler.js index 5f1eb07c7c0..d533b998484 100644 --- a/lib/ace/mouse/touch_handler.js +++ b/lib/ace/mouse/touch_handler.js @@ -206,6 +206,8 @@ exports.addTouchListeners = function(el, editor) { var cursorPos = editor.renderer.$cursorLayer.getPixelPosition(cursor, true); var anchorPos = editor.renderer.$cursorLayer.getPixelPosition(anchor, true); var rect = editor.renderer.scroller.getBoundingClientRect(); + var offsetTop = editor.renderer.layerConfig.offset; + var offsetLeft = editor.renderer.scrollLeft; var weightedDistance = function(x, y) { x = x / w; y = y / h - 0.75; @@ -218,12 +220,12 @@ exports.addTouchListeners = function(el, editor) { } var diff1 = weightedDistance( - e.clientX - rect.left - cursorPos.left, - e.clientY - rect.top - cursorPos.top + e.clientX - rect.left - cursorPos.left + offsetLeft, + e.clientY - rect.top - cursorPos.top + offsetTop ); var diff2 = weightedDistance( - e.clientX - rect.left - anchorPos.left, - e.clientY - rect.top - anchorPos.top + e.clientX - rect.left - anchorPos.left + offsetLeft, + e.clientY - rect.top - anchorPos.top + offsetTop ); if (diff1 < 3.5 && diff2 < 3.5) mode = diff1 > diff2 ? "cursor" : "anchor"; diff --git a/lib/ace/test/all_browser.js b/lib/ace/test/all_browser.js index b76abc8c29c..7ee95c19a35 100644 --- a/lib/ace/test/all_browser.js +++ b/lib/ace/test/all_browser.js @@ -66,6 +66,7 @@ var testNames = [ "ace/snippets_test", "ace/token_iterator_test", "ace/tokenizer_test", + "ace/test/mockdom_test", "ace/undomanager_test", "ace/virtual_renderer_test" ]; diff --git a/lib/ace/test/mockdom.js b/lib/ace/test/mockdom.js index 39d27094fdf..9c89ab5a4d1 100644 --- a/lib/ace/test/mockdom.js +++ b/lib/ace/test/mockdom.js @@ -330,8 +330,8 @@ function Node(name) { else if (this.parentNode) { var rect = this.parentNode.getBoundingClientRect(); - left = parseCssLength(this.style.top || "0", rect.width); - top = parseCssLength(this.style.left || "0", rect.height); + left = parseCssLength(this.style.left || "0", rect.width); + top = parseCssLength(this.style.top || "0", rect.height); var right = parseCssLength(this.style.right || "0", rect.width); var bottom = parseCssLength(this.style.bottom || "0", rect.width); @@ -626,7 +626,14 @@ function TextNode(value) { }); }).call(TextNode.prototype); -var window = {}; +var window = { + get innerHeight() { + return WINDOW_HEIGHT; + }, + get innerWidth() { + return WINDOW_WIDTH; + } +}; window.navigator = {userAgent: "node", platform: "win", appName: ""}; window.HTMLDocument = window.XMLDocument = window.Document = function() { var document = this; diff --git a/lib/ace/test/mockdom_test.js b/lib/ace/test/mockdom_test.js index 2b41e38fb0f..8c4a1751db5 100644 --- a/lib/ace/test/mockdom_test.js +++ b/lib/ace/test/mockdom_test.js @@ -13,14 +13,22 @@ var assert = require("./assertions"); module.exports = { "test: getBoundingClientRect" : function() { var span = document.createElement("span"); - span.textContent = "xxx"; + span.textContent = "x"; - assert.equal(span.clientWidth, 0); - assert.equal(span.clientHeight, 0); + assert.equal(span.offsetWidth, 0); + assert.equal(span.offsetHeight, 0); document.body.appendChild(span); - assert.equal(span.clientWidth, 6 * 3); - assert.equal(span.clientHeight, 10); + + var w = span.offsetWidth; + var h = span.offsetHeight; + + assert.ok(h != 0); + assert.ok(w != 0); + + span.textContent = "xxx"; + assert.equal(span.offsetWidth, w * 3); + assert.equal(span.offsetHeight, h); var div = document.createElement("div"); document.body.appendChild(div); @@ -28,18 +36,25 @@ module.exports = { div.style.top = "20px"; div.style.left = "40px"; div.style.bottom = "20px"; - div.style.right = "12.5%"; + div.style.right = "12%"; var rect = div.getBoundingClientRect(); - assert.deepEqual(rect, { top: 40, left: 20, width: 876, height: 708, right: 896, bottom: 748 }); + var parentWidth = div.parentElement.clientWidth; + assert.ok(parentWidth != 0); + assert.equal(rect.top, 20); + assert.equal(rect.left, 40); + assert.equal(rect.width, parentWidth * (1 - 0.12) - 40); + assert.equal(rect.height, window.innerHeight - 40); + assert.equal(rect.right, parentWidth * (1 - 0.12)); + assert.equal(rect.bottom, window.innerHeight - 20); div.style.width = "40px"; rect = div.getBoundingClientRect(); assert.equal(rect.width, 40); - assert.equal(rect.right, 60); + assert.equal(rect.right, 80); div.style.height = "150%"; rect = div.getBoundingClientRect(); - assert.equal(rect.height, 1152); + assert.equal(rect.height, window.innerHeight * 1.5); }, "test: eventListener" : function() { From 8f4443be770b19cdc485e6b4be15b059895b9bff Mon Sep 17 00:00:00 2001 From: mkslanc Date: Mon, 4 May 2020 21:38:03 +0300 Subject: [PATCH 0343/1293] ruby mode token-based folding/matching; highlight updates --- lib/ace/mode/folding/ruby.js | 293 +++++++++++++++ lib/ace/mode/folding/ruby_test.js | 281 +++++++++++++++ lib/ace/mode/ruby.js | 23 +- lib/ace/mode/ruby_highlight_rules.js | 520 +++++++++++++++++++++------ lib/ace/mode/ruby_test.js | 138 ++++++- 5 files changed, 1141 insertions(+), 114 deletions(-) create mode 100644 lib/ace/mode/folding/ruby.js create mode 100644 lib/ace/mode/folding/ruby_test.js diff --git a/lib/ace/mode/folding/ruby.js b/lib/ace/mode/folding/ruby.js new file mode 100644 index 00000000000..1ceaeb2cfb4 --- /dev/null +++ b/lib/ace/mode/folding/ruby.js @@ -0,0 +1,293 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function (require, exports, module) { +"use strict"; + +var oop = require("../../lib/oop"); +var BaseFoldMode = require("./fold_mode").FoldMode; +var Range = require("../../range").Range; +var TokenIterator = require("../../token_iterator").TokenIterator; + + +var FoldMode = exports.FoldMode = function () { +}; + +oop.inherits(FoldMode, BaseFoldMode); + +(function () { + this.indentKeywords = { + "class": 1, + "def": 1, + "module": 1, + "do": 1, + "unless": 1, + "if": 1, + "while": 1, + "for": 1, + "until": 1, + "begin": 1, + "else": 0, + "elsif": 0, + "rescue": 0, + "ensure": 0, + "when": 0, + "end": -1, + "case": 1, + "=begin": 1, + "=end": -1 + }; + + this.foldingStartMarker = /(?:\s|^)(def|do|while|class|unless|module|if|for|until|begin|else|elsif|case|rescue|ensure|when)\b|({\s*$)|(=begin)/; + this.foldingStopMarker = /(=end(?=$|\s.*$))|(^\s*})|\b(end)\b/; + + this.getFoldWidget = function (session, foldStyle, row) { + var line = session.getLine(row); + var isStart = this.foldingStartMarker.test(line); + var isEnd = this.foldingStopMarker.test(line); + + if (isStart && !isEnd) { + var match = line.match(this.foldingStartMarker); + if (match[1]) { + if (match[1] == "if" || match[1] == "else" || match[1] == "while" || match[1] == "until" || match[1] == "unless") { + if (match[1] == "else" && /^\s*else\s*$/.test(line) === false) { + return; + } + if (/^\s*(?:if|else|while|until|unless)\s*/.test(line) === false) { + return; + } + } + + if (match[1] == "when") { + if (/\sthen\s/.test(line) === true) { + return; + } + } + if (session.getTokenAt(row, match.index + 2).type === "keyword") + return "start"; + } else if (match[3]) { + if (session.getTokenAt(row, match.index + 1).type === "comment.multiline") + return "start"; + } else { + return "start"; + } + } + if (foldStyle != "markbeginend" || !isEnd || isStart && isEnd) + return ""; + + var match = line.match(this.foldingStopMarker); + if (match[3] === "end") { + if (session.getTokenAt(row, match.index + 1).type === "keyword") + return "end"; + } else if (match[1]) { + if (session.getTokenAt(row, match.index + 1).type === "comment.multiline") + return "end"; + } else + return "end"; + }; + + this.getFoldWidgetRange = function (session, foldStyle, row) { + var line = session.doc.getLine(row); + var match = this.foldingStartMarker.exec(line); + if (match) { + if (match[1] || match[3]) + return this.rubyBlock(session, row, match.index + 2); + + return this.openingBracketBlock(session, "{", row, match.index); + } + + var match = this.foldingStopMarker.exec(line); + if (match) { + if (match[3] === "end") { + if (session.getTokenAt(row, match.index + 1).type === "keyword") + return this.rubyBlock(session, row, match.index + 1); + } + + if (match[1] === "=end") { + if (session.getTokenAt(row, match.index + 1).type === "comment.multiline") + return this.rubyBlock(session, row, match.index + 1); + } + + return this.closingBracketBlock(session, "}", row, match.index + match[0].length); + } + }; + + this.rubyBlock = function (session, row, column, tokenRange) { + var stream = new TokenIterator(session, row, column); + + var token = stream.getCurrentToken(); + if (!token || (token.type != "keyword" && token.type != "comment.multiline")) + return; + + var val = token.value; + var line = session.getLine(row); + switch (token.value) { + case "if": + case "unless": + case "while": + case "until": + var checkToken = new RegExp("^\\s*" + token.value); + if (!checkToken.test(line)) { + return; + } + var dir = this.indentKeywords[val]; + break; + case "when": + if (/\sthen\s/.test(line)) { + return; + } + case "elsif": + case "rescue": + case "ensure": + var dir = 1; + break; + case "else": + var checkToken = new RegExp("^\\s*" + token.value + "\\s*$"); + if (!checkToken.test(line)) { + return; + } + var dir = 1; + break; + default: + var dir = this.indentKeywords[val]; + break; + } + + var stack = [val]; + if (!dir) + return; + + var startColumn = dir === -1 ? session.getLine(row - 1).length : session.getLine(row).length; + var startRow = row; + var ranges = []; + ranges.push(stream.getCurrentTokenRange()); + + stream.step = dir === -1 ? stream.stepBackward : stream.stepForward; + if (token.type == "comment.multiline") { + while (token = stream.step()) { + if (token.type !== "comment.multiline") + continue; + if (dir == 1) { + startColumn = 6; + if (token.value == "=end") { + break; + } + } else { + if (token.value == "=begin") { + break; + } + } + } + } else { + while (token = stream.step()) { + var ignore = false; + if (token.type !== "keyword") + continue; + var level = dir * this.indentKeywords[token.value]; + line = session.getLine(stream.getCurrentTokenRow()); + switch (token.value) { + case "do": + for (var i = stream.$tokenIndex - 1; i >= 0; i--) { + var prevToken = stream.$rowTokens[i]; + if (prevToken && (prevToken.value == "while" || prevToken.value == "until" || prevToken.value == "for")) { + level = 0; + break; + } + } + break; + case "else": + var checkToken = new RegExp("^\\s*" + token.value + "\\s*$"); + if (!checkToken.test(line) || val == "case") { + level = 0; + ignore = true; + } + break; + case "if": + case "unless": + case "while": + case "until": + var checkToken = new RegExp("^\\s*" + token.value); + if (!checkToken.test(line)) { + level = 0; + ignore = true; + } + break; + case "when": + if (/\sthen\s/.test(line) || val == "case") { + level = 0; + ignore = true; + } + break; + } + + if (level > 0) { + stack.unshift(token.value); + } else if (level <= 0 && ignore === false) { + stack.shift(); + if (!stack.length) { + if ((val == "while" || val == "until" || val == "for") && token.value != "do") { + break; + } + if (token.value == "do" && dir == -1 && level != 0) + break; + if (token.value != "do") + break; + } + + if (level === 0) { + stack.unshift(token.value); + } + } + } + } + + if (!token) + return null; + + if (tokenRange) { + ranges.push(stream.getCurrentTokenRange()); + return ranges; + } + + var row = stream.getCurrentTokenRow(); + if (dir === -1) { + if (token.type === "comment.multiline") { + var endColumn = 6; + } else { + var endColumn = session.getLine(row).length; + } + return new Range(row, endColumn, startRow - 1, startColumn); + } else + return new Range(startRow, startColumn, row - 1, session.getLine(row - 1).length); + }; + +}).call(FoldMode.prototype); + +}); diff --git a/lib/ace/mode/folding/ruby_test.js b/lib/ace/mode/folding/ruby_test.js new file mode 100644 index 00000000000..393fbc10773 --- /dev/null +++ b/lib/ace/mode/folding/ruby_test.js @@ -0,0 +1,281 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") + require("amd-loader"); + +define(function(require, exports, module) { +"use strict"; + +var RubyMode = require("../ruby").Mode; +var EditSession = require("../../edit_session").EditSession; +var assert = require("../../test/assertions"); + +module.exports = { + setUp : function() { + this.mode = new RubyMode(); + }, + + "test: opening/ending tags matching/folding": function() { + var session = new EditSession([ + 'def Name(n)', + ' if i == 0', + ' ...', + ' else', + ' ...', + ' end', + 'end' + ]); + + session.setFoldStyle("markbeginend"); + session.setMode(this.mode); + + var ranges = this.mode.getMatching(session, 0, 0); + assert.range(ranges[0], 0, 0, 0, 3); + assert.range(ranges[1], 6, 0, 6, 3); + + ranges = this.mode.getMatching(session, 6, 1); + assert.range(ranges[1], 0, 0, 0, 3); + assert.range(ranges[0], 6, 0, 6, 3); + + ranges = this.mode.getMatching(session, 1, 4); + assert.range(ranges[0], 1, 3, 1, 5); + assert.range(ranges[1], 3, 3, 3, 7); + + ranges = this.mode.getMatching(session, 5, 4); + assert.range(ranges[1], 3, 3, 3, 7); + assert.range(ranges[0], 5, 3, 5, 6); + + assert.equal(session.getFoldWidget(0), "start"); + assert.equal(session.getFoldWidget(1), "start"); + assert.equal(session.getFoldWidget(2), ""); + assert.equal(session.getFoldWidget(3), "start"); + assert.equal(session.getFoldWidget(4), ""); + assert.equal(session.getFoldWidget(5), "end"); + assert.equal(session.getFoldWidget(6), "end"); + + assert.range(session.getFoldWidgetRange(0), 0, 11, 5, 6); + assert.equal(session.getFoldWidgetRange(2), null); + assert.equal(session.getFoldWidgetRange(4), null); + assert.range(session.getFoldWidgetRange(5), 3, 7, 4, 9); + }, + + "test: if/unless/while/until used as modifier shouldn't have matching tag and start/end fold": function() { + var session = new EditSession([ + 'if i == 0', + ' a += 1 if a.zero?', + 'else', + ' a += 1 unless a.zero?', + 'end' + ]); + + session.setMode(this.mode); + }, + + "test: brackets folding": function() { + var session = new EditSession([ + 'def to_json(*a)', + '{', + '"json_class" => self.class.name, # = "Range"', + '"data" => [ first, last, exclude_end? ]', + '}.to_json(*a)', + 'end' + ]); + + session.setFoldStyle("markbeginend"); + session.setMode(this.mode); + + assert.equal(session.getFoldWidget(0), "start"); + assert.equal(session.getFoldWidget(1), "start"); + assert.equal(session.getFoldWidget(2), ""); + assert.equal(session.getFoldWidget(4), "end"); + assert.equal(session.getFoldWidget(5), "end"); + + assert.range(session.getFoldWidgetRange(1), 1, 1, 4, 0); + assert.range(session.getFoldWidgetRange(4), 1, 1, 4, 0); + }, + + "test: multiline comments matching and folding": function() { + var session = new EditSession([ + '=begin', + 'text line 1', + 'text line 2', + 'text line 3', + '=end' + ]); + + session.setFoldStyle("markbeginend"); + session.setMode(this.mode); + + var ranges = this.mode.getMatching(session, 0, 2); + assert.range(ranges[0], 0, 0, 0, 6); + assert.range(ranges[1], 4, 0, 4, 4); + + ranges = this.mode.getMatching(session, 4, 2); + assert.range(ranges[1], 0, 0, 0, 6); + assert.range(ranges[0], 4, 0, 4, 4); + + assert.equal(session.getFoldWidget(0), "start"); + assert.equal(session.getFoldWidget(1), ""); + assert.equal(session.getFoldWidget(4), "end"); + + assert.range(session.getFoldWidgetRange(0), 0,6,3,11); + assert.range(session.getFoldWidgetRange(4), 0,6,3,11); + }, + + "test: `case` with multiline `when` expressions matchings and foldings": function() { + var session = new EditSession([ + 'case', + 'when a == 1', + ' puts "a is one"', + 'when a == 2', + ' puts "a is two"', + 'else', + ' puts "a is not one or two"', + 'end' + ]); + + session.setFoldStyle("markbeginend"); + session.setMode(this.mode); + + var ranges = this.mode.getMatching(session, 0, 2); + + //`case` should always be closed with `end` + assert.range(ranges[0], 0, 0, 0, 4); + assert.range(ranges[1], 7, 0, 7, 3); + + assert.equal(session.getFoldWidget(0), "start"); + assert.range(session.getFoldWidgetRange(0), 0,4,6,27); + + //`end` should close last block + ranges = this.mode.getMatching(session, 7, 2); + assert.range(ranges[0], 7, 0, 7, 3); + assert.range(ranges[1], 5, 0, 5, 4); + + assert.equal(session.getFoldWidget(7), "end"); + assert.range(session.getFoldWidgetRange(7), 5,4,6,27); + + //`else` should be closed with `end` + ranges = this.mode.getMatching(session, 5, 2); + assert.range(ranges[1], 7, 0, 7, 3); + assert.range(ranges[0], 5, 0, 5, 4); + + assert.equal(session.getFoldWidget(5), "start"); + assert.range(session.getFoldWidgetRange(5), 5,4,6,27); + + //first `when` should close by next `when` + ranges = this.mode.getMatching(session, 1, 2); + assert.range(ranges[0], 1, 0, 1, 4); + assert.range(ranges[1], 3, 0, 3, 4); + + assert.equal(session.getFoldWidget(1), "start"); + assert.range(session.getFoldWidgetRange(1), 1,11,2,16); + }, + + "test: `case` with single line `when` expressions matchings and foldings": function() { + var session = new EditSession([ + 'kind = case year', + ' when 1850..1889 then "Blues"', + ' when 1890..1909 then "Ragtime"', + ' when 1910..1929 then "New Orleans Jazz"', + ' when 1930..1939 then "Swing"', + ' when 1940..1950 then "Bebop"', + ' else "Jazz"', + ' end' + ]); + + session.setMode(this.mode); + + var ranges = this.mode.getMatching(session, 0, 9); + + //`case` should always be closed with `end` + assert.range(ranges[0], 0, 7, 0, 11); + assert.range(ranges[1], 7, 7, 7, 10); + + //`end` should close `case` + ranges = this.mode.getMatching(session, 7, 9); + assert.range(ranges[1], 0, 7, 0, 11); + assert.range(ranges[0], 7, 7, 7, 10); + + //`when` shouldn't have any matchings in single line form + ranges = this.mode.getMatching(session, 1, 8); + assert.equal(ranges, undefined); + + assert.equal(session.getFoldWidget(1), undefined); + assert.equal(session.getFoldWidgetRange(1), null); + + //`else` shouldn't have any matchings in single line form + ranges = this.mode.getMatching(session, 6, 8); + assert.equal(ranges, undefined); + + assert.equal(session.getFoldWidget(6), undefined); + assert.equal(session.getFoldWidgetRange(6), null); + }, + + "test: loops `while` and `until` including `do` keyword and `do` loops should properly highlight": function() { + var session = new EditSession([ + 'while a < 10 do', + ' p a', + ' a += 1', + ' 0.upto 5 do |value|', + ' selected << value if value==2...value==2', + ' end', + 'end' + ]); + + session.setMode(this.mode); + + var ranges = this.mode.getMatching(session, 0, 3); + assert.range(ranges[0], 0, 0, 0, 5); + assert.range(ranges[1], 6, 0, 6, 3); + + ranges = this.mode.getMatching(session, 6, 1); + assert.range(ranges[1], 0, 0, 0, 5); + assert.range(ranges[0], 6, 0, 6, 3); + + //for `do` keyword we also returns proper `end` from `while` loop + ranges = this.mode.getMatching(session, 0, 14); + assert.range(ranges[0], 0, 13, 0, 15); + assert.range(ranges[1], 6, 0, 6, 3); + + ranges = this.mode.getMatching(session, 3, 13); + assert.range(ranges[0], 3, 12, 3, 14); + assert.range(ranges[1], 5, 3, 5, 6); + + ranges = this.mode.getMatching(session, 5, 4); + assert.range(ranges[1], 3, 12, 3, 14); + assert.range(ranges[0], 5, 3, 5, 6); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) + require("asyncjs").test.testcase(module.exports).exec(); diff --git a/lib/ace/mode/ruby.js b/lib/ace/mode/ruby.js index 7a0ac99cde0..5a0c1f51304 100644 --- a/lib/ace/mode/ruby.js +++ b/lib/ace/mode/ruby.js @@ -37,13 +37,14 @@ var RubyHighlightRules = require("./ruby_highlight_rules").RubyHighlightRules; var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; var Range = require("../range").Range; var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; -var FoldMode = require("./folding/coffee").FoldMode; +var FoldMode = require("./folding/ruby").FoldMode; var Mode = function() { this.HighlightRules = RubyHighlightRules; this.$outdent = new MatchingBraceOutdent(); this.$behaviour = new CstyleBehaviour(); this.foldingRules = new FoldMode(); + this.indentKeywords = this.foldingRules.indentKeywords; }; oop.inherits(Mode, TextMode); @@ -58,7 +59,7 @@ oop.inherits(Mode, TextMode); var tokenizedLine = this.getTokenizer().getLineTokens(line, state); var tokens = tokenizedLine.tokens; - if (tokens.length && tokens[tokens.length-1].type == "comment") { + if (tokens.length && tokens[tokens.length - 1].type == "comment") { return indent; } @@ -66,7 +67,7 @@ oop.inherits(Mode, TextMode); var match = line.match(/^.*[\{\(\[]\s*$/); var startingClassOrMethod = line.match(/^\s*(class|def|module)\s.*$/); var startingDoBlock = line.match(/.*do(\s*|\s+\|.*\|\s*)$/); - var startingConditional = line.match(/^\s*(if|else|when)\s*/); + var startingConditional = line.match(/^\s*(if|else|when|elsif|unless|while|for|begin|rescue|ensure)\s*/); if (match || startingClassOrMethod || startingDoBlock || startingConditional) { indent += tab; } @@ -76,7 +77,7 @@ oop.inherits(Mode, TextMode); }; this.checkOutdent = function(state, line, input) { - return /^\s+(end|else)$/.test(line + input) || this.$outdent.checkOutdent(line, input); + return /^\s+(end|else|rescue|ensure)$/.test(line + input) || this.$outdent.checkOutdent(line, input); }; this.autoOutdent = function(state, session, row) { @@ -89,10 +90,22 @@ oop.inherits(Mode, TextMode); var tab = session.getTabString(); if (prevIndent.length <= indent.length) { if (indent.slice(-tab.length) == tab) - session.remove(new Range(row, indent.length-tab.length, row, indent.length)); + session.remove(new Range(row, indent.length - tab.length, row, indent.length)); } }; + this.getMatching = function(session, row, column) { + if (row == undefined) { + var pos = session.selection.lead; + column = pos.column; + row = pos.row; + } + + var startToken = session.getTokenAt(row, column); + if (startToken && startToken.value in this.indentKeywords) + return this.foldingRules.rubyBlock(session, row, column, true); + }; + this.$id = "ace/mode/ruby"; this.snippetFileId = "ace/snippets/ruby"; }).call(Mode.prototype); diff --git a/lib/ace/mode/ruby_highlight_rules.js b/lib/ace/mode/ruby_highlight_rules.js index b37becf4e5e..4d6d2b228c3 100644 --- a/lib/ace/mode/ruby_highlight_rules.js +++ b/lib/ace/mode/ruby_highlight_rules.js @@ -60,9 +60,34 @@ var constantNumericHex = exports.constantNumericHex = { regex : "0[xX][0-9a-fA-F](?:[0-9a-fA-F]|_(?=[0-9a-fA-F]))*\\b" }; +var constantNumericBinary = exports.constantNumericBinary = { + token: "constant.numeric", + regex: /\b(0[bB][01](?:[01]|_(?=[01]))*)\b/ +}; + +var constantNumericDecimal = exports.constantNumericDecimal = { + token: "constant.numeric", + regex: /\b(0[dD](?:[1-9](?:[\d]|_(?=[\d]))*|0))\b/ +}; + +var constantNumericOctal = exports.constantNumericDecimal = { + token: "constant.numeric", + regex: /\b(0[oO]?(?:[1-7](?:[0-7]|_(?=[0-7]))*|0))\b/ +}; + +var constantNumericRational = exports.constantNumericRational = { + token: "constant.numeric", //rational + complex + regex: /\b([\d]+(?:[./][\d]+)?ri?)\b/ +}; + +var constantNumericComplex = exports.constantNumericComplex = { + token: "constant.numeric", //simple complex numbers + regex: /\b([\d]i)\b/ +}; + var constantNumericFloat = exports.constantNumericFloat = { - token : "constant.numeric", // float - regex : "[+-]?\\d(?:\\d|_(?=\\d))*(?:(?:\\.\\d(?:\\d|_(?=\\d))*)?(?:[eE][+-]?\\d+)?)?\\b" + token : "constant.numeric", // float + complex + regex : "[+-]?\\d(?:\\d|_(?=\\d))*(?:(?:\\.\\d(?:\\d|_(?=\\d))*)?(?:[eE][+-]?\\d+)?)?i?\\b" }; var instanceVariable = exports.instanceVariable = { @@ -102,18 +127,19 @@ var RubyHighlightRules = function() { "filter_parameter_logging|match|get|post|resources|redirect|scope|assert_routing|" + "translate|localize|extract_locale_from_tld|caches_page|expire_page|caches_action|expire_action|" + "cache|expire_fragment|expire_cache_for|observe|cache_sweeper|" + - "has_many|has_one|belongs_to|has_and_belongs_to_many" + "has_many|has_one|belongs_to|has_and_belongs_to_many|p|warn|refine|using|module_function|extend|alias_method|" + + "private_class_method|remove_method|undef_method" ); var keywords = ( "alias|and|BEGIN|begin|break|case|class|def|defined|do|else|elsif|END|end|ensure|" + "__FILE__|finally|for|gem|if|in|__LINE__|module|next|not|or|private|protected|public|" + - "redo|rescue|retry|return|super|then|undef|unless|until|when|while|yield" + "redo|rescue|retry|return|super|then|undef|unless|until|when|while|yield|__ENCODING__|prepend" ); var buildinConstants = ( "true|TRUE|false|FALSE|nil|NIL|ARGF|ARGV|DATA|ENV|RUBY_PLATFORM|RUBY_RELEASE_DATE|" + - "RUBY_VERSION|STDERR|STDIN|STDOUT|TOPLEVEL_BINDING" + "RUBY_VERSION|STDERR|STDIN|STDOUT|TOPLEVEL_BINDING|RUBY_PATCHLEVEL|RUBY_REVISION|RUBY_COPYRIGHT|RUBY_ENGINE|RUBY_ENGINE_VERSION|RUBY_DESCRIPTION" ); var builtinVariables = ( @@ -129,132 +155,191 @@ var RubyHighlightRules = function() { "invalid.deprecated": "debugger" // TODO is this a remnant from js mode? }, "identifier"); + var escapedChars = "\\\\(?:n(?:[1-7][0-7]{0,2}|0)|[nsrtvfbae'\"\\\\]|c(?:\\\\M-)?.|M-(?:\\\\C-|\\\\c)?.|C-(?:\\\\M-)?.|[0-7]{3}|x[\\da-fA-F]{2}|u[\\da-fA-F]{4}|u{[\\da-fA-F]{1,6}(?:\\s[\\da-fA-F]{1,6})*})"; + + var closeParen = { + "(": ")", + "[": "]", + "{": "}", + "<": ">", + "^": "^", + "|": "|", + "%": "%" + }; // regexp must not have capturing parentheses. Use (?:) instead. // regexps are ordered -> the first match is used this.$rules = { - "start" : [ + "start": [ { - token : "comment", - regex : "#.*$" + token: "comment", + regex: "#.*$" }, { - token : "comment", // multi line comment - regex : "^=begin(?:$|\\s.*$)", - next : "comment" + token: "comment.multiline", // multi line comment + regex: "^=begin(?=$|\\s.*$)", + next: "comment" }, { - token : "string.regexp", - regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)" + token: "string.regexp", + regex: /[/](?=.*\/)/, + next: "regex" }, [{ - regex: "[{}]", onMatch: function(val, state, stack) { - this.next = val == "{" ? this.nextState : ""; - if (val == "{" && stack.length) { - stack.unshift("start", state); - return "paren.lparen"; - } - if (val == "}" && stack.length) { - stack.shift(); - this.next = stack.shift(); - if (this.next.indexOf("string") != -1) - return "paren.end"; - } - return val == "{" ? "paren.lparen" : "paren.rparen"; - }, - nextState: "start" - }, { - token : "string.start", - regex : /"/, - push : [{ - token : "constant.language.escape", - regex : /\\(?:[nsrtvfbae'"\\]|c.|C-.|M-.(?:\\C-.)?|[0-7]{3}|x[\da-fA-F]{2}|u[\da-fA-F]{4})/ + token: ["constant.other.symbol.ruby", "string.start"], + regex: /(:)?(")/, + push: [{ + token: "constant.language.escape", + regex: escapedChars }, { - token : "paren.start", - regex : /#{/, - push : "start" + token: "paren.start", + regex: /#{/, + push: "start" }, { - token : "string.end", - regex : /"/, - next : "pop" + token: "string.end", + regex: /"/, + next: "pop" }, { defaultToken: "string" }] }, { - token : "string.start", - regex : /`/, - push : [{ - token : "constant.language.escape", - regex : /\\(?:[nsrtvfbae'"\\]|c.|C-.|M-.(?:\\C-.)?|[0-7]{3}|x[\da-fA-F]{2}|u[\da-fA-F]{4})/ + token: "string.start", + regex: /`/, + push: [{ + token: "constant.language.escape", + regex: escapedChars }, { - token : "paren.start", - regex : /#{/, - push : "start" + token: "paren.start", + regex: /#{/, + push: "start" }, { - token : "string.end", - regex : /`/, - next : "pop" + token: "string.end", + regex: /`/, + next: "pop" }, { defaultToken: "string" }] }, { - token : "string.start", - regex : /'/, - push : [{ - token : "constant.language.escape", - regex : /\\['\\]/ - }, { - token : "string.end", - regex : /'/, - next : "pop" + token: ["constant.other.symbol.ruby", "string.start"], + regex: /(:)?(')/, + push: [{ + token: "constant.language.escape", + regex: /\\['\\]/ + }, { + token: "string.end", + regex: /'/, + next: "pop" }, { defaultToken: "string" }] + }, { + token: "string.start",//doesn't see any differences between strings and array of strings in highlighting + regex: /%[qwx]([(\[<{^|%])/, onMatch: function (val, state, stack) { + if (stack.length) + stack = []; + var paren = val[val.length - 1]; + stack.unshift(paren, state); + this.next = "qStateWithoutInterpolation"; + return this.token; + } + }, { + token: "string.start", //doesn't see any differences between strings and array of strings in highlighting + regex: /%[QWX]?([(\[<{^|%])/, onMatch: function (val, state, stack) { + if (stack.length) + stack = []; + var paren = val[val.length - 1]; + stack.unshift(paren, state); + this.next = "qStateWithInterpolation"; + return this.token; + } + }, { + token: "constant.other.symbol.ruby", //doesn't see any differences between symbols and array of symbols in highlighting + regex: /%[si]([(\[<{^|%])/, onMatch: function (val, state, stack) { + if (stack.length) + stack = []; + var paren = val[val.length - 1]; + stack.unshift(paren, state); + this.next = "sStateWithoutInterpolation"; + return this.token; + } + }, { + token: "constant.other.symbol.ruby", //doesn't see any differences between symbols and array of symbols in highlighting + regex: /%[SI]([(\[<{^|%])/, onMatch: function (val, state, stack) { + if (stack.length) + stack = []; + var paren = val[val.length - 1]; + stack.unshift(paren, state); + this.next = "sStateWithInterpolation"; + return this.token; + } + }, { + token: "string.regexp", + regex: /%[r]([(\[<{^|%])/, onMatch: function (val, state, stack) { + if (stack.length) + stack = []; + var paren = val[val.length - 1]; + stack.unshift(paren, state); + this.next = "rState"; + return this.token; + } }], - // TODO: add support for %[QqxWwrs][{[(] { - token : "text", // namespaces aren't symbols - regex : "::" + token: "punctuation", // namespaces aren't symbols + regex: "::" + }, { + token: "variable.instance", // instance variable + regex: "@{1,2}[a-zA-Z_\\d]+" }, { - token : "variable.instance", // instance variable - regex : "@{1,2}[a-zA-Z_\\d]+" + token: "variable.global", // global variable + regex: "[$][a-zA-Z_\\d]+" }, { - token : "support.class", // class name - regex : "[A-Z][a-zA-Z_\\d]+" + token: "support.class", // class name + regex: "[A-Z][a-zA-Z_\\d]*" + }, { + token: ["punctuation.operator", "support.function"], + regex: /(\.)([a-zA-Z_\d]+)(?=\()/ + }, { + token: ["punctuation.operator", "identifier"], + regex: /(\.)([a-zA-Z_][a-zA-Z_\d]*)/ + }, { + token: "punctuation.operator", + regex: /\?(?=.+:)/ }, + constantNumericRational, + constantNumericComplex, constantOtherSymbol, constantNumericHex, constantNumericFloat, - + constantNumericBinary, + constantNumericDecimal, + constantNumericOctal, { - token : "constant.language.boolean", - regex : "(?:true|false)\\b" + token: "constant.language.boolean", + regex: "(?:true|false)\\b" }, { - token : keywordMapper, - // TODO: Unicode escape sequences - // TODO: Unicode identifiers - regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + token: keywordMapper, + regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" }, { - token : "punctuation.separator.key-value", - regex : "=>" + token: "punctuation.separator.key-value", + regex: "=>" }, { stateName: "heredoc", - onMatch : function(value, currentState, stack) { - var next = value[2] == '-' ? "indentedHeredoc" : "heredoc"; + onMatch: function (value, currentState, stack) { + var next = (value[2] == '-' || value[2] == '~') ? "indentedHeredoc" : "heredoc"; var tokens = value.split(this.splitRegex); stack.push(next, tokens[3]); return [ - {type:"constant", value: tokens[1]}, - {type:"string", value: tokens[2]}, - {type:"support.class", value: tokens[3]}, - {type:"string", value: tokens[4]} + {type: "constant", value: tokens[1]}, + {type: "string", value: tokens[2]}, + {type: "support.class", value: tokens[3]}, + {type: "string", value: tokens[4]} ]; }, - regex : "(<<-?)(['\"`]?)([\\w]+)(['\"`]?)", + regex: "(<<[-~]?)(['\"`]?)([\\w]+)(['\"`]?)", rules: { heredoc: [{ - onMatch: function(value, currentState, stack) { + onMatch: function(value, currentState, stack) { if (value === stack[1]) { stack.shift(); stack.shift(); @@ -271,7 +356,7 @@ var RubyHighlightRules = function() { token: "string", regex: "^ +" }, { - onMatch: function(value, currentState, stack) { + onMatch: function(value, currentState, stack) { if (value === stack[1]) { stack.shift(); stack.shift(); @@ -286,38 +371,265 @@ var RubyHighlightRules = function() { }] } }, { - regex : "$", - token : "empty", - next : function(currentState, stack) { + regex: "$", + token: "empty", + next: function(currentState, stack) { if (stack[0] === "heredoc" || stack[0] === "indentedHeredoc") return stack[0]; return currentState; } }, { - token : "string.character", - regex : "\\B\\?." + token: "string.character", + regex: "\\B\\?(?:" + escapedChars + "|\\S)" + }, { + token: "keyword.operator", + regex: "!|\\$|%|&|\\*|/|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\||\\b(?:in|instanceof|new|delete|typeof|void)" }, { - token : "keyword.operator", - regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)" + token: "paren.lparen", + regex: "[[({]" }, { - token : "paren.lparen", - regex : "[[({]" + token: "paren.rparen", + regex: "[\\])}]", + onMatch: function(value, currentState, stack) { + this.next = ''; + if (value == "}" && stack.length > 1 && stack[1] != "start") { + stack.shift(); + this.next = stack.shift(); + } + return this.token; + } }, { - token : "paren.rparen", - regex : "[\\])}]" + token: "text", + regex: "\\s+" }, { - token : "text", - regex : "\\s+" + token: "punctuation.operator", + regex: /[?:,;.]/ } ], - "comment" : [ + "comment": [ { - token : "comment", // closing comment - regex : "^=end(?:$|\\s.*$)", - next : "start" + token: "comment.multiline", // closing comment + regex: "^=end(?=$|\\s.*$)", + next: "start" + }, { + token: "comment", // comment spanning whole line + regex: ".+" + } + ], + "qStateWithInterpolation": [{ + token: "string.start",// excluded nested |^% due to difficulty in realization + regex: /[(\[<{]/, onMatch: function (val, state, stack) { + if (stack.length && val === stack[0]) { + stack.unshift(val, state); + return this.token; + } + return "string" + } + }, { + token: "constant.language.escape", + regex: escapedChars + }, { + token: "constant.language.escape", + regex: /\\./ + }, { + token: "paren.start", + regex: /#{/, + push: "start" + }, { + token: "string.end", + regex: /[)\]>}^|%]/, onMatch: function (val, state, stack) { + if (stack.length && val === closeParen[stack[0]]) { + stack.shift(); + this.next = stack.shift(); + return this.token; + } + this.next = ''; + return "string"; + } + }, { + defaultToken: "string" + }], + "qStateWithoutInterpolation": [{ + token: "string.start",// excluded nested |^% due to difficulty in realization + regex: /[(\[<{]/, onMatch: function (val, state, stack) { + if (stack.length && val === stack[0]) { + stack.unshift(val, state); + return this.token; + } + return "string"; + } + }, { + token: "constant.language.escape", + regex: /\\['\\]/ + }, { + token: "constant.language.escape", + regex: /\\./ + }, { + token: "string.end", + regex: /[)\]>}^|%]/, onMatch: function (val, state, stack) { + if (stack.length && val === closeParen[stack[0]]) { + stack.shift(); + this.next = stack.shift(); + return this.token; + } + this.next = ''; + return "string"; + } + }, { + defaultToken: "string" + }], + "sStateWithoutInterpolation": [{ + token: "constant.other.symbol.ruby",// excluded nested |^% due to difficulty in realization + regex: /[(\[<{]/, onMatch: function (val, state, stack) { + if (stack.length && val === stack[0]) { + stack.unshift(val, state); + return this.token; + } + return "constant.other.symbol.ruby"; + } + }, { + token: "constant.other.symbol.ruby", + regex: /[)\]>}^|%]/, onMatch: function (val, state, stack) { + if (stack.length && val === closeParen[stack[0]]) { + stack.shift(); + this.next = stack.shift(); + return this.token; + } + this.next = ''; + return "constant.other.symbol.ruby"; + } + }, { + defaultToken: "constant.other.symbol.ruby" + }], + "sStateWithInterpolation": [{ + token: "constant.other.symbol.ruby",// excluded nested |^% due to difficulty in realization + regex: /[(\[<{]/, onMatch: function (val, state, stack) { + if (stack.length && val === stack[0]) { + stack.unshift(val, state); + return this.token; + } + return "constant.other.symbol.ruby"; + } + }, { + token: "constant.language.escape", + regex: escapedChars + }, { + token: "constant.language.escape", + regex: /\\./ + }, { + token: "paren.start", + regex: /#{/, + push: "start" + }, { + token: "constant.other.symbol.ruby", + regex: /[)\]>}^|%]/, onMatch: function (val, state, stack) { + if (stack.length && val === closeParen[stack[0]]) { + stack.shift(); + this.next = stack.shift(); + return this.token; + } + this.next = ''; + return "constant.other.symbol.ruby"; + } + }, { + defaultToken: "constant.other.symbol.ruby" + }], + "rState": [{ + token: "string.regexp",// excluded nested |^% due to difficulty in realization + regex: /[(\[<{]/, onMatch: function (val, state, stack) { + if (stack.length && val === stack[0]) { + stack.unshift(val, state); + return this.token; + } + return "constant.language.escape" + } + }, { + token: "paren.start", + regex: /#{/, + push: "start" + }, { + token: "string.regexp", + regex: /\// + }, { + token: "string.regexp", + regex: /[)\]>}^|%][imxouesn]*/, onMatch: function (val, state, stack) { + if (stack.length && val[0] === closeParen[stack[0]]) { + stack.shift(); + this.next = stack.shift(); + return this.token; + } + this.next = ''; + return "constant.language.escape"; + } + }, + {include: "regex"}, + { + defaultToken: "string.regexp" + }], + "regex": [ + {// character classes + token: "regexp.keyword", + regex: /\\[wWdDhHsS]/ + }, { + token: "constant.language.escape", + regex: /\\[AGbBzZ]/ + }, { + token: "constant.language.escape", + regex: /\\g<[a-zA-Z0-9]*>/ + }, { + token: ["constant.language.escape", "regexp.keyword", "constant.language.escape"], + regex: /(\\p{\^?)(Alnum|Alpha|Blank|Cntrl|Digit|Graph|Lower|Print|Punct|Space|Upper|XDigit|Word|ASCII|Any|Assigned|Arabic|Armenian|Balinese|Bengali|Bopomofo|Braille|Buginese|Buhid|Canadian_Aboriginal|Carian|Cham|Cherokee|Common|Coptic|Cuneiform|Cypriot|Cyrillic|Deseret|Devanagari|Ethiopic|Georgian|Glagolitic|Gothic|Greek|Gujarati|Gurmukhi|Han|Hangul|Hanunoo|Hebrew|Hiragana|Inherited|Kannada|Katakana|Kayah_Li|Kharoshthi|Khmer|Lao|Latin|Lepcha|Limbu|Linear_B|Lycian|Lydian|Malayalam|Mongolian|Myanmar|New_Tai_Lue|Nko|Ogham|Ol_Chiki|Old_Italic|Old_Persian|Oriya|Osmanya|Phags_Pa|Phoenician|Rejang|Runic|Saurashtra|Shavian|Sinhala|Sundanese|Syloti_Nagri|Syriac|Tagalog|Tagbanwa|Tai_Le|Tamil|Telugu|Thaana|Thai|Tibetan|Tifinagh|Ugaritic|Vai|Yi|Ll|Lm|Lt|Lu|Lo|Mn|Mc|Me|Nd|Nl|Pc|Pd|Ps|Pe|Pi|Pf|Po|No|Sm|Sc|Sk|So|Zs|Zl|Zp|Cc|Cf|Cn|Co|Cs|N|L|M|P|S|Z|C)(})/ + }, { + token: ["constant.language.escape", "invalid", "constant.language.escape"], + regex: /(\\p{\^?)([^/]*)(})/ + }, {// escapes + token: "regexp.keyword.operator", + regex: "\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)" + }, {// flag + token: "string.regexp", + regex: /[/][imxouesn]*/, + next: "start" + }, {// invalid operators + token: "invalid", + regex: /\{\d+\b,?\d*\}[+*]|[+*$^?][+*]|[$^][?]|\?{3,}/ + }, {// operators + token: "constant.language.escape", + regex: /\(\?(?:[:=!>]|<'?[a-zA-Z]*'?>|<[=!])|\)|\{\d+\b,?\d*\}|[+*]\?|[()$^+*?.]/ + }, { + token: "constant.language.delimiter", + regex: /\|/ + }, { + token: "regexp.keyword", + regex: /\[\[:(?:alnum|alpha|blank|cntrl|digit|graph|lower|print|punct|space|upper|xdigit|word|ascii):\]\]/ + }, { + token: "constant.language.escape", + regex: /\[\^?/, + push: "regex_character_class" + }, { + defaultToken: "string.regexp" + } + ], + "regex_character_class": [ + { + // character classes + token: "regexp.keyword", + regex: /\\[wWdDhHsS]/ + }, { + token: "regexp.charclass.keyword.operator", + regex: "\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)" + }, { + token: "constant.language.escape", + regex: /&?&?\[\^?/, + push: "regex_character_class" + }, { + token: "constant.language.escape", + regex: "]", + next: "pop" + }, { + token: "constant.language.escape", + regex: "-" }, { - token : "comment", // comment spanning whole line - regex : ".+" + defaultToken: "string.regexp.characterclass" } ] }; diff --git a/lib/ace/mode/ruby_test.js b/lib/ace/mode/ruby_test.js index 7b40da96488..4a3c020ab0f 100644 --- a/lib/ace/mode/ruby_test.js +++ b/lib/ace/mode/ruby_test.js @@ -40,7 +40,7 @@ var Mode = require("./ruby").Mode; var assert = require("../test/assertions"); module.exports = { - setUp : function() { + setUp: function() { this.mode = new Mode(); }, @@ -62,10 +62,138 @@ module.exports = { assert.equal(this.mode.checkOutdent("start", "foo = ba", "r"), false); }, - "test: auto outdent" : function() { - var session = new EditSession(["class Phil", " Foo = 'bar'", " end"]); - this.mode.autoOutdent("start", session, 2); - assert.equal(" end", session.getLine(2)); + "test: auto outdent": function() { + var session = new EditSession([ + "class Phil", + " Foo = 'bar'", + " def to_json(*a)", + " {", + " 'json_class' => self.class.name, # = 'Range'", + " 'data' => [ first, last, exclude_end? ]", + " }", + " end"]); + this.mode.autoOutdent("start", session, 6); + assert.equal(" }", session.getLine(6)); + this.mode.autoOutdent("start", session, 7); + assert.equal(" end", session.getLine(7)); + }, + + "test: different delimiters in percent strings": function() { + var tokenizer = this.mode.getTokenizer(); + var tokens = tokenizer.getLineTokens("%q", "start").tokens; + assert.equal("string", tokens[1].type); + assert.equal("t(es)t", tokens[1].value); + + tokens = tokenizer.getLineTokens("%q Date: Mon, 4 May 2020 22:28:00 +0300 Subject: [PATCH 0344/1293] ruby symbols precedance before shorthand conditions --- lib/ace/mode/ruby_highlight_rules.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ace/mode/ruby_highlight_rules.js b/lib/ace/mode/ruby_highlight_rules.js index 4d6d2b228c3..fdcbb6104c3 100644 --- a/lib/ace/mode/ruby_highlight_rules.js +++ b/lib/ace/mode/ruby_highlight_rules.js @@ -301,6 +301,9 @@ var RubyHighlightRules = function() { }, { token: ["punctuation.operator", "identifier"], regex: /(\.)([a-zA-Z_][a-zA-Z_\d]*)/ + }, { + token: "string.character", + regex: "\\B\\?(?:" + escapedChars + "|\\S)" }, { token: "punctuation.operator", regex: /\?(?=.+:)/ @@ -378,10 +381,7 @@ var RubyHighlightRules = function() { return stack[0]; return currentState; } - }, { - token: "string.character", - regex: "\\B\\?(?:" + escapedChars + "|\\S)" - }, { + }, { token: "keyword.operator", regex: "!|\\$|%|&|\\*|/|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\||\\b(?:in|instanceof|new|delete|typeof|void)" }, { From b4bd4fa98ebf0f3d3c1a80033f1750c9a860dab4 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Mon, 4 May 2020 22:44:16 +0300 Subject: [PATCH 0345/1293] missing semicolons added; unnecessary vars deleted --- lib/ace/mode/ruby_highlight_rules.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/ace/mode/ruby_highlight_rules.js b/lib/ace/mode/ruby_highlight_rules.js index fdcbb6104c3..684f3c4f59b 100644 --- a/lib/ace/mode/ruby_highlight_rules.js +++ b/lib/ace/mode/ruby_highlight_rules.js @@ -40,17 +40,17 @@ var constantOtherSymbol = exports.constantOtherSymbol = { regex : "[:](?:[A-Za-z_]|[@$](?=[a-zA-Z0-9_]))[a-zA-Z0-9_]*[!=?]?" }; -var qString = exports.qString = { +exports.qString = { token : "string", // single line regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" }; -var qqString = exports.qqString = { +exports.qqString = { token : "string", // single line regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' }; -var tString = exports.tString = { +exports.tString = { token : "string", // backtick string regex : "[`](?:(?:\\\\.)|(?:[^'\\\\]))*?[`]" }; @@ -286,10 +286,9 @@ var RubyHighlightRules = function() { { token: "punctuation", // namespaces aren't symbols regex: "::" - }, { - token: "variable.instance", // instance variable - regex: "@{1,2}[a-zA-Z_\\d]+" - }, { + }, + instanceVariable, + { token: "variable.global", // global variable regex: "[$][a-zA-Z_\\d]+" }, { @@ -423,7 +422,7 @@ var RubyHighlightRules = function() { stack.unshift(val, state); return this.token; } - return "string" + return "string"; } }, { token: "constant.language.escape", @@ -541,7 +540,7 @@ var RubyHighlightRules = function() { stack.unshift(val, state); return this.token; } - return "constant.language.escape" + return "constant.language.escape"; } }, { token: "paren.start", From c0e39a093d3408c20ca59db22244755297424ce5 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Mon, 4 May 2020 23:00:47 +0300 Subject: [PATCH 0346/1293] updated tokens for tests --- lib/ace/mode/_test/tokens_html_ruby.json | 30 +++-- lib/ace/mode/_test/tokens_ruby.json | 153 +++++++++++++++-------- 2 files changed, 121 insertions(+), 62 deletions(-) diff --git a/lib/ace/mode/_test/tokens_html_ruby.json b/lib/ace/mode/_test/tokens_html_ruby.json index 8ff5f6ea97a..ea923f7fdf5 100644 --- a/lib/ace/mode/_test/tokens_html_ruby.json +++ b/lib/ace/mode/_test/tokens_html_ruby.json @@ -82,13 +82,15 @@ ["support.ruby_tag","<%"], ["text"," "], ["variable.instance","@books"], - ["text","."], + ["punctuation.operator","."], ["identifier","each"], ["text"," "], ["keyword","do"], - ["text"," |"], + ["text"," "], + ["keyword.operator","|"], ["identifier","book"], - ["text","| "], + ["keyword.operator","|"], + ["text"," "], ["support.ruby_tag","%>"] ],[ "start", @@ -111,7 +113,7 @@ ["support.ruby_tag","<%="], ["text"," "], ["identifier","book"], - ["text","."], + ["punctuation.operator","."], ["identifier","title"], ["text"," "], ["support.ruby_tag","%>"], @@ -127,7 +129,7 @@ ["support.ruby_tag","<%="], ["text"," "], ["identifier","book"], - ["text","."], + ["punctuation.operator","."], ["identifier","content"], ["text"," "], ["support.ruby_tag","%>"], @@ -147,7 +149,8 @@ ["string.start","'"], ["string","Show"], ["string.end","'"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["identifier","book"], ["text"," "], ["support.ruby_tag","%>"], @@ -167,7 +170,8 @@ ["string.start","'"], ["string","Edit"], ["string.end","'"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["identifier","edit_book_path"], ["paren.lparen","("], ["identifier","book"], @@ -190,9 +194,11 @@ ["string.start","'"], ["string","Remove"], ["string.end","'"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["identifier","book"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":confirm"], ["text"," "], ["punctuation.separator.key-value","=>"], @@ -200,7 +206,8 @@ ["string.start","'"], ["string","Are you sure?"], ["string.end","'"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":method"], ["text"," "], ["punctuation.separator.key-value","=>"], @@ -250,7 +257,8 @@ ["string.start","'"], ["string","New book"], ["string.end","'"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["identifier","new_book_path"], ["text"," "], ["support.ruby_tag","%>"] diff --git a/lib/ace/mode/_test/tokens_ruby.json b/lib/ace/mode/_test/tokens_ruby.json index f9991e9cec4..2eac0c350f1 100644 --- a/lib/ace/mode/_test/tokens_ruby.json +++ b/lib/ace/mode/_test/tokens_ruby.json @@ -7,55 +7,83 @@ ["text"," "], ["paren.lparen","["], ["constant.other.symbol.ruby",":@thing"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":$thing"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":_thing"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":thing"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":Thing"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":thing1"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":thing_a"], - ["text",","] + ["punctuation.operator",","] ],[ "start", ["text"," "], ["constant.other.symbol.ruby",":THING"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":thing!"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":thing="], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":thing?"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":t?"], - ["text",","] + ["punctuation.operator",","] ],[ "start", - ["text"," :, :@, :"], + ["text"," "], + ["punctuation.operator",":,"], + ["text"," "], + ["punctuation.operator",":"], + ["text","@"], + ["punctuation.operator",","], + ["text"," "], + ["punctuation.operator",":"], ["keyword.operator","$"], - ["text",", :"], + ["punctuation.operator",","], + ["text"," "], + ["punctuation.operator",":"], ["constant.numeric","1"], - ["text",", :1"], + ["punctuation.operator",","], + ["text"," "], + ["punctuation.operator",":"], + ["text","1"], ["identifier","thing"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":th?"], ["identifier","ing"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":thi="], ["identifier","ng"], - ["text",", :1"], + ["punctuation.operator",","], + ["text"," "], + ["punctuation.operator",":"], + ["text","1"], ["identifier","thing"], - ["text",","] + ["punctuation.operator",","] ],[ "start", ["text"," "], ["constant.other.symbol.ruby",":th!"], ["identifier","ing"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":thing"], ["comment","#"] ],[ @@ -72,7 +100,7 @@ "start", ["text"," "], ["support.class","Namespaced"], - ["text","::"], + ["punctuation","::"], ["support.class","Class"] ],[ "start", @@ -82,17 +110,22 @@ "start", ["text"," "], ["constant.numeric","0x9a"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.numeric","0XA1"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.numeric","0x9_a"], - ["text",", 0"], + ["punctuation.operator",","], + ["text"," 0"], ["identifier","x"], - ["text",", 0"], + ["punctuation.operator",","], + ["text"," 0"], ["identifier","x_9a"], - ["text",", 0"], + ["punctuation.operator",","], + ["text"," 0"], ["identifier","x9a_"], - ["text",","] + ["punctuation.operator",","] ],[ "start", ["text"," "], @@ -102,33 +135,41 @@ ["text"," "], ["paren.lparen","["], ["constant.numeric","1"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.numeric","+1"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.numeric","-1"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.numeric","12_345"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.numeric","0.000_1"], - ["text",","] + ["punctuation.operator",","] ],[ "start", ["text"," "], ["identifier","_"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.numeric","3_1"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.numeric","1_2"], - ["text",", 1"], + ["punctuation.operator",","], + ["text"," 1"], ["identifier","_"], - ["text","."], + ["punctuation.operator","."], ["constant.numeric","0"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.numeric","0"], - ["text","."], + ["punctuation.operator","."], ["identifier","_1"], ["paren.rparen","]"], - ["text",";"] + ["punctuation.operator",";"] ],[ "start", ["text"," "] @@ -140,7 +181,8 @@ ["punctuation.separator.key-value","=>"], ["text"," "], ["string.character","?\""], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant.other.symbol.ruby",":key"], ["text"," "], ["punctuation.separator.key-value","=>"], @@ -148,34 +190,40 @@ ["string.start","\""], ["string","value"], ["string.end","\""], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["identifier","anotherKey"], - ["text",": "], + ["punctuation.operator",":"], + ["text"," "], ["paren.lparen","["], ["identifier","x"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["identifier","y"], - ["text","?"], + ["punctuation.operator","?"], ["paren.rparen","]}"] ],[ "start" ],[ "comment", - ["comment","=begin"] + ["comment.multiline","=begin"] ],[ "start", - ["comment","=end"] + ["comment.multiline","=end"] ],[ "start" ],[ "comment", - ["comment","=begin x"] + ["comment.multiline","=begin"], + ["comment"," x"] ],[ "comment", ["comment","=end-"] ],[ "start", - ["comment","=end x"] + ["comment.multiline","=end"], + ["text"," "], + ["identifier","x"] ],[ "start" ],[ @@ -190,17 +238,20 @@ ["string","'"], ["support.class","FOO"], ["string","'"], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant","<<"], ["string",""], ["support.class","BAR"], ["string",""], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant","<<-"], ["string",""], ["support.class","BAZ"], ["string",""], - ["text",", "], + ["punctuation.operator",","], + ["text"," "], ["constant","<<-"], ["string","`"], ["support.class","EXEC"], From aa82fd0e3d870b3f4337f3db71dcf1821aa39ad5 Mon Sep 17 00:00:00 2001 From: Simon Morgan Date: Wed, 6 May 2020 10:23:03 +1200 Subject: [PATCH 0347/1293] fix xml highlighting to correctly deal with self-closing tags --- lib/ace/editor.js | 54 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 556f8692afa..2cd108fdaa4 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -593,26 +593,34 @@ Editor.$uid = 0; return; } - if (token.type.indexOf("tag-open") != -1) { + if (token.type.indexOf("tag-open") !== -1) { token = iterator.stepForward(); if (!token) return; } var tag = token.value; + var currentTag = token.value; var depth = 0; var prevToken = iterator.stepBackward(); - if (prevToken.value == '<'){ + if (prevToken.value === '<'){ //find closing tag do { prevToken = token; token = iterator.stepForward(); - - if (token && token.value === tag && token.type.indexOf('tag-name') !== -1) { - if (prevToken.value === '<'){ - depth++; - } else if (prevToken.value === '') { // self closing tag depth--; } } @@ -623,12 +631,32 @@ Editor.$uid = 0; do { token = prevToken; prevToken = iterator.stepBackward(); - - if (token && token.value === tag && token.type.indexOf('tag-name') !== -1) { - if (prevToken.value === '<') { - depth++; - } else if (prevToken.value === '') { // self closing tag + var stepCount = 0; + var tmpToken = prevToken; + while (tmpToken) { + if (tmpToken.type.indexOf('tag-name') !== -1 && tmpToken.value === tag) { + depth--; + break; + } else if (tmpToken.value === '<') { + break; + } + tmpToken = iterator.stepBackward(); + stepCount++; + } + for (var i = 0; i < stepCount; i++) { + iterator.stepForward(); + } } } } while (prevToken && depth <= 0); From 836e5fb879a85ebedda984111e17d1dc9c9c59bd Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 7 May 2020 03:24:13 +0400 Subject: [PATCH 0348/1293] fix greedy string highlighter pattern --- lib/ace/mode/abc.js | 5 ++--- lib/ace/mode/d_highlight_rules.js | 2 +- lib/ace/mode/python_highlight_rules.js | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/ace/mode/abc.js b/lib/ace/mode/abc.js index 30a443cc729..b4cba0ff322 100644 --- a/lib/ace/mode/abc.js +++ b/lib/ace/mode/abc.js @@ -48,9 +48,8 @@ define(function (require, exports, module) { oop.inherits(Mode, TextMode); (function () { - // this.lineCommentStart = ""%.*""; - // this.blockComment = {start: ""/*"", end: ""*/""}; - // Extra logic goes here. + this.lineCommentStart = "%"; + this.$id = "ace/mode/abc"; this.snippetFileId = "ace/snippets/abc"; }).call(Mode.prototype); diff --git a/lib/ace/mode/d_highlight_rules.js b/lib/ace/mode/d_highlight_rules.js index 2509bb1654c..ab2b43711cd 100644 --- a/lib/ace/mode/d_highlight_rules.js +++ b/lib/ace/mode/d_highlight_rules.js @@ -293,7 +293,7 @@ var DHighlightRules = function() { regex: '[a-zA-Z]+' }, { token: 'string', - regex: '".*"' + regex: '"[^"]*"' }, { token: 'comment', regex: '//.*$' diff --git a/lib/ace/mode/python_highlight_rules.js b/lib/ace/mode/python_highlight_rules.js index 171cc0d3a05..276495cee15 100644 --- a/lib/ace/mode/python_highlight_rules.js +++ b/lib/ace/mode/python_highlight_rules.js @@ -378,10 +378,10 @@ var PythonHighlightRules = function() { regex: "\\s+" }, { token: "string", - regex: "'(.)*'" + regex: "'[^']*'" }, { token: "string", - regex: '"(.)*"' + regex: '"[^"]*"' }, { token: "function.support", regex: "(!s|!r|!a)" From 36e5da7949327ed02546e34767b4d3e7aaded68d Mon Sep 17 00:00:00 2001 From: Thien Do Date: Mon, 11 May 2020 13:56:28 +0700 Subject: [PATCH 0349/1293] Fix type of wrap in typescript definition As noted here https://github.com/ajaxorg/ace/wiki/Configuring-Ace#session-options wrap should be `boolean | number`, not `string | number` --- ace.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ace.d.ts b/ace.d.ts index 16f084d8ebc..1bcaf761084 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -152,7 +152,7 @@ export namespace Ace { } export interface EditSessionOptions { - wrap: string | number; + wrap: boolean | number; wrapMethod: 'code' | 'text' | 'auto'; indentedSoftWrap: boolean; firstLineNumber: number; From 481c682006d906c9d286c1ab8054e2a6317f1525 Mon Sep 17 00:00:00 2001 From: Thien Do Date: Mon, 11 May 2020 14:42:01 +0700 Subject: [PATCH 0350/1293] Fix removeCommand signature in TS def According to the test: https://github.com/ajaxorg/ace/blob/a0cf0e371677d35236c74c27353ad93f52ece750/lib/ace/commands/command_manager_test.js#L103-L111 It's ok to remove a command by name --- ace.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ace.d.ts b/ace.d.ts index 16f084d8ebc..7395ab9fced 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -549,7 +549,7 @@ export namespace Ace { toggleRecording(editor: Editor): void; replay(editor: Editor): void; addCommand(command: Command): void; - removeCommand(command: Command, keepCommand?: boolean): void; + removeCommand(command: Command | string, keepCommand?: boolean): void; bindKey(key: string | { mac?: string, win?: string }, command: CommandLike, position?: number): void; From b92fd1fe4911097f2aac6475e4d5c8ed89412640 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 15 May 2020 01:22:30 +0400 Subject: [PATCH 0351/1293] fix composition breaking on long lines --- lib/ace/keyboard/textinput.js | 9 +++++++-- lib/ace/keyboard/textinput_test.js | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index a621c480740..fc2e3e48171 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -224,8 +224,13 @@ var TextInput = function(parentNode, host) { line = line.slice(0, MAX_LINE_LENGTH); } else { line = "\n"; - selectionStart = 0; - selectionEnd = 1; + if (selectionStart == selectionEnd) { + selectionStart = selectionEnd = 0; + } + else { + selectionStart = 0; + selectionEnd = 1; + } } } } diff --git a/lib/ace/keyboard/textinput_test.js b/lib/ace/keyboard/textinput_test.js index 496ad767901..98ce3ffeb98 100644 --- a/lib/ace/keyboard/textinput_test.js +++ b/lib/ace/keyboard/textinput_test.js @@ -484,7 +484,7 @@ module.exports = { editor.execCommand("selectright"); assert.equal([textarea.value.length, textarea.selectionStart, textarea.selectionEnd].join(","), "402,1,2"); editor.execCommand("gotolineend"); - assert.equal([textarea.value.length, textarea.selectionStart, textarea.selectionEnd].join(","), "3,0,1"); + assert.equal([textarea.value.length, textarea.selectionStart, textarea.selectionEnd].join(","), "3,0,0"); editor.execCommand("selectleft"); assert.equal([textarea.value.length, textarea.selectionStart, textarea.selectionEnd].join(","), "3,0,1"); }, From e1266f5f4d83d72133cc82c5f30bce059f2acdbf Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 7 May 2020 02:22:45 +0400 Subject: [PATCH 0352/1293] workaround for gboard converting two spaces into dot --- lib/ace/keyboard/textinput.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index a621c480740..42de8356906 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -329,6 +329,14 @@ var TextInput = function(parentNode, host) { if (!fromInput && !inserted && !restoreStart && !extendLeft && !extendRight && !restoreEnd) return ""; sendingText = true; + + // some android keyboards converts two spaces into sentence end, which is not useful for code + var shouldReset = false; + if (useragent.isAndroid && inserted == ". ") { + inserted = " "; + shouldReset = true; + } + if (inserted && !extendLeft && !extendRight && !restoreStart && !restoreEnd || commandMode) { host.onTextInput(inserted); } else { @@ -345,7 +353,7 @@ var TextInput = function(parentNode, host) { lastSelectionStart = selectionStart; lastSelectionEnd = selectionEnd; lastRestoreEnd = restoreEnd; - return inserted; + return shouldReset ? "\n" : inserted; } }; var onInput = function(e) { From 8879ded846d2a25beaa8038e6cfad6d9bf08e0a4 Mon Sep 17 00:00:00 2001 From: Robert Egglestone Date: Mon, 18 May 2020 01:22:07 +1200 Subject: [PATCH 0353/1293] Generate a base for 3rd-party workers --- Makefile.dryice.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 5ad19197be0..9773666c564 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -424,6 +424,17 @@ function buildAce(options, callback) { }] }, "worker-" + name, addCb()); }); + // worker base + buildSubmodule(options, { + projectType: "worker", + require: ["ace/worker/mirror"], + ignore: [], + additional: [{ + id: "ace/worker/worker", + transforms: [], + order: -1000 + }] + }, "worker-base", addCb()); // function addCb() { addCb.count = (addCb.count || 0) + 1; From b85a0e9cecf987c137596e74d605b4a9b81b42bb Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 28 May 2020 12:08:52 +0400 Subject: [PATCH 0354/1293] fix missing comment warnings --- .travis.yml | 2 +- lib/ace/mode/_test/highlight_rules_test.js | 4 ++-- lib/ace/mode/kotlin.js | 4 ++-- lib/ace/mode/puppet.js | 3 +++ lib/ace/mode/puppet_highlight_rules.js | 8 ++------ lib/ace/mode/terraform.js | 3 +++ lib/ace/mode/terraform_highlight_rules.js | 14 +++++++------- 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3936326cbc7..9df0d8ab767 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ node_js: install: - cleanup() { find node_modules -regextype posix-extended -iregex '.*((test|example|doc|demo)s?|\.(md)|license|idea|coverage|file.txt)$' -exec rm -rf {} \; || echo $?; }; - install() { npm i && npm i eslint codecov istanbul typescript && cp package.json node_modules/package.json; cleanup; }; + install() { npm i && npm i eslint@6.1.0 codecov istanbul typescript && cp package.json node_modules/package.json; cleanup; }; cmp --silent package.json node_modules/package.json || install; script: diff --git a/lib/ace/mode/_test/highlight_rules_test.js b/lib/ace/mode/_test/highlight_rules_test.js index e48042f6c62..98cbc8dccb7 100644 --- a/lib/ace/mode/_test/highlight_rules_test.js +++ b/lib/ace/mode/_test/highlight_rules_test.js @@ -38,8 +38,8 @@ function checkModes() { return; } var m = new Mode(); - if (!("lineCommentStart" in m) && !("blockComment" in m)) - console.warn("missing comment in " + modeName); + if (!m.lineCommentStart && !m.blockComment) + console.error("missing comment in " + modeName); if (!m.$id) console.warn("missing id in " + modeName); if (!m.$behaviour) diff --git a/lib/ace/mode/kotlin.js b/lib/ace/mode/kotlin.js index 3f9b0f63cf8..f1e3fa8a51e 100644 --- a/lib/ace/mode/kotlin.js +++ b/lib/ace/mode/kotlin.js @@ -49,8 +49,8 @@ var Mode = function() { oop.inherits(Mode, TextMode); (function() { - // this.lineCommentStart = ""/\\*""; - // this.blockComment = {start: ""/*"", end: ""*/""}; + this.lineCommentStart = "//"; + this.blockComment = {start: "/*", end: "*/"}; // Extra logic goes here. this.$id = "ace/mode/kotlin"; }).call(Mode.prototype); diff --git a/lib/ace/mode/puppet.js b/lib/ace/mode/puppet.js index 0f038beca51..243fcd837dd 100644 --- a/lib/ace/mode/puppet.js +++ b/lib/ace/mode/puppet.js @@ -50,6 +50,9 @@ oop.inherits(Mode, TextMode); (function () { + this.lineCommentStart = "#"; + this.blockComment = {start: "/*", end: "*/"}; + this.$id = "ace/mode/puppet"; }).call(Mode.prototype); diff --git a/lib/ace/mode/puppet_highlight_rules.js b/lib/ace/mode/puppet_highlight_rules.js index a98ed060e43..5ba1ae2cbe6 100644 --- a/lib/ace/mode/puppet_highlight_rules.js +++ b/lib/ace/mode/puppet_highlight_rules.js @@ -74,7 +74,7 @@ var PuppetHighlightRules = function () { }, { token: "multiline.comment.begin.puppet", - regex: '^\\s*\\/\\*\\s*$', + regex: '^\\s*\\/\\*', push: "blockComment" }, { @@ -112,11 +112,7 @@ var PuppetHighlightRules = function () { } ], blockComment: [{ - regex: "^\\s*\\/\\*\\s*$", - token: "multiline.comment.begin.puppet", - push: "blockComment" - }, { - regex: "^\\s*\\*\\/\\s*$", + regex: "\\*\\/", token: "multiline.comment.end.puppet", next: "pop" }, { diff --git a/lib/ace/mode/terraform.js b/lib/ace/mode/terraform.js index 6b495147dba..037ac566c19 100644 --- a/lib/ace/mode/terraform.js +++ b/lib/ace/mode/terraform.js @@ -50,6 +50,9 @@ oop.inherits(Mode, TextMode); (function () { + this.lineCommentStart = ["#", "//"]; + this.blockComment = {start: "/*", end: "*/"}; + this.$id = "ace/mode/terraform"; }).call(Mode.prototype); diff --git a/lib/ace/mode/terraform_highlight_rules.js b/lib/ace/mode/terraform_highlight_rules.js index 20208c3a831..aaee003af42 100644 --- a/lib/ace/mode/terraform_highlight_rules.js +++ b/lib/ace/mode/terraform_highlight_rules.js @@ -70,11 +70,15 @@ var TerraformHighlightRules = function () { { token: "singleline.comment.terraform", - regex: '#(.)*$' + regex: '#.*$' + }, + { + token: "singleline.comment.terraform", + regex: '//.*$' }, { token: "multiline.comment.begin.terraform", - regex: '^\\s*\\/\\*', + regex: /\/\*/, push: "blockComment" }, { @@ -96,11 +100,7 @@ var TerraformHighlightRules = function () { {include: "variables"} ], blockComment: [{ - regex: "^\\s*\\/\\*", - token: "multiline.comment.begin.terraform", - push: "blockComment" - }, { - regex: "\\*\\/\\s*$", + regex: /\*\//, token: "multiline.comment.end.terraform", next: "pop" }, { From 9f2dae7fb11615f316313a39417ccb2566df04ad Mon Sep 17 00:00:00 2001 From: Thien Do Date: Mon, 1 Jun 2020 12:50:26 +0700 Subject: [PATCH 0355/1293] Update ace.d.ts --- ace.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ace.d.ts b/ace.d.ts index 1bcaf761084..9cff3d6688b 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -152,7 +152,7 @@ export namespace Ace { } export interface EditSessionOptions { - wrap: boolean | number; + wrap: "off" | "free" | "printmargin" | boolean | number; wrapMethod: 'code' | 'text' | 'auto'; indentedSoftWrap: boolean; firstLineNumber: number; From b4690250794541de937dc28270c90c0f24b9f3c9 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Sat, 6 Jun 2020 18:06:31 +0300 Subject: [PATCH 0356/1293] updated folding --- lib/ace/mode/folding/vbscript.js | 46 +++++++++++++++++--------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/lib/ace/mode/folding/vbscript.js b/lib/ace/mode/folding/vbscript.js index c614f61ea46..44b89d57774 100644 --- a/lib/ace/mode/folding/vbscript.js +++ b/lib/ace/mode/folding/vbscript.js @@ -61,13 +61,19 @@ oop.inherits(FoldMode, BaseFoldMode); "wend": -1 }; + this.foldingStartMarker = /(?:\s|^)(class|function|sub|if|select|do|for|while|with|property|else|elseif)\b/i; + this.foldingStopMarker = /\b(end|loop|next|wend)\b/i; + this.getFoldWidgetRange = function (session, foldStyle, row) { var line = session.getLine(row); - var match = /(\w+)\b/i.exec(line); - var keyword = match && match[1].toLowerCase(); - - if (keyword && this.indentKeywords.hasOwnProperty(keyword)) { - return this.vbsBlock(session, row, match.index + 1); + var isStart = this.foldingStartMarker.test(line); + var isEnd = this.foldingStopMarker.test(line); + if (isStart || isEnd) { + var match = (isEnd) ? this.foldingStopMarker.exec(line) : this.foldingStartMarker.exec(line); + var keyword = match && match[1].toLowerCase(); + if (keyword) { + return this.vbsBlock(session, row, match.index + 2); + } } }; @@ -75,17 +81,17 @@ oop.inherits(FoldMode, BaseFoldMode); // must return "" if there's no fold, to enable caching this.getFoldWidget = function(session, foldStyle, row) { var line = session.getLine(row); - var match = /^\s*(\w+)\b/i.exec(line); - var keyword = match && match[1].toLowerCase(); - - if (keyword && this.indentKeywords.hasOwnProperty(keyword)) { - if (this.indentKeywords[keyword] == -1) - return ""; - if (keyword == "if" && !/then\s*('|$)/i.test(line)) - return ""; - return "start"; + var isStart = this.foldingStartMarker.test(line); + var isEnd = this.foldingStopMarker.test(line); + if (isStart && !isEnd) { + var match = this.foldingStartMarker.exec(line); + var keyword = match && match[1].toLowerCase(); + if (keyword) { + if (keyword == "if" && !/then\s*('|$)/i.test(line)) + return ""; + return "start"; + } } - return ""; }; @@ -118,12 +124,10 @@ oop.inherits(FoldMode, BaseFoldMode); return; var firstRange = stream.getCurrentTokenRange(); - var modifiers = ''; switch (val) { case "property": case "sub": case "function": - modifiers = "(?:(?:Private|Public(?:\\s+Default)?)\\s+)?"; case "if": case "select": case "do": @@ -135,7 +139,7 @@ oop.inherits(FoldMode, BaseFoldMode); var singleLineCondition = /^\s*If\s+.*\s+Then(?!')\s+(?!')\S/i.test(line); if (singleLineCondition) return; - var checkToken = new RegExp("^\\s*"+ modifiers + val, "i"); + var checkToken = new RegExp("(?:^|\\s)" + val, "i"); var endTest = /^\s*End\s(If|Sub|Select|Function|Class|With|Property)\s*/i.test(line); if (!checkToken.test(line) && !endTest) { return; @@ -184,7 +188,6 @@ oop.inherits(FoldMode, BaseFoldMode); stream.step = dir === -1 ? stream.stepBackward : stream.stepForward; while(token = stream.step()) { - modifiers = ''; var outputRange = null; var ignore = false; if (token.type != "keyword.control.asp" && token.type != "storage.type.function.asp") @@ -196,7 +199,6 @@ oop.inherits(FoldMode, BaseFoldMode); case "property": case "sub": case "function": - modifiers = "(?:(?:Private|Public(?:\\sDefault)?)\\s+)?"; case "if": case "select": case "do": @@ -210,8 +212,8 @@ oop.inherits(FoldMode, BaseFoldMode); level = 0; ignore = true; } - var checkToken = new RegExp("^\\s*" + modifiers + val, "i"); - if (!checkToken.test(line)) { + var checkToken = new RegExp("^\\s* end\\s+" + val, "i"); + if (checkToken.test(line)) { level = 0; ignore = true; } From 2eb41f3c62b75a46ef111116d129ce8e887fd0b1 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Sat, 6 Jun 2020 18:13:00 +0300 Subject: [PATCH 0357/1293] updated net level determination --- lib/ace/mode/vbscript.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/ace/mode/vbscript.js b/lib/ace/mode/vbscript.js index 4afa3f0432f..d7cbd6708f0 100644 --- a/lib/ace/mode/vbscript.js +++ b/lib/ace/mode/vbscript.js @@ -69,7 +69,6 @@ oop.inherits(Mode, TextMode); function getNetIndentLevel(tokens, line, indentKeywords) { var level = 0; - var modifiers = ''; // Support single-line blocks by decrementing the indent level if // an ending token is found for (var i = 0; i < tokens.length; i++) { @@ -81,15 +80,14 @@ oop.inherits(Mode, TextMode); case "property": case "sub": case "function": - modifiers = "(?:(?:Private|Public(?:\\s+Default)?)\\s+)?"; case "select": case "do": case "for": case "class": case "while": case "with": - var checkToken = new RegExp("^\\s*" + modifiers + val,"i"); - if (checkToken.test(line)) { + var checkToken = new RegExp("^\\s* end\\s+" + val, "i"); + if (!checkToken.test(line)) { level += indentKeywords[val]; } break; From 66e7d6aeac67cf0be991e5238592f63e4e348576 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Sat, 6 Jun 2020 18:51:54 +0300 Subject: [PATCH 0358/1293] excluding folding tokens with wrong token type --- lib/ace/mode/folding/vbscript.js | 13 +++++++++---- lib/ace/mode/vbscript.js | 8 ++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/ace/mode/folding/vbscript.js b/lib/ace/mode/folding/vbscript.js index 44b89d57774..05c8402bdc0 100644 --- a/lib/ace/mode/folding/vbscript.js +++ b/lib/ace/mode/folding/vbscript.js @@ -72,7 +72,9 @@ oop.inherits(FoldMode, BaseFoldMode); var match = (isEnd) ? this.foldingStopMarker.exec(line) : this.foldingStartMarker.exec(line); var keyword = match && match[1].toLowerCase(); if (keyword) { - return this.vbsBlock(session, row, match.index + 2); + var type = session.getTokenAt(row, match.index + 2).type; + if (type === "keyword.control.asp" || type === "storage.type.function.asp") + return this.vbsBlock(session, row, match.index + 2); } } }; @@ -87,9 +89,12 @@ oop.inherits(FoldMode, BaseFoldMode); var match = this.foldingStartMarker.exec(line); var keyword = match && match[1].toLowerCase(); if (keyword) { - if (keyword == "if" && !/then\s*('|$)/i.test(line)) - return ""; - return "start"; + var type = session.getTokenAt(row, match.index + 2).type; + if (type == "keyword.control.asp" || type == "storage.type.function.asp") { + if (keyword == "if" && !/then\s*('|$)/i.test(line)) + return ""; + return "start"; + } } } return ""; diff --git a/lib/ace/mode/vbscript.js b/lib/ace/mode/vbscript.js index d7cbd6708f0..bdf75583a72 100644 --- a/lib/ace/mode/vbscript.js +++ b/lib/ace/mode/vbscript.js @@ -86,14 +86,10 @@ oop.inherits(Mode, TextMode); case "class": case "while": case "with": - var checkToken = new RegExp("^\\s* end\\s+" + val, "i"); - if (!checkToken.test(line)) { - level += indentKeywords[val]; - } - break; case "if": + var checkToken = new RegExp("^\\s* end\\s+" + val, "i"); var singleLineCondition = /^\s*If\s+.*\s+Then(?!')\s+(?!')\S/i.test(line); - if (!singleLineCondition) + if (!singleLineCondition && !checkToken.test(line)) level += indentKeywords[val]; break; default: From 347b7cd734ee382601611918be498a8a55c50542 Mon Sep 17 00:00:00 2001 From: skacurt Date: Fri, 1 May 2020 05:57:34 +0300 Subject: [PATCH 0359/1293] [vbscript] add missing separator --- lib/ace/mode/vbscript_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index 9fd20ee9287..56131834ceb 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -66,7 +66,7 @@ var VBScriptHighlightRules = function() { + "|ScriptEngineMinorVersion|Second|SetLocale|Sgn|Sin|Space|Split|Sqr|StrComp|String|StrReverse" + "|Tan|Time|Timer|TimeSerial|TimeValue|TypeName|UBound|UCase|Unescape|VarType|Weekday|WeekdayName|Year", "support.type.vb.asp": "vbtrue|vbfalse|vbcr|vbcrlf|vbformfeed|vblf|vbnewline|vbnullchar|vbnullstring|" - + "int32|vbtab|vbverticaltab|vbbinarycompare|vbtextcomparevbsunday|vbmonday|vbtuesday|vbwednesday" + + "int32|vbtab|vbverticaltab|vbbinarycompare|vbtextcompare|vbsunday|vbmonday|vbtuesday|vbwednesday" + "|vbthursday|vbfriday|vbsaturday|vbusesystemdayofweek|vbfirstjan1|vbfirstfourdays|vbfirstfullweek" + "|vbgeneraldate|vblongdate|vbshortdate|vblongtime|vbshorttime|vbobjecterror|vbEmpty|vbNull|vbInteger" + "|vbLong|vbSingle|vbDouble|vbCurrency|vbDate|vbString|vbObject|vbError|vbBoolean|vbVariant" From 0f3a5905ab8f889d31dd797062dfe53bcc384995 Mon Sep 17 00:00:00 2001 From: skacurt Date: Fri, 1 May 2020 09:20:47 +0300 Subject: [PATCH 0360/1293] [vbscript] add missing "Me" keyword --- lib/ace/mode/vbscript_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index 56131834ceb..16063092a62 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -46,7 +46,7 @@ var VBScriptHighlightRules = function() { "storage.type.asp": "Dim|Call|Const|Redim|Set|Let|Get|New|Randomize|Option|Explicit", "storage.modifier.asp": "Private|Public|Default", "keyword.operator.asp": "Mod|And|Not|Or|Xor|as", - "constant.language.asp": "Empty|False|Nothing|Null|True", + "constant.language.asp": "Empty|False|Nothing|Null|True|Me", "support.class.asp": "Application|ObjectContext|Request|Response|Server|Session", "support.class.collection.asp": "Contents|StaticObjects|ClientCertificate|Cookies|Form|QueryString|ServerVariables", "support.constant.asp": "TotalBytes|Buffer|CacheControl|Charset|ContentType|Expires|ExpiresAbsolute" From 86dc54f3872b4624f433723b804daf101762bbf2 Mon Sep 17 00:00:00 2001 From: skacurt Date: Fri, 1 May 2020 09:21:39 +0300 Subject: [PATCH 0361/1293] [vbscript] add missing keyword operators: "Eqv", "Imp" and "Is" --- lib/ace/mode/vbscript_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index 16063092a62..a6fa912532f 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -45,7 +45,7 @@ var VBScriptHighlightRules = function() { + "|Continue|Do|Until|Loop|Next|With|Exit|Function|Property|Type|Enum|Sub|IIf|Class", "storage.type.asp": "Dim|Call|Const|Redim|Set|Let|Get|New|Randomize|Option|Explicit", "storage.modifier.asp": "Private|Public|Default", - "keyword.operator.asp": "Mod|And|Not|Or|Xor|as", + "keyword.operator.asp": "Mod|And|Not|Or|Xor|as|Eqv|Imp|Is", "constant.language.asp": "Empty|False|Nothing|Null|True|Me", "support.class.asp": "Application|ObjectContext|Request|Response|Server|Session", "support.class.collection.asp": "Contents|StaticObjects|ClientCertificate|Cookies|Form|QueryString|ServerVariables", From 00cfabe855df820d1a85c7a68c9097064cc161df Mon Sep 17 00:00:00 2001 From: skacurt Date: Fri, 1 May 2020 09:23:26 +0300 Subject: [PATCH 0362/1293] [vbscript] add missing match alternation character in the pattern --- lib/ace/mode/vbscript_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index a6fa912532f..cb96a28fb18 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -152,7 +152,7 @@ var VBScriptHighlightRules = function() { // }, { token: ["keyword.operator.asp"], - regex: "\\-|\\+|\\*\\/|\\>|\\<|\\=|\\&" + regex: "\\-|\\+|\\*|\\/|\\>|\\<|\\=|\\&" } ], "state_3": [ From 4194ddd5438f4d5446d6a78a69eb89dd91b8fa40 Mon Sep 17 00:00:00 2001 From: skacurt Date: Fri, 1 May 2020 09:23:52 +0300 Subject: [PATCH 0363/1293] [vbscript] add missing operators: integer division "\" and exponentiation "^" --- lib/ace/mode/vbscript_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index cb96a28fb18..d67c09ed77f 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -152,7 +152,7 @@ var VBScriptHighlightRules = function() { // }, { token: ["keyword.operator.asp"], - regex: "\\-|\\+|\\*|\\/|\\>|\\<|\\=|\\&" + regex: "\\-|\\+|\\*|\\/|\\>|\\<|\\=|\\&|\\\\|\\^" } ], "state_3": [ From 3aafbd6f410ceb2a7f6523f933fb34501e99965c Mon Sep 17 00:00:00 2001 From: skacurt Date: Fri, 1 May 2020 14:06:02 +0300 Subject: [PATCH 0364/1293] [vbscript] make white space matches greedy and ensure that the statement ends with boundary --- lib/ace/mode/vbscript_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index d67c09ed77f..a4c35a2f57f 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -112,7 +112,7 @@ var VBScriptHighlightRules = function() { }, { token: "storage.type.asp", - regex: "On Error Resume Next|On Error GoTo", + regex: "On\\s+Error\\s+(?:Resume\\s+Next|GoTo)\\b", caseInsensitive: true }, { From a5ebadd000ad44f88cb7071ec975717d1918810f Mon Sep 17 00:00:00 2001 From: skacurt Date: Fri, 1 May 2020 14:06:51 +0300 Subject: [PATCH 0365/1293] [vbscript] remove redundant ASP-specific end of comment lookup --- lib/ace/mode/vbscript_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index a4c35a2f57f..0c6bf4fa050 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -191,7 +191,7 @@ var VBScriptHighlightRules = function() { "comment": [ { token: "comment.line.apostrophe.asp", - regex: "$|(?=(?:%>))", + regex: "$", next: "start" }, { From 06b76a5d8aff325876e4bbeece9ff9596173e9f2 Mon Sep 17 00:00:00 2001 From: skacurt Date: Fri, 1 May 2020 14:10:23 +0300 Subject: [PATCH 0366/1293] [vbscript] add missing built-in functions List of functions added support with this commit: AscB, AscW, ChrB, ChrW, InStrB, LeftB, LenB, MidB, RightB, Abs, GetUILanguage --- lib/ace/mode/vbscript_highlight_rules.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index 0c6bf4fa050..ea22b936a29 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -64,7 +64,8 @@ var VBScriptHighlightRules = function() { + "|Trim|Maths|Mid|Minute|Month|MonthName|MsgBox|Now|Oct|Remove|RemoveAll|Replace" + "|RGB|Right|Rnd|Round|ScriptEngine|ScriptEngineBuildVersion|ScriptEngineMajorVersion" + "|ScriptEngineMinorVersion|Second|SetLocale|Sgn|Sin|Space|Split|Sqr|StrComp|String|StrReverse" - + "|Tan|Time|Timer|TimeSerial|TimeValue|TypeName|UBound|UCase|Unescape|VarType|Weekday|WeekdayName|Year", + + "|Tan|Time|Timer|TimeSerial|TimeValue|TypeName|UBound|UCase|Unescape|VarType|Weekday|WeekdayName|Year" + + "|AscB|AscW|ChrB|ChrW|InStrB|LeftB|LenB|MidB|RightB|Abs|GetUILanguage", "support.type.vb.asp": "vbtrue|vbfalse|vbcr|vbcrlf|vbformfeed|vblf|vbnewline|vbnullchar|vbnullstring|" + "int32|vbtab|vbverticaltab|vbbinarycompare|vbtextcompare|vbsunday|vbmonday|vbtuesday|vbwednesday" + "|vbthursday|vbfriday|vbsaturday|vbusesystemdayofweek|vbfirstjan1|vbfirstfourdays|vbfirstfullweek" From 4366c00fc4ada52eab9e5f93f4bae58ca832342b Mon Sep 17 00:00:00 2001 From: skacurt Date: Fri, 1 May 2020 14:43:06 +0300 Subject: [PATCH 0367/1293] [vbscript] add missing MsgBoxStyle constants --- lib/ace/mode/vbscript_highlight_rules.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index ea22b936a29..21dc2e70110 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -71,7 +71,9 @@ var VBScriptHighlightRules = function() { + "|vbthursday|vbfriday|vbsaturday|vbusesystemdayofweek|vbfirstjan1|vbfirstfourdays|vbfirstfullweek" + "|vbgeneraldate|vblongdate|vbshortdate|vblongtime|vbshorttime|vbobjecterror|vbEmpty|vbNull|vbInteger" + "|vbLong|vbSingle|vbDouble|vbCurrency|vbDate|vbString|vbObject|vbError|vbBoolean|vbVariant" - + "|vbDataObject|vbDecimal|vbByte|vbArray" + + "|vbDataObject|vbDecimal|vbByte|vbArray|vbOKOnly|vbOKCancel|vbAbortRetryIgnore|vbYesNoCancel|vbYesNo" + + "|vbRetryCancel|vbCritical|vbQuestion|vbExclamation|vbInformation|vbDefaultButton1|vbDefaultButton2" + + "|vbDefaultButton3|vbDefaultButton4|vbApplicationModal|vbSystemModal" }, "identifier", true); this.$rules = { From d88b088bddb6cf69331433f6b26b78f5b9336ccd Mon Sep 17 00:00:00 2001 From: skacurt Date: Fri, 1 May 2020 14:45:00 +0300 Subject: [PATCH 0368/1293] [vbscript] add missing MsgBoxResult constants --- lib/ace/mode/vbscript_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index 21dc2e70110..05685a3a5cf 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -73,7 +73,7 @@ var VBScriptHighlightRules = function() { + "|vbLong|vbSingle|vbDouble|vbCurrency|vbDate|vbString|vbObject|vbError|vbBoolean|vbVariant" + "|vbDataObject|vbDecimal|vbByte|vbArray|vbOKOnly|vbOKCancel|vbAbortRetryIgnore|vbYesNoCancel|vbYesNo" + "|vbRetryCancel|vbCritical|vbQuestion|vbExclamation|vbInformation|vbDefaultButton1|vbDefaultButton2" - + "|vbDefaultButton3|vbDefaultButton4|vbApplicationModal|vbSystemModal" + + "|vbDefaultButton3|vbDefaultButton4|vbApplicationModal|vbSystemModal|vbOK|vbCancel|vbAbort|vbRetry|vbIgnore|vbYes|vbNo" }, "identifier", true); this.$rules = { From 2bf26a8e4e7625321590971fa00814aa7e5f6776 Mon Sep 17 00:00:00 2001 From: skacurt Date: Fri, 1 May 2020 14:48:22 +0300 Subject: [PATCH 0369/1293] [vbscript] add missing TriState constant: vbUseDefault --- lib/ace/mode/vbscript_highlight_rules.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index 05685a3a5cf..182382cc98b 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -74,6 +74,7 @@ var VBScriptHighlightRules = function() { + "|vbDataObject|vbDecimal|vbByte|vbArray|vbOKOnly|vbOKCancel|vbAbortRetryIgnore|vbYesNoCancel|vbYesNo" + "|vbRetryCancel|vbCritical|vbQuestion|vbExclamation|vbInformation|vbDefaultButton1|vbDefaultButton2" + "|vbDefaultButton3|vbDefaultButton4|vbApplicationModal|vbSystemModal|vbOK|vbCancel|vbAbort|vbRetry|vbIgnore|vbYes|vbNo" + + "|vbUseDefault" }, "identifier", true); this.$rules = { From b4ea7bfbbefef7733abd8df04e49d2d6bffeeee0 Mon Sep 17 00:00:00 2001 From: skacurt Date: Sat, 2 May 2020 12:36:29 +0300 Subject: [PATCH 0370/1293] [vbscript] add missing keywords "Preserve", "Erase", "Execute" and "ExecuteGlobal" --- lib/ace/mode/vbscript_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index 182382cc98b..6c74ac16fe2 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -43,7 +43,7 @@ var VBScriptHighlightRules = function() { var keywordMapper = this.createKeywordMapper({ "keyword.control.asp": "If|Then|Else|ElseIf|End|While|Wend|For|To|Each|Case|Select|Return" + "|Continue|Do|Until|Loop|Next|With|Exit|Function|Property|Type|Enum|Sub|IIf|Class", - "storage.type.asp": "Dim|Call|Const|Redim|Set|Let|Get|New|Randomize|Option|Explicit", + "storage.type.asp": "Dim|Call|Const|Redim|Set|Let|Get|New|Randomize|Option|Explicit|Preserve|Erase|Execute|ExecuteGlobal", "storage.modifier.asp": "Private|Public|Default", "keyword.operator.asp": "Mod|And|Not|Or|Xor|as|Eqv|Imp|Is", "constant.language.asp": "Empty|False|Nothing|Null|True|Me", From 554e460b491042fc344ab88c3cce3924cfe75d29 Mon Sep 17 00:00:00 2001 From: skacurt Date: Sun, 3 May 2020 01:04:47 +0300 Subject: [PATCH 0371/1293] [vbscript] follow Common Tokens guideline, make "Me" keyword a variable.language --- lib/ace/mode/vbscript_highlight_rules.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index 6c74ac16fe2..0bf8d57b1cd 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -46,7 +46,8 @@ var VBScriptHighlightRules = function() { "storage.type.asp": "Dim|Call|Const|Redim|Set|Let|Get|New|Randomize|Option|Explicit|Preserve|Erase|Execute|ExecuteGlobal", "storage.modifier.asp": "Private|Public|Default", "keyword.operator.asp": "Mod|And|Not|Or|Xor|as|Eqv|Imp|Is", - "constant.language.asp": "Empty|False|Nothing|Null|True|Me", + "constant.language.asp": "Empty|False|Nothing|Null|True", + "variable.language.vb.asp": "Me", "support.class.asp": "Application|ObjectContext|Request|Response|Server|Session", "support.class.collection.asp": "Contents|StaticObjects|ClientCertificate|Cookies|Form|QueryString|ServerVariables", "support.constant.asp": "TotalBytes|Buffer|CacheControl|Charset|ContentType|Expires|ExpiresAbsolute" From 503790becbdd69d7576d02ba127b22912ec70aac Mon Sep 17 00:00:00 2001 From: skacurt Date: Sun, 3 May 2020 14:19:37 +0300 Subject: [PATCH 0372/1293] [vbscript] add missing built-in RegExp object support --- lib/ace/mode/vbscript_highlight_rules.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index 0bf8d57b1cd..2a218ad004a 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -48,6 +48,7 @@ var VBScriptHighlightRules = function() { "keyword.operator.asp": "Mod|And|Not|Or|Xor|as|Eqv|Imp|Is", "constant.language.asp": "Empty|False|Nothing|Null|True", "variable.language.vb.asp": "Me", + "support.class.vb.asp": "RegExp", "support.class.asp": "Application|ObjectContext|Request|Response|Server|Session", "support.class.collection.asp": "Contents|StaticObjects|ClientCertificate|Cookies|Form|QueryString|ServerVariables", "support.constant.asp": "TotalBytes|Buffer|CacheControl|Charset|ContentType|Expires|ExpiresAbsolute" From 300c4f5e7cd73bd91ecdf4df3b33e71b0c08ff13 Mon Sep 17 00:00:00 2001 From: skacurt Date: Sun, 3 May 2020 18:44:08 +0300 Subject: [PATCH 0373/1293] [vbscript] preserve official Title and Camel cases in identifiers For the sake of readability --- lib/ace/mode/vbscript_highlight_rules.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/ace/mode/vbscript_highlight_rules.js b/lib/ace/mode/vbscript_highlight_rules.js index 2a218ad004a..9fa2a07f71a 100644 --- a/lib/ace/mode/vbscript_highlight_rules.js +++ b/lib/ace/mode/vbscript_highlight_rules.js @@ -45,7 +45,7 @@ var VBScriptHighlightRules = function() { + "|Continue|Do|Until|Loop|Next|With|Exit|Function|Property|Type|Enum|Sub|IIf|Class", "storage.type.asp": "Dim|Call|Const|Redim|Set|Let|Get|New|Randomize|Option|Explicit|Preserve|Erase|Execute|ExecuteGlobal", "storage.modifier.asp": "Private|Public|Default", - "keyword.operator.asp": "Mod|And|Not|Or|Xor|as|Eqv|Imp|Is", + "keyword.operator.asp": "Mod|And|Not|Or|Xor|As|Eqv|Imp|Is", "constant.language.asp": "Empty|False|Nothing|Null|True", "variable.language.vb.asp": "Me", "support.class.vb.asp": "RegExp", @@ -68,15 +68,15 @@ var VBScriptHighlightRules = function() { + "|ScriptEngineMinorVersion|Second|SetLocale|Sgn|Sin|Space|Split|Sqr|StrComp|String|StrReverse" + "|Tan|Time|Timer|TimeSerial|TimeValue|TypeName|UBound|UCase|Unescape|VarType|Weekday|WeekdayName|Year" + "|AscB|AscW|ChrB|ChrW|InStrB|LeftB|LenB|MidB|RightB|Abs|GetUILanguage", - "support.type.vb.asp": "vbtrue|vbfalse|vbcr|vbcrlf|vbformfeed|vblf|vbnewline|vbnullchar|vbnullstring|" - + "int32|vbtab|vbverticaltab|vbbinarycompare|vbtextcompare|vbsunday|vbmonday|vbtuesday|vbwednesday" - + "|vbthursday|vbfriday|vbsaturday|vbusesystemdayofweek|vbfirstjan1|vbfirstfourdays|vbfirstfullweek" - + "|vbgeneraldate|vblongdate|vbshortdate|vblongtime|vbshorttime|vbobjecterror|vbEmpty|vbNull|vbInteger" + "support.type.vb.asp": "vbTrue|vbFalse|vbCr|vbCrLf|vbFormFeed|vbLf|vbNewLine|vbNullChar|vbNullString" + + "|vbTab|vbVerticalTab|vbBinaryCompare|vbTextCompare|vbSunday|vbMonday|vbTuesday|vbWednesday" + + "|vbThursday|vbFriday|vbSaturday|vbUseSystemDayOfWeek|vbFirstJan1|vbFirstFourDays|vbFirstFullWeek" + + "|vbGeneralDate|vbLongDate|vbShortDate|vbLongTime|vbShortTime|vbObjectError|vbEmpty|vbNull|vbInteger" + "|vbLong|vbSingle|vbDouble|vbCurrency|vbDate|vbString|vbObject|vbError|vbBoolean|vbVariant" + "|vbDataObject|vbDecimal|vbByte|vbArray|vbOKOnly|vbOKCancel|vbAbortRetryIgnore|vbYesNoCancel|vbYesNo" - + "|vbRetryCancel|vbCritical|vbQuestion|vbExclamation|vbInformation|vbDefaultButton1|vbDefaultButton2" - + "|vbDefaultButton3|vbDefaultButton4|vbApplicationModal|vbSystemModal|vbOK|vbCancel|vbAbort|vbRetry|vbIgnore|vbYes|vbNo" - + "|vbUseDefault" + + "|vbRetryCancel|vbCritical|vbQuestion|vbExclamation|vbInformation|vbDefaultButton1|vbDefaultButton2" + + "|vbDefaultButton3|vbDefaultButton4|vbApplicationModal|vbSystemModal|vbOK|vbCancel|vbAbort|vbRetry|vbIgnore|vbYes|vbNo" + + "|vbUseDefault" }, "identifier", true); this.$rules = { From 694c49bf10d3f39554f068dbde80bb107735c8ad Mon Sep 17 00:00:00 2001 From: skacurt Date: Sun, 3 May 2020 17:49:11 +0300 Subject: [PATCH 0374/1293] [vbscript] make the test conforming to new tokens --- lib/ace/mode/_test/tokens_vbscript.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ace/mode/_test/tokens_vbscript.json b/lib/ace/mode/_test/tokens_vbscript.json index b06c245b376..3cc4dbe22db 100644 --- a/lib/ace/mode/_test/tokens_vbscript.json +++ b/lib/ace/mode/_test/tokens_vbscript.json @@ -79,7 +79,7 @@ ["punctuation.definition.string.begin.asp","\""], ["string.quoted.double.asp"," exists ... OK to overwrite?\""], ["text",", "], - ["identifier","vbOKCancel"], + ["support.type.vb.asp","vbOKCancel"], ["text",")"] ],[ "start", @@ -106,7 +106,7 @@ ["text"," "], ["keyword.operator.asp","<>"], ["text"," "], - ["identifier","vbOK"], + ["support.type.vb.asp","vbOK"], ["text"," "], ["keyword.control.asp","Then"], ["text"," "], @@ -148,7 +148,7 @@ ["punctuation.definition.string.begin.asp","\""], ["string.quoted.double.asp"," ... OK to create?\""], ["text",", "], - ["identifier","vbOKCancel"], + ["support.type.vb.asp","vbOKCancel"], ["text",")"] ],[ "start", @@ -161,7 +161,7 @@ ["text"," "], ["keyword.operator.asp","<>"], ["text"," "], - ["identifier","vbOK"], + ["support.type.vb.asp","vbOK"], ["text"," "], ["keyword.control.asp","Then"], ["text"," "], From 39bf32a94c81ad17b00f58f11716084780b12aee Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 7 Jun 2020 17:47:12 +0400 Subject: [PATCH 0375/1293] add more folding commands --- lib/ace/commands/default_commands.js | 18 +++++++++ lib/ace/edit_session/folding.js | 58 +++++++++++++++++----------- lib/ace/edit_session_test.js | 24 ++++++++++++ 3 files changed, 78 insertions(+), 22 deletions(-) diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index fa6276ff64c..45058913b1c 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -131,6 +131,13 @@ exports.commands = [{ exec: function(editor) { editor.session.foldAll(); }, scrollIntoView: "center", readOnly: true +}, { + name: "foldAllComments", + description: "Fold all comments", + bindKey: bindKey(null, "Ctrl-Command-Option-0"), + exec: function(editor) { editor.session.foldAllComments(); }, + scrollIntoView: "center", + readOnly: true }, { name: "foldOther", description: "Fold other", @@ -884,4 +891,15 @@ exports.commands = [{ readOnly: true }]; +for (var i = 1; i < 9; i++) { + exports.commands.push({ + name: "foldToLevel" + i, + description: "Fold To Level " + i, + level: i, + exec: function(editor) { editor.session.foldToLevel(this.level); }, + scrollIntoView: "center", + readOnly: true + }); +} + }); diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index 7197cd7a25c..4c095621674 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -296,9 +296,11 @@ function Folding() { // Remove the folds from fold data. this.removeFolds(folds); // Add the removed folds as subfolds on the new fold. - folds.forEach(function(subFold) { - fold.addSubFold(subFold); - }); + if (!fold.collapseChildren) { + folds.forEach(function(subFold) { + fold.addSubFold(subFold); + }); + } } for (var i = 0; i < foldData.length; i++) { @@ -436,7 +438,7 @@ function Folding() { var range, folds; if (location == null) { range = new Range(0, 0, this.getLength(), 0); - expandInner = true; + if (expandInner == null) expandInner = true; } else if (typeof location == "number") range = new Range(location, 0, location, this.getLine(location).length); else if ("row" in location) @@ -445,16 +447,10 @@ function Folding() { range = location; folds = this.getFoldsInRangeList(range); - if (expandInner) { + if (expandInner != false) { this.removeFolds(folds); } else { - var subFolds = folds; - // TODO: might be better to remove and add folds in one go instead of using - // expandFolds several times. - while (subFolds.length) { - this.expandFolds(subFolds); - subFolds = this.getFoldsInRangeList(range); - } + this.expandFolds(folds); } if (folds.length) return folds; @@ -599,7 +595,7 @@ function Folding() { this.getCommentFoldRange = function(row, column, dir) { var iterator = new TokenIterator(this, row, column); var token = iterator.getCurrentToken(); - var type = token.type; + var type = token && token.type; if (token && /^comment|string/.test(type)) { type = type.match(/comment|string/)[0]; if (type == "comment") @@ -640,7 +636,7 @@ function Folding() { } }; - this.foldAll = function(startRow, endRow, depth) { + this.foldAll = function(startRow, endRow, depth, test) { if (depth == undefined) depth = 100000; // JSON.stringify doesn't hanle Infinity var foldWidgets = this.foldWidgets; @@ -653,25 +649,43 @@ function Folding() { foldWidgets[row] = this.getFoldWidget(row); if (foldWidgets[row] != "start") continue; + + if (test && !test(row)) continue; var range = this.getFoldWidgetRange(row); - // sometimes range can be incompatible with existing fold - // TODO change addFold to return null istead of throwing if (range && range.isMultiLine() && range.end.row <= endRow && range.start.row >= startRow ) { row = range.end.row; - try { - // addFold can change the range - var fold = this.addFold("...", range); - if (fold) - fold.collapseChildren = depth; - } catch(e) {} + range.collapseChildren = depth; + // addFold can change the range + this.addFold("...", range); } } }; + this.foldToLevel = function(level) { + this.foldAll(); + while (level-- > 0) + this.unfold(null, false); + }; + + this.foldAllComments = function() { + var session = this; + this.foldAll(null, null, null, function(row) { + var tokens = session.getTokens(row); + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + if (token.type == "text" && /^\s+$/.test(token.value)) + continue; + if (/comment/.test(token.type)) + return true; + return false; + } + }); + }; + // structured folding this.$foldStyles = { "manual": 1, diff --git a/lib/ace/edit_session_test.js b/lib/ace/edit_session_test.js index 9439ee523d5..8d89dfbb08b 100644 --- a/lib/ace/edit_session_test.js +++ b/lib/ace/edit_session_test.js @@ -502,6 +502,30 @@ module.exports = { assert.equal(session.doc.getValue(), ["", "foo"].join("\n")); }, + + "test foldAll": function() { + var session = createFoldTestSession(); + var editor = new Editor(new MockRenderer(), session); + var value = " /*\n*comment\n*/\n" + editor.getValue() + "\n"; + editor.setValue(value + value, 1); + editor.setOption("mode", new JavaScriptMode()); + + editor.execCommand("foldToLevel1"); + assert.equal(session.$foldData.length, 2); + editor.execCommand("foldAllComments"); + assert.equal(session.$foldData.length, 4); + editor.execCommand("foldall"); + assert.equal(session.$foldData.length, 4); + assert.equal(session.$foldData[1].range.start.row, 3); + assert.equal(session.$foldData[3].range.start.row, 11); + editor.execCommand("golineup"); + editor.execCommand("gotolineend"); + editor.execCommand("unfold"); + assert.equal(session.$foldData.length, 4); + assert.equal(session.$foldData[3].range.start.row, 12); + editor.execCommand("unfoldall"); + assert.equal(session.$foldData.length, 0); + }, "test fold getFoldDisplayLine": function() { var session = createFoldTestSession(); From 5834d8ff8f7e29357bb7131cc362d8bc703b1eab Mon Sep 17 00:00:00 2001 From: Sjon Hortensius Date: Fri, 4 Oct 2019 11:59:14 +0200 Subject: [PATCH 0376/1293] Support PHP 7.4 syntax this repeats #3107, but for 7.4, instead of the kmyacc binary I used https://github.com/ircmaxell/PHP-Yacc here is the rebuildParser that I used: ``` &1')), '"', "\n"; preg_match_all('/T_\w+/', $tokens, $matches); foreach ($matches[0] as $match) echo '"' . $match . '",'; echo "\n". str_repeat('-', 45). "\n"; foreach ($matches[0] as $match) if (NULL != constant($match)) echo 'PHP.Constants.' . $match . ' = ' . constant($match) . "\n"; ``` --- lib/ace/mode/php/php.js | 1613 ++++++++++++++++++++------------------- 1 file changed, 841 insertions(+), 772 deletions(-) diff --git a/lib/ace/mode/php/php.js b/lib/ace/mode/php/php.js index 6d08b30302e..29f4c05699b 100644 --- a/lib/ace/mode/php/php.js +++ b/lib/ace/mode/php/php.js @@ -21,141 +21,143 @@ define(function(require, exports, module) { var PHP = {Constants:{}}; -PHP.Constants.T_INCLUDE = 257; -PHP.Constants.T_INCLUDE_ONCE = 258; -PHP.Constants.T_EVAL = 259; -PHP.Constants.T_REQUIRE = 260; -PHP.Constants.T_REQUIRE_ONCE = 261; -PHP.Constants.T_LOGICAL_OR = 262; -PHP.Constants.T_LOGICAL_XOR = 263; -PHP.Constants.T_LOGICAL_AND = 264; -PHP.Constants.T_PRINT = 265; -PHP.Constants.T_YIELD = 266; -PHP.Constants.T_DOUBLE_ARROW = 267; -PHP.Constants.T_YIELD_FROM = 268; -PHP.Constants.T_PLUS_EQUAL = 269; -PHP.Constants.T_MINUS_EQUAL = 270; -PHP.Constants.T_MUL_EQUAL = 271; -PHP.Constants.T_DIV_EQUAL = 272; -PHP.Constants.T_CONCAT_EQUAL = 273; -PHP.Constants.T_MOD_EQUAL = 274; -PHP.Constants.T_AND_EQUAL = 275; -PHP.Constants.T_OR_EQUAL = 276; -PHP.Constants.T_XOR_EQUAL = 277; -PHP.Constants.T_SL_EQUAL = 278; -PHP.Constants.T_SR_EQUAL = 279; -PHP.Constants.T_POW_EQUAL = 280; -PHP.Constants.T_COALESCE = 281; -PHP.Constants.T_BOOLEAN_OR = 282; -PHP.Constants.T_BOOLEAN_AND = 283; -PHP.Constants.T_IS_EQUAL = 284; -PHP.Constants.T_IS_NOT_EQUAL = 285; -PHP.Constants.T_IS_IDENTICAL = 286; -PHP.Constants.T_IS_NOT_IDENTICAL = 287; -PHP.Constants.T_SPACESHIP = 288; -PHP.Constants.T_IS_SMALLER_OR_EQUAL = 289; -PHP.Constants.T_IS_GREATER_OR_EQUAL = 290; -PHP.Constants.T_SL = 291; -PHP.Constants.T_SR = 292; -PHP.Constants.T_INSTANCEOF = 293; -PHP.Constants.T_INC = 294; -PHP.Constants.T_DEC = 295; -PHP.Constants.T_INT_CAST = 296; -PHP.Constants.T_DOUBLE_CAST = 297; -PHP.Constants.T_STRING_CAST = 298; -PHP.Constants.T_ARRAY_CAST = 299; -PHP.Constants.T_OBJECT_CAST = 300; -PHP.Constants.T_BOOL_CAST = 301; -PHP.Constants.T_UNSET_CAST = 302; -PHP.Constants.T_POW = 303; -PHP.Constants.T_NEW = 304; -PHP.Constants.T_CLONE = 305; -PHP.Constants.T_EXIT = 306; -PHP.Constants.T_IF = 307; -PHP.Constants.T_ELSEIF = 308; -PHP.Constants.T_ELSE = 309; -PHP.Constants.T_ENDIF = 310; -PHP.Constants.T_LNUMBER = 311; -PHP.Constants.T_DNUMBER = 312; -PHP.Constants.T_STRING = 313; -PHP.Constants.T_STRING_VARNAME = 314; -PHP.Constants.T_VARIABLE = 315; -PHP.Constants.T_NUM_STRING = 316; -PHP.Constants.T_INLINE_HTML = 317; -PHP.Constants.T_CHARACTER = 318; -PHP.Constants.T_BAD_CHARACTER = 319; -PHP.Constants.T_ENCAPSED_AND_WHITESPACE = 320; -PHP.Constants.T_CONSTANT_ENCAPSED_STRING = 321; -PHP.Constants.T_ECHO = 322; -PHP.Constants.T_DO = 323; -PHP.Constants.T_WHILE = 324; -PHP.Constants.T_ENDWHILE = 325; -PHP.Constants.T_FOR = 326; -PHP.Constants.T_ENDFOR = 327; -PHP.Constants.T_FOREACH = 328; -PHP.Constants.T_ENDFOREACH = 329; -PHP.Constants.T_DECLARE = 330; -PHP.Constants.T_ENDDECLARE = 331; -PHP.Constants.T_AS = 332; -PHP.Constants.T_SWITCH = 333; -PHP.Constants.T_ENDSWITCH = 334; -PHP.Constants.T_CASE = 335; -PHP.Constants.T_DEFAULT = 336; -PHP.Constants.T_BREAK = 337; -PHP.Constants.T_CONTINUE = 338; -PHP.Constants.T_GOTO = 339; -PHP.Constants.T_FUNCTION = 340; -PHP.Constants.T_CONST = 341; -PHP.Constants.T_RETURN = 342; -PHP.Constants.T_TRY = 343; -PHP.Constants.T_CATCH = 344; -PHP.Constants.T_FINALLY = 345; -PHP.Constants.T_THROW = 346; -PHP.Constants.T_USE = 347; -PHP.Constants.T_INSTEADOF = 348; -PHP.Constants.T_GLOBAL = 349; -PHP.Constants.T_STATIC = 350; -PHP.Constants.T_ABSTRACT = 351; -PHP.Constants.T_FINAL = 352; -PHP.Constants.T_PRIVATE = 353; -PHP.Constants.T_PROTECTED = 354; -PHP.Constants.T_PUBLIC = 355; -PHP.Constants.T_VAR = 356; -PHP.Constants.T_UNSET = 357; -PHP.Constants.T_ISSET = 358; -PHP.Constants.T_EMPTY = 359; -PHP.Constants.T_HALT_COMPILER = 360; -PHP.Constants.T_CLASS = 361; -PHP.Constants.T_TRAIT = 362; -PHP.Constants.T_INTERFACE = 363; -PHP.Constants.T_EXTENDS = 364; -PHP.Constants.T_IMPLEMENTS = 365; -PHP.Constants.T_OBJECT_OPERATOR = 366; -PHP.Constants.T_LIST = 367; -PHP.Constants.T_ARRAY = 368; -PHP.Constants.T_CALLABLE = 369; -PHP.Constants.T_CLASS_C = 370; -PHP.Constants.T_TRAIT_C = 371; -PHP.Constants.T_METHOD_C = 372; -PHP.Constants.T_FUNC_C = 373; -PHP.Constants.T_LINE = 374; -PHP.Constants.T_FILE = 375; -PHP.Constants.T_COMMENT = 376; -PHP.Constants.T_DOC_COMMENT = 377; -PHP.Constants.T_OPEN_TAG = 378; -PHP.Constants.T_OPEN_TAG_WITH_ECHO = 379; -PHP.Constants.T_CLOSE_TAG = 380; -PHP.Constants.T_WHITESPACE = 381; -PHP.Constants.T_START_HEREDOC = 382; -PHP.Constants.T_END_HEREDOC = 383; -PHP.Constants.T_DOLLAR_OPEN_CURLY_BRACES = 384; -PHP.Constants.T_CURLY_OPEN = 385; -PHP.Constants.T_PAAMAYIM_NEKUDOTAYIM = 386; -PHP.Constants.T_NAMESPACE = 387; -PHP.Constants.T_NS_C = 388; -PHP.Constants.T_DIR = 389; -PHP.Constants.T_NS_SEPARATOR = 390; -PHP.Constants.T_ELLIPSIS = 391; +PHP.Constants.T_INCLUDE = 259 +PHP.Constants.T_INCLUDE_ONCE = 260 +PHP.Constants.T_EVAL = 318 +PHP.Constants.T_REQUIRE = 261 +PHP.Constants.T_REQUIRE_ONCE = 262 +PHP.Constants.T_LOGICAL_OR = 263 +PHP.Constants.T_LOGICAL_XOR = 264 +PHP.Constants.T_LOGICAL_AND = 265 +PHP.Constants.T_PRINT = 266 +PHP.Constants.T_YIELD = 267 +PHP.Constants.T_DOUBLE_ARROW = 268 +PHP.Constants.T_YIELD_FROM = 269 +PHP.Constants.T_PLUS_EQUAL = 270 +PHP.Constants.T_MINUS_EQUAL = 271 +PHP.Constants.T_MUL_EQUAL = 272 +PHP.Constants.T_DIV_EQUAL = 273 +PHP.Constants.T_CONCAT_EQUAL = 274 +PHP.Constants.T_MOD_EQUAL = 275 +PHP.Constants.T_AND_EQUAL = 276 +PHP.Constants.T_OR_EQUAL = 277 +PHP.Constants.T_XOR_EQUAL = 278 +PHP.Constants.T_SL_EQUAL = 279 +PHP.Constants.T_SR_EQUAL = 280 +PHP.Constants.T_POW_EQUAL = 281 +PHP.Constants.T_COALESCE_EQUAL = 282 +PHP.Constants.T_COALESCE = 283 +PHP.Constants.T_BOOLEAN_OR = 284 +PHP.Constants.T_BOOLEAN_AND = 285 +PHP.Constants.T_IS_EQUAL = 286 +PHP.Constants.T_IS_NOT_EQUAL = 287 +PHP.Constants.T_IS_IDENTICAL = 288 +PHP.Constants.T_IS_NOT_IDENTICAL = 289 +PHP.Constants.T_SPACESHIP = 290 +PHP.Constants.T_IS_SMALLER_OR_EQUAL = 291 +PHP.Constants.T_IS_GREATER_OR_EQUAL = 292 +PHP.Constants.T_SL = 293 +PHP.Constants.T_SR = 294 +PHP.Constants.T_INSTANCEOF = 295 +PHP.Constants.T_INC = 319 +PHP.Constants.T_DEC = 320 +PHP.Constants.T_INT_CAST = 296 +PHP.Constants.T_DOUBLE_CAST = 297 +PHP.Constants.T_STRING_CAST = 298 +PHP.Constants.T_ARRAY_CAST = 299 +PHP.Constants.T_OBJECT_CAST = 300 +PHP.Constants.T_BOOL_CAST = 301 +PHP.Constants.T_UNSET_CAST = 302 +PHP.Constants.T_POW = 303 +PHP.Constants.T_NEW = 304 +PHP.Constants.T_CLONE = 305 +PHP.Constants.T_EXIT = 321 +PHP.Constants.T_IF = 322 +PHP.Constants.T_ELSEIF = 307 +PHP.Constants.T_ELSE = 308 +PHP.Constants.T_ENDIF = 323 +PHP.Constants.T_LNUMBER = 309 +PHP.Constants.T_DNUMBER = 310 +PHP.Constants.T_STRING = 311 +PHP.Constants.T_STRING_VARNAME = 316 +PHP.Constants.T_VARIABLE = 312 +PHP.Constants.T_NUM_STRING = 317 +PHP.Constants.T_INLINE_HTML = 313 +PHP.Constants.T_BAD_CHARACTER = 395 +PHP.Constants.T_ENCAPSED_AND_WHITESPACE = 314 +PHP.Constants.T_CONSTANT_ENCAPSED_STRING = 315 +PHP.Constants.T_ECHO = 324 +PHP.Constants.T_DO = 325 +PHP.Constants.T_WHILE = 326 +PHP.Constants.T_ENDWHILE = 327 +PHP.Constants.T_FOR = 328 +PHP.Constants.T_ENDFOR = 329 +PHP.Constants.T_FOREACH = 330 +PHP.Constants.T_ENDFOREACH = 331 +PHP.Constants.T_DECLARE = 332 +PHP.Constants.T_ENDDECLARE = 333 +PHP.Constants.T_AS = 334 +PHP.Constants.T_SWITCH = 335 +PHP.Constants.T_ENDSWITCH = 336 +PHP.Constants.T_CASE = 337 +PHP.Constants.T_DEFAULT = 338 +PHP.Constants.T_BREAK = 339 +PHP.Constants.T_CONTINUE = 340 +PHP.Constants.T_GOTO = 341 +PHP.Constants.T_FUNCTION = 342 +PHP.Constants.T_FN = 343 +PHP.Constants.T_CONST = 344 +PHP.Constants.T_RETURN = 345 +PHP.Constants.T_TRY = 346 +PHP.Constants.T_CATCH = 347 +PHP.Constants.T_FINALLY = 348 +PHP.Constants.T_THROW = 349 +PHP.Constants.T_USE = 350 +PHP.Constants.T_INSTEADOF = 351 +PHP.Constants.T_GLOBAL = 352 +PHP.Constants.T_STATIC = 353 +PHP.Constants.T_ABSTRACT = 354 +PHP.Constants.T_FINAL = 355 +PHP.Constants.T_PRIVATE = 356 +PHP.Constants.T_PROTECTED = 357 +PHP.Constants.T_PUBLIC = 358 +PHP.Constants.T_VAR = 359 +PHP.Constants.T_UNSET = 360 +PHP.Constants.T_ISSET = 361 +PHP.Constants.T_EMPTY = 362 +PHP.Constants.T_HALT_COMPILER = 363 +PHP.Constants.T_CLASS = 364 +PHP.Constants.T_TRAIT = 365 +PHP.Constants.T_INTERFACE = 366 +PHP.Constants.T_EXTENDS = 367 +PHP.Constants.T_IMPLEMENTS = 368 +PHP.Constants.T_OBJECT_OPERATOR = 369 +PHP.Constants.T_DOUBLE_ARROW = 268 +PHP.Constants.T_LIST = 370 +PHP.Constants.T_ARRAY = 371 +PHP.Constants.T_CALLABLE = 372 +PHP.Constants.T_CLASS_C = 376 +PHP.Constants.T_TRAIT_C = 377 +PHP.Constants.T_METHOD_C = 378 +PHP.Constants.T_FUNC_C = 379 +PHP.Constants.T_LINE = 373 +PHP.Constants.T_FILE = 374 +PHP.Constants.T_COMMENT = 380 +PHP.Constants.T_DOC_COMMENT = 381 +PHP.Constants.T_OPEN_TAG = 382 +PHP.Constants.T_OPEN_TAG_WITH_ECHO = 383 +PHP.Constants.T_CLOSE_TAG = 384 +PHP.Constants.T_WHITESPACE = 385 +PHP.Constants.T_START_HEREDOC = 386 +PHP.Constants.T_END_HEREDOC = 387 +PHP.Constants.T_DOLLAR_OPEN_CURLY_BRACES = 388 +PHP.Constants.T_CURLY_OPEN = 389 +PHP.Constants.T_PAAMAYIM_NEKUDOTAYIM = 390 +PHP.Constants.T_NAMESPACE = 391 +PHP.Constants.T_NS_C = 392 +PHP.Constants.T_DIR = 375 +PHP.Constants.T_NS_SEPARATOR = 393 +PHP.Constants.T_ELLIPSIS = 394 PHP.Lexer = function(src, ini) { var heredoc, heredocEndAllowed, @@ -376,6 +378,10 @@ PHP.Lexer = function(src, ini) { value: PHP.Constants.T_FINALLY, re: /^finally\b/i }, + { + value: PHP.Constants.T_FN, + re: /^fn\b/i + }, { value: PHP.Constants.T_FOR, re: /^for\b/i @@ -1293,7 +1299,7 @@ PHP.Parser.prototype.getNextToken = function( ) { }; PHP.Parser.prototype.tokenName = function( token ) { - var constants = ["T_INCLUDE","T_INCLUDE_ONCE","T_EVAL","T_REQUIRE","T_REQUIRE_ONCE","T_LOGICAL_OR","T_LOGICAL_XOR","T_LOGICAL_AND","T_PRINT","T_YIELD","T_DOUBLE_ARROW","T_YIELD_FROM","T_PLUS_EQUAL","T_MINUS_EQUAL","T_MUL_EQUAL","T_DIV_EQUAL","T_CONCAT_EQUAL","T_MOD_EQUAL","T_AND_EQUAL","T_OR_EQUAL","T_XOR_EQUAL","T_SL_EQUAL","T_SR_EQUAL","T_POW_EQUAL","T_COALESCE","T_BOOLEAN_OR","T_BOOLEAN_AND","T_IS_EQUAL","T_IS_NOT_EQUAL","T_IS_IDENTICAL","T_IS_NOT_IDENTICAL","T_SPACESHIP","T_IS_SMALLER_OR_EQUAL","T_IS_GREATER_OR_EQUAL","T_SL","T_SR","T_INSTANCEOF","T_INC","T_DEC","T_INT_CAST","T_DOUBLE_CAST","T_STRING_CAST","T_ARRAY_CAST","T_OBJECT_CAST","T_BOOL_CAST","T_UNSET_CAST","T_POW","T_NEW","T_CLONE","T_EXIT","T_IF","T_ELSEIF","T_ELSE","T_ENDIF","T_LNUMBER","T_DNUMBER","T_STRING","T_STRING_VARNAME","T_VARIABLE","T_NUM_STRING","T_INLINE_HTML","T_CHARACTER","T_BAD_CHARACTER","T_ENCAPSED_AND_WHITESPACE","T_CONSTANT_ENCAPSED_STRING","T_ECHO","T_DO","T_WHILE","T_ENDWHILE","T_FOR","T_ENDFOR","T_FOREACH","T_ENDFOREACH","T_DECLARE","T_ENDDECLARE","T_AS","T_SWITCH","T_ENDSWITCH","T_CASE","T_DEFAULT","T_BREAK","T_CONTINUE","T_GOTO","T_FUNCTION","T_CONST","T_RETURN","T_TRY","T_CATCH","T_FINALLY","T_THROW","T_USE","T_INSTEADOF","T_GLOBAL","T_STATIC","T_ABSTRACT","T_FINAL","T_PRIVATE","T_PROTECTED","T_PUBLIC","T_VAR","T_UNSET","T_ISSET","T_EMPTY","T_HALT_COMPILER","T_CLASS","T_TRAIT","T_INTERFACE","T_EXTENDS","T_IMPLEMENTS","T_OBJECT_OPERATOR","T_DOUBLE_ARROW","T_LIST","T_ARRAY","T_CALLABLE","T_CLASS_C","T_TRAIT_C","T_METHOD_C","T_FUNC_C","T_LINE","T_FILE","T_COMMENT","T_DOC_COMMENT","T_OPEN_TAG","T_OPEN_TAG_WITH_ECHO","T_CLOSE_TAG","T_WHITESPACE","T_START_HEREDOC","T_END_HEREDOC","T_DOLLAR_OPEN_CURLY_BRACES","T_CURLY_OPEN","T_PAAMAYIM_NEKUDOTAYIM","T_NAMESPACE","T_NS_C","T_DIR","T_NS_SEPARATOR","T_ELLIPSIS"]; + var constants = ["T_INCLUDE","T_INCLUDE_ONCE","T_EVAL","T_REQUIRE","T_REQUIRE_ONCE","T_LOGICAL_OR","T_LOGICAL_XOR","T_LOGICAL_AND","T_PRINT","T_YIELD","T_DOUBLE_ARROW","T_YIELD_FROM","T_PLUS_EQUAL","T_MINUS_EQUAL","T_MUL_EQUAL","T_DIV_EQUAL","T_CONCAT_EQUAL","T_MOD_EQUAL","T_AND_EQUAL","T_OR_EQUAL","T_XOR_EQUAL","T_SL_EQUAL","T_SR_EQUAL","T_POW_EQUAL","T_COALESCE_EQUAL","T_COALESCE","T_BOOLEAN_OR","T_BOOLEAN_AND","T_IS_EQUAL","T_IS_NOT_EQUAL","T_IS_IDENTICAL","T_IS_NOT_IDENTICAL","T_SPACESHIP","T_IS_SMALLER_OR_EQUAL","T_IS_GREATER_OR_EQUAL","T_SL","T_SR","T_INSTANCEOF","T_INC","T_DEC","T_INT_CAST","T_DOUBLE_CAST","T_STRING_CAST","T_ARRAY_CAST","T_OBJECT_CAST","T_BOOL_CAST","T_UNSET_CAST","T_POW","T_NEW","T_CLONE","T_EXIT","T_IF","T_ELSEIF","T_ELSE","T_ENDIF","T_LNUMBER","T_DNUMBER","T_STRING","T_STRING_VARNAME","T_VARIABLE","T_NUM_STRING","T_INLINE_HTML","T_CHARACTER","T_BAD_CHARACTER","T_ENCAPSED_AND_WHITESPACE","T_CONSTANT_ENCAPSED_STRING","T_ECHO","T_DO","T_WHILE","T_ENDWHILE","T_FOR","T_ENDFOR","T_FOREACH","T_ENDFOREACH","T_DECLARE","T_ENDDECLARE","T_AS","T_SWITCH","T_ENDSWITCH","T_CASE","T_DEFAULT","T_BREAK","T_CONTINUE","T_GOTO","T_FUNCTION","T_FN","T_CONST","T_RETURN","T_TRY","T_CATCH","T_FINALLY","T_THROW","T_USE","T_INSTEADOF","T_GLOBAL","T_STATIC","T_ABSTRACT","T_FINAL","T_PRIVATE","T_PROTECTED","T_PUBLIC","T_VAR","T_UNSET","T_ISSET","T_EMPTY","T_HALT_COMPILER","T_CLASS","T_TRAIT","T_INTERFACE","T_EXTENDS","T_IMPLEMENTS","T_OBJECT_OPERATOR","T_DOUBLE_ARROW","T_LIST","T_ARRAY","T_CALLABLE","T_CLASS_C","T_TRAIT_C","T_METHOD_C","T_FUNC_C","T_LINE","T_FILE","T_COMMENT","T_DOC_COMMENT","T_OPEN_TAG","T_OPEN_TAG_WITH_ECHO","T_CLOSE_TAG","T_WHITESPACE","T_START_HEREDOC","T_END_HEREDOC","T_DOLLAR_OPEN_CURLY_BRACES","T_CURLY_OPEN","T_PAAMAYIM_NEKUDOTAYIM","T_NAMESPACE","T_NS_C","T_DIR","T_NS_SEPARATOR","T_ELLIPSIS"]; var current = "UNKNOWN"; constants.some(function( constant ) { if (PHP.Constants[ constant ] === token) { @@ -1339,6 +1345,7 @@ PHP.Parser.prototype.createTokenMap = function() { }; + /* This is an automatically GENERATED file, which should not be manually edited. * Instead edit one of the following: * * the grammar file grammar/zend_language_parser.jsy @@ -1351,14 +1358,14 @@ PHP.Parser.prototype.createTokenMap = function() { */ PHP.Parser.prototype.TOKEN_NONE = -1; -PHP.Parser.prototype.TOKEN_INVALID = 157; +PHP.Parser.prototype.TOKEN_INVALID = 159; -PHP.Parser.prototype.TOKEN_MAP_SIZE = 392; +PHP.Parser.prototype.TOKEN_MAP_SIZE = 394; -PHP.Parser.prototype.YYLAST = 889; -PHP.Parser.prototype.YY2TBLSTATE = 337; -PHP.Parser.prototype.YYGLAST = 410; -PHP.Parser.prototype.YYNLSTATES = 564; +PHP.Parser.prototype.YYLAST = 964; +PHP.Parser.prototype.YY2TBLSTATE = 348; +PHP.Parser.prototype.YYGLAST = 508; +PHP.Parser.prototype.YYNLSTATES = 602; PHP.Parser.prototype.YYUNEXPECTED = 32767; PHP.Parser.prototype.YYDEFAULT = -32766; @@ -1388,122 +1395,124 @@ PHP.Parser.prototype.T_XOR_EQUAL = 277; PHP.Parser.prototype.T_SL_EQUAL = 278; PHP.Parser.prototype.T_SR_EQUAL = 279; PHP.Parser.prototype.T_POW_EQUAL = 280; -PHP.Parser.prototype.T_COALESCE = 281; -PHP.Parser.prototype.T_BOOLEAN_OR = 282; -PHP.Parser.prototype.T_BOOLEAN_AND = 283; -PHP.Parser.prototype.T_IS_EQUAL = 284; -PHP.Parser.prototype.T_IS_NOT_EQUAL = 285; -PHP.Parser.prototype.T_IS_IDENTICAL = 286; -PHP.Parser.prototype.T_IS_NOT_IDENTICAL = 287; -PHP.Parser.prototype.T_SPACESHIP = 288; -PHP.Parser.prototype.T_IS_SMALLER_OR_EQUAL = 289; -PHP.Parser.prototype.T_IS_GREATER_OR_EQUAL = 290; -PHP.Parser.prototype.T_SL = 291; -PHP.Parser.prototype.T_SR = 292; -PHP.Parser.prototype.T_INSTANCEOF = 293; -PHP.Parser.prototype.T_INC = 294; -PHP.Parser.prototype.T_DEC = 295; -PHP.Parser.prototype.T_INT_CAST = 296; -PHP.Parser.prototype.T_DOUBLE_CAST = 297; -PHP.Parser.prototype.T_STRING_CAST = 298; -PHP.Parser.prototype.T_ARRAY_CAST = 299; -PHP.Parser.prototype.T_OBJECT_CAST = 300; -PHP.Parser.prototype.T_BOOL_CAST = 301; -PHP.Parser.prototype.T_UNSET_CAST = 302; -PHP.Parser.prototype.T_POW = 303; -PHP.Parser.prototype.T_NEW = 304; -PHP.Parser.prototype.T_CLONE = 305; -PHP.Parser.prototype.T_EXIT = 306; -PHP.Parser.prototype.T_IF = 307; -PHP.Parser.prototype.T_ELSEIF = 308; -PHP.Parser.prototype.T_ELSE = 309; -PHP.Parser.prototype.T_ENDIF = 310; -PHP.Parser.prototype.T_LNUMBER = 311; -PHP.Parser.prototype.T_DNUMBER = 312; -PHP.Parser.prototype.T_STRING = 313; -PHP.Parser.prototype.T_STRING_VARNAME = 314; -PHP.Parser.prototype.T_VARIABLE = 315; -PHP.Parser.prototype.T_NUM_STRING = 316; -PHP.Parser.prototype.T_INLINE_HTML = 317; -PHP.Parser.prototype.T_CHARACTER = 318; -PHP.Parser.prototype.T_BAD_CHARACTER = 319; -PHP.Parser.prototype.T_ENCAPSED_AND_WHITESPACE = 320; -PHP.Parser.prototype.T_CONSTANT_ENCAPSED_STRING = 321; -PHP.Parser.prototype.T_ECHO = 322; -PHP.Parser.prototype.T_DO = 323; -PHP.Parser.prototype.T_WHILE = 324; -PHP.Parser.prototype.T_ENDWHILE = 325; -PHP.Parser.prototype.T_FOR = 326; -PHP.Parser.prototype.T_ENDFOR = 327; -PHP.Parser.prototype.T_FOREACH = 328; -PHP.Parser.prototype.T_ENDFOREACH = 329; -PHP.Parser.prototype.T_DECLARE = 330; -PHP.Parser.prototype.T_ENDDECLARE = 331; -PHP.Parser.prototype.T_AS = 332; -PHP.Parser.prototype.T_SWITCH = 333; -PHP.Parser.prototype.T_ENDSWITCH = 334; -PHP.Parser.prototype.T_CASE = 335; -PHP.Parser.prototype.T_DEFAULT = 336; -PHP.Parser.prototype.T_BREAK = 337; -PHP.Parser.prototype.T_CONTINUE = 338; -PHP.Parser.prototype.T_GOTO = 339; -PHP.Parser.prototype.T_FUNCTION = 340; -PHP.Parser.prototype.T_CONST = 341; -PHP.Parser.prototype.T_RETURN = 342; -PHP.Parser.prototype.T_TRY = 343; -PHP.Parser.prototype.T_CATCH = 344; -PHP.Parser.prototype.T_FINALLY = 345; -PHP.Parser.prototype.T_THROW = 346; -PHP.Parser.prototype.T_USE = 347; -PHP.Parser.prototype.T_INSTEADOF = 348; -PHP.Parser.prototype.T_GLOBAL = 349; -PHP.Parser.prototype.T_STATIC = 350; -PHP.Parser.prototype.T_ABSTRACT = 351; -PHP.Parser.prototype.T_FINAL = 352; -PHP.Parser.prototype.T_PRIVATE = 353; -PHP.Parser.prototype.T_PROTECTED = 354; -PHP.Parser.prototype.T_PUBLIC = 355; -PHP.Parser.prototype.T_VAR = 356; -PHP.Parser.prototype.T_UNSET = 357; -PHP.Parser.prototype.T_ISSET = 358; -PHP.Parser.prototype.T_EMPTY = 359; -PHP.Parser.prototype.T_HALT_COMPILER = 360; -PHP.Parser.prototype.T_CLASS = 361; -PHP.Parser.prototype.T_TRAIT = 362; -PHP.Parser.prototype.T_INTERFACE = 363; -PHP.Parser.prototype.T_EXTENDS = 364; -PHP.Parser.prototype.T_IMPLEMENTS = 365; -PHP.Parser.prototype.T_OBJECT_OPERATOR = 366; -PHP.Parser.prototype.T_LIST = 367; -PHP.Parser.prototype.T_ARRAY = 368; -PHP.Parser.prototype.T_CALLABLE = 369; -PHP.Parser.prototype.T_CLASS_C = 370; -PHP.Parser.prototype.T_TRAIT_C = 371; -PHP.Parser.prototype.T_METHOD_C = 372; -PHP.Parser.prototype.T_FUNC_C = 373; -PHP.Parser.prototype.T_LINE = 374; -PHP.Parser.prototype.T_FILE = 375; -PHP.Parser.prototype.T_COMMENT = 376; -PHP.Parser.prototype.T_DOC_COMMENT = 377; -PHP.Parser.prototype.T_OPEN_TAG = 378; -PHP.Parser.prototype.T_OPEN_TAG_WITH_ECHO = 379; -PHP.Parser.prototype.T_CLOSE_TAG = 380; -PHP.Parser.prototype.T_WHITESPACE = 381; -PHP.Parser.prototype.T_START_HEREDOC = 382; -PHP.Parser.prototype.T_END_HEREDOC = 383; -PHP.Parser.prototype.T_DOLLAR_OPEN_CURLY_BRACES = 384; -PHP.Parser.prototype.T_CURLY_OPEN = 385; -PHP.Parser.prototype.T_PAAMAYIM_NEKUDOTAYIM = 386; -PHP.Parser.prototype.T_NAMESPACE = 387; -PHP.Parser.prototype.T_NS_C = 388; -PHP.Parser.prototype.T_DIR = 389; -PHP.Parser.prototype.T_NS_SEPARATOR = 390; -PHP.Parser.prototype.T_ELLIPSIS = 391; +PHP.Parser.prototype.T_COALESCE_EQUAL = 281; +PHP.Parser.prototype.T_COALESCE = 282; +PHP.Parser.prototype.T_BOOLEAN_OR = 283; +PHP.Parser.prototype.T_BOOLEAN_AND = 284; +PHP.Parser.prototype.T_IS_EQUAL = 285; +PHP.Parser.prototype.T_IS_NOT_EQUAL = 286; +PHP.Parser.prototype.T_IS_IDENTICAL = 287; +PHP.Parser.prototype.T_IS_NOT_IDENTICAL = 288; +PHP.Parser.prototype.T_SPACESHIP = 289; +PHP.Parser.prototype.T_IS_SMALLER_OR_EQUAL = 290; +PHP.Parser.prototype.T_IS_GREATER_OR_EQUAL = 291; +PHP.Parser.prototype.T_SL = 292; +PHP.Parser.prototype.T_SR = 293; +PHP.Parser.prototype.T_INSTANCEOF = 294; +PHP.Parser.prototype.T_INC = 295; +PHP.Parser.prototype.T_DEC = 296; +PHP.Parser.prototype.T_INT_CAST = 297; +PHP.Parser.prototype.T_DOUBLE_CAST = 298; +PHP.Parser.prototype.T_STRING_CAST = 299; +PHP.Parser.prototype.T_ARRAY_CAST = 300; +PHP.Parser.prototype.T_OBJECT_CAST = 301; +PHP.Parser.prototype.T_BOOL_CAST = 302; +PHP.Parser.prototype.T_UNSET_CAST = 303; +PHP.Parser.prototype.T_POW = 304; +PHP.Parser.prototype.T_NEW = 305; +PHP.Parser.prototype.T_CLONE = 306; +PHP.Parser.prototype.T_EXIT = 307; +PHP.Parser.prototype.T_IF = 308; +PHP.Parser.prototype.T_ELSEIF = 309; +PHP.Parser.prototype.T_ELSE = 310; +PHP.Parser.prototype.T_ENDIF = 311; +PHP.Parser.prototype.T_LNUMBER = 312; +PHP.Parser.prototype.T_DNUMBER = 313; +PHP.Parser.prototype.T_STRING = 314; +PHP.Parser.prototype.T_STRING_VARNAME = 315; +PHP.Parser.prototype.T_VARIABLE = 316; +PHP.Parser.prototype.T_NUM_STRING = 317; +PHP.Parser.prototype.T_INLINE_HTML = 318; +PHP.Parser.prototype.T_CHARACTER = 319; +PHP.Parser.prototype.T_BAD_CHARACTER = 320; +PHP.Parser.prototype.T_ENCAPSED_AND_WHITESPACE = 321; +PHP.Parser.prototype.T_CONSTANT_ENCAPSED_STRING = 322; +PHP.Parser.prototype.T_ECHO = 323; +PHP.Parser.prototype.T_DO = 324; +PHP.Parser.prototype.T_WHILE = 325; +PHP.Parser.prototype.T_ENDWHILE = 326; +PHP.Parser.prototype.T_FOR = 327; +PHP.Parser.prototype.T_ENDFOR = 328; +PHP.Parser.prototype.T_FOREACH = 329; +PHP.Parser.prototype.T_ENDFOREACH = 330; +PHP.Parser.prototype.T_DECLARE = 331; +PHP.Parser.prototype.T_ENDDECLARE = 332; +PHP.Parser.prototype.T_AS = 333; +PHP.Parser.prototype.T_SWITCH = 334; +PHP.Parser.prototype.T_ENDSWITCH = 335; +PHP.Parser.prototype.T_CASE = 336; +PHP.Parser.prototype.T_DEFAULT = 337; +PHP.Parser.prototype.T_BREAK = 338; +PHP.Parser.prototype.T_CONTINUE = 339; +PHP.Parser.prototype.T_GOTO = 340; +PHP.Parser.prototype.T_FUNCTION = 341; +PHP.Parser.prototype.T_FN = 342; +PHP.Parser.prototype.T_CONST = 343; +PHP.Parser.prototype.T_RETURN = 344; +PHP.Parser.prototype.T_TRY = 345; +PHP.Parser.prototype.T_CATCH = 346; +PHP.Parser.prototype.T_FINALLY = 347; +PHP.Parser.prototype.T_THROW = 348; +PHP.Parser.prototype.T_USE = 349; +PHP.Parser.prototype.T_INSTEADOF = 350; +PHP.Parser.prototype.T_GLOBAL = 351; +PHP.Parser.prototype.T_STATIC = 352; +PHP.Parser.prototype.T_ABSTRACT = 353; +PHP.Parser.prototype.T_FINAL = 354; +PHP.Parser.prototype.T_PRIVATE = 355; +PHP.Parser.prototype.T_PROTECTED = 356; +PHP.Parser.prototype.T_PUBLIC = 357; +PHP.Parser.prototype.T_VAR = 358; +PHP.Parser.prototype.T_UNSET = 359; +PHP.Parser.prototype.T_ISSET = 360; +PHP.Parser.prototype.T_EMPTY = 361; +PHP.Parser.prototype.T_HALT_COMPILER = 362; +PHP.Parser.prototype.T_CLASS = 363; +PHP.Parser.prototype.T_TRAIT = 364; +PHP.Parser.prototype.T_INTERFACE = 365; +PHP.Parser.prototype.T_EXTENDS = 366; +PHP.Parser.prototype.T_IMPLEMENTS = 367; +PHP.Parser.prototype.T_OBJECT_OPERATOR = 368; +PHP.Parser.prototype.T_LIST = 369; +PHP.Parser.prototype.T_ARRAY = 370; +PHP.Parser.prototype.T_CALLABLE = 371; +PHP.Parser.prototype.T_CLASS_C = 372; +PHP.Parser.prototype.T_TRAIT_C = 373; +PHP.Parser.prototype.T_METHOD_C = 374; +PHP.Parser.prototype.T_FUNC_C = 375; +PHP.Parser.prototype.T_LINE = 376; +PHP.Parser.prototype.T_FILE = 377; +PHP.Parser.prototype.T_COMMENT = 378; +PHP.Parser.prototype.T_DOC_COMMENT = 379; +PHP.Parser.prototype.T_OPEN_TAG = 380; +PHP.Parser.prototype.T_OPEN_TAG_WITH_ECHO = 381; +PHP.Parser.prototype.T_CLOSE_TAG = 382; +PHP.Parser.prototype.T_WHITESPACE = 383; +PHP.Parser.prototype.T_START_HEREDOC = 384; +PHP.Parser.prototype.T_END_HEREDOC = 385; +PHP.Parser.prototype.T_DOLLAR_OPEN_CURLY_BRACES = 386; +PHP.Parser.prototype.T_CURLY_OPEN = 387; +PHP.Parser.prototype.T_PAAMAYIM_NEKUDOTAYIM = 388; +PHP.Parser.prototype.T_NAMESPACE = 389; +PHP.Parser.prototype.T_NS_C = 390; +PHP.Parser.prototype.T_DIR = 391; +PHP.Parser.prototype.T_NS_SEPARATOR = 392; +PHP.Parser.prototype.T_ELLIPSIS = 393; // }}} /* @var array Map of token ids to their respective names */ PHP.Parser.prototype.terminals = [ - "$EOF", + "EOF", "error", "T_INCLUDE", "T_INCLUDE_ONCE", @@ -1531,6 +1540,7 @@ PHP.Parser.prototype.terminals = [ "T_SL_EQUAL", "T_SR_EQUAL", "T_POW_EQUAL", + "T_COALESCE_EQUAL", "'?'", "':'", "T_COALESCE", @@ -1606,6 +1616,7 @@ PHP.Parser.prototype.terminals = [ "T_CONTINUE", "T_GOTO", "T_FUNCTION", + "T_FN", "T_CONST", "T_RETURN", "T_TRY", @@ -1665,504 +1676,554 @@ PHP.Parser.prototype.terminals = [ /* @var Map which translates lexer tokens to internal tokens */ PHP.Parser.prototype.translate = [ - 0, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 53, 155, 157, 156, 52, 35, 157, - 151, 152, 50, 47, 7, 48, 49, 51, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 29, 148, - 41, 15, 43, 28, 65, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 67, 157, 154, 34, 157, 153, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 149, 33, 150, 55, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, - 157, 157, 157, 157, 157, 157, 1, 2, 3, 4, + 0, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 54, 157, 159, 158, 53, 36, 159, + 153, 154, 51, 48, 7, 49, 50, 52, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 30, 150, + 42, 15, 44, 29, 66, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 68, 159, 156, 35, 159, 155, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 151, 34, 152, 56, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 30, 31, 32, 36, 37, 38, 39, 40, 42, - 44, 45, 46, 54, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 66, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 157, 157, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 27, 28, 31, 32, 33, 37, 38, 39, 40, 41, + 43, 45, 46, 47, 55, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 67, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 159, + 159, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 157, 157, 157, 157, - 157, 157, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147 + 132, 133, 134, 135, 136, 137, 138, 139, 159, 159, + 159, 159, 159, 159, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149 ]; PHP.Parser.prototype.yyaction = [ - 569, 570, 571, 572, 573, 215, 574, 575, 576, 612, - 613, 0, 27, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110,-32766,-32766,-32766, 95, 96, - 97, 24, 240, 226, -267,-32766,-32766,-32766,-32766,-32766, - -32766, 530, 344, 114, 98,-32766, 286,-32766,-32766,-32766, - -32766,-32766, 577, 870, 872,-32766,-32766,-32766,-32766,-32766, - -32766,-32766,-32766, 224,-32766, 714, 578, 579, 580, 581, - 582, 583, 584,-32766, 264, 644, 840, 841, 842, 839, - 838, 837, 585, 586, 587, 588, 589, 590, 591, 592, - 593, 594, 595, 615, 616, 617, 618, 619, 607, 608, - 609, 610, 611, 596, 597, 598, 599, 600, 601, 602, - 638, 639, 640, 641, 642, 643, 603, 604, 605, 606, - 636, 627, 625, 626, 622, 623, 116, 614, 620, 621, - 628, 629, 631, 630, 632, 633, 42, 43, 381, 44, - 45, 624, 635, 634, -214, 46, 47, 289, 48,-32767, - -32767,-32767,-32767, 90, 91, 92, 93, 94, 267, 241, - 22, 840, 841, 842, 839, 838, 837, 832,-32766,-32766, - -32766, 306, 1000, 1000, 1037, 120, 966, 436, -423, 244, - 797, 49, 50, 660, 661, 272, 362, 51,-32766, 52, - 219, 220, 53, 54, 55, 56, 57, 58, 59, 60, - 1016, 22, 238, 61, 351, 945,-32766,-32766,-32766, 967, - 968, 646, 705, 1000, 28, -456, 125, 966,-32766,-32766, - -32766, 715, 398, 399, 216, 1000,-32766, 339,-32766,-32766, - -32766,-32766, 25, 222, 980, 552, 355, 378,-32766, -423, - -32766,-32766,-32766, 121, 65, 1045, 408, 1047, 1046, 274, - 274, 131, 244, -423, 394, 395, 358, 519, 945, 537, - -423, 111, -426, 398, 399, 130, 972, 973, 974, 975, - 969, 970, 243, 128, -422, -421, 1013, 409, 976, 971, - 353, 791, 792, 7, -162, 63, 124, 255, 701, 256, - 274, 382, -122, -122, -122, -4, 715, 383, 646, 1042, - -421, 704, 274, -219, 33, 17, 384, -122, 385, -122, - 386, -122, 387, -122, 369, 388, -122, -122, -122, 34, - 35, 389, 352, 520, 36, 390, 353, 702, 62, 112, - 818, 287, 288, 391, 392, -422, -421, -161, 350, 393, - 40, 38, 690, 735, 396, 397, 361, 22, 122, -422, - -421,-32766,-32766,-32766, 791, 792, -422, -421, -425, 1000, - -456, -421, -238, 966, 409, 41, 382, 353, 717, 535, - -122,-32766, 383,-32766,-32766, -421, 704, 21, 813, 33, - 17, 384, -421, 385, -466, 386, 224, 387, -467, 273, - 388, 367, 945, -458, 34, 35, 389, 352, 345, 36, - 390, 248, 247, 62, 254, 715, 287, 288, 391, 392, - 399,-32766,-32766,-32766, 393, 295, 1000, 652, 735, 396, - 397, 117, 115, 113, 814, 119, 72, 73, 74, -162, - 764, 65, 240, 541, 370, 518, 274, 118, 270, 92, - 93, 94, 242, 717, 535, -4, 26, 1000, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 547, 240, 713, 715, 382, 276,-32766,-32766, 126, - 945, 383, -161, 938, 98, 704, 225, 659, 33, 17, - 384, 346, 385, 274, 386, 728, 387, 221, 120, 388, - 505, 506, 540, 34, 35, 389, 715, -238, 36, 390, - 1017, 223, 62, 494, 18, 287, 288, 127, 297, 376, - 6, 98, 798, 393, 274, 660, 661, 490, 491, -466, - 39, -466, 514, -467, 539, -467, 16, 458, -458, 315, - 791, 792, 829, 553, 382, 817, 563, 653, 538, 765, - 383, 449, 751, 535, 704, 448, 435, 33, 17, 384, - 430, 385, 646, 386, 359, 387, 357, 647, 388, 673, - 429, 1040, 34, 35, 389, 715, 382, 36, 390, 941, - 492, 62, 383, 503, 287, 288, 704, 434, 440, 33, - 17, 384, 393, 385,-32766, 386, 445, 387, 495, 509, - 388, 10, 529, 542, 34, 35, 389, 715, 515, 36, - 390, 499, 500, 62, 214, -80, 287, 288, 452, 269, - 736, 717, 535, 488, 393, 356, 266, 979, 265, 730, - 982, 722, 358, 338, 493, 548, 0, 294, 737, 0, - 3, 0, 309, 0, 0, 382, 0, 0, 271, 0, - 0, 383, 0, 717, 535, 704, 227, 0, 33, 17, - 384, 9, 385, 0, 386, 0, 387, -382, 0, 388, - 0, 0, 325, 34, 35, 389, 715, 382, 36, 390, - 321, 341, 62, 383, 340, 287, 288, 704, 22, 320, - 33, 17, 384, 393, 385, 442, 386, 337, 387, 562, - 1000, 388, 32, 31, 966, 34, 35, 389, 823, 657, - 36, 390, 656, 821, 62, 703, 711, 287, 288, 561, - 822, 825, 717, 535, 695, 393, 747, 749, 693, 759, - 758, 752, 767, 945, 824, 706, 700, 712, 699, 698, - 658, 0, 263, 262, 559, 558, 382, 556, 554, 551, - 398, 399, 383, 550, 717, 535, 704, 546, 545, 33, - 17, 384, 543, 385, 536, 386, 71, 387, 933, 932, - 388, 30, 65, 731, 34, 35, 389, 274, 724, 36, - 390, 830, 734, 62, 663, 662, 287, 288,-32766,-32766, - -32766, 733, 732, 934, 393, 665, 664, 756, 555, 691, - 1041, 1001, 994, 1006, 1011, 1014, 757, 1043,-32766, 654, - -32766,-32766,-32766,-32766,-32766,-32766,-32767,-32767,-32767,-32767, - -32767, 655, 1044, 717, 535, -446, 926, 348, 343, 268, - 237, 236, 235, 234, 218, 217, 132, 129, -426, -425, - -424, 123, 20, 23, 70, 69, 29, 37, 64, 68, - 66, 67, -448, 0, 15, 19, 250, 910, 296, -217, - 467, 484, 909, 472, 528, 913, 11, 964, 955, -215, - 525, 379, 375, 373, 371, 14, 13, 12, -214, 0, - -393, 0, 1005, 1039, 992, 993, 963, 0, 981 + 607, 608, 609, 610, 611, 685, 612, 613, 614, 650, + 651, 0, 32, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115,-32767,-32767,-32767,-32767, + 94, 95, 96, 97, 98,-32766,-32766,-32766, 687, 491, + -497, 904, 905, 906, 903, 902, 901, 904, 905, 906, + 903, 902, 901, 615, 938, 940,-32766, 9,-32766,-32766, + -32766,-32766,-32766,-32766,-32766,-32766,-32766, 616, 617, 618, + 619, 620, 621, 622, 333, 1104, 683,-32766,-32766,-32766, + 846, 1103, 119, 623, 624, 625, 626, 627, 628, 629, + 630, 631, 632, 633, 653, 654, 655, 656, 657, 645, + 646, 647, 675, 648, 649, 634, 635, 636, 637, 638, + 639, 640, 677, 678, 679, 680, 681, 682, 641, 642, + 643, 644, 674, 665, 663, 664, 660, 661, 402, 652, + 658, 659, 666, 667, 669, 668, 670, 671, 45, 46, + 421, 47, 48, 662, 673, 672, 27, 49, 50, 233, + 51,-32766,-32766,-32766, 96, 97, 98, 24,-32766,-32766, + -32766, -458, 261, 121, 1023,-32766,-32766,-32766, 1091, 1073, + -32766,-32766,-32766, 1039,-32766,-32766,-32766,-32766,-32766,-32766, + -496,-32766,-32766,-32766, 52, 53,-32766, -497,-32766,-32766, + 54, 687, 55, 231, 232, 56, 57, 58, 59, 60, + 61, 62, 63, 1016, 24, 242, 64, 369,-32766,-32766, + -32766, 226, 1040, 1041, 423, 1076, 1073, -493, 880, 508, + 1039, 436, 1023, -458, 768, 1073, 239, 333, -500,-32766, + -500,-32766,-32766,-32766,-32766, 856, 253, -458, 276, 378, + 372, 786, 68, 1073, -458, 685, -461, 278, 1126, 403, + 289, 1127, 288, 99, 100, 101, 303, 252, 433, 434, + 822,-32766, 69, 261, 237, 850, 851, 435, 436, 102, + 1045, 1046, 1047, 1048, 1042, 1043, 256, 1016, -456, -456, + 306, 444, 1049, 1044, 375, 133, 561, -239, 363, 66, + 237, 268, 692, 273, 278, 422, -137, -137, -137, -4, + 768, 1073, 310, 278, 1035, 757, 687, 362, 37, 20, + 424, -137, 425, -137, 426, -137, 427, -137, 127, 428, + -295, 278, -295, 38, 39, 370, 371, -496, 271, 40, + 429, 277, 687, 65, 261, 1016, 302, 896, 430, 431, + -456, -456, 333, -494, 432, 44, 42, 743, 791, 373, + 374, -457, -234, 562, -456, -456, 375,-32766,-32766,-32766, + 882, -456, -456, 124, -493, 75, 850, 851, 333, -273, + -260, 422, 768, 770, 576, -137, 261, 125,-32766, 278, + 823, 757, 857, 1073, 37, 20, 424, 240, 425, -178, + 426, 589, 427, 393, 503, 428, 687, 235, 241, 38, + 39, 370, 371, 125, 354, 40, 429, 260, 259, 65, + 267, 687, 302, -457, 430, 431, -296, -177, -296, 24, + 432, 305, 365, 700, 791, 373, 374, -457, 120, 118, + 24, 1073, 30, 366, -457, 1039, -460, 850, 851, 687, + 367, 691, 1073, 422, 291, 768, 1039, 333, -83, 770, + 576, -4, 467, 757, 126, 368, 37, 20, 424, -92, + 425, 278, 426, 444, 427, 1016, 375, 428, -219, -219, + -219, 38, 39, 370, 371, 333, 1016, 40, 429, 850, + 851, 65, 435, 436, 302, 236, 430, 431, 225, 708, + -494, 709, 432, 435, 436, 743, 791, 373, 374, 690, + 387, 136, 1117, 578, 68, 413, 238, 8, 33, 278, + 1053, 227, 708, 687, 709, 68, 422, -260, 535, 21, + 278, 770, 576, -219, 550, 551, 757, 687, 116, 37, + 20, 424, 117, 425, 358, 426, -178, 427, 132, 328, + 428, -218, -218, -218, 38, 39, 370, 371, 687, 333, + 40, 429, 122, 768, 65, 383, 384, 302, 123, 430, + 431, 29, 234, 333, -177, 432, 528, 529, 743, 791, + 373, 374, 129, 850, 851, 135, 76, 77, 78, 1092, + 881, 599, 582, 254, 333, 137, 138, 782, 590, 593, + 293, 767, 131, 252, 770, 576, -218, 31, 102, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 43, 252, 422, 558, 768, 687, 690,-32766, + 471, 130, 476, 685, 757, 102, 553, 37, 20, 424, + 526, 425, 688, 426, 272, 427, 910, 1016, 428, 792, + 1128, 793, 38, 39, 370, 583, 269, 570, 40, 429, + 536, 1052, 65, 275, 1055, 302, -415, 541, 270, -81, + 10, 391, 768, 432, 542, 554, 784, 594, 5, 0, + 12, 577, 0, 0, 304, 0, 0, 0, 0, 336, + 342, 0, 0, 0, 0, 0, 0, 422, 0, 0, + 0, 584, 770, 576, 0, 0, 0, 757, 0, 0, + 37, 20, 424, 343, 425, 0, 426, 0, 427, 768, + 0, 428, 0, 0, 0, 38, 39, 370, 347, 387, + 473, 40, 429, 359, 360, 65, 744, 35, 302, 36, + 597, 598, 748, 422, 825, 809, 432, 816, 587, 876, + 877, 806, 817, 757, 746, 804, 37, 20, 424, 885, + 425, 888, 426, 889, 427, 768, 886, 428, 887, 893, + -485, 38, 39, 370, 579, 770, 576, 40, 429, 581, + 585, 65, 586, 588, 302, 592, 286, 287, 352, 353, + 422, 580, 432, 1123, 591, 1125, 703, 790, 702, 712, + 757, 789, 713, 37, 20, 424, 710, 425, 1124, 426, + 788, 427, 768, 1004, 428, 711, 777, 785, 38, 39, + 370, 808, 576, -483, 40, 429, 775, 814, 65, 815, + 1122, 302, 1074, 1067, 1081, 1086, 422, 1089, -237, 432, + -461, -460, -459, 23, 25, 28, 757, 34, 41, 37, + 20, 424, 67, 425, 70, 426, 71, 427, 72, 73, + 428, 74, 128, 134, 38, 39, 370, 139, 770, 576, + 40, 429, 229, 230, 65, 246, 247, 302, 248, 249, + 250, 251, 290, 422, 355, 432, 357, -427, -235, -234, + 14, 15, 16, 757, 17, 19, 37, 20, 424, 325, + 425, 404, 426, 406, 427, 409, 411, 428, 412, 419, + 567, 38, 39, 370, 770, 576, 1027, 40, 429, 977, + 1037, 65, 858, 1008, 302,-32766,-32766,-32766, -92, 13, + 18, 22, 432, 263, 324, 501, 522, 569, 981, 978, + 0, 994, 0, 1036, 1065, 1066,-32766, 1080,-32766,-32766, + -32766,-32766,-32766,-32766,-32767,-32767,-32767,-32767,-32767, 1120, + 532, 770, 576, 1054 ]; PHP.Parser.prototype.yycheck = [ - 2, 3, 4, 5, 6, 13, 8, 9, 10, 11, + 2, 3, 4, 5, 6, 78, 8, 9, 10, 11, 12, 0, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 8, 9, 10, 50, 51, - 52, 7, 54, 7, 79, 8, 9, 10, 8, 9, - 10, 77, 7, 13, 66, 28, 7, 30, 31, 32, - 33, 34, 54, 56, 57, 28, 8, 30, 31, 32, - 33, 34, 35, 35, 109, 1, 68, 69, 70, 71, - 72, 73, 74, 118, 7, 77, 112, 113, 114, 115, - 116, 117, 84, 85, 86, 87, 88, 89, 90, 91, + 23, 24, 25, 26, 27, 28, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 8, 9, 10, 78, 79, + 7, 114, 115, 116, 117, 118, 119, 114, 115, 116, + 117, 118, 119, 55, 57, 58, 29, 7, 31, 32, + 33, 34, 35, 36, 8, 9, 10, 69, 70, 71, + 72, 73, 74, 75, 114, 1, 78, 8, 9, 10, + 1, 7, 13, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 7, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 2, 3, 4, 5, - 6, 143, 144, 145, 152, 11, 12, 7, 14, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 109, 7, - 67, 112, 113, 114, 115, 116, 117, 118, 8, 9, - 10, 79, 79, 79, 82, 147, 83, 82, 67, 28, - 152, 47, 48, 102, 103, 7, 7, 53, 28, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 1, 67, 68, 69, 70, 112, 8, 9, 10, 75, - 76, 77, 148, 79, 13, 7, 67, 83, 8, 9, - 10, 1, 129, 130, 13, 79, 28, 146, 30, 31, - 32, 33, 140, 141, 139, 29, 102, 7, 28, 128, - 30, 31, 32, 149, 151, 77, 112, 79, 80, 156, - 156, 15, 28, 142, 120, 121, 146, 77, 112, 149, - 149, 15, 151, 129, 130, 15, 132, 133, 134, 135, - 136, 137, 138, 15, 67, 67, 77, 143, 144, 145, - 146, 130, 131, 7, 7, 151, 15, 153, 148, 155, - 156, 71, 72, 73, 74, 0, 1, 77, 77, 150, - 67, 81, 156, 152, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 29, 95, 96, 97, 98, 99, - 100, 101, 102, 143, 104, 105, 146, 148, 108, 15, - 150, 111, 112, 113, 114, 128, 128, 7, 7, 119, - 67, 67, 122, 123, 124, 125, 7, 67, 149, 142, - 142, 8, 9, 10, 130, 131, 149, 149, 151, 79, - 152, 128, 7, 83, 143, 7, 71, 146, 148, 149, - 150, 28, 77, 30, 31, 142, 81, 7, 148, 84, - 85, 86, 149, 88, 7, 90, 35, 92, 7, 33, - 95, 7, 112, 7, 99, 100, 101, 102, 103, 104, - 105, 128, 128, 108, 109, 1, 111, 112, 113, 114, - 130, 8, 9, 10, 119, 142, 79, 122, 123, 124, - 125, 15, 149, 149, 148, 29, 8, 9, 10, 152, - 29, 151, 54, 29, 149, 79, 156, 15, 143, 47, - 48, 49, 29, 148, 149, 150, 28, 79, 30, 31, + 122, 123, 124, 125, 126, 127, 128, 129, 30, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 2, 3, + 4, 5, 6, 145, 146, 147, 7, 11, 12, 36, + 14, 8, 9, 10, 48, 49, 50, 68, 8, 9, + 10, 68, 29, 7, 1, 8, 9, 10, 1, 80, + 8, 9, 29, 84, 31, 32, 33, 34, 35, 29, + 7, 31, 32, 33, 48, 49, 29, 154, 31, 32, + 54, 78, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 114, 68, 69, 70, 71, 8, 9, + 10, 13, 76, 77, 78, 1, 80, 7, 1, 49, + 84, 132, 1, 130, 1, 80, 7, 114, 154, 29, + 156, 31, 32, 33, 34, 1, 7, 144, 7, 103, + 104, 1, 153, 80, 151, 78, 153, 158, 78, 151, + 114, 81, 7, 51, 52, 53, 7, 55, 122, 123, + 30, 8, 149, 29, 36, 132, 133, 131, 132, 67, + 134, 135, 136, 137, 138, 139, 140, 114, 68, 68, + 7, 145, 146, 147, 148, 13, 78, 154, 125, 153, + 36, 155, 1, 157, 158, 72, 73, 74, 75, 0, + 1, 80, 7, 158, 1, 82, 78, 7, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 151, 96, + 103, 158, 105, 100, 101, 102, 103, 154, 111, 106, + 107, 68, 78, 110, 29, 114, 113, 120, 115, 116, + 130, 130, 114, 7, 121, 68, 68, 124, 125, 126, + 127, 68, 154, 145, 144, 144, 148, 8, 9, 10, + 152, 151, 151, 30, 154, 151, 132, 133, 114, 152, + 7, 72, 1, 150, 151, 152, 29, 149, 29, 158, + 150, 82, 154, 80, 85, 86, 87, 36, 89, 7, + 91, 151, 93, 130, 1, 96, 78, 36, 36, 100, + 101, 102, 103, 149, 105, 106, 107, 130, 130, 110, + 111, 78, 113, 130, 115, 116, 103, 7, 105, 68, + 121, 144, 7, 124, 125, 126, 127, 144, 151, 151, + 68, 80, 7, 7, 151, 84, 153, 132, 133, 78, + 7, 150, 80, 72, 145, 1, 84, 114, 30, 150, + 151, 152, 83, 82, 151, 7, 85, 86, 87, 154, + 89, 158, 91, 145, 93, 114, 148, 96, 97, 98, + 99, 100, 101, 102, 103, 114, 114, 106, 107, 132, + 133, 110, 131, 132, 113, 36, 115, 116, 95, 103, + 154, 105, 121, 131, 132, 124, 125, 126, 127, 80, + 148, 13, 83, 151, 153, 103, 36, 105, 13, 158, + 141, 13, 103, 78, 105, 153, 72, 154, 73, 74, + 158, 150, 151, 152, 73, 74, 82, 78, 15, 85, + 86, 87, 15, 89, 148, 91, 154, 93, 98, 99, + 96, 97, 98, 99, 100, 101, 102, 103, 78, 114, + 106, 107, 15, 1, 110, 103, 104, 113, 15, 115, + 116, 142, 143, 114, 154, 121, 108, 109, 124, 125, + 126, 127, 15, 132, 133, 15, 8, 9, 10, 154, + 150, 151, 30, 30, 114, 15, 15, 36, 30, 30, + 34, 30, 30, 55, 150, 151, 152, 29, 67, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 29, 54, 29, 1, 71, 67, 8, 9, 29, - 112, 77, 152, 152, 66, 81, 35, 148, 84, 85, - 86, 123, 88, 156, 90, 35, 92, 35, 147, 95, - 72, 73, 29, 99, 100, 101, 1, 152, 104, 105, - 152, 35, 108, 72, 73, 111, 112, 97, 98, 102, - 103, 66, 152, 119, 156, 102, 103, 106, 107, 152, - 67, 154, 74, 152, 29, 154, 152, 128, 152, 78, - 130, 131, 148, 149, 71, 148, 149, 148, 149, 148, - 77, 77, 148, 149, 81, 77, 77, 84, 85, 86, - 77, 88, 77, 90, 77, 92, 77, 77, 95, 77, - 77, 77, 99, 100, 101, 1, 71, 104, 105, 79, - 79, 108, 77, 79, 111, 112, 81, 79, 82, 84, - 85, 86, 119, 88, 82, 90, 86, 92, 87, 96, - 95, 94, 89, 29, 99, 100, 101, 1, 91, 104, - 105, 93, 96, 108, 94, 94, 111, 112, 94, 110, - 123, 148, 149, 109, 119, 102, 127, 139, 126, 147, - 139, 150, 146, 149, 154, 29, -1, 142, 123, -1, - 142, -1, 146, -1, -1, 71, -1, -1, 126, -1, - -1, 77, -1, 148, 149, 81, 35, -1, 84, 85, - 86, 142, 88, -1, 90, -1, 92, 142, -1, 95, - -1, -1, 146, 99, 100, 101, 1, 71, 104, 105, - 146, 146, 108, 77, 146, 111, 112, 81, 67, 146, - 84, 85, 86, 119, 88, 146, 90, 149, 92, 148, - 79, 95, 148, 148, 83, 99, 100, 101, 148, 148, - 104, 105, 148, 148, 108, 148, 148, 111, 112, 148, - 148, 148, 148, 149, 148, 119, 148, 148, 148, 148, - 148, 148, 148, 112, 148, 148, 148, 148, 148, 148, - 148, -1, 149, 149, 149, 149, 71, 149, 149, 149, - 129, 130, 77, 149, 148, 149, 81, 149, 149, 84, - 85, 86, 149, 88, 149, 90, 149, 92, 150, 150, - 95, 151, 151, 150, 99, 100, 101, 156, 150, 104, - 105, 150, 150, 108, 150, 150, 111, 112, 8, 9, - 10, 150, 150, 150, 119, 150, 150, 150, 150, 150, - 150, 150, 150, 150, 150, 150, 150, 150, 28, 150, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 150, 150, 148, 149, 151, 153, 151, 151, 151, - 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, - 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, - 151, 151, 151, -1, 152, 152, 152, 152, 152, 152, - 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, - 152, 152, 152, 152, 152, 152, 152, 152, 152, -1, - 153, -1, 154, 154, 154, 154, 154, -1, 155 + 52, 53, 68, 55, 72, 75, 1, 78, 80, 83, + 83, 68, 87, 78, 82, 67, 92, 85, 86, 87, + 111, 89, 78, 91, 112, 93, 80, 114, 96, 125, + 81, 125, 100, 101, 102, 30, 128, 90, 106, 107, + 88, 141, 110, 128, 141, 113, 144, 94, 129, 95, + 95, 95, 1, 121, 97, 97, 149, 152, 144, -1, + 144, 151, -1, -1, 144, -1, -1, -1, -1, 148, + 148, -1, -1, -1, -1, -1, -1, 72, -1, -1, + -1, 30, 150, 151, -1, -1, -1, 82, -1, -1, + 85, 86, 87, 148, 89, -1, 91, -1, 93, 1, + -1, 96, -1, -1, -1, 100, 101, 102, 148, 148, + 148, 106, 107, 148, 148, 110, 152, 150, 113, 150, + 150, 150, 150, 72, 150, 150, 121, 150, 30, 150, + 150, 150, 150, 82, 150, 150, 85, 86, 87, 150, + 89, 150, 91, 150, 93, 1, 150, 96, 150, 150, + 153, 100, 101, 102, 151, 150, 151, 106, 107, 151, + 151, 110, 151, 151, 113, 151, 151, 151, 151, 151, + 72, 151, 121, 152, 30, 152, 152, 152, 152, 152, + 82, 152, 152, 85, 86, 87, 152, 89, 152, 91, + 152, 93, 1, 152, 96, 152, 152, 152, 100, 101, + 102, 150, 151, 153, 106, 107, 152, 152, 110, 152, + 152, 113, 152, 152, 152, 152, 72, 152, 154, 121, + 153, 153, 153, 153, 153, 153, 82, 153, 153, 85, + 86, 87, 153, 89, 153, 91, 153, 93, 153, 153, + 96, 153, 153, 153, 100, 101, 102, 153, 150, 151, + 106, 107, 153, 153, 110, 153, 153, 113, 153, 153, + 153, 153, 153, 72, 153, 121, 153, 155, 154, 154, + 154, 154, 154, 82, 154, 154, 85, 86, 87, 154, + 89, 154, 91, 154, 93, 154, 154, 96, 154, 154, + 154, 100, 101, 102, 150, 151, 154, 106, 107, 154, + 154, 110, 154, 154, 113, 8, 9, 10, 154, 154, + 154, 154, 121, 154, 154, 154, 154, 154, 154, 154, + -1, 155, -1, 156, 156, 156, 29, 156, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 156, + 156, 150, 151, 157 ]; PHP.Parser.prototype.yybase = [ - 0, 220, 295, 94, 180, 560, -2, -2, -2, -2, - -36, 473, 574, 606, 574, 505, 404, 675, 675, 675, - 28, 351, 462, 462, 462, 461, 396, 476, 451, 134, - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 401, 64, 201, 568, 704, 713, 708, - 702, 714, 520, 706, 705, 211, 650, 651, 450, 652, - 653, 654, 655, 709, 480, 703, 712, 418, 418, 418, - 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, - 418, 418, 418, 48, 30, 469, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 160, 160, 160, 343, 210, - 208, 198, 17, 233, 27, 780, 780, 780, 780, 780, - 108, 108, 108, 108, 621, 621, 93, 280, 280, 280, - 280, 280, 280, 280, 280, 280, 280, 280, 632, 641, - 642, 643, 392, 392, 151, 151, 151, 151, 368, -45, - 146, 224, 224, 95, 410, 491, 733, 199, 199, 111, - 207, -22, -22, -22, 81, 506, 92, 92, 233, 233, - 273, 233, 423, 423, 423, 221, 221, 221, 221, 221, - 110, 221, 221, 221, 617, 512, 168, 516, 647, 397, - 503, 656, 274, 381, 377, 538, 535, 337, 523, 337, - 421, 441, 428, 525, 337, 337, 285, 401, 394, 378, - 567, 474, 339, 564, 140, 179, 409, 399, 384, 594, - 561, 711, 330, 710, 358, 149, 378, 378, 378, 370, - 593, 548, 355, -8, 646, 484, 277, 417, 386, 645, - 635, 230, 634, 276, 331, 356, 565, 485, 485, 485, - 485, 485, 485, 460, 485, 483, 691, 691, 478, 501, - 460, 696, 460, 485, 691, 460, 460, 502, 485, 522, - 522, 483, 508, 499, 691, 691, 499, 478, 460, 571, - 551, 514, 482, 413, 413, 514, 460, 413, 501, 413, - 11, 697, 699, 444, 700, 695, 698, 676, 694, 493, - 615, 497, 515, 684, 683, 693, 479, 489, 620, 692, - 549, 592, 487, 246, 314, 498, 463, 689, 523, 486, - 455, 455, 455, 463, 687, 455, 455, 455, 455, 455, - 455, 455, 455, 732, 24, 495, 510, 591, 590, 589, - 406, 588, 496, 524, 422, 599, 488, 549, 549, 649, - 727, 673, 490, 682, 716, 690, 555, 119, 271, 681, - 648, 543, 492, 534, 680, 598, 246, 715, 494, 672, - 549, 671, 455, 674, 701, 730, 731, 688, 728, 722, - 152, 526, 587, 178, 729, 659, 596, 595, 554, 725, - 707, 721, 720, 178, 576, 511, 717, 518, 677, 504, - 678, 613, 258, 657, 686, 584, 724, 723, 726, 583, - 582, 609, 608, 250, 236, 685, 442, 458, 517, 581, - 500, 628, 604, 679, 580, 579, 623, 619, 718, 521, - 486, 519, 509, 507, 513, 600, 618, 719, 206, 578, - 586, 573, 481, 572, 631, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 134, 134, -2, -2, -2, - 0, 0, 0, 0, -2, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 223, 299, 371, 444, 303, 208, 618, -2, -2, + -73, -2, -2, 625, 718, 718, 764, 718, 552, 671, + 811, 811, 811, 228, 113, 113, 113, 254, 361, -40, + 361, 333, 449, 470, 435, 435, 435, 435, 435, 435, + 435, 435, 435, 435, 435, 435, 435, 435, 435, 435, + 435, 435, 435, 435, 435, 435, 435, 435, 435, 435, + 435, 435, 435, 435, 435, 435, 435, 435, 435, 435, + 435, 435, 435, 435, 435, 435, 435, 435, 435, 435, + 435, 435, 435, 435, 435, 435, 435, 435, 435, 435, + 435, 435, 435, 435, 435, 435, 435, 435, 435, 435, + 435, 435, 435, 435, 435, 435, 435, 435, 435, 435, + 435, 435, 435, 435, 435, 435, 435, 435, 435, 435, + 435, 435, 435, 435, 435, 435, 435, 435, 435, 435, + 435, 435, 435, 435, 435, 435, 435, 435, 435, 435, + 291, 291, 230, 393, 495, 779, 784, 781, 776, 775, + 780, 785, 498, 678, 680, 562, 681, 682, 683, 685, + 782, 804, 777, 783, 568, 568, 568, 568, 568, 568, + 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, + 568, 253, 69, 162, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 349, 349, 349, 157, + 210, 150, 200, 211, 143, 27, 917, 917, 917, 917, + 917, -16, -16, -16, -16, 351, 351, 362, 217, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 163, 313, 106, 106, 133, 133, 133, 133, + 133, 133, 221, 305, 234, 347, 369, 523, 806, 167, + 167, 441, 93, 283, 202, 202, 202, 386, 547, 533, + 533, 533, 533, 419, 419, 533, 533, 170, 214, 74, + 211, 211, 277, 211, 211, 211, 409, 409, 409, 452, + 318, 352, 546, 318, 619, 640, 577, 675, 578, 677, + 278, 585, 145, 586, 145, 145, 145, 458, 445, 451, + 774, 291, 522, 291, 291, 291, 291, 722, 291, 291, + 291, 291, 291, 291, 98, 291, 79, 430, 230, 240, + 240, 556, 240, 452, 538, 263, 635, 410, 425, 538, + 538, 538, 636, 637, 336, 363, 198, 638, 382, 402, + 173, 33, 549, 549, 555, 555, 566, 551, 549, 549, + 549, 549, 549, 690, 690, 555, 548, 555, 566, 695, + 555, 551, 551, 555, 555, 549, 555, 690, 551, 156, + 415, 249, 273, 551, 551, 426, 528, 549, 535, 535, + 433, 555, 219, 555, 139, 539, 690, 690, 539, 229, + 551, 231, 590, 591, 529, 527, 553, 245, 553, 553, + 300, 529, 553, 551, 553, 448, 50, 548, 295, 553, + 11, 699, 701, 418, 703, 694, 705, 731, 706, 530, + 524, 526, 719, 720, 708, 692, 691, 561, 582, 513, + 517, 534, 554, 689, 581, 531, 531, 531, 554, 687, + 531, 531, 531, 531, 531, 531, 531, 531, 787, 540, + 545, 723, 537, 541, 576, 543, 623, 520, 582, 582, + 584, 732, 786, 564, 722, 762, 709, 587, 557, 741, + 725, 525, 542, 565, 726, 727, 745, 765, 628, 513, + 766, 641, 563, 643, 582, 644, 531, 670, 617, 788, + 789, 688, 791, 736, 747, 749, 580, 645, 569, 803, + 646, 768, 629, 631, 589, 737, 684, 751, 647, 752, + 754, 649, 592, 572, 734, 573, 733, 272, 729, 632, + 650, 654, 656, 658, 661, 710, 594, 738, 544, 740, + 735, 595, 597, 560, 663, 488, 599, 570, 571, 600, + 714, 558, 550, 601, 602, 769, 664, 728, 604, 665, + 756, 574, 581, 536, 532, 575, 567, 634, 755, 559, + 605, 609, 611, 613, 674, 616, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 136, 136, 136, 136, -2, -2, -2, + 0, 0, -2, 0, 0, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 568, 568, 568, 568, 568, 568, 568, 568, + 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, + 568, 568, 568, 568, 568, 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 418, 418, 418, - 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, - 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, - 418, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 418, 418, 418, - 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, - 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, - 418, 418, 418, 418, -3, 418, 418, -3, 418, 418, - 418, 418, 418, 418, -22, -22, -22, -22, 221, 221, - 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, - 221, 221, 49, 49, 49, 49, -22, -22, 221, 221, - 221, 221, 221, 49, 221, 221, 221, 92, 221, 92, - 92, 337, 337, 0, 0, 0, 0, 0, 485, 92, - 0, 0, 0, 0, 0, 0, 485, 485, 485, 0, - 0, 0, 0, 0, 485, 0, 0, 0, 337, 92, - 0, 420, 420, 178, 420, 420, 0, 0, 0, 485, - 485, 0, 508, 0, 0, 0, 0, 691, 0, 0, - 0, 0, 0, 455, 119, 682, 0, 39, 0, 0, - 0, 0, 0, 490, 39, 26, 0, 26, 0, 0, - 455, 455, 455, 0, 490, 490, 0, 0, 67, 490, - 0, 0, 0, 67, 35, 0, 35, 0, 0, 0, - 178 + 0, 0, 0, 568, 568, 568, 568, 568, 568, 568, + 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, + 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, + 568, 568, -3, 568, 568, -3, 568, 568, 568, 568, + 568, 568, 568, 202, 202, 202, 202, 318, 318, 318, + -67, 318, 318, 318, 318, 318, 318, 318, 318, 318, + 318, 318, 318, 318, 318, -67, 202, 202, 318, 318, + 318, 318, 318, 318, 318, 318, 318, 318, 419, 419, + 419, 145, 145, 318, 0, 0, 0, 0, 0, 549, + 419, 318, 318, 318, 318, 0, 0, 318, 318, 548, + 145, 0, 0, 0, 0, 0, 0, 0, 549, 549, + 549, 548, 0, 549, 419, 0, 240, 291, 440, 440, + 440, 440, 0, 549, 0, 549, 0, 0, 0, 0, + 0, 0, 551, 0, 690, 0, 0, 0, 0, 555, + 0, 0, 0, 0, 0, 0, 0, 0, 548, 0, + 0, 0, 0, 548, 0, 0, 531, 0, 564, 0, + 0, 531, 531, 531, 564, 564, 0, 0, 0, 564 ]; PHP.Parser.prototype.yydefault = [ - 3,32767,32767,32767,32767,32767,32767,32767,32767,32767, + 3,32767,32767,32767,32767,32767,32767,32767,32767, 92, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, - 32767,32767, 468, 468, 468,32767,32767,32767,32767, 285, - 460, 285, 285,32767, 419, 419, 419, 419, 419, 419, - 419, 460,32767,32767,32767,32767,32767, 364,32767,32767, + 32767,32767,32767,32767, 510, 510, 510, 94, 499,32767, + 499,32767,32767,32767, 314, 314, 314,32767, 454, 454, + 454, 454, 454, 454, 454,32767,32767,32767,32767,32767, + 394,32767,32767,32767,32767,32767,32767,32767,32767,32767, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, + 32767, 92,32767,32767,32767,32767,32767,32767,32767,32767, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, + 32767,32767,32767,32767, 506,32767,32767,32767,32767,32767, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, - 32767,32767,32767,32767,32767, 465,32767,32767,32767,32767, + 32767,32767,32767,32767, 377, 378, 380, 381, 313, 455, + 509, 259, 505, 312, 130, 270, 261, 211, 243, 310, + 134, 342, 395, 344, 393, 397, 343, 319, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 317, 318, 396, 398, 399, 374, 373, 372, 340, + 316, 341, 345, 316, 347, 346, 363, 364, 361, 362, + 365, 366, 367, 368, 369,32767,32767,32767,32767,32767, + 32767,32767,32767,32767,32767,32767,32767,32767,32767, 94, + 32767,32767,32767, 293, 354, 355, 250, 250, 250, 250, + 250, 250,32767, 250,32767, 250,32767,32767,32767,32767, + 32767,32767, 448, 371, 349, 350, 348,32767, 426,32767, + 32767,32767,32767,32767, 428,32767, 92,32767,32767,32767, + 337, 339, 420, 508, 320, 507,32767,32767, 94, 414, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, - 32767,32767,32767,32767,32767,32767,32767, 347, 348, 350, - 351, 284, 420, 237, 464, 283, 116, 246, 239, 191, - 282, 223, 119, 312, 365, 314, 363, 367, 313, 290, - 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, - 304, 305, 288, 289, 366, 344, 343, 342, 310, 311, - 287, 315, 317, 287, 316, 333, 334, 331, 332, 335, - 336, 337, 338, 339,32767,32767,32767,32767,32767,32767, - 32767,32767,32767,32767,32767,32767,32767,32767, 269, 269, - 269, 269, 324, 325, 229, 229, 229, 229,32767, 270, - 32767, 229,32767,32767,32767,32767,32767,32767,32767, 413, - 341, 319, 320, 318,32767, 392,32767, 394, 307, 309, - 387, 291,32767,32767,32767,32767,32767,32767,32767,32767, + 423,32767,32767, 92,32767,32767, 92, 174, 230, 232, + 179,32767, 431,32767,32767,32767,32767,32767,32767,32767, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, - 32767,32767, 389, 421, 421,32767,32767,32767, 381,32767, - 159, 210, 212, 397,32767,32767,32767,32767,32767, 329, - 32767,32767,32767,32767,32767,32767, 474,32767,32767,32767, - 32767,32767, 421,32767,32767,32767, 321, 322, 323,32767, - 32767,32767, 421, 421,32767,32767, 421,32767, 421,32767, + 32767,32767,32767, 414, 359, 517,32767, 456,32767, 351, + 352, 353,32767,32767, 456, 456, 456,32767, 456,32767, + 456, 456,32767,32767,32767,32767,32767, 179,32767,32767, + 32767,32767, 94, 429, 429, 92, 92, 92, 92, 424, + 32767, 179, 179,32767,32767,32767,32767,32767, 179, 91, + 91, 91, 91, 179, 179, 91, 194,32767, 192, 192, + 91,32767, 93,32767, 93, 196,32767, 470, 196, 91, + 179, 91, 216, 216, 405, 181, 252, 93, 252, 252, + 93, 405, 252, 179, 252, 91, 91,32767, 91, 252, + 32767,32767,32767, 85,32767,32767,32767,32767,32767,32767, + 32767,32767,32767,32767,32767,32767,32767,32767, 416,32767, + 436,32767, 449, 468,32767, 357, 358, 360,32767, 458, + 382, 383, 384, 385, 386, 387, 388, 390,32767, 419, + 32767,32767,32767, 87, 121, 269,32767, 515, 87, 417, + 32767, 515,32767,32767,32767,32767,32767,32767,32767,32767, + 32767,32767, 87, 87,32767,32767,32767,32767,32767, 495, + 32767, 516,32767, 456, 418,32767, 356, 432, 475,32767, + 32767, 457,32767,32767,32767,32767, 87,32767,32767,32767, + 32767,32767,32767,32767,32767,32767, 436,32767,32767,32767, + 32767,32767,32767,32767, 456,32767,32767,32767,32767,32767, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, - 32767,32767,32767, 163,32767,32767, 395, 395,32767,32767, - 163, 390, 163,32767,32767, 163, 163, 176,32767, 174, - 174,32767,32767, 178,32767, 435, 178,32767, 163, 196, - 196, 373, 165, 231, 231, 373, 163, 231,32767, 231, - 32767,32767,32767, 82,32767,32767,32767,32767,32767,32767, + 456,32767,32767, 242,32767,32767,32767, 309,32767,32767, 32767,32767,32767,32767,32767,32767,32767,32767,32767,32767, - 383,32767,32767,32767, 401,32767, 414, 433, 381,32767, - 327, 328, 330,32767, 423, 352, 353, 354, 355, 356, - 357, 358, 360,32767, 461, 386,32767,32767,32767,32767, - 32767,32767, 84, 108, 245,32767, 473, 84, 384,32767, - 473,32767,32767,32767,32767,32767,32767, 286,32767,32767, - 32767, 84,32767, 84,32767,32767, 457,32767,32767, 421, - 385,32767, 326, 398, 439,32767,32767, 422,32767,32767, - 218, 84,32767, 177,32767,32767,32767,32767,32767,32767, - 401,32767,32767, 179,32767,32767, 421,32767,32767,32767, - 32767,32767, 281,32767,32767,32767,32767,32767, 421,32767, - 32767,32767,32767, 222,32767,32767,32767,32767,32767,32767, - 32767,32767,32767,32767,32767,32767,32767,32767,32767, 82, - 60,32767, 263,32767,32767,32767,32767,32767,32767,32767, - 32767,32767,32767,32767,32767, 121, 121, 3, 3, 121, - 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, - 121, 121, 121, 121, 248, 154, 248, 204, 248, 248, - 207, 196, 196, 255 + 32767, 85, 60,32767, 289,32767,32767,32767,32767,32767, + 32767,32767,32767,32767,32767,32767, 136, 136, 3, 272, + 3, 272, 136, 136, 136, 272, 272, 136, 136, 136, + 136, 136, 136, 136, 169, 224, 227, 216, 216, 281, + 136, 136 ]; PHP.Parser.prototype.yygoto = [ - 163, 163, 135, 135, 135, 146, 148, 179, 164, 161, - 145, 161, 161, 161, 162, 162, 162, 162, 162, 162, - 162, 145, 157, 158, 159, 160, 176, 174, 177, 410, - 411, 299, 412, 415, 416, 417, 418, 419, 420, 421, - 422, 857, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 147, 173, 175, 178, 195, 198, 199, 201, 202, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 232, 233, 251, 252, 253, 316, 317, 318, 462, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 149, 194, 150, 165, 166, 167, 196, - 168, 151, 152, 153, 169, 154, 197, 133, 170, 155, - 171, 172, 156, 521, 200, 257, 246, 464, 432, 687, - 649, 278, 481, 482, 527, 200, 437, 437, 437, 766, - 5, 746, 650, 557, 437, 426, 775, 770, 428, 431, - 444, 465, 466, 468, 483, 279, 651, 336, 450, 453, - 437, 560, 485, 487, 508, 511, 763, 516, 517, 777, - 524, 762, 526, 532, 773, 534, 480, 480, 965, 965, - 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, - 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, - 413, 413, 413, 413, 942, 502, 478, 496, 512, 456, - 298, 437, 437, 451, 471, 437, 437, 674, 437, 229, - 456, 230, 231, 463, 828, 533, 681, 438, 513, 826, - 461, 475, 460, 414, 414, 414, 414, 414, 414, 414, - 414, 414, 414, 414, 414, 414, 414, 301, 674, 674, - 443, 454, 1033, 1033, 1034, 1034, 425, 531, 425, 708, - 750, 800, 457, 372, 1033, 943, 1034, 1026, 300, 1018, - 497, 8, 313, 904, 796, 944, 996, 785, 789, 1007, - 285, 670, 1036, 329, 307, 310, 804, 668, 544, 332, - 935, 940, 366, 807, 678, 477, 377, 754, 844, 0, - 667, 667, 675, 675, 675, 677, 0, 666, 323, 498, - 328, 312, 312, 258, 259, 283, 459, 261, 322, 284, - 326, 486, 280, 281, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 790, 790, 790, 790, 946, 0, 946, - 790, 790, 1004, 790, 1004, 0, 0, 0, 0, 836, - 0, 1015, 1015, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 744, 744, 744, 720, 744, 0, - 739, 745, 721, 780, 780, 1023, 0, 0, 1002, 0, + 171, 144, 144, 144, 171, 152, 153, 152, 155, 187, + 172, 168, 168, 168, 168, 169, 169, 169, 169, 169, + 169, 169, 164, 165, 166, 167, 184, 182, 185, 445, + 446, 334, 447, 450, 451, 452, 453, 454, 455, 456, + 457, 924, 141, 145, 146, 147, 170, 148, 149, 143, + 150, 151, 154, 181, 183, 186, 206, 209, 211, 212, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 244, 245, 264, 265, 266, 339, 340, 341, 496, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, 199, 200, 201, 202, 156, 203, 157, 173, 174, + 175, 207, 176, 158, 159, 160, 177, 161, 208, 142, + 204, 162, 178, 205, 179, 180, 163, 563, 210, 463, + 210, 516, 516, 1038, 572, 1038, 1038, 1038, 1038, 1038, + 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 468, 468, + 468, 514, 537, 468, 297, 489, 521, 489, 498, 274, + 533, 534, 698, 483, 258, 468, 448, 448, 448, 725, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 448, 449, 449, 449, 699, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 1114, 1114, 734, 725, 899, 725, 315, 319, 475, 499, + 500, 502, 1083, 1084, 468, 468, 760, 1114, 761, 900, + 482, 506, 468, 468, 468, 329, 330, 686, 481, 545, + 495, 332, 510, 596, 523, 525, 294, 469, 538, 556, + 559, 835, 566, 574, 831, 765, 729, 717, 864, 494, + 807, 868, 490, 860, 716, 716, 810, 697, 1013, 1105, + 726, 726, 726, 728, 715, 840, 1093, 800, 824, 805, + 805, 803, 805, 595, 313, 460, 833, 828, 459, 3, + 4, 907, 733, 539, 1009, 487, 317, 461, 459, 497, + 892, 575, 972, 474, 843, 557, 890, 1129, 484, 485, + 505, 517, 519, 520, 568, 801, 801, 801, 801, 465, + 855, 795, 802, 1002, 787, 405, 1003, 799, 327, 571, + 356, 1082, 530, 1014, 848, 346, 540, 350, 11, 337, + 337, 280, 281, 283, 493, 344, 284, 345, 285, 348, + 524, 351, 1015, 1069, 1113, 1113, 543, 301, 298, 299, + 721, 560, 838, 838, 1100, 295, 865, 718, 600, 323, + 544, 1113, 1010, 1017, 511, 1005, 869, 849, 849, 849, + 849, 849, 849, 1017, 849, 849, 849, 720, 730, 1116, + 714, 812, 849, 1088, 1088, 909, 465, 398, 513, 414, + 1017, 1017, 1017, 1017, 0, 1079, 1017, 1017, 0, 701, + 0, 0, 0, 0, 0, 1079, 0, 0, 0, 0, + 0, 773, 1090, 1090, 774, 706, 0, 756, 751, 752, + 766, 0, 707, 753, 704, 754, 755, 705, 0, 759, + 0, 1075, 0, 0, 0, 0, 0, 1012, 0, 0, + 0, 480, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 867, 0, 1077, 1077, 867, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 806, 0, 806, 0, 0, 0, 0, 1008, 1009 + 0, 0, 0, 0, 0, 0, 0, 0, 462, 478, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 462, + 0, 478, 0, 0, 316, 0, 0, 466, 386, 0, + 388, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 724, 0, 1121 ]; PHP.Parser.prototype.yygcheck = [ - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 52, 45, 112, 112, 80, 8, 10, - 10, 64, 55, 55, 55, 45, 8, 8, 8, 10, - 92, 10, 11, 10, 8, 10, 10, 10, 38, 38, - 38, 38, 38, 38, 62, 62, 12, 62, 28, 8, - 8, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 113, 113, 113, 113, 76, 56, 35, 35, 56, 69, - 56, 8, 8, 8, 8, 8, 8, 19, 8, 60, - 69, 60, 60, 7, 7, 7, 25, 8, 7, 7, - 2, 2, 8, 115, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 53, 19, 19, - 53, 53, 123, 123, 124, 124, 109, 5, 109, 44, - 29, 78, 114, 53, 123, 76, 124, 122, 41, 120, - 43, 53, 42, 96, 74, 76, 76, 72, 75, 117, - 14, 21, 123, 18, 9, 13, 79, 20, 66, 17, - 102, 104, 58, 81, 22, 59, 100, 63, 94, -1, - 19, 19, 19, 19, 19, 19, -1, 19, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 64, 64, -1, -1, -1, -1, -1, -1, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 63, 56, 10, + 56, 86, 86, 86, 8, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 10, 10, + 10, 46, 46, 10, 80, 85, 73, 85, 97, 134, + 73, 73, 17, 10, 134, 10, 135, 135, 135, 26, + 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 137, 137, 137, 18, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 148, 148, 36, 26, 111, 26, 49, 49, 49, 49, + 49, 49, 141, 141, 10, 10, 55, 148, 55, 111, + 10, 10, 10, 10, 10, 69, 69, 5, 39, 69, + 2, 69, 2, 39, 39, 39, 69, 10, 39, 39, + 39, 39, 39, 39, 39, 13, 14, 14, 14, 10, + 40, 14, 136, 94, 26, 26, 14, 16, 92, 146, + 26, 26, 26, 26, 26, 14, 143, 14, 16, 16, + 16, 16, 16, 16, 52, 16, 16, 16, 75, 37, + 37, 14, 14, 54, 14, 53, 65, 65, 75, 7, + 7, 7, 118, 65, 88, 7, 7, 12, 65, 65, + 68, 68, 68, 68, 68, 75, 75, 75, 75, 12, + 90, 75, 75, 67, 67, 65, 67, 76, 76, 76, + 89, 139, 24, 92, 91, 56, 56, 56, 65, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 92, 92, 147, 147, 12, 20, 80, 80, + 30, 12, 85, 85, 85, 11, 96, 28, 82, 19, + 23, 147, 127, 63, 15, 124, 99, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 15, 32, 147, + 15, 79, 63, 8, 8, 114, 12, 71, 72, 122, + 63, 63, 63, 63, -1, 97, 63, 63, -1, 13, + -1, -1, -1, -1, -1, 97, -1, -1, -1, -1, + -1, 63, 97, 97, 63, 13, -1, 13, 13, 13, + 13, -1, 13, 13, 13, 13, 13, 13, -1, 13, + -1, 97, -1, -1, -1, -1, -1, 12, -1, -1, + -1, 8, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 97, -1, 97, 97, 97, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 52, 52, 52, 52, 52, -1, 52, - 52, 52, 80, 52, 80, -1, -1, -1, -1, 92, - -1, 80, 80, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 52, 52, 52, 52, 52, -1, - 52, 52, 52, 69, 69, 69, -1, -1, 80, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 80, -1, 80, -1, -1, -1, -1, 80, 80 + -1, -1, -1, -1, -1, -1, -1, -1, 8, 8, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, + -1, 8, -1, -1, 8, -1, -1, 8, 8, -1, + 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8, -1, 8 ]; PHP.Parser.prototype.yygbase = [ - 0, 0, -317, 0, 0, 237, 0, 210, -136, 4, - 118, 130, 144, -10, 16, 0, 0, -59, 10, -47, - -9, 7, -77, -20, 0, 209, 0, 0, -388, 234, - 0, 0, 0, 0, 0, 165, 0, 0, 103, 0, - 0, 225, 44, 45, 235, 84, 0, 0, 0, 0, - 0, 0, 109, -115, 0, -113, -179, 0, -78, -81, - -347, 0, -122, -80, -249, 0, -19, 0, 0, 169, - -48, 0, 26, 0, 22, 24, -99, 0, 230, -13, - 114, -79, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 120, 0, -90, 0, 23, 0, 0, 0, - -89, 0, -67, 0, -69, 0, 0, 0, 0, 8, - 0, 0, -140, -34, 229, 9, 0, 21, 0, 0, - 218, 0, 233, -3, -1, 0 + 0, 0, -358, 0, 0, 207, 0, 274, 114, 0, + -148, 54, 10, 94, -144, -40, 245, 150, 174, 48, + 70, 0, 0, -3, 25, 0, -108, 0, 44, 0, + 52, 0, 3, -23, 0, 0, 183, -331, 0, -359, + 221, 0, 0, 0, 0, 0, 106, 0, 0, 157, + 0, 0, 227, 45, 47, 191, 90, 0, 0, 0, + 0, 0, 0, 111, 0, -95, 0, -26, 43, -193, + 0, -12, -20, -435, 0, 26, 37, 0, 0, 4, + -259, 0, 20, 0, 0, 117, -104, 0, 31, 55, + 46, 53, -64, 0, 216, 0, 40, 143, 0, -10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -34, 0, 0, 7, 0, 0, 0, 30, 0, + 0, 0, -32, 0, -9, 0, 0, -5, 0, 0, + 0, 0, 0, 0, -119, -69, 217, -52, 0, 51, + 0, -102, 0, 226, 0, 0, 223, 77, -67, 0, + 0 ]; PHP.Parser.prototype.yygdefault = [ - -32768, 380, 565, 2, 566, 637, 645, 504, 400, 433, - 748, 688, 689, 303, 342, 401, 302, 330, 324, 676, - 669, 671, 679, 134, 333, 682, 1, 684, 439, 716, - 291, 692, 292, 507, 694, 446, 696, 697, 427, 304, - 305, 447, 311, 479, 707, 203, 308, 709, 290, 710, - 719, 335, 293, 510, 489, 469, 501, 402, 363, 476, - 228, 455, 473, 753, 277, 761, 549, 769, 772, 403, - 404, 470, 784, 368, 794, 788, 960, 319, 799, 805, - 991, 808, 811, 349, 331, 327, 815, 816, 4, 820, - 522, 523, 835, 239, 843, 856, 347, 923, 925, 441, - 374, 936, 360, 334, 939, 995, 354, 405, 364, 952, - 260, 282, 245, 406, 423, 249, 407, 365, 998, 314, - 1019, 424, 1027, 1035, 275, 474 + -32768, 420, 603, 2, 604, 676, 684, 548, 437, 573, + 438, 464, 335, 758, 913, 778, 740, 741, 742, 320, + 361, 311, 318, 531, 518, 410, 727, 381, 719, 407, + 722, 380, 731, 140, 549, 416, 735, 1, 737, 470, + 769, 308, 745, 309, 552, 747, 477, 749, 750, 314, + 321, 322, 917, 486, 515, 762, 213, 479, 763, 307, + 764, 772, 331, 312, 392, 417, 326, 894, 504, 527, + 376, 395, 512, 507, 488, 1024, 797, 401, 390, 811, + 296, 819, 601, 827, 830, 439, 440, 399, 842, 400, + 853, 847, 1032, 394, 859, 382, 866, 1064, 385, 870, + 228, 873, 255, 546, 349, 878, 879, 6, 884, 564, + 565, 7, 243, 415, 908, 547, 379, 923, 364, 991, + 993, 472, 408, 1006, 389, 555, 418, 1011, 1068, 377, + 441, 396, 282, 300, 257, 442, 458, 262, 443, 397, + 1071, 1078, 338, 1094, 279, 26, 1106, 1115, 292, 492, + 509 ]; PHP.Parser.prototype.yylhs = [ @@ -2173,48 +2234,52 @@ PHP.Parser.prototype.yylhs = [ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 8, 8, 9, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 14, 14, 15, 15, - 15, 15, 17, 17, 13, 13, 18, 18, 19, 19, - 20, 20, 21, 21, 16, 16, 22, 24, 24, 25, - 26, 26, 28, 27, 27, 27, 27, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 10, 10, 48, 48, 51, 51, 50, 49, - 49, 42, 42, 53, 53, 54, 54, 11, 12, 12, - 12, 57, 57, 57, 58, 58, 61, 61, 59, 59, - 62, 62, 36, 36, 44, 44, 47, 47, 47, 46, - 46, 63, 37, 37, 37, 37, 64, 64, 65, 65, - 66, 66, 34, 34, 30, 30, 67, 32, 32, 68, - 31, 31, 33, 33, 43, 43, 43, 43, 55, 55, - 71, 71, 72, 72, 74, 74, 75, 75, 75, 73, - 73, 56, 56, 76, 76, 77, 77, 78, 78, 78, - 39, 39, 79, 40, 40, 81, 81, 60, 60, 82, - 82, 82, 82, 87, 87, 88, 88, 89, 89, 89, - 89, 89, 90, 91, 91, 86, 86, 83, 83, 85, - 85, 93, 93, 92, 92, 92, 92, 92, 92, 84, - 84, 94, 94, 41, 41, 35, 35, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 101, 95, 95, 100, 100, 103, 103, 104, 105, 105, - 105, 109, 109, 52, 52, 52, 96, 96, 107, 107, - 97, 97, 99, 99, 99, 102, 102, 113, 113, 70, - 115, 115, 115, 98, 98, 98, 98, 98, 98, 98, - 98, 98, 98, 98, 98, 98, 98, 98, 98, 38, - 38, 111, 111, 111, 106, 106, 106, 116, 116, 116, - 116, 116, 116, 45, 45, 45, 80, 80, 80, 118, - 110, 110, 110, 110, 110, 110, 108, 108, 108, 117, - 117, 117, 117, 69, 119, 119, 120, 120, 120, 120, - 120, 114, 121, 121, 122, 122, 122, 122, 122, 112, - 112, 112, 112, 124, 123, 123, 123, 123, 123, 123, - 123, 125, 125, 125 + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 8, 9, 10, 10, 11, 12, 13, + 13, 14, 14, 15, 15, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 20, 20, 21, 21, + 21, 21, 23, 25, 25, 19, 27, 27, 24, 29, + 29, 26, 26, 28, 28, 30, 30, 22, 31, 31, + 32, 34, 35, 35, 36, 37, 37, 39, 38, 38, + 38, 38, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 16, 16, 59, + 59, 62, 62, 61, 60, 60, 53, 64, 64, 65, + 65, 66, 66, 67, 67, 17, 18, 18, 18, 70, + 70, 70, 71, 71, 74, 74, 72, 72, 76, 77, + 77, 47, 47, 55, 55, 58, 58, 58, 57, 78, + 78, 79, 48, 48, 48, 48, 80, 80, 81, 81, + 82, 82, 45, 45, 41, 41, 83, 43, 43, 84, + 42, 42, 44, 44, 54, 54, 54, 54, 68, 68, + 87, 87, 88, 88, 88, 90, 90, 91, 91, 91, + 89, 89, 69, 69, 69, 92, 92, 93, 93, 94, + 94, 94, 50, 95, 95, 96, 51, 98, 98, 99, + 99, 100, 100, 73, 101, 101, 101, 101, 101, 106, + 106, 107, 107, 108, 108, 108, 108, 108, 109, 110, + 110, 105, 105, 102, 102, 104, 104, 112, 112, 111, + 111, 111, 111, 111, 111, 103, 113, 113, 115, 114, + 114, 52, 116, 116, 46, 46, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 123, 117, 117, 122, 122, 125, 126, 126, + 127, 128, 128, 128, 75, 75, 63, 63, 63, 118, + 118, 118, 130, 130, 119, 119, 121, 121, 121, 124, + 124, 135, 135, 135, 86, 137, 137, 137, 120, 120, + 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 49, 49, 133, 133, 133, 129, + 129, 129, 138, 138, 138, 138, 138, 138, 56, 56, + 56, 97, 97, 97, 97, 141, 140, 132, 132, 132, + 132, 132, 132, 131, 131, 131, 139, 139, 139, 139, + 85, 142, 142, 143, 143, 143, 143, 143, 143, 143, + 136, 145, 145, 144, 144, 146, 146, 146, 146, 146, + 146, 134, 134, 134, 134, 148, 149, 147, 147, 147, + 147, 147, 147, 147, 150, 150, 150, 150 ]; PHP.Parser.prototype.yylen = [ @@ -2226,47 +2291,51 @@ PHP.Parser.prototype.yylen = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, + 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, + 1, 0, 1, 0, 1, 1, 1, 1, 1, 3, 5, 4, 3, 4, 2, 3, 1, 1, 7, 8, - 6, 7, 3, 1, 3, 1, 3, 1, 1, 3, - 1, 2, 1, 2, 3, 1, 3, 3, 1, 3, - 2, 0, 1, 1, 1, 1, 1, 3, 7, 10, - 5, 7, 9, 5, 3, 3, 3, 3, 3, 3, - 1, 2, 5, 7, 9, 5, 6, 3, 3, 2, - 2, 1, 1, 1, 0, 2, 1, 3, 8, 0, - 4, 1, 3, 0, 1, 0, 1, 10, 7, 6, - 5, 1, 2, 2, 0, 2, 0, 2, 0, 2, - 1, 3, 1, 4, 1, 4, 1, 1, 4, 1, + 6, 7, 2, 3, 1, 2, 3, 1, 2, 3, + 1, 1, 3, 1, 2, 1, 2, 2, 3, 1, + 3, 2, 3, 1, 3, 2, 0, 1, 1, 1, + 1, 1, 3, 7, 10, 5, 7, 9, 5, 3, + 3, 3, 3, 3, 3, 1, 2, 5, 7, 9, + 6, 5, 6, 3, 3, 2, 1, 1, 1, 0, + 2, 1, 3, 8, 0, 4, 2, 1, 3, 0, + 1, 0, 1, 3, 1, 8, 7, 6, 5, 1, + 2, 2, 0, 2, 0, 2, 0, 2, 2, 1, + 3, 1, 4, 1, 4, 1, 1, 4, 2, 1, 3, 3, 3, 4, 4, 5, 0, 2, 4, 3, 1, 1, 1, 4, 0, 2, 5, 0, 2, 6, - 0, 2, 0, 3, 1, 2, 1, 1, 1, 0, - 1, 3, 4, 6, 1, 2, 1, 1, 1, 0, - 1, 0, 2, 2, 3, 1, 3, 1, 2, 2, - 3, 1, 1, 3, 1, 1, 3, 2, 0, 3, - 4, 9, 3, 1, 3, 0, 2, 4, 5, 4, - 4, 4, 3, 1, 1, 1, 3, 1, 1, 0, - 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, - 3, 1, 3, 3, 1, 0, 1, 1, 3, 3, - 3, 4, 1, 2, 3, 3, 3, 3, 3, 3, + 0, 2, 0, 3, 1, 2, 1, 1, 2, 0, + 1, 3, 4, 6, 4, 1, 2, 1, 1, 1, + 0, 1, 0, 2, 2, 2, 4, 1, 3, 1, + 2, 2, 2, 3, 1, 1, 2, 3, 1, 1, + 3, 2, 0, 1, 4, 4, 9, 3, 1, 1, + 3, 0, 2, 4, 5, 4, 4, 4, 3, 1, + 1, 1, 1, 1, 1, 0, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 2, 1, 3, 1, 1, + 3, 2, 3, 1, 0, 1, 1, 3, 3, 3, + 4, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 4, 4, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 1, 3, 2, 1, 2, 4, 2, 10, 11, - 7, 3, 2, 0, 4, 1, 3, 2, 2, 2, - 4, 1, 1, 1, 2, 3, 1, 1, 1, 1, - 0, 3, 0, 1, 1, 0, 1, 1, 3, 3, - 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 3, 2, 3, 3, 0, - 1, 1, 3, 1, 1, 3, 1, 1, 4, 4, - 4, 1, 4, 1, 1, 3, 1, 4, 2, 3, - 1, 4, 4, 3, 3, 3, 1, 3, 1, 1, - 3, 1, 1, 4, 3, 1, 1, 1, 3, 3, - 0, 1, 3, 1, 3, 1, 4, 2, 0, 2, - 2, 1, 2, 1, 1, 4, 3, 3, 3, 6, - 3, 1, 1, 1 + 2, 1, 3, 2, 1, 2, 4, 2, 8, 9, + 8, 9, 7, 3, 2, 0, 4, 2, 1, 3, + 2, 2, 2, 4, 1, 1, 1, 2, 3, 1, + 1, 1, 1, 1, 0, 3, 0, 1, 1, 0, + 1, 1, 3, 3, 3, 4, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 2, 3, 3, 0, 1, 1, 3, 1, 1, + 3, 1, 1, 4, 4, 4, 1, 4, 1, 1, + 3, 1, 4, 2, 2, 1, 3, 1, 4, 4, + 3, 3, 3, 1, 3, 1, 1, 3, 1, 1, + 4, 3, 1, 1, 2, 1, 3, 4, 3, 0, + 1, 1, 1, 3, 1, 3, 1, 4, 2, 2, + 0, 2, 2, 1, 2, 1, 1, 1, 4, 3, + 3, 3, 6, 3, 1, 1, 2, 1 ]; From 0b98d52e883ad93c16e8a26ed7bbd74c1d969c39 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 7 Jun 2020 18:55:32 +0400 Subject: [PATCH 0377/1293] add tripple quote string support to swift mode --- lib/ace/mode/swift_highlight_rules.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/ace/mode/swift_highlight_rules.js b/lib/ace/mode/swift_highlight_rules.js index 55b49cd3fcb..b1d1631a5f7 100644 --- a/lib/ace/mode/swift_highlight_rules.js +++ b/lib/ace/mode/swift_highlight_rules.js @@ -146,6 +146,12 @@ var SwiftHighlightRules = function() { this.$rules = { start: [ + string('"""', { + escape: /\\(?:[0\\tnr"']|u{[a-fA-F1-9]{0,8}})/, + interpolation: {lead: "\\", open: "(", close: ")"}, + error: /\\./, + multiline: true + }), string('"', { escape: /\\(?:[0\\tnr"']|u{[a-fA-F1-9]{0,8}})/, interpolation: {lead: "\\", open: "(", close: ")"}, From 02b5326898f956b430a1322f3300b649930ad7e3 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 7 Jun 2020 18:59:48 +0400 Subject: [PATCH 0378/1293] keep letter case in keyword completion --- lib/ace/mode/text_highlight_rules.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/ace/mode/text_highlight_rules.js b/lib/ace/mode/text_highlight_rules.js index eaace2cc4ee..0360b5d12de 100644 --- a/lib/ace/mode/text_highlight_rules.js +++ b/lib/ace/mode/text_highlight_rules.js @@ -209,20 +209,18 @@ var TextHighlightRules = function() { this.createKeywordMapper = function(map, defaultToken, ignoreCase, splitChar) { var keywords = Object.create(null); + this.$keywordList = []; Object.keys(map).forEach(function(className) { var a = map[className]; - if (ignoreCase) - a = a.toLowerCase(); var list = a.split(splitChar || "|"); - for (var i = list.length; i--; ) - keywords[list[i]] = className; - }); - // in old versions of opera keywords["__proto__"] sets prototype - // even on objects with __proto__=null - if (Object.getPrototypeOf(keywords)) { - keywords.__proto__ = null; - } - this.$keywordList = Object.keys(keywords); + for (var i = list.length; i--; ) { + var word = list[i]; + this.$keywordList.push(word); + if (ignoreCase) + word = word.toLowerCase(); + keywords[word] = className; + } + }, this); map = null; return ignoreCase ? function(value) {return keywords[value.toLowerCase()] || defaultToken; } From 3ffdc6be6102d54381c47f61dc5e98723902364f Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 7 Jun 2020 19:01:02 +0400 Subject: [PATCH 0379/1293] workaround for chrome returning browser zoom as css zoom on documentElement --- lib/ace/layer/font_metrics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/layer/font_metrics.js b/lib/ace/layer/font_metrics.js index d0f83978a8c..87754766ace 100644 --- a/lib/ace/layer/font_metrics.js +++ b/lib/ace/layer/font_metrics.js @@ -168,7 +168,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { this.$getZoom = function getZoom(element) { - if (!element) return 1; + if (!element || !element.parentElement) return 1; return (window.getComputedStyle(element).zoom || 1) * getZoom(element.parentElement); }; this.$initTransformMeasureNodes = function() { From 87d0e2b631df93a84221ab14420a51ef51f6140e Mon Sep 17 00:00:00 2001 From: kylon Date: Sat, 13 Jun 2020 18:04:40 +0200 Subject: [PATCH 0380/1293] ASL mode: cleanup --- lib/ace/mode/asl_highlight_rules.js | 33 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/ace/mode/asl_highlight_rules.js b/lib/ace/mode/asl_highlight_rules.js index 8a075bb1213..5e946504f84 100644 --- a/lib/ace/mode/asl_highlight_rules.js +++ b/lib/ace/mode/asl_highlight_rules.js @@ -38,16 +38,7 @@ define(function(require, exports, module) { var ASLHighlightRules = function() { var keywords = ( "Default|DefinitionBlock|Device|Method|Else|ElseIf|For|Function|If|Include|Method|Return|" + - "Scope|Switch|Case|While|Break|BreakPoint|Continue|NoOp|Wait" - ); - - var keywordOperators = ( - "Add|And|Decrement|Divide|Increment|Index|LAnd|LEqual|LGreater|LGreaterEqual|" + - "LLess|LLessEqual|LNot|LNotEqual|LOr|Mod|Multiply|NAnd|NOr|Not|Or|RefOf|Revision|" + - "ShiftLeft|ShiftRight|Subtract|XOr|DerefOf" - ); - - var buildinFunctions = ( + "Scope|Switch|Case|While|Break|BreakPoint|Continue|NoOp|Wait|True|False|" + "AccessAs|Acquire|Alias|BankField|Buffer|Concatenate|ConcatenateResTemplate|" + "CondRefOf|Connection|CopyObject|CreateBitField|CreateByteField|CreateDWordField|" + "CreateField|CreateQWordField|CreateWordField|DataTableRegion|Debug|" + @@ -63,6 +54,12 @@ define(function(require, exports, module) { "WordSpace" ); + var keywordOperators = ( + "Add|And|Decrement|Divide|Increment|Index|LAnd|LEqual|LGreater|LGreaterEqual|" + + "LLess|LLessEqual|LNot|LNotEqual|LOr|Mod|Multiply|NAnd|NOr|Not|Or|RefOf|Revision|" + + "ShiftLeft|ShiftRight|Subtract|XOr|DerefOf" + ); + var flags = ( "AttribQuick|AttribSendReceive|AttribByte|AttribBytes|AttribRawBytes|" + "AttribRawProcessBytes|AttribWord|AttribBlock|AttribProcessCall|AttribBlockProcessCall|" + @@ -101,21 +98,25 @@ define(function(require, exports, module) { "ThermalZoneObj|BuffFieldObj|DDBHandleObj" ); - var buildinConstants = ( + var builtinConstants = ( "__FILE__|__PATH__|__LINE__|__DATE__|__IASL__" ); + var strNumbers = ( + "One|Ones|Zero" + ); + var deprecated = ( "Memory24|Processor" ); var keywordMapper = this.createKeywordMapper({ "keyword": keywords, + "constant.numeric": strNumbers, "keyword.operator": keywordOperators, - "function.buildin": buildinFunctions, - "constant.language": buildinConstants, + "constant.language": builtinConstants, "storage.type": storageTypes, - "constant.character": flags, + "constant.library": flags, "invalid.deprecated": deprecated }, "identifier"); @@ -154,13 +155,13 @@ define(function(require, exports, module) { regex : /0[xX][0-9a-fA-F]+\b/ }, { token : "constant.numeric", - regex : /(One(s)?|Zero|True|False|[0-9]+)\b/ + regex : /[0-9]+\b/ }, { token : keywordMapper, regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" }, { token : "keyword.operator", - regex : "/|!|\\$|%|&|\\||\\*|\\-\\-|\\-|\\+\\+|\\+|~|==|=|!=|\\^|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\|=" + regex : /[!\~\*\/%+-<>\^|=&]/ }, { token : "lparen", regex : "[[({]" From 375cc6c7883c401c1e21eeb0e7485a86b3a9489c Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 18 Jun 2020 17:40:26 +0700 Subject: [PATCH 0381/1293] improved mobile context menu positioning --- lib/ace/mouse/touch_handler.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/ace/mouse/touch_handler.js b/lib/ace/mouse/touch_handler.js index d533b998484..11578ecdc92 100644 --- a/lib/ace/mouse/touch_handler.js +++ b/lib/ace/mouse/touch_handler.js @@ -120,9 +120,17 @@ exports.addTouchListeners = function(el, editor) { if (!contextMenu) createContextMenu(); var cursor = editor.selection.cursor; var pagePos = editor.renderer.textToScreenCoordinates(cursor.row, cursor.column); + var leftOffset = editor.renderer.textToScreenCoordinates(0, 0).pageX; + var scrollLeft = editor.renderer.scrollLeft; var rect = editor.container.getBoundingClientRect(); contextMenu.style.top = pagePos.pageY - rect.top - 3 + "px"; - contextMenu.style.right = "10px"; + if(pagePos.pageX - rect.left < rect.width - 70) { + contextMenu.style.removeProperty('left'); + contextMenu.style.right = "10px"; + } else { + contextMenu.style.removeProperty('right'); + contextMenu.style.left = leftOffset + scrollLeft - rect.left + "px"; + } contextMenu.style.display = ""; contextMenu.firstChild.style.display = "none"; editor.on("input", hideContextMenu); From 2cf7d29ab1325cc580e0b2b868e61f091da7ca06 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Tue, 14 Apr 2020 18:02:19 +0400 Subject: [PATCH 0382/1293] use github actions --- .github/workflows/nodejs.yml | 51 ++++++++++ .travis.yml | 42 --------- Readme.md | 2 +- build | 2 +- lib/ace/config_test.js | 4 +- lib/ace/mode/_test/tokens_asl.json | 146 ++++++++++++++++++----------- lib/ace/mouse/touch_handler.js | 10 +- package.json | 2 +- 8 files changed, 150 insertions(+), 109 deletions(-) create mode 100644 .github/workflows/nodejs.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 00000000000..a223ab2b8cd --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,51 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [12.x] + + steps: + - uses: actions/checkout@v2 + - name: Fetch the master branch + run: git fetch origin HEAD:refs/remotes/origin/HEAD --depth 1 + - name: Fetch the master branch + run: git diff --name-only origin/HEAD --no-renames --diff-filter=ACMR + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm i && npm i eslint istanbul typescript + - run: node_modules/.bin/istanbul cover lib/ace/test/all.js + - run: changes=$(git diff --name-only origin/HEAD --no-renames --diff-filter=ACMR); + if [ "$changes" == "" ]; then + echo "checking all files"; + node node_modules/eslint/bin/eslint "lib/ace/**/*.js"; + else + changes=$(echo "$changes" | grep -P '.js$'); + echo "checking $changes"; + if [ "$changes" != "" ]; then + node node_modules/eslint/bin/eslint $changes; + fi + fi + # - run: npm run lint + - run: node_modules/.bin/tsc --noImplicitAny --strict --noUnusedLocals --noImplicitReturns --noUnusedParameters --noImplicitThis ace.d.ts + - uses: codecov/codecov-action@v1 + with: + file: ./coverage/coverage.json + flags: unittests + name: codecov-umbrella + fail_ci_if_error: true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9df0d8ab767..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,42 +0,0 @@ -language: node_js - -node_js: - - "8" - -install: - - cleanup() { find node_modules -regextype posix-extended -iregex '.*((test|example|doc|demo)s?|\.(md)|license|idea|coverage|file.txt)$' -exec rm -rf {} \; || echo $?; }; - install() { npm i && npm i eslint@6.1.0 codecov istanbul typescript && cp package.json node_modules/package.json; cleanup; }; - cmp --silent package.json node_modules/package.json || install; - -script: - - changes=$(git diff --name-only origin/HEAD --no-renames --diff-filter=ACMR); - if [ "$changes" == "" ]; then - echo "checking all files"; - node node_modules/eslint/bin/eslint "lib/ace/**/*.js"; - else - changes=$(echo "$changes" | grep -P '.js$'); - echo "checking $changes"; - if [ "$changes" != "" ]; then - node node_modules/eslint/bin/eslint $changes; - fi - fi - - node_modules/.bin/istanbul cover lib/ace/test/all.js - - node_modules/.bin/codecov - - node_modules/.bin/tsc --noImplicitAny --strict --noUnusedLocals --noImplicitReturns --noUnusedParameters --noImplicitThis ace.d.ts - -matrix: - fast_finish: false - -cache: - directories: - - node_modules - -sudo: false - -git: - depth: 1 - submodules: false - -branches: - only: - - master \ No newline at end of file diff --git a/Readme.md b/Readme.md index 8ebb711b4a4..055e23f4b9b 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,7 @@ Ace (Ajax.org Cloud9 Editor) ============================ -[![Build Status](https://secure.travis-ci.org/ajaxorg/ace.svg?branch=master)](http://travis-ci.org/ajaxorg/ace) [![npm](https://img.shields.io/npm/v/ace-builds.svg)](https://www.npmjs.com/package/ace-builds) +[![Build Status](https://github.com/nightwing/ace/workflows/CI/badge.svg)](https://github.com/nightwing/ace/actions) [![npm](https://img.shields.io/npm/v/ace-builds.svg)](https://www.npmjs.com/package/ace-builds) _Note_: The new site at http://ace.c9.io contains all the info below along with an embedding guide and all the other resources you need to get started with Ace. diff --git a/build b/build index 2ea299a2bee..bb63e649538 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 2ea299a2bee97fdf58fc90cb76eec6c45535a63f +Subproject commit bb63e6495383f1731c297d1a6ef76f814d71c23b diff --git a/lib/ace/config_test.js b/lib/ace/config_test.js index f1d516056ce..92aee486bff 100644 --- a/lib/ace/config_test.js +++ b/lib/ace/config_test.js @@ -68,9 +68,7 @@ module.exports = { assert.equal(url, "_.js"); url = config.moduleUrl("ace/ext/textarea"); - assert.equal(url, "a/b/ext-textarea.js"); - - assert.equal(); + assert.equal(url, "a/b/ext-textarea.js"); }, "test: define options" : function() { var o = {}; diff --git a/lib/ace/mode/_test/tokens_asl.json b/lib/ace/mode/_test/tokens_asl.json index 9218492ae5f..09bf65b5c09 100644 --- a/lib/ace/mode/_test/tokens_asl.json +++ b/lib/ace/mode/_test/tokens_asl.json @@ -22,15 +22,20 @@ ["text"," "], ["lparen","("], ["string","\"\""], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["string","\"SSDT\""], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["constant.numeric","1"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["string","\"PmRef\""], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["string","\"Cpu0Ist\""], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["constant.numeric","0x00003000"], ["rparen",")"] ],[ @@ -39,25 +44,27 @@ ],[ "start", ["text"," "], - ["function.buildin","External"], + ["keyword","External"], ["text"," "], ["lparen","("], ["identifier","_PR_"], - ["text","."], + ["keyword.operator","."], ["identifier","CPU0"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["storage.type","DeviceObj"], ["rparen",")"] ],[ "start", ["text"," "], - ["function.buildin","External"], + ["keyword","External"], ["text"," "], ["lparen","("], ["identifier","_SB_"], - ["text","."], + ["keyword.operator","."], ["identifier","CPUP"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["storage.type","UnknownObj"], ["rparen",")"] ],[ @@ -70,7 +77,7 @@ ["lparen","("], ["text","\\"], ["identifier","_PR"], - ["text","."], + ["keyword.operator","."], ["identifier","CPU0"], ["rparen",")"] ],[ @@ -84,10 +91,12 @@ ["text"," "], ["lparen","("], ["identifier","_PCT"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["constant.numeric","0"], - ["text",", "], - ["constant.character","NotSerialized"], + ["keyword.operator",","], + ["text"," "], + ["constant.library","NotSerialized"], ["rparen",")"], ["text"," "], ["comment","// _PCT: Performance Control"] @@ -127,7 +136,7 @@ ["keyword","Return"], ["text"," "], ["lparen","("], - ["function.buildin","Package"], + ["keyword","Package"], ["text"," "], ["lparen","("], ["constant.numeric","0x02"], @@ -139,7 +148,7 @@ ],[ "start", ["text"," "], - ["function.buildin","ResourceTemplate"], + ["keyword","ResourceTemplate"], ["text"," "], ["lparen","("], ["rparen",")"] @@ -150,44 +159,50 @@ ],[ "start", ["text"," "], - ["function.buildin","Register"], + ["keyword","Register"], ["text"," "], ["lparen","("], - ["constant.character","FFixedHW"], - ["text",", "] + ["constant.library","FFixedHW"], + ["keyword.operator",","], + ["text"," "] ],[ "start", ["text"," "], ["constant.numeric","0x00"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Bit Width"] ],[ "start", ["text"," "], ["constant.numeric","0x00"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Bit Offset"] ],[ "start", ["text"," "], ["constant.numeric","0x0000000000000000"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Address"] ],[ "start", - ["text"," ,"], + ["text"," "], + ["keyword.operator",","], ["rparen",")"] ],[ "start", ["text"," "], ["rparen","}"], - ["text",", "] + ["keyword.operator",","], + ["text"," "] ],[ "start" ],[ "start", ["text"," "], - ["function.buildin","ResourceTemplate"], + ["keyword","ResourceTemplate"], ["text"," "], ["lparen","("], ["rparen",")"] @@ -198,32 +213,37 @@ ],[ "start", ["text"," "], - ["function.buildin","Register"], + ["keyword","Register"], ["text"," "], ["lparen","("], - ["constant.character","FFixedHW"], - ["text",", "] + ["constant.library","FFixedHW"], + ["keyword.operator",","], + ["text"," "] ],[ "start", ["text"," "], ["constant.numeric","0x00"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Bit Width"] ],[ "start", ["text"," "], ["constant.numeric","0x00"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Bit Offset"] ],[ "start", ["text"," "], ["constant.numeric","0x0000000000000000"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Address"] ],[ "start", - ["text"," ,"], + ["text"," "], + ["keyword.operator",","], ["rparen",")"] ],[ "start", @@ -245,7 +265,7 @@ ["keyword","Return"], ["text"," "], ["lparen","("], - ["function.buildin","Package"], + ["keyword","Package"], ["text"," "], ["lparen","("], ["constant.numeric","0x02"], @@ -257,7 +277,7 @@ ],[ "start", ["text"," "], - ["function.buildin","ResourceTemplate"], + ["keyword","ResourceTemplate"], ["text"," "], ["lparen","("], ["rparen",")"] @@ -268,44 +288,50 @@ ],[ "start", ["text"," "], - ["function.buildin","Register"], + ["keyword","Register"], ["text"," "], ["lparen","("], - ["constant.character","SystemIO"], - ["text",", "] + ["constant.library","SystemIO"], + ["keyword.operator",","], + ["text"," "] ],[ "start", ["text"," "], ["constant.numeric","0x10"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Bit Width"] ],[ "start", ["text"," "], ["constant.numeric","0x00"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Bit Offset"] ],[ "start", ["text"," "], ["constant.numeric","0x0000000000001000"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Address"] ],[ "start", - ["text"," ,"], + ["text"," "], + ["keyword.operator",","], ["rparen",")"] ],[ "start", ["text"," "], ["rparen","}"], - ["text",", "] + ["keyword.operator",","], + ["text"," "] ],[ "start" ],[ "start", ["text"," "], - ["function.buildin","ResourceTemplate"], + ["keyword","ResourceTemplate"], ["text"," "], ["lparen","("], ["rparen",")"] @@ -316,32 +342,37 @@ ],[ "start", ["text"," "], - ["function.buildin","Register"], + ["keyword","Register"], ["text"," "], ["lparen","("], - ["constant.character","SystemIO"], - ["text",", "] + ["constant.library","SystemIO"], + ["keyword.operator",","], + ["text"," "] ],[ "start", ["text"," "], ["constant.numeric","0x08"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Bit Width"] ],[ "start", ["text"," "], ["constant.numeric","0x00"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Bit Offset"] ],[ "start", ["text"," "], ["constant.numeric","0x00000000000000B3"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["comment","// Address"] ],[ "start", - ["text"," ,"], + ["text"," "], + ["keyword.operator",","], ["rparen",")"] ],[ "start", @@ -360,11 +391,12 @@ ],[ "start", ["text"," "], - ["function.buildin","Name"], + ["keyword","Name"], ["text"," "], ["lparen","("], ["identifier","PSDF"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["constant.numeric","Zero"], ["rparen",")"] ],[ @@ -374,10 +406,12 @@ ["text"," "], ["lparen","("], ["identifier","_PSD"], - ["text",", "], + ["keyword.operator",","], + ["text"," "], ["constant.numeric","0"], - ["text",", "], - ["constant.character","NotSerialized"], + ["keyword.operator",","], + ["text"," "], + ["constant.library","NotSerialized"], ["rparen",")"], ["text"," "], ["comment","// _PSD: Power State Dependencies"] diff --git a/lib/ace/mouse/touch_handler.js b/lib/ace/mouse/touch_handler.js index 11578ecdc92..7d02b25b7a1 100644 --- a/lib/ace/mouse/touch_handler.js +++ b/lib/ace/mouse/touch_handler.js @@ -124,12 +124,12 @@ exports.addTouchListeners = function(el, editor) { var scrollLeft = editor.renderer.scrollLeft; var rect = editor.container.getBoundingClientRect(); contextMenu.style.top = pagePos.pageY - rect.top - 3 + "px"; - if(pagePos.pageX - rect.left < rect.width - 70) { - contextMenu.style.removeProperty('left'); - contextMenu.style.right = "10px"; + if (pagePos.pageX - rect.left < rect.width - 70) { + contextMenu.style.left = ""; + contextMenu.style.right = "10px"; } else { - contextMenu.style.removeProperty('right'); - contextMenu.style.left = leftOffset + scrollLeft - rect.left + "px"; + contextMenu.style.right = ""; + contextMenu.style.left = leftOffset + scrollLeft - rect.left + "px"; } contextMenu.style.display = ""; contextMenu.firstChild.style.display = "none"; diff --git a/package.json b/package.json index 8fa740bfca0..1003406f727 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "scripts": { "start": "node static.js", "test": "node lib/ace/test/all.js", - "lint": "eslint 'lib/ace/**/*.js'", + "lint": "eslint \"lib/ace/**/*.js\"", "fix": "eslint --fix 'lib/ace/**/*.js'" } } From e8babcd289631710a72b80d41980ef2ae630dc47 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 1 Jul 2020 01:32:09 +0400 Subject: [PATCH 0383/1293] fix error when destroying editor in iframe --- lib/ace/editor.js | 2 ++ lib/ace/lib/event.js | 13 +++++++------ lib/ace/mouse/mouse_handler.js | 3 +++ lib/ace/mouse/mouse_handler_test.js | 11 ++++++++++- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 2cd108fdaa4..65de11e157f 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -2764,6 +2764,8 @@ Editor.$uid = 0; }); this.$toDestroy = null; } + if (this.$mouseHandler) + this.$mouseHandler.destroy(); this.renderer.destroy(); this._signal("destroy", this); if (this.session) diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js index 3edef160496..4f33c6cd636 100644 --- a/lib/ace/lib/event.js +++ b/lib/ace/lib/event.js @@ -108,18 +108,19 @@ exports.getButton = function(e) { }; exports.capture = function(el, eventHandler, releaseCaptureHandler) { + var ownerDocument = el && el.ownerDocument || document; function onMouseUp(e) { eventHandler && eventHandler(e); releaseCaptureHandler && releaseCaptureHandler(e); - removeListener(document, "mousemove", eventHandler); - removeListener(document, "mouseup", onMouseUp); - removeListener(document, "dragstart", onMouseUp); + removeListener(ownerDocument, "mousemove", eventHandler); + removeListener(ownerDocument, "mouseup", onMouseUp); + removeListener(ownerDocument, "dragstart", onMouseUp); } - addListener(document, "mousemove", eventHandler); - addListener(document, "mouseup", onMouseUp); - addListener(document, "dragstart", onMouseUp); + addListener(ownerDocument, "mousemove", eventHandler); + addListener(ownerDocument, "mouseup", onMouseUp); + addListener(ownerDocument, "dragstart", onMouseUp); return onMouseUp; }; diff --git a/lib/ace/mouse/mouse_handler.js b/lib/ace/mouse/mouse_handler.js index 37cce5fc6fc..e6287dd1964 100644 --- a/lib/ace/mouse/mouse_handler.js +++ b/lib/ace/mouse/mouse_handler.js @@ -205,6 +205,9 @@ var MouseHandler = function(editor) { setTimeout(stop, 10); this.editor.on("nativecontextmenu", stop); }; + this.destroy = function() { + if (this.releaseMouse) this.releaseMouse(); + }; }).call(MouseHandler.prototype); config.defineOptions(MouseHandler.prototype, "mouseHandler", { diff --git a/lib/ace/mouse/mouse_handler_test.js b/lib/ace/mouse/mouse_handler_test.js index 39538fff562..2a3f6685046 100644 --- a/lib/ace/mouse/mouse_handler_test.js +++ b/lib/ace/mouse/mouse_handler_test.js @@ -265,8 +265,17 @@ module.exports = { assert.equal(editor.getSelectedText(), "Kin"); }, + "test: destroy while mouse is pressed": function() { + assert.ok(!this.editor.$mouseHandler.releaseMouse); + var target = this.editor.renderer.getMouseEventTarget(); + target.dispatchEvent(MouseEvent("down", {x: 0, y: 0})); + assert.ok(this.editor.$mouseHandler.releaseMouse); + this.editor.destroy(); + assert.ok(!this.editor.$mouseHandler.releaseMouse); + }, tearDown : function() { - document.body.removeChild(this.editor.container); + this.editor.destroy(); + document.body.removeChild(this.editor.container); } }; From 4fa3fb6b302745212af27ad96c7f9453b68e45fb Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 3 Jul 2020 15:11:29 +0400 Subject: [PATCH 0384/1293] fix snippet choices popup --- lib/ace/autocomplete.js | 10 +++++++--- lib/ace/snippets.js | 12 ++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index 078cd6dbf47..07659197954 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -108,6 +108,7 @@ var Autocomplete = function() { } else if (keepPopupPosition && !prefix) { this.detach(); } + this.changeTimer.cancel(); }; this.detach = function() { @@ -172,15 +173,16 @@ var Autocomplete = function() { if (!data) return false; + var completions = this.completions; this.editor.startOperation({command: {name: "insertMatch"}}); if (data.completer && data.completer.insertMatch) { data.completer.insertMatch(this.editor, data); } else { // TODO add support for options.deleteSuffix - if (this.completions.filterText) { + if (completions.filterText) { var ranges = this.editor.selection.getAllRanges(); for (var i = 0, range; range = ranges[i]; i++) { - range.start.column -= this.completions.filterText.length; + range.start.column -= completions.filterText.length; this.editor.session.remove(range); } } @@ -189,7 +191,9 @@ var Autocomplete = function() { else this.editor.execCommand("insertstring", data.value || data); } - this.detach(); + // detach only if new popup was not opened while inserting match + if (this.completions == completions) + this.detach(); this.editor.endOperation(); }; diff --git a/lib/ace/snippets.js b/lib/ace/snippets.js index a96e91bfea1..594b5362498 100644 --- a/lib/ace/snippets.js +++ b/lib/ace/snippets.js @@ -177,7 +177,9 @@ var SnippetManager = function() { {regex: "\\|" + escape("\\|") + "*\\|", onMatch: function(val, state, stack) { var choices = val.slice(1, -1).replace(/\\[,|\\]|,/g, function(operator) { return operator.length == 2 ? operator[1] : "\x00"; - }).split("\x00"); + }).split("\x00").map(function(value){ + return {value: value}; + }); stack[0].choices = choices; return [choices[0]]; }, next: "start"}, @@ -886,19 +888,17 @@ var TabstopManager = function(editor) { this.selectedTabstop = ts; var range = ts.firstNonLinked || ts; + if (ts.choices) range.cursor = range.start; if (!this.editor.inVirtualSelectionMode) { var sel = this.editor.multiSelect; - sel.toSingleRange(range.clone()); + sel.toSingleRange(range); for (var i = 0; i < ts.length; i++) { if (ts.hasLinkedRanges && ts[i].linked) continue; sel.addRange(ts[i].clone(), true); } - // todo investigate why is this needed - if (sel.ranges[0]) - sel.addRange(sel.ranges[0].clone()); } else { - this.editor.selection.setRange(range); + this.editor.selection.fromOrientedRange(range); } this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); From 2ccda8c1ba350415de0e949abd50888abb6645fe Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 6 Jul 2020 20:03:52 +0400 Subject: [PATCH 0385/1293] release v1.4.12 --- ChangeLog.txt | 5 +++++ build | 2 +- lib/ace/config.js | 2 +- package.json | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 0c823853b4c..9ac4cccef35 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,8 @@ +2020.07.06 Version 1.4.12 +* removed unused es5-shim +* imporved ruby and vbscript highlighting and folding +* workaround for double space being converted to dot on mobile keyboards + 2020.04.15 Version 1.4.10 * added workaround for chrome bug causing memory leak after calling editor.destroy * added code folding support for vbscript mode diff --git a/build b/build index bb63e649538..53be42342df 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit bb63e6495383f1731c297d1a6ef76f814d71c23b +Subproject commit 53be42342df216d2d25dc60a12dfcb263c6f0592 diff --git a/lib/ace/config.js b/lib/ace/config.js index ac6d8938441..349635e2c85 100644 --- a/lib/ace/config.js +++ b/lib/ace/config.js @@ -220,6 +220,6 @@ function deHyphenate(str) { return str.replace(/-(.)/g, function(m, m1) { return m1.toUpperCase(); }); } -exports.version = "1.4.10"; +exports.version = "1.4.12"; }); diff --git a/package.json b/package.json index 1003406f727..95882b15f55 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.4.10", + "version": "1.4.12", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" From 4e96653032f248a87d879d7d28cddd5e196d6ecf Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 6 Jul 2020 23:00:29 +0400 Subject: [PATCH 0386/1293] disable hi-dpi on chromeOs to avoid blurred text --- Readme.md | 3 ++- lib/ace/lib/dom.js | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 055e23f4b9b..80e7775121b 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,8 @@ Ace (Ajax.org Cloud9 Editor) ============================ -[![Build Status](https://github.com/nightwing/ace/workflows/CI/badge.svg)](https://github.com/nightwing/ace/actions) [![npm](https://img.shields.io/npm/v/ace-builds.svg)](https://www.npmjs.com/package/ace-builds) +[![Build Status](https://github.com/ajaxorg/ace/workflows/CI/badge.svg)](https://github.com/ajaxorg/ace/actions) +[![npm](https://img.shields.io/npm/v/ace-builds.svg)](https://www.npmjs.com/package/ace-builds) _Note_: The new site at http://ace.c9.io contains all the info below along with an embedding guide and all the other resources you need to get started with Ace. diff --git a/lib/ace/lib/dom.js b/lib/ace/lib/dom.js index e34cdfdc889..0e8d324cc51 100644 --- a/lib/ace/lib/dom.js +++ b/lib/ace/lib/dom.js @@ -267,6 +267,8 @@ exports.HI_DPI = useragent.isWin ? typeof window !== "undefined" && window.devicePixelRatio >= 1.5 : true; +if (useragent.isChromeOS) exports.HI_DPI = false; + if (typeof document !== "undefined") { // detect CSS transformation support var div = document.createElement("div"); From 66ecb6258f13c0e4e82065751cfbe921d207fa41 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 6 Jul 2020 23:40:15 +0400 Subject: [PATCH 0387/1293] do not break negative lookbehind regexp group --- lib/ace/tokenizer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/tokenizer.js b/lib/ace/tokenizer.js index d3585107eff..ad181bd77be 100644 --- a/lib/ace/tokenizer.js +++ b/lib/ace/tokenizer.js @@ -176,7 +176,7 @@ var Tokenizer = function(rules) { this.removeCapturingGroups = function(src) { var r = src.replace( - /\\.|\[(?:\\.|[^\\\]])*|\(\?[:=!]|(\()/g, + /\\.|\[(?:\\.|[^\\\]])*|\(\?[:=!<]|(\()/g, function(x, y) {return y ? "(?:" : x;} ); return r; From 53347eb75bc45444662e0e12823a6dcb89e18d65 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 7 Jul 2020 00:46:55 +0400 Subject: [PATCH 0388/1293] fix Command pallete showing wrong shortcuts when running on Mac --- demo/kitchen-sink/demo.js | 1 - kitchen-sink.html | 4 ++++ lib/ace/ext/prompt.js | 9 +++------ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 603475e5c7f..9aa7e7cc085 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -48,7 +48,6 @@ var env = {}; var dom = require("ace/lib/dom"); var net = require("ace/lib/net"); var lang = require("ace/lib/lang"); -var useragent = require("ace/lib/useragent"); var event = require("ace/lib/event"); var theme = require("ace/theme/textmate"); diff --git a/kitchen-sink.html b/kitchen-sink.html index 6cf83c887c0..9102831f9a6 100644 --- a/kitchen-sink.html +++ b/kitchen-sink.html @@ -51,6 +51,10 @@
    + + + + + diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index bd4226c59c5..e863dc170bc 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -119,6 +119,7 @@ var supportedModes = { Julia: ["jl"], Kotlin: ["kt|kts"], LaTeX: ["tex|latex|ltx|bib"], + Latte: ["latte"], LESS: ["less"], Liquid: ["liquid"], Lisp: ["lisp"], @@ -195,7 +196,7 @@ var supportedModes = { Textile: ["textile"], Toml: ["toml"], TSX: ["tsx"], - Twig: ["latte|twig|swig"], + Twig: ["twig|swig"], Typescript: ["ts|typescript|str"], Vala: ["vala"], VBScript: ["vbs|vb"], diff --git a/lib/ace/mode/_test/tokens_latte.json b/lib/ace/mode/_test/tokens_latte.json new file mode 100644 index 00000000000..df1a5312e8f --- /dev/null +++ b/lib/ace/mode/_test/tokens_latte.json @@ -0,0 +1,309 @@ +[[ + "start", + ["xml-pe.doctype.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","html"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","head"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","title"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.latte","{"], + ["variable","$title"], + ["meta.tag.punctuation.tag-close.latte","}"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "comment.start.latte", + ["text.xml"," "], + ["comment.start.latte","{*"], + ["comment"," "] +],[ + "comment.start.latte", + ["comment"," \tcomment"] +],[ + "start", + ["comment.end.latte"," *}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","body"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," \t"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h1"], + ["text.tag-whitespace.xml"," "], + ["meta.attribute.latte","n:inner-if"], + ["keyword.operator.attribute-equals.xml","="], + ["constant.numeric","0"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["entity.other.attribute-name.xml","My"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","Webpage"], + ["text",""] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","ul"], + ["text.tag-whitespace.xml"," "], + ["meta.attribute.latte","n:if"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["string.unquoted","count"], + ["paren.lparen","("], + ["variable","$navigation"], + ["paren.rparen",")"], + ["keyword.operator"," > "], + ["constant.numeric","0"], + ["string.attribute-value.xml","\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"navigation\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.latte","{"], + ["meta.tag.latte","foreach"], + ["keyword.operator"," "], + ["paren.lparen","["], + ["string.unquoted","a"], + ["keyword.operator",", "], + ["string.unquoted","b"], + ["keyword.operator",", "], + ["string.start","'"], + ["string","x"], + ["string.end","'"], + ["keyword.operator",", "], + ["constant.numeric","10"], + ["paren.rparen","]"], + ["keyword.operator"," "], + ["keyword.control","as"], + ["keyword.operator"," "], + ["variable","$item"], + ["meta.tag.punctuation.tag-close.latte","}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","li"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-open.latte","{"], + ["variable","$item"], + ["meta.tag.punctuation.tag-close.latte","}"], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.latte","{"], + ["meta.tag.latte","test"], + ["paren.lparen","("], + ["variable","$item"], + ["keyword.operator","->"], + ["string.unquoted","caption"], + ["paren.rparen",")"], + ["meta.tag.punctuation.tag-close.latte","}"], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.latte","{/"], + ["meta.tag.latte","foreach"], + ["meta.tag.punctuation.tag-close.latte","}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.latte","{"], + ["variable","$variable"], + ["meta.tag.punctuation.tag-close.latte","}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.latte","{"], + ["meta.tag.latte","="], + ["variable","$variable"], + ["meta.tag.punctuation.tag-close.latte","}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.latte","{"], + ["variable","$variable"], + ["keyword.operator","|"], + ["string.unquoted","filter"], + ["meta.tag.punctuation.tag-close.latte","}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.latte","{"], + ["variable","$variable"], + ["keyword.operator","|"], + ["string.unquoted","filter"], + ["keyword.operator",":"], + ["constant.numeric","10"], + ["keyword.operator",","], + ["constant.numeric","20"], + ["keyword.operator","|"], + ["string.unquoted","filter2"], + ["meta.tag.punctuation.tag-close.latte","}"] +],[ + "start" +],[ + "js-start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.script.tag-name.xml","script"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "js-start", + ["text","\t "], + ["storage.type","var"], + ["text"," "], + ["identifier","a"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["meta.tag.punctuation.tag-open.latte","{"], + ["variable","$a"], + ["meta.tag.punctuation.tag-close.latte","}"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","b"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","{"], + ["string","'a'"], + ["punctuation.operator",":"], + ["text"," "], + ["constant.numeric","1"], + ["paren.rparen","}"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","c"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","{"], + ["string","'a'"], + ["punctuation.operator",":"], + ["text"," "], + ["constant.numeric","1"], + ["paren.rparen","}"], + ["punctuation.operator",";"] +],[ + "js-start", + ["text","\t "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["constant.language.boolean","true"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "js-start", + ["text","\t \t"], + ["support.function","alert"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "js-no_regex", + ["text","\t "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "css-start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.style.tag-name.xml","style"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "css-start", + ["text"," \t"], + ["constant","body"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["support.type","color"], + ["punctuation.operator",":"], + ["text"," "], + ["meta.tag.punctuation.tag-open.latte","{"], + ["variable","$color"], + ["meta.tag.punctuation.tag-close.latte","}"], + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +]] \ No newline at end of file diff --git a/lib/ace/mode/latte.js b/lib/ace/mode/latte.js new file mode 100644 index 00000000000..5a2bb566efa --- /dev/null +++ b/lib/ace/mode/latte.js @@ -0,0 +1,73 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2013, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var HtmlMode = require("./html").Mode; +var LatteHighlightRules = require("./latte_highlight_rules").LatteHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; + +var Mode = function() { + HtmlMode.call(this); + this.HighlightRules = LatteHighlightRules; + this.$outdent = new MatchingBraceOutdent(); +}; +oop.inherits(Mode, HtmlMode); + +(function() { + this.blockComment = {start: "{*", end: "*}"}; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + if (state == "start") { + var match = line.match(/^.*\{(?:if|else|elseif|ifset|elseifset|ifchanged|switch|case|foreach|iterateWhile|for|while|first|last|sep|try|capture|spaceless|snippet|block|define|embed|snippetArea)\b[^{]*$/); + if (match) { + indent += tab; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return /^\s+\{\/$/.test(line + input); + }; + + this.autoOutdent = function(state, doc, row) { + }; + + this.$id = "ace/mode/latte"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); \ No newline at end of file diff --git a/lib/ace/mode/latte_highlight_rules.js b/lib/ace/mode/latte_highlight_rules.js new file mode 100644 index 00000000000..74f7985f2e6 --- /dev/null +++ b/lib/ace/mode/latte_highlight_rules.js @@ -0,0 +1,193 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2013, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var lang = require("../lib/lang"); +var HtmlHighlightRules = require("./html_highlight_rules").HtmlHighlightRules; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var LatteHighlightRules = function() { + // inherit from html + HtmlHighlightRules.call(this); + + // add latte start tags to the HTML + for (var rule in this.$rules) { + this.$rules[rule].unshift( + { + token : "comment.start.latte", + regex : "\\{\\*", + push : [{ + token : "comment.end.latte", + regex : ".*\\*\\}", + next : "pop" + }, { + defaultToken : "comment" + }] + }, { + token : "meta.tag.punctuation.tag-open.latte", + regex : "\\{(?![\\s'\"{}]|$)/?", + push : [{ + token : "meta.tag.latte", + regex : "(?:_|=|[a-z]\\w*(?:[.:-]\\w+)*)?", + next: [{ + token : "meta.tag.punctuation.tag-close.latte", + regex : "\\}", + next : "pop" + }, { + include: "latte-content" + }] + }] + }); + } + + // add n:attribute to HTML tag + this.$rules['tag_stuff'].unshift({ + token : "meta.attribute.latte", + regex : "n:[\\w-]+", + next : [{ + include: "tag_whitespace" + }, { + token : "keyword.operator.attribute-equals.xml", + regex : "=", + next : [{ + token : "string.attribute-value.xml", + regex : "'", + next : [ + {token : "string.attribute-value.xml", regex: "'", next: "tag_stuff"}, + {include : "latte-content"} + ] + }, { + token : "string.attribute-value.xml", + regex : '"', + next : [ + {token : "string.attribute-value.xml", regex: '"', next: "tag_stuff"}, + {include : "latte-content"} + ] + }, { + token : "text.tag-whitespace.xml", + regex : "\\s", + next: "tag_stuff" + }, { + token : "meta.tag.punctuation.tag-close.xml", + regex : "/?>", + next: "tag_stuff" + }, { + include : "latte-content", + }] + }, { + token : "empty", + regex : "", + next : "tag_stuff" + }] + }); + + + // PHP content + this.$rules["latte-content"] = [ + { + token : "comment.start.latte", // multi line comment + regex : "\\/\\*", + push : [ + { + token : "comment.end.latte", + regex : "\\*\\/", + next : "pop" + }, { + defaultToken : "comment" + } + ] + }, { + token : "string.start", // " string start + regex : '"', + push : [ + { + token : "constant.language.escape", + regex : '\\\\(?:[nrtvef\\\\"$]|[0-7]{1,3}|x[0-9A-Fa-f]{1,2})' + }, { + token : "variable", + regex : /\$[\w]+(?:\[[\w\]+]|[=\-]>\w+)?/ + }, { + token : "variable", + regex : /\$\{[^"\}]+\}?/ // this is wrong but ok for now + }, + {token : "string.end", regex : '"', next : "pop"}, + {defaultToken : "string"} + ] + }, { + token : "string.start", // ' string start + regex : "'", + push : [ + {token : "constant.language.escape", regex : /\\['\\]/}, + {token : "string.end", regex : "'", next : "pop"}, + {defaultToken : "string"} + ] + }, { + token : "keyword.control", + regex : "\\b(?:INF|NAN|and|or|xor|AND|OR|XOR|clone|new|instanceof|return|continue|break|as)\\b" + }, { + token : "constant.language", + regex : "\\b(?:true|false|null|TRUE|FALSE|NULL)\\b" + }, { + token : "variable", + regex : /\$\w+/ + }, { + token : "constant.numeric", + regex : "[+-]?[0-9]+(?:\\.[0-9]+)?(?:e[0-9]+)?" + }, { + token : ["support.class", "keyword.operator"], + regex : "\\b(\\w+)(::)" + }, { + token : "constant.language", // constants + regex : "\\b(?:[A-Z0-9_]+)\\b" + }, { + token : "string.unquoted", + regex : "\\w+(?:-+\\w+)*" + }, { + token : "paren.lparen", + regex : "[[({]" + }, { + token : "paren.rparen", + regex : "[\\])}]" + }, { + token : "keyword.operator", + regex : "::|=>|->|\\?->|\\?\\?->|\\+\\+|--|<<|>>|<=>|<=|>=|===|!==|==|!=|<>|&&|\\|\\||\\?\\?|\\?>|\\*\\*|\\.\\.\\.|[^'\"]", // =>, any char except quotes + } + ]; + + this.normalizeRules(); +}; + +oop.inherits(LatteHighlightRules, TextHighlightRules); + +exports.LatteHighlightRules = LatteHighlightRules; +}); From ba0c3913f73db1ebdb5cfb1d82c0651eccafbbe7 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 4 Feb 2021 17:39:38 +0100 Subject: [PATCH 0418/1293] fixes --- lib/ace/mode/latte_highlight_rules.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/ace/mode/latte_highlight_rules.js b/lib/ace/mode/latte_highlight_rules.js index 74f7985f2e6..62749a9b53f 100644 --- a/lib/ace/mode/latte_highlight_rules.js +++ b/lib/ace/mode/latte_highlight_rules.js @@ -32,7 +32,6 @@ define(function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); -var lang = require("../lib/lang"); var HtmlHighlightRules = require("./html_highlight_rules").HtmlHighlightRules; var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; @@ -102,7 +101,7 @@ var LatteHighlightRules = function() { regex : "/?>", next: "tag_stuff" }, { - include : "latte-content", + include : "latte-content" }] }, { token : "empty", @@ -180,7 +179,7 @@ var LatteHighlightRules = function() { regex : "[\\])}]" }, { token : "keyword.operator", - regex : "::|=>|->|\\?->|\\?\\?->|\\+\\+|--|<<|>>|<=>|<=|>=|===|!==|==|!=|<>|&&|\\|\\||\\?\\?|\\?>|\\*\\*|\\.\\.\\.|[^'\"]", // =>, any char except quotes + regex : "::|=>|->|\\?->|\\?\\?->|\\+\\+|--|<<|>>|<=>|<=|>=|===|!==|==|!=|<>|&&|\\|\\||\\?\\?|\\?>|\\*\\*|\\.\\.\\.|[^'\"]" // =>, any char except quotes } ]; From 0e4a721b00af24123c9c1afbc4f50ce4dbb04076 Mon Sep 17 00:00:00 2001 From: Nick <589193+nbilyk@users.noreply.github.com> Date: Sat, 6 Feb 2021 08:03:05 -0600 Subject: [PATCH 0419/1293] Change links from ace.ajax.org to ace.c9.io --- api/index.html | 2 +- api/resources/javascripts/ux.js | 2 +- demo/kitchen-sink/docs/livescript.ls | 2 +- doc/index.md | 2 +- doc/site/js/main.js | 2 +- doc/template/resources/javascripts/ux.js | 2 +- tool/tmtheme.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/index.html b/api/index.html index cccaab54bec..7d3a386ede6 100644 --- a/api/index.html +++ b/api/index.html @@ -1,7 +1,7 @@

    Ace API Reference

    Welcome to the Ace API Reference Guide. Ace is a standalone code editor written in JavaScript that you can embed onto any website. We're used in a bunch of places already, like GitHub, Google, and Facebook.

    -

    On the left, you'll find a list of all of our currently documented classes. There are plenty more to do, but these represent the "core" set. For more information on how to work with Ace, check out the main Ace website.

    +

    On the left, you'll find a list of all of our currently documented classes. There are plenty more to do, but these represent the "core" set. For more information on how to work with Ace, check out the main Ace website.

    diff --git a/api/resources/javascripts/ux.js b/api/resources/javascripts/ux.js index 3bb07cf44ac..ec94c25630d 100644 --- a/api/resources/javascripts/ux.js +++ b/api/resources/javascripts/ux.js @@ -24,7 +24,7 @@ $(function () { if (query) { input.value = ""; input.blur(); - var url = "https://www.google.com/search?q=" + encodeURIComponent("site:ace.ajax.org" + " " + query); + var url = "https://www.google.com/search?q=" + encodeURIComponent("site:ace.c9.io" + " " + query); window.open(url); } return false; diff --git a/demo/kitchen-sink/docs/livescript.ls b/demo/kitchen-sink/docs/livescript.ls index ce082b4cb2d..d029ffae14d 100644 --- a/demo/kitchen-sink/docs/livescript.ls +++ b/demo/kitchen-sink/docs/livescript.ls @@ -1,4 +1,4 @@ -# Defines an editing mode for [Ace](http://ace.ajax.org). +# Defines an editing mode for [Ace](https://ace.c9.io). # # Open [test/ace.html](../test/ace.html) to test. diff --git a/doc/index.md b/doc/index.md index 41733852872..589802cbd5b 100644 --- a/doc/index.md +++ b/doc/index.md @@ -2,4 +2,4 @@ Welcome to the Ace API Reference Guide. Ace is a standalone code editor written in JavaScript that you can embed onto any website. We're used in a bunch of places already, like GitHub, Google, and Facebook. -On the left, you'll find a list of all of our currently documented classes. There are plenty more to do, but these represent the "core" set. For more information on how to work with Ace, check out the [main Ace website](http://ace.ajax.org). \ No newline at end of file +On the left, you'll find a list of all of our currently documented classes. There are plenty more to do, but these represent the "core" set. For more information on how to work with Ace, check out the [main Ace website](https://ace.c9.io). diff --git a/doc/site/js/main.js b/doc/site/js/main.js index c50760ba673..d7df23a4437 100644 --- a/doc/site/js/main.js +++ b/doc/site/js/main.js @@ -100,7 +100,7 @@ $(function() { tabs.find(tab_a_selector).click(function(e) { e.preventDefault(); if ($(this).attr("href") === "/") { - window.location = "http://ace.ajax.org/"; + window.location = "https://ace.c9.io/"; return; } if ($(this).attr("href").indexOf("#api") === 0) { diff --git a/doc/template/resources/javascripts/ux.js b/doc/template/resources/javascripts/ux.js index 3bb07cf44ac..ec94c25630d 100644 --- a/doc/template/resources/javascripts/ux.js +++ b/doc/template/resources/javascripts/ux.js @@ -24,7 +24,7 @@ $(function () { if (query) { input.value = ""; input.blur(); - var url = "https://www.google.com/search?q=" + encodeURIComponent("site:ace.ajax.org" + " " + query); + var url = "https://www.google.com/search?q=" + encodeURIComponent("site:ace.c9.io" + " " + query); window.open(url); } return false; diff --git a/tool/tmtheme.js b/tool/tmtheme.js index e3f40ade43c..90b27e959f4 100755 --- a/tool/tmtheme.js +++ b/tool/tmtheme.js @@ -398,7 +398,7 @@ if (Object.keys(unsupportedScopes).length > 0) { console.log("I found these unsupported scopes:"); console.log(sortedUnsupportedScopes); console.log("It's safe to ignore these, but they may affect your syntax highlighting if your mode depends on any of these rules."); - console.log("Refer to the docs on ace.ajax.org for information on how to add a scope to the CSS generator."); + console.log("Refer to the docs on ace.c9.io for information on how to add a scope to the CSS generator."); } From ff8b08b8758ce94231f94c72ecef6b09b61ef779 Mon Sep 17 00:00:00 2001 From: bogger33 Date: Wed, 10 Feb 2021 07:15:51 +0100 Subject: [PATCH 0420/1293] remove 2 csslint rules that only target ancient browsers These two rules no longer serve any purpose, all modern and even fairly old browsers support these features now. --- lib/ace/mode/css/csslint.js | 104 ------------------------------------ 1 file changed, 104 deletions(-) diff --git a/lib/ace/mode/css/csslint.js b/lib/ace/mode/css/csslint.js index 2dc5e44d16e..9be23ed05ea 100644 --- a/lib/ace/mode/css/csslint.js +++ b/lib/ace/mode/css/csslint.js @@ -7300,34 +7300,6 @@ CSSLint.addRule({ }); -/* - * Rule: box-sizing doesn't work in IE6 and IE7. - */ - -CSSLint.addRule({ - - //rule information - id: "box-sizing", - name: "Disallow use of box-sizing", - desc: "The box-sizing properties isn't supported in IE6 and IE7.", - browsers: "IE6, IE7", - tags: ["Compatibility"], - - //initialization - init: function(parser, reporter){ - var rule = this; - - parser.addListener("property", function(event){ - var name = event.property.text.toLowerCase(); - - if (name === "box-sizing"){ - reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule); - } - }); - } - -}); - /* * Rule: Use the bulletproof @font-face syntax to avoid 404's in old IE * (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax) @@ -7843,82 +7815,6 @@ CSSLint.addRule({ }); -CSSLint.addRule({ - - //rule information - id: "fallback-colors", - name: "Require fallback colors", - desc: "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.", - browsers: "IE6,IE7,IE8", - - //initialization - init: function(parser, reporter){ - var rule = this, - lastProperty, - propertiesToCheck = { - color: 1, - background: 1, - "border-color": 1, - "border-top-color": 1, - "border-right-color": 1, - "border-bottom-color": 1, - "border-left-color": 1, - border: 1, - "border-top": 1, - "border-right": 1, - "border-bottom": 1, - "border-left": 1, - "background-color": 1 - }, - properties; - - function startRule(){ - properties = {}; - lastProperty = null; - } - - parser.addListener("startrule", startRule); - parser.addListener("startfontface", startRule); - parser.addListener("startpage", startRule); - parser.addListener("startpagemargin", startRule); - parser.addListener("startkeyframerule", startRule); - - parser.addListener("property", function(event){ - var property = event.property, - name = property.text.toLowerCase(), - parts = event.value.parts, - i = 0, - colorType = "", - len = parts.length; - - if(propertiesToCheck[name]){ - while(i < len){ - if (parts[i].type === "color"){ - if ("alpha" in parts[i] || "hue" in parts[i]){ - - if (/([^\)]+)\(/.test(parts[i])){ - colorType = RegExp.$1.toUpperCase(); - } - - if (!lastProperty || (lastProperty.property.text.toLowerCase() !== name || lastProperty.colorType !== "compat")){ - reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule); - } - } else { - event.colorType = "compat"; - } - } - - i++; - } - } - - lastProperty = event; - }); - - } - -}); - /* * Rule: You shouldn't use more than 10 floats. If you do, there's probably * room for some abstraction. From dbba2178b78fd7402ba0f282a85d334eea1d5c9c Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 13 Feb 2021 12:47:04 +0000 Subject: [PATCH 0421/1293] Fix vim's `dG` when performed over the whole range --- lib/ace/keyboard/vim.js | 3 ++- lib/ace/keyboard/vim_test.js | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index 8e87d78c5ce..a56a4525afa 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -2921,7 +2921,8 @@ dom.importCssString(".normal-mode .ace_cursor{\ } var prevLineEnd = new Pos(anchor.line - 1, Number.MAX_VALUE); var wasLastLine = cm.firstLine() == cm.lastLine(); - if (head.line > cm.lastLine() && args.linewise && !wasLastLine) { + var isFirstLine = cm.firstLine() == anchor.line; + if (head.line > cm.lastLine() && args.linewise && !wasLastLine && !isFirstLine) { cm.replaceRange('', prevLineEnd, head); } else { cm.replaceRange('', anchor, head); diff --git a/lib/ace/keyboard/vim_test.js b/lib/ace/keyboard/vim_test.js index 86f2b657ff0..625f6fbade4 100644 --- a/lib/ace/keyboard/vim_test.js +++ b/lib/ace/keyboard/vim_test.js @@ -1091,6 +1091,12 @@ testVim('dd_only_line', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq(expectedRegister, register.toString()); }, { value: "thisistheonlyline" }); +testVim('cG', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('c', 'G', 'inserted'); + eq('inserted\n', cm.getValue()); + helpers.assertCursorAt(0, 8); +}, { value: 'line1\nline2'}); // Yank commands should behave the exact same as d commands, expect that nothing // gets deleted. testVim('yw_repeat', function(cm, vim, helpers) { From b0fdf260ea00806246ca9d5adfd09849ebcf4c93 Mon Sep 17 00:00:00 2001 From: wafuwafu13 Date: Sat, 20 Feb 2021 15:20:50 +0900 Subject: [PATCH 0422/1293] add some types --- ace.d.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ace.d.ts b/ace.d.ts index ac4e606f423..0cd2a983350 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -20,10 +20,12 @@ export namespace Ace { getLine(row: number): string; getLines(firstRow: number, lastRow: number): string[]; getAllLines(): string[]; + getLength(): number; getTextRange(range: Range): string; getLinesForRange(range: Range): string[]; insert(position: Point, text: string): Point; insertInLine(position: Point, text: string): Point; + insertNewLine(position: Point): Point; clippedPos(row: number, column: number): Point; clonePos(pos: Point): Point; pos(row: number, column: number): Point; @@ -398,6 +400,8 @@ export namespace Ace { export interface EditSession extends EventEmitter, OptionsProvider, Folding { selection: Selection; + // TODO: define BackgroundTokenizer + on(name: 'changeFold', callback: (obj: { data: Fold, action: string }) => void): Function; on(name: 'changeScrollLeft', callback: (scrollLeft: number) => void): Function; @@ -519,6 +523,8 @@ export namespace Ace { removeKeyboardHandler(handler: KeyboardHandler): boolean; getKeyboardHandler(): KeyboardHandler; getStatusText(): string; + onCommandKey(e: any, hashId: number, keyCode: number): boolean; + onTextInput(text: string): boolean; } interface CommandMap { @@ -549,6 +555,7 @@ export namespace Ace { toggleRecording(editor: Editor): void; replay(editor: Editor): void; addCommand(command: Command): void; + addCommands(command: Command): void; removeCommand(command: Command | string, keepCommand?: boolean): void; bindKey(key: string | { mac?: string, win?: string }, command: CommandLike, From 67cccf6d45060547270a998db6fe8175dc42de83 Mon Sep 17 00:00:00 2001 From: wafuwafu13 Date: Sat, 20 Feb 2021 16:23:30 +0900 Subject: [PATCH 0423/1293] add some types --- ace.d.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ace.d.ts b/ace.d.ts index 0cd2a983350..6d7a5664cf8 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -555,11 +555,17 @@ export namespace Ace { toggleRecording(editor: Editor): void; replay(editor: Editor): void; addCommand(command: Command): void; - addCommands(command: Command): void; + addCommands(command: Command[]): void; removeCommand(command: Command | string, keepCommand?: boolean): void; + removeCommands(command: Command[]) bindKey(key: string | { mac?: string, win?: string }, command: CommandLike, position?: number): void; + bindKeys(keys: {[s: string]: Function}): void; + parseKeys(keyPart: string): {key: string, hashId: number}; + findKeyCommand(hashId: number, keyString: string): string | undefined; + handleKeyboard(data: {}, hashId: number, keyString: string, keyCode: string | number): void | {command: string}; + getStatusText(editor?: Editor, data: {}): string; } export interface VirtualRenderer extends OptionsProvider, EventEmitter { From 5bbd4cecb23b5a6f8c96025a9b82271252319d86 Mon Sep 17 00:00:00 2001 From: wafuwafu13 Date: Sat, 20 Feb 2021 16:33:33 +0900 Subject: [PATCH 0424/1293] fix semi --- lib/ace/mode/smithy_highlight_rules.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/mode/smithy_highlight_rules.js b/lib/ace/mode/smithy_highlight_rules.js index 54ddcfb6236..78aef2b4244 100644 --- a/lib/ace/mode/smithy_highlight_rules.js +++ b/lib/ace/mode/smithy_highlight_rules.js @@ -301,7 +301,7 @@ var SmithyHighlightRules = function() { token: "storage.type.smithy", regex: /[A-Z-a-z_][A-Z-a-z0-9_\.#$-]*/ }] - } + }; this.normalizeRules(); }; @@ -312,7 +312,7 @@ SmithyHighlightRules.metaData = { scopeName: "source.smithy", foldingStartMarker: "(\\{|\\[)\\s*", foldingStopMarker: "\\s*(\\}|\\])" -} +}; oop.inherits(SmithyHighlightRules, TextHighlightRules); From 4bad94ad4a040669f162a6c8936f6c90d5c05d6b Mon Sep 17 00:00:00 2001 From: wafuwafu13 Date: Sat, 20 Feb 2021 16:38:54 +0900 Subject: [PATCH 0425/1293] fix types --- ace.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index 6d7a5664cf8..289befd46aa 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -557,7 +557,7 @@ export namespace Ace { addCommand(command: Command): void; addCommands(command: Command[]): void; removeCommand(command: Command | string, keepCommand?: boolean): void; - removeCommands(command: Command[]) + removeCommands(command: Command[]): void; bindKey(key: string | { mac?: string, win?: string }, command: CommandLike, position?: number): void; @@ -565,7 +565,7 @@ export namespace Ace { parseKeys(keyPart: string): {key: string, hashId: number}; findKeyCommand(hashId: number, keyString: string): string | undefined; handleKeyboard(data: {}, hashId: number, keyString: string, keyCode: string | number): void | {command: string}; - getStatusText(editor?: Editor, data: {}): string; + getStatusText(editor: Editor, data: {}): string; } export interface VirtualRenderer extends OptionsProvider, EventEmitter { From 1629085a2aea6a6fb761b5b78f4f014b65a2b07d Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 1 Mar 2021 23:43:04 +0000 Subject: [PATCH 0426/1293] Rename Perl 6 to Raku As per language renaming: https://github.com/Raku/problem-solving/pull/89 --- demo/kitchen-sink/docs/{perl6.p6 => raku.raku} | 4 ++-- lib/ace/ext/modelist.js | 3 ++- .../mode/_test/{tokens_perl6.json => tokens_raku.json} | 4 ++-- lib/ace/mode/{perl6.js => raku.js} | 6 +++--- ...erl6_highlight_rules.js => raku_highlight_rules.js} | 10 +++++----- 5 files changed, 14 insertions(+), 13 deletions(-) rename demo/kitchen-sink/docs/{perl6.p6 => raku.raku} (90%) rename lib/ace/mode/_test/{tokens_perl6.json => tokens_raku.json} (99%) rename lib/ace/mode/{perl6.js => raku.js} (95%) rename lib/ace/mode/{perl6_highlight_rules.js => raku_highlight_rules.js} (98%) diff --git a/demo/kitchen-sink/docs/perl6.p6 b/demo/kitchen-sink/docs/raku.raku similarity index 90% rename from demo/kitchen-sink/docs/perl6.p6 rename to demo/kitchen-sink/docs/raku.raku index db1ae8f24d9..19f212da795 100644 --- a/demo/kitchen-sink/docs/perl6.p6 +++ b/demo/kitchen-sink/docs/raku.raku @@ -1,5 +1,5 @@ =begin comment -Perl 6 example for ace +Raku example for ace =end comment class Cook is Employee { has @.utensils is rw; @@ -38,4 +38,4 @@ my $baker = Baker.new( $baker.cook('brioche'); # OUTPUT: «Baking a tasty brioche␤» say $baker.utensils.perl; # OUTPUT: «["self cleaning oven"]␤» say $baker.cookbooks.perl; # OUTPUT: «["The Baker's Apprentice"]␤» -say $baker.salary; # OUTPUT: «50000␤» \ No newline at end of file +say $baker.salary; # OUTPUT: «50000␤» diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index bd4226c59c5..08843f11489 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -148,7 +148,6 @@ var supportedModes = { OCaml: ["ml|mli"], Pascal: ["pas|p"], Perl: ["pl|pm"], - Perl6: ["p6|pl6|pm6"], pgSQL: ["pgsql"], PHP: ["php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"], PHP_Laravel_blade: ["blade.php"], @@ -163,6 +162,7 @@ var supportedModes = { Python: ["py"], QML: ["qml"], R: ["r"], + Raku: ["raku|rakumod|rakutest|p6|pl6|pm6"], Razor: ["cshtml|asp"], RDoc: ["Rd"], Red: ["red|reds"], @@ -228,6 +228,7 @@ var nameOverrides = { Perl6: "Perl 6", AutoHotKey: "AutoHotkey / AutoIt" }; + var modesByName = {}; for (var name in supportedModes) { var data = supportedModes[name]; diff --git a/lib/ace/mode/_test/tokens_perl6.json b/lib/ace/mode/_test/tokens_raku.json similarity index 99% rename from lib/ace/mode/_test/tokens_perl6.json rename to lib/ace/mode/_test/tokens_raku.json index a45e3793481..ad03da2795f 100644 --- a/lib/ace/mode/_test/tokens_perl6.json +++ b/lib/ace/mode/_test/tokens_raku.json @@ -3,7 +3,7 @@ ["comment.doc","=begin comment"] ],[ "block_comment", - ["comment.doc","Perl 6 example for ace"] + ["comment.doc","Raku example for ace"] ],[ "start", ["comment.doc","=end comment"] @@ -312,4 +312,4 @@ ["identifier","salary"], ["text","; "], ["comment","# OUTPUT: «50000␤» "] -]] \ No newline at end of file +]] diff --git a/lib/ace/mode/perl6.js b/lib/ace/mode/raku.js similarity index 95% rename from lib/ace/mode/perl6.js rename to lib/ace/mode/raku.js index 882724a2ae9..834f5966993 100644 --- a/lib/ace/mode/perl6.js +++ b/lib/ace/mode/raku.js @@ -33,12 +33,12 @@ define(function(require, exports, module) { var oop = require("../lib/oop"); var TextMode = require("./text").Mode; -var Perl6HighlightRules = require("./perl6_highlight_rules").Perl6HighlightRules; +var RakuHighlightRules = require("./Raku_highlight_rules").RakuHighlightRules; var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; var CStyleFoldMode = require("./folding/cstyle").FoldMode; var Mode = function() { - this.HighlightRules = Perl6HighlightRules; + this.HighlightRules = RakuHighlightRules; this.$outdent = new MatchingBraceOutdent(); this.foldingRules = new CStyleFoldMode({start: "^=(begin)\\b", end: "^=(end)\\b"}); @@ -83,7 +83,7 @@ oop.inherits(Mode, TextMode); this.$outdent.autoOutdent(doc, row); }; - this.$id = "ace/mode/perl6"; + this.$id = "ace/mode/raku"; }).call(Mode.prototype); exports.Mode = Mode; diff --git a/lib/ace/mode/perl6_highlight_rules.js b/lib/ace/mode/raku_highlight_rules.js similarity index 98% rename from lib/ace/mode/perl6_highlight_rules.js rename to lib/ace/mode/raku_highlight_rules.js index deab04d44b3..29454bae46c 100644 --- a/lib/ace/mode/perl6_highlight_rules.js +++ b/lib/ace/mode/raku_highlight_rules.js @@ -34,7 +34,7 @@ define(function(require, exports, module) { var oop = require("../lib/oop"); var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; -var Perl6HighlightRules = function() { +var RakuHighlightRules = function() { var keywords = ( "my|our|class|role|grammar|is|does|sub|method|submethod|try|" + @@ -64,7 +64,7 @@ var Perl6HighlightRules = function() { "Pod::Block|Pod::Block::Code|Pod::Block::Comment|Pod::Block::Declarator|"+ "Pod::Block::Named|Pod::Block::Para|Pod::Block::Table|Pod::Heading|Pod::Item|"+ "Positional|PositionalBindFailover|Proc|Proc::Async|Promise|Proxy|PseudoStash|"+ - "QuantHash|Range|Rat|Rational|RatStr|Real|Regex|Routine|Scalar|Scheduler|"+ + "Raku|QuantHash|Range|Rat|Rational|RatStr|Real|Regex|Routine|Scalar|Scheduler|"+ "Semaphore|Seq|Set|SetHash|Setty|Signature|Slip|Stash|Str|StrDistance|Stringy|"+ "Sub|Submethod|Supplier|Supplier::Preserving|Supply|Systemic|Tap|Telemetry|"+ "Telemetry::Instrument::Thread|Telemetry::Instrument::Usage|Telemetry::Period|"+ @@ -150,7 +150,7 @@ var Perl6HighlightRules = function() { "positional|posix|postfix|postmatch|precomp-ext|precomp-target|pred|prefix|prematch|prepend|"+ "print|printf|print-nl|print-to|private|private_method_table|proc|produce|Promise|prompt|"+ "protect|pull-one|push|push-all|push-at-least|push-exactly|push-until-lazy|put|"+ - "qualifier-type|quit|r|race|radix|rand|range|raw|re|read|readchars|readonly|"+ + "qualifier-type|quit|r|race|radix|raku|rand|range|raw|re|read|readchars|readonly|"+ "ready|Real|reallocate|reals|reason|rebless|receive|recv|redispatcher|redo|reduce|"+ "rel2abs|relative|release|rename|repeated|replacement|report|reserved|resolve|"+ "restore|result|resume|rethrow|reverse|right|rindex|rmdir|roles_to_compose|"+ @@ -389,7 +389,7 @@ var Perl6HighlightRules = function() { }; }; -oop.inherits(Perl6HighlightRules, TextHighlightRules); +oop.inherits(RakuHighlightRules, TextHighlightRules); -exports.Perl6HighlightRules = Perl6HighlightRules; +exports.RakuHighlightRules = RakuHighlightRules; }); From dfbfe1351dfe7599ec0d36a047df817ee8cff24d Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Tue, 2 Mar 2021 09:29:09 +0000 Subject: [PATCH 0427/1293] Fix typo in require --- lib/ace/mode/raku.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/raku.js b/lib/ace/mode/raku.js index 834f5966993..68ab2e21cd9 100644 --- a/lib/ace/mode/raku.js +++ b/lib/ace/mode/raku.js @@ -33,7 +33,7 @@ define(function(require, exports, module) { var oop = require("../lib/oop"); var TextMode = require("./text").Mode; -var RakuHighlightRules = require("./Raku_highlight_rules").RakuHighlightRules; +var RakuHighlightRules = require("./raku_highlight_rules").RakuHighlightRules; var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; var CStyleFoldMode = require("./folding/cstyle").FoldMode; From ea3b8c31965974e1c347bc6836fabac36c41dc6e Mon Sep 17 00:00:00 2001 From: bogger33 Date: Tue, 2 Mar 2021 11:01:48 +0100 Subject: [PATCH 0428/1293] add a few CSS property values --- lib/ace/mode/css/csslint.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ace/mode/css/csslint.js b/lib/ace/mode/css/csslint.js index 9be23ed05ea..59c38df301a 100644 --- a/lib/ace/mode/css/csslint.js +++ b/lib/ace/mode/css/csslint.js @@ -3901,7 +3901,7 @@ var Properties = { "inline-box-align" : "initial | last | ", //J - "justify-content" : "flex-start | flex-end | center | space-between | space-around", + "justify-content" : "flex-start | flex-end | center | space-between | space-around | space-evenly | stretch", "-webkit-justify-content" : "flex-start | flex-end | center | space-between | space-around", //L @@ -3984,7 +3984,7 @@ var Properties = { "pitch-range" : 1, "play-during" : 1, "pointer-events" : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit", - "position" : "static | relative | absolute | fixed | inherit", + "position" : "static | relative | absolute | fixed | sticky | inherit", "presentation-level" : 1, "punctuation-trim" : 1, @@ -4072,7 +4072,7 @@ var Properties = { "white-space-collapse" : 1, "widows" : " | inherit", "width" : " | | | auto | inherit", - "word-break" : "normal | keep-all | break-all", + "word-break" : "normal | keep-all | break-all | break-word", "word-spacing" : " | normal | inherit", "word-wrap" : "normal | break-word", "writing-mode" : "horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb | inherit", From 9c8d8ea7d61fa7513667ac8b0087964dcae06f9b Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 2 Mar 2021 18:42:26 +0400 Subject: [PATCH 0429/1293] fix eslint test in github action runner --- .github/workflows/nodejs.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index a223ab2b8cd..39d988440f3 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -30,15 +30,21 @@ jobs: node-version: ${{ matrix.node-version }} - run: npm i && npm i eslint istanbul typescript - run: node_modules/.bin/istanbul cover lib/ace/test/all.js - - run: changes=$(git diff --name-only origin/HEAD --no-renames --diff-filter=ACMR); + - run: | + set -x; + git status; + git checkout HEAD -- package.json; + changes=$(git diff --name-only origin/HEAD --no-renames --diff-filter=ACMR); if [ "$changes" == "" ]; then echo "checking all files"; node node_modules/eslint/bin/eslint "lib/ace/**/*.js"; else - changes=$(echo "$changes" | grep -P '.js$'); - echo "checking $changes"; - if [ "$changes" != "" ]; then - node node_modules/eslint/bin/eslint $changes; + jsChanges=$(echo "$changes" | grep -P '.js$' || :); + if [ "$jsChanges" == "" ]; then + echo "nothing to check"; + else + echo "checking $jsChanges"; + node node_modules/eslint/bin/eslint $jsChanges; fi fi # - run: npm run lint From 760ce70f35b3f40094249050ba1720508abe3413 Mon Sep 17 00:00:00 2001 From: bogger33 Date: Tue, 2 Mar 2021 20:27:20 +0100 Subject: [PATCH 0430/1293] remove an old IE6 rule, and a redundant one --- lib/ace/mode/css/csslint.js | 121 ------------------------------------ 1 file changed, 121 deletions(-) diff --git a/lib/ace/mode/css/csslint.js b/lib/ace/mode/css/csslint.js index 59c38df301a..76196b541ae 100644 --- a/lib/ace/mode/css/csslint.js +++ b/lib/ace/mode/css/csslint.js @@ -7154,52 +7154,6 @@ CSSLint.Util = { } }; -/* - * Rule: Don't use adjoining classes (.foo.bar). - */ - -CSSLint.addRule({ - - //rule information - id: "adjoining-classes", - name: "Disallow adjoining classes", - desc: "Don't use adjoining classes.", - browsers: "IE6", - - //initialization - init: function(parser, reporter){ - var rule = this; - parser.addListener("startrule", function(event){ - var selectors = event.selectors, - selector, - part, - modifier, - classCount, - i, j, k; - - for (i=0; i < selectors.length; i++){ - selector = selectors[i]; - for (j=0; j < selector.parts.length; j++){ - part = selector.parts[j]; - if (part.type === parser.SELECTOR_PART_TYPE){ - classCount = 0; - for (k=0; k < part.modifiers.length; k++){ - modifier = part.modifiers[k]; - if (modifier.type === "class"){ - classCount++; - } - if (classCount > 1){ - reporter.report("Don't use adjoining classes.", part.line, part.col, rule); - } - } - } - } - } - }); - } - -}); - /* * Rule: Don't use width or height when using padding or border. */ @@ -8720,81 +8674,6 @@ CSSLint.addRule({ } }); -/* - * Rule: Headings (h1-h6) should be defined only once. - */ - -CSSLint.addRule({ - - //rule information - id: "unique-headings", - name: "Headings should only be defined once", - desc: "Headings should be defined only once.", - browsers: "All", - - //initialization - init: function(parser, reporter){ - var rule = this; - - var headings = { - h1: 0, - h2: 0, - h3: 0, - h4: 0, - h5: 0, - h6: 0 - }; - - parser.addListener("startrule", function(event){ - var selectors = event.selectors, - selector, - part, - pseudo, - i, j; - - for (i=0; i < selectors.length; i++){ - selector = selectors[i]; - part = selector.parts[selector.parts.length-1]; - - if (part.elementName && /(h[1-6])/i.test(part.elementName.toString())){ - - for (j=0; j < part.modifiers.length; j++){ - if (part.modifiers[j].type === "pseudo"){ - pseudo = true; - break; - } - } - - if (!pseudo){ - headings[RegExp.$1]++; - if (headings[RegExp.$1] > 1) { - reporter.report("Heading (" + part.elementName + ") has already been defined.", part.line, part.col, rule); - } - } - } - } - }); - - parser.addListener("endstylesheet", function(){ - var prop, - messages = []; - - for (prop in headings){ - if (headings.hasOwnProperty(prop)){ - if (headings[prop] > 1){ - messages.push(headings[prop] + " " + prop + "s"); - } - } - } - - if (messages.length){ - reporter.rollupWarn("You have " + messages.join(", ") + " defined in this stylesheet.", rule); - } - }); - } - -}); - /* * Rule: Don't use universal selector because it's slow. */ From 107e3e00141da20663bac2164975d33140fa2f46 Mon Sep 17 00:00:00 2001 From: bogger33 Date: Tue, 2 Mar 2021 20:35:36 +0100 Subject: [PATCH 0431/1293] Remove qualified-headings rule --- lib/ace/mode/css/csslint.js | 39 ------------------------------------- 1 file changed, 39 deletions(-) diff --git a/lib/ace/mode/css/csslint.js b/lib/ace/mode/css/csslint.js index 76196b541ae..b08e73db465 100644 --- a/lib/ace/mode/css/csslint.js +++ b/lib/ace/mode/css/csslint.js @@ -8263,45 +8263,6 @@ CSSLint.addRule({ }); -/* - * Rule: Headings (h1-h6) should not be qualified (namespaced). - */ - -CSSLint.addRule({ - - //rule information - id: "qualified-headings", - name: "Disallow qualified headings", - desc: "Headings should not be qualified (namespaced).", - browsers: "All", - - //initialization - init: function(parser, reporter){ - var rule = this; - - parser.addListener("startrule", function(event){ - var selectors = event.selectors, - selector, - part, - i, j; - - for (i=0; i < selectors.length; i++){ - selector = selectors[i]; - - for (j=0; j < selector.parts.length; j++){ - part = selector.parts[j]; - if (part.type === parser.SELECTOR_PART_TYPE){ - if (part.elementName && /h[1-6]/.test(part.elementName.toString()) && j > 0){ - reporter.report("Heading (" + part.elementName + ") should not be qualified.", part.line, part.col, rule); - } - } - } - } - }); - } - -}); - /* * Rule: Selectors that look like regular expressions are slow and should be avoided. */ From 1c582daa946eef9456c6c862e34b5bde1c1f96c6 Mon Sep 17 00:00:00 2001 From: bogger33 Date: Tue, 2 Mar 2021 20:35:52 +0100 Subject: [PATCH 0432/1293] add rule about box-sizing to InfoRules --- lib/ace/mode/css_worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/css_worker.js b/lib/ace/mode/css_worker.js index d92e23fc267..f0b89eb92d5 100644 --- a/lib/ace/mode/css_worker.js +++ b/lib/ace/mode/css_worker.js @@ -42,7 +42,7 @@ var Worker = exports.Worker = function(sender) { this.ruleset = null; this.setDisabledRules("ids|order-alphabetical"); this.setInfoRules( - "adjoining-classes|qualified-headings|zero-units|gradients|" + + "adjoining-classes|zero-units|gradients|box-model" + "import|outline-none|vendor-prefix" ); }; From 776e763577e366b669dd447cbd0eb2fa14196385 Mon Sep 17 00:00:00 2001 From: bogger33 Date: Tue, 2 Mar 2021 20:54:34 +0100 Subject: [PATCH 0433/1293] I forgot a pipe --- lib/ace/mode/css_worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/css_worker.js b/lib/ace/mode/css_worker.js index f0b89eb92d5..cfeb838f27d 100644 --- a/lib/ace/mode/css_worker.js +++ b/lib/ace/mode/css_worker.js @@ -42,7 +42,7 @@ var Worker = exports.Worker = function(sender) { this.ruleset = null; this.setDisabledRules("ids|order-alphabetical"); this.setInfoRules( - "adjoining-classes|zero-units|gradients|box-model" + + "adjoining-classes|zero-units|gradients|box-model|" + "import|outline-none|vendor-prefix" ); }; From 2f79be9ec288a11e98db13e156e07c89150398e4 Mon Sep 17 00:00:00 2001 From: kyo Date: Mon, 8 Mar 2021 20:16:38 +0100 Subject: [PATCH 0434/1293] update csslint.js --- lib/ace/mode/css/csslint.js | 12861 +++++++++++++++++++--------------- 1 file changed, 7263 insertions(+), 5598 deletions(-) diff --git a/lib/ace/mode/css/csslint.js b/lib/ace/mode/css/csslint.js index b08e73db465..15d5f64b68a 100644 --- a/lib/ace/mode/css/csslint.js +++ b/lib/ace/mode/css/csslint.js @@ -1,7 +1,7 @@ define(function(require, exports, module) { /*! -CSSLint -Copyright (c) 2014 Nicole Sullivan and Nicholas C. Zakas. All rights reserved. +CSSLint v1.0.5 +Copyright (c) 2021 Nicole Sullivan and Nicholas C. Zakas. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal @@ -22,10 +22,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* Build: v0.10.0 22-July-2014 01:17:52 */ + +var CSSLint = (function(){ + var module = module || {}, + exports = exports || {}; + /*! Parser-Lib -Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. +Copyright (c) 2009-2016 Nicholas C. Zakas. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -44,4074 +48,3829 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -/* Version v0.2.5, Build time: 7-May-2014 03:37:38 */ -var parserlib = {}; -(function(){ +/* Version v1.1.2, Build time: 8-March-2021 19:42:03 */ +var parserlib = (function () { +var require; +require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i). + * @namespace parserlib.css + * @class Combinator + * @extends parserlib.util.SyntaxUnit * @constructor + * @param {String} text The text representation of the unit. + * @param {int} line The line of text on which the unit resides. + * @param {int} col The column of text on which the unit resides. */ -function EventTarget(){ +function Combinator(text, line, col) { + + SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE); /** - * The array of listeners for various events. - * @type Object - * @property _listeners - * @private + * The type of modifier. + * @type String + * @property type */ - this._listeners = {}; + this.type = "unknown"; + + // pretty simple + if (/^\s+$/.test(text)) { + this.type = "descendant"; + } else if (text === ">") { + this.type = "child"; + } else if (text === "+") { + this.type = "adjacent-sibling"; + } else if (text === "~") { + this.type = "sibling"; + } + } -EventTarget.prototype = { +Combinator.prototype = new SyntaxUnit(); +Combinator.prototype.constructor = Combinator; - //restore constructor - constructor: EventTarget, - /** - * Adds a listener for a given event type. - * @param {String} type The type of event to add a listener for. - * @param {Function} listener The function to call when the event occurs. - * @return {void} - * @method addListener - */ - addListener: function(type, listener){ - if (!this._listeners[type]){ - this._listeners[type] = []; +},{"../util/SyntaxUnit":26,"./Parser":6}],3:[function(require,module,exports){ +"use strict"; + +module.exports = Matcher; + +var StringReader = require("../util/StringReader"); +var SyntaxError = require("../util/SyntaxError"); + +/** + * This class implements a combinator library for matcher functions. + * The combinators are described at: + * https://developer.mozilla.org/en-US/docs/Web/CSS/Value_definition_syntax#Component_value_combinators + */ +function Matcher(matchFunc, toString) { + this.match = function(expression) { + // Save/restore marks to ensure that failed matches always restore + // the original location in the expression. + var result; + expression.mark(); + result = matchFunc(expression); + if (result) { + expression.drop(); + } else { + expression.restore(); } + return result; + }; + this.toString = typeof toString === "function" ? toString : function() { + return toString; + }; +} - this._listeners[type].push(listener); - }, +/** Precedence table of combinators. */ +Matcher.prec = { + MOD: 5, + SEQ: 4, + ANDAND: 3, + OROR: 2, + ALT: 1 +}; - /** - * Fires an event based on the passed-in object. - * @param {Object|String} event An object with at least a 'type' attribute - * or a string indicating the event name. - * @return {void} - * @method fire - */ - fire: function(event){ - if (typeof event == "string"){ - event = { type: event }; +/** Simple recursive-descent grammar to build matchers from strings. */ +Matcher.parse = function(str) { + var reader, eat, expr, oror, andand, seq, mod, term, result; + reader = new StringReader(str); + eat = function(matcher) { + var result = reader.readMatch(matcher); + if (result === null) { + throw new SyntaxError( + "Expected " + matcher, reader.getLine(), reader.getCol()); } - if (typeof event.target != "undefined"){ - event.target = this; + return result; + }; + expr = function() { + // expr = oror (" | " oror)* + var m = [ oror() ]; + while (reader.readMatch(" | ") !== null) { + m.push(oror()); + } + return m.length === 1 ? m[0] : Matcher.alt.apply(Matcher, m); + }; + oror = function() { + // oror = andand ( " || " andand)* + var m = [ andand() ]; + while (reader.readMatch(" || ") !== null) { + m.push(andand()); + } + return m.length === 1 ? m[0] : Matcher.oror.apply(Matcher, m); + }; + andand = function() { + // andand = seq ( " && " seq)* + var m = [ seq() ]; + while (reader.readMatch(" && ") !== null) { + m.push(seq()); + } + return m.length === 1 ? m[0] : Matcher.andand.apply(Matcher, m); + }; + seq = function() { + // seq = mod ( " " mod)* + var m = [ mod() ]; + while (reader.readMatch(/^ (?![&|\]])/) !== null) { + m.push(mod()); + } + return m.length === 1 ? m[0] : Matcher.seq.apply(Matcher, m); + }; + mod = function() { + // mod = term ( "?" | "*" | "+" | "#" | "{,}" )? + var m = term(); + if (reader.readMatch("?") !== null) { + return m.question(); + } else if (reader.readMatch("*") !== null) { + return m.star(); + } else if (reader.readMatch("+") !== null) { + return m.plus(); + } else if (reader.readMatch("#") !== null) { + return m.hash(); + } else if (reader.readMatch(/^\{\s*/) !== null) { + var min = eat(/^\d+/); + eat(/^\s*,\s*/); + var max = eat(/^\d+/); + eat(/^\s*\}/); + return m.braces(Number(min), Number(max)); + } + return m; + }; + term = function() { + // term = | literal | "[ " expression " ]" + if (reader.readMatch("[ ") !== null) { + var m = expr(); + eat(" ]"); + return m; } + return Matcher.fromType(eat(/^[^ ?*+#{]+/)); + }; + result = expr(); + if (!reader.eof()) { + throw new SyntaxError( + "Expected end of string", reader.getLine(), reader.getCol()); + } + return result; +}; - if (typeof event.type == "undefined"){ - throw new Error("Event object missing 'type' property."); +/** + * Convert a string to a matcher (parsing simple alternations), + * or do nothing if the argument is already a matcher. + */ +Matcher.cast = function(m) { + if (m instanceof Matcher) { + return m; + } + return Matcher.parse(m); +}; + +/** + * Create a matcher for a single type. + */ +Matcher.fromType = function(type) { + // Late require of ValidationTypes to break a dependency cycle. + var ValidationTypes = require("./ValidationTypes"); + return new Matcher(function(expression) { + return expression.hasNext() && ValidationTypes.isType(expression, type); + }, type); +}; + +/** + * Create a matcher for one or more juxtaposed words, which all must + * occur, in the given order. + */ +Matcher.seq = function() { + var ms = Array.prototype.slice.call(arguments).map(Matcher.cast); + if (ms.length === 1) { + return ms[0]; + } + return new Matcher(function(expression) { + var i, result = true; + for (i = 0; result && i < ms.length; i++) { + result = ms[i].match(expression); + } + return result; + }, function(prec) { + var p = Matcher.prec.SEQ; + var s = ms.map(function(m) { + return m.toString(p); + }).join(" "); + if (prec > p) { + s = "[ " + s + " ]"; } + return s; + }); +}; - if (this._listeners[event.type]){ +/** + * Create a matcher for one or more alternatives, where exactly one + * must occur. + */ +Matcher.alt = function() { + var ms = Array.prototype.slice.call(arguments).map(Matcher.cast); + if (ms.length === 1) { + return ms[0]; + } + return new Matcher(function(expression) { + var i, result = false; + for (i = 0; !result && i < ms.length; i++) { + result = ms[i].match(expression); + } + return result; + }, function(prec) { + var p = Matcher.prec.ALT; + var s = ms.map(function(m) { + return m.toString(p); + }).join(" | "); + if (prec > p) { + s = "[ " + s + " ]"; + } + return s; + }); +}; - //create a copy of the array and use that so listeners can't chane - var listeners = this._listeners[event.type].concat(); - for (var i=0, len=listeners.length; i < len; i++){ - listeners[i].call(this, event); - } +/** + * Create a matcher for two or more options. This implements the + * double bar (||) and double ampersand (&&) operators, as well as + * variants of && where some of the alternatives are optional. + * This will backtrack through even successful matches to try to + * maximize the number of items matched. + */ +Matcher.many = function(required) { + var ms = Array.prototype.slice.call(arguments, 1).reduce(function(acc, v) { + if (v.expand) { + // Insert all of the options for the given complex rule as + // individual options. + var ValidationTypes = require("./ValidationTypes"); + acc.push.apply(acc, ValidationTypes.complex[v.expand].options); + } else { + acc.push(Matcher.cast(v)); } - }, + return acc; + }, []); - /** - * Removes a listener for a given event type. - * @param {String} type The type of event to remove a listener from. - * @param {Function} listener The function to remove from the event. - * @return {void} - * @method removeListener - */ - removeListener: function(type, listener){ - if (this._listeners[type]){ - var listeners = this._listeners[type]; - for (var i=0, len=listeners.length; i < len; i++){ - if (listeners[i] === listener){ - listeners.splice(i, 1); - break; + if (required === true) { + required = ms.map(function() { + return true; + }); + } + + var result = new Matcher(function(expression) { + var seen = [], max = 0, pass = 0; + var success = function(matchCount) { + if (pass === 0) { + max = Math.max(matchCount, max); + return matchCount === ms.length; + } else { + return matchCount === max; + } + }; + var tryMatch = function(matchCount) { + for (var i = 0; i < ms.length; i++) { + if (seen[i]) { + continue; + } + expression.mark(); + if (ms[i].match(expression)) { + seen[i] = true; + // Increase matchCount iff this was a required element + // (or if all the elements are optional) + if (tryMatch(matchCount + (required === false || required[i] ? 1 : 0))) { + expression.drop(); + return true; + } + // Backtrack: try *not* matching using this rule, and + // let's see if it leads to a better overall match. + expression.restore(); + seen[i] = false; + } else { + expression.drop(); } } + return success(matchCount); + }; + if (!tryMatch(0)) { + // Couldn't get a complete match, retrace our steps to make the + // match with the maximum # of required elements. + pass++; + tryMatch(0); + } + + if (required === false) { + return max > 0; + } + // Use finer-grained specification of which matchers are required. + for (var i = 0; i < ms.length; i++) { + if (required[i] && !seen[i]) { + return false; + } + } + return true; + }, function(prec) { + var p = required === false ? Matcher.prec.OROR : Matcher.prec.ANDAND; + var s = ms.map(function(m, i) { + if (required !== false && !required[i]) { + return m.toString(Matcher.prec.MOD) + "?"; + } + return m.toString(p); + }).join(required === false ? " || " : " && "); + if (prec > p) { + s = "[ " + s + " ]"; + } + return s; + }); + result.options = ms; + return result; +}; + +/** + * Create a matcher for two or more options, where all options are + * mandatory but they may appear in any order. + */ +Matcher.andand = function() { + var args = Array.prototype.slice.call(arguments); + args.unshift(true); + return Matcher.many.apply(Matcher, args); +}; +/** + * Create a matcher for two or more options, where options are + * optional and may appear in any order, but at least one must be + * present. + */ +Matcher.oror = function() { + var args = Array.prototype.slice.call(arguments); + args.unshift(false); + return Matcher.many.apply(Matcher, args); +}; +/** Instance methods on Matchers. */ +Matcher.prototype = { + constructor: Matcher, + // These are expected to be overridden in every instance. + match: function() { + throw new Error("unimplemented"); + }, + toString: function() { + throw new Error("unimplemented"); + }, + // This returns a standalone function to do the matching. + func: function() { + return this.match.bind(this); + }, + // Basic combinators + then: function(m) { + return Matcher.seq(this, m); + }, + or: function(m) { + return Matcher.alt(this, m); + }, + andand: function(m) { + return Matcher.many(true, this, m); + }, + oror: function(m) { + return Matcher.many(false, this, m); + }, + // Component value multipliers + star: function() { + return this.braces(0, Infinity, "*"); + }, + plus: function() { + return this.braces(1, Infinity, "+"); + }, + question: function() { + return this.braces(0, 1, "?"); + }, + hash: function() { + return this.braces(1, Infinity, "#", Matcher.cast(",")); + }, + braces: function(min, max, marker, optSep) { + var m1 = this, m2 = optSep ? optSep.then(this) : this; + if (!marker) { + marker = "{" + min + "," + max + "}"; } + return new Matcher(function(expression) { + var result = true, i; + for (i = 0; i < max; i++) { + if (i > 0 && optSep) { + result = m2.match(expression); + } else { + result = m1.match(expression); + } + if (!result) { + break; + } + } + return i >= min; + }, function() { + return m1.toString(Matcher.prec.MOD) + marker; + }); } }; + +},{"../util/StringReader":24,"../util/SyntaxError":25,"./ValidationTypes":21}],4:[function(require,module,exports){ +"use strict"; + +module.exports = MediaFeature; + +var SyntaxUnit = require("../util/SyntaxUnit"); + +var Parser = require("./Parser"); + /** - * Convenient way to read through strings. - * @namespace parserlib.util - * @class StringReader + * Represents a media feature, such as max-width:500. + * @namespace parserlib.css + * @class MediaFeature + * @extends parserlib.util.SyntaxUnit * @constructor - * @param {String} text The text to read. + * @param {SyntaxUnit} name The name of the feature. + * @param {SyntaxUnit} value The value of the feature or null if none. */ -function StringReader(text){ +function MediaFeature(name, value) { + + SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE); /** - * The input text with line endings normalized. - * @property _input + * The name of the media feature * @type String - * @private + * @property name */ - this._input = text.replace(/\n\r?/g, "\n"); - + this.name = name; /** - * The row for the character to be read next. - * @property _line - * @type int - * @private + * The value for the feature or null if there is none. + * @type SyntaxUnit + * @property value */ - this._line = 1; + this.value = value; +} +MediaFeature.prototype = new SyntaxUnit(); +MediaFeature.prototype.constructor = MediaFeature; - /** - * The column for the character to be read next. - * @property _col - * @type int - * @private - */ - this._col = 1; - /** - * The index of the character in the input to be read next. - * @property _cursor - * @type int - * @private - */ - this._cursor = 0; -} +},{"../util/SyntaxUnit":26,"./Parser":6}],5:[function(require,module,exports){ +"use strict"; -StringReader.prototype = { +module.exports = MediaQuery; - //restore constructor - constructor: StringReader, +var SyntaxUnit = require("../util/SyntaxUnit"); - //------------------------------------------------------------------------- - // Position info - //------------------------------------------------------------------------- +var Parser = require("./Parser"); - /** - * Returns the column of the character to be read next. - * @return {int} The column of the character to be read next. - * @method getCol - */ - getCol: function(){ - return this._col; - }, +/** + * Represents an individual media query. + * @namespace parserlib.css + * @class MediaQuery + * @extends parserlib.util.SyntaxUnit + * @constructor + * @param {String} modifier The modifier "not" or "only" (or null). + * @param {String} mediaType The type of media (i.e., "print"). + * @param {Array} parts Array of selectors parts making up this selector. + * @param {int} line The line of text on which the unit resides. + * @param {int} col The column of text on which the unit resides. + */ +function MediaQuery(modifier, mediaType, features, line, col) { + + SyntaxUnit.call(this, (modifier ? modifier + " " : "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE); /** - * Returns the row of the character to be read next. - * @return {int} The row of the character to be read next. - * @method getLine + * The media modifier ("not" or "only") + * @type String + * @property modifier */ - getLine: function(){ - return this._line ; - }, + this.modifier = modifier; /** - * Determines if you're at the end of the input. - * @return {Boolean} True if there's no more input, false otherwise. - * @method eof + * The mediaType (i.e., "print") + * @type String + * @property mediaType */ - eof: function(){ - return (this._cursor == this._input.length); - }, - - //------------------------------------------------------------------------- - // Basic reading - //------------------------------------------------------------------------- + this.mediaType = mediaType; /** - * Reads the next character without advancing the cursor. - * @param {int} count How many characters to look ahead (default is 1). - * @return {String} The next character or null if there is no next character. - * @method peek + * The parts that make up the selector. + * @type Array + * @property features */ - peek: function(count){ - var c = null; - count = (typeof count == "undefined" ? 1 : count); + this.features = features; - //if we're not at the end of the input... - if (this._cursor < this._input.length){ +} - //get character and increment cursor and column - c = this._input.charAt(this._cursor + count - 1); - } +MediaQuery.prototype = new SyntaxUnit(); +MediaQuery.prototype.constructor = MediaQuery; - return c; - }, - /** - * Reads the next character from the input and adjusts the row and column - * accordingly. - * @return {String} The next character or null if there is no next character. - * @method read - */ - read: function(){ - var c = null; +},{"../util/SyntaxUnit":26,"./Parser":6}],6:[function(require,module,exports){ +"use strict"; - //if we're not at the end of the input... - if (this._cursor < this._input.length){ +module.exports = Parser; - //if the last character was a newline, increment row count - //and reset column count - if (this._input.charAt(this._cursor) == "\n"){ - this._line++; - this._col=1; - } else { - this._col++; - } +var EventTarget = require("../util/EventTarget"); +var SyntaxError = require("../util/SyntaxError"); +var SyntaxUnit = require("../util/SyntaxUnit"); - //get character and increment cursor and column - c = this._input.charAt(this._cursor++); - } +var Combinator = require("./Combinator"); +var MediaFeature = require("./MediaFeature"); +var MediaQuery = require("./MediaQuery"); +var PropertyName = require("./PropertyName"); +var PropertyValue = require("./PropertyValue"); +var PropertyValuePart = require("./PropertyValuePart"); +var Selector = require("./Selector"); +var SelectorPart = require("./SelectorPart"); +var SelectorSubPart = require("./SelectorSubPart"); +var TokenStream = require("./TokenStream"); +var Tokens = require("./Tokens"); +var Validation = require("./Validation"); - return c; - }, +/** + * A CSS3 parser. + * @namespace parserlib.css + * @class Parser + * @constructor + * @param {Object} options (Optional) Various options for the parser: + * starHack (true|false) to allow IE6 star hack as valid, + * underscoreHack (true|false) to interpret leading underscores + * as IE6-7 targeting for known properties, ieFilters (true|false) + * to indicate that IE < 8 filters should be accepted and not throw + * syntax errors. + */ +function Parser(options) { - //------------------------------------------------------------------------- - // Misc - //------------------------------------------------------------------------- + // inherit event functionality + EventTarget.call(this); - /** - * Saves the current location so it can be returned to later. - * @method mark - * @return {void} - */ - mark: function(){ - this._bookmark = { - cursor: this._cursor, - line: this._line, - col: this._col - }; - }, - reset: function(){ - if (this._bookmark){ - this._cursor = this._bookmark.cursor; - this._line = this._bookmark.line; - this._col = this._bookmark.col; - delete this._bookmark; - } - }, + this.options = options || {}; - //------------------------------------------------------------------------- - // Advanced reading - //------------------------------------------------------------------------- + this._tokenStream = null; +} - /** - * Reads up to and including the given string. Throws an error if that - * string is not found. - * @param {String} pattern The string to read. - * @return {String} The string when it is found. - * @throws Error when the string pattern is not found. - * @method readTo - */ - readTo: function(pattern){ +// Static constants +Parser.DEFAULT_TYPE = 0; +Parser.COMBINATOR_TYPE = 1; +Parser.MEDIA_FEATURE_TYPE = 2; +Parser.MEDIA_QUERY_TYPE = 3; +Parser.PROPERTY_NAME_TYPE = 4; +Parser.PROPERTY_VALUE_TYPE = 5; +Parser.PROPERTY_VALUE_PART_TYPE = 6; +Parser.SELECTOR_TYPE = 7; +Parser.SELECTOR_PART_TYPE = 8; +Parser.SELECTOR_SUB_PART_TYPE = 9; - var buffer = "", - c; +Parser.prototype = function() { - /* - * First, buffer must be the same length as the pattern. - * Then, buffer must end with the pattern or else reach the - * end of the input. - */ - while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){ - c = this.read(); - if (c){ - buffer += c; - } else { - throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + "."); - } - } + var proto = new EventTarget(), // new prototype + prop, + additions = { + __proto__: null, - return buffer; + // restore constructor + constructor: Parser, - }, + // instance constants - yuck + DEFAULT_TYPE : 0, + COMBINATOR_TYPE : 1, + MEDIA_FEATURE_TYPE : 2, + MEDIA_QUERY_TYPE : 3, + PROPERTY_NAME_TYPE : 4, + PROPERTY_VALUE_TYPE : 5, + PROPERTY_VALUE_PART_TYPE : 6, + SELECTOR_TYPE : 7, + SELECTOR_PART_TYPE : 8, + SELECTOR_SUB_PART_TYPE : 9, - /** - * Reads characters while each character causes the given - * filter function to return true. The function is passed - * in each character and either returns true to continue - * reading or false to stop. - * @param {Function} filter The function to read on each character. - * @return {String} The string made up of all characters that passed the - * filter check. - * @method readWhile - */ - readWhile: function(filter){ + //----------------------------------------------------------------- + // Grammar + //----------------------------------------------------------------- - var buffer = "", - c = this.read(); + _stylesheet: function() { - while(c !== null && filter(c)){ - buffer += c; - c = this.read(); - } + /* + * stylesheet + * : [ CHARSET_SYM S* STRING S* ';' ]? + * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]* + * [ namespace [S|CDO|CDC]* ]* + * [ [ ruleset | media | page | font_face | keyframes_rule | supports_rule ] [S|CDO|CDC]* ]* + * ; + */ - return buffer; + var tokenStream = this._tokenStream, + count, + token, + tt; - }, + this.fire("startstylesheet"); - /** - * Reads characters that match either text or a regular expression and - * returns those characters. If a match is found, the row and column - * are adjusted; if no match is found, the reader's state is unchanged. - * reading or false to stop. - * @param {String|RegExp} matcher If a string, then the literal string - * value is searched for. If a regular expression, then any string - * matching the pattern is search for. - * @return {String} The string made up of all characters that matched or - * null if there was no match. - * @method readMatch - */ - readMatch: function(matcher){ + // try to read character set + this._charset(); - var source = this._input.substring(this._cursor), - value = null; + this._skipCruft(); - //if it's a string, just do a straight match - if (typeof matcher == "string"){ - if (source.indexOf(matcher) === 0){ - value = this.readCount(matcher.length); - } - } else if (matcher instanceof RegExp){ - if (matcher.test(source)){ - value = this.readCount(RegExp.lastMatch.length); - } - } + // try to read imports - may be more than one + while (tokenStream.peek() === Tokens.IMPORT_SYM) { + this._import(); + this._skipCruft(); + } - return value; - }, + // try to read namespaces - may be more than one + while (tokenStream.peek() === Tokens.NAMESPACE_SYM) { + this._namespace(); + this._skipCruft(); + } + // get the next token + tt = tokenStream.peek(); - /** - * Reads a given number of characters. If the end of the input is reached, - * it reads only the remaining characters and does not throw an error. - * @param {int} count The number of characters to read. - * @return {String} The string made up the read characters. - * @method readCount - */ - readCount: function(count){ - var buffer = ""; + // try to read the rest + while (tt > Tokens.EOF) { - while(count--){ - buffer += this.read(); - } + try { - return buffer; - } + switch (tt) { + case Tokens.MEDIA_SYM: + this._media(); + this._skipCruft(); + break; + case Tokens.PAGE_SYM: + this._page(); + this._skipCruft(); + break; + case Tokens.FONT_FACE_SYM: + this._font_face(); + this._skipCruft(); + break; + case Tokens.KEYFRAMES_SYM: + this._keyframes(); + this._skipCruft(); + break; + case Tokens.VIEWPORT_SYM: + this._viewport(); + this._skipCruft(); + break; + case Tokens.DOCUMENT_SYM: + this._document(); + this._skipCruft(); + break; + case Tokens.SUPPORTS_SYM: + this._supports(); + this._skipCruft(); + break; + case Tokens.UNKNOWN_SYM: // unknown @ rule + tokenStream.get(); + if (!this.options.strict) { -}; -/** - * Type to use when a syntax error occurs. - * @class SyntaxError - * @namespace parserlib.util - * @constructor - * @param {String} message The error message. - * @param {int} line The line at which the error occurred. - * @param {int} col The column at which the error occurred. - */ -function SyntaxError(message, line, col){ + // fire error event + this.fire({ + type: "error", + error: null, + message: "Unknown @ rule: " + tokenStream.LT(0).value + ".", + line: tokenStream.LT(0).startLine, + col: tokenStream.LT(0).startCol + }); - /** - * The column at which the error occurred. - * @type int - * @property col - */ - this.col = col; + // skip braces + count = 0; + while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) === Tokens.LBRACE) { + count++; // keep track of nesting depth + } - /** - * The line at which the error occurred. - * @type int - * @property line - */ - this.line = line; + while (count) { + tokenStream.advance([Tokens.RBRACE]); + count--; + } - /** - * The text representation of the unit. - * @type String - * @property text - */ - this.message = message; + } else { + // not a syntax error, rethrow it + throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol); + } + break; + case Tokens.S: + this._readWhitespace(); + break; + default: + if (!this._ruleset()) { -} + // error handling for known issues + switch (tt) { + case Tokens.CHARSET_SYM: + token = tokenStream.LT(1); + this._charset(false); + throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol); + case Tokens.IMPORT_SYM: + token = tokenStream.LT(1); + this._import(false); + throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol); + case Tokens.NAMESPACE_SYM: + token = tokenStream.LT(1); + this._namespace(false); + throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol); + default: + tokenStream.get(); // get the last token + this._unexpectedToken(tokenStream.token()); + } -//inherit from Error -SyntaxError.prototype = new Error(); -/** - * Base type to represent a single syntactic unit. - * @class SyntaxUnit - * @namespace parserlib.util - * @constructor - * @param {String} text The text of the unit. - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - */ -function SyntaxUnit(text, line, col, type){ + } + } + } catch (ex) { + if (ex instanceof SyntaxError && !this.options.strict) { + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + } else { + throw ex; + } + } + tt = tokenStream.peek(); + } - /** - * The column of text on which the unit resides. - * @type int - * @property col - */ - this.col = col; + if (tt !== Tokens.EOF) { + this._unexpectedToken(tokenStream.token()); + } - /** - * The line of text on which the unit resides. - * @type int - * @property line - */ - this.line = line; + this.fire("endstylesheet"); + }, - /** - * The text representation of the unit. - * @type String - * @property text - */ - this.text = text; + _charset: function(emit) { + var tokenStream = this._tokenStream, + charset, + token, + line, + col; - /** - * The type of syntax unit. - * @type int - * @property type - */ - this.type = type; -} + if (tokenStream.match(Tokens.CHARSET_SYM)) { + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; -/** - * Create a new syntax unit based solely on the given token. - * Convenience method for creating a new syntax unit when - * it represents a single token instead of multiple. - * @param {Object} token The token object to represent. - * @return {parserlib.util.SyntaxUnit} The object representing the token. - * @static - * @method fromToken - */ -SyntaxUnit.fromToken = function(token){ - return new SyntaxUnit(token.value, token.startLine, token.startCol); -}; + this._readWhitespace(); + tokenStream.mustMatch(Tokens.STRING); -SyntaxUnit.prototype = { + token = tokenStream.token(); + charset = token.value; - //restore constructor - constructor: SyntaxUnit, + this._readWhitespace(); + tokenStream.mustMatch(Tokens.SEMICOLON); - /** - * Returns the text representation of the unit. - * @return {String} The text representation of the unit. - * @method valueOf - */ - valueOf: function(){ - return this.text; - }, + if (emit !== false) { + this.fire({ + type: "charset", + charset:charset, + line: line, + col: col + }); + } + } + }, - /** - * Returns the text representation of the unit. - * @return {String} The text representation of the unit. - * @method toString - */ - toString: function(){ - return this.text; - } + _import: function(emit) { + /* + * import + * : IMPORT_SYM S* + * [STRING|URI] S* media_query_list? ';' S* + */ -}; -/*global StringReader, SyntaxError*/ + var tokenStream = this._tokenStream, + uri, + importToken, + mediaList = []; -/** - * Generic TokenStream providing base functionality. - * @class TokenStreamBase - * @namespace parserlib.util - * @constructor - * @param {String|StringReader} input The text to tokenize or a reader from - * which to read the input. - */ -function TokenStreamBase(input, tokenData){ + // read import symbol + tokenStream.mustMatch(Tokens.IMPORT_SYM); + importToken = tokenStream.token(); + this._readWhitespace(); - /** - * The string reader for easy access to the text. - * @type StringReader - * @property _reader - * @private - */ - this._reader = input ? new StringReader(input.toString()) : null; + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); - /** - * Token object for the last consumed token. - * @type Token - * @property _token - * @private - */ - this._token = null; + // grab the URI value + uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, "$1"); - /** - * The array of token information. - * @type Array - * @property _tokenData - * @private - */ - this._tokenData = tokenData; + this._readWhitespace(); - /** - * Lookahead token buffer. - * @type Array - * @property _lt - * @private - */ - this._lt = []; + mediaList = this._media_query_list(); - /** - * Lookahead token buffer index. - * @type int - * @property _ltIndex - * @private - */ - this._ltIndex = 0; + // must end with a semicolon + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); - this._ltIndexCache = []; -} + if (emit !== false) { + this.fire({ + type: "import", + uri: uri, + media: mediaList, + line: importToken.startLine, + col: importToken.startCol + }); + } -/** - * Accepts an array of token information and outputs - * an array of token data containing key-value mappings - * and matching functions that the TokenStream needs. - * @param {Array} tokens An array of token descriptors. - * @return {Array} An array of processed token data. - * @method createTokenData - * @static - */ -TokenStreamBase.createTokenData = function(tokens){ + }, - var nameMap = [], - typeMap = {}, - tokenData = tokens.concat([]), - i = 0, - len = tokenData.length+1; + _namespace: function(emit) { + /* + * namespace + * : NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S* + */ - tokenData.UNKNOWN = -1; - tokenData.unshift({name:"EOF"}); + var tokenStream = this._tokenStream, + line, + col, + prefix, + uri; - for (; i < len; i++){ - nameMap.push(tokenData[i].name); - tokenData[tokenData[i].name] = i; - if (tokenData[i].text){ - typeMap[tokenData[i].text] = i; - } - } + // read import symbol + tokenStream.mustMatch(Tokens.NAMESPACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + this._readWhitespace(); - tokenData.name = function(tt){ - return nameMap[tt]; - }; + // it's a namespace prefix - no _namespace_prefix() method because it's just an IDENT + if (tokenStream.match(Tokens.IDENT)) { + prefix = tokenStream.token().value; + this._readWhitespace(); + } - tokenData.type = function(c){ - return typeMap[c]; - }; + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); + /*if (!tokenStream.match(Tokens.STRING)){ + tokenStream.mustMatch(Tokens.URI); + }*/ - return tokenData; -}; + // grab the URI value + uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); -TokenStreamBase.prototype = { + this._readWhitespace(); - //restore constructor - constructor: TokenStreamBase, + // must end with a semicolon + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); - //------------------------------------------------------------------------- - // Matching methods - //------------------------------------------------------------------------- + if (emit !== false) { + this.fire({ + type: "namespace", + prefix: prefix, + uri: uri, + line: line, + col: col + }); + } - /** - * Determines if the next token matches the given token type. - * If so, that token is consumed; if not, the token is placed - * back onto the token stream. You can pass in any number of - * token types and this will return true if any of the token - * types is found. - * @param {int|int[]} tokenTypes Either a single token type or an array of - * token types that the next token might be. If an array is passed, - * it's assumed that the token can be any of these. - * @param {variant} channel (Optional) The channel to read from. If not - * provided, reads from the default (unnamed) channel. - * @return {Boolean} True if the token type matches, false if not. - * @method match - */ - match: function(tokenTypes, channel){ + }, - //always convert to an array, makes things easier - if (!(tokenTypes instanceof Array)){ - tokenTypes = [tokenTypes]; - } + _supports: function(emit) { + /* + * supports_rule + * : SUPPORTS_SYM S* supports_condition S* group_rule_body + * ; + */ + var tokenStream = this._tokenStream, + line, + col; - var tt = this.get(channel), - i = 0, - len = tokenTypes.length; + if (tokenStream.match(Tokens.SUPPORTS_SYM)) { + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; - while(i < len){ - if (tt == tokenTypes[i++]){ - return true; - } - } + this._readWhitespace(); + this._supports_condition(); + this._readWhitespace(); - //no match found, put the token back - this.unget(); - return false; - }, + tokenStream.mustMatch(Tokens.LBRACE); + this._readWhitespace(); - /** - * Determines if the next token matches the given token type. - * If so, that token is consumed; if not, an error is thrown. - * @param {int|int[]} tokenTypes Either a single token type or an array of - * token types that the next token should be. If an array is passed, - * it's assumed that the token must be one of these. - * @param {variant} channel (Optional) The channel to read from. If not - * provided, reads from the default (unnamed) channel. - * @return {void} - * @method mustMatch - */ - mustMatch: function(tokenTypes, channel){ + if (emit !== false) { + this.fire({ + type: "startsupports", + line: line, + col: col + }); + } - var token; + while (true) { + if (!this._ruleset()) { + break; + } + } - //always convert to an array, makes things easier - if (!(tokenTypes instanceof Array)){ - tokenTypes = [tokenTypes]; - } + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); - if (!this.match.apply(this, arguments)){ - token = this.LT(1); - throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name + - " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); - } - }, + this.fire({ + type: "endsupports", + line: line, + col: col + }); + } + }, - //------------------------------------------------------------------------- - // Consuming methods - //------------------------------------------------------------------------- + _supports_condition: function() { + /* + * supports_condition + * : supports_negation | supports_conjunction | supports_disjunction | + * supports_condition_in_parens + * ; + */ + var tokenStream = this._tokenStream, + ident; - /** - * Keeps reading from the token stream until either one of the specified - * token types is found or until the end of the input is reached. - * @param {int|int[]} tokenTypes Either a single token type or an array of - * token types that the next token should be. If an array is passed, - * it's assumed that the token must be one of these. - * @param {variant} channel (Optional) The channel to read from. If not - * provided, reads from the default (unnamed) channel. - * @return {void} - * @method advance - */ - advance: function(tokenTypes, channel){ + if (tokenStream.match(Tokens.IDENT)) { + ident = tokenStream.token().value.toLowerCase(); - while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){ - this.get(); - } + if (ident === "not") { + tokenStream.mustMatch(Tokens.S); + this._supports_condition_in_parens(); + } else { + tokenStream.unget(); + } + } else { + this._supports_condition_in_parens(); + this._readWhitespace(); - return this.LA(0); - }, + while (tokenStream.peek() === Tokens.IDENT) { + ident = tokenStream.LT(1).value.toLowerCase(); + if (ident === "and" || ident === "or") { + tokenStream.mustMatch(Tokens.IDENT); + this._readWhitespace(); + this._supports_condition_in_parens(); + this._readWhitespace(); + } + } + } + }, - /** - * Consumes the next token from the token stream. - * @return {int} The token type of the token that was just consumed. - * @method get - */ - get: function(channel){ + _supports_condition_in_parens: function() { + /* + * supports_condition_in_parens + * : ( '(' S* supports_condition S* ')' ) | supports_declaration_condition | + * general_enclosed + * ; + */ + var tokenStream = this._tokenStream, + ident; - var tokenInfo = this._tokenData, - reader = this._reader, - value, - i =0, - len = tokenInfo.length, - found = false, - token, - info; + if (tokenStream.match(Tokens.LPAREN)) { + this._readWhitespace(); + if (tokenStream.match(Tokens.IDENT)) { + // look ahead for not keyword, if not given, continue with declaration condition. + ident = tokenStream.token().value.toLowerCase(); + if (ident === "not") { + this._readWhitespace(); + this._supports_condition(); + this._readWhitespace(); + tokenStream.mustMatch(Tokens.RPAREN); + } else { + tokenStream.unget(); + this._supports_declaration_condition(false); + } + } else { + this._supports_condition(); + this._readWhitespace(); + tokenStream.mustMatch(Tokens.RPAREN); + } + } else { + this._supports_declaration_condition(); + } + }, - //check the lookahead buffer first - if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){ + _supports_declaration_condition: function(requireStartParen) { + /* + * supports_declaration_condition + * : '(' S* declaration ')' + * ; + */ + var tokenStream = this._tokenStream; - i++; - this._token = this._lt[this._ltIndex++]; - info = tokenInfo[this._token.type]; + if (requireStartParen !== false) { + tokenStream.mustMatch(Tokens.LPAREN); + } + this._readWhitespace(); + this._declaration(); + tokenStream.mustMatch(Tokens.RPAREN); + }, - //obey channels logic - while((info.channel !== undefined && channel !== info.channel) && - this._ltIndex < this._lt.length){ - this._token = this._lt[this._ltIndex++]; - info = tokenInfo[this._token.type]; - i++; - } + _media: function() { + /* + * media + * : MEDIA_SYM S* media_query_list S* '{' S* ruleset* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + mediaList; // = []; - //here be dragons - if ((info.channel === undefined || channel === info.channel) && - this._ltIndex <= this._lt.length){ - this._ltIndexCache.push(i); - return this._token.type; - } - } + // look for @media + tokenStream.mustMatch(Tokens.MEDIA_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; - //call token retriever method - token = this._getToken(); + this._readWhitespace(); - //if it should be hidden, don't save a token - if (token.type > -1 && !tokenInfo[token.type].hide){ + mediaList = this._media_query_list(); - //apply token channel - token.channel = tokenInfo[token.type].channel; + tokenStream.mustMatch(Tokens.LBRACE); + this._readWhitespace(); - //save for later - this._token = token; - this._lt.push(token); + this.fire({ + type: "startmedia", + media: mediaList, + line: line, + col: col + }); - //save space that will be moved (must be done before array is truncated) - this._ltIndexCache.push(this._lt.length - this._ltIndex + i); + while (true) { + if (tokenStream.peek() === Tokens.PAGE_SYM) { + this._page(); + } else if (tokenStream.peek() === Tokens.FONT_FACE_SYM) { + this._font_face(); + } else if (tokenStream.peek() === Tokens.VIEWPORT_SYM) { + this._viewport(); + } else if (tokenStream.peek() === Tokens.DOCUMENT_SYM) { + this._document(); + } else if (tokenStream.peek() === Tokens.SUPPORTS_SYM) { + this._supports(); + } else if (tokenStream.peek() === Tokens.MEDIA_SYM) { + this._media(); + } else if (!this._ruleset()) { + break; + } + } - //keep the buffer under 5 items - if (this._lt.length > 5){ - this._lt.shift(); - } + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); - //also keep the shift buffer under 5 items - if (this._ltIndexCache.length > 5){ - this._ltIndexCache.shift(); - } + this.fire({ + type: "endmedia", + media: mediaList, + line: line, + col: col + }); + }, - //update lookahead index - this._ltIndex = this._lt.length; - } - /* - * Skip to the next token if: - * 1. The token type is marked as hidden. - * 2. The token type has a channel specified and it isn't the current channel. - */ - info = tokenInfo[token.type]; - if (info && - (info.hide || - (info.channel !== undefined && channel !== info.channel))){ - return this.get(channel); - } else { - //return just the type - return token.type; - } - }, + // CSS3 Media Queries + _media_query_list: function() { + /* + * media_query_list + * : S* [media_query [ ',' S* media_query ]* ]? + * ; + */ + var tokenStream = this._tokenStream, + mediaList = []; - /** - * Looks ahead a certain number of tokens and returns the token type at - * that position. This will throw an error if you lookahead past the - * end of input, past the size of the lookahead buffer, or back past - * the first token in the lookahead buffer. - * @param {int} The index of the token type to retrieve. 0 for the - * current token, 1 for the next, -1 for the previous, etc. - * @return {int} The token type of the token in the given position. - * @method LA - */ - LA: function(index){ - var total = index, - tt; - if (index > 0){ - //TODO: Store 5 somewhere - if (index > 5){ - throw new Error("Too much lookahead."); - } - //get all those tokens - while(total){ - tt = this.get(); - total--; - } + this._readWhitespace(); - //unget all those tokens - while(total < index){ - this.unget(); - total++; - } - } else if (index < 0){ + if (tokenStream.peek() === Tokens.IDENT || tokenStream.peek() === Tokens.LPAREN) { + mediaList.push(this._media_query()); + } - if(this._lt[this._ltIndex+index]){ - tt = this._lt[this._ltIndex+index].type; - } else { - throw new Error("Too much lookbehind."); - } + while (tokenStream.match(Tokens.COMMA)) { + this._readWhitespace(); + mediaList.push(this._media_query()); + } - } else { - tt = this._token.type; - } - - return tt; - - }, + return mediaList; + }, - /** - * Looks ahead a certain number of tokens and returns the token at - * that position. This will throw an error if you lookahead past the - * end of input, past the size of the lookahead buffer, or back past - * the first token in the lookahead buffer. - * @param {int} The index of the token type to retrieve. 0 for the - * current token, 1 for the next, -1 for the previous, etc. - * @return {Object} The token of the token in the given position. - * @method LA - */ - LT: function(index){ + /* + * Note: "expression" in the grammar maps to the _media_expression + * method. - //lookahead first to prime the token buffer - this.LA(index); + */ + _media_query: function() { + /* + * media_query + * : [ONLY | NOT]? S* media_type S* [ AND S* expression ]* + * | expression [ AND S* expression ]* + * ; + */ + var tokenStream = this._tokenStream, + type = null, + ident = null, + token = null, + expressions = []; - //now find the token, subtract one because _ltIndex is already at the next index - return this._lt[this._ltIndex+index-1]; - }, + if (tokenStream.match(Tokens.IDENT)) { + ident = tokenStream.token().value.toLowerCase(); - /** - * Returns the token type for the next token in the stream without - * consuming it. - * @return {int} The token type of the next token in the stream. - * @method peek - */ - peek: function(){ - return this.LA(1); - }, + // since there's no custom tokens for these, need to manually check + if (ident !== "only" && ident !== "not") { + tokenStream.unget(); + ident = null; + } else { + token = tokenStream.token(); + } + } - /** - * Returns the actual token object for the last consumed token. - * @return {Token} The token object for the last consumed token. - * @method token - */ - token: function(){ - return this._token; - }, + this._readWhitespace(); - /** - * Returns the name of the token for the given token type. - * @param {int} tokenType The type of token to get the name of. - * @return {String} The name of the token or "UNKNOWN_TOKEN" for any - * invalid token type. - * @method tokenName - */ - tokenName: function(tokenType){ - if (tokenType < 0 || tokenType > this._tokenData.length){ - return "UNKNOWN_TOKEN"; - } else { - return this._tokenData[tokenType].name; - } - }, + if (tokenStream.peek() === Tokens.IDENT) { + type = this._media_type(); + if (token === null) { + token = tokenStream.token(); + } + } else if (tokenStream.peek() === Tokens.LPAREN) { + if (token === null) { + token = tokenStream.LT(1); + } + expressions.push(this._media_expression()); + } - /** - * Returns the token type value for the given token name. - * @param {String} tokenName The name of the token whose value should be returned. - * @return {int} The token type value for the given token name or -1 - * for an unknown token. - * @method tokenName - */ - tokenType: function(tokenName){ - return this._tokenData[tokenName] || -1; - }, + if (type === null && expressions.length === 0) { + return null; + } else { + this._readWhitespace(); + while (tokenStream.match(Tokens.IDENT)) { + if (tokenStream.token().value.toLowerCase() !== "and") { + this._unexpectedToken(tokenStream.token()); + } - /** - * Returns the last consumed token to the token stream. - * @method unget - */ - unget: function(){ - //if (this._ltIndex > -1){ - if (this._ltIndexCache.length){ - this._ltIndex -= this._ltIndexCache.pop();//--; - this._token = this._lt[this._ltIndex - 1]; - } else { - throw new Error("Too much lookahead."); - } - } + this._readWhitespace(); + expressions.push(this._media_expression()); + } + } -}; + return new MediaQuery(ident, type, expressions, token.startLine, token.startCol); + }, + // CSS3 Media Queries + _media_type: function() { + /* + * media_type + * : IDENT + * ; + */ + return this._media_feature(); + }, -parserlib.util = { -StringReader: StringReader, -SyntaxError : SyntaxError, -SyntaxUnit : SyntaxUnit, -EventTarget : EventTarget, -TokenStreamBase : TokenStreamBase -}; -})(); -/* -Parser-Lib -Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. + /** + * Note: in CSS3 Media Queries, this is called "expression". + * Renamed here to avoid conflict with CSS3 Selectors + * definition of "expression". Also note that "expr" in the + * grammar now maps to "expression" from CSS3 selectors. + * @method _media_expression + * @private + */ + _media_expression: function() { + /* + * expression + * : '(' S* media_feature S* [ ':' S* expr ]? ')' S* + * ; + */ + var tokenStream = this._tokenStream, + feature = null, + token, + expression = null; -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + tokenStream.mustMatch(Tokens.LPAREN); -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. + feature = this._media_feature(); + this._readWhitespace(); -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. + if (tokenStream.match(Tokens.COLON)) { + this._readWhitespace(); + token = tokenStream.LT(1); + expression = this._expression(); + } -*/ -/* Version v0.2.5, Build time: 7-May-2014 03:37:38 */ -(function(){ -var EventTarget = parserlib.util.EventTarget, -TokenStreamBase = parserlib.util.TokenStreamBase, -StringReader = parserlib.util.StringReader, -SyntaxError = parserlib.util.SyntaxError, -SyntaxUnit = parserlib.util.SyntaxUnit; - -var Colors = { - aliceblue :"#f0f8ff", - antiquewhite :"#faebd7", - aqua :"#00ffff", - aquamarine :"#7fffd4", - azure :"#f0ffff", - beige :"#f5f5dc", - bisque :"#ffe4c4", - black :"#000000", - blanchedalmond :"#ffebcd", - blue :"#0000ff", - blueviolet :"#8a2be2", - brown :"#a52a2a", - burlywood :"#deb887", - cadetblue :"#5f9ea0", - chartreuse :"#7fff00", - chocolate :"#d2691e", - coral :"#ff7f50", - cornflowerblue :"#6495ed", - cornsilk :"#fff8dc", - crimson :"#dc143c", - cyan :"#00ffff", - darkblue :"#00008b", - darkcyan :"#008b8b", - darkgoldenrod :"#b8860b", - darkgray :"#a9a9a9", - darkgrey :"#a9a9a9", - darkgreen :"#006400", - darkkhaki :"#bdb76b", - darkmagenta :"#8b008b", - darkolivegreen :"#556b2f", - darkorange :"#ff8c00", - darkorchid :"#9932cc", - darkred :"#8b0000", - darksalmon :"#e9967a", - darkseagreen :"#8fbc8f", - darkslateblue :"#483d8b", - darkslategray :"#2f4f4f", - darkslategrey :"#2f4f4f", - darkturquoise :"#00ced1", - darkviolet :"#9400d3", - deeppink :"#ff1493", - deepskyblue :"#00bfff", - dimgray :"#696969", - dimgrey :"#696969", - dodgerblue :"#1e90ff", - firebrick :"#b22222", - floralwhite :"#fffaf0", - forestgreen :"#228b22", - fuchsia :"#ff00ff", - gainsboro :"#dcdcdc", - ghostwhite :"#f8f8ff", - gold :"#ffd700", - goldenrod :"#daa520", - gray :"#808080", - grey :"#808080", - green :"#008000", - greenyellow :"#adff2f", - honeydew :"#f0fff0", - hotpink :"#ff69b4", - indianred :"#cd5c5c", - indigo :"#4b0082", - ivory :"#fffff0", - khaki :"#f0e68c", - lavender :"#e6e6fa", - lavenderblush :"#fff0f5", - lawngreen :"#7cfc00", - lemonchiffon :"#fffacd", - lightblue :"#add8e6", - lightcoral :"#f08080", - lightcyan :"#e0ffff", - lightgoldenrodyellow :"#fafad2", - lightgray :"#d3d3d3", - lightgrey :"#d3d3d3", - lightgreen :"#90ee90", - lightpink :"#ffb6c1", - lightsalmon :"#ffa07a", - lightseagreen :"#20b2aa", - lightskyblue :"#87cefa", - lightslategray :"#778899", - lightslategrey :"#778899", - lightsteelblue :"#b0c4de", - lightyellow :"#ffffe0", - lime :"#00ff00", - limegreen :"#32cd32", - linen :"#faf0e6", - magenta :"#ff00ff", - maroon :"#800000", - mediumaquamarine:"#66cdaa", - mediumblue :"#0000cd", - mediumorchid :"#ba55d3", - mediumpurple :"#9370d8", - mediumseagreen :"#3cb371", - mediumslateblue :"#7b68ee", - mediumspringgreen :"#00fa9a", - mediumturquoise :"#48d1cc", - mediumvioletred :"#c71585", - midnightblue :"#191970", - mintcream :"#f5fffa", - mistyrose :"#ffe4e1", - moccasin :"#ffe4b5", - navajowhite :"#ffdead", - navy :"#000080", - oldlace :"#fdf5e6", - olive :"#808000", - olivedrab :"#6b8e23", - orange :"#ffa500", - orangered :"#ff4500", - orchid :"#da70d6", - palegoldenrod :"#eee8aa", - palegreen :"#98fb98", - paleturquoise :"#afeeee", - palevioletred :"#d87093", - papayawhip :"#ffefd5", - peachpuff :"#ffdab9", - peru :"#cd853f", - pink :"#ffc0cb", - plum :"#dda0dd", - powderblue :"#b0e0e6", - purple :"#800080", - red :"#ff0000", - rosybrown :"#bc8f8f", - royalblue :"#4169e1", - saddlebrown :"#8b4513", - salmon :"#fa8072", - sandybrown :"#f4a460", - seagreen :"#2e8b57", - seashell :"#fff5ee", - sienna :"#a0522d", - silver :"#c0c0c0", - skyblue :"#87ceeb", - slateblue :"#6a5acd", - slategray :"#708090", - slategrey :"#708090", - snow :"#fffafa", - springgreen :"#00ff7f", - steelblue :"#4682b4", - tan :"#d2b48c", - teal :"#008080", - thistle :"#d8bfd8", - tomato :"#ff6347", - turquoise :"#40e0d0", - violet :"#ee82ee", - wheat :"#f5deb3", - white :"#ffffff", - whitesmoke :"#f5f5f5", - yellow :"#ffff00", - yellowgreen :"#9acd32", - //CSS2 system colors http://www.w3.org/TR/css3-color/#css2-system - activeBorder :"Active window border.", - activecaption :"Active window caption.", - appworkspace :"Background color of multiple document interface.", - background :"Desktop background.", - buttonface :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.", - buttonhighlight :"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", - buttonshadow :"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", - buttontext :"Text on push buttons.", - captiontext :"Text in caption, size box, and scrollbar arrow box.", - graytext :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.", - greytext :"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.", - highlight :"Item(s) selected in a control.", - highlighttext :"Text of item(s) selected in a control.", - inactiveborder :"Inactive window border.", - inactivecaption :"Inactive window caption.", - inactivecaptiontext :"Color of text in an inactive caption.", - infobackground :"Background color for tooltip controls.", - infotext :"Text color for tooltip controls.", - menu :"Menu background.", - menutext :"Text in menus.", - scrollbar :"Scroll bar gray area.", - threeddarkshadow :"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", - threedface :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", - threedhighlight :"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", - threedlightshadow :"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", - threedshadow :"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", - window :"Window background.", - windowframe :"Window frame.", - windowtext :"Text in windows." -}; -/*global SyntaxUnit, Parser*/ -/** - * Represents a selector combinator (whitespace, +, >). - * @namespace parserlib.css - * @class Combinator - * @extends parserlib.util.SyntaxUnit - * @constructor - * @param {String} text The text representation of the unit. - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - */ -function Combinator(text, line, col){ + tokenStream.mustMatch(Tokens.RPAREN); + this._readWhitespace(); - SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE); + return new MediaFeature(feature, expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null); + }, - /** - * The type of modifier. - * @type String - * @property type - */ - this.type = "unknown"; + // CSS3 Media Queries + _media_feature: function() { + /* + * media_feature + * : IDENT + * ; + */ + var tokenStream = this._tokenStream; - //pretty simple - if (/^\s+$/.test(text)){ - this.type = "descendant"; - } else if (text == ">"){ - this.type = "child"; - } else if (text == "+"){ - this.type = "adjacent-sibling"; - } else if (text == "~"){ - this.type = "sibling"; - } + this._readWhitespace(); -} + tokenStream.mustMatch(Tokens.IDENT); -Combinator.prototype = new SyntaxUnit(); -Combinator.prototype.constructor = Combinator; + return SyntaxUnit.fromToken(tokenStream.token()); + }, -/*global SyntaxUnit, Parser*/ -/** - * Represents a media feature, such as max-width:500. - * @namespace parserlib.css - * @class MediaFeature - * @extends parserlib.util.SyntaxUnit - * @constructor - * @param {SyntaxUnit} name The name of the feature. - * @param {SyntaxUnit} value The value of the feature or null if none. - */ -function MediaFeature(name, value){ + // CSS3 Paged Media + _page: function() { + /* + * page: + * PAGE_SYM S* IDENT? pseudo_page? S* + * '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + identifier = null, + pseudoPage = null; - SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE); + // look for @page + tokenStream.mustMatch(Tokens.PAGE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; - /** - * The name of the media feature - * @type String - * @property name - */ - this.name = name; + this._readWhitespace(); - /** - * The value for the feature or null if there is none. - * @type SyntaxUnit - * @property value - */ - this.value = value; -} + if (tokenStream.match(Tokens.IDENT)) { + identifier = tokenStream.token().value; -MediaFeature.prototype = new SyntaxUnit(); -MediaFeature.prototype.constructor = MediaFeature; + // The value 'auto' may not be used as a page name and MUST be treated as a syntax error. + if (identifier.toLowerCase() === "auto") { + this._unexpectedToken(tokenStream.token()); + } + } -/*global SyntaxUnit, Parser*/ -/** - * Represents an individual media query. - * @namespace parserlib.css - * @class MediaQuery - * @extends parserlib.util.SyntaxUnit - * @constructor - * @param {String} modifier The modifier "not" or "only" (or null). - * @param {String} mediaType The type of media (i.e., "print"). - * @param {Array} parts Array of selectors parts making up this selector. - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - */ -function MediaQuery(modifier, mediaType, features, line, col){ + // see if there's a colon upcoming + if (tokenStream.peek() === Tokens.COLON) { + pseudoPage = this._pseudo_page(); + } - SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE); + this._readWhitespace(); - /** - * The media modifier ("not" or "only") - * @type String - * @property modifier - */ - this.modifier = modifier; + this.fire({ + type: "startpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); - /** - * The mediaType (i.e., "print") - * @type String - * @property mediaType - */ - this.mediaType = mediaType; + this._readDeclarations(true, true); - /** - * The parts that make up the selector. - * @type Array - * @property features - */ - this.features = features; + this.fire({ + type: "endpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); -} + }, -MediaQuery.prototype = new SyntaxUnit(); -MediaQuery.prototype.constructor = MediaQuery; + // CSS3 Paged Media + _margin: function() { + /* + * margin : + * margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + marginSym = this._margin_sym(); -/*global Tokens, TokenStream, SyntaxError, Properties, Validation, ValidationError, SyntaxUnit, - PropertyValue, PropertyValuePart, SelectorPart, SelectorSubPart, Selector, - PropertyName, Combinator, MediaFeature, MediaQuery, EventTarget */ + if (marginSym) { + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; -/** - * A CSS3 parser. - * @namespace parserlib.css - * @class Parser - * @constructor - * @param {Object} options (Optional) Various options for the parser: - * starHack (true|false) to allow IE6 star hack as valid, - * underscoreHack (true|false) to interpret leading underscores - * as IE6-7 targeting for known properties, ieFilters (true|false) - * to indicate that IE < 8 filters should be accepted and not throw - * syntax errors. - */ -function Parser(options){ + this.fire({ + type: "startpagemargin", + margin: marginSym, + line: line, + col: col + }); - //inherit event functionality - EventTarget.call(this); + this._readDeclarations(true); + this.fire({ + type: "endpagemargin", + margin: marginSym, + line: line, + col: col + }); + return true; + } else { + return false; + } + }, - this.options = options || {}; + // CSS3 Paged Media + _margin_sym: function() { - this._tokenStream = null; -} + /* + * margin_sym : + * TOPLEFTCORNER_SYM | + * TOPLEFT_SYM | + * TOPCENTER_SYM | + * TOPRIGHT_SYM | + * TOPRIGHTCORNER_SYM | + * BOTTOMLEFTCORNER_SYM | + * BOTTOMLEFT_SYM | + * BOTTOMCENTER_SYM | + * BOTTOMRIGHT_SYM | + * BOTTOMRIGHTCORNER_SYM | + * LEFTTOP_SYM | + * LEFTMIDDLE_SYM | + * LEFTBOTTOM_SYM | + * RIGHTTOP_SYM | + * RIGHTMIDDLE_SYM | + * RIGHTBOTTOM_SYM + * ; + */ -//Static constants -Parser.DEFAULT_TYPE = 0; -Parser.COMBINATOR_TYPE = 1; -Parser.MEDIA_FEATURE_TYPE = 2; -Parser.MEDIA_QUERY_TYPE = 3; -Parser.PROPERTY_NAME_TYPE = 4; -Parser.PROPERTY_VALUE_TYPE = 5; -Parser.PROPERTY_VALUE_PART_TYPE = 6; -Parser.SELECTOR_TYPE = 7; -Parser.SELECTOR_PART_TYPE = 8; -Parser.SELECTOR_SUB_PART_TYPE = 9; + var tokenStream = this._tokenStream; -Parser.prototype = function(){ + if (tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM, + Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM, + Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM, + Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM, + Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM, + Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM, + Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM])) { + return SyntaxUnit.fromToken(tokenStream.token()); + } else { + return null; + } - var proto = new EventTarget(), //new prototype - prop, - additions = { + }, - //restore constructor - constructor: Parser, + _pseudo_page: function() { + /* + * pseudo_page + * : ':' IDENT + * ; + */ - //instance constants - yuck - DEFAULT_TYPE : 0, - COMBINATOR_TYPE : 1, - MEDIA_FEATURE_TYPE : 2, - MEDIA_QUERY_TYPE : 3, - PROPERTY_NAME_TYPE : 4, - PROPERTY_VALUE_TYPE : 5, - PROPERTY_VALUE_PART_TYPE : 6, - SELECTOR_TYPE : 7, - SELECTOR_PART_TYPE : 8, - SELECTOR_SUB_PART_TYPE : 9, + var tokenStream = this._tokenStream; - //----------------------------------------------------------------- - // Grammar - //----------------------------------------------------------------- + tokenStream.mustMatch(Tokens.COLON); + tokenStream.mustMatch(Tokens.IDENT); - _stylesheet: function(){ + // TODO: CSS3 Paged Media says only "left", "center", and "right" are allowed + + return tokenStream.token().value; + }, + _font_face: function() { /* - * stylesheet - * : [ CHARSET_SYM S* STRING S* ';' ]? - * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]* - * [ namespace [S|CDO|CDC]* ]* - * [ [ ruleset | media | page | font_face | keyframes ] [S|CDO|CDC]* ]* - * ; + * font_face + * : FONT_FACE_SYM S* + * '{' S* declaration [ ';' S* declaration ]* '}' S* + * ; */ - var tokenStream = this._tokenStream, - charset = null, - count, - token, - tt; + line, + col; - this.fire("startstylesheet"); + // look for @page + tokenStream.mustMatch(Tokens.FONT_FACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; - //try to read character set - this._charset(); + this._readWhitespace(); - this._skipCruft(); + this.fire({ + type: "startfontface", + line: line, + col: col + }); - //try to read imports - may be more than one - while (tokenStream.peek() == Tokens.IMPORT_SYM){ - this._import(); - this._skipCruft(); - } + this._readDeclarations(true); - //try to read namespaces - may be more than one - while (tokenStream.peek() == Tokens.NAMESPACE_SYM){ - this._namespace(); - this._skipCruft(); - } + this.fire({ + type: "endfontface", + line: line, + col: col + }); + }, - //get the next token - tt = tokenStream.peek(); + _viewport: function() { + /* + * viewport + * : VIEWPORT_SYM S* + * '{' S* declaration? [ ';' S* declaration? ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col; - //try to read the rest - while(tt > Tokens.EOF){ + tokenStream.mustMatch(Tokens.VIEWPORT_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; - try { + this._readWhitespace(); - switch(tt){ - case Tokens.MEDIA_SYM: - this._media(); - this._skipCruft(); - break; - case Tokens.PAGE_SYM: - this._page(); - this._skipCruft(); - break; - case Tokens.FONT_FACE_SYM: - this._font_face(); - this._skipCruft(); - break; - case Tokens.KEYFRAMES_SYM: - this._keyframes(); - this._skipCruft(); - break; - case Tokens.VIEWPORT_SYM: - this._viewport(); - this._skipCruft(); - break; - case Tokens.UNKNOWN_SYM: //unknown @ rule - tokenStream.get(); - if (!this.options.strict){ + this.fire({ + type: "startviewport", + line: line, + col: col + }); - //fire error event - this.fire({ - type: "error", - error: null, - message: "Unknown @ rule: " + tokenStream.LT(0).value + ".", - line: tokenStream.LT(0).startLine, - col: tokenStream.LT(0).startCol - }); + this._readDeclarations(true); - //skip braces - count=0; - while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){ - count++; //keep track of nesting depth - } + this.fire({ + type: "endviewport", + line: line, + col: col + }); - while(count){ - tokenStream.advance([Tokens.RBRACE]); - count--; - } + }, - } else { - //not a syntax error, rethrow it - throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol); - } - break; - case Tokens.S: - this._readWhitespace(); - break; - default: - if(!this._ruleset()){ + _document: function() { + /* + * document + * : DOCUMENT_SYM S* + * _document_function [ ',' S* _document_function ]* S* + * '{' S* ruleset* '}' + * ; + */ - //error handling for known issues - switch(tt){ - case Tokens.CHARSET_SYM: - token = tokenStream.LT(1); - this._charset(false); - throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol); - case Tokens.IMPORT_SYM: - token = tokenStream.LT(1); - this._import(false); - throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol); - case Tokens.NAMESPACE_SYM: - token = tokenStream.LT(1); - this._namespace(false); - throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol); - default: - tokenStream.get(); //get the last token - this._unexpectedToken(tokenStream.token()); - } - - } - } - } catch(ex) { - if (ex instanceof SyntaxError && !this.options.strict){ - this.fire({ - type: "error", - error: ex, - message: ex.message, - line: ex.line, - col: ex.col - }); - } else { - throw ex; - } - } - - tt = tokenStream.peek(); - } - - if (tt != Tokens.EOF){ - this._unexpectedToken(tokenStream.token()); - } - - this.fire("endstylesheet"); - }, - - _charset: function(emit){ var tokenStream = this._tokenStream, - charset, token, - line, - col; + functions = [], + prefix = ""; - if (tokenStream.match(Tokens.CHARSET_SYM)){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; + tokenStream.mustMatch(Tokens.DOCUMENT_SYM); + token = tokenStream.token(); + if (/^@-([^-]+)-/.test(token.value)) { + prefix = RegExp.$1; + } + this._readWhitespace(); + functions.push(this._document_function()); + + while (tokenStream.match(Tokens.COMMA)) { this._readWhitespace(); - tokenStream.mustMatch(Tokens.STRING); + functions.push(this._document_function()); + } - token = tokenStream.token(); - charset = token.value; + tokenStream.mustMatch(Tokens.LBRACE); + this._readWhitespace(); - this._readWhitespace(); - tokenStream.mustMatch(Tokens.SEMICOLON); + this.fire({ + type: "startdocument", + functions: functions, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); - if (emit !== false){ - this.fire({ - type: "charset", - charset:charset, - line: line, - col: col - }); + var ok = true; + while (ok) { + switch (tokenStream.peek()) { + case Tokens.PAGE_SYM: + this._page(); + break; + case Tokens.FONT_FACE_SYM: + this._font_face(); + break; + case Tokens.VIEWPORT_SYM: + this._viewport(); + break; + case Tokens.MEDIA_SYM: + this._media(); + break; + case Tokens.KEYFRAMES_SYM: + this._keyframes(); + break; + case Tokens.DOCUMENT_SYM: + this._document(); + break; + default: + ok = Boolean(this._ruleset()); } } + + tokenStream.mustMatch(Tokens.RBRACE); + token = tokenStream.token(); + this._readWhitespace(); + + this.fire({ + type: "enddocument", + functions: functions, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); }, - _import: function(emit){ + _document_function: function() { /* - * import - * : IMPORT_SYM S* - * [STRING|URI] S* media_query_list? ';' S* + * document_function + * : function | URI S* + * ; */ var tokenStream = this._tokenStream, - tt, - uri, - importToken, - mediaList = []; - - //read import symbol - tokenStream.mustMatch(Tokens.IMPORT_SYM); - importToken = tokenStream.token(); - this._readWhitespace(); - - tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); - - //grab the URI value - uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, "$1"); - - this._readWhitespace(); - - mediaList = this._media_query_list(); - - //must end with a semicolon - tokenStream.mustMatch(Tokens.SEMICOLON); - this._readWhitespace(); + value; - if (emit !== false){ - this.fire({ - type: "import", - uri: uri, - media: mediaList, - line: importToken.startLine, - col: importToken.startCol - }); + if (tokenStream.match(Tokens.URI)) { + value = tokenStream.token().value; + this._readWhitespace(); + } else { + value = this._function(); } + return value; }, - _namespace: function(emit){ + _operator: function(inFunction) { + /* - * namespace - * : NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S* + * operator (outside function) + * : '/' S* | ',' S* | /( empty )/ + * operator (inside function) + * : '/' S* | '+' S* | '*' S* | '-' S* /( empty )/ + * ; */ var tokenStream = this._tokenStream, - line, - col, - prefix, - uri; - - //read import symbol - tokenStream.mustMatch(Tokens.NAMESPACE_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - this._readWhitespace(); + token = null; - //it's a namespace prefix - no _namespace_prefix() method because it's just an IDENT - if (tokenStream.match(Tokens.IDENT)){ - prefix = tokenStream.token().value; + if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) || + inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS])) { + token = tokenStream.token(); this._readWhitespace(); } + return token ? PropertyValuePart.fromToken(token) : null; - tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); - /*if (!tokenStream.match(Tokens.STRING)){ - tokenStream.mustMatch(Tokens.URI); - }*/ + }, - //grab the URI value - uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); + _combinator: function() { - this._readWhitespace(); + /* + * combinator + * : PLUS S* | GREATER S* | TILDE S* | S+ + * ; + */ - //must end with a semicolon - tokenStream.mustMatch(Tokens.SEMICOLON); - this._readWhitespace(); + var tokenStream = this._tokenStream, + value = null, + token; - if (emit !== false){ - this.fire({ - type: "namespace", - prefix: prefix, - uri: uri, - line: line, - col: col - }); + if (tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])) { + token = tokenStream.token(); + value = new Combinator(token.value, token.startLine, token.startCol); + this._readWhitespace(); } + return value; }, - _media: function(){ + _unary_operator: function() { + /* - * media - * : MEDIA_SYM S* media_query_list S* '{' S* ruleset* '}' S* - * ; + * unary_operator + * : '-' | '+' + * ; */ - var tokenStream = this._tokenStream, - line, - col, - mediaList;// = []; - - //look for @media - tokenStream.mustMatch(Tokens.MEDIA_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this._readWhitespace(); - - mediaList = this._media_query_list(); - - tokenStream.mustMatch(Tokens.LBRACE); - this._readWhitespace(); - this.fire({ - type: "startmedia", - media: mediaList, - line: line, - col: col - }); + var tokenStream = this._tokenStream; - while(true) { - if (tokenStream.peek() == Tokens.PAGE_SYM){ - this._page(); - } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){ - this._font_face(); - } else if (tokenStream.peek() == Tokens.VIEWPORT_SYM){ - this._viewport(); - } else if (!this._ruleset()){ - break; - } + if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])) { + return tokenStream.token().value; + } else { + return null; } - - tokenStream.mustMatch(Tokens.RBRACE); - this._readWhitespace(); - - this.fire({ - type: "endmedia", - media: mediaList, - line: line, - col: col - }); }, + _property: function() { - //CSS3 Media Queries - _media_query_list: function(){ /* - * media_query_list - * : S* [media_query [ ',' S* media_query ]* ]? + * property + * : IDENT S* * ; */ - var tokenStream = this._tokenStream, - mediaList = []; + var tokenStream = this._tokenStream, + value = null, + hack = null, + propertyName = "", + token, + line, + col; - this._readWhitespace(); + // check for star hack - throws error if not allowed + if (tokenStream.peek() === Tokens.STAR && this.options.starHack) { + tokenStream.get(); + token = tokenStream.token(); + hack = token.value; + line = token.startLine; + col = token.startCol; + } - if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){ - mediaList.push(this._media_query()); + // consume a single hyphen before finding the identifier, to support custom properties + if (tokenStream.peek() === Tokens.MINUS) { + tokenStream.get(); + token = tokenStream.token(); + propertyName = token.value; + line = token.startLine; + col = token.startCol; } - while(tokenStream.match(Tokens.COMMA)){ + if (tokenStream.match(Tokens.IDENT)) { + token = tokenStream.token(); + propertyName += token.value; + + // check for underscore hack - no error if not allowed because it's valid CSS syntax + if (propertyName.charAt(0) === "_" && this.options.underscoreHack) { + hack = "_"; + propertyName = propertyName.substring(1); + } + + value = new PropertyName(propertyName, hack, line || token.startLine, col || token.startCol); this._readWhitespace(); - mediaList.push(this._media_query()); + } else if (tokenStream.peek() === Tokens.RBRACE) { + // Encountered when there are no more properties. + } else { + this._unexpectedToken(tokenStream.LT(1)); } - return mediaList; + return value; }, - /* - * Note: "expression" in the grammar maps to the _media_expression - * method. - - */ - _media_query: function(){ + // Augmented with CSS3 Selectors + _ruleset: function() { /* - * media_query - * : [ONLY | NOT]? S* media_type S* [ AND S* expression ]* - * | expression [ AND S* expression ]* + * ruleset + * : selectors_group + * '{' S* declaration? [ ';' S* declaration? ]* '}' S* * ; */ + var tokenStream = this._tokenStream, - type = null, - ident = null, - token = null, - expressions = []; + tt, + selectors; - if (tokenStream.match(Tokens.IDENT)){ - ident = tokenStream.token().value.toLowerCase(); - //since there's no custom tokens for these, need to manually check - if (ident != "only" && ident != "not"){ - tokenStream.unget(); - ident = null; + /* + * Error Recovery: If even a single selector fails to parse, + * then the entire ruleset should be thrown away. + */ + try { + selectors = this._selectors_group(); + } catch (ex) { + if (ex instanceof SyntaxError && !this.options.strict) { + + // fire error event + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + + // skip over everything until closing brace + tt = tokenStream.advance([Tokens.RBRACE]); + if (tt === Tokens.RBRACE) { + // if there's a right brace, the rule is finished so don't do anything + } else { + // otherwise, rethrow the error because it wasn't handled properly + throw ex; + } + } else { - token = tokenStream.token(); + // not a syntax error, rethrow it + throw ex; } + + // trigger parser to continue + return true; } - this._readWhitespace(); + // if it got here, all selectors parsed + if (selectors) { - if (tokenStream.peek() == Tokens.IDENT){ - type = this._media_type(); - if (token === null){ - token = tokenStream.token(); - } - } else if (tokenStream.peek() == Tokens.LPAREN){ - if (token === null){ - token = tokenStream.LT(1); - } - expressions.push(this._media_expression()); - } + this.fire({ + type: "startrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); - if (type === null && expressions.length === 0){ - return null; - } else { - this._readWhitespace(); - while (tokenStream.match(Tokens.IDENT)){ - if (tokenStream.token().value.toLowerCase() != "and"){ - this._unexpectedToken(tokenStream.token()); - } + this._readDeclarations(true); + + this.fire({ + type: "endrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); - this._readWhitespace(); - expressions.push(this._media_expression()); - } } - return new MediaQuery(ident, type, expressions, token.startLine, token.startCol); - }, + return selectors; - //CSS3 Media Queries - _media_type: function(){ - /* - * media_type - * : IDENT - * ; - */ - return this._media_feature(); }, - /** - * Note: in CSS3 Media Queries, this is called "expression". - * Renamed here to avoid conflict with CSS3 Selectors - * definition of "expression". Also note that "expr" in the - * grammar now maps to "expression" from CSS3 selectors. - * @method _media_expression - * @private - */ - _media_expression: function(){ + // CSS3 Selectors + _selectors_group: function() { + /* - * expression - * : '(' S* media_feature S* [ ':' S* expr ]? ')' S* - * ; + * selectors_group + * : selector [ COMMA S* selector ]* + * ; */ var tokenStream = this._tokenStream, - feature = null, - token, - expression = null; - - tokenStream.mustMatch(Tokens.LPAREN); - this._readWhitespace(); + selectors = [], + selector; - feature = this._media_feature(); - this._readWhitespace(); + selector = this._selector(); + if (selector !== null) { - if (tokenStream.match(Tokens.COLON)){ - this._readWhitespace(); - token = tokenStream.LT(1); - expression = this._expression(); + selectors.push(selector); + while (tokenStream.match(Tokens.COMMA)) { + this._readWhitespace(); + selector = this._selector(); + if (selector !== null) { + selectors.push(selector); + } else { + this._unexpectedToken(tokenStream.LT(1)); + } + } } - tokenStream.mustMatch(Tokens.RPAREN); - this._readWhitespace(); - - return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null)); + return selectors.length ? selectors : null; }, - //CSS3 Media Queries - _media_feature: function(){ + // CSS3 Selectors + _selector: function() { /* - * media_feature - * : IDENT + * selector + * : simple_selector_sequence [ combinator simple_selector_sequence ]* * ; */ - var tokenStream = this._tokenStream; - tokenStream.mustMatch(Tokens.IDENT); + var tokenStream = this._tokenStream, + selector = [], + nextSelector = null, + combinator = null, + ws = null; - return SyntaxUnit.fromToken(tokenStream.token()); - }, + // if there's no simple selector, then there's no selector + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null) { + return null; + } - //CSS3 Paged Media - _page: function(){ - /* - * page: - * PAGE_SYM S* IDENT? pseudo_page? S* - * '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* - * ; - */ - var tokenStream = this._tokenStream, - line, - col, - identifier = null, - pseudoPage = null; + selector.push(nextSelector); - //look for @page - tokenStream.mustMatch(Tokens.PAGE_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; + do { - this._readWhitespace(); + // look for a combinator + combinator = this._combinator(); - if (tokenStream.match(Tokens.IDENT)){ - identifier = tokenStream.token().value; + if (combinator !== null) { + selector.push(combinator); + nextSelector = this._simple_selector_sequence(); - //The value 'auto' may not be used as a page name and MUST be treated as a syntax error. - if (identifier.toLowerCase() === "auto"){ - this._unexpectedToken(tokenStream.token()); - } - } + // there must be a next selector + if (nextSelector === null) { + this._unexpectedToken(tokenStream.LT(1)); + } else { - //see if there's a colon upcoming - if (tokenStream.peek() == Tokens.COLON){ - pseudoPage = this._pseudo_page(); - } + // nextSelector is an instance of SelectorPart + selector.push(nextSelector); + } + } else { - this._readWhitespace(); + // if there's not whitespace, we're done + if (this._readWhitespace()) { - this.fire({ - type: "startpage", - id: identifier, - pseudo: pseudoPage, - line: line, - col: col - }); + // add whitespace separator + ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol); - this._readDeclarations(true, true); + //combinator is not required + combinator = this._combinator(); - this.fire({ - type: "endpage", - id: identifier, - pseudo: pseudoPage, - line: line, - col: col - }); + // selector is required if there's a combinator + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null) { + if (combinator !== null) { + this._unexpectedToken(tokenStream.LT(1)); + } + } else { + if (combinator !== null) { + selector.push(combinator); + } else { + selector.push(ws); + } + + selector.push(nextSelector); + } + } else { + break; + } + + } + } while (true); + + return new Selector(selector, selector[0].line, selector[0].col); }, - //CSS3 Paged Media - _margin: function(){ + // CSS3 Selectors + _simple_selector_sequence: function() { /* - * margin : - * margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S* - * ; + * simple_selector_sequence + * : [ type_selector | universal ] + * [ HASH | class | attrib | pseudo | negation ]* + * | [ HASH | class | attrib | pseudo | negation ]+ + * ; */ + var tokenStream = this._tokenStream, + + // parts of a simple selector + elementName = null, + modifiers = [], + + // complete selector text + selectorText = "", + + // the different parts after the element name to search for + components = [ + // HASH + function() { + return tokenStream.match(Tokens.HASH) ? + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : + null; + }, + this._class, + this._attrib, + this._pseudo, + this._negation + ], + i = 0, + len = components.length, + component = null, line, - col, - marginSym = this._margin_sym(); + col; - if (marginSym){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - this.fire({ - type: "startpagemargin", - margin: marginSym, - line: line, - col: col - }); + // get starting line and column for the selector + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; - this._readDeclarations(true); + elementName = this._type_selector(); + if (!elementName) { + elementName = this._universal(); + } - this.fire({ - type: "endpagemargin", - margin: marginSym, - line: line, - col: col - }); - return true; - } else { - return false; + if (elementName !== null) { + selectorText += elementName; } - }, - //CSS3 Paged Media - _margin_sym: function(){ + while (true) { - /* - * margin_sym : - * TOPLEFTCORNER_SYM | - * TOPLEFT_SYM | - * TOPCENTER_SYM | - * TOPRIGHT_SYM | - * TOPRIGHTCORNER_SYM | - * BOTTOMLEFTCORNER_SYM | - * BOTTOMLEFT_SYM | - * BOTTOMCENTER_SYM | - * BOTTOMRIGHT_SYM | - * BOTTOMRIGHTCORNER_SYM | - * LEFTTOP_SYM | - * LEFTMIDDLE_SYM | - * LEFTBOTTOM_SYM | - * RIGHTTOP_SYM | - * RIGHTMIDDLE_SYM | - * RIGHTBOTTOM_SYM - * ; - */ + // whitespace means we're done + if (tokenStream.peek() === Tokens.S) { + break; + } - var tokenStream = this._tokenStream; + // check for each component + while (i < len && component === null) { + component = components[i++].call(this); + } - if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM, - Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM, - Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM, - Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM, - Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM, - Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM, - Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM])) - { - return SyntaxUnit.fromToken(tokenStream.token()); - } else { - return null; + if (component === null) { + + // we don't have a selector + if (selectorText === "") { + return null; + } else { + break; + } + } else { + i = 0; + modifiers.push(component); + selectorText += component.toString(); + component = null; + } } + + return selectorText !== "" ? + new SelectorPart(elementName, modifiers, selectorText, line, col) : + null; }, - _pseudo_page: function(){ + // CSS3 Selectors + _type_selector: function() { /* - * pseudo_page - * : ':' IDENT + * type_selector + * : [ namespace_prefix ]? element_name * ; */ - var tokenStream = this._tokenStream; - - tokenStream.mustMatch(Tokens.COLON); - tokenStream.mustMatch(Tokens.IDENT); + var tokenStream = this._tokenStream, + ns = this._namespace_prefix(), + elementName = this._element_name(); - //TODO: CSS3 Paged Media says only "left", "center", and "right" are allowed + if (!elementName) { + /* + * Need to back out the namespace that was read due to both + * type_selector and universal reading namespace_prefix + * first. Kind of hacky, but only way I can figure out + * right now how to not change the grammar. + */ + if (ns) { + tokenStream.unget(); + if (ns.length > 1) { + tokenStream.unget(); + } + } - return tokenStream.token().value; + return null; + } else { + if (ns) { + elementName.text = ns + elementName.text; + elementName.col -= ns.length; + } + return elementName; + } }, - _font_face: function(){ + // CSS3 Selectors + _class: function() { /* - * font_face - * : FONT_FACE_SYM S* - * '{' S* declaration [ ';' S* declaration ]* '}' S* + * class + * : '.' IDENT * ; */ + var tokenStream = this._tokenStream, - line, - col; + token; - //look for @page - tokenStream.mustMatch(Tokens.FONT_FACE_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; + if (tokenStream.match(Tokens.DOT)) { + tokenStream.mustMatch(Tokens.IDENT); + token = tokenStream.token(); + return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1); + } else { + return null; + } - this._readWhitespace(); + }, - this.fire({ - type: "startfontface", - line: line, - col: col - }); + // CSS3 Selectors + _element_name: function() { + /* + * element_name + * : IDENT + * ; + */ - this._readDeclarations(true); + var tokenStream = this._tokenStream, + token; - this.fire({ - type: "endfontface", - line: line, - col: col - }); + if (tokenStream.match(Tokens.IDENT)) { + token = tokenStream.token(); + return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol); + + } else { + return null; + } }, - _viewport: function(){ + // CSS3 Selectors + _namespace_prefix: function() { /* - * viewport - * : VIEWPORT_SYM S* - * '{' S* declaration? [ ';' S* declaration? ]* '}' S* + * namespace_prefix + * : [ IDENT | '*' ]? '|' * ; */ - var tokenStream = this._tokenStream, - line, - col; - - tokenStream.mustMatch(Tokens.VIEWPORT_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; + var tokenStream = this._tokenStream, + value = ""; - this._readWhitespace(); + // verify that this is a namespace prefix + if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE) { - this.fire({ - type: "startviewport", - line: line, - col: col - }); + if (tokenStream.match([Tokens.IDENT, Tokens.STAR])) { + value += tokenStream.token().value; + } - this._readDeclarations(true); + tokenStream.mustMatch(Tokens.PIPE); + value += "|"; - this.fire({ - type: "endviewport", - line: line, - col: col - }); + } + return value.length ? value : null; }, - _operator: function(inFunction){ - + // CSS3 Selectors + _universal: function() { /* - * operator (outside function) - * : '/' S* | ',' S* | /( empty )/ - * operator (inside function) - * : '/' S* | '+' S* | '*' S* | '-' S* /( empty )/ - * ; + * universal + * : [ namespace_prefix ]? '*' + * ; */ - var tokenStream = this._tokenStream, - token = null; + value = "", + ns; - if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) || - (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){ - token = tokenStream.token(); - this._readWhitespace(); + ns = this._namespace_prefix(); + if (ns) { + value += ns; } - return token ? PropertyValuePart.fromToken(token) : null; - }, + if (tokenStream.match(Tokens.STAR)) { + value += "*"; + } + + return value.length ? value : null; - _combinator: function(){ + }, + // CSS3 Selectors + _attrib: function() { /* - * combinator - * : PLUS S* | GREATER S* | TILDE S* | S+ - * ; + * attrib + * : '[' S* [ namespace_prefix ]? IDENT S* + * [ [ PREFIXMATCH | + * SUFFIXMATCH | + * SUBSTRINGMATCH | + * '=' | + * INCLUDES | + * DASHMATCH ] S* [ IDENT | STRING ] S* + * ]? ']' + * ; */ var tokenStream = this._tokenStream, value = null, + ns, token; - if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){ + if (tokenStream.match(Tokens.LBRACKET)) { token = tokenStream.token(); - value = new Combinator(token.value, token.startLine, token.startCol); - this._readWhitespace(); - } + value = token.value; + value += this._readWhitespace(); - return value; - }, + ns = this._namespace_prefix(); - _unary_operator: function(){ + if (ns) { + value += ns; + } - /* - * unary_operator - * : '-' | '+' - * ; - */ + tokenStream.mustMatch(Tokens.IDENT); + value += tokenStream.token().value; + value += this._readWhitespace(); - var tokenStream = this._tokenStream; + if (tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH, + Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])) { - if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){ - return tokenStream.token().value; + value += tokenStream.token().value; + value += this._readWhitespace(); + + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + value += tokenStream.token().value; + value += this._readWhitespace(); + } + + tokenStream.mustMatch(Tokens.RBRACKET); + + return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol); } else { return null; } }, - _property: function(){ + // CSS3 Selectors + _pseudo: function() { /* - * property - * : IDENT S* + * pseudo + * : ':' ':'? [ IDENT | functional_pseudo ] * ; */ var tokenStream = this._tokenStream, - value = null, - hack = null, - tokenValue, - token, + pseudo = null, + colons = ":", line, col; - //check for star hack - throws error if not allowed - if (tokenStream.peek() == Tokens.STAR && this.options.starHack){ - tokenStream.get(); - token = tokenStream.token(); - hack = token.value; - line = token.startLine; - col = token.startCol; - } + if (tokenStream.match(Tokens.COLON)) { - if(tokenStream.match(Tokens.IDENT)){ - token = tokenStream.token(); - tokenValue = token.value; + if (tokenStream.match(Tokens.COLON)) { + colons += ":"; + } - //check for underscore hack - no error if not allowed because it's valid CSS syntax - if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){ - hack = "_"; - tokenValue = tokenValue.substring(1); + if (tokenStream.match(Tokens.IDENT)) { + pseudo = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol - colons.length; + } else if (tokenStream.peek() === Tokens.FUNCTION) { + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol - colons.length; + pseudo = this._functional_pseudo(); } - value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol)); - this._readWhitespace(); + if (pseudo) { + pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col); + } else { + var startLine = tokenStream.LT(1).startLine, + startCol = tokenStream.LT(0).startCol; + throw new SyntaxError("Expected a `FUNCTION` or `IDENT` after colon at line " + startLine + ", col " + startCol + ".", startLine, startCol); + } } - return value; + return pseudo; }, - //Augmented with CSS3 Selectors - _ruleset: function(){ + // CSS3 Selectors + _functional_pseudo: function() { /* - * ruleset - * : selectors_group - * '{' S* declaration? [ ';' S* declaration? ]* '}' S* + * functional_pseudo + * : FUNCTION S* expression ')' * ; - */ + */ var tokenStream = this._tokenStream, - tt, - selectors; + value = null; + + if (tokenStream.match(Tokens.FUNCTION)) { + value = tokenStream.token().value; + value += this._readWhitespace(); + value += this._expression(); + tokenStream.mustMatch(Tokens.RPAREN); + value += ")"; + } + return value; + }, + // CSS3 Selectors + _expression: function() { /* - * Error Recovery: If even a single selector fails to parse, - * then the entire ruleset should be thrown away. - */ - try { - selectors = this._selectors_group(); - } catch (ex){ - if (ex instanceof SyntaxError && !this.options.strict){ - - //fire error event - this.fire({ - type: "error", - error: ex, - message: ex.message, - line: ex.line, - col: ex.col - }); - - //skip over everything until closing brace - tt = tokenStream.advance([Tokens.RBRACE]); - if (tt == Tokens.RBRACE){ - //if there's a right brace, the rule is finished so don't do anything - } else { - //otherwise, rethrow the error because it wasn't handled properly - throw ex; - } - - } else { - //not a syntax error, rethrow it - throw ex; - } - - //trigger parser to continue - return true; - } - - //if it got here, all selectors parsed - if (selectors){ - - this.fire({ - type: "startrule", - selectors: selectors, - line: selectors[0].line, - col: selectors[0].col - }); - - this._readDeclarations(true); - - this.fire({ - type: "endrule", - selectors: selectors, - line: selectors[0].line, - col: selectors[0].col - }); - - } - - return selectors; - - }, - - //CSS3 Selectors - _selectors_group: function(){ - - /* - * selectors_group - * : selector [ COMMA S* selector ]* + * expression + * : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+ * ; */ + var tokenStream = this._tokenStream, - selectors = [], - selector; + value = ""; - selector = this._selector(); - if (selector !== null){ + while (tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION, + Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH, + Tokens.FREQ, Tokens.ANGLE, Tokens.TIME, + Tokens.RESOLUTION, Tokens.SLASH])) { - selectors.push(selector); - while(tokenStream.match(Tokens.COMMA)){ - this._readWhitespace(); - selector = this._selector(); - if (selector !== null){ - selectors.push(selector); - } else { - this._unexpectedToken(tokenStream.LT(1)); - } - } + value += tokenStream.token().value; + value += this._readWhitespace(); } - return selectors.length ? selectors : null; + return value.length ? value : null; + }, - //CSS3 Selectors - _selector: function(){ + // CSS3 Selectors + _negation: function() { /* - * selector - * : simple_selector_sequence [ combinator simple_selector_sequence ]* + * negation + * : NOT S* negation_arg S* ')' * ; */ var tokenStream = this._tokenStream, - selector = [], - nextSelector = null, - combinator = null, - ws = null; - - //if there's no simple selector, then there's no selector - nextSelector = this._simple_selector_sequence(); - if (nextSelector === null){ - return null; - } - - selector.push(nextSelector); - - do { - - //look for a combinator - combinator = this._combinator(); - - if (combinator !== null){ - selector.push(combinator); - nextSelector = this._simple_selector_sequence(); - - //there must be a next selector - if (nextSelector === null){ - this._unexpectedToken(tokenStream.LT(1)); - } else { - - //nextSelector is an instance of SelectorPart - selector.push(nextSelector); - } - } else { - - //if there's not whitespace, we're done - if (this._readWhitespace()){ - - //add whitespace separator - ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol); - - //combinator is not required - combinator = this._combinator(); - - //selector is required if there's a combinator - nextSelector = this._simple_selector_sequence(); - if (nextSelector === null){ - if (combinator !== null){ - this._unexpectedToken(tokenStream.LT(1)); - } - } else { - - if (combinator !== null){ - selector.push(combinator); - } else { - selector.push(ws); - } + line, + col, + value = "", + arg, + subpart = null; - selector.push(nextSelector); - } - } else { - break; - } + if (tokenStream.match(Tokens.NOT)) { + value = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + value += this._readWhitespace(); + arg = this._negation_arg(); + value += arg; + value += this._readWhitespace(); + tokenStream.match(Tokens.RPAREN); + value += tokenStream.token().value; - } - } while(true); + subpart = new SelectorSubPart(value, "not", line, col); + subpart.args.push(arg); + } - return new Selector(selector, selector[0].line, selector[0].col); + return subpart; }, - //CSS3 Selectors - _simple_selector_sequence: function(){ + // CSS3 Selectors + _negation_arg: function() { /* - * simple_selector_sequence - * : [ type_selector | universal ] - * [ HASH | class | attrib | pseudo | negation ]* - * | [ HASH | class | attrib | pseudo | negation ]+ + * negation_arg + * : type_selector | universal | HASH | class | attrib | pseudo * ; */ var tokenStream = this._tokenStream, - - //parts of a simple selector - elementName = null, - modifiers = [], - - //complete selector text - selectorText= "", - - //the different parts after the element name to search for - components = [ - //HASH - function(){ + args = [ + this._type_selector, + this._universal, + function() { return tokenStream.match(Tokens.HASH) ? new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : null; }, this._class, this._attrib, - this._pseudo, - this._negation + this._pseudo ], + arg = null, i = 0, - len = components.length, - component = null, - found = false, + len = args.length, line, - col; - + col, + part; - //get starting line and column for the selector line = tokenStream.LT(1).startLine; col = tokenStream.LT(1).startCol; - elementName = this._type_selector(); - if (!elementName){ - elementName = this._universal(); - } + while (i < len && arg === null) { - if (elementName !== null){ - selectorText += elementName; + arg = args[i].call(this); + i++; } - while(true){ - - //whitespace means we're done - if (tokenStream.peek() === Tokens.S){ - break; - } - - //check for each component - while(i < len && component === null){ - component = components[i++].call(this); - } - - if (component === null){ - - //we don't have a selector - if (selectorText === ""){ - return null; - } else { - break; - } - } else { - i = 0; - modifiers.push(component); - selectorText += component.toString(); - component = null; - } + // must be a negation arg + if (arg === null) { + this._unexpectedToken(tokenStream.LT(1)); } + // it's an element name + if (arg.type === "elementName") { + part = new SelectorPart(arg, [], arg.toString(), line, col); + } else { + part = new SelectorPart(null, [arg], arg.toString(), line, col); + } - return selectorText !== "" ? - new SelectorPart(elementName, modifiers, selectorText, line, col) : - null; + return part; }, - //CSS3 Selectors - _type_selector: function(){ + _declaration: function() { + /* - * type_selector - * : [ namespace_prefix ]? element_name + * declaration + * : property ':' S* expr prio? + * | /( empty )/ * ; */ - var tokenStream = this._tokenStream, - ns = this._namespace_prefix(), - elementName = this._element_name(); + var tokenStream = this._tokenStream, + property = null, + expr = null, + prio = null, + invalid = null, + propertyName = ""; + + property = this._property(); + if (property !== null) { + + tokenStream.mustMatch(Tokens.COLON); + this._readWhitespace(); + + expr = this._expr(); + + // if there's no parts for the value, it's an error + if (!expr || expr.length === 0) { + this._unexpectedToken(tokenStream.LT(1)); + } + + prio = this._prio(); - if (!elementName){ /* - * Need to back out the namespace that was read due to both - * type_selector and universal reading namespace_prefix - * first. Kind of hacky, but only way I can figure out - * right now how to not change the grammar. + * If hacks should be allowed, then only check the root + * property. If hacks should not be allowed, treat + * _property or *property as invalid properties. */ - if (ns){ - tokenStream.unget(); - if (ns.length > 1){ - tokenStream.unget(); - } + propertyName = property.toString(); + if (this.options.starHack && property.hack === "*" || + this.options.underscoreHack && property.hack === "_") { + + propertyName = property.text; } - return null; - } else { - if (ns){ - elementName.text = ns + elementName.text; - elementName.col -= ns.length; + try { + this._validateProperty(propertyName, expr); + } catch (ex) { + invalid = ex; } - return elementName; + + this.fire({ + type: "property", + property: property, + value: expr, + important: prio, + line: property.line, + col: property.col, + invalid: invalid + }); + + return true; + } else { + return false; } }, - //CSS3 Selectors - _class: function(){ + _prio: function() { /* - * class - * : '.' IDENT + * prio + * : IMPORTANT_SYM S* * ; */ var tokenStream = this._tokenStream, - token; - - if (tokenStream.match(Tokens.DOT)){ - tokenStream.mustMatch(Tokens.IDENT); - token = tokenStream.token(); - return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1); - } else { - return null; - } + result = tokenStream.match(Tokens.IMPORTANT_SYM); + this._readWhitespace(); + return result; }, - //CSS3 Selectors - _element_name: function(){ + _expr: function(inFunction) { /* - * element_name - * : IDENT + * expr + * : term [ operator term ]* * ; */ - var tokenStream = this._tokenStream, - token; - - if (tokenStream.match(Tokens.IDENT)){ - token = tokenStream.token(); - return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol); + var values = [], + //valueParts = [], + value = null, + operator = null; - } else { - return null; - } - }, + value = this._term(inFunction); + if (value !== null) { - //CSS3 Selectors - _namespace_prefix: function(){ - /* - * namespace_prefix - * : [ IDENT | '*' ]? '|' - * ; - */ - var tokenStream = this._tokenStream, - value = ""; + values.push(value); - //verify that this is a namespace prefix - if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){ + do { + operator = this._operator(inFunction); - if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){ - value += tokenStream.token().value; - } + // if there's an operator, keep building up the value parts + if (operator) { + values.push(operator); + } /*else { + // if there's not an operator, you have a full value + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); + valueParts = []; + }*/ - tokenStream.mustMatch(Tokens.PIPE); - value += "|"; + value = this._term(inFunction); + if (value === null) { + break; + } else { + values.push(value); + } + } while (true); } - return value.length ? value : null; + // cleanup + /*if (valueParts.length) { + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); + }*/ + + return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null; }, - //CSS3 Selectors - _universal: function(){ + _term: function(inFunction) { + /* - * universal - * : [ namespace_prefix ]? '*' + * term + * : unary_operator? + * [ NUMBER S* | PERCENTAGE S* | LENGTH S* | ANGLE S* | + * TIME S* | FREQ S* | function | ie_function ] + * | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor * ; */ - var tokenStream = this._tokenStream, - value = "", - ns; - ns = this._namespace_prefix(); - if(ns){ - value += ns; - } + var tokenStream = this._tokenStream, + unary = null, + value = null, + endChar = null, + part = null, + token, + line, + col; - if(tokenStream.match(Tokens.STAR)){ - value += "*"; + // returns the operator or null + unary = this._unary_operator(); + if (unary !== null) { + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; } - return value.length ? value : null; - - }, + // exception for IE filters + if (tokenStream.peek() === Tokens.IE_FUNCTION && this.options.ieFilters) { - //CSS3 Selectors - _attrib: function(){ - /* - * attrib - * : '[' S* [ namespace_prefix ]? IDENT S* - * [ [ PREFIXMATCH | - * SUFFIXMATCH | - * SUBSTRINGMATCH | - * '=' | - * INCLUDES | - * DASHMATCH ] S* [ IDENT | STRING ] S* - * ]? ']' - * ; - */ + value = this._ie_function(); + if (unary === null) { + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } - var tokenStream = this._tokenStream, - value = null, - ns, - token; + // see if it's a simple block + } else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])) { - if (tokenStream.match(Tokens.LBRACKET)){ token = tokenStream.token(); - value = token.value; - value += this._readWhitespace(); + endChar = token.endChar; + value = token.value + this._expr(inFunction).text; + if (unary === null) { + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + tokenStream.mustMatch(Tokens.type(endChar)); + value += endChar; + this._readWhitespace(); - ns = this._namespace_prefix(); + // see if there's a simple match + } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH, + Tokens.ANGLE, Tokens.TIME, + Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])) { - if (ns){ - value += ns; + value = tokenStream.token().value; + if (unary === null) { + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + // Correct potentially-inaccurate IDENT parsing in + // PropertyValuePart constructor. + part = PropertyValuePart.fromToken(tokenStream.token()); } + this._readWhitespace(); + } else { - tokenStream.mustMatch(Tokens.IDENT); - value += tokenStream.token().value; - value += this._readWhitespace(); + // see if it's a color + token = this._hexcolor(); + if (token === null) { - if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH, - Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){ + // if there's no unary, get the start of the next token for line/col info + if (unary === null) { + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + } - value += tokenStream.token().value; - value += this._readWhitespace(); + // has to be a function + if (value === null) { - tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); - value += tokenStream.token().value; - value += this._readWhitespace(); - } + /* + * This checks for alpha(opacity=0) style of IE + * functions. IE_FUNCTION only presents progid: style. + */ + if (tokenStream.LA(3) === Tokens.EQUALS && this.options.ieFilters) { + value = this._ie_function(); + } else { + value = this._function(); + } + } - tokenStream.mustMatch(Tokens.RBRACKET); + /*if (value === null) { + return null; + //throw new Error("Expected identifier at line " + tokenStream.token().startLine + ", character " + tokenStream.token().startCol + "."); + }*/ + + } else { + value = token.value; + if (unary === null) { + line = token.startLine; + col = token.startCol; + } + } - return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol); - } else { - return null; } + + return part !== null ? part : value !== null ? + new PropertyValuePart(unary !== null ? unary + value : value, line, col) : + null; + }, - //CSS3 Selectors - _pseudo: function(){ + _function: function() { /* - * pseudo - * : ':' ':'? [ IDENT | functional_pseudo ] + * function + * : FUNCTION S* expr ')' S* * ; */ var tokenStream = this._tokenStream, - pseudo = null, - colons = ":", - line, - col; + functionText = null, + expr = null, + lt; - if (tokenStream.match(Tokens.COLON)){ + if (tokenStream.match(Tokens.FUNCTION)) { + functionText = tokenStream.token().value; + this._readWhitespace(); + expr = this._expr(true); + functionText += expr; - if (tokenStream.match(Tokens.COLON)){ - colons += ":"; - } + // START: Horrible hack in case it's an IE filter + if (this.options.ieFilters && tokenStream.peek() === Tokens.EQUALS) { + do { - if (tokenStream.match(Tokens.IDENT)){ - pseudo = tokenStream.token().value; - line = tokenStream.token().startLine; - col = tokenStream.token().startCol - colons.length; - } else if (tokenStream.peek() == Tokens.FUNCTION){ - line = tokenStream.LT(1).startLine; - col = tokenStream.LT(1).startCol - colons.length; - pseudo = this._functional_pseudo(); - } + if (this._readWhitespace()) { + functionText += tokenStream.token().value; + } - if (pseudo){ - pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col); - } - } + // might be second time in the loop + if (tokenStream.LA(0) === Tokens.COMMA) { + functionText += tokenStream.token().value; + } - return pseudo; - }, + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; - //CSS3 Selectors - _functional_pseudo: function(){ - /* - * functional_pseudo - * : FUNCTION S* expression ')' - * ; - */ + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; - var tokenStream = this._tokenStream, - value = null; + //functionText += this._term(); + lt = tokenStream.peek(); + while (lt !== Tokens.COMMA && lt !== Tokens.S && lt !== Tokens.RPAREN) { + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while (tokenStream.match([Tokens.COMMA, Tokens.S])); + } - if(tokenStream.match(Tokens.FUNCTION)){ - value = tokenStream.token().value; - value += this._readWhitespace(); - value += this._expression(); - tokenStream.mustMatch(Tokens.RPAREN); - value += ")"; + // END: Horrible Hack + + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); } - return value; + return functionText; }, - //CSS3 Selectors - _expression: function(){ - /* - * expression - * : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+ + _ie_function: function() { + + /* (My own extension) + * ie_function + * : IE_FUNCTION S* IDENT '=' term [S* ','? IDENT '=' term]+ ')' S* * ; */ var tokenStream = this._tokenStream, - value = ""; + functionText = null, + lt; - while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION, - Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH, - Tokens.FREQ, Tokens.ANGLE, Tokens.TIME, - Tokens.RESOLUTION, Tokens.SLASH])){ + // IE function can begin like a regular function, too + if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])) { + functionText = tokenStream.token().value; - value += tokenStream.token().value; - value += this._readWhitespace(); - } + do { - return value.length ? value : null; + if (this._readWhitespace()) { + functionText += tokenStream.token().value; + } - }, + // might be second time in the loop + if (tokenStream.LA(0) === Tokens.COMMA) { + functionText += tokenStream.token().value; + } - //CSS3 Selectors - _negation: function(){ - /* - * negation - * : NOT S* negation_arg S* ')' - * ; - */ + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; - var tokenStream = this._tokenStream, - line, - col, - value = "", - arg, - subpart = null; + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; - if (tokenStream.match(Tokens.NOT)){ - value = tokenStream.token().value; - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - value += this._readWhitespace(); - arg = this._negation_arg(); - value += arg; - value += this._readWhitespace(); - tokenStream.match(Tokens.RPAREN); - value += tokenStream.token().value; + //functionText += this._term(); + lt = tokenStream.peek(); + while (lt !== Tokens.COMMA && lt !== Tokens.S && lt !== Tokens.RPAREN) { + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while (tokenStream.match([Tokens.COMMA, Tokens.S])); - subpart = new SelectorSubPart(value, "not", line, col); - subpart.args.push(arg); + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); } - return subpart; + return functionText; }, - //CSS3 Selectors - _negation_arg: function(){ + _hexcolor: function() { /* - * negation_arg - * : type_selector | universal | HASH | class | attrib | pseudo + * There is a constraint on the color that it must + * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F]) + * after the "#"; e.g., "#000" is OK, but "#abcd" is not. + * + * hexcolor + * : HASH S* * ; */ var tokenStream = this._tokenStream, - args = [ - this._type_selector, - this._universal, - function(){ - return tokenStream.match(Tokens.HASH) ? - new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : - null; - }, - this._class, - this._attrib, - this._pseudo - ], - arg = null, - i = 0, - len = args.length, - elementName, - line, - col, - part; - - line = tokenStream.LT(1).startLine; - col = tokenStream.LT(1).startCol; - - while(i < len && arg === null){ + token = null, + color; - arg = args[i].call(this); - i++; - } + if (tokenStream.match(Tokens.HASH)) { - //must be a negation arg - if (arg === null){ - this._unexpectedToken(tokenStream.LT(1)); - } + // need to do some validation here - //it's an element name - if (arg.type == "elementName"){ - part = new SelectorPart(arg, [], arg.toString(), line, col); - } else { - part = new SelectorPart(null, [arg], arg.toString(), line, col); + token = tokenStream.token(); + color = token.value; + if (!/#[a-f0-9]{3,6}/i.test(color)) { + throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + } + this._readWhitespace(); } - return part; + return token; }, - _declaration: function(){ + //----------------------------------------------------------------- + // Animations methods + //----------------------------------------------------------------- + + _keyframes: function() { /* - * declaration - * : property ':' S* expr prio? - * | /( empty )/ + * keyframes: + * : KEYFRAMES_SYM S* keyframe_name S* '{' S* keyframe_rule* '}' { * ; */ - var tokenStream = this._tokenStream, - property = null, - expr = null, - prio = null, - error = null, - invalid = null, - propertyName= ""; - - property = this._property(); - if (property !== null){ + token, + tt, + name, + prefix = ""; - tokenStream.mustMatch(Tokens.COLON); - this._readWhitespace(); + tokenStream.mustMatch(Tokens.KEYFRAMES_SYM); + token = tokenStream.token(); + if (/^@-([^-]+)-/.test(token.value)) { + prefix = RegExp.$1; + } - expr = this._expr(); + this._readWhitespace(); + name = this._keyframe_name(); - //if there's no parts for the value, it's an error - if (!expr || expr.length === 0){ - this._unexpectedToken(tokenStream.LT(1)); - } + this._readWhitespace(); + tokenStream.mustMatch(Tokens.LBRACE); - prio = this._prio(); + this.fire({ + type: "startkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); - /* - * If hacks should be allowed, then only check the root - * property. If hacks should not be allowed, treat - * _property or *property as invalid properties. - */ - propertyName = property.toString(); - if (this.options.starHack && property.hack == "*" || - this.options.underscoreHack && property.hack == "_") { + this._readWhitespace(); + tt = tokenStream.peek(); - propertyName = property.text; - } + // check for key + while (tt === Tokens.IDENT || tt === Tokens.PERCENTAGE) { + this._keyframe_rule(); + this._readWhitespace(); + tt = tokenStream.peek(); + } - try { - this._validateProperty(propertyName, expr); - } catch (ex) { - invalid = ex; - } + this.fire({ + type: "endkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); - this.fire({ - type: "property", - property: property, - value: expr, - important: prio, - line: property.line, - col: property.col, - invalid: invalid - }); + this._readWhitespace(); + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); - return true; - } else { - return false; - } }, - _prio: function(){ + _keyframe_name: function() { + /* - * prio - * : IMPORTANT_SYM S* + * keyframe_name: + * : IDENT + * | STRING * ; */ + var tokenStream = this._tokenStream; - var tokenStream = this._tokenStream, - result = tokenStream.match(Tokens.IMPORTANT_SYM); - - this._readWhitespace(); - return result; + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + return SyntaxUnit.fromToken(tokenStream.token()); }, - _expr: function(inFunction){ + _keyframe_rule: function() { + /* - * expr - * : term [ operator term ]* + * keyframe_rule: + * : key_list S* + * '{' S* declaration [ ';' S* declaration ]* '}' S* * ; */ + var keyList = this._key_list(); - var tokenStream = this._tokenStream, - values = [], - //valueParts = [], - value = null, - operator = null; + this.fire({ + type: "startkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); - value = this._term(inFunction); - if (value !== null){ + this._readDeclarations(true); - values.push(value); + this.fire({ + type: "endkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); - do { - operator = this._operator(inFunction); + }, - //if there's an operator, keep building up the value parts - if (operator){ - values.push(operator); - } /*else { - //if there's not an operator, you have a full value - values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); - valueParts = []; - }*/ + _key_list: function() { - value = this._term(inFunction); + /* + * key_list: + * : key [ S* ',' S* key]* + * ; + */ + var tokenStream = this._tokenStream, + keyList = []; - if (value === null){ - break; - } else { - values.push(value); - } - } while(true); - } + // must be least one key + keyList.push(this._key()); - //cleanup - /*if (valueParts.length){ - values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); - }*/ + this._readWhitespace(); - return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null; - }, + while (tokenStream.match(Tokens.COMMA)) { + this._readWhitespace(); + keyList.push(this._key()); + this._readWhitespace(); + } - _term: function(inFunction){ + return keyList; + }, + _key: function() { /* - * term - * : unary_operator? - * [ NUMBER S* | PERCENTAGE S* | LENGTH S* | ANGLE S* | - * TIME S* | FREQ S* | function | ie_function ] - * | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor + * There is a restriction that IDENT can be only "from" or "to". + * + * key + * : PERCENTAGE + * | IDENT * ; */ var tokenStream = this._tokenStream, - unary = null, - value = null, - endChar = null, - token, - line, - col; - - //returns the operator or null - unary = this._unary_operator(); - if (unary !== null){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - } + token; - //exception for IE filters - if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){ + if (tokenStream.match(Tokens.PERCENTAGE)) { + return SyntaxUnit.fromToken(tokenStream.token()); + } else if (tokenStream.match(Tokens.IDENT)) { + token = tokenStream.token(); - value = this._ie_function(); - if (unary === null){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; + if (/from|to/i.test(token.value)) { + return SyntaxUnit.fromToken(token); } - //see if it's a simple block - } else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])){ - - token = tokenStream.token(); - endChar = token.endChar; - value = token.value + this._expr(inFunction).text; - if (unary === null){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - } - tokenStream.mustMatch(Tokens.type(endChar)); - value += endChar; - this._readWhitespace(); - - //see if there's a simple match - } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH, - Tokens.ANGLE, Tokens.TIME, - Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){ - - value = tokenStream.token().value; - if (unary === null){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - } - this._readWhitespace(); - } else { - - //see if it's a color - token = this._hexcolor(); - if (token === null){ - - //if there's no unary, get the start of the next token for line/col info - if (unary === null){ - line = tokenStream.LT(1).startLine; - col = tokenStream.LT(1).startCol; - } - - //has to be a function - if (value === null){ - - /* - * This checks for alpha(opacity=0) style of IE - * functions. IE_FUNCTION only presents progid: style. - */ - if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){ - value = this._ie_function(); - } else { - value = this._function(); - } - } + tokenStream.unget(); + } - /*if (value === null){ - return null; - //throw new Error("Expected identifier at line " + tokenStream.token().startLine + ", character " + tokenStream.token().startCol + "."); - }*/ + // if it gets here, there wasn't a valid token, so time to explode + this._unexpectedToken(tokenStream.LT(1)); + }, - } else { - value = token.value; - if (unary === null){ - line = token.startLine; - col = token.startCol; - } - } + //----------------------------------------------------------------- + // Helper methods + //----------------------------------------------------------------- + /** + * Not part of CSS grammar, but useful for skipping over + * combination of white space and HTML-style comments. + * @return {void} + * @method _skipCruft + * @private + */ + _skipCruft: function() { + while (this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])) { + // noop } - - return value !== null ? - new PropertyValuePart(unary !== null ? unary + value : value, line, col) : - null; - }, - _function: function(){ - + /** + * Not part of CSS grammar, but this pattern occurs frequently + * in the official CSS grammar. Split out here to eliminate + * duplicate code. + * @param {Boolean} checkStart Indicates if the rule should check + * for the left brace at the beginning. + * @param {Boolean} readMargins Indicates if the rule should check + * for margin patterns. + * @return {void} + * @method _readDeclarations + * @private + */ + _readDeclarations: function(checkStart, readMargins) { /* - * function - * : FUNCTION S* expr ')' S* - * ; + * Reads the pattern + * S* '{' S* declaration [ ';' S* declaration ]* '}' S* + * or + * S* '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* + * Note that this is how it is described in CSS3 Paged Media, but is actually incorrect. + * A semicolon is only necessary following a declaration if there's another declaration + * or margin afterwards. */ - var tokenStream = this._tokenStream, - functionText = null, - expr = null, - lt; + tt; - if (tokenStream.match(Tokens.FUNCTION)){ - functionText = tokenStream.token().value; - this._readWhitespace(); - expr = this._expr(true); - functionText += expr; - //START: Horrible hack in case it's an IE filter - if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){ - do { + this._readWhitespace(); - if (this._readWhitespace()){ - functionText += tokenStream.token().value; - } + if (checkStart) { + tokenStream.mustMatch(Tokens.LBRACE); + } - //might be second time in the loop - if (tokenStream.LA(0) == Tokens.COMMA){ - functionText += tokenStream.token().value; - } + this._readWhitespace(); - tokenStream.match(Tokens.IDENT); - functionText += tokenStream.token().value; + try { - tokenStream.match(Tokens.EQUALS); - functionText += tokenStream.token().value; + while (true) { - //functionText += this._term(); - lt = tokenStream.peek(); - while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ - tokenStream.get(); - functionText += tokenStream.token().value; - lt = tokenStream.peek(); + if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())) { + // noop + } else if (this._declaration()) { + if (!tokenStream.match(Tokens.SEMICOLON)) { + break; } - } while(tokenStream.match([Tokens.COMMA, Tokens.S])); - } + } else { + break; + } - //END: Horrible Hack + //if ((!this._margin() && !this._declaration()) || !tokenStream.match(Tokens.SEMICOLON)) { + // break; + //} + this._readWhitespace(); + } - tokenStream.match(Tokens.RPAREN); - functionText += ")"; + tokenStream.mustMatch(Tokens.RBRACE); this._readWhitespace(); - } - - return functionText; - }, - _ie_function: function(){ - - /* (My own extension) - * ie_function - * : IE_FUNCTION S* IDENT '=' term [S* ','? IDENT '=' term]+ ')' S* - * ; - */ - - var tokenStream = this._tokenStream, - functionText = null, - expr = null, - lt; - - //IE function can begin like a regular function, too - if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){ - functionText = tokenStream.token().value; + } catch (ex) { + if (ex instanceof SyntaxError && !this.options.strict) { - do { + // fire error event + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); - if (this._readWhitespace()){ - functionText += tokenStream.token().value; + // see if there's another declaration + tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]); + if (tt === Tokens.SEMICOLON) { + // if there's a semicolon, then there might be another declaration + this._readDeclarations(false, readMargins); + } else if (tt !== Tokens.RBRACE) { + // if there's a right brace, the rule is finished so don't do anything + // otherwise, rethrow the error because it wasn't handled properly + throw ex; } - //might be second time in the loop - if (tokenStream.LA(0) == Tokens.COMMA){ - functionText += tokenStream.token().value; - } + } else { + // not a syntax error, rethrow it + throw ex; + } + } - tokenStream.match(Tokens.IDENT); - functionText += tokenStream.token().value; + }, - tokenStream.match(Tokens.EQUALS); - functionText += tokenStream.token().value; + /** + * In some cases, you can end up with two white space tokens in a + * row. Instead of making a change in every function that looks for + * white space, this function is used to match as much white space + * as necessary. + * @method _readWhitespace + * @return {String} The white space if found, empty string if not. + * @private + */ + _readWhitespace: function() { - //functionText += this._term(); - lt = tokenStream.peek(); - while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ - tokenStream.get(); - functionText += tokenStream.token().value; - lt = tokenStream.peek(); - } - } while(tokenStream.match([Tokens.COMMA, Tokens.S])); + var tokenStream = this._tokenStream, + ws = ""; - tokenStream.match(Tokens.RPAREN); - functionText += ")"; - this._readWhitespace(); + while (tokenStream.match(Tokens.S)) { + ws += tokenStream.token().value; } - return functionText; + return ws; }, - _hexcolor: function(){ - /* - * There is a constraint on the color that it must - * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F]) - * after the "#"; e.g., "#000" is OK, but "#abcd" is not. - * - * hexcolor - * : HASH S* - * ; - */ - - var tokenStream = this._tokenStream, - token = null, - color; - - if(tokenStream.match(Tokens.HASH)){ - //need to do some validation here + /** + * Throws an error when an unexpected token is found. + * @param {Object} token The token that was found. + * @method _unexpectedToken + * @return {void} + * @private + */ + _unexpectedToken: function(token) { + throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + }, - token = tokenStream.token(); - color = token.value; - if (!/#[a-f0-9]{3,6}/i.test(color)){ - throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); - } - this._readWhitespace(); + /** + * Helper method used for parsing subparts of a style sheet. + * @return {void} + * @method _verifyEnd + * @private + */ + _verifyEnd: function() { + if (this._tokenStream.LA(1) !== Tokens.EOF) { + this._unexpectedToken(this._tokenStream.LT(1)); } + }, - return token; + //----------------------------------------------------------------- + // Validation methods + //----------------------------------------------------------------- + _validateProperty: function(property, value) { + Validation.validate(property, value); }, //----------------------------------------------------------------- - // Animations methods + // Parsing methods //----------------------------------------------------------------- - _keyframes: function(){ + parse: function(input) { + this._tokenStream = new TokenStream(input, Tokens); + this._stylesheet(); + }, - /* - * keyframes: - * : KEYFRAMES_SYM S* keyframe_name S* '{' S* keyframe_rule* '}' { - * ; - */ - var tokenStream = this._tokenStream, - token, - tt, - name, - prefix = ""; + parseStyleSheet: function(input) { + // just passthrough + return this.parse(input); + }, - tokenStream.mustMatch(Tokens.KEYFRAMES_SYM); - token = tokenStream.token(); - if (/^@\-([^\-]+)\-/.test(token.value)) { - prefix = RegExp.$1; - } + parseMediaQuery: function(input) { + this._tokenStream = new TokenStream(input, Tokens); + var result = this._media_query(); - this._readWhitespace(); - name = this._keyframe_name(); + // if there's anything more, then it's an invalid selector + this._verifyEnd(); - this._readWhitespace(); - tokenStream.mustMatch(Tokens.LBRACE); + // otherwise return result + return result; + }, - this.fire({ - type: "startkeyframes", - name: name, - prefix: prefix, - line: token.startLine, - col: token.startCol - }); + /** + * Parses a property value (everything after the semicolon). + * @return {parserlib.css.PropertyValue} The property value. + * @throws parserlib.util.SyntaxError If an unexpected token is found. + * @method parserPropertyValue + */ + parsePropertyValue: function(input) { + this._tokenStream = new TokenStream(input, Tokens); this._readWhitespace(); - tt = tokenStream.peek(); - - //check for key - while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) { - this._keyframe_rule(); - this._readWhitespace(); - tt = tokenStream.peek(); - } - this.fire({ - type: "endkeyframes", - name: name, - prefix: prefix, - line: token.startLine, - col: token.startCol - }); + var result = this._expr(); + // okay to have a trailing white space this._readWhitespace(); - tokenStream.mustMatch(Tokens.RBRACE); - - }, - - _keyframe_name: function(){ - - /* - * keyframe_name: - * : IDENT - * | STRING - * ; - */ - var tokenStream = this._tokenStream, - token; - - tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); - return SyntaxUnit.fromToken(tokenStream.token()); - }, - - _keyframe_rule: function(){ - - /* - * keyframe_rule: - * : key_list S* - * '{' S* declaration [ ';' S* declaration ]* '}' S* - * ; - */ - var tokenStream = this._tokenStream, - token, - keyList = this._key_list(); - - this.fire({ - type: "startkeyframerule", - keys: keyList, - line: keyList[0].line, - col: keyList[0].col - }); - - this._readDeclarations(true); - this.fire({ - type: "endkeyframerule", - keys: keyList, - line: keyList[0].line, - col: keyList[0].col - }); + // if there's anything more, then it's an invalid selector + this._verifyEnd(); + // otherwise return result + return result; }, - _key_list: function(){ + /** + * Parses a complete CSS rule, including selectors and + * properties. + * @param {String} input The text to parser. + * @return {Boolean} True if the parse completed successfully, false if not. + * @method parseRule + */ + parseRule: function(input) { + this._tokenStream = new TokenStream(input, Tokens); - /* - * key_list: - * : key [ S* ',' S* key]* - * ; - */ - var tokenStream = this._tokenStream, - token, - key, - keyList = []; + // skip any leading white space + this._readWhitespace(); - //must be least one key - keyList.push(this._key()); + var result = this._ruleset(); + // skip any trailing white space this._readWhitespace(); - while(tokenStream.match(Tokens.COMMA)){ - this._readWhitespace(); - keyList.push(this._key()); - this._readWhitespace(); - } + // if there's anything more, then it's an invalid selector + this._verifyEnd(); - return keyList; + // otherwise return result + return result; }, - _key: function(){ - /* - * There is a restriction that IDENT can be only "from" or "to". - * - * key - * : PERCENTAGE - * | IDENT - * ; - */ - - var tokenStream = this._tokenStream, - token; + /** + * Parses a single CSS selector (no comma) + * @param {String} input The text to parse as a CSS selector. + * @return {Selector} An object representing the selector. + * @throws parserlib.util.SyntaxError If an unexpected token is found. + * @method parseSelector + */ + parseSelector: function(input) { - if (tokenStream.match(Tokens.PERCENTAGE)){ - return SyntaxUnit.fromToken(tokenStream.token()); - } else if (tokenStream.match(Tokens.IDENT)){ - token = tokenStream.token(); + this._tokenStream = new TokenStream(input, Tokens); - if (/from|to/i.test(token.value)){ - return SyntaxUnit.fromToken(token); - } + // skip any leading white space + this._readWhitespace(); - tokenStream.unget(); - } + var result = this._selector(); - //if it gets here, there wasn't a valid token, so time to explode - this._unexpectedToken(tokenStream.LT(1)); - }, + // skip any trailing white space + this._readWhitespace(); - //----------------------------------------------------------------- - // Helper methods - //----------------------------------------------------------------- + // if there's anything more, then it's an invalid selector + this._verifyEnd(); - /** - * Not part of CSS grammar, but useful for skipping over - * combination of white space and HTML-style comments. - * @return {void} - * @method _skipCruft - * @private - */ - _skipCruft: function(){ - while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){ - //noop - } + // otherwise return result + return result; }, /** - * Not part of CSS grammar, but this pattern occurs frequently - * in the official CSS grammar. Split out here to eliminate - * duplicate code. - * @param {Boolean} checkStart Indicates if the rule should check - * for the left brace at the beginning. - * @param {Boolean} readMargins Indicates if the rule should check - * for margin patterns. + * Parses an HTML style attribute: a set of CSS declarations + * separated by semicolons. + * @param {String} input The text to parse as a style attribute * @return {void} - * @method _readDeclarations - * @private + * @method parseStyleAttribute */ - _readDeclarations: function(checkStart, readMargins){ - /* - * Reads the pattern - * S* '{' S* declaration [ ';' S* declaration ]* '}' S* - * or - * S* '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* - * Note that this is how it is described in CSS3 Paged Media, but is actually incorrect. - * A semicolon is only necessary following a declaration is there's another declaration - * or margin afterwards. - */ - var tokenStream = this._tokenStream, - tt; - + parseStyleAttribute: function(input) { + input += "}"; // for error recovery in _readDeclarations() + this._tokenStream = new TokenStream(input, Tokens); + this._readDeclarations(); + } + }; - this._readWhitespace(); + // copy over onto prototype + for (prop in additions) { + if (Object.prototype.hasOwnProperty.call(additions, prop)) { + proto[prop] = additions[prop]; + } + } - if (checkStart){ - tokenStream.mustMatch(Tokens.LBRACE); - } + return proto; +}(); - this._readWhitespace(); - try { +/* +nth + : S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? | + ['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S* + ; +*/ - while(true){ +},{"../util/EventTarget":23,"../util/SyntaxError":25,"../util/SyntaxUnit":26,"./Combinator":2,"./MediaFeature":4,"./MediaQuery":5,"./PropertyName":8,"./PropertyValue":9,"./PropertyValuePart":11,"./Selector":13,"./SelectorPart":14,"./SelectorSubPart":15,"./TokenStream":17,"./Tokens":18,"./Validation":19}],7:[function(require,module,exports){ +/* exported Properties */ + +"use strict"; + +var Properties = module.exports = { + __proto__: null, + + // A + "align-items" : "flex-start | flex-end | center | baseline | stretch", + "align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", + "align-self" : "auto | flex-start | flex-end | center | baseline | stretch", + "all" : "initial | inherit | unset", + "-webkit-align-items" : "flex-start | flex-end | center | baseline | stretch", + "-webkit-align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", + "-webkit-align-self" : "auto | flex-start | flex-end | center | baseline | stretch", + "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | | ", + "alignment-baseline" : "auto | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", + "animation" : 1, + "animation-delay" : "
    - \ No newline at end of file + + + +{{-- comment --}} + +@if ( + {{-- comment --}} + /*block comment*/ + #another comment + $user->type == 1 + // c comment + /* comment*/ +) + # not a comment
    +@endif diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 166cacd210e..109a419e76a 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -152,8 +152,8 @@ var supportedModes = { Pascal: ["pas|p"], Perl: ["pl|pm"], pgSQL: ["pgsql"], - PHP: ["php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"], PHP_Laravel_blade: ["blade.php"], + PHP: ["php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"], Pig: ["pig"], Powershell: ["ps1"], Praat: ["praat|praatscript|psc|proc"], diff --git a/lib/ace/mode/_test/tokens_php_laravel_blade.json b/lib/ace/mode/_test/tokens_php_laravel_blade.json index 70b0ce0d7c3..4e03df37604 100644 --- a/lib/ace/mode/_test/tokens_php_laravel_blade.json +++ b/lib/ace/mode/_test/tokens_php_laravel_blade.json @@ -402,8 +402,7 @@ ["parenthesis.end.blade",")"] ],[ "start", - ["text.xml"," "], - ["punctuation.definition.comment.blade","// The application is in the local environment..."] + ["text.xml"," // The application is in the local environment..."] ],[ "start", ["text.xml"," "], @@ -416,8 +415,7 @@ ["parenthesis.end.blade",")"] ],[ "start", - ["text.xml"," "], - ["punctuation.definition.comment.blade","// The application is in the testing environment..."] + ["text.xml"," // The application is in the testing environment..."] ],[ "start", ["text.xml"," "], @@ -425,8 +423,7 @@ ["keyword.control.blade","else"] ],[ "start", - ["text.xml"," "], - ["punctuation.definition.comment.blade","// The application is not in the local or testing environment..."] + ["text.xml"," // The application is not in the local or testing environment..."] ],[ "start", ["text.xml"," "], @@ -471,4 +468,78 @@ ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start" +],[ + "start", + ["punctuation.definition.comment.begin.blade","{{--"], + ["comment.block.blade"," comment "], + ["punctuation.definition.comment.end.blade","--}}"] +],[ + "start" +],[ + "parenthesis.begin.blade", + ["directive.declaration.blade","@"], + ["keyword.control.blade","if"], + ["text.xml"," "], + ["parenthesis.begin.blade","("] +],[ + "parenthesis.begin.blade", + ["source.blade"," "], + ["punctuation.definition.comment.begin.blade","{{--"], + ["comment.block.blade"," comment "], + ["punctuation.definition.comment.end.blade","--}}"] +],[ + "parenthesis.begin.blade", + ["source.blade"," "], + ["punctuation.definition.comment.begin.php","/*"], + ["comment.block.blade","block comment"], + ["punctuation.definition.comment.end.php","*/"] +],[ + "parenthesis.begin.blade", + ["source.blade"," "], + ["punctuation.definition.comment.blade","#another comment"] +],[ + "parenthesis.begin.blade", + ["source.blade"," "], + ["variable.blade","$user"], + ["keyword.operator.blade","->"], + ["constant.other.property.blade","type"], + ["source.blade"," "], + ["keyword.operator.blade","=="], + ["source.blade"," 1"] +],[ + "parenthesis.begin.blade", + ["source.blade"," "], + ["punctuation.definition.comment.blade","// c comment"] +],[ + "parenthesis.begin.blade", + ["source.blade"," "], + ["punctuation.definition.comment.begin.php","/*"], + ["comment.block.blade"," comment"], + ["punctuation.definition.comment.end.php","*/"] +],[ + "start", + ["parenthesis.end.blade",")"] +],[ + "start", + ["text.xml"," # not a comment "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"#//x\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["directive.declaration.blade","@"], + ["keyword.control.blade","endif"] +],[ + "start" ]] \ No newline at end of file diff --git a/lib/ace/mode/php_laravel_blade_highlight_rules.js b/lib/ace/mode/php_laravel_blade_highlight_rules.js index b5c6e63db0c..4d01a9b98ca 100644 --- a/lib/ace/mode/php_laravel_blade_highlight_rules.js +++ b/lib/ace/mode/php_laravel_blade_highlight_rules.js @@ -39,16 +39,17 @@ var PHPLaravelBladeHighlightRules = function() { var bladeRules = { start: [{ - include: "comments" + include: "bladeComments" }, { include: "directives" }, { include: "parenthesis" }], comments: [{ + include: "bladeComments" + }, { token: "punctuation.definition.comment.blade", - regex: "(\\/\\/(.)*)|(\\#(.)*)", - next: "pop" + regex: "(\\/\\/(.)*)|(\\#(.)*)" }, { token: "punctuation.definition.comment.begin.php", regex: "(?:\\/\\*)", @@ -59,7 +60,8 @@ var PHPLaravelBladeHighlightRules = function() { }, { defaultToken: "comment.block.blade" }] - }, { + }], + bladeComments: [{ token: "punctuation.definition.comment.begin.blade", regex: "(?:\\{\\{\\-\\-)", push: [{ @@ -85,6 +87,8 @@ var PHPLaravelBladeHighlightRules = function() { include: "lang" }, { include: "parenthesis" + }, { + include: "comments" }, { defaultToken: "source.blade" }] @@ -107,6 +111,8 @@ var PHPLaravelBladeHighlightRules = function() { include: "strings" }, { include: "variables" + }, { + include: "comments" }, { defaultToken: "source.blade" }] From e707ae21d5eb611bed1d13105f82e78abb75e6be Mon Sep 17 00:00:00 2001 From: zeng_j Date: Sat, 2 Apr 2022 16:10:21 +0800 Subject: [PATCH 0500/1293] snippets tooltip display more friendly --- lib/ace/ext/language_tools.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/ace/ext/language_tools.js b/lib/ace/ext/language_tools.js index 2cbeea45a27..371fcf29d43 100644 --- a/lib/ace/ext/language_tools.js +++ b/lib/ace/ext/language_tools.js @@ -49,6 +49,13 @@ var keyWordCompleter = { } }; +var transformSnippetTooltip = function(str) { + var record = {} + return str.replace(/\${(\d+)(:(.*?))?}/g, function(_, p1, p2, p3) { + return (record[p1] = p3 || ''); + }).replace(/\$(\d+?)/g, (_, p1) => record[p1]) +} + var snippetCompleter = { getCompletions: function(editor, session, pos, prefix, callback) { var scopes = []; @@ -83,7 +90,7 @@ var snippetCompleter = { if (item.type == "snippet" && !item.docHTML) { item.docHTML = [ "", lang.escapeHTML(item.caption), "", "
    ", - lang.escapeHTML(item.snippet) + lang.escapeHTML(transformSnippetTooltip(item.snippet)) ].join(""); } } From b78d77240e1909b9d91fcd2ac35a4c17af05f56b Mon Sep 17 00:00:00 2001 From: zeng_j Date: Fri, 8 Apr 2022 10:06:53 +0800 Subject: [PATCH 0501/1293] fix: Modify syntax --- lib/ace/ext/language_tools.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/ace/ext/language_tools.js b/lib/ace/ext/language_tools.js index 371fcf29d43..4ba2e34c5bf 100644 --- a/lib/ace/ext/language_tools.js +++ b/lib/ace/ext/language_tools.js @@ -50,10 +50,12 @@ var keyWordCompleter = { }; var transformSnippetTooltip = function(str) { - var record = {} + var record = {}; return str.replace(/\${(\d+)(:(.*?))?}/g, function(_, p1, p2, p3) { return (record[p1] = p3 || ''); - }).replace(/\$(\d+?)/g, (_, p1) => record[p1]) + }).replace(/\$(\d+?)/g, function (_, p1) { + return record[p1]; + }) } var snippetCompleter = { From 808ae91acd2bf78483e216154afa1a56c45ccdfb Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 11 Apr 2022 18:32:36 +0400 Subject: [PATCH 0502/1293] fix lua block comments --- lib/ace/mode/lua.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/lua.js b/lib/ace/mode/lua.js index 32faf8e6b39..07fbeaee26d 100644 --- a/lib/ace/mode/lua.js +++ b/lib/ace/mode/lua.js @@ -49,7 +49,7 @@ oop.inherits(Mode, TextMode); (function() { this.lineCommentStart = "--"; - this.blockComment = {start: "--[", end: "]--"}; + this.blockComment = {start: "--[[", end: "--]]"}; var indentKeywords = { "function": 1, From 62d2d1ad1f942bd738adadd90f8afb29050b8465 Mon Sep 17 00:00:00 2001 From: zeng_j Date: Fri, 15 Apr 2022 11:57:35 +0800 Subject: [PATCH 0503/1293] style: code eslint --- lib/ace/ext/language_tools.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/ext/language_tools.js b/lib/ace/ext/language_tools.js index 4ba2e34c5bf..396342ccade 100644 --- a/lib/ace/ext/language_tools.js +++ b/lib/ace/ext/language_tools.js @@ -55,8 +55,8 @@ var transformSnippetTooltip = function(str) { return (record[p1] = p3 || ''); }).replace(/\$(\d+?)/g, function (_, p1) { return record[p1]; - }) -} + }); +}; var snippetCompleter = { getCompletions: function(editor, session, pos, prefix, callback) { From e91705e41cb32deab6d827386b1c3905d4e007c2 Mon Sep 17 00:00:00 2001 From: Sullivan Ford Date: Thu, 5 May 2022 12:06:37 +0100 Subject: [PATCH 0504/1293] Fix indentation and add extra snippets --- lib/ace/snippets/robot.snippets | 90 ++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 25 deletions(-) diff --git a/lib/ace/snippets/robot.snippets b/lib/ace/snippets/robot.snippets index fe5c23a7404..2cb13946ec1 100644 --- a/lib/ace/snippets/robot.snippets +++ b/lib/ace/snippets/robot.snippets @@ -1,29 +1,69 @@ -snippet settings -description Settings section -scope robot - *** Settings *** - ${1:Library} ${2} -snippet keywords -description Keywords section -scope robot - *** Keywords *** -snippet for -description For Loop -scope robot - FOR ${1:\$\{item\}} IN RANGE ${2:10} - Log ${1:\$\{item\}} - END +# scope: robot +### Sections +snippet settingssection +description *** Settings *** section + *** Settings *** + Library ${1} + +snippet keywordssection +description *** Keywords *** section + *** Keywords *** + ${1:Keyword Name} + [Arguments] \${${2:Example Arg 1}} + +snippet testcasessection +description *** Test Cases *** section + *** Test Cases *** + ${1:First Test Case} + ${2:Log Example Arg} + +snippet variablessection +description *** Variables *** section + *** Variables *** + \${${1:Variable Name}}= ${2:Variable Value} + +### Helpful keywords +snippet testcase +description A test case + ${1:Test Case Name} + ${2:Log Example log message} + +snippet keyword +description A keyword + ${1:Example Keyword} + [Arguments] \${${2:Example Arg 1}} + +### Built Ins +snippet forinr +description For In Range Loop + FOR \${${1:Index}} IN RANGE \${${2:10}} + Log \${${1:Index}} + END + +snippet forin +description For In Loop + FOR \${${1:Item}} IN @{${2:List Variable}} + Log \${${1:Item}} + END + snippet if description If Statement -scope robot - IF ${1:condition} - ${2:Do something} - END + IF ${1:condition} + ${2:Do something} + END + +snippet else +description If Statement + IF ${1:Condition} + ${2:Do something} + ELSE + ${3:Otherwise do this} + END + snippet elif description Else-If Statement -scope robot - IF ${1:condition} - ${2:Do something} - ELSE IF ${3:condition} - ${4:Do something else} - END + IF ${1:Condition 1} + ${2:Do something} + ELSE IF ${3:Condition 2} + ${4:Do something else} + END From 461c020561064cc18bce044aea407c927c976d84 Mon Sep 17 00:00:00 2001 From: Sullivan Ford Date: Thu, 5 May 2022 12:16:37 +0100 Subject: [PATCH 0505/1293] Fix keywords highlighting in the middle of words --- lib/ace/mode/robot_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/robot_highlight_rules.js b/lib/ace/mode/robot_highlight_rules.js index 0059de27210..785d913601e 100644 --- a/lib/ace/mode/robot_highlight_rules.js +++ b/lib/ace/mode/robot_highlight_rules.js @@ -127,7 +127,7 @@ var RobotHighlightRules = function() { regex: /\b[0-9]+(?:\.[0-9]+)?\b/ }, { token: "keyword", - regex: /\s{2,}(for|in range|in|end|else if|if|else|with name)/, + regex: /\s{2,}(for|in range|in|end|else if|if|else|with name)(\s{2,}|$)/, caseInsensitive: true }, { token: "storage.type.function", From 843c017298270f401060486b82644eba3561a5c2 Mon Sep 17 00:00:00 2001 From: Sullivan Ford Date: Thu, 5 May 2022 16:50:48 +0100 Subject: [PATCH 0506/1293] Remove unnecessary escape chars --- lib/ace/mode/robot_highlight_rules.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/mode/robot_highlight_rules.js b/lib/ace/mode/robot_highlight_rules.js index 785d913601e..ed274de7dec 100644 --- a/lib/ace/mode/robot_highlight_rules.js +++ b/lib/ace/mode/robot_highlight_rules.js @@ -114,7 +114,7 @@ var RobotHighlightRules = function() { }] }, { token: "keyword.control.robot", - regex: /^[^\s\t\*$\|]+|(?=^\|)\s+[^\s\t\*$\|]+/, + regex: /^[^\s\t*$|]+|(?=^\|)\s+[^\s\t*$|]+/, push: [{ token: "keyword.control.robot", regex: /(?=\s{2})|\t|$|\s+(?=\|)/, @@ -131,7 +131,7 @@ var RobotHighlightRules = function() { caseInsensitive: true }, { token: "storage.type.function", - regex: /^(?:\s{2,}\s+)[^ \t\*$@&%\[.\|]+/, + regex: /^(?:\s{2,}\s+)[^ \t*$@&%[.|]+/, push: [{ token: "storage.type.function", regex: /(?=\s{2})|\t|$|\s+(?=\|)/, From e8df6f2887f4b7a25be12c6477ce4eabd6992dc8 Mon Sep 17 00:00:00 2001 From: Andrei Nestser Date: Mon, 9 May 2022 12:58:23 +0200 Subject: [PATCH 0507/1293] Added GitHub issues templates --- .github/ISSUE_TEMPLATE/bug-report.yml | 67 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 6 ++ .github/ISSUE_TEMPLATE/documentation.yml | 23 ++++++++ .github/ISSUE_TEMPLATE/feature-request.yml | 53 +++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/documentation.yml create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 00000000000..29f7f0b18ee --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,67 @@ +--- +name: "🐞 Bug Report" +description: Report a bug +title: "(module name): (short issue description)" +labels: [bug, needs-triage] +assignees: [] +body: + - type: textarea + id: description + attributes: + label: Describe the bug + description: What is the problem? A clear and concise description of the bug. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected Behavior + description: | + What did you expect to happen? + validations: + required: true + - type: textarea + id: current + attributes: + label: Current Behavior + description: | + What actually happened? + + Please include full errors, uncaught exceptions, stack traces, and relevant logs. + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Reproduction Steps + description: | + Provide a self-contained, concise snippet of code that can be used to reproduce the issue. + For more complex issues provide a repo with the smallest sample that reproduces the bug. + + Avoid including business logic or unrelated code, it makes diagnosis more difficult. + validations: + required: true + - type: textarea + id: solution + attributes: + label: Possible Solution + description: | + Suggest a fix/reason for the bug + validations: + required: false + - type: textarea + id: context + attributes: + label: Additional Information/Context + description: | + Anything else that might be relevant for troubleshooting this bug. Providing context helps us come up with a solution that is most useful in the real world. + validations: + required: false + + - type: input + id: ace-version + attributes: + label: Ace Version + description: Ace editor version + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..5b43894a794 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,6 @@ +--- +blank_issues_enabled: false +contact_links: + - name: 🤔 General Question + url: https://github.com/ajaxorg/ace/discussions/categories/q-a + about: Please ask and answer questions as a discussion thread diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml new file mode 100644 index 00000000000..29361a78480 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -0,0 +1,23 @@ +--- +name: "📕 Documentation Issue" +description: Report an issue in the documentation +title: "(short issue description)" +labels: [documentation, needs-triage] +assignees: [] +body: + - type: textarea + id: description + attributes: + label: Describe the issue + description: A clear and concise description of the issue. + validations: + required: true + + - type: textarea + id: links + attributes: + label: Links + description: | + Include links to affected documentation page(s). + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 00000000000..40778b549b3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,53 @@ +--- +name: 🚀 Feature Request +description: Suggest an idea for this project +title: "(short issue description)" +labels: [feature-request, needs-triage] +assignees: [] +body: + - type: textarea + id: description + attributes: + label: Describe the feature + description: A clear and concise description of the feature you are proposing. + validations: + required: true + - type: textarea + id: use-case + attributes: + label: Use Case + description: | + Why do you need this feature? For example: "I'm always frustrated when..." + validations: + required: true + - type: textarea + id: solution + attributes: + label: Proposed Solution + description: | + Suggest how to implement the addition or change. Please include prototype/workaround/sketch/reference implementation. + validations: + required: false + - type: textarea + id: other + attributes: + label: Other Information + description: | + Any alternative solutions or features you considered, a more detailed explanation, stack traces, related issues, links for context, etc. + validations: + required: false + - type: checkboxes + id: ack + attributes: + label: Acknowledgements + options: + - label: I may be able to implement this feature request + required: false + - label: This feature might incur a breaking change + required: false + - type: input + id: ace-version + attributes: + label: ACE version used + validations: + required: true From 970bd7569b2a6b22fef8370002fa4816a7aa977a Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 7 Jan 2022 14:56:03 +0400 Subject: [PATCH 0508/1293] improve mouse wheel handling --- lib/ace/lib/event.js | 64 +++++++++++------------------ lib/ace/mouse/mouse_handler_test.js | 46 +++++++++++++++++---- lib/ace/test/all_browser.js | 1 + 3 files changed, 61 insertions(+), 50 deletions(-) diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js index 4f33c6cd636..21adebebd98 100644 --- a/lib/ace/lib/event.js +++ b/lib/ace/lib/event.js @@ -126,47 +126,29 @@ exports.capture = function(el, eventHandler, releaseCaptureHandler) { }; exports.addMouseWheelListener = function(el, callback, destroyer) { - if ("onmousewheel" in el) { - addListener(el, "mousewheel", function(e) { - var factor = 8; - if (e.wheelDeltaX !== undefined) { - e.wheelX = -e.wheelDeltaX / factor; - e.wheelY = -e.wheelDeltaY / factor; - } else { - e.wheelX = 0; - e.wheelY = -e.wheelDelta / factor; - } - callback(e); - }, destroyer); - } else if ("onwheel" in el) { - addListener(el, "wheel", function(e) { - var factor = 0.35; - switch (e.deltaMode) { - case e.DOM_DELTA_PIXEL: - e.wheelX = e.deltaX * factor || 0; - e.wheelY = e.deltaY * factor || 0; - break; - case e.DOM_DELTA_LINE: - case e.DOM_DELTA_PAGE: - e.wheelX = (e.deltaX || 0) * 5; - e.wheelY = (e.deltaY || 0) * 5; - break; - } - - callback(e); - }, destroyer); - } else { - addListener(el, "DOMMouseScroll", function(e) { - if (e.axis && e.axis == e.HORIZONTAL_AXIS) { - e.wheelX = (e.detail || 0) * 5; - e.wheelY = 0; - } else { - e.wheelX = 0; - e.wheelY = (e.detail || 0) * 5; - } - callback(e); - }, destroyer); - } + addListener(el, "wheel", function(e) { + var factor = 0.15; + // workaround for firefox changing deltaMode based on which property is accessed first + var deltaX = e.deltaX || 0; + var deltaY = e.deltaY || 0; + switch (e.deltaMode) { + case e.DOM_DELTA_PIXEL: + e.wheelX = deltaX * factor; + e.wheelY = deltaY * factor; + break; + case e.DOM_DELTA_LINE: + var linePixels = 15; + e.wheelX = deltaX * linePixels; + e.wheelY = deltaY * linePixels; + break; + case e.DOM_DELTA_PAGE: + var pagePixels = 150; + e.wheelX = deltaX * pagePixels; + e.wheelY = deltaY * pagePixels; + break; + } + callback(e); + }, destroyer); }; exports.addMultiMouseDownListener = function(elements, timeouts, eventHandler, callbackName, destroyer) { diff --git a/lib/ace/mouse/mouse_handler_test.js b/lib/ace/mouse/mouse_handler_test.js index 2a3f6685046..d0209d3ad7b 100644 --- a/lib/ace/mouse/mouse_handler_test.js +++ b/lib/ace/mouse/mouse_handler_test.js @@ -44,7 +44,7 @@ var VirtualRenderer = require("../virtual_renderer").VirtualRenderer; var assert = require("../test/assertions"); var MouseEvent = function(type, opts){ var e = document.createEvent("MouseEvents"); - e.initMouseEvent(/click|DOM/.test(type) ? type : "mouse" + type, + e.initMouseEvent(/click|wheel/.test(type) ? type : "mouse" + type, true, true, window, opts.detail, opts.x, opts.y, opts.x, opts.y, @@ -52,6 +52,17 @@ var MouseEvent = function(type, opts){ opts.button || 0, opts.relatedTarget); return e; }; +var WheelEvent = function(opts) { + var e = new MouseEvent("wheel", opts); + e.DOM_DELTA_PIXEL = 0; + e.DOM_DELTA_LINE = 1; + e.DOM_DELTA_PAGE = 2; + e.deltaMode = e["DOM_DELTA_" + opts.mode.toUpperCase()]; + e.deltaX = opts.x || 0; + e.deltaY = opts.y || 0; + return e; +}; + function sendTouchEvent(type, opts, editor) { var e = new window.Event("touch" + type, {bubbles: true, cancelable: true}); Object.defineProperties(e, Object.getOwnPropertyDescriptors(opts)); @@ -162,18 +173,35 @@ module.exports = { assert.ok(/ace_gutter-active-line/.test(lines.cells[1].element.className)); assert.equal(lines.cells[1].element.textContent, "51"); - var e; - if ("onmousewheel" in toggler) { - e = MouseEvent("wheel", {}); - e.wheelDelta = -500; - } - else { - e = MouseEvent("DOMMouseScroll", {detail: 100}); - } + // wheel event on toggler + var e = WheelEvent({mode: "pixel", y: 100}); toggler.dispatchEvent(e); editor.renderer.$loop._flush(); assert.ok(parseInt(lines.cells[0].element.textContent) > 1); }, + "test: wheel" : function() { + var editor = this.editor; + var lines = editor.renderer.$gutterLayer.$lines; + editor.setValue("\n".repeat(100), -1); + editor.renderer.$loop._flush(); + + assert.ok(parseInt(lines.cells[0].element.textContent) == 1); + + var e = WheelEvent({mode: "line", y: 2}); + editor.container.dispatchEvent(e); + editor.renderer.$loop._flush(); + assert.ok(parseInt(lines.cells[0].element.textContent) > 1); + + e = WheelEvent({mode: "line", y: -2}); + editor.container.dispatchEvent(e); + editor.renderer.$loop._flush(); + assert.ok(parseInt(lines.cells[0].element.textContent) == 1); + + e = WheelEvent({mode: "page", y: 1}); + editor.container.dispatchEvent(e); + editor.renderer.$loop._flush(); + assert.ok(parseInt(lines.cells[0].element.textContent) > 10); + }, "test: touch" : function(done) { var editor = this.editor; diff --git a/lib/ace/test/all_browser.js b/lib/ace/test/all_browser.js index 8a6e2b1bb50..e790bab570f 100644 --- a/lib/ace/test/all_browser.js +++ b/lib/ace/test/all_browser.js @@ -29,6 +29,7 @@ var testNames = [ "ace/ext/whitespace_test", "ace/ext/error_marker_test", "ace/ext/code_lens_test", + "ace/ext/beautify_test", "ace/incremental_search_test", "ace/keyboard/emacs_test", "ace/keyboard/textinput_test", From 189ccfb2122a8a1f84a5d0eee21d88a07d561b75 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Mon, 9 May 2022 14:46:01 +0200 Subject: [PATCH 0509/1293] chore: Added standard-version to be used to generate ChangeLog from conventional commits --- ChangeLog.txt => CHANGELOG.md | 443 +++++++++++++++++++--------------- Makefile.dryice.js | 2 +- package.json | 16 +- tool/release.sh | 4 - 4 files changed, 255 insertions(+), 210 deletions(-) rename ChangeLog.txt => CHANGELOG.md (57%) diff --git a/ChangeLog.txt b/CHANGELOG.md similarity index 57% rename from ChangeLog.txt rename to CHANGELOG.md index 2819a6014d0..664b820abc4 100644 --- a/ChangeLog.txt +++ b/CHANGELOG.md @@ -1,225 +1,250 @@ 2022.01.26 Version 1.4.14 -* update vim mode -* remove slow regex in beautify extension -2021.09.30 Version 1.4.13 -* added useStrictCSP global option to use in environments where dynamic style creation is disabled +- update vim mode +- remove slow regex in beautify extension + + 2021.09.30 Version 1.4.13 + +- added useStrictCSP global option to use in environments where dynamic style creation is disabled see demo/csp.html for an example of a page which loads external css files instead of generating styles with javascript -* updated vim mode, added support for gqq command +- updated vim mode, added support for gqq command + + 2020.07.06 Version 1.4.12 + +- removed unused es5-shim +- imporved ruby and vbscript highlighting and folding +- workaround for double space being converted to dot on mobile keyboards + + 2020.04.15 Version 1.4.10 + +- added workaround for chrome bug causing memory leak after calling editor.destroy +- added code folding support for vbscript mode + + 2020.04.01 Version 1.4.9 + +- added option to disable autoindent +- added new language modes +- fixed backspace not working with some mobile keyboards + + 2020.01.14 Version 1.4.8 + +- highlight both matched braces, and highlight unmatched brace in red +- improve snippet manager +- compatibility with webpack file-loader v5 +- improve vim mode + + 2019.10.17 Version 1.4.7 + +- add placeholder option + + 2019.09.08 Version 1.4.6 + +- restore native behavior of ctrl-p on mac (jumptomatching command is moved to cmd-\) +- improve snippet manager +- fix backspace handling on mobile -2020.07.06 Version 1.4.12 -* removed unused es5-shim -* imporved ruby and vbscript highlighting and folding -* workaround for double space being converted to dot on mobile keyboards + 2019.06.17 Version 1.4.5 -2020.04.15 Version 1.4.10 -* added workaround for chrome bug causing memory leak after calling editor.destroy -* added code folding support for vbscript mode +- improve scrolling and selection on mobile +- improve type definitions -2020.04.01 Version 1.4.9 -* added option to disable autoindent -* added new language modes -* fixed backspace not working with some mobile keyboards + 2019.04.24 Version 1.4.4 -2020.01.14 Version 1.4.8 -* highlight both matched braces, and highlight unmatched brace in red -* improve snippet manager -* compatibility with webpack file-loader v5 -* improve vim mode +- add experimental command prompt +- add chrystal, nim and nginx highlight rules +- fix regression in vim mode on ios -2019.10.17 Version 1.4.7 -* add placeholder option + 2019.02.21 Version 1.4.3 -2019.09.08 Version 1.4.6 -* restore native behavior of ctrl-p on mac (jumptomatching command is moved to cmd-\) -* improve snippet manager -* fix backspace handling on mobile +- add sublime keybindings +- add rtl option +- implement ` and < textobjects in vim mode -2019.06.17 Version 1.4.5 -* improve scrolling and selection on mobile -* improve type definitions + 2018.11.21 Version 1.4.2 -2019.04.24 Version 1.4.4 -* add experimental command prompt -* add chrystal, nim and nginx highlight rules -* fix regression in vim mode on ios +- fix regression in vim mode +- improve keyboard input handling on ipad and IE +- add new syntax highlighters -2019.02.21 Version 1.4.3 -* add sublime keybindings -* add rtl option -* implement ` and < textobjects in vim mode + 2018.08.07 Version 1.4.1 -2018.11.21 Version 1.4.2 -* fix regression in vim mode -* improve keyboard input handling on ipad and IE -* add new syntax highlighters +- fix regression in autocomplete -2018.08.07 Version 1.4.1 -* fix regression in autocomplete + 2018.08.06 Version 1.4.0 -2018.08.06 Version 1.4.0 +- remove usage of innerHTML +- improved handling of textinput for IME and mobile +- add support for relative line numbers +- improve autocompletion popup -* remove usage of innerHTML -* improved handling of textinput for IME and mobile -* add support for relative line numbers -* improve autocompletion popup + 2018.03.26 Version 1.3.3 -2018.03.26 Version 1.3.3 -* fix regession in static-highlight extension -* use css animation for cursor blinking +- fix regession in static-highlight extension +- use css animation for cursor blinking -2018.03.21 Version 1.3.2 -* add experimental support for using ace-builds with webpack + 2018.03.21 Version 1.3.2 -2018.02.11 Version 1.3.1 +- add experimental support for using ace-builds with webpack -* fixed regression with selectionChange event not firing some times -* improved handling of non-ascii characters in vim normal mode + 2018.02.11 Version 1.3.1 -2018.01.31 Version 1.3.0 +- fixed regression with selectionChange event not firing some times +- improved handling of non-ascii characters in vim normal mode -* added copy copyWithEmptySelection option -* improved undoManager -* improved settings_menu plugin -* improved handling of files with very long lines -* fixed bug with scrolling editor out of view in transformed elements + 2018.01.31 Version 1.3.0 -2017.10.17 Version 1.2.9 +- added copy copyWithEmptySelection option +- improved undoManager +- improved settings_menu plugin +- improved handling of files with very long lines +- fixed bug with scrolling editor out of view in transformed elements -* added support for bidirectional text, with monospace font (Alex Shensis) -* added support for emoji 😊 + 2017.10.17 Version 1.2.9 + +- added support for bidirectional text, with monospace font (Alex Shensis) +- added support for emoji 😊 + +- new language modes -* new language modes - Red (Toomas Vooglaid) - CSound (Nathan Whetsell) - JSSM (John Haugeland) -* New Themes +- New Themes + - Dracula (Austin Schwartz) -2017.07.02 Version 1.2.8 -* Fixed small bugs in searchbox and autocompleter + 2017.07.02 Version 1.2.8 + +- Fixed small bugs in searchbox and autocompleter -2017.06.18 Version 1.2.7 + 2017.06.18 Version 1.2.7 -* Added Support for arrow keys on external IPad keyboard (Emanuele Tamponi) -* added match counter to searchbox extension +- Added Support for arrow keys on external IPad keyboard (Emanuele Tamponi) +- added match counter to searchbox extension -- implemented higlighting of multiline strings in yaml mode (Maxim Trushin) -- improved haml syntax highlighter (Andrés Álvarez) +* implemented higlighting of multiline strings in yaml mode (Maxim Trushin) +* improved haml syntax highlighter (Andrés Álvarez) -2016.12.03 Version 1.2.6 + 2016.12.03 Version 1.2.6 -* Fixed IME handling on new Chrome -* Support for php 7 in the syntax checker +- Fixed IME handling on new Chrome +- Support for php 7 in the syntax checker -2016.08.16 Version 1.2.5 + 2016.08.16 Version 1.2.5 -* Fixed regression in noconflict mode +- Fixed regression in noconflict mode -2016.07.27 Version 1.2.4 + 2016.07.27 Version 1.2.4 -* Maintenance release with several new modes and small bugfixes +- Maintenance release with several new modes and small bugfixes -2016.01.17 Version 1.2.3 + 2016.01.17 Version 1.2.3 -* Bugfixes +- Bugfixes - fix memory leak in setSession (Tyler Stalder) - double click not working on linux/mac - -* new language modes +- new language modes + - reStructuredText (Robin Jarry) - NSIS (Jan T. Sott) + 2015.10.28 Version 1.2.1 -2015.10.28 Version 1.2.1 +- new language modes -* new language modes - Swift - JSX -2015.07.11 Version 1.2.0 + 2015.07.11 Version 1.2.0 + +- New Features -* New Features - Indented soft wrap (danyaPostfactum) - Rounded borders on selections -* API Changes - - unified delta types `{start, end, action, lines}` (Alden Daniels https://github.com/ajaxorg/ace/pull/1745) +- API Changes + + - unified delta types `{start, end, action, lines}` (Alden Daniels https://github.com/ajaxorg/ace/pull/1745) - "change" event listeners on session and editor get delta objects directly -* new language modes +- new language modes + - SQLServer (Morgan Yarbrough) - -2015.04.03 Version 1.1.9 + + 2015.04.03 Version 1.1.9 - Small Enhancements and Bugfixes -2014.11.08 Version 1.1.8 + 2014.11.08 Version 1.1.8 -* API Changes +- API Changes - `editor.commands.commandKeyBinding` now contains direct map from keys to commands instead of grouping them by hashid - -* New Features +- New Features - Improved autoindent for html and php modes (Adam Jimenez) - Find All from searchbox (Colton Voege) - -* new language modes +- new language modes + - Elixir, Elm - -2014.09.21 Version 1.1.7 + 2014.09.21 Version 1.1.7 + +- Bugfixes -* Bugfixes - fix several bugs in autocompletion - workaround for inaccurate getBoundingClientRect on chrome 37 -2014.08.17 Version 1.1.6 + 2014.08.17 Version 1.1.6 -* Bugfixes - - fix regression in double tap to highlight +- Bugfixes + - fix regression in double tap to highlight - Improved Latex Mode (Daniel Felder) - -* API Changes +- API Changes + - editor.destroy destroys editor.session too (call editor.setSession(null) to prevent that) -* new language modes - - Praat (José Joaquín Atria) - - Eiffel (Victorien Elvinger) - - G-code (Adam Joseph Cook) - -2014.07.09 Version 1.1.5 +- new language modes + +* Praat (José Joaquín Atria) +* Eiffel (Victorien Elvinger) +* G-code (Adam Joseph Cook) + 2014.07.09 Version 1.1.5 + +- Bugfixes -* Bugfixes - fix regression in autocomplete popup -* new language modes - - gitignore (Devon Carew) - -2014.07.01 Version 1.1.4 +- new language modes + +* gitignore (Devon Carew) + 2014.07.01 Version 1.1.4 + +- New Features -* New Features - Highlight matching tags (Adam Jimenez) - Improved jump to matching command (Adam Jimenez) -* new language modes - - AppleScript (Yaogang Lian) - - Vala +- new language modes + +* AppleScript (Yaogang Lian) +* Vala + + 2014.03.08 Version 1.1.3 -2014.03.08 Version 1.1.3 +- New Features -* New Features - Allow syntax checkers to be loaded from CDN (Derk-Jan Hartman) - Add ColdFusion behavior (Abram Adams) - add showLineNumbers option - Add html syntax checker (danyaPostfactum) - -* new language modes + +- new language modes + - Gherkin (Patrick Nevels) - Smarty -2013.12.02 Version 1.1.2 + 2013.12.02 Version 1.1.2 -* New Features +- New Features - Accessibility Theme for Ace (Peter Xiao) - use snipetManager for expanding emmet snippets - update jshint to 2.1.4 @@ -231,24 +256,26 @@ - add option to merge similar changes in undo history - add scrollPastEnd option - use html5 dragndrop for text dragging (danyaPostfactum) - -* API Changes +- API Changes + - fixed typo in HashHandler commmandManager -* new language modes +- new language modes + - Nix (Zef Hemel) - Protobuf (Zef Hemel) - Soy - Handlebars -2013.06.04 Version 1.1.1 + 2013.06.04 Version 1.1.1 - Improved emacs keybindings (Robert Krahn) - Added markClean, isClean methods to UndoManager (Joonsoo Jeon) - Do not allow `Toggle comments` command to remove spaces from indentation - Softer colors for indent guides in dark themes -* new language modes +- new language modes + - Ada - Assembly_x86 - Cobol @@ -259,9 +286,10 @@ - Twig - Verilog -2013.05.01, Version 1.1.0 + 2013.05.01, Version 1.1.0 + +- API Changes -* API Changes - Default position of the editor container is changed to relative. Add `.ace_editor {position: absolute}` css rule to restore old behavior - Changed default line-height to `normal` to not conflict with bootstrap. Use `line-height: inherit` for old behavior. - Changed marker types accepted by session.addMarker. It now accepts "text"|"line"|"fullLine"|"screenLine" @@ -269,7 +297,8 @@ - Introduced `editor.setOption/getOption/setOptions/getOptions` methods - Introduced positionToIndex, indexToPosition methods -* New Features +- New Features + - Improved emacs mode (chetstone) with Incremental search and Occur modes (Robert Krahn) @@ -289,44 +318,46 @@ - Added suppoert for Delete and SelectAll from context menu (danyaPostfactum) - Make wrapping behavior optional - - Selective bracket insertion/skipping - - - Added commands for increase/decrease numbers, sort lines (Vlad Zinculescu) - - Folding for Markdown, Lua, LaTeX + - Selective bracket insertion/skipping + - Added commands for increase/decrease numbers, sort lines (Vlad Zinculescu) + - Folding for Markdown, Lua, LaTeX - Selective bracket insertion/skipping for C-like languages -* Many new languages +- Many new languages + - Scheme (Mu Lei) - Dot (edwardsp) - FreeMarker (nguillaumin) - Tiny Mushcode (h3rb) - Velocity (Ryan Griffith) - - TOML (Garen Torikian) + - TOML (Garen Torikian) - LSL (Nemurimasu Neiro, Builders Brewery) - Curly (Libo Cannici) - - vbScript (Jan Jongboom) - - R (RStudio) + - vbScript (Jan Jongboom) + - R (RStudio) - ABAP - Lucene (Graham Scott) - Haml (Garen Torikian) - - Objective-C (Garen Torikian) - - Makefile (Garen Torikian) - - TypeScript (Garen Torikian) - - Lisp (Garen Torikian) - - Stylus (Garen Torikian) + - Objective-C (Garen Torikian) + - Makefile (Garen Torikian) + - TypeScript (Garen Torikian) + - Lisp (Garen Torikian) + - Stylus (Garen Torikian) - Dart (Garen Torikian) -* Live syntax checks +- Live syntax checks + - PHP (danyaPostfactum) - Lua -* New Themes - - Chaos - - Terminal - -2012.09.17, Version 1.0.0 +- New Themes + + - Chaos + - Terminal + 2012.09.17, Version 1.0.0 + +- New Features -* New Features - Multiple cursors and selections (https://c9.io/site/blog/2012/08/be-an-armenian-warrior-with-block-selection-on-steroids/) - Fold buttons displayed in the gutter - Indent Guides @@ -334,7 +365,8 @@ - Improved emacs keybindings - Autoclosing of html tags (danyaPostfactum) -* 20 New language modes +- 20 New language modes + - Coldfusion (Russ) - Diff - GLSL (Ed Mackey) @@ -357,33 +389,38 @@ - Yaml (Meg Sharkey) * Live syntax checks + - for XQuery and JSON -* New Themes +- New Themes + - Ambiance (Irakli Gozalishvili) - Dreamweaver (Adam Jimenez) - Github (bootstraponline) - Tommorrow themes (https://github.com/chriskempson/tomorrow-theme) - XCode -* Many Small Enhancements and Bugfixes - -2011.08.02, Version 0.2.0 +- Many Small Enhancements and Bugfixes + + 2011.08.02, Version 0.2.0 + +- Split view (Julian Viereck) -* Split view (Julian Viereck) - split editor area horizontally or vertivally to show two files at the same time -* Code Folding (Julian Viereck) +- Code Folding (Julian Viereck) + - Unstructured code folding - Will be the basis for language aware folding -* Mode behaviours (Chris Spencer) +- Mode behaviours (Chris Spencer) + - Adds mode specific hooks which allow transformations of entered text - Autoclosing of braces, paranthesis and quotation marks in C style modes - Autoclosing of angular brackets in XML style modes -* New language modes +- New language modes - Clojure (Carin Meier) - C# (Rob Conery) - Groovy (Ben Tilford) @@ -395,19 +432,21 @@ - SVG - Textile (Kelley van Evert) - SCAD (Jacob Hansson) - -* Live syntax checks +- Live syntax checks + - Lint for CSS using CSS Lint - CoffeeScript -* New Themes +- New Themes + - Crimson Editor (iebuggy) - Merbivore (Michael Schwartz) - Merbivore soft (Michael Schwartz) - Solarized dark/light (David Alan Hjelle) - Vibrant Ink (Michael Schwartz) -* Small Features/Enhancements +- Small Features/Enhancements + - Lots of render performance optimizations (Harutyun Amirjanyan) - Improved Ruby highlighting (Chris Wanstrath, Trent Ogren) - Improved PHP highlighting (Thomas Hruska) @@ -420,7 +459,8 @@ - When unfocused make cursor transparent instead of removing it (Harutyun Amirjanyan) - Support for matching groups in tokenizer with arrays of tokens (Chris Spencer) -* Bug fixes +- Bug fixes + - Add support for the new OSX scroll bars - Properly highlight JavaScript regexp literals - Proper handling of unicode characters in JavaScript identifiers @@ -428,55 +468,56 @@ - Fix scroll wheel sluggishness in Safari - Make keyboard infrastructure route keys like []^$ the right way (Julian Viereck) -2011.02.14, Version 0.1.6 + 2011.02.14, Version 0.1.6 -* Floating Anchors - - An Anchor is a floating pointer in the document. +- Floating Anchors + - An Anchor is a floating pointer in the document. - Whenever text is inserted or deleted before the cursor, the position of the cursor is updated - Usesd for the cursor and selection - Basis for bookmarks, multiple cursors and snippets in the future -* Extensive support for Cocoa style keybindings on the Mac -* New commands: +- Extensive support for Cocoa style keybindings on the Mac +- New commands: - center selection in viewport - remove to end/start of line - split line - transpose letters -* Refator markers +- Refator markers - Custom code can be used to render markers - Markers can be in front or behind the text - Markers are now stored in the session (was in the renderer) -* Lots of IE8 fixes including copy, cut and selections -* Unit tests can also be run in the browser +- Lots of IE8 fixes including copy, cut and selections +- Unit tests can also be run in the browser -* Soft wrap can adapt to the width of the editor (Mike Ratcliffe, Joe Cheng) -* Add minimal node server server.js to run the Ace demo in Chrome -* The top level editor.html demo has been renamed to index.html -* Bug fixes +- Soft wrap can adapt to the width of the editor (Mike Ratcliffe, Joe Cheng) +- Add minimal node server server.js to run the Ace demo in Chrome +- The top level editor.html demo has been renamed to index.html +- Bug fixes + - Fixed gotoLine to consider wrapped lines when calculating where to scroll to (James Allen) - Fixed isues when the editor was scrolled in the web page (Eric Allam) - Highlighting of Python string literals - Syntax rule for PHP comments -2011.02.08, Version 0.1.5 + 2011.02.08, Version 0.1.5 -* Add Coffeescript Mode (Satoshi Murakami) -* Fix word wrap bug (Julian Viereck) -* Fix packaged version of the Eclipse mode -* Loading of workers is more robust -* Fix "click selection" -* Allow tokizing empty lines (Daniel Krech) -* Make PageUp/Down behavior more consistent with native OS (Joe Cheng) +- Add Coffeescript Mode (Satoshi Murakami) +- Fix word wrap bug (Julian Viereck) +- Fix packaged version of the Eclipse mode +- Loading of workers is more robust +- Fix "click selection" +- Allow tokizing empty lines (Daniel Krech) +- Make PageUp/Down behavior more consistent with native OS (Joe Cheng) -2011.02.04, Version 0.1.4 + 2011.02.04, Version 0.1.4 -* Add C/C++ mode contributed by Gastón Kleiman -* Fix exception in key input +- Add C/C++ mode contributed by Gastón Kleiman +- Fix exception in key input -2011.02.04, Version 0.1.3 + 2011.02.04, Version 0.1.3 -* Let the packaged version play nice with requireJS -* Add Ruby mode contributed by Shlomo Zalman Heigh -* Add Java mode contributed by Tom Tasche -* Fix annotation bug -* Changing a document added a new empty line at the end +- Let the packaged version play nice with requireJS +- Add Ruby mode contributed by Shlomo Zalman Heigh +- Add Java mode contributed by Tom Tasche +- Fix annotation bug +- Changing a document added a new empty line at the end diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 6afec7f1fc1..5f8313783bb 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -105,7 +105,7 @@ function ace() { copy.file(ACE_HOME + "/build_support/editor.html", BUILD_DIR + "/editor.html"); copy.file(ACE_HOME + "/LICENSE", BUILD_DIR + "/LICENSE"); - copy.file(ACE_HOME + "/ChangeLog.txt", BUILD_DIR + "/ChangeLog.txt"); + copy.file(ACE_HOME + "/CHANGELOG.md", BUILD_DIR + "/CHANGELOG.md"); console.log('# ace ---------'); for (var i = 0; i < 4; i++) { diff --git a/package.json b/package.json index e674ab382e2..972ddc23184 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,11 @@ "url": "http://github.com/ajaxorg/ace.git" }, "devDependencies": { - "asyncjs": "~0.0.12", "amd-loader": "~0.0.4", + "architect-build": "https://github.com/c9/architect-build/tarball/43a6fdeffe", + "asyncjs": "~0.0.12", "dryice": "0.4.11", - "architect-build": "https://github.com/c9/architect-build/tarball/43a6fdeffe" + "standard-version": "^9.3.2" }, "mappings": { "ace": "." @@ -35,6 +36,13 @@ "start": "node static.js", "test": "node lib/ace/test/all.js", "lint": "eslint \"lib/ace/**/*.js\"", - "fix": "eslint --fix 'lib/ace/**/*.js'" + "fix": "eslint --fix 'lib/ace/**/*.js'", + "changelog": "standard-version" + }, + "standard-version": { + "skip": { + "commit": true, + "tag": true + } } -} +} \ No newline at end of file diff --git a/tool/release.sh b/tool/release.sh index 5c1a25f0886..380d7c7653c 100755 --- a/tool/release.sh +++ b/tool/release.sh @@ -74,10 +74,6 @@ node -e " update('package.json'); update('build/package.json'); update('./lib/ace/config.js'); - update('ChangeLog.txt', function(str) { - var date='"`date +%Y.%m.%d`"'; - return date + ' Version ' + version + '\n' + str.replace(/^\d+.*/, '').replace(/^\n/, ''); - }); " pause "versions updated. do you want to start build script? [y/n]" From 556f692cdee710c795968f4683cf92e55bbae7fb Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Mon, 9 May 2022 15:11:31 +0200 Subject: [PATCH 0510/1293] chore: Added workflows for closing stale issues and issue reprioritization --- .github/workflows/close-stale-issues.yml | 49 ++++++++++++++++++++ .github/workflows/issue-reprioritization.yml | 22 +++++++++ 2 files changed, 71 insertions(+) create mode 100644 .github/workflows/close-stale-issues.yml create mode 100644 .github/workflows/issue-reprioritization.yml diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml new file mode 100644 index 00000000000..12d877d2251 --- /dev/null +++ b/.github/workflows/close-stale-issues.yml @@ -0,0 +1,49 @@ +name: "Close Stale Issues" + +# Controls when the action will run. +on: + workflow_dispatch: + schedule: + - cron: "0 */4 * * *" + +jobs: + cleanup: + permissions: + issues: write + contents: read + pull-requests: write + runs-on: ubuntu-latest + name: Stale issue job + steps: + - uses: aws-actions/stale-issue-cleanup@v5 + with: + issue-types: issues + # Setting messages to an empty string will cause the automation to skip + # that category + ancient-issue-message: This issue has not received any attention in 1 year. If you want to keep this issue open, please leave a comment below and auto-close will be canceled. + stale-issue-message: This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled. + + # These labels are required + stale-issue-label: closing-soon + exempt-issue-label: no-autoclose + response-requested-label: response-requested + + # Don't set closed-for-staleness label to skip closing very old issues + # regardless of label + closed-for-staleness-label: closed-for-staleness + + # Issue timing + days-before-stale: 7 + days-before-close: 7 + days-before-ancient: 365 + + # If you don't want to mark a issue as being ancient based on a + # threshold of "upvotes", you can set this here. An "upvote" is + # the total number of +1, heart, hooray, and rocket reactions + # on an issue. + minimum-upvotes-to-exempt: 5 + + repo-token: ${{ secrets.GITHUB_TOKEN }} + loglevel: DEBUG + # Set dry-run to true to not perform label or close actions. + dry-run: false diff --git a/.github/workflows/issue-reprioritization.yml b/.github/workflows/issue-reprioritization.yml new file mode 100644 index 00000000000..06a8b3ee033 --- /dev/null +++ b/.github/workflows/issue-reprioritization.yml @@ -0,0 +1,22 @@ +name: issue-reprioritization +on: + schedule: + - cron: "0 0 * * 0" + +jobs: + issue-reprioritization: + permissions: + issues: write + runs-on: ubuntu-latest + steps: + - uses: kaizencc/issue-reprioritization-manager@main + id: reprioritization-manager + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + original-label: p2 + new-label: p1 + reprioritization-threshold: 5 + - uses: kaizencc/pr-triage-manager@main + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + on-pulls: ${{ steps.reprioritization-manager.outputs.linked-pulls }} From 357815cd3ec6470290647c20a45197fdebc3b865 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Mon, 9 May 2022 16:38:11 +0200 Subject: [PATCH 0511/1293] chore: fixed a typo in exempt label for autoclose workflow --- .github/workflows/close-stale-issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml index 12d877d2251..beee38a8470 100644 --- a/.github/workflows/close-stale-issues.yml +++ b/.github/workflows/close-stale-issues.yml @@ -25,7 +25,7 @@ jobs: # These labels are required stale-issue-label: closing-soon - exempt-issue-label: no-autoclose + exempt-issue-labels: no-autoclose response-requested-label: response-requested # Don't set closed-for-staleness label to skip closing very old issues From 7cc98c795a4a0ba5210b2c9c5ca25c901bd49385 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Tue, 10 May 2022 10:34:09 +0200 Subject: [PATCH 0512/1293] Reduced period to close issues from 5 to 2 days (#4692) chore: Reduced period to close issues from 5 to 2 days --- .github/workflows/close-stale-issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml index beee38a8470..0eefe6383a5 100644 --- a/.github/workflows/close-stale-issues.yml +++ b/.github/workflows/close-stale-issues.yml @@ -34,7 +34,7 @@ jobs: # Issue timing days-before-stale: 7 - days-before-close: 7 + days-before-close: 2 days-before-ancient: 365 # If you don't want to mark a issue as being ancient based on a From 4d2ecf08afeb1556f2511a1423729c2549802da8 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Wed, 11 May 2022 09:06:39 +0200 Subject: [PATCH 0513/1293] fix: Render bidirectional unicode characters as control characters (#4693) --- lib/ace/layer/text.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index ff5748d3697..84ba805030a 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -344,7 +344,7 @@ var Text = function(parentEl) { this.$renderToken = function(parent, screenColumn, token, value) { var self = this; - var re = /(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g; + var re = /(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC\u2066\u2067\u2068\u202A\u202B\u202D\u202E\u202C\u2069]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g; var valueFragment = this.dom.createFragment(this.element); From 20275de79c40636d27d5ce293cf528c915338fbd Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Wed, 11 May 2022 15:16:56 +0200 Subject: [PATCH 0514/1293] feat: Added ability to configure certain format options for beautify extension --- lib/ace/ext/beautify.js | 7 ++++++- lib/ace/ext/beautify_test.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/ace/ext/beautify.js b/lib/ace/ext/beautify.js index f8d3713b169..278bb262e3b 100644 --- a/lib/ace/ext/beautify.js +++ b/lib/ace/ext/beautify.js @@ -44,12 +44,17 @@ exports.singletonTags = ["area", "base", "br", "col", "command", "embed", "hr", // insert a line break after block level tags exports.blockTags = ["article", "aside", "blockquote", "body", "div", "dl", "fieldset", "footer", "form", "head", "header", "html", "nav", "ol", "p", "script", "section", "style", "table", "tbody", "tfoot", "thead", "ul"]; +exports.formatOptions = { + lineBreaksAfterCommasInCurlyBlock: true +}; + exports.beautify = function(session) { var iterator = new TokenIterator(session, 0, 0); var token = iterator.getCurrentToken(); var tabString = session.getTabString(); var singletonTags = exports.singletonTags; var blockTags = exports.blockTags; + var formatOptions = exports.formatOptions || {}; var nextToken; var breakBefore = false; var spaceBefore = false; @@ -269,7 +274,7 @@ exports.beautify = function(session) { trimNext(); // line break after commas in curly block - if (value.match(/^(,)$/) && curlyDepth>0 && roundDepth===0) { + if (value.match(/^(,)$/) && curlyDepth>0 && roundDepth===0 && formatOptions.lineBreaksAfterCommasInCurlyBlock) { rowsToAdd++; } else { spaceAfter = true; diff --git a/lib/ace/ext/beautify_test.js b/lib/ace/ext/beautify_test.js index 982bbce0268..b925cbcb0d6 100644 --- a/lib/ace/ext/beautify_test.js +++ b/lib/ace/ext/beautify_test.js @@ -383,6 +383,40 @@ module.exports = { + "\t\t\"b\": \"2\"\n" + "\t}\n" + ""); + }, + + "test beautify php default behaviour with line breaks after comma": function() { + var s = new EditSession([ + " Date: Thu, 12 May 2022 14:08:15 +0400 Subject: [PATCH 0515/1293] chore: use npm changelog in release script (#4698) --- tool/release.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tool/release.sh b/tool/release.sh index 380d7c7653c..cc8b920b840 100755 --- a/tool/release.sh +++ b/tool/release.sh @@ -52,10 +52,11 @@ git --no-pager log --color --first-parent --oneline v$CUR_VERSION..master | echo "current version is $CUR_VERSION" # get new version number -VERSION_NUM=; -until [[ "$VERSION_NUM" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] ; do - read -p "enter version number for the build " VERSION_NUM -done +git checkout -- package.json +git checkout -- CHANGELOG.md +npm run changelog +VERSION_NUM="$(node -p "require('./package.json').version")"; +echo "version number for the build is" $VERSION_NUM # update version number everywhere node -e " From 4fb4214cca8a146c6aeb2a5f3c42d0498e5813fa Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Thu, 12 May 2022 12:37:01 +0200 Subject: [PATCH 0516/1293] release v1.5.0 --- CHANGELOG.md | 17 +++++++++++++++++ build | 2 +- lib/ace/config.js | 2 +- package.json | 4 ++-- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 664b820abc4..c9e6d84e69a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +# Changelog + +All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +## [1.5.0](https://github.com/ajaxorg/ace/compare/v1.4.14...v1.5.0) (2022-05-12) + + +### Features + +* Added ability to configure certain format options for beautify extension ([20275de](https://github.com/ajaxorg/ace/commit/20275de79c40636d27d5ce293cf528c915338fbd)) + + +### Bug Fixes + +* Modify syntax ([b78d772](https://github.com/ajaxorg/ace/commit/b78d77240e1909b9d91fcd2ac35a4c17af05f56b)) +* Render bidirectional unicode characters as control characters ([#4693](https://github.com/ajaxorg/ace/issues/4693)) ([4d2ecf0](https://github.com/ajaxorg/ace/commit/4d2ecf08afeb1556f2511a1423729c2549802da8)) + 2022.01.26 Version 1.4.14 - update vim mode diff --git a/build b/build index 6c0e60e5525..61015eb194d 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 6c0e60e5525a6d6ff0e9e929848f7834809a4784 +Subproject commit 61015eb194d5783b705a77338ebb3a78569e9484 diff --git a/lib/ace/config.js b/lib/ace/config.js index 976903f62bd..a5b0b7737c0 100644 --- a/lib/ace/config.js +++ b/lib/ace/config.js @@ -223,6 +223,6 @@ function deHyphenate(str) { return str.replace(/-(.)/g, function(m, m1) { return m1.toUpperCase(); }); } -exports.version = "1.4.14"; +exports.version = "1.5.0"; }); diff --git a/package.json b/package.json index 972ddc23184..d5ec1435a5a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.4.14", + "version": "1.5.0", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" @@ -45,4 +45,4 @@ "tag": true } } -} \ No newline at end of file +} From 33cf1c66af970edaf7eb0a468276fca249b8a5c8 Mon Sep 17 00:00:00 2001 From: jeroenpost86 Date: Thu, 12 May 2022 03:49:39 -0700 Subject: [PATCH 0517/1293] fix: Updated PHP mode to support PHP8.1 syntax (#4696) Co-authored-by: Pipelines --- lib/ace/mode/php/php.js | 4830 ++++++++++++++++++++------------------- 1 file changed, 2509 insertions(+), 2321 deletions(-) diff --git a/lib/ace/mode/php/php.js b/lib/ace/mode/php/php.js index 29f4c05699b..315471c3376 100644 --- a/lib/ace/mode/php/php.js +++ b/lib/ace/mode/php/php.js @@ -16,2329 +16,2517 @@ */ - -define(function(require, exports, module) { - -var PHP = {Constants:{}}; - -PHP.Constants.T_INCLUDE = 259 -PHP.Constants.T_INCLUDE_ONCE = 260 -PHP.Constants.T_EVAL = 318 -PHP.Constants.T_REQUIRE = 261 -PHP.Constants.T_REQUIRE_ONCE = 262 -PHP.Constants.T_LOGICAL_OR = 263 -PHP.Constants.T_LOGICAL_XOR = 264 -PHP.Constants.T_LOGICAL_AND = 265 -PHP.Constants.T_PRINT = 266 -PHP.Constants.T_YIELD = 267 -PHP.Constants.T_DOUBLE_ARROW = 268 -PHP.Constants.T_YIELD_FROM = 269 -PHP.Constants.T_PLUS_EQUAL = 270 -PHP.Constants.T_MINUS_EQUAL = 271 -PHP.Constants.T_MUL_EQUAL = 272 -PHP.Constants.T_DIV_EQUAL = 273 -PHP.Constants.T_CONCAT_EQUAL = 274 -PHP.Constants.T_MOD_EQUAL = 275 -PHP.Constants.T_AND_EQUAL = 276 -PHP.Constants.T_OR_EQUAL = 277 -PHP.Constants.T_XOR_EQUAL = 278 -PHP.Constants.T_SL_EQUAL = 279 -PHP.Constants.T_SR_EQUAL = 280 -PHP.Constants.T_POW_EQUAL = 281 -PHP.Constants.T_COALESCE_EQUAL = 282 -PHP.Constants.T_COALESCE = 283 -PHP.Constants.T_BOOLEAN_OR = 284 -PHP.Constants.T_BOOLEAN_AND = 285 -PHP.Constants.T_IS_EQUAL = 286 -PHP.Constants.T_IS_NOT_EQUAL = 287 -PHP.Constants.T_IS_IDENTICAL = 288 -PHP.Constants.T_IS_NOT_IDENTICAL = 289 -PHP.Constants.T_SPACESHIP = 290 -PHP.Constants.T_IS_SMALLER_OR_EQUAL = 291 -PHP.Constants.T_IS_GREATER_OR_EQUAL = 292 -PHP.Constants.T_SL = 293 -PHP.Constants.T_SR = 294 -PHP.Constants.T_INSTANCEOF = 295 -PHP.Constants.T_INC = 319 -PHP.Constants.T_DEC = 320 -PHP.Constants.T_INT_CAST = 296 -PHP.Constants.T_DOUBLE_CAST = 297 -PHP.Constants.T_STRING_CAST = 298 -PHP.Constants.T_ARRAY_CAST = 299 -PHP.Constants.T_OBJECT_CAST = 300 -PHP.Constants.T_BOOL_CAST = 301 -PHP.Constants.T_UNSET_CAST = 302 -PHP.Constants.T_POW = 303 -PHP.Constants.T_NEW = 304 -PHP.Constants.T_CLONE = 305 -PHP.Constants.T_EXIT = 321 -PHP.Constants.T_IF = 322 -PHP.Constants.T_ELSEIF = 307 -PHP.Constants.T_ELSE = 308 -PHP.Constants.T_ENDIF = 323 -PHP.Constants.T_LNUMBER = 309 -PHP.Constants.T_DNUMBER = 310 -PHP.Constants.T_STRING = 311 -PHP.Constants.T_STRING_VARNAME = 316 -PHP.Constants.T_VARIABLE = 312 -PHP.Constants.T_NUM_STRING = 317 -PHP.Constants.T_INLINE_HTML = 313 -PHP.Constants.T_BAD_CHARACTER = 395 -PHP.Constants.T_ENCAPSED_AND_WHITESPACE = 314 -PHP.Constants.T_CONSTANT_ENCAPSED_STRING = 315 -PHP.Constants.T_ECHO = 324 -PHP.Constants.T_DO = 325 -PHP.Constants.T_WHILE = 326 -PHP.Constants.T_ENDWHILE = 327 -PHP.Constants.T_FOR = 328 -PHP.Constants.T_ENDFOR = 329 -PHP.Constants.T_FOREACH = 330 -PHP.Constants.T_ENDFOREACH = 331 -PHP.Constants.T_DECLARE = 332 -PHP.Constants.T_ENDDECLARE = 333 -PHP.Constants.T_AS = 334 -PHP.Constants.T_SWITCH = 335 -PHP.Constants.T_ENDSWITCH = 336 -PHP.Constants.T_CASE = 337 -PHP.Constants.T_DEFAULT = 338 -PHP.Constants.T_BREAK = 339 -PHP.Constants.T_CONTINUE = 340 -PHP.Constants.T_GOTO = 341 -PHP.Constants.T_FUNCTION = 342 -PHP.Constants.T_FN = 343 -PHP.Constants.T_CONST = 344 -PHP.Constants.T_RETURN = 345 -PHP.Constants.T_TRY = 346 -PHP.Constants.T_CATCH = 347 -PHP.Constants.T_FINALLY = 348 -PHP.Constants.T_THROW = 349 -PHP.Constants.T_USE = 350 -PHP.Constants.T_INSTEADOF = 351 -PHP.Constants.T_GLOBAL = 352 -PHP.Constants.T_STATIC = 353 -PHP.Constants.T_ABSTRACT = 354 -PHP.Constants.T_FINAL = 355 -PHP.Constants.T_PRIVATE = 356 -PHP.Constants.T_PROTECTED = 357 -PHP.Constants.T_PUBLIC = 358 -PHP.Constants.T_VAR = 359 -PHP.Constants.T_UNSET = 360 -PHP.Constants.T_ISSET = 361 -PHP.Constants.T_EMPTY = 362 -PHP.Constants.T_HALT_COMPILER = 363 -PHP.Constants.T_CLASS = 364 -PHP.Constants.T_TRAIT = 365 -PHP.Constants.T_INTERFACE = 366 -PHP.Constants.T_EXTENDS = 367 -PHP.Constants.T_IMPLEMENTS = 368 -PHP.Constants.T_OBJECT_OPERATOR = 369 -PHP.Constants.T_DOUBLE_ARROW = 268 -PHP.Constants.T_LIST = 370 -PHP.Constants.T_ARRAY = 371 -PHP.Constants.T_CALLABLE = 372 -PHP.Constants.T_CLASS_C = 376 -PHP.Constants.T_TRAIT_C = 377 -PHP.Constants.T_METHOD_C = 378 -PHP.Constants.T_FUNC_C = 379 -PHP.Constants.T_LINE = 373 -PHP.Constants.T_FILE = 374 -PHP.Constants.T_COMMENT = 380 -PHP.Constants.T_DOC_COMMENT = 381 -PHP.Constants.T_OPEN_TAG = 382 -PHP.Constants.T_OPEN_TAG_WITH_ECHO = 383 -PHP.Constants.T_CLOSE_TAG = 384 -PHP.Constants.T_WHITESPACE = 385 -PHP.Constants.T_START_HEREDOC = 386 -PHP.Constants.T_END_HEREDOC = 387 -PHP.Constants.T_DOLLAR_OPEN_CURLY_BRACES = 388 -PHP.Constants.T_CURLY_OPEN = 389 -PHP.Constants.T_PAAMAYIM_NEKUDOTAYIM = 390 -PHP.Constants.T_NAMESPACE = 391 -PHP.Constants.T_NS_C = 392 -PHP.Constants.T_DIR = 375 -PHP.Constants.T_NS_SEPARATOR = 393 -PHP.Constants.T_ELLIPSIS = 394 - -PHP.Lexer = function(src, ini) { - var heredoc, heredocEndAllowed, - - stateStack = ['INITIAL'], stackPos = 0, - swapState = function(state) { - stateStack[stackPos] = state; - }, - pushState = function(state) { - stateStack[++stackPos] = state; - }, - popState = function() { - --stackPos; - }, - - shortOpenTag = ini === undefined || /^(on|true|1)$/i.test(ini.short_open_tag), - openTag = shortOpenTag - ? /^(\<\?php(?:\r\n|[ \t\r\n])|<\?|\ - + - - # Attributes snippet attr - ${1:attribute}="${2:property}" + \${1:attribute}="\${2:property}" snippet attr+ - ${1:attribute}="${2:property}" attr+${3} + \${1:attribute}="\${2:property}" attr+\${3} snippet . - class="${1}"${2} + class="\${1}"\${2} snippet # - id="${1}"${2} + id="\${1}"\${2} snippet alt - alt="${1}"${2} + alt="\${1}"\${2} snippet charset - charset="${1:utf-8}"${2} + charset="\${1:utf-8}"\${2} snippet data - data-${1}="${2:$1}"${3} + data-\${1}="\${2:\$1}"\${3} snippet for - for="${1}"${2} + for="\${1}"\${2} snippet height - height="${1}"${2} + height="\${1}"\${2} snippet href - href="http://github.com/$%7B1:#}"${2} + href="http://github.com/$%7B1:#}"\${2} snippet lang - lang="${1:en}"${2} + lang="\${1:en}"\${2} snippet media - media="${1}"${2} + media="\${1}"\${2} snippet name - name="${1}"${2} + name="\${1}"\${2} snippet rel - rel="${1}"${2} + rel="\${1}"\${2} snippet scope - scope="${1:row}"${2} + scope="\${1:row}"\${2} snippet src - src="http://github.com/$%7B1%7D"${2} + src="http://github.com/$%7B1%7D"\${2} snippet title= - title="${1}"${2} + title="\${1}"\${2} snippet type - type="${1}"${2} + type="\${1}"\${2} snippet value - value="${1}"${2} + value="\${1}"\${2} snippet width - width="${1}"${2} + width="\${1}"\${2} # Elements snippet a - ${2:$1} + \${2:\$1} snippet a. - ${3:$1} + \${3:\$1} snippet a# - ${3:$1} + \${3:\$1} snippet a:ext - ${2:$1} + \${2:\$1} snippet a:mail - ${3:email me} + \${3:email me} snippet abbr - ${2} + \${2} snippet address
    - ${1} + \${1}
    snippet area - ${4} + \${4} snippet area+ - ${4} - area+${5} + \${4} + area+\${5} snippet area:c - ${3} + \${3} snippet area:d - ${3} + \${3} snippet area:p - ${3} + \${3} snippet area:r - ${3} + \${3} snippet article
    - ${1} + \${1}
    snippet article. -
    - ${2} +
    + \${2}
    snippet article# -
    - ${2} +
    + \${2}
    snippet aside snippet aside. -
    \${6} snippet ol
      - ${1} + \${1}
    snippet ol. -
      + \${2}
    snippet ol# -
      + \${2}
    snippet ol+
      -
    1. ${1}
    2. - li+${2} +
    3. \${1}
    4. + li+\${2}
    snippet opt - + snippet opt+ - - opt+${3} + + opt+\${3} snippet optt - + snippet optgroup - - opt+${3} + + opt+\${3} snippet output - ${1} + \${1} snippet p -

    ${1}

    +

    \${1}

    snippet param - ${3} + \${3} snippet pre
    -		${1}
    +		\${1}
     	
    snippet progress - ${1} + \${1} snippet q - ${1} + \${1} snippet rp - ${1} + \${1} snippet rt - ${1} + \${1} snippet ruby - ${1} + \${1} snippet s - ${1} + \${1} snippet samp - ${1} + \${1} snippet script snippet scriptsrc - + snippet newscript snippet newscriptsrc - + snippet section
    - ${1} + \${1}
    snippet section. -
    - ${2} +
    + \${2}
    snippet section# -
    - ${2} +
    + \${2}
    snippet select - + \${3} snippet select. - + + opt+\${5} snippet small - ${1} + \${1} snippet source - + snippet span - ${1} + \${1} snippet strong - ${1} + \${1} snippet style - snippet sub - ${1} + \${1} snippet summary - ${1} + \${1} snippet sup - ${1} + \${1} snippet table - - ${2} +
    + \${2}
    snippet table. - - ${3} +
    + \${3}
    snippet table# - - ${3} +
    + \${3}
    snippet tbody - ${1} + \${1} snippet td - ${1} + \${1} snippet td. - ${2} + \${2} snippet td# - ${2} + \${2} snippet td+ - ${1} - td+${2} + \${1} + td+\${2} snippet textarea - ${6} + \${6} snippet tfoot - ${1} + \${1} snippet th - ${1} + \${1} snippet th. - ${2} + \${2} snippet th# - ${2} + \${2} snippet th+ - ${1} - th+${2} + \${1} + th+\${2} snippet thead - ${1} + \${1} snippet time -
    From 87e0dc7b868798300e874e39304aeda18d3d1a76 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Mon, 17 Oct 2022 13:11:13 +0400 Subject: [PATCH 0661/1293] fix: recognisition of uppercase hex numbers for stylus mode (#4962) --- src/mode/stylus_highlight_rules.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mode/stylus_highlight_rules.js b/src/mode/stylus_highlight_rules.js index b03c61d0c95..86d9f776dca 100644 --- a/src/mode/stylus_highlight_rules.js +++ b/src/mode/stylus_highlight_rules.js @@ -63,12 +63,12 @@ var StylusHighlightRules = function() { regex: "(?:\\b)(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|datalist|dd|del|details|dfn|dialog|div|dl|dt|em|eventsource|fieldset|figure|figcaption|footer|form|frame|frameset|(?:h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|label|legend|li|link|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|samp|script|section|select|small|span|strike|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)(?:\\b)" }, { - token : "constant.numeric", // hex6 color - regex : "#[a-f0-9]{6}" + token: "constant.numeric", // hex6 color + regex: "#[a-fA-F0-9]{6}" }, { - token : "constant.numeric", // hex3 color - regex : "#[a-f0-9]{3}" + token: "constant.numeric", // hex3 color + regex: "#[a-fA-F0-9]{3}" }, { token: ["punctuation.definition.entity.stylus", "entity.other.attribute-name.id.stylus"], From 52dbb0577693e29f124a1f16008b4e11e2ce7c02 Mon Sep 17 00:00:00 2001 From: Master Weber <47494224+masterWeber@users.noreply.github.com> Date: Mon, 17 Oct 2022 12:22:01 +0300 Subject: [PATCH 0662/1293] fix: php worker rules for T_NAME_FULLY_QUALIFIED (#4960) --- lib/ace/mode/php/php.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/mode/php/php.js b/lib/ace/mode/php/php.js index 9d21661e470..ec7db074546 100644 --- a/lib/ace/mode/php/php.js +++ b/lib/ace/mode/php/php.js @@ -772,7 +772,7 @@ define(function (require, exports, module) { }, { value: PHP.Constants.T_NAME_FULLY_QUALIFIED, - re: /^\\\w+\\\w+(?:\\\w+)*/ + re: /^\\\w+(?:\\\w+)*/ }, { value: PHP.Constants.T_NAME_QUALIFIED, From cd2de869d6e9ac94af0263d519e5c53283733bae Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Mon, 17 Oct 2022 11:31:54 +0200 Subject: [PATCH 0663/1293] release v1.12.1 --- CHANGELOG.md | 8 ++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56a4a95e49f..f4ecccd7ce3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.12.1](https://github.com/ajaxorg/ace/compare/v1.12.0...v1.12.1) (2022-10-17) + + +### Bug Fixes + +* php worker rules for T_NAME_FULLY_QUALIFIED ([#4960](https://github.com/ajaxorg/ace/issues/4960)) ([52dbb05](https://github.com/ajaxorg/ace/commit/52dbb0577693e29f124a1f16008b4e11e2ce7c02)) +* recognisition of uppercase hex numbers for stylus mode ([#4962](https://github.com/ajaxorg/ace/issues/4962)) ([87e0dc7](https://github.com/ajaxorg/ace/commit/87e0dc7b868798300e874e39304aeda18d3d1a76)) + ## [1.12.0](https://github.com/ajaxorg/ace/compare/v1.11.2...v1.12.0) (2022-10-15) diff --git a/build b/build index a802f36b179..3367cc68628 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit a802f36b179d43deaa8f860a6ca79cdb1e9b62c7 +Subproject commit 3367cc686282d587a5791be7e25b31aee17846e8 diff --git a/package.json b/package.json index 6ae8acf2f39..bb4525372e1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.12.0", + "version": "1.12.1", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 042ec80ff33..e55183e874f 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.12.0"; +exports.version = "1.12.1"; From 96e4066341fb7b82d02ad8272929711073d3bfc4 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Mon, 17 Oct 2022 14:15:11 +0400 Subject: [PATCH 0664/1293] fix: Namespace-relative names for php (#4963) --- lib/ace/mode/php/php.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ace/mode/php/php.js b/lib/ace/mode/php/php.js index ec7db074546..cf0b56c42a8 100644 --- a/lib/ace/mode/php/php.js +++ b/lib/ace/mode/php/php.js @@ -461,10 +461,6 @@ define(function (require, exports, module) { value: PHP.Constants.T_MATCH, re: /^match\b/i }, - { - value: PHP.Constants.T_NAMESPACE, - re: /^namespace\b/i - }, { value: PHP.Constants.T_NEW, re: /^new\b/i @@ -782,6 +778,10 @@ define(function (require, exports, module) { value: PHP.Constants.T_NAME_RELATIVE, re: /^namespace\\\w+(?:\\\w+)*/ }, + { + value: PHP.Constants.T_NAMESPACE, + re: /^namespace\b/i + }, { value: PHP.Constants.T_ATTRIBUTE, re: /^#\[([\S\s]*?)]/ From be8eb1236fb7e1d27cedf033d301f094ec6764e5 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Tue, 18 Oct 2022 14:34:45 +0400 Subject: [PATCH 0665/1293] fix: custom scrollbar breaks csp mode (#4967) --- src/scrollbar_custom.js | 48 ++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/scrollbar_custom.js b/src/scrollbar_custom.js index b6150f9edf3..f94ace3cf54 100644 --- a/src/scrollbar_custom.js +++ b/src/scrollbar_custom.js @@ -5,16 +5,44 @@ var dom = require("./lib/dom"); var event = require("./lib/event"); var EventEmitter = require("./lib/event_emitter").EventEmitter; -dom.importCssString('.ace_editor>.ace_sb-v div, .ace_editor>.ace_sb-h div{\n' + ' position: absolute;\n' - + ' background: rgba(128, 128, 128, 0.6);\n' + ' -moz-box-sizing: border-box;\n' + ' box-sizing: border-box;\n' - + ' border: 1px solid #bbb;\n' + ' border-radius: 2px;\n' + ' z-index: 8;\n' + '}\n' - + '.ace_editor>.ace_sb-v, .ace_editor>.ace_sb-h {\n' + ' position: absolute;\n' + ' z-index: 6;\n' - + ' background: none;' + ' overflow: hidden!important;\n' + '}\n' + '.ace_editor>.ace_sb-v {\n' - + ' z-index: 6;\n' + ' right: 0;\n' + ' top: 0;\n' + ' width: 12px;\n' + '}' + '.ace_editor>.ace_sb-v div {\n' - + ' z-index: 8;\n' + ' right: 0;\n' + ' width: 100%;\n' + '}' + '.ace_editor>.ace_sb-h {\n' + ' bottom: 0;\n' - + ' left: 0;\n' + ' height: 12px;\n' + '}' + '.ace_editor>.ace_sb-h div {\n' + ' bottom: 0;\n' - + ' height: 100%;\n' + '}' + '.ace_editor>.ace_sb_grabbed {\n' + ' z-index: 8;\n' + ' background: #000;\n' - + '}'); +dom.importCssString(`.ace_editor>.ace_sb-v div, .ace_editor>.ace_sb-h div{ + position: absolute; + background: rgba(128, 128, 128, 0.6); + -moz-box-sizing: border-box; + box-sizing: border-box; + border: 1px solid #bbb; + border-radius: 2px; + z-index: 8; +} +.ace_editor>.ace_sb-v, .ace_editor>.ace_sb-h { + position: absolute; + z-index: 6; + background: none;' + ' overflow: hidden!important; +} +.ace_editor>.ace_sb-v { + z-index: 6; + right: 0; + top: 0; + width: 12px; +} +.ace_editor>.ace_sb-v div { + z-index: 8; + right: 0; + width: 100%; +} +.ace_editor>.ace_sb-h { + bottom: 0; + left: 0; + height: 12px; +} +.ace_editor>.ace_sb-h div { + bottom: 0; + height: 100%; +} +.ace_editor>.ace_sb_grabbed { + z-index: 8; + background: #000; +}`, "ace_scrollbar.css", false); /** * An abstract class representing a native scrollbar control. From 5294aa21a10fba38f41a78128f70790a66fc8373 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Tue, 18 Oct 2022 12:37:39 +0200 Subject: [PATCH 0666/1293] release v1.12.2 --- CHANGELOG.md | 9 +++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4ecccd7ce3..a198661ebea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.12.2](https://github.com/ajaxorg/ace/compare/v1.12.1...v1.12.2) (2022-10-18) + + +### Bug Fixes + +* custom scrollbar breaks csp mode ([#4967](https://github.com/ajaxorg/ace/issues/4967)) ([be8eb12](https://github.com/ajaxorg/ace/commit/be8eb1236fb7e1d27cedf033d301f094ec6764e5)) +* find all in range bug ([13bd553](https://github.com/ajaxorg/ace/commit/13bd55348dc8de5c547c74ec0e48c52b6db96a26)) +* Namespace-relative names for php ([#4963](https://github.com/ajaxorg/ace/issues/4963)) ([96e4066](https://github.com/ajaxorg/ace/commit/96e4066341fb7b82d02ad8272929711073d3bfc4)) + ### [1.12.1](https://github.com/ajaxorg/ace/compare/v1.12.0...v1.12.1) (2022-10-17) diff --git a/build b/build index 3367cc68628..42819bea089 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 3367cc686282d587a5791be7e25b31aee17846e8 +Subproject commit 42819bea089aa2652a52712d92c0144cb52de517 diff --git a/package.json b/package.json index bb4525372e1..fbf1919386e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.12.1", + "version": "1.12.2", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index e55183e874f..3562dcd1017 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.12.1"; +exports.version = "1.12.2"; From f2a424a649f655b9511b1bb6047097634edb0e3f Mon Sep 17 00:00:00 2001 From: Darek Miskiewicz Date: Tue, 18 Oct 2022 17:38:17 +0200 Subject: [PATCH 0667/1293] fix: Fix syntax error in the custom scroll CSS (#4968) --- src/scrollbar_custom.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scrollbar_custom.js b/src/scrollbar_custom.js index f94ace3cf54..77edf5c3ddd 100644 --- a/src/scrollbar_custom.js +++ b/src/scrollbar_custom.js @@ -17,7 +17,8 @@ dom.importCssString(`.ace_editor>.ace_sb-v div, .ace_editor>.ace_sb-h div{ .ace_editor>.ace_sb-v, .ace_editor>.ace_sb-h { position: absolute; z-index: 6; - background: none;' + ' overflow: hidden!important; + background: none; + overflow: hidden!important; } .ace_editor>.ace_sb-v { z-index: 6; From 352e4a6d69b1f47d9da6ec2fb0b49072e308f465 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Tue, 18 Oct 2022 17:39:10 +0200 Subject: [PATCH 0668/1293] release v1.12.3 --- CHANGELOG.md | 7 +++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a198661ebea..762065836bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.12.3](https://github.com/ajaxorg/ace/compare/v1.12.2...v1.12.3) (2022-10-18) + + +### Bug Fixes + +* Fix syntax error in the custom scroll CSS ([#4968](https://github.com/ajaxorg/ace/issues/4968)) ([f2a424a](https://github.com/ajaxorg/ace/commit/f2a424a649f655b9511b1bb6047097634edb0e3f)) + ### [1.12.2](https://github.com/ajaxorg/ace/compare/v1.12.1...v1.12.2) (2022-10-18) diff --git a/build b/build index 42819bea089..5f6080166fc 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 42819bea089aa2652a52712d92c0144cb52de517 +Subproject commit 5f6080166fcc3142ad36f272834d4f9f98d34866 diff --git a/package.json b/package.json index fbf1919386e..f48e471ee01 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.12.2", + "version": "1.12.3", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 3562dcd1017..a529567e9dd 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.12.2"; +exports.version = "1.12.3"; From bf2913a71624e94d13727115b2aa0ef0c279c89f Mon Sep 17 00:00:00 2001 From: Ani Amirjanyan <56698448+anijanyan@users.noreply.github.com> Date: Sat, 29 Oct 2022 14:45:58 +0400 Subject: [PATCH 0669/1293] fix: Open valid url under cursor (#4970) * Open valid url under cursor * Namings fixed due to code review * Test added due to code review --- src/commands/default_commands.js | 4 ++++ src/editor.js | 35 ++++++++++++++++++++++++++++++++ src/editor_commands_test.js | 12 +++++++++-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/commands/default_commands.js b/src/commands/default_commands.js index 6dfa827a625..d7c6413247d 100644 --- a/src/commands/default_commands.js +++ b/src/commands/default_commands.js @@ -744,6 +744,10 @@ exports.commands = [{ multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true +}, { + name: "openlink", + bindKey: bindKey("Ctrl+F3", "F3"), + exec: function(editor) { editor.openLink(); } }, { name: "joinlines", description: "Join lines", diff --git a/src/editor.js b/src/editor.js index 47580fc7493..276893fb527 100644 --- a/src/editor.js +++ b/src/editor.js @@ -1729,6 +1729,41 @@ Editor.$uid = 0; } }; + /** + * Finds link at defined {row} and {column} + * @returns {String} + **/ + this.findLinkAt = function (row, column) { + var line = this.session.getLine(row); + var wordParts = line.split(/((?:https?|ftp):\/\/[\S]+)/); + var columnPosition = column; + if (columnPosition < 0) columnPosition = 0; + var previousPosition = 0, currentPosition = 0, match; + for (let item of wordParts) { + currentPosition = previousPosition + item.length; + if (columnPosition >= previousPosition && columnPosition <= currentPosition) { + if (item.match(/((?:https?|ftp):\/\/[\S]+)/)) { + match = item.replace(/[\s:.,'";}\]]+$/, ""); + break; + } + } + previousPosition = currentPosition; + } + return match; + }; + + /** + * Open valid url under cursor in another tab + * @returns {Boolean} + **/ + this.openLink = function () { + var cursor = this.selection.getCursor(); + var url = this.findLinkAt(cursor.row, cursor.column); + if (url) + window.open(url, '_blank'); + return url != null; + }; + /** * Removes all the lines in the current selection * @related EditSession.remove diff --git a/src/editor_commands_test.js b/src/editor_commands_test.js index ce9fc657d9d..e74e5e7c2c2 100644 --- a/src/editor_commands_test.js +++ b/src/editor_commands_test.js @@ -5,8 +5,6 @@ if (typeof process !== "undefined") { "use strict"; -var ace = require("./ace"); -var EditSession = require("./edit_session").EditSession; var Editor = require("./editor").Editor; var UndoManager = require("./undomanager").UndoManager; var MockRenderer = require("./test/mockrenderer").MockRenderer; @@ -533,6 +531,16 @@ module.exports = { exec("selectlineend", 1); editor.execCommand(editor.commands.byName.joinlines); assert.equal(editor.getValue(), "foo for foo foo foo for foo foo\nfoo for foo foo"); + }, + "test findlink": function() { + editor = new Editor(new MockRenderer()); + + editor.setValue("foo for foo foo\nhttps://www.google.com/", 1); + var url = editor.findLinkAt(0, 1); + assert.equal(url, null); + + url = editor.findLinkAt(1, 5); + assert.equal(url, "https://www.google.com/"); } }; From 0fbc54cc5130b0271928995660413ba0fab678cb Mon Sep 17 00:00:00 2001 From: mkslanc Date: Thu, 27 Oct 2022 18:34:51 +0400 Subject: [PATCH 0670/1293] fix: vim "normal" mode brackets highlighting --- src/edit_session/bracket_match.js | 30 ++++++++++++++++++++++-------- src/editor.js | 6 +++++- src/keyboard/vim.js | 9 +++++++++ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/edit_session/bracket_match.js b/src/edit_session/bracket_match.js index 1883d2c722b..d0940d4823b 100644 --- a/src/edit_session/bracket_match.js +++ b/src/edit_session/bracket_match.js @@ -69,17 +69,31 @@ function BracketMatch() { * * one Range if there is only one bracket * * @param {Point} pos + * @param {number|null} offset * @returns {null|Range[]} */ - this.getMatchingBracketRanges = function(pos) { + this.getMatchingBracketRanges = function(pos, offset) { var line = this.getLine(pos.row); - - var chr = line.charAt(pos.column - 1); - var match = chr && chr.match(/([\(\[\{])|([\)\]\}])/); - if (!match) { - chr = line.charAt(pos.column); - pos = {row: pos.row, column: pos.column + 1}; - match = chr && chr.match(/([\(\[\{])|([\)\]\}])/); + var bracketsRegExp = /([\(\[\{])|([\)\]\}])/; + if (offset != null) { + var chr = line.charAt(pos.column + offset); + pos = { + row: pos.row, + column: pos.column + offset + 1 + }; + var match = chr && chr.match(bracketsRegExp); + } + else { + var chr = line.charAt(pos.column - 1); + var match = chr && chr.match(bracketsRegExp); + if (!match) { + var chr = line.charAt(pos.column); + pos = { + row: pos.row, + column: pos.column + 1 + }; + var match = chr && chr.match(bracketsRegExp); + } } if (!match) diff --git a/src/editor.js b/src/editor.js index 47580fc7493..acabec3702e 100644 --- a/src/editor.js +++ b/src/editor.js @@ -507,7 +507,11 @@ Editor.$uid = 0; session.$bracketHighlight = null; } var pos = self.getCursorPosition(); - var ranges = session.getMatchingBracketRanges(pos); + var handler = self.getKeyboardHandler(); + var vimOffset = handler && handler.$getCursorOffsetForHighlight && handler.$getCursorOffsetForHighlight( + self); + var ranges = session.getMatchingBracketRanges(pos, vimOffset); + if (!ranges) { var iterator = new TokenIterator(session, pos.row, pos.column); var token = iterator.getCurrentToken(); diff --git a/src/keyboard/vim.js b/src/keyboard/vim.js index b8756d21f4e..961d09b2af9 100644 --- a/src/keyboard/vim.js +++ b/src/keyboard/vim.js @@ -6985,6 +6985,15 @@ domLib.importCssString(`.normal-mode .ace_cursor{ domLib.setStyle(element.style, "width", w + "px"); domLib.setStyle(element.style, "height", h + "px"); }, + $getCursorOffsetForHighlight: function (editor) { + var cm = editor.state.cm; + var vim = getVim(cm); + if (!vim.insertMode) { + var isBackwards = editor.session.selection.isBackwards() || editor.session.selection.isEmpty(); + return isBackwards ? 0 : -1; + } + return null; + }, handleKeyboard: function(data, hashId, key, keyCode, e) { var editor = data.editor; var cm = editor.state.cm; From 6f960393ebed764b5abdcb6e4c305fe23fe461be Mon Sep 17 00:00:00 2001 From: mkslanc Date: Sat, 29 Oct 2022 19:06:15 +0400 Subject: [PATCH 0671/1293] add: test for brackets highlighting in vim normal mode; test for common brackets highlighting --- src/keyboard/vim_ace_test.js | 28 ++++++++++++++++++++++++++++ src/virtual_renderer_test.js | 27 +++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/keyboard/vim_ace_test.js b/src/keyboard/vim_ace_test.js index f120f888811..09bcb5e2204 100644 --- a/src/keyboard/vim_ace_test.js +++ b/src/keyboard/vim_ace_test.js @@ -317,6 +317,34 @@ module.exports = { editor.renderer.$loop._flush(); return editor.renderer.scrollTop / editor.renderer.lineHeight; } + }, + "test: vim normal mode brackets highlighting": function () { + editor.setValue("{((hello, world))}"); + editor.focus(); + + var handler = editor.getKeyboardHandler(); + var vimOffsetFunc = handler && handler.$getCursorOffsetForHighlight; + assert.ok(vimOffsetFunc); + var values = [ + {offset: 0, anchorRow: 0, anchorColumn: 0, cursorRow: 0, cursorColumn: 0, + startRow: 0, startColumn: 17, endRow: 0, endColumn: 18}, + {offset: 0, anchorRow: 0, anchorColumn: 2, cursorRow: 0, cursorColumn: 2, + startRow: 0, startColumn: 15, endRow: 0, endColumn: 16}, + {offset: -1, anchorRow: 0, anchorColumn: 15, cursorRow: 0, cursorColumn: 17, + startRow: 0, startColumn: 1, endRow: 0, endColumn: 2}, + {offset: 0, anchorRow: 0, anchorColumn: 17, cursorRow: 0, cursorColumn: 16, + startRow: 0, startColumn: 1, endRow: 0, endColumn: 2} + ]; + values.forEach((el) => { + editor.session.selection.$setSelection(el.anchorRow, el.anchorColumn, el.cursorRow, el.cursorColumn); + var offset = vimOffsetFunc(editor); + assert.ok(offset === el.offset); + var ranges = editor.session.getMatchingBracketRanges({ + row: el.cursorRow, + column: el.cursorColumn + }, offset); + assert.range(ranges[1], el.startRow, el.startColumn, el.endRow, el.endColumn); + }); } }; diff --git a/src/virtual_renderer_test.js b/src/virtual_renderer_test.js index 24b484c0557..c489e4cd389 100644 --- a/src/virtual_renderer_test.js +++ b/src/virtual_renderer_test.js @@ -9,6 +9,7 @@ var Range = require("./range").Range; var Editor = require("./editor").Editor; var EditSession = require("./edit_session").EditSession; var VirtualRenderer = require("./virtual_renderer").VirtualRenderer; +var vim = require("./keyboard/vim"); var assert = require("./test/assertions"); require("./ext/error_marker"); @@ -298,6 +299,32 @@ module.exports = { {x: 6, y: 6, color: "rgba(0, 0, 0, 0)"} ]; assertCoordsColor(values, imageData.data); + }, + "test: brackets highlighting": function (done) { + var renderer = editor.renderer; + editor.session.setValue( + "function Test() {\n" + " function Inner(){\n" + " \n" + " \n" + " }\n" + "}"); + editor.session.selection.$setSelection(1, 21, 1, 21); + renderer.$loop._flush(); + + setTimeout(function () { + assert.ok(editor.session.$bracketHighlight); + assert.range(editor.session.$bracketHighlight.ranges[0], 1, 20, 1, 21); + assert.range(editor.session.$bracketHighlight.ranges[1], 4, 4, 4, 5); + + editor.session.selection.$setSelection(1, 16, 1, 16); + setTimeout(function () { + assert.ok(editor.session.$bracketHighlight == null); + editor.setKeyboardHandler(vim.handler); + editor.session.selection.$setSelection(1, 20, 1, 20); + setTimeout(function () { + assert.ok(editor.session.$bracketHighlight); + assert.range(editor.session.$bracketHighlight.ranges[0], 1, 20, 1, 21); + assert.range(editor.session.$bracketHighlight.ranges[1], 4, 4, 4, 5); + done(); + }, 60); + }, 60); + }, 60); } // change tab size after setDocument (for text layer) From b3b8d485ec85380fcfaa46bfe3889c20f5b8846f Mon Sep 17 00:00:00 2001 From: mkslanc Date: Sun, 30 Oct 2022 16:15:24 +0400 Subject: [PATCH 0672/1293] refactor `getMatchingBracketRanges` --- src/edit_session/bracket_match.js | 26 ++++++++------------------ src/editor.js | 4 ++-- src/keyboard/vim.js | 4 ++-- src/keyboard/vim_ace_test.js | 18 +++++++++--------- 4 files changed, 21 insertions(+), 31 deletions(-) diff --git a/src/edit_session/bracket_match.js b/src/edit_session/bracket_match.js index d0940d4823b..3137e6ab026 100644 --- a/src/edit_session/bracket_match.js +++ b/src/edit_session/bracket_match.js @@ -69,31 +69,21 @@ function BracketMatch() { * * one Range if there is only one bracket * * @param {Point} pos - * @param {number|null} offset + * @param {number|null} side * @returns {null|Range[]} */ - this.getMatchingBracketRanges = function(pos, offset) { + this.getMatchingBracketRanges = function(pos, side) { var line = this.getLine(pos.row); var bracketsRegExp = /([\(\[\{])|([\)\]\}])/; - if (offset != null) { - var chr = line.charAt(pos.column + offset); + var chr = side !== 1 && line.charAt(pos.column - 1); + var match = chr && chr.match(bracketsRegExp); + if (!match) { + chr = side !== 0 && line.charAt(pos.column); pos = { row: pos.row, - column: pos.column + offset + 1 + column: pos.column + 1 }; - var match = chr && chr.match(bracketsRegExp); - } - else { - var chr = line.charAt(pos.column - 1); - var match = chr && chr.match(bracketsRegExp); - if (!match) { - var chr = line.charAt(pos.column); - pos = { - row: pos.row, - column: pos.column + 1 - }; - var match = chr && chr.match(bracketsRegExp); - } + match = chr && chr.match(bracketsRegExp); } if (!match) diff --git a/src/editor.js b/src/editor.js index acabec3702e..dcabf265eff 100644 --- a/src/editor.js +++ b/src/editor.js @@ -508,9 +508,9 @@ Editor.$uid = 0; } var pos = self.getCursorPosition(); var handler = self.getKeyboardHandler(); - var vimOffset = handler && handler.$getCursorOffsetForHighlight && handler.$getCursorOffsetForHighlight( + var side = handler && handler.$getSideForHighlight && handler.$getSideForHighlight( self); - var ranges = session.getMatchingBracketRanges(pos, vimOffset); + var ranges = session.getMatchingBracketRanges(pos, side); if (!ranges) { var iterator = new TokenIterator(session, pos.row, pos.column); diff --git a/src/keyboard/vim.js b/src/keyboard/vim.js index 961d09b2af9..f973f13ffed 100644 --- a/src/keyboard/vim.js +++ b/src/keyboard/vim.js @@ -6985,12 +6985,12 @@ domLib.importCssString(`.normal-mode .ace_cursor{ domLib.setStyle(element.style, "width", w + "px"); domLib.setStyle(element.style, "height", h + "px"); }, - $getCursorOffsetForHighlight: function (editor) { + $getSideForHighlight: function (editor) { var cm = editor.state.cm; var vim = getVim(cm); if (!vim.insertMode) { var isBackwards = editor.session.selection.isBackwards() || editor.session.selection.isEmpty(); - return isBackwards ? 0 : -1; + return isBackwards ? 1 : 0; } return null; }, diff --git a/src/keyboard/vim_ace_test.js b/src/keyboard/vim_ace_test.js index 09bcb5e2204..68077ff2033 100644 --- a/src/keyboard/vim_ace_test.js +++ b/src/keyboard/vim_ace_test.js @@ -323,26 +323,26 @@ module.exports = { editor.focus(); var handler = editor.getKeyboardHandler(); - var vimOffsetFunc = handler && handler.$getCursorOffsetForHighlight; - assert.ok(vimOffsetFunc); + var vimSideFunc = handler && handler.$getSideForHighlight; + assert.ok(vimSideFunc); var values = [ - {offset: 0, anchorRow: 0, anchorColumn: 0, cursorRow: 0, cursorColumn: 0, + {side: 1, anchorRow: 0, anchorColumn: 0, cursorRow: 0, cursorColumn: 0, startRow: 0, startColumn: 17, endRow: 0, endColumn: 18}, - {offset: 0, anchorRow: 0, anchorColumn: 2, cursorRow: 0, cursorColumn: 2, + {side: 1, anchorRow: 0, anchorColumn: 2, cursorRow: 0, cursorColumn: 2, startRow: 0, startColumn: 15, endRow: 0, endColumn: 16}, - {offset: -1, anchorRow: 0, anchorColumn: 15, cursorRow: 0, cursorColumn: 17, + {side: 0, anchorRow: 0, anchorColumn: 15, cursorRow: 0, cursorColumn: 17, startRow: 0, startColumn: 1, endRow: 0, endColumn: 2}, - {offset: 0, anchorRow: 0, anchorColumn: 17, cursorRow: 0, cursorColumn: 16, + {side: 1, anchorRow: 0, anchorColumn: 17, cursorRow: 0, cursorColumn: 16, startRow: 0, startColumn: 1, endRow: 0, endColumn: 2} ]; values.forEach((el) => { editor.session.selection.$setSelection(el.anchorRow, el.anchorColumn, el.cursorRow, el.cursorColumn); - var offset = vimOffsetFunc(editor); - assert.ok(offset === el.offset); + var side = vimSideFunc(editor); + assert.ok(side === el.side); var ranges = editor.session.getMatchingBracketRanges({ row: el.cursorRow, column: el.cursorColumn - }, offset); + }, side); assert.range(ranges[1], el.startRow, el.startColumn, el.endRow, el.endColumn); }); } From 6886b0233e9e1d8d6cce5d3ade7b27fe4527c940 Mon Sep 17 00:00:00 2001 From: Nate Whetsell Date: Mon, 31 Oct 2022 05:22:24 -0400 Subject: [PATCH 0673/1293] fix: Update for Csound 6.18.0 (#4974) --- src/mode/csound_orchestra_highlight_rules.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mode/csound_orchestra_highlight_rules.js b/src/mode/csound_orchestra_highlight_rules.js index f98cd8e0f37..5d261c47612 100644 --- a/src/mode/csound_orchestra_highlight_rules.js +++ b/src/mode/csound_orchestra_highlight_rules.js @@ -368,6 +368,8 @@ var CsoundOrchestraHighlightRules = function(embeddedRulePrefix) { "duserrnd", "dust", "dust2", + "elapsedcycles", + "elapsedtime", "envlpx", "envlpxr", "ephasor", @@ -375,6 +377,8 @@ var CsoundOrchestraHighlightRules = function(embeddedRulePrefix) { "evalstr", "event", "event_i", + "eventcycles", + "eventtime", "exciter", "exitnow", "exp", @@ -1277,6 +1281,7 @@ var CsoundOrchestraHighlightRules = function(embeddedRulePrefix) { "seqtime", "seqtime2", "sequ", + "sequstate", "serialBegin", "serialEnd", "serialFlush", From 2b8236eaf1df10caa9ff45a06902df14947cd968 Mon Sep 17 00:00:00 2001 From: Parker Mauney Date: Mon, 31 Oct 2022 05:32:31 -0400 Subject: [PATCH 0674/1293] Fix: update/add missing demo samples (#4975) * Rename unmatched demo samples + Remove nix override thing * Add undeclared impls to modelist * Backfill samples for django, txt, mips --- demo/kitchen-sink/doclist.js | 1 - demo/kitchen-sink/docs/django.html | 7 +++++++ .../docs/{fortran.f90 => fortran.f} | 0 demo/kitchen-sink/docs/{Haxe.hx => haxe.hx} | 0 .../kitchen-sink/docs/{Jack.jack => jack.jack} | 0 demo/kitchen-sink/docs/mips.s | 18 ++++++++++++++++++ demo/kitchen-sink/docs/{Nix.nix => nix.nix} | 0 demo/kitchen-sink/docs/text.txt | 9 +++++++++ src/ext/modelist.js | 3 +++ 9 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 demo/kitchen-sink/docs/django.html rename demo/kitchen-sink/docs/{fortran.f90 => fortran.f} (100%) rename demo/kitchen-sink/docs/{Haxe.hx => haxe.hx} (100%) rename demo/kitchen-sink/docs/{Jack.jack => jack.jack} (100%) create mode 100644 demo/kitchen-sink/docs/mips.s rename demo/kitchen-sink/docs/{Nix.nix => nix.nix} (100%) create mode 100644 demo/kitchen-sink/docs/text.txt diff --git a/demo/kitchen-sink/doclist.js b/demo/kitchen-sink/doclist.js index b5f00b941f5..2ca6a81c468 100644 --- a/demo/kitchen-sink/doclist.js +++ b/demo/kitchen-sink/doclist.js @@ -48,7 +48,6 @@ var docs = { "docs/c9search.c9search_results": "C9 Search Results", "docs/mel.mel": "MEL", - "docs/Nix.nix": "Nix" }; var ownSource = { diff --git a/demo/kitchen-sink/docs/django.html b/demo/kitchen-sink/docs/django.html new file mode 100644 index 00000000000..936afb3a5da --- /dev/null +++ b/demo/kitchen-sink/docs/django.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block title %}Ace Django Template{% endblock %} + +{% block content %} +

    Hello, {{ name|default:"World" }}!

    +{% endblock %} diff --git a/demo/kitchen-sink/docs/fortran.f90 b/demo/kitchen-sink/docs/fortran.f similarity index 100% rename from demo/kitchen-sink/docs/fortran.f90 rename to demo/kitchen-sink/docs/fortran.f diff --git a/demo/kitchen-sink/docs/Haxe.hx b/demo/kitchen-sink/docs/haxe.hx similarity index 100% rename from demo/kitchen-sink/docs/Haxe.hx rename to demo/kitchen-sink/docs/haxe.hx diff --git a/demo/kitchen-sink/docs/Jack.jack b/demo/kitchen-sink/docs/jack.jack similarity index 100% rename from demo/kitchen-sink/docs/Jack.jack rename to demo/kitchen-sink/docs/jack.jack diff --git a/demo/kitchen-sink/docs/mips.s b/demo/kitchen-sink/docs/mips.s new file mode 100644 index 00000000000..ec4f0091975 --- /dev/null +++ b/demo/kitchen-sink/docs/mips.s @@ -0,0 +1,18 @@ +# Original source from https://eng.libretexts.org +# Kann, Charles W., "Introduction To MIPS Assembly Language Programming" (2015). Open Textbooks. 2. +# https://cupola.gettysburg.edu/oer/2 + +# Program File: Program2-1.asm +# Author: Charles Kann +# Purpose: First program, Hello World +.text # Define the program instructions. +main: # Label to define the main program. + li $v0,4 # Load 4 into $v0 to indicate a print string. + la $a0, greeting # Load the address of the greeting into $a0. + syscall # Print greeting. The print is indicated by + # $v0 having a value of 4, and the string to + # print is stored at the address in $a0. + li $v0, 10 # Load a 10 (halt) into $v0. + syscall # The program ends. +.data # Define the program data. +greeting: .asciiz "Hello World" #The string to print. diff --git a/demo/kitchen-sink/docs/Nix.nix b/demo/kitchen-sink/docs/nix.nix similarity index 100% rename from demo/kitchen-sink/docs/Nix.nix rename to demo/kitchen-sink/docs/nix.nix diff --git a/demo/kitchen-sink/docs/text.txt b/demo/kitchen-sink/docs/text.txt new file mode 100644 index 00000000000..991a5d70146 --- /dev/null +++ b/demo/kitchen-sink/docs/text.txt @@ -0,0 +1,9 @@ +This is just some text! + +// These + # are + -- not + + (but indent actions work) + +This is just some text! diff --git a/src/ext/modelist.js b/src/ext/modelist.js index 8d0517db3cd..c95bb54937b 100644 --- a/src/ext/modelist.js +++ b/src/ext/modelist.js @@ -127,6 +127,7 @@ var supportedModes = { LiveScript: ["ls"], Log: ["log"], LogiQL: ["logic|lql"], + Logtalk: ["lgt"], LSL: ["lsl"], Lua: ["lua"], LuaPage: ["lp"], @@ -190,6 +191,7 @@ var supportedModes = { snippets: ["snippets"], Soy_Template:["soy"], Space: ["space"], + SPARQL: ["rq"], SQL: ["sql"], SQLServer: ["sqlserver"], Stylus: ["styl|stylus"], @@ -202,6 +204,7 @@ var supportedModes = { Textile: ["textile"], Toml: ["toml"], TSX: ["tsx"], + Turtle: ["ttl"], Twig: ["twig|swig"], Typescript: ["ts|typescript|str"], Vala: ["vala"], From 2b6392046c042e0b2d66d6291281919d27275a30 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Mon, 31 Oct 2022 11:41:35 +0100 Subject: [PATCH 0675/1293] release v1.12.4 --- CHANGELOG.md | 9 +++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 762065836bf..354282365cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.12.4](https://github.com/ajaxorg/ace/compare/v1.12.3...v1.12.4) (2022-10-31) + + +### Bug Fixes + +* Open valid url under cursor ([#4970](https://github.com/ajaxorg/ace/issues/4970)) ([bf2913a](https://github.com/ajaxorg/ace/commit/bf2913a71624e94d13727115b2aa0ef0c279c89f)) +* Update for Csound 6.18.0 ([#4974](https://github.com/ajaxorg/ace/issues/4974)) ([6886b02](https://github.com/ajaxorg/ace/commit/6886b0233e9e1d8d6cce5d3ade7b27fe4527c940)) +* update/add missing demo samples ([#4975](https://github.com/ajaxorg/ace/issues/4975)) ([2b8236e](https://github.com/ajaxorg/ace/commit/2b8236eaf1df10caa9ff45a06902df14947cd968)) + ### [1.12.3](https://github.com/ajaxorg/ace/compare/v1.12.2...v1.12.3) (2022-10-18) diff --git a/build b/build index 5f6080166fc..7896f6f8e6e 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 5f6080166fcc3142ad36f272834d4f9f98d34866 +Subproject commit 7896f6f8e6e93531da9d8f46c24fbc2aa256a78f diff --git a/package.json b/package.json index f48e471ee01..14f29161062 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.12.3", + "version": "1.12.4", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index a529567e9dd..010b8215d80 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.12.3"; +exports.version = "1.12.4"; From 62986b39433047e9013f2620fe48c13d83f7875d Mon Sep 17 00:00:00 2001 From: mkslanc Date: Mon, 31 Oct 2022 18:30:38 +0400 Subject: [PATCH 0676/1293] better `getMatchingBracketRanges` param type (`isBackwards` - optional `boolean`) --- src/edit_session/bracket_match.js | 8 ++++---- src/editor.js | 5 ++--- src/keyboard/vim.js | 6 ++---- src/keyboard/vim_ace_test.js | 18 +++++++++--------- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/edit_session/bracket_match.js b/src/edit_session/bracket_match.js index 3137e6ab026..3dfe05897cb 100644 --- a/src/edit_session/bracket_match.js +++ b/src/edit_session/bracket_match.js @@ -69,16 +69,16 @@ function BracketMatch() { * * one Range if there is only one bracket * * @param {Point} pos - * @param {number|null} side + * @param {boolean} [isBackwards] * @returns {null|Range[]} */ - this.getMatchingBracketRanges = function(pos, side) { + this.getMatchingBracketRanges = function(pos, isBackwards) { var line = this.getLine(pos.row); var bracketsRegExp = /([\(\[\{])|([\)\]\}])/; - var chr = side !== 1 && line.charAt(pos.column - 1); + var chr = !isBackwards && line.charAt(pos.column - 1); var match = chr && chr.match(bracketsRegExp); if (!match) { - chr = side !== 0 && line.charAt(pos.column); + chr = (isBackwards === undefined || isBackwards) && line.charAt(pos.column); pos = { row: pos.row, column: pos.column + 1 diff --git a/src/editor.js b/src/editor.js index dcabf265eff..b3cc65f0d22 100644 --- a/src/editor.js +++ b/src/editor.js @@ -508,9 +508,8 @@ Editor.$uid = 0; } var pos = self.getCursorPosition(); var handler = self.getKeyboardHandler(); - var side = handler && handler.$getSideForHighlight && handler.$getSideForHighlight( - self); - var ranges = session.getMatchingBracketRanges(pos, side); + var isBackwards = handler && handler.$getDirectionForHighlight && handler.$getDirectionForHighlight(self); + var ranges = session.getMatchingBracketRanges(pos, isBackwards); if (!ranges) { var iterator = new TokenIterator(session, pos.row, pos.column); diff --git a/src/keyboard/vim.js b/src/keyboard/vim.js index f973f13ffed..a37760ec2ee 100644 --- a/src/keyboard/vim.js +++ b/src/keyboard/vim.js @@ -6985,14 +6985,12 @@ domLib.importCssString(`.normal-mode .ace_cursor{ domLib.setStyle(element.style, "width", w + "px"); domLib.setStyle(element.style, "height", h + "px"); }, - $getSideForHighlight: function (editor) { + $getDirectionForHighlight: function (editor) { var cm = editor.state.cm; var vim = getVim(cm); if (!vim.insertMode) { - var isBackwards = editor.session.selection.isBackwards() || editor.session.selection.isEmpty(); - return isBackwards ? 1 : 0; + return editor.session.selection.isBackwards() || editor.session.selection.isEmpty(); } - return null; }, handleKeyboard: function(data, hashId, key, keyCode, e) { var editor = data.editor; diff --git a/src/keyboard/vim_ace_test.js b/src/keyboard/vim_ace_test.js index 68077ff2033..0b1dd140ef4 100644 --- a/src/keyboard/vim_ace_test.js +++ b/src/keyboard/vim_ace_test.js @@ -323,26 +323,26 @@ module.exports = { editor.focus(); var handler = editor.getKeyboardHandler(); - var vimSideFunc = handler && handler.$getSideForHighlight; - assert.ok(vimSideFunc); + var vimDirectionFunc = handler && handler.$getDirectionForHighlight; + assert.ok(vimDirectionFunc); var values = [ - {side: 1, anchorRow: 0, anchorColumn: 0, cursorRow: 0, cursorColumn: 0, + {isBackwards: true, anchorRow: 0, anchorColumn: 0, cursorRow: 0, cursorColumn: 0, startRow: 0, startColumn: 17, endRow: 0, endColumn: 18}, - {side: 1, anchorRow: 0, anchorColumn: 2, cursorRow: 0, cursorColumn: 2, + {isBackwards: true, anchorRow: 0, anchorColumn: 2, cursorRow: 0, cursorColumn: 2, startRow: 0, startColumn: 15, endRow: 0, endColumn: 16}, - {side: 0, anchorRow: 0, anchorColumn: 15, cursorRow: 0, cursorColumn: 17, + {isBackwards: false, anchorRow: 0, anchorColumn: 15, cursorRow: 0, cursorColumn: 17, startRow: 0, startColumn: 1, endRow: 0, endColumn: 2}, - {side: 1, anchorRow: 0, anchorColumn: 17, cursorRow: 0, cursorColumn: 16, + {isBackwards: true, anchorRow: 0, anchorColumn: 17, cursorRow: 0, cursorColumn: 16, startRow: 0, startColumn: 1, endRow: 0, endColumn: 2} ]; values.forEach((el) => { editor.session.selection.$setSelection(el.anchorRow, el.anchorColumn, el.cursorRow, el.cursorColumn); - var side = vimSideFunc(editor); - assert.ok(side === el.side); + var isBackwards = vimDirectionFunc(editor); + assert.ok(isBackwards === el.isBackwards); var ranges = editor.session.getMatchingBracketRanges({ row: el.cursorRow, column: el.cursorColumn - }, side); + }, isBackwards); assert.range(ranges[1], el.startRow, el.startColumn, el.endRow, el.endColumn); }); } From 987ab7602e06acc9b08c75914f5c1335d5cdc8cc Mon Sep 17 00:00:00 2001 From: Ani Amirjanyan <56698448+anijanyan@users.noreply.github.com> Date: Mon, 31 Oct 2022 21:00:21 +0400 Subject: [PATCH 0677/1293] fix: enableLiveAutocompletion documentation (#4976) * some typings fixed * enableLiveAutocompletion documentation fixed --- ace.d.ts | 6 +++++- src/ext/language_tools.js | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index 186c3af4731..4509ca29e2f 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -397,6 +397,10 @@ export namespace Ace { canRedo(): boolean; bookmark(rev?: number): void; isAtBookmark(): boolean; + hasUndo(): boolean; + hasRedo(): boolean; + isClean(): boolean; + markClean(rev?: number): void; } export interface Position { @@ -459,7 +463,7 @@ export namespace Ace { inFront?: boolean): number; addDynamicMarker(marker: MarkerLike, inFront: boolean): MarkerLike; removeMarker(markerId: number): void; - getMarkers(inFront?: boolean): MarkerLike[]; + getMarkers(inFront?: boolean): {[id: number]: MarkerLike}; highlight(re: RegExp): void; highlightLines(startRow: number, endRow: number, diff --git a/src/ext/language_tools.js b/src/ext/language_tools.js index 2cfa7bb831c..943e4af9b1e 100644 --- a/src/ext/language_tools.js +++ b/src/ext/language_tools.js @@ -162,10 +162,12 @@ require("../config").defineOptions(Editor.prototype, "editor", { value: false }, /** - * Enable live autocomplete. If the value is an array, it is assumed to be an array of completers - * and will use them instead of the default completers. + * Enable live autocompletion */ enableLiveAutocompletion: { + /** + * @param {boolean} val + */ set: function(val) { if (val) { if (!this.completers) From 0c49167c302ab80f55b5d97a6c36ccda9d27c07f Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Tue, 1 Nov 2022 10:49:17 +0100 Subject: [PATCH 0678/1293] release v1.12.5 --- CHANGELOG.md | 8 ++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 354282365cc..d3b44b34990 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.12.5](https://github.com/ajaxorg/ace/compare/v1.12.4...v1.12.5) (2022-11-01) + + +### Bug Fixes + +* enableLiveAutocompletion documentation ([#4976](https://github.com/ajaxorg/ace/issues/4976)) ([987ab76](https://github.com/ajaxorg/ace/commit/987ab7602e06acc9b08c75914f5c1335d5cdc8cc)) +* vim "normal" mode brackets highlighting ([0fbc54c](https://github.com/ajaxorg/ace/commit/0fbc54cc5130b0271928995660413ba0fab678cb)) + ### [1.12.4](https://github.com/ajaxorg/ace/compare/v1.12.3...v1.12.4) (2022-10-31) diff --git a/build b/build index 7896f6f8e6e..051fceb2fb8 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 7896f6f8e6e93531da9d8f46c24fbc2aa256a78f +Subproject commit 051fceb2fb874da0d6d071f972d2a4a1e6234a9d diff --git a/package.json b/package.json index 14f29161062..b674f01c988 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.12.4", + "version": "1.12.5", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 010b8215d80..e1848cf7314 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.12.4"; +exports.version = "1.12.5"; From 4e8926ef9f9207e57529e07cdbe2305b09e712e2 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Wed, 2 Nov 2022 19:57:55 +0400 Subject: [PATCH 0679/1293] feat: add highlight mode for Apache JEXL (#4979) --- demo/kitchen-sink/docs/jexl.jexl | 20 ++++ src/ext/modelist.js | 1 + src/mode/_test/tokens_jexl.json | 156 +++++++++++++++++++++++++++++++ src/mode/jexl.js | 23 +++++ src/mode/jexl_highlight_rules.js | 138 +++++++++++++++++++++++++++ 5 files changed, 338 insertions(+) create mode 100644 demo/kitchen-sink/docs/jexl.jexl create mode 100644 src/mode/_test/tokens_jexl.json create mode 100644 src/mode/jexl.js create mode 100644 src/mode/jexl_highlight_rules.js diff --git a/demo/kitchen-sink/docs/jexl.jexl b/demo/kitchen-sink/docs/jexl.jexl new file mode 100644 index 00000000000..6e1c33e1b97 --- /dev/null +++ b/demo/kitchen-sink/docs/jexl.jexl @@ -0,0 +1,20 @@ +#pragma execution.option 42 + +## +## This is a test script +## + +/* This is +a multi-line +comment +*/ +if (out != null and result == null) out.println("The result is " + result); +x = ~/\w+\/test/; +y = 2; +result = x * y + 5; +if (out != null) out.println("The result is " + result); + +@lenient @silent x.someMethod(); + +`multi-line string +with ${var interpolation = "Hey!"} and \escap\u00E9 chars` diff --git a/src/ext/modelist.js b/src/ext/modelist.js index c95bb54937b..9a91896114a 100644 --- a/src/ext/modelist.js +++ b/src/ext/modelist.js @@ -111,6 +111,7 @@ var supportedModes = { Jade: ["jade|pug"], Java: ["java"], JavaScript: ["js|jsm|jsx|cjs|mjs"], + JEXL: ["jexl"], JSON: ["json"], JSON5: ["json5"], JSONiq: ["jq"], diff --git a/src/mode/_test/tokens_jexl.json b/src/mode/_test/tokens_jexl.json new file mode 100644 index 00000000000..9abf21d9bff --- /dev/null +++ b/src/mode/_test/tokens_jexl.json @@ -0,0 +1,156 @@ +[[ + "start", + ["comment","#pragma"], + ["text"," execution.option 42"] +],[ + "start" +],[ + "start", + ["comment","##"] +],[ + "start", + ["comment","## This is a test script"] +],[ + "start", + ["comment","##"] +],[ + "start" +],[ + "comment", + ["comment","/* This is"] +],[ + "comment", + ["comment","a multi-line"] +],[ + "comment", + ["comment","comment"] +],[ + "start", + ["comment","*/"] +],[ + "start", + ["keyword","if"], + ["text"," "], + ["lparen","("], + ["identifier","out"], + ["text"," "], + ["keyword.operator","!="], + ["text"," "], + ["constant.language","null"], + ["text"," "], + ["keyword","and"], + ["text"," "], + ["identifier","result"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["constant.language","null"], + ["rparen",")"], + ["text"," "], + ["identifier","out"], + ["punctuation","."], + ["identifier","println"], + ["lparen","("], + ["string","\"The result is \""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["identifier","result"], + ["rparen",")"], + ["text",";"] +],[ + "start", + ["identifier","x"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.regexp","~/\\w+"], + ["constant.language.escape","\\/"], + ["string.regexp","test/"], + ["text",";"] +],[ + "start", + ["identifier","y"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","2"], + ["text",";"] +],[ + "start", + ["identifier","result"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["identifier","y"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","5"], + ["text",";"] +],[ + "start", + ["keyword","if"], + ["text"," "], + ["lparen","("], + ["identifier","out"], + ["text"," "], + ["keyword.operator","!="], + ["text"," "], + ["constant.language","null"], + ["rparen",")"], + ["text"," "], + ["identifier","out"], + ["punctuation","."], + ["identifier","println"], + ["lparen","("], + ["string","\"The result is \""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["identifier","result"], + ["rparen",")"], + ["text",";"] +],[ + "start" +],[ + "start", + ["storage.type.annotation","@lenient"], + ["text"," "], + ["storage.type.annotation","@silent"], + ["text"," "], + ["identifier","x"], + ["punctuation","."], + ["identifier","someMethod"], + ["lparen","("], + ["rparen",")"], + ["text",";"] +],[ + "start" +],[ + "string", + ["string","`multi-line string"] +],[ + "start", + ["string","with "], + ["lparen","${"], + ["keyword","var"], + ["text"," "], + ["identifier","interpolation"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"Hey!\""], + ["rparen","}"], + ["string"," and "], + ["constant.language.escape","\\"], + ["string","escap"], + ["constant.language.escape","\\u00E9"], + ["string"," chars`"] +],[ + "start" +]] \ No newline at end of file diff --git a/src/mode/jexl.js b/src/mode/jexl.js new file mode 100644 index 00000000000..1e3e234c808 --- /dev/null +++ b/src/mode/jexl.js @@ -0,0 +1,23 @@ +"use strict"; + +var oop = require("../lib/oop"); +var JexlHighlightRules = require("./jexl_highlight_rules").JexlHighlightRules; +var TextMode = require("./text").Mode; +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function () { + this.HighlightRules = JexlHighlightRules; + this.$behaviour = new CstyleBehaviour(); + this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function () { + this.lineCommentStart = ["//", "##"]; + this.blockComment = {start: "/*", end: "*/"}; + + this.$id = "ace/mode/jexl"; +}).call(Mode.prototype); + +exports.Mode = Mode; diff --git a/src/mode/jexl_highlight_rules.js b/src/mode/jexl_highlight_rules.js new file mode 100644 index 00000000000..03f6c4fbf59 --- /dev/null +++ b/src/mode/jexl_highlight_rules.js @@ -0,0 +1,138 @@ +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var JexlHighlightRules = function () { + + var keywords = "return|var|function|and|or|not|if|for|while|do|continue|break"; + var buildinConstants = "null"; + var supportFunc = "empty|size|new"; + + var keywordMapper = this.createKeywordMapper({ + "keyword": keywords, + "constant.language": buildinConstants, + "support.function": supportFunc + }, "identifier"); + + var escapedRe = "\\\\(?:x[0-9a-fA-F]{2}|" + // hex + "u[0-9a-fA-F]{4}|" + // unicode + "u{[0-9a-fA-F]{1,6}}|" + // es6 unicode + "|.)"; + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + "start": [ + { + token: "comment", + regex: "\\/\\/.*$" + }, { + token: "comment", + regex: "##.*$" + }, { + token: "comment", // multi line comment + regex: "\\/\\*", + next: "comment" + }, { + token: ["comment", "text"], + regex: "(#pragma)(\\s.*$)" + }, { + token: "string", // single line + regex: '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' + }, { + token: "string", // single line + regex: "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" + }, { + token: "string", // multi line string + regex: "`", + push: [ + { + token: "constant.language.escape", + regex: escapedRe + }, { + token: "string", + regex: "`", + next: "pop" + }, { + token: "lparen", //interpolation + regex: "\\${", + push: [ + { + token: "rparen", + regex: "}", + next: "pop" + }, { + include: "start" + } + ] + }, { + defaultToken: "string" + } + ] + }, { + token: "constant.numeric", // hex + regex: /0(?:[xX][0-9a-fA-F][0-9a-fA-F_]*|[bB][01][01_]*)[LlSsDdFfYy]?\b/ + }, { + token: "constant.numeric", // float + regex: /[+-]?\d[\d_]*(?:(?:\.[\d_]*)?(?:[eE][+-]?[\d_]+)?)?[LlSsDdFfYy]?\b/ + }, { + token: "constant.language.boolean", + regex: "(?:true|false)\\b" + }, { + token: "string.regexp", + regex: "~/", + push: [ + { + token: "constant.language.escape", + regex: "\\\\/" + }, { + token: "string.regexp", + regex: "$|/", + next: "pop" + }, { + defaultToken: "string.regexp" + } + ] + }, { + token: keywordMapper, + regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token: "keyword.operator", + regex: "&&|\\|\\||!|&|\\||\\^|~|\\?|:|\\?\\?|==|!=|<|<=|>|>=|=~|!~|=\\^|=\\$|!\\$|\\+|\\-|\\*|%|\\/|=" + }, { + token: "lparen", + regex: "[[({]" + }, { + token: "rparen", + regex: "[\\])}]" + }, { + token: "text", + regex: "\\s+" + }, { + token: "punctuation", + regex: "[,.]" + }, { + token: "storage.type.annotation", + regex: "@[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + } + ], + "comment": [ + { + token: "comment", + regex: "\\*\\/", + next: "start" + }, { + defaultToken: "comment" + } + ] + }; + + + this.normalizeRules(); +}; + +oop.inherits(JexlHighlightRules, TextHighlightRules); + +exports.JexlHighlightRules = JexlHighlightRules; From df441585ef44e17a027141e3ceed648e104e9cf9 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Fri, 4 Nov 2022 14:14:10 +0400 Subject: [PATCH 0680/1293] fix: rare case when document passed to `dom.scrollbarWidth` doesn't have `documentElement` (#4981) --- src/ace_test.js | 14 ++++++++++++++ src/lib/dom.js | 10 ++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/ace_test.js b/src/ace_test.js index af65146019b..fa9462e01e8 100644 --- a/src/ace_test.js +++ b/src/ace_test.js @@ -101,6 +101,20 @@ module.exports = { ace.config.set("useStrictCSP", false); assert.ok(getStyleNode()); + }, + "test: edit template" : function() { + var template = document.createElement("template"); + var div = document.createElement("div"); + template.content = document.createDocumentFragment(); + template.content.appendChild(div); + var fragment = template.content.cloneNode(true); + var el = fragment.firstChild; + //emulating template content document fragment behaviour in browser + //which cause #4634 issue (virtual Document that doesn't have `documentElement`) + el.ownerDocument = {}; + var editor = ace.edit(el); + assert.equal(editor.container, el); + editor.destroy(); } }; diff --git a/src/lib/dom.js b/src/lib/dom.js index 26ae1f6e2e1..fc3125fa490 100644 --- a/src/lib/dom.js +++ b/src/lib/dom.js @@ -217,7 +217,7 @@ exports.importCssString = importCssString; exports.importCssStylsheet = function(uri, doc) { exports.buildDom(["link", {rel: "stylesheet", href: uri}], exports.getDocumentHead(doc)); }; -exports.scrollbarWidth = function(document) { +exports.scrollbarWidth = function(doc) { var inner = exports.createElement("ace_inner"); inner.style.width = "100%"; inner.style.minWidth = "0px"; @@ -237,7 +237,9 @@ exports.scrollbarWidth = function(document) { outer.appendChild(inner); - var body = document.documentElement; + var body = (doc && doc.documentElement) || (document && document.documentElement); + if (!body) return 0; + body.appendChild(outer); var noScrollbar = inner.offsetWidth; @@ -245,13 +247,13 @@ exports.scrollbarWidth = function(document) { style.overflow = "scroll"; var withScrollbar = inner.offsetWidth; - if (noScrollbar == withScrollbar) { + if (noScrollbar === withScrollbar) { withScrollbar = outer.clientWidth; } body.removeChild(outer); - return noScrollbar-withScrollbar; + return noScrollbar - withScrollbar; }; exports.computedStyle = function(element, style) { From 19dd2ecc178bef2fedd6a53900f2db58ea7a3c23 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Mon, 7 Nov 2022 20:02:28 +0400 Subject: [PATCH 0681/1293] fix: Add missing options to `VirtualRendererOptions` and `EditorOptions` (#4983) --- ace.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ace.d.ts b/ace.d.ts index 4509ca29e2f..5c12afb81d5 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -180,6 +180,7 @@ export namespace Ace { showFoldWidgets: boolean; showLineNumbers: boolean; displayIndentGuides: boolean; + highlightIndentGuides: boolean; highlightGutterLine: boolean; hScrollBarAlwaysVisible: boolean; vScrollBarAlwaysVisible: boolean; @@ -189,6 +190,7 @@ export namespace Ace { minLines: number; scrollPastEnd: boolean; fixedWidthGutter: boolean; + customScrollbar: boolean; theme: string; hasCssTransforms: boolean; maxPixelHeight: number; @@ -220,6 +222,7 @@ export namespace Ace { placeholder: string; value: string; session: EditSession; + relativeLineNumbers: boolean; } export interface SearchOptions { From 794fef33e4a97e7335e58f5f6c49c6f219b1de53 Mon Sep 17 00:00:00 2001 From: Piotr Duperas Date: Thu, 10 Nov 2022 01:33:26 +0100 Subject: [PATCH 0682/1293] #4987 - Fix for '-' keybinding in Vim in Firefox --- src/lib/keys.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/keys.js b/src/lib/keys.js index ffc9c1d7476..527bc35c9d6 100644 --- a/src/lib/keys.js +++ b/src/lib/keys.js @@ -108,6 +108,9 @@ var Keys = (function() { } }; + // workaround for firefox bug + ret.PRINTABLE_KEYS[173] = '-'; + // A reverse map of FUNCTION_KEYS var name, i; for (i in ret.FUNCTION_KEYS) { @@ -131,9 +134,6 @@ var Keys = (function() { ret.enter = ret["return"]; ret.escape = ret.esc; ret.del = ret["delete"]; - - // workaround for firefox bug - ret[173] = '-'; (function() { var mods = ["cmd", "ctrl", "alt", "shift"]; From 0092f3f8c1f0d9c8a0b8bebe58cc3517931697b7 Mon Sep 17 00:00:00 2001 From: Piotr Duperas <49131852+piotrduperas@users.noreply.github.com> Date: Fri, 11 Nov 2022 12:27:24 +0100 Subject: [PATCH 0683/1293] fix: Fix of scroll while interrupting animation (#4993) --- src/virtual_renderer.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 0410051ba5d..e0642c51c5b 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -1232,6 +1232,10 @@ var VirtualRenderer = function(container, theme) { var topMargin = $viewMargin && $viewMargin.top || 0; var bottomMargin = $viewMargin && $viewMargin.bottom || 0; + + if (this.$scrollAnimation) { + this.$stopAnimation = true; + } var scrollTop = this.$scrollAnimation ? this.session.getScrollTop() : this.scrollTop; @@ -1378,7 +1382,20 @@ var VirtualRenderer = function(container, theme) { _self.session.setScrollTop(steps.shift()); // trick session to think it's already scrolled to not loose toValue _self.session.$scrollTop = toValue; + + function endAnimation() { + _self.$timer = clearInterval(_self.$timer); + _self.$scrollAnimation = null; + _self.$stopAnimation = false; + callback && callback(); + } + this.$timer = setInterval(function() { + if (_self.$stopAnimation) { + endAnimation(); + return; + } + if (!_self.session) return clearInterval(_self.$timer); if (steps.length) { @@ -1390,9 +1407,7 @@ var VirtualRenderer = function(container, theme) { toValue = null; } else { // do this on separate step to not get spurious scroll event from scrollbar - _self.$timer = clearInterval(_self.$timer); - _self.$scrollAnimation = null; - callback && callback(); + endAnimation(); } }, 10); }; From 28103d4690eac107cfd50c315da37a4ec10c18bb Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Fri, 11 Nov 2022 12:33:49 +0100 Subject: [PATCH 0684/1293] release v1.13.0 --- CHANGELOG.md | 14 ++++++++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3b44b34990..ebb84af1a96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.13.0](https://github.com/ajaxorg/ace/compare/v1.12.5...v1.13.0) (2022-11-11) + + +### Features + +* add highlight mode for Apache JEXL ([#4979](https://github.com/ajaxorg/ace/issues/4979)) ([4e8926e](https://github.com/ajaxorg/ace/commit/4e8926ef9f9207e57529e07cdbe2305b09e712e2)) + + +### Bug Fixes + +* Add missing options to `VirtualRendererOptions` and `EditorOptions` ([#4983](https://github.com/ajaxorg/ace/issues/4983)) ([19dd2ec](https://github.com/ajaxorg/ace/commit/19dd2ecc178bef2fedd6a53900f2db58ea7a3c23)) +* Fix of scroll while interrupting animation ([#4993](https://github.com/ajaxorg/ace/issues/4993)) ([0092f3f](https://github.com/ajaxorg/ace/commit/0092f3f8c1f0d9c8a0b8bebe58cc3517931697b7)) +* rare case when document passed to `dom.scrollbarWidth` doesn't have `documentElement` ([#4981](https://github.com/ajaxorg/ace/issues/4981)) ([df44158](https://github.com/ajaxorg/ace/commit/df441585ef44e17a027141e3ceed648e104e9cf9)) + ### [1.12.5](https://github.com/ajaxorg/ace/compare/v1.12.4...v1.12.5) (2022-11-01) diff --git a/build b/build index 051fceb2fb8..5795b1bd397 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 051fceb2fb874da0d6d071f972d2a4a1e6234a9d +Subproject commit 5795b1bd397a75229eec61f5dc847a03e74f7e30 diff --git a/package.json b/package.json index b674f01c988..7fbb1bc8a41 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.12.5", + "version": "1.13.0", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index e1848cf7314..d02a3f9731a 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.12.5"; +exports.version = "1.13.0"; From ecf56b00e708ad97ec5e44429e322bb7891968db Mon Sep 17 00:00:00 2001 From: Bill Yosafat Date: Mon, 26 Oct 2020 17:14:08 +0700 Subject: [PATCH 0685/1293] added ES6 default parameters states --- src/mode/javascript_highlight_rules.js | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/mode/javascript_highlight_rules.js b/src/mode/javascript_highlight_rules.js index 0fb341484a3..e898abab4f1 100644 --- a/src/mode/javascript_highlight_rules.js +++ b/src/mode/javascript_highlight_rules.js @@ -274,10 +274,43 @@ var JavaScriptHighlightRules = function(options) { defaultToken: "string.regexp.charachterclass" } ], + "default_parameter": [ + { + token : "string", + regex : "'(?=.)" + }, { + token : "string", + regex : '"(?=.)' + }, { + token : "constant.language", + regex : "null|Infinity|NaN|undefined" + }, { + token : "constant.numeric", // hexadecimal, octal and binary + regex : /0(?:[xX][0-9a-fA-F]+|[oO][0-7]+|[bB][01]+)\b/ + }, { + token : "constant.numeric", // decimal integers and floats + regex : /(?:\d\d*(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+\b)?/ + }, { + token: "punctuation.operator", + regex: "[, ]+", + next: "function_arguments" + }, { + token: "punctuation.operator", + regex: "$" + }, { + token: "empty", + regex: "", + next: "no_regex" + } + ], "function_arguments": [ { token: "variable.parameter", regex: identifierRe + }, { + token : "keyword.operator", + regex : "[= ]+", + next : "default_parameter" }, { token: "punctuation.operator", regex: "[, ]+" From 2760234d3d8d1acba72a42df7763482655af5ebc Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Wed, 16 Nov 2022 15:15:53 +0400 Subject: [PATCH 0686/1293] fix: Change curly braces insertion behavior for Markdown to act the same as for other braces (#4994) --- src/mode/markdown.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mode/markdown.js b/src/mode/markdown.js index f2a067ebb72..3aab4155074 100644 --- a/src/mode/markdown.js +++ b/src/mode/markdown.js @@ -1,10 +1,8 @@ "use strict"; var oop = require("../lib/oop"); +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; var TextMode = require("./text").Mode; -var JavaScriptMode = require("./javascript").Mode; -var XmlMode = require("./xml").Mode; -var HtmlMode = require("./html").Mode; var MarkdownHighlightRules = require("./markdown_highlight_rules").MarkdownHighlightRules; var MarkdownFoldMode = require("./folding/markdown").FoldMode; @@ -21,7 +19,7 @@ var Mode = function() { }); this.foldingRules = new MarkdownFoldMode(); - this.$behaviour = this.$defaultBehaviour; + this.$behaviour = new CstyleBehaviour({ braces: true }); }; oop.inherits(Mode, TextMode); From e57a9d9eef0c056cd38a07c77c460bea39cc9551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Oliveira?= Date: Wed, 16 Nov 2022 11:19:42 +0000 Subject: [PATCH 0687/1293] fix: incorrect cursor position for very long lines (#4996) * fix: incorrect cursor position for very long lines * fix: styling --- src/ext/static_highlight_test.js | 14 +++---- src/layer/font_metrics.js | 66 ++++++++++++++++++-------------- src/layer/text.js | 49 ++++++++++++++++-------- src/layer/text_test.js | 18 ++++----- src/virtual_renderer.js | 2 +- 5 files changed, 88 insertions(+), 61 deletions(-) diff --git a/src/ext/static_highlight_test.js b/src/ext/static_highlight_test.js index 7b0a9e1adb7..025eb1a369c 100644 --- a/src/ext/static_highlight_test.js +++ b/src/ext/static_highlight_test.js @@ -39,15 +39,15 @@ module.exports = { ].join("\n"); var mode = new JavaScriptMode(); var result = highlighter.render(snippet, mode, theme); - assert.equal(result.html, "
    " + assert.equal(result.html, "
    " + "
    /** this is a function\n
    " + "
    *\n
    " + "
    */\n
    " + "
    \n
    " - + "
    function hello (a, b, c) {\n
    " - + "
    console.log(a * b + c + 'sup$');\n
    " - + "
    //\n
    " - + "
    //\n
    " + + "
    function hello (a, b, c) {\n
    " + + "
    console.log(a * b + c + 'sup$');\n
    " + + "
    //\n
    " + + "
    //\n
    " + "
    }\n
    " + "
    "); assert.ok(!!result.css); @@ -97,7 +97,7 @@ module.exports = { var mode = new TextMode(); var result = highlighter.render(snippet, mode, theme); - assert.ok(result.html.indexOf("$'$1$2$$$&\n
    ") != -1); + assert.ok(result.html.indexOf("$'$1$2$$$&\n
    ") != -1); next(); }, @@ -108,7 +108,7 @@ module.exports = { var mode = new TextMode(); var result = highlighter.render(snippet, mode, theme); - assert.ok(result.html.indexOf("&<>'"\n
    ") != -1); + assert.ok(result.html.indexOf("&<>'"\n
    ") != -1); var mode = new JavaScriptMode(); var result = highlighter.render("/*" + snippet, mode, theme); diff --git a/src/layer/font_metrics.js b/src/layer/font_metrics.js index 6a438946c0c..2fbc2e44e40 100644 --- a/src/layer/font_metrics.js +++ b/src/layer/font_metrics.js @@ -5,30 +5,30 @@ var event = require("../lib/event"); var useragent = require("../lib/useragent"); var EventEmitter = require("../lib/event_emitter").EventEmitter; -var CHAR_COUNT = 256; +var DEFAULT_CHAR_COUNT = 250; var USE_OBSERVER = typeof ResizeObserver == "function"; var L = 200; -var FontMetrics = exports.FontMetrics = function(parentEl) { +var FontMetrics = exports.FontMetrics = function(parentEl, charCount) { + this.charCount = charCount || DEFAULT_CHAR_COUNT; + this.el = dom.createElement("div"); this.$setMeasureNodeStyles(this.el.style, true); - + this.$main = dom.createElement("div"); this.$setMeasureNodeStyles(this.$main.style); - + this.$measureNode = dom.createElement("div"); this.$setMeasureNodeStyles(this.$measureNode.style); - - + this.el.appendChild(this.$main); this.el.appendChild(this.$measureNode); parentEl.appendChild(this.el); - - this.$measureNode.textContent = lang.stringRepeat("X", CHAR_COUNT); - + + this.$measureNode.textContent = lang.stringRepeat("X", this.charCount); + this.$characterSize = {width: 0, height: 0}; - - + if (USE_OBSERVER) this.$addObserver(); else @@ -38,9 +38,9 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { (function() { oop.implement(this, EventEmitter); - + this.$characterSize = {width: 0, height: 0}; - + this.$setMeasureNodeStyles = function(style, isRoot) { style.width = style.height = "auto"; style.left = style.top = "0px"; @@ -69,7 +69,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { this._emit("changeCharacterSize", {data: size}); } }; - + this.$addObserver = function() { var self = this; this.$observer = new window.ResizeObserver(function(e) { @@ -83,13 +83,13 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { if (this.$pollSizeChangesTimer || this.$observer) return this.$pollSizeChangesTimer; var self = this; - + return this.$pollSizeChangesTimer = event.onIdle(function cb() { self.checkForSizeChanges(); event.onIdle(cb, 500); }, 500); }; - + this.setPolling = function(val) { if (val) { this.$pollSizeChanges(); @@ -100,24 +100,32 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { }; this.$measureSizes = function(node) { - var size = { - height: (node || this.$measureNode).clientHeight, - width: (node || this.$measureNode).clientWidth / CHAR_COUNT + node = node || this.$measureNode; + + // Avoid `Element.clientWidth` since it is rounded to an integer (see + // https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth). + // Using it here can result in a noticeable cursor offset for long lines. + const rect = node.getBoundingClientRect(); + const charSize = { + height: rect.height, + width: rect.width / this.charCount }; - + // Size and width can be null if the editor is not visible or // detached from the document - if (size.width === 0 || size.height === 0) + if (charSize.width === 0 || charSize.height === 0) return null; - return size; + return charSize; }; this.$measureCharWidth = function(ch) { - this.$main.textContent = lang.stringRepeat(ch, CHAR_COUNT); + this.$main.textContent = lang.stringRepeat(ch, this.charCount); + // Avoid `Element.clientWidth` since it is rounded to an integer (see + // https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth). var rect = this.$main.getBoundingClientRect(); - return rect.width / CHAR_COUNT; + return rect.width / this.charCount; }; - + this.getCharacterWidth = function(ch) { var w = this.charSizes[ch]; if (w === undefined) { @@ -134,7 +142,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { this.el.parentNode.removeChild(this.el); }; - + this.$getZoom = function getZoom(element) { if (!element || !element.parentElement) return 1; return (window.getComputedStyle(element).zoom || 1) * getZoom(element.parentElement); @@ -171,7 +179,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { if (!this.els) this.$initTransformMeasureNodes(); - + function p(el) { var r = el.getBoundingClientRect(); return [r.left, r.top]; @@ -186,7 +194,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { var m1 = mul(1 + h[0], sub(b, a)); var m2 = mul(1 + h[1], sub(c, a)); - + if (elPos) { var x = elPos; var k = h[0] * x[0] / L + h[1] * x[1] / L + 1; @@ -197,5 +205,5 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { var f = solve(sub(m1, mul(h[0], u)), sub(m2, mul(h[1], u)), u); return mul(L, f); }; - + }).call(FontMetrics.prototype); diff --git a/src/layer/text.js b/src/layer/text.js index aa3be47f9cf..3e94d48f634 100644 --- a/src/layer/text.js +++ b/src/layer/text.js @@ -27,6 +27,8 @@ var Text = function(parentEl) { this.SPACE_CHAR = "\xB7"; this.$padding = 0; this.MAX_LINE_LENGTH = 10000; + // Smaller chunks result in higher cursor precision at the cost of more DOM nodes + this.MAX_CHUNK_LENGTH = 250; this.$updateEolChar = function() { var doc = this.session.doc; @@ -320,6 +322,19 @@ var Text = function(parentEl) { "lparen": true }; + this.$renderTokenInChunks = function(parent, screenColumn, token, value) { + var newScreenColumn; + for (var i = 0; i < value.length; i += this.MAX_CHUNK_LENGTH) { + var valueChunk = value.substring(i, i + this.MAX_CHUNK_LENGTH); + var tokenChunk = { + type: token.type, + value: valueChunk + }; + newScreenColumn = this.$renderToken(parent, screenColumn + i, tokenChunk, valueChunk); + } + return newScreenColumn; + }; + this.$renderToken = function(parent, screenColumn, token, value) { var self = this; var re = /(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC\u2066\u2067\u2068\u202A\u202B\u202D\u202E\u202C\u2069]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g; @@ -385,20 +400,16 @@ var Text = function(parentEl) { valueFragment.appendChild(this.dom.createTextNode(i ? value.slice(i) : value, this.element)); + var span = this.dom.createElement("span"); if (!this.$textToken[token.type]) { var classes = "ace_" + token.type.replace(/\./g, " ace_"); - var span = this.dom.createElement("span"); if (token.type == "fold") span.style.width = (token.value.length * this.config.characterWidth) + "px"; span.className = classes; - span.appendChild(valueFragment); - - parent.appendChild(span); - } - else { - parent.appendChild(valueFragment); } + span.appendChild(valueFragment); + parent.appendChild(span); return screenColumn + value.length; }; @@ -565,11 +576,11 @@ var Text = function(parentEl) { } if (chars + value.length < splitChars) { - screenColumn = this.$renderToken(lineEl, screenColumn, token, value); + screenColumn = this.$renderTokenInChunks(lineEl, screenColumn, token, value); chars += value.length; } else { while (chars + value.length >= splitChars) { - screenColumn = this.$renderToken( + screenColumn = this.$renderTokenInChunks( lineEl, screenColumn, token, value.substring(0, splitChars - chars) ); @@ -587,7 +598,7 @@ var Text = function(parentEl) { } if (value.length != 0) { chars += value.length; - screenColumn = this.$renderToken( + screenColumn = this.$renderTokenInChunks( lineEl, screenColumn, token, value ); } @@ -609,15 +620,23 @@ var Text = function(parentEl) { if (!value) continue; } - if (screenColumn + value.length > this.MAX_LINE_LENGTH) - return this.$renderOverflowMessage(parent, screenColumn, token, value); - screenColumn = this.$renderToken(parent, screenColumn, token, value); + if (screenColumn + value.length > this.MAX_LINE_LENGTH) { + this.$renderOverflowMessage(parent, screenColumn, token, value); + return; + } + screenColumn = this.$renderTokenInChunks(parent, screenColumn, token, value); } }; this.$renderOverflowMessage = function(parent, screenColumn, token, value, hide) { - token && this.$renderToken(parent, screenColumn, token, - value.slice(0, this.MAX_LINE_LENGTH - screenColumn)); + if (token) { + this.$renderTokenInChunks( + parent, + screenColumn, + token, + value.slice(0, this.MAX_LINE_LENGTH - screenColumn) + ); + } var overflowEl = this.dom.createElement("span"); overflowEl.className = "ace_inline_button ace_keyword ace_toggle_wrap"; diff --git a/src/layer/text_test.js b/src/layer/text_test.js index 7276fa840dd..15bfebcb62b 100644 --- a/src/layer/text_test.js +++ b/src/layer/text_test.js @@ -44,13 +44,13 @@ module.exports = { var parent = dom.createElement("div"); this.textLayer.$renderLine(parent, 0); - assert.domNode(parent, ["div", {}, ["span", {class: "ace_cjk", style: "width: 20px;"}, "\u3000"]]); + assert.domNode(parent, ["div", {}, ["span", {}, ["span", {class: "ace_cjk", style: "width: 20px;"}, "\u3000"]]]); this.textLayer.setShowInvisibles(true); var parent = dom.createElement("div"); this.textLayer.$renderLine(parent, 0); assert.domNode(parent, ["div", {}, - ["span", {class: "ace_cjk ace_invisible ace_invisible_space", style: "width: 20px;"}, this.textLayer.SPACE_CHAR], + ["span", {}, ["span", {class: "ace_cjk ace_invisible ace_invisible_space", style: "width: 20px;"}, this.textLayer.SPACE_CHAR]], ["span", {class: "ace_invisible ace_invisible_eol"}, "\xB6"] ]); }, @@ -72,21 +72,21 @@ module.exports = { this.session.setValue(" \n\t\tf\n "); testRender([ - "" + SPACE(4) + "" + SPACE(2), - "" + SPACE(4) + "" + SPACE(4) + "f", - SPACE(3) + "" + SPACE(4) + "" + SPACE(2) + "", + "" + SPACE(4) + "" + SPACE(4) + "f", + "" + SPACE(3) + "" ]); this.textLayer.setShowInvisibles(true); testRender([ - "" + DOT(4) + "" + DOT(2) + "" + EOL, - "" + TAB(4) + "" + TAB(4) + "f" + EOL + "" + DOT(4) + "" + DOT(2) + "" + EOL, + "" + TAB(4) + "" + TAB(4) + "f" + EOL ]); this.textLayer.setDisplayIndentGuides(false); testRender([ - "" + DOT(6) + "" + EOL, - "" + TAB(4) + "" + TAB(4) + "f" + EOL + "" + DOT(6) + "" + EOL, + "" + TAB(4) + "" + TAB(4) + "f" + EOL ]); } }; diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index e0642c51c5b..6c1ce891e53 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -98,7 +98,7 @@ var VirtualRenderer = function(container, theme) { column : 0 }; - this.$fontMetrics = new FontMetrics(this.container); + this.$fontMetrics = new FontMetrics(this.container, this.$textLayer.MAX_CHUNK_LENGTH); this.$textLayer.$setFontMetrics(this.$fontMetrics); this.$textLayer.on("changeCharacterSize", function(e) { _self.updateCharacterSize(); From 50044ceaef7d28d65f14dfaca04509b46a9430aa Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Wed, 16 Nov 2022 12:21:06 +0100 Subject: [PATCH 0688/1293] release v1.13.1 --- CHANGELOG.md | 8 ++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebb84af1a96..2f6c73c845e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.13.1](https://github.com/ajaxorg/ace/compare/v1.13.0...v1.13.1) (2022-11-16) + + +### Bug Fixes + +* Change curly braces insertion behavior for Markdown to act the same as for other braces ([#4994](https://github.com/ajaxorg/ace/issues/4994)) ([2760234](https://github.com/ajaxorg/ace/commit/2760234d3d8d1acba72a42df7763482655af5ebc)) +* incorrect cursor position for very long lines ([#4996](https://github.com/ajaxorg/ace/issues/4996)) ([e57a9d9](https://github.com/ajaxorg/ace/commit/e57a9d9eef0c056cd38a07c77c460bea39cc9551)) + ## [1.13.0](https://github.com/ajaxorg/ace/compare/v1.12.5...v1.13.0) (2022-11-11) diff --git a/build b/build index 5795b1bd397..fdab4a6eabe 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 5795b1bd397a75229eec61f5dc847a03e74f7e30 +Subproject commit fdab4a6eabe634f888533e3a3922016c83f18d94 diff --git a/package.json b/package.json index 7fbb1bc8a41..e50e91cd887 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.13.0", + "version": "1.13.1", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index d02a3f9731a..bca147a4f82 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.13.0"; +exports.version = "1.13.1"; From 7abbd0cf96b0c5a909bcea527bf046e67997c0c8 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Wed, 16 Nov 2022 17:55:10 +0400 Subject: [PATCH 0689/1293] add support of arrow functions, built-in methods, default parameters, promises, maps/sets and other es6 features --- src/mode/javascript_highlight_rules.js | 87 ++++++++++++++++++++------ 1 file changed, 68 insertions(+), 19 deletions(-) diff --git a/src/mode/javascript_highlight_rules.js b/src/mode/javascript_highlight_rules.js index e898abab4f1..ccdfad6c119 100644 --- a/src/mode/javascript_highlight_rules.js +++ b/src/mode/javascript_highlight_rules.js @@ -11,7 +11,7 @@ var JavaScriptHighlightRules = function(options) { // see: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects var keywordMapper = this.createKeywordMapper({ "variable.language": - "Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|" + // Constructors + "Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|Symbol|" + // Constructors "Namespace|QName|XML|XMLList|" + // E4X "ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|" + "Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|" + @@ -27,7 +27,7 @@ var JavaScriptHighlightRules = function(options) { "if|in|of|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|" + // invalid or reserved "__parent__|__count__|escape|unescape|with|__proto__|" + - "class|enum|extends|super|export|implements|private|public|interface|package|protected|static", + "class|enum|extends|super|export|implements|private|public|interface|package|protected|static|constructor", "storage.type": "const|let|var|function", "constant.language": @@ -82,7 +82,7 @@ var JavaScriptHighlightRules = function(options) { "storage.type", "punctuation.operator", "entity.name.function", "text", "keyword.operator", "text", "storage.type", "text", "paren.lparen" ], - regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s*)(\\()", + regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function\\*?)(\\s*)(\\()", next: "function_arguments" }, { // play = function() { } @@ -90,7 +90,7 @@ var JavaScriptHighlightRules = function(options) { "entity.name.function", "text", "keyword.operator", "text", "storage.type", "text", "paren.lparen" ], - regex : "(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s*)(\\()", + regex : "(" + identifierRe +")(\\s*)(=)(\\s*)(function\\*?)(\\s*)(\\()", next: "function_arguments" }, { // Sound.play = function play() { } @@ -99,14 +99,14 @@ var JavaScriptHighlightRules = function(options) { "keyword.operator", "text", "storage.type", "text", "entity.name.function", "text", "paren.lparen" ], - regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s+)(\\w+)(\\s*)(\\()", + regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function\\*?)(\\s+)(\\w+)(\\s*)(\\()", next: "function_arguments" }, { // function myFunc(arg) { } token : [ "storage.type", "text", "entity.name.function", "text", "paren.lparen" ], - regex : "(function)(\\s+)(" + identifierRe + ")(\\s*)(\\()", + regex : "(function\\*?)(\\s+)(" + identifierRe + ")(\\s*)(\\()", next: "function_arguments" }, { // foobar: function() { } @@ -114,14 +114,14 @@ var JavaScriptHighlightRules = function(options) { "entity.name.function", "text", "punctuation.operator", "text", "storage.type", "text", "paren.lparen" ], - regex : "(" + identifierRe + ")(\\s*)(:)(\\s*)(function)(\\s*)(\\()", + regex : "(" + identifierRe + ")(\\s*)(:)(\\s*)(function\\*?)(\\s*)(\\()", next: "function_arguments" }, { // : function() { } (this is for issues with 'foo': function() { }) token : [ "text", "text", "storage.type", "text", "paren.lparen" ], - regex : "(:)(\\s*)(function)(\\s*)(\\()", + regex : "(:)(\\s*)(function\\*?)(\\s*)(\\()", next: "function_arguments" }, { // from "module-path" (this is the only case where 'from' should be a keyword) @@ -132,7 +132,7 @@ var JavaScriptHighlightRules = function(options) { regex : "(?:" + kwBeforeRe + ")\\b", next : "start" }, { - token : ["support.constant"], + token : "support.constant", regex : /that\b/ }, { token : ["storage.type", "punctuation.operator", "support.function.firebug"], @@ -178,14 +178,14 @@ var JavaScriptHighlightRules = function(options) { "keyword.operator", "text", "storage.type", "text", "entity.name.function", "text", "paren.lparen" ], - regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(?:(\\s+)(\\w+))?(\\s*)(\\()", + regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function\\*?)(?:(\\s+)(\\w+))?(\\s*)(\\()", next: "function_arguments" }, { token : "punctuation.operator", regex : /[.](?![.])/ }, { token : "support.function", - regex : /(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/ + regex : /(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|lter|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward|rEach)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/ }, { token : "support.function.dom", regex : /(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName|ClassName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/ @@ -277,10 +277,28 @@ var JavaScriptHighlightRules = function(options) { "default_parameter": [ { token : "string", - regex : "'(?=.)" + regex : "'(?=.)", + push: [ + { + token: "string", + regex: "'|$", + next: "pop" + }, { + include: "qstring" + } + ] }, { token : "string", - regex : '"(?=.)' + regex : '"(?=.)', + push: [ + { + token: "string", + regex: '"|$', + next: "pop" + }, { + include: "qqstring" + } + ] }, { token : "constant.language", regex : "null|Infinity|NaN|undefined" @@ -292,8 +310,11 @@ var JavaScriptHighlightRules = function(options) { regex : /(?:\d\d*(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+\b)?/ }, { token: "punctuation.operator", - regex: "[, ]+", + regex: ",", next: "function_arguments" + }, { + token: "text", + regex: "\\s+", }, { token: "punctuation.operator", regex: "$" @@ -304,16 +325,16 @@ var JavaScriptHighlightRules = function(options) { } ], "function_arguments": [ + comments("function_arguments"), { token: "variable.parameter", regex: identifierRe - }, { - token : "keyword.operator", - regex : "[= ]+", - next : "default_parameter" }, { token: "punctuation.operator", - regex: "[, ]+" + regex: "," + }, { + token: "text", + regex: "\\s+" }, { token: "punctuation.operator", regex: "$" @@ -391,6 +412,34 @@ var JavaScriptHighlightRules = function(options) { }, { defaultToken: "string.quasi" }] + }, { + token: ["variable.parameter", "text"], + regex: "(" + identifierRe + ")(\\s*)(?=\\=>)", + }, { + token: "paren.lparen", + regex: "(\\()(?=.+\\s*=>)", + next: "function_arguments" + }, { + token: "variable.language", + regex: "(?:(?:(?:Weak)?(?:Set|Map))|Promise)\\b" + }); + + this.$rules["function_arguments"].unshift({ + token: "keyword.operator", + regex: "=", + next: "default_parameter" + }, { + token: "keyword.operator", + regex: "\\.{3}" + }); + + this.$rules["property"].unshift({ + token: "support.function", + regex: "(findIndex|repeat|startsWith|endsWith|includes|isSafeInteger|trunc|cbrt|log2|log10|sign|then|catch|" + + "finally|resolve|reject|race|any|all|allSettled|keys|entries|isInteger)\\b(?=\\()" + }, { + token : "constant.language", + regex : "(?:MAX_SAFE_INTEGER|MIN_SAFE_INTEGER|EPSILON)\\b" }); if (!options || options.jsx != false) From 0634049b3e3aa55508e6e63616fe286fa3bdaeec Mon Sep 17 00:00:00 2001 From: mkslanc Date: Wed, 16 Nov 2022 18:03:28 +0400 Subject: [PATCH 0690/1293] add tests for new es6 js tokens; fix other generated tokens --- src/ext/static_highlight_test.js | 4 +- src/mode/_test/text_javascript.txt | 71 ++- src/mode/_test/tokens_ejs.json | 2 +- src/mode/_test/tokens_javascript.json | 640 ++++++++++++++++++++++++-- src/mode/_test/tokens_sjs.json | 3 +- src/mode/_test/tokens_velocity.json | 5 +- 6 files changed, 685 insertions(+), 40 deletions(-) diff --git a/src/ext/static_highlight_test.js b/src/ext/static_highlight_test.js index 7b0a9e1adb7..e9f4a8cb690 100644 --- a/src/ext/static_highlight_test.js +++ b/src/ext/static_highlight_test.js @@ -39,12 +39,12 @@ module.exports = { ].join("\n"); var mode = new JavaScriptMode(); var result = highlighter.render(snippet, mode, theme); - assert.equal(result.html, "
    " + assert.equal(result.html, "
    " + "
    /** this is a function\n
    " + "
    *\n
    " + "
    */\n
    " + "
    \n
    " - + "
    function hello (a, b, c) {\n
    " + + "
    function hello (a, b, c) {\n
    " + "
    console.log(a * b + c + 'sup$');\n
    " + "
    //\n
    " + "
    //\n
    " diff --git a/src/mode/_test/text_javascript.txt b/src/mode/_test/text_javascript.txt index 390709ca10e..faa075282da 100644 --- a/src/mode/_test/text_javascript.txt +++ b/src/mode/_test/text_javascript.txt @@ -30,8 +30,8 @@ console.log('\\u1232Feh' a=' b="\ still a string - - + + function foo(items, nada) { for (var i=0; i>=t<>r>>>s>=0b1 foo.protoype.d = function(a, b, c, d) foo.d =function(a, b) -foo.d =function(a, /*****/ d"string" +foo.d =function(a, /*****/ d"string"
    x > 3) // 4 +[ 1, 3, 4, 2 ].findIndex(x => x > 3) // 2 +"foo".repeat(3) +Number.isSafeInteger(42) === true + +let x = Number.MAX_SAFE_INTEGER; +let x = Number.MIN_SAFE_INTEGER; +let x = Number.EPSILON; +//test Promises +new Promise(tetheredGetNumber) + .then(determineParity, troubleWithGetNumber) + .then(promiseGetWord) + .then((info) => { + console.log(`Got: ${info.value}, ${info.wordEvenOdd}`); + return info; + }) + .catch((reason) => { + if (reason.cause) { + console.error("Had previously handled error"); + } else { + console.error(`Trouble with promiseGetWord(): ${reason}`); + } + }) + .finally((info) => console.log("All done")); +//test ES6 arrow functions +param => expression; + +(param) => expression; + +(param1 = 123, paramN = "test") => expression; + +param => { + statements; +}; +(param1, paramN) => { + statements +} + +(a, b, ...r) => expression; + +(a = 400, b = 20, c) => expression; + +async param => expression; + +//test JSX functions arguments in arrow functions + { + console.log("Test") +}}/> + { + console.log("Test") +}}/> \ No newline at end of file diff --git a/src/mode/_test/tokens_ejs.json b/src/mode/_test/tokens_ejs.json index 7e54af9130f..131c73b2835 100644 --- a/src/mode/_test/tokens_ejs.json +++ b/src/mode/_test/tokens_ejs.json @@ -156,7 +156,7 @@ ["text"," "], ["identifier","entries"], ["punctuation.operator","."], - ["identifier","forEach"], + ["support.function","forEach"], ["paren.lparen","("], ["storage.type","function"], ["paren.lparen","("], diff --git a/src/mode/_test/tokens_javascript.json b/src/mode/_test/tokens_javascript.json index 8759595b6d6..9223c4d49d9 100644 --- a/src/mode/_test/tokens_javascript.json +++ b/src/mode/_test/tokens_javascript.json @@ -186,11 +186,9 @@ "no_regex", ["string","still a string"] ],[ - "no_regex", - ["text"," "] + "no_regex" ],[ - "no_regex", - ["text"," "] + "no_regex" ],[ "start", ["storage.type","function"], @@ -198,7 +196,8 @@ ["entity.name.function","foo"], ["paren.lparen","("], ["variable.parameter","items"], - ["punctuation.operator",", "], + ["punctuation.operator",","], + ["text"," "], ["variable.parameter","nada"], ["paren.rparen",")"], ["text"," "], @@ -470,22 +469,13 @@ ],[ "no_regex" ],[ - "no_regex", - ["string","\"trailing space"], - ["constant.language.escape","\\ "], - ["string"," "] + "qqstring", + ["string","\"trailing space\\"] ],[ "no_regex", - ["string","\" \""], - ["text"," "], - ["keyword.operator","/"], - ["identifier","not"], - ["text"," "], - ["identifier","a"], - ["text"," "], - ["identifier","regexp"], - ["keyword.operator","/"], - ["identifier","g"] + ["string","\""], + ["text"," "], + ["string","\" /not a regexp/g"] ],[ "no_regex" ],[ @@ -568,14 +558,16 @@ ["storage.type","function"], ["paren.lparen","("], ["variable.parameter","a"], - ["punctuation.operator",", "], + ["punctuation.operator",","], + ["text"," "], ["variable.parameter","b"], ["punctuation.operator",","] ],[ "no_regex", - ["punctuation.operator"," "], + ["text"," "], ["variable.parameter","c"], - ["punctuation.operator",", "], + ["punctuation.operator",","], + ["text"," "], ["variable.parameter","d"], ["paren.rparen",")"] ],[ @@ -588,7 +580,8 @@ ["storage.type","function"], ["paren.lparen","("], ["variable.parameter","a"], - ["punctuation.operator",", "], + ["punctuation.operator",","], + ["text"," "], ["variable.parameter","b"], ["paren.rparen",")"] ],[ @@ -601,12 +594,12 @@ ["storage.type","function"], ["paren.lparen","("], ["variable.parameter","a"], - ["punctuation.operator",", "], - ["comment.doc","/*****/"], + ["punctuation.operator",","], + ["text"," "], + ["comment","/*****/"], ["text"," "], - ["identifier","d"], - ["string","\"string\""], - ["text"," "] + ["variable.parameter","d"], + ["string","\"string\""] ],[ "no_regex" ],[ @@ -712,9 +705,9 @@ ["punctuation.operator","."], ["identifier","map"], ["paren.lparen","("], - ["identifier","x"], + ["variable.parameter","x"], ["text"," "], - ["storage.type","=>"], + ["keyword.operator","=>"], ["text"," "], ["paren.lparen","{"] ],[ @@ -733,4 +726,591 @@ "start", ["paren.rparen","}"], ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["comment","//test generator function"] +],[ + "start", + ["storage.type","function*"], + ["text"," "], + ["entity.name.function","range"], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","start"], + ["punctuation.operator",","], + ["text"," "], + ["variable.parameter","end"], + ["punctuation.operator",","], + ["text"," "], + ["variable.parameter","step"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","while"], + ["text"," "], + ["paren.lparen","("], + ["identifier","start"], + ["text"," "], + ["keyword.operator","<"], + ["text"," "], + ["identifier","end"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "no_regex", + ["text"," "], + ["keyword","yield"], + ["text"," "], + ["identifier","start"] +],[ + "no_regex", + ["text"," "], + ["identifier","start"], + ["text"," "], + ["keyword.operator","+="], + ["text"," "], + ["identifier","step"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "no_regex", + ["paren.rparen","}"] +],[ + "no_regex", + ["comment","//test ES6 new built-in methods"] +],[ + "no_regex", + ["string","\"hello\""], + ["punctuation.operator","."], + ["support.function","startsWith"], + ["paren.lparen","("], + ["string","\"ello\""], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","1"], + ["paren.rparen",")"], + ["text"," "], + ["comment","// true"] +],[ + "no_regex", + ["string","\"hello\""], + ["punctuation.operator","."], + ["support.function","endsWith"], + ["paren.lparen","("], + ["string","\"hell\""], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","4"], + ["paren.rparen",")"], + ["text"," "], + ["comment","// true"] +],[ + "no_regex", + ["string","\"hello\""], + ["punctuation.operator","."], + ["support.function","includes"], + ["paren.lparen","("], + ["string","\"ell\""], + ["paren.rparen",")"], + ["text"," "], + ["comment","// true"] +],[ + "no_regex", + ["paren.lparen","["], + ["text"," "], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","3"], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","4"], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["paren.rparen","]"], + ["punctuation.operator","."], + ["support.function","find"], + ["paren.lparen","("], + ["variable.parameter","x"], + ["text"," "], + ["keyword.operator","=>"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["constant.numeric","3"], + ["paren.rparen",")"], + ["text"," "], + ["comment","// 4"] +],[ + "no_regex", + ["paren.lparen","["], + ["text"," "], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","3"], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","4"], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["paren.rparen","]"], + ["punctuation.operator","."], + ["support.function","findIndex"], + ["paren.lparen","("], + ["variable.parameter","x"], + ["text"," "], + ["keyword.operator","=>"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["constant.numeric","3"], + ["paren.rparen",")"], + ["text"," "], + ["comment","// 2"] +],[ + "no_regex", + ["string","\"foo\""], + ["punctuation.operator","."], + ["support.function","repeat"], + ["paren.lparen","("], + ["constant.numeric","3"], + ["paren.rparen",")"] +],[ + "no_regex", + ["variable.language","Number"], + ["punctuation.operator","."], + ["support.function","isSafeInteger"], + ["paren.lparen","("], + ["constant.numeric","42"], + ["paren.rparen",")"], + ["text"," "], + ["keyword.operator","==="], + ["text"," "], + ["constant.language.boolean","true"] +],[ + "no_regex" +],[ + "start", + ["storage.type","let"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["variable.language","Number"], + ["punctuation.operator","."], + ["constant.language","MAX_SAFE_INTEGER"], + ["punctuation.operator",";"] +],[ + "start", + ["storage.type","let"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["variable.language","Number"], + ["punctuation.operator","."], + ["constant.language","MIN_SAFE_INTEGER"], + ["punctuation.operator",";"] +],[ + "start", + ["storage.type","let"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["variable.language","Number"], + ["punctuation.operator","."], + ["constant.language","EPSILON"], + ["punctuation.operator",";"] +],[ + "start", + ["comment","//test Promises"] +],[ + "no_regex", + ["keyword","new"], + ["text"," "], + ["variable.language","Promise"], + ["paren.lparen","("], + ["identifier","tetheredGetNumber"], + ["paren.rparen",")"] +],[ + "no_regex", + ["text"," "], + ["punctuation.operator","."], + ["support.function","then"], + ["paren.lparen","("], + ["identifier","determineParity"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","troubleWithGetNumber"], + ["paren.rparen",")"] +],[ + "no_regex", + ["text"," "], + ["punctuation.operator","."], + ["support.function","then"], + ["paren.lparen","("], + ["identifier","promiseGetWord"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["punctuation.operator","."], + ["support.function","then"], + ["paren.lparen","(("], + ["variable.parameter","info"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["storage.type","console"], + ["punctuation.operator","."], + ["support.function.firebug","log"], + ["paren.lparen","("], + ["string.quasi.start","`"], + ["string.quasi","Got: "], + ["paren.quasi.start","${"], + ["identifier","info"], + ["punctuation.operator","."], + ["identifier","value"], + ["paren.quasi.end","}"], + ["string.quasi",", "], + ["paren.quasi.start","${"], + ["identifier","info"], + ["punctuation.operator","."], + ["identifier","wordEvenOdd"], + ["paren.quasi.end","}"], + ["string.quasi.end","`"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword","return"], + ["text"," "], + ["identifier","info"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","})"] +],[ + "start", + ["text"," "], + ["punctuation.operator","."], + ["support.function","catch"], + ["paren.lparen","(("], + ["variable.parameter","reason"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["identifier","reason"], + ["punctuation.operator","."], + ["identifier","cause"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["storage.type","console"], + ["punctuation.operator","."], + ["support.function.firebug","error"], + ["paren.lparen","("], + ["string","\"Had previously handled error\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"], + ["text"," "], + ["keyword","else"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["storage.type","console"], + ["punctuation.operator","."], + ["support.function.firebug","error"], + ["paren.lparen","("], + ["string.quasi.start","`"], + ["string.quasi","Trouble with promiseGetWord(): "], + ["paren.quasi.start","${"], + ["identifier","reason"], + ["paren.quasi.end","}"], + ["string.quasi.end","`"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","})"] +],[ + "start", + ["text"," "], + ["punctuation.operator","."], + ["support.function","finally"], + ["paren.lparen","(("], + ["variable.parameter","info"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["storage.type","console"], + ["punctuation.operator","."], + ["support.function.firebug","log"], + ["paren.lparen","("], + ["string","\"All done\""], + ["paren.rparen","))"], + ["punctuation.operator",";"] +],[ + "start", + ["comment","//test ES6 arrow functions"] +],[ + "start", + ["variable.parameter","param"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["identifier","expression"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["paren.lparen","("], + ["variable.parameter","param"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["identifier","expression"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["paren.lparen","("], + ["variable.parameter","param1"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","123"], + ["punctuation.operator",","], + ["text"," "], + ["variable.parameter","paramN"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"test\""], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["identifier","expression"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["variable.parameter","param"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","statements"], + ["punctuation.operator",";"] +],[ + "start", + ["paren.rparen","}"], + ["punctuation.operator",";"] +],[ + "start", + ["paren.lparen","("], + ["variable.parameter","param1"], + ["punctuation.operator",","], + ["text"," "], + ["variable.parameter","paramN"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["paren.lparen","{"] +],[ + "no_regex", + ["text"," "], + ["identifier","statements"] +],[ + "no_regex", + ["paren.rparen","}"] +],[ + "no_regex" +],[ + "start", + ["paren.lparen","("], + ["variable.parameter","a"], + ["punctuation.operator",","], + ["text"," "], + ["variable.parameter","b"], + ["punctuation.operator",","], + ["text"," "], + ["keyword.operator","..."], + ["variable.parameter","r"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["identifier","expression"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["paren.lparen","("], + ["variable.parameter","a"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","400"], + ["punctuation.operator",","], + ["text"," "], + ["variable.parameter","b"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","20"], + ["punctuation.operator",","], + ["text"," "], + ["variable.parameter","c"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["identifier","expression"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["keyword","async"], + ["text"," "], + ["variable.parameter","param"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["identifier","expression"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["comment","//test JSX functions arguments in arrow functions"] +],[ + ["start","no_regex","start","jsxAttributes","jsxAttributes","jsx",1], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","Component"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","onclick"], + ["keyword.operator.attribute-equals.xml","="], + ["paren.quasi.start","{"], + ["paren.lparen","("], + ["variable.parameter","param1"], + ["punctuation.operator",","], + ["text"," "], + ["variable.parameter","param2"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"Test\""], + ["punctuation.operator",","], + ["text"," "], + ["keyword.operator","..."], + ["variable.parameter","paramN"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["#tmp","no_regex","start","no_regex","start","jsxAttributes","jsxAttributes","jsx",1], + ["text"," "], + ["storage.type","console"], + ["punctuation.operator","."], + ["support.function.firebug","log"], + ["paren.lparen","("], + ["string","\"Test\""], + ["paren.rparen",")"] +],[ + "start", + ["paren.rparen","}"], + ["paren.quasi.end","}"], + ["meta.tag.punctuation.tag-close.xml","/>"] +],[ + ["start","no_regex","start","jsxAttributes","jsxAttributes","jsx",1], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","Component"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","onclick"], + ["keyword.operator.attribute-equals.xml","="], + ["paren.quasi.start","{"], + ["variable.parameter","param1"], + ["text"," "], + ["storage.type","=>"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["#tmp","no_regex","start","no_regex","start","jsxAttributes","jsxAttributes","jsx",1], + ["text"," "], + ["storage.type","console"], + ["punctuation.operator","."], + ["support.function.firebug","log"], + ["paren.lparen","("], + ["string","\"Test\""], + ["paren.rparen",")"] +],[ + "start", + ["paren.rparen","}"], + ["paren.quasi.end","}"], + ["meta.tag.punctuation.tag-close.xml","/>"] ]] \ No newline at end of file diff --git a/src/mode/_test/tokens_sjs.json b/src/mode/_test/tokens_sjs.json index 5cd9645143c..d9655811b79 100644 --- a/src/mode/_test/tokens_sjs.json +++ b/src/mode/_test/tokens_sjs.json @@ -44,7 +44,8 @@ ["entity.name.function","foo"], ["paren.lparen","("], ["variable.parameter","items"], - ["punctuation.operator",", "], + ["punctuation.operator",","], + ["text"," "], ["variable.parameter","nada"], ["paren.rparen",")"], ["text"," "], diff --git a/src/mode/_test/tokens_velocity.json b/src/mode/_test/tokens_velocity.json index f99a09d12fa..ecfbf7a15aa 100644 --- a/src/mode/_test/tokens_velocity.json +++ b/src/mode/_test/tokens_velocity.json @@ -163,7 +163,8 @@ ["entity.name.function","foo"], ["paren.lparen","("], ["variable.parameter","items"], - ["punctuation.operator",", "], + ["punctuation.operator",","], + ["text"," "], ["variable.parameter","nada"], ["paren.rparen",")"], ["text"," "], @@ -287,4 +288,4 @@ ["meta.tag.punctuation.end-tag-open.xml",""] -]] +]] \ No newline at end of file From 53427d1811f906f4912fc54b211948ad7e4fb41c Mon Sep 17 00:00:00 2001 From: mkslanc Date: Wed, 16 Nov 2022 18:45:30 +0400 Subject: [PATCH 0691/1293] fix test to reflect recent changes in js mode --- src/ext/static_highlight_test.js | 2 +- src/mode/javascript_highlight_rules.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ext/static_highlight_test.js b/src/ext/static_highlight_test.js index 025eb1a369c..f28d7833cca 100644 --- a/src/ext/static_highlight_test.js +++ b/src/ext/static_highlight_test.js @@ -44,7 +44,7 @@ module.exports = { + "
    *\n
    " + "
    */\n
    " + "
    \n
    " - + "
    function hello (a, b, c) {\n
    " + + "
    function hello (a, b, c) {\n
    " + "
    console.log(a * b + c + 'sup$');\n
    " + "
    //\n
    " + "
    //\n
    " diff --git a/src/mode/javascript_highlight_rules.js b/src/mode/javascript_highlight_rules.js index ccdfad6c119..729a8b545cd 100644 --- a/src/mode/javascript_highlight_rules.js +++ b/src/mode/javascript_highlight_rules.js @@ -314,7 +314,7 @@ var JavaScriptHighlightRules = function(options) { next: "function_arguments" }, { token: "text", - regex: "\\s+", + regex: "\\s+" }, { token: "punctuation.operator", regex: "$" @@ -414,7 +414,7 @@ var JavaScriptHighlightRules = function(options) { }] }, { token: ["variable.parameter", "text"], - regex: "(" + identifierRe + ")(\\s*)(?=\\=>)", + regex: "(" + identifierRe + ")(\\s*)(?=\\=>)" }, { token: "paren.lparen", regex: "(\\()(?=.+\\s*=>)", From 743190ea71841c0186b2f513b3d1e1a9e30d3de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Oliveira?= Date: Fri, 18 Nov 2022 14:39:05 +0000 Subject: [PATCH 0692/1293] fix: show 2 context characters of a line when moving to it (#4998) --- src/virtual_renderer.js | 57 ++++++++++++++++++++---------------- src/virtual_renderer_test.js | 27 +++++++++++++++++ 2 files changed, 59 insertions(+), 25 deletions(-) diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 6c1ce891e53..58d214a525c 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -1227,40 +1227,47 @@ var VirtualRenderer = function(container, theme) { var pos = this.$cursorLayer.getPixelPosition(cursor); - var left = pos.left; - var top = pos.top; - + var newLeft = pos.left; + var newTop = pos.top; + var topMargin = $viewMargin && $viewMargin.top || 0; var bottomMargin = $viewMargin && $viewMargin.bottom || 0; if (this.$scrollAnimation) { this.$stopAnimation = true; } - - var scrollTop = this.$scrollAnimation ? this.session.getScrollTop() : this.scrollTop; - - if (scrollTop + topMargin > top) { - if (offset && scrollTop + topMargin > top + this.lineHeight) - top -= offset * this.$size.scrollerHeight; - if (top === 0) - top = -this.scrollMargin.top; - this.session.setScrollTop(top); - } else if (scrollTop + this.$size.scrollerHeight - bottomMargin < top + this.lineHeight) { - if (offset && scrollTop + this.$size.scrollerHeight - bottomMargin < top - this.lineHeight) - top += offset * this.$size.scrollerHeight; - this.session.setScrollTop(top + this.lineHeight + bottomMargin - this.$size.scrollerHeight); + + var currentTop = this.$scrollAnimation ? this.session.getScrollTop() : this.scrollTop; + + if (currentTop + topMargin > newTop) { + if (offset && currentTop + topMargin > newTop + this.lineHeight) + newTop -= offset * this.$size.scrollerHeight; + if (newTop === 0) + newTop = -this.scrollMargin.top; + this.session.setScrollTop(newTop); + } else if (currentTop + this.$size.scrollerHeight - bottomMargin < newTop + this.lineHeight) { + if (offset && currentTop + this.$size.scrollerHeight - bottomMargin < newTop - this.lineHeight) + newTop += offset * this.$size.scrollerHeight; + this.session.setScrollTop(newTop + this.lineHeight + bottomMargin - this.$size.scrollerHeight); } - var scrollLeft = this.scrollLeft; + var currentLeft = this.scrollLeft; + // Show 2 context characters of the line when moving to it + var twoCharsWidth = 2 * this.layerConfig.characterWidth; - if (scrollLeft > left) { - if (left < this.$padding + 2 * this.layerConfig.characterWidth) - left = -this.scrollMargin.left; - this.session.setScrollLeft(left); - } else if (scrollLeft + this.$size.scrollerWidth < left + this.characterWidth) { - this.session.setScrollLeft(Math.round(left + this.characterWidth - this.$size.scrollerWidth)); - } else if (scrollLeft <= this.$padding && left - scrollLeft < this.characterWidth) { - this.session.setScrollLeft(0); + if (newLeft - twoCharsWidth < currentLeft) { + newLeft -= twoCharsWidth; + if (newLeft < this.$padding + twoCharsWidth) { + newLeft = -this.scrollMargin.left; + } + this.session.setScrollLeft(newLeft); + } else { + newLeft += twoCharsWidth; + if (currentLeft + this.$size.scrollerWidth < newLeft + this.characterWidth) { + this.session.setScrollLeft(Math.round(newLeft + this.characterWidth - this.$size.scrollerWidth)); + } else if (currentLeft <= this.$padding && newLeft - currentLeft < this.characterWidth) { + this.session.setScrollLeft(0); + } } }; diff --git a/src/virtual_renderer_test.js b/src/virtual_renderer_test.js index c489e4cd389..e307fa1b685 100644 --- a/src/virtual_renderer_test.js +++ b/src/virtual_renderer_test.js @@ -325,6 +325,33 @@ module.exports = { }, 60); }, 60); }, 60); + }, + "test: scroll cursor into view": function() { + function X(n) { + return "X".repeat(n); + } + editor.session.setValue(`${X(10)}\n${X(1000)}}`); + + var initialContentLeft = editor.renderer.content.getBoundingClientRect().left; + + // Scroll so far to the right that the first line is completely hidden + editor.session.selection.$setSelection(1, 1000, 1, 1000); + editor.renderer.scrollCursorIntoView(); + editor.renderer.$loop._flush(); + + editor.session.selection.$setSelection(0, 10, 0, 10); + editor.renderer.scrollCursorIntoView(); + editor.renderer.$loop._flush(); + + var contentLeft = editor.renderer.content.getBoundingClientRect().left; + var scrollDelta = initialContentLeft - contentLeft; + + const leftBoundPixelPos = editor.renderer.$cursorLayer.getPixelPosition({row: 0, column: 8}).left; + const rightBoundPixelPos = editor.renderer.$cursorLayer.getPixelPosition({row: 0, column: 9}).left; + assert.ok( + scrollDelta >= leftBoundPixelPos && scrollDelta < rightBoundPixelPos, + "Expected content to have been scrolled two characters beyond the cursor" + ); } // change tab size after setDocument (for text layer) From 09505f37016baf7fa4a87e6c56149359803f283e Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Fri, 18 Nov 2022 06:39:38 -0800 Subject: [PATCH 0693/1293] chore: Update bug-report.yml (#5001) --- .github/ISSUE_TEMPLATE/bug-report.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 29f7f0b18ee..3a3931524a4 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -61,7 +61,7 @@ body: - type: input id: ace-version attributes: - label: Ace Version - description: Ace editor version + label: Ace Version / Browser / OS / Keyboard layout + description: Information about software versions and keyboard configuration that can be relevant for reproducing the issue validations: required: true From 8562f9493e0ebef865064992f0526fdc6df8535a Mon Sep 17 00:00:00 2001 From: Ani Amirjanyan <56698448+anijanyan@users.noreply.github.com> Date: Fri, 18 Nov 2022 18:50:06 +0400 Subject: [PATCH 0694/1293] fix: Fix vim keybindings scroll to the selected line (#4980) * Fix vim keybindings scroll to the selected line * Test added for vim gotoline * Fix vim keybindings scroll to the selected line --- src/keyboard/vim.js | 4 +- src/keyboard/vim_ace_test.js | 73 ++++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/src/keyboard/vim.js b/src/keyboard/vim.js index a37760ec2ee..df760a6e9f8 100644 --- a/src/keyboard/vim.js +++ b/src/keyboard/vim.js @@ -205,7 +205,7 @@ var result = fn(); if (this.ace.curOp && this.ace.curOp.command.name == "vim") { if (this.state.dialog) - this.ace.curOp.command.scrollIntoView = false; + this.ace.curOp.command.scrollIntoView = this.ace.curOp.vimDialogScroll; this.ace.endOperation(); if (!curOp.cursorActivity && !curOp.lastChange && prevOp) this.ace.prevOp = prevOp; @@ -2521,6 +2521,8 @@ domLib.importCssString(`.normal-mode .ace_cursor{ cursorIsBefore(newAnchor, newHead) ? newHead : newAnchor); } else if (!operator) { + if (cm.ace.curOp) + cm.ace.curOp.vimDialogScroll = "center-animate"; // ace_patch newHead = clipCursorToContent(cm, newHead, oldHead); cm.setCursor(newHead.line, newHead.ch); } diff --git a/src/keyboard/vim_ace_test.js b/src/keyboard/vim_ace_test.js index 0b1dd140ef4..abe45f4173b 100644 --- a/src/keyboard/vim_ace_test.js +++ b/src/keyboard/vim_ace_test.js @@ -86,6 +86,12 @@ function applyEvent(data) { editor.resize(true); } +function scrollTop() { + editor.endOperation(); + editor.renderer.$loop._flush(); + return editor.renderer.scrollTop / editor.renderer.lineHeight; +} + module.exports = { setUp: function() { if (!editor) { @@ -119,7 +125,7 @@ module.exports = { { _: "keydown", range: [12,12], value: "\thello world\n\n", key: { code: "ControlLeft", key: "Control", keyCode: 17}, modifier: "ctrl-"}, { _: "keydown", range: [12,12], value: "\thello world\n\n", key: { code: "AltLeft", key: "Alt", keyCode: 18}, modifier: "ctrl-alt-"}, { _: "keydown", range: [6,11], value: "hello world\n\n", key: { code: "KeyL", key: "fi", keyCode: 76}, modifier: "ctrl-alt-"}, - + { _: "keydown", range: [6,11], value: "hello world\n\n", key: { code: "KeyC", key: "c", keyCode: 67}}, { _: "input", range: [7,7], value: "hello c\n\n"}, { _: "keydown", range: [7,7], value: "hello c\n\n", key: { code: "KeyX", key: "x", keyCode: 88}}, @@ -136,10 +142,10 @@ module.exports = { }, { _: "keydown", range: [7,7], value: "hello ^x\n\n", key: { code: "Escape", key: "Escape", keyCode: 27}}, { _: "keydown", key: { code: "KeyH", key: "˛", keyCode: 72}, modifier: "ctrl-alt-"}, - + { _: "keydown", range: [1,6], value: "\thello x\n\n", key: { code: "AltRight", key: "Alt", keyCode: 18}, modifier: "alt-"}, { _: "keydown", range: [1,6], value: "\thello x\n\n", key: { code: "Digit4", key: "$", keyCode: 52}, modifier: "alt-"}, - + { _: "input", range: [2,2], value: "\t$ x\n\n"}, function() { testSelection(editor, [[1,5,1,8], [0,4,0,7]]); @@ -149,7 +155,7 @@ module.exports = { testSelection(editor, [[1,7],[0,6]]); }, { _: "keydown", key: { code: "Escape", key: "Escape", keyCode: 27}}, - + ].forEach(function(data) { applyEvent(data); }); @@ -162,7 +168,7 @@ module.exports = { { _: "keydown", range: [12,12], value: "\thello world\n\n", key: { code: "ControlLeft", key: "Control", keyCode: 17}, modifier: "ctrl-"}, { _: "keydown", range: [12,12], value: "\thello world\n\n", key: { code: "AltLeft", key: "Alt", keyCode: 18}, modifier: "ctrl-alt-"}, { _: "keydown", range: [6,11], value: "hello world\n\n", key: { code: "KeyL", key: "fi", keyCode: 76}, modifier: "ctrl-alt-"}, - + { _: "keydown", range: [6,11], value: "hello world\n\n", key: { code: "KeyC", key: "c", keyCode: 67}}, { _: "input", range: [7,7], value: "hello c\n\n"}, { _: "keydown", range: [7,7], value: "hello c\n\n", key: { code: "KeyX", key: "x", keyCode: 88}}, @@ -179,10 +185,10 @@ module.exports = { }, { _: "keydown", range: [7,7], value: "hello ^x\n\n", key: { code: "Escape", key: "Escape", keyCode: 27}}, { _: "keydown", key: { code: "KeyH", key: "˛", keyCode: 72}, modifier: "ctrl-alt-"}, - + { _: "keydown", range: [1,6], value: "\thello x\n\n", key: { code: "AltRight", key: "Alt", keyCode: 18}, modifier: "alt-"}, { _: "keydown", range: [1,6], value: "\thello x\n\n", key: { code: "Digit4", key: "$", keyCode: 52}, modifier: "alt-"}, - + { _: "input", range: [2,2], value: "\t$ x\n\n"}, function() { testSelection(editor, [[1,5,1,8], [0,4,0,7]]); @@ -192,7 +198,7 @@ module.exports = { testSelection(editor, [[1,7],[0,6]]); }, { _: "keydown", key: { code: "Escape", key: "Escape", keyCode: 27}}, - + ].forEach(function(data) { applyEvent(data); }); @@ -206,15 +212,15 @@ module.exports = { { _: "keyup", range: [1,1], value: "V\n\n", key: { code: "KeyV", key: "V", keyCode: 86}, modifier: "shift-"}, { _: "keyup", range: [1,1], value: "V\n\n", key: { code: "ShiftLeft", key: "Shift", keyCode: 16}}, { _: "keydown", range: [1,1], value: "V\n\n", key: { code: "KeyK", key: "k", keyCode: 75}}, - { _: "keypress", range: [1,1], value: "V\n\n", key: { code: "KeyK", key: "k", keyCode: 107}}, + { _: "keypress", range: [1,1], value: "V\n\n", key: { code: "KeyK", key: "k", keyCode: 107}}, { _: "input", range: [2,2], value: "Vk\n\n"}, { _: "keyup", range: [2,2], value: "Vk\n\n", key: { code: "KeyK", key: "k", keyCode: 75}}, { _: "keydown", range: [2,2], value: "Vk\n\n", key: { code: "KeyC", key: "c", keyCode: 67}}, - { _: "keypress", range: [2,2], value: "Vk\n\n", key: { code: "KeyC", key: "c", keyCode: 99}}, + { _: "keypress", range: [2,2], value: "Vk\n\n", key: { code: "KeyC", key: "c", keyCode: 99}}, { _: "input", range: [3,3], value: "Vkc\n\n"}, { _: "keyup", range: [3,3], value: "Vkc\n\n", key: { code: "KeyC", key: "c", keyCode: 67}}, { _: "keydown", range: [3,3], value: "Vkc\n\n", key: { code: "KeyO", key: "o", keyCode: 79}}, - { _: "keypress", range: [3,3], value: "Vkc\n\n", key: { code: "KeyO", key: "o", keyCode: 111}}, + { _: "keypress", range: [3,3], value: "Vkc\n\n", key: { code: "KeyO", key: "o", keyCode: 111}}, { _: "input", range: [4,4], value: "Vkco\n\n"}, { _: "keyup", range: [4,4], value: "Vkco\n\n", key: { code: "KeyO", key: "o", keyCode: 79}}, function() { @@ -224,12 +230,12 @@ module.exports = { { _: "keydown", range: [0,0], value: "ozzz\n\n", key: { code: "Escape", key: "Escape", keyCode: 27}}, { _: "keyup", range: [0,0], value: "ozzz\n\n", key: { code: "Escape", key: "Escape", keyCode: 27}}, { _: "keydown", range: [0,0], value: "ozzz\n\n", key: { code: "ControlLeft", key: "Control", keyCode: 17}, modifier: "ctrl-"}, - + { _: "keydown", range: [0,1], value: "ozzz\n\n", key: { code: "KeyV", key: "v", keyCode: 86}, modifier: "ctrl-"}, { _: "select", range: [0,1], value: "ozzz\n\n"}, { _: "keyup", range: [0,1], value: "ozzz\n\n", key: { code: "KeyV", key: "v", keyCode: 86}, modifier: "ctrl-"}, { _: "keyup", range: [0,1], value: "ozzz\n\n", key: { code: "ControlLeft", key: "Control", keyCode: 17}}, - + { _: "keydown", range: [0,1], value: "ccc\n\n", key: { code: "ArrowDown", key: "ArrowDown", keyCode: 40}}, { _: "select", range: [0,1], value: "ccc\n\n"}, { _: "keyup", range: [0,1], value: "ccc\n\n", key: { code: "ArrowDown", key: "ArrowDown", keyCode: 40}}, @@ -239,7 +245,7 @@ module.exports = { }, { _: "keydown", range: [0,1], value: "ccc\n\n", key: { code: "Period", key: ".", keyCode: 190}}, { _: "keypress", range: [0,1], value: "ccc\n\n", key: { code: "Period", key: ".", keyCode: 46}}, - + { _: "input", range: [1,1], value: ".cc\n\n"}, { _: "keyup", range: [1,1], value: ".cc\n\n", key: { code: "Period", key: ".", keyCode: 190}}, function() { @@ -252,8 +258,8 @@ module.exports = { }, "test vim gq": function() { editor.setValue( - "1\n2\nhello world\n" - + "xxx ".repeat(20) + "\nyyy" + "1\n2\nhello world\n" + + "xxx ".repeat(20) + "\nyyy" + "\n\nnext\nparagraph" ); editor.selection.moveTo(2,5) @@ -298,25 +304,19 @@ module.exports = { var screenSize = editor.renderer.layerConfig.height / editor.renderer.lineHeight; user.type("Escape", "gg"); - assert.equal(scollTop(), 0); + assert.equal(scrollTop(), 0); user.type("/", "needle"); - assert.ok(scollTop() > 40 - screenSize); + assert.ok(scrollTop() > 40 - screenSize); editor.endOperation(); user.type("Escape"); - assert.equal(scollTop(), 0); + assert.equal(scrollTop(), 0); user.type("/", "needle", "Enter"); - assert.ok(scollTop() > 40 - screenSize); - assert.ok(scollTop() < 40); + assert.ok(scrollTop() > 40 - screenSize); + assert.ok(scrollTop() < 40); user.type("6", "/", "more", "Enter"); editor.endOperation(); - assert.ok(scollTop() > 40 + 16 - screenSize); - - function scollTop() { - editor.endOperation(); - editor.renderer.$loop._flush(); - return editor.renderer.scrollTop / editor.renderer.lineHeight; - } + assert.ok(scrollTop() > 40 + 16 - screenSize); }, "test: vim normal mode brackets highlighting": function () { editor.setValue("{((hello, world))}"); @@ -345,6 +345,23 @@ module.exports = { }, isBackwards); assert.range(ranges[1], el.startRow, el.startColumn, el.endRow, el.endColumn); }); + }, + "test: gotoline": function () { + editor.renderer.setOption("animatedScroll", false); + editor.setValue( + "very\nlong\n\ntext\n".repeat(20), + -1 + ); + + editor.focus(); + var screenSize = editor.renderer.layerConfig.height / editor.renderer.lineHeight; + + assert.equal(scrollTop(), 0); + user.type(":30", "Enter"); + editor.endOperation(); + + assert.ok(scrollTop() > 30 - screenSize); + assert.ok(scrollTop() < 30); } }; From 11448fd0ac4a684a973f54261fc510143e145b39 Mon Sep 17 00:00:00 2001 From: Reza Salkhordeh Date: Sun, 20 Nov 2022 19:54:45 +0100 Subject: [PATCH 0695/1293] Update marker.js --- src/layer/marker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layer/marker.js b/src/layer/marker.js index 80443d17e6b..d7b99848a36 100644 --- a/src/layer/marker.js +++ b/src/layer/marker.js @@ -193,7 +193,7 @@ var Marker = function(parentEl) { this.elt( clazz, "height:" + height + "px;" + - "width:" + selection.width + (extraLength || 0) + "px;" + + "width:" + (selection.width + (extraLength || 0)) + "px;" + "top:" + top + "px;" + "left:" + (padding + selection.left) + "px;" + (extraStyle || "") ); From 6d2a3b0953bd261e76a273e2583d73d5c6c9fafb Mon Sep 17 00:00:00 2001 From: mkslanc Date: Fri, 25 Nov 2022 19:49:59 +0400 Subject: [PATCH 0696/1293] fix `Completer` and `Completion` declaration --- ace.d.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index 5c12afb81d5..5ac2dd3d377 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -311,11 +311,12 @@ export namespace Ace { } export interface Completion { - value: string; - score: number; + value?: string; + snippet?: string; + score?: number; meta?: string; - name?: string; caption?: string; + docHTML?: string; } export interface Tokenizer { @@ -913,6 +914,7 @@ export namespace Ace { position: Point, prefix: string, callback: CompleterCallback): void; + getDocTooltip(item: Completion): void; } } From eeefd8971bfc9bf68ed9fb0653c96def97ef3aaa Mon Sep 17 00:00:00 2001 From: mkslanc Date: Fri, 25 Nov 2022 19:57:15 +0400 Subject: [PATCH 0697/1293] add `typedef` for `Completion`; add two internal properties for `Completion` - `range` and `command` --- src/autocomplete.js | 30 ++++++++++++-- src/autocomplete_test.js | 69 +++++++++++++++++++++++++++++--- src/commands/default_commands.js | 6 +++ src/snippets.js | 11 +++-- 4 files changed, 103 insertions(+), 13 deletions(-) diff --git a/src/autocomplete.js b/src/autocomplete.js index b9ba51ca51d..0b12cbe4203 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -8,6 +8,18 @@ var dom = require("./lib/dom"); var snippetManager = require("./snippets").snippetManager; var config = require("./config"); +/** + * Completion represents a text snippet that is proposed to complete text + * @typedef Completion + * @property {string} [value] - text that would be inserted when selecting this completion (if `type` is "value") + * @property {string} [snippet] - snippet that would be inserted, if completion's type is "snippet" + * @property {number} [score] - determine order in which completions would be displayed, less score - further from start + * @property {string} [meta] - small description of completion + * @property {string} [caption] - text that would be displayed in completion list, if omitted `value` or `snippet` + * would be shown instead + * @property {string} [docHTML] - human-readable string that would be displayed as additional popup + */ + var Autocomplete = function() { this.autoInsert = false; this.autoSelect = true; @@ -158,9 +170,21 @@ var Autocomplete = function() { } } if (data.snippet) - snippetManager.insertSnippet(this.editor, data.snippet); - else - this.editor.execCommand("insertstring", data.value || data); + snippetManager.insertSnippet(this.editor, data.snippet, data.range); + else { + if (data.range) { + this.editor.execCommand("replacestring", { + range: data.range, + str: data.value || data + }); + } else { + this.editor.execCommand("insertstring", data.value || data); + } + } + + if (data.command && data.command === "startAutocomplete") { + this.editor.execCommand(data.command); + } } // detach only if new popup was not opened while inserting match if (this.completions == completions) diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index e060d532af7..06b69be0a52 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -7,6 +7,7 @@ if (typeof process !== "undefined") { var ace = require("./ace"); var assert = require("./test/assertions"); +var Range = require("./range").Range; require("./ext/language_tools"); module.exports = { @@ -21,17 +22,17 @@ module.exports = { // editor.container.style.height = "500px"; document.body.appendChild(editor.container); assert.ok(!editor.container.querySelector("style")); - + // workaround for autocomplete using non-relative path editor.renderer.$themeId = "./theme/textmate"; - + editor.execCommand("insertstring", "a"); checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { editor.execCommand("insertstring", "rr"); checkInnerHTML('arraysortlocal', function() { editor.execCommand("insertstring", "r"); checkInnerHTML('arraysortlocal', function() { - + editor.onCommandKey(null, 0, 13); assert.equal(editor.getValue(), "arraysort\narraysort alooooooooooooooooooooooooooooong_word"); editor.execCommand("insertstring", " looooooooooooooooooooooooooooong_"); @@ -44,15 +45,15 @@ module.exports = { }); }); }); - + var last; function checkInnerHTML(expected, callback) { var popup = editor.completer.popup; - + popup.renderer.on("afterRender", function wait() { var innerHTML = popup.renderer.$textLayer.element.innerHTML .replace(/\s*style="[^"]+"|class=|(d)iv|(s)pan/g, "$1$2"); - if (innerHTML == last) + if (innerHTML == last) return; assert.equal(innerHTML, expected); last = innerHTML; @@ -60,6 +61,62 @@ module.exports = { callback(); }); } + }, + "test: completions range and command properties": function (done) { + var editor = ace.edit(null, { + value: "goods ", + maxLines: 10, + enableBasicAutocompletion: true, + enableLiveAutocompletion: true + }); + + editor.completers = [ + { + getCompletions: function (editor, session, pos, prefix, callback) { + var completions = [ + { + caption: "will", + snippet: "will: $1", + meta: "snippet", + command: "startAutocomplete", + range: new Range(0, 4, 0, 6) + }, { + caption: "here", + value: "-here", + range: new Range(0, 8, 0, 10) + } + ]; + callback(null, completions); + } + } + ]; + document.body.appendChild(editor.container); + + // workaround for autocomplete using non-relative path + editor.renderer.$themeId = "./theme/textmate"; + + editor.moveCursorTo(0, 6); + editor.execCommand("insertstring", "w"); + var popup = editor.completer.popup; + check(function () { + assert.equal(popup.data.length, 1); + editor.onCommandKey(null, 0, 13); + assert.equal(popup.data.length, 2); + assert.equal(editor.getValue(), "goodwill: "); + check(function () { + editor.onCommandKey(null, 0, 13); + assert.equal(editor.getValue(), "goodwill-here"); + done(); + }); + }); + + function check(callback) { + popup = editor.completer.popup; + popup.renderer.on("afterRender", function wait() { + popup.renderer.off("afterRender", wait); + callback(); + }); + } } }; diff --git a/src/commands/default_commands.js b/src/commands/default_commands.js index d7c6413247d..d7606bc416c 100644 --- a/src/commands/default_commands.js +++ b/src/commands/default_commands.js @@ -695,6 +695,12 @@ exports.commands = [{ }, multiSelectAction: "forEach", scrollIntoView: "cursor" +}, { + name: "replacestring", + description: "Replace string", + exec: function(editor, args) { editor.session.replace(args.range, args.str); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" }, { name: "splitline", description: "Split line", diff --git a/src/snippets.js b/src/snippets.js index d54e3ead65c..3c93c5110f5 100644 --- a/src/snippets.js +++ b/src/snippets.js @@ -349,7 +349,7 @@ var SnippetManager = function() { return result; }; - this.insertSnippetForSelection = function(editor, snippetText) { + this.insertSnippetForSelection = function(editor, snippetText, replaceRange) { var cursor = editor.getCursorPosition(); var line = editor.session.getLine(cursor.row); var tabString = editor.session.getTabString(); @@ -467,6 +467,9 @@ var SnippetManager = function() { } }); var range = editor.getSelectionRange(); + if (replaceRange && replaceRange.compareRange(range) === 0) { + range = replaceRange; + } var end = editor.session.replace(range, text); var tabstopManager = new TabstopManager(editor); @@ -474,13 +477,13 @@ var SnippetManager = function() { tabstopManager.addTabstops(tabstops, range.start, end, selectionId); }; - this.insertSnippet = function(editor, snippetText) { + this.insertSnippet = function(editor, snippetText, replaceRange) { var self = this; if (editor.inVirtualSelectionMode) - return self.insertSnippetForSelection(editor, snippetText); + return self.insertSnippetForSelection(editor, snippetText, replaceRange); editor.forEachSelection(function() { - self.insertSnippetForSelection(editor, snippetText); + self.insertSnippetForSelection(editor, snippetText, replaceRange); }, null, {keepOrder: true}); if (editor.tabstopManager) From ceaaa967306950d06c247990fdc3fee1e1f2ce8f Mon Sep 17 00:00:00 2001 From: mkslanc Date: Mon, 28 Nov 2022 15:13:39 +0400 Subject: [PATCH 0698/1293] add ability to use separate `getDocTooltip` method for each completer --- ace.d.ts | 3 + src/autocomplete.js | 7 ++- src/autocomplete_test.js | 128 ++++++++++++++++++++++++++++++-------- src/ext/language_tools.js | 10 ++- 4 files changed, 118 insertions(+), 30 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index 5ac2dd3d377..ef22ecf3441 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -317,6 +317,8 @@ export namespace Ace { meta?: string; caption?: string; docHTML?: string; + docText?: string; + completerId?: string; } export interface Tokenizer { @@ -915,6 +917,7 @@ export namespace Ace { prefix: string, callback: CompleterCallback): void; getDocTooltip(item: Completion): void; + id?: string; } } diff --git a/src/autocomplete.js b/src/autocomplete.js index 0b12cbe4203..7d4b1ee6d83 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -17,7 +17,10 @@ var config = require("./config"); * @property {string} [meta] - small description of completion * @property {string} [caption] - text that would be displayed in completion list, if omitted `value` or `snippet` * would be shown instead - * @property {string} [docHTML] - human-readable string that would be displayed as additional popup + * @property {string} [docHTML] - html string that would be displayed as additional popup + * @property {string} [docText] - plain text that would be displayed as additional popup. If `docHtml` exists, it would + * be used instead of `docText` + * @property {string} [completerId] - completer's identifier */ var Autocomplete = function() { @@ -364,7 +367,7 @@ var Autocomplete = function() { if (!selected || !this.editor || !this.popup.isOpen) return this.hideDocTooltip(); this.editor.completers.some(function(completer) { - if (completer.getDocTooltip) + if (completer.getDocTooltip && selected.completerId === completer.id) doc = completer.getDocTooltip(selected); return doc; }); diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index 06b69be0a52..eed634bbf01 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -10,21 +10,27 @@ var assert = require("./test/assertions"); var Range = require("./range").Range; require("./ext/language_tools"); +function initEditor(value) { + var editor = ace.edit(null, { + value: value, + maxLines: 10, + enableBasicAutocompletion: true, + enableLiveAutocompletion: true + }); + document.body.appendChild(editor.container); + + // workaround for autocomplete using non-relative path + editor.renderer.$themeId = "./theme/textmate"; + return editor; +} + module.exports = { - "test: highlighting in the popup" : function(done) { - var editor = ace.edit(null, { - value: "\narraysort alooooooooooooooooooooooooooooong_word", - maxLines: 10, - enableBasicAutocompletion: true, - enableLiveAutocompletion: true - }); - // editor.container.style.width = "500px"; - // editor.container.style.height = "500px"; - document.body.appendChild(editor.container); - assert.ok(!editor.container.querySelector("style")); + "test: highlighting in the popup": function (done) { + var editor = initEditor("\narraysort alooooooooooooooooooooooooooooong_word"); + // editor.container.style.width = "500px"; + // editor.container.style.height = "500px"; - // workaround for autocomplete using non-relative path - editor.renderer.$themeId = "./theme/textmate"; + assert.ok(!editor.container.querySelector("style")); editor.execCommand("insertstring", "a"); checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { @@ -53,8 +59,7 @@ module.exports = { popup.renderer.on("afterRender", function wait() { var innerHTML = popup.renderer.$textLayer.element.innerHTML .replace(/\s*style="[^"]+"|class=|(d)iv|(s)pan/g, "$1$2"); - if (innerHTML == last) - return; + if (innerHTML == last) return; assert.equal(innerHTML, expected); last = innerHTML; popup.renderer.off("afterRender", wait); @@ -63,12 +68,7 @@ module.exports = { } }, "test: completions range and command properties": function (done) { - var editor = ace.edit(null, { - value: "goods ", - maxLines: 10, - enableBasicAutocompletion: true, - enableLiveAutocompletion: true - }); + var editor = initEditor("goods "); editor.completers = [ { @@ -90,10 +90,6 @@ module.exports = { } } ]; - document.body.appendChild(editor.container); - - // workaround for autocomplete using non-relative path - editor.renderer.$themeId = "./theme/textmate"; editor.moveCursorTo(0, 6); editor.execCommand("insertstring", "w"); @@ -106,6 +102,8 @@ module.exports = { check(function () { editor.onCommandKey(null, 0, 13); assert.equal(editor.getValue(), "goodwill-here"); + editor.destroy(); + editor.container.remove(); done(); }); }); @@ -117,6 +115,86 @@ module.exports = { callback(); }); } + }, + "test: different completers tooltips": function (done) { + var editor = initEditor(""); + var firstDoc = "First"; + var secondDoc = "Second"; + editor.completers = [ + { + getCompletions: function (editor, session, pos, prefix, callback) { + var completions = [ + { + caption: "abc", + snippet: "ab: $1", + meta: "snippet", + completerId: "firstCompleter" + }, { + caption: "cde", + value: "cde", + completerId: "firstCompleter" + } + ]; + callback(null, completions); + }, + getDocTooltip: function (item) { + if (!item.docHTML) { + item.docHTML = firstDoc; + } + }, + id: "firstCompleter" + }, { + getCompletions: function (editor, session, pos, prefix, callback) { + var completions = [ + { + caption: "abcd", + snippet: "abcd: $1", + meta: "snippet", + completerId: "secondCompleter" + }, { + caption: "cdef", + value: "cdef", + completerId: "secondCompleter" + } + ]; + callback(null, completions); + }, + getDocTooltip: function (item) { + if (!item.docText) { + item.docText = secondDoc; + } + }, + id: "secondCompleter" + } + ]; + + editor.execCommand("insertstring", "c"); + var popup = editor.completer.popup; + check(function () { + assert.equal(popup.data.length, 4); + assert.equal(document.body.lastChild.innerHTML, firstDoc); + editor.onCommandKey(null, 0, 40); + check(function () { + assert.equal(document.body.lastChild.innerHTML, secondDoc); + editor.onCommandKey(null, 0, 40); + check(function () { + assert.equal(document.body.lastChild.innerHTML, firstDoc); + editor.onCommandKey(null, 0, 40); + check(function () { + assert.equal(document.body.lastChild.innerHTML, secondDoc); + editor.destroy(); + editor.container.remove(); + done(); + }); + }); + }); + }); + + function check(callback) { + setTimeout(function wait() { + callback(); + }, 70); + } } }; diff --git a/src/ext/language_tools.js b/src/ext/language_tools.js index 943e4af9b1e..f34c2c741eb 100644 --- a/src/ext/language_tools.js +++ b/src/ext/language_tools.js @@ -14,8 +14,10 @@ var keyWordCompleter = { } var state = editor.session.getState(pos.row); var completions = session.$mode.getCompletions(state, session, pos, prefix); + completions = completions.map((el) => el.completerId = keyWordCompleter.id); callback(null, completions); - } + }, + id: "keywordCompleter" }; var transformSnippetTooltip = function(str) { @@ -51,7 +53,8 @@ var snippetCompleter = { caption: caption, snippet: s.content, meta: s.tabTrigger && !s.name ? s.tabTrigger + "\u21E5 " : "snippet", - type: "snippet" + type: "snippet", + completerId: snippetCompleter.id }); } }, this); @@ -64,7 +67,8 @@ var snippetCompleter = { lang.escapeHTML(transformSnippetTooltip(item.snippet)) ].join(""); } - } + }, + id: "snippetCompleter" }; var completers = [snippetCompleter, textCompleter, keyWordCompleter]; From 043b2e4892baf956c1a69fdc34990b87121b53c2 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Mon, 28 Nov 2022 15:43:37 +0400 Subject: [PATCH 0699/1293] fix wrong replace command for basic completions (not snippets one) --- src/autocomplete.js | 29 +++++++++++++++++++++-------- src/commands/default_commands.js | 6 ------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/autocomplete.js b/src/autocomplete.js index 7d4b1ee6d83..d7cf964bf5a 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -175,14 +175,7 @@ var Autocomplete = function() { if (data.snippet) snippetManager.insertSnippet(this.editor, data.snippet, data.range); else { - if (data.range) { - this.editor.execCommand("replacestring", { - range: data.range, - str: data.value || data - }); - } else { - this.editor.execCommand("insertstring", data.value || data); - } + this.$insertString(data); } if (data.command && data.command === "startAutocomplete") { @@ -195,6 +188,26 @@ var Autocomplete = function() { this.editor.endOperation(); }; + this.$insertString = function (data) { + var text = data.value || data; + if (data.range) { + if (this.editor.inVirtualSelectionMode) { + return this.editor.session.replace(data.range, text); + } + this.editor.forEachSelection(() => { + var range = this.editor.getSelectionRange(); + if (data.range.compareRange(range) === 0) { + this.editor.session.replace(data.range, text); + } + else { + this.editor.insert(text); + } + }, null, {keepOrder: true}); + } + else { + this.editor.execCommand("insertstring", text); + } + }; this.commands = { "Up": function(editor) { editor.completer.goTo("up"); }, diff --git a/src/commands/default_commands.js b/src/commands/default_commands.js index d7606bc416c..d7c6413247d 100644 --- a/src/commands/default_commands.js +++ b/src/commands/default_commands.js @@ -695,12 +695,6 @@ exports.commands = [{ }, multiSelectAction: "forEach", scrollIntoView: "cursor" -}, { - name: "replacestring", - description: "Replace string", - exec: function(editor, args) { editor.session.replace(args.range, args.str); }, - multiSelectAction: "forEach", - scrollIntoView: "cursor" }, { name: "splitline", description: "Split line", From 451b63f2243762d6de2fc5b9ee8c580c348b933c Mon Sep 17 00:00:00 2001 From: Kay J Date: Wed, 30 Nov 2022 13:41:33 +0100 Subject: [PATCH 0700/1293] fix: Add missing options to `EditorOptions` (#5003) --- ace.d.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ace.d.ts b/ace.d.ts index 5c12afb81d5..222b68b43e4 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -217,6 +217,9 @@ export namespace Ace { behavioursEnabled: boolean; wrapBehavioursEnabled: boolean; enableAutoIndent: boolean; + enableBasicAutocompletion: boolean | Completer[], + enableLiveAutocompletion: boolean | Completer[], + enableSnippets: boolean, autoScrollEditorIntoView: boolean; keyboardHandler: string | null; placeholder: string; @@ -935,4 +938,4 @@ export const Range: { new(startRow: number, startColumn: number, endRow: number, endColumn: number): Ace.Range; fromPoints(start: Ace.Point, end: Ace.Point): Ace.Range; comparePoints(p1: Ace.Point, p2: Ace.Point): number; -}; \ No newline at end of file +}; From 5016e9030a8b41672f98816a8ddcedcca188fb80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Oliveira?= Date: Wed, 7 Dec 2022 18:14:07 +0100 Subject: [PATCH 0701/1293] release v1.13.2 --- CHANGELOG.md | 10 ++++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f6c73c845e..5727e7c5e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.13.2](https://github.com/ajaxorg/ace/compare/v1.13.1...v1.13.2) (2022-12-07) + + +### Bug Fixes + +* Add missing options to `EditorOptions` ([#5003](https://github.com/ajaxorg/ace/issues/5003)) ([451b63f](https://github.com/ajaxorg/ace/commit/451b63f2243762d6de2fc5b9ee8c580c348b933c)) +* Better ES6 support for JavaScript Mode ([6fb39e3](https://github.com/ajaxorg/ace/commit/6fb39e38c79dd966233e48ed06be800c59c4c101)) +* Fix vim keybindings scroll to the selected line ([#4980](https://github.com/ajaxorg/ace/issues/4980)) ([8562f94](https://github.com/ajaxorg/ace/commit/8562f9493e0ebef865064992f0526fdc6df8535a)) +* show 2 context characters of a line when moving to it ([#4998](https://github.com/ajaxorg/ace/issues/4998)) ([743190e](https://github.com/ajaxorg/ace/commit/743190ea71841c0186b2f513b3d1e1a9e30d3de3)) + ### [1.13.1](https://github.com/ajaxorg/ace/compare/v1.13.0...v1.13.1) (2022-11-16) diff --git a/build b/build index fdab4a6eabe..44279f41911 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit fdab4a6eabe634f888533e3a3922016c83f18d94 +Subproject commit 44279f4191129f1cad89f4c550ea98c2c2fd2203 diff --git a/package.json b/package.json index e50e91cd887..e240e09fa36 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.13.1", + "version": "1.13.2", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index bca147a4f82..cd7319bb43d 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.13.1"; +exports.version = "1.13.2"; From 3b7bb5e4afbad0f2bdbc7f8487442a5cb78b8284 Mon Sep 17 00:00:00 2001 From: aoyku <116817988+aoyku@users.noreply.github.com> Date: Fri, 9 Dec 2022 12:04:23 +0100 Subject: [PATCH 0702/1293] feat: Autocomplete accessibility features (#5008) * Accessible autocomplete * remove ace_line_id and fix autocompletion tests --- src/autocomplete.js | 2 ++ src/autocomplete/popup.js | 23 +++++++++++++++++++++-- src/autocomplete_test.js | 8 ++++---- src/keyboard/textinput.js | 18 +++++++++++++++++- src/layer/text.js | 1 + 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/autocomplete.js b/src/autocomplete.js index b9ba51ca51d..546c3538c36 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -2,6 +2,7 @@ var HashHandler = require("./keyboard/hash_handler").HashHandler; var AcePopup = require("./autocomplete/popup").AcePopup; +var getAriaId = require("./autocomplete/popup").getAriaId; var util = require("./autocomplete/util"); var lang = require("./lib/lang"); var dom = require("./lib/dom"); @@ -54,6 +55,7 @@ var Autocomplete = function() { this.popup.autoSelect = this.autoSelect; this.popup.setData(this.completions.filtered, this.completions.filterText); + this.editor.textInput.setAriaOptions({activeDescendant: getAriaId(this.popup.getRow())}); editor.keyBinding.addKeyboardHandler(this.keyboardHandler); diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js index ed48d279c3a..494166fa976 100644 --- a/src/autocomplete/popup.js +++ b/src/autocomplete/popup.js @@ -7,6 +7,10 @@ var event = require("../lib/event"); var lang = require("../lib/lang"); var dom = require("../lib/dom"); +var getAriaId = function(index) { + return `suggest-aria-id:${index}`; +}; + var $singleLineEditor = function(el) { var renderer = new Renderer(el); @@ -45,6 +49,10 @@ var AcePopup = function(parentNode) { popup.renderer.content.style.cursor = "default"; popup.renderer.setStyle("ace_autocomplete"); + // Set aria attributes for the popup + popup.renderer.container.setAttribute("role", "listbox"); + popup.renderer.container.setAttribute("aria-label", "Autocomplete suggestions"); + popup.setOption("displayIndentGuides", false); popup.setOption("dragDelay", 150); @@ -114,11 +122,21 @@ var AcePopup = function(parentNode) { var row = popup.getRow(); var t = popup.renderer.$textLayer; var selected = t.element.childNodes[row - t.config.firstRow]; - if (selected !== t.selectedNode && t.selectedNode) + var el = document.activeElement; // Active element is textarea of main editor + if (selected !== t.selectedNode && t.selectedNode) { dom.removeCssClass(t.selectedNode, "ace_selected"); + el.removeAttribute("aria-activedescendant"); + t.selectedNode.removeAttribute("id"); + } t.selectedNode = selected; - if (selected) + if (selected) { dom.addCssClass(selected, "ace_selected"); + var ariaId = getAriaId(row); + selected.id = ariaId; + popup.renderer.container.setAttribute("aria-activedescendant", ariaId); + el.setAttribute("aria-activedescendant", ariaId); + selected.setAttribute("aria-label", popup.getData(row).value); + } }); var hideHoverMarker = function() { setHoverMarker(-1); }; var setHoverMarker = function(row, suppressRedraw) { @@ -350,3 +368,4 @@ dom.importCssString(` exports.AcePopup = AcePopup; exports.$singleLineEditor = $singleLineEditor; +exports.getAriaId = getAriaId; diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index e060d532af7..8352f52f7e5 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -26,16 +26,16 @@ module.exports = { editor.renderer.$themeId = "./theme/textmate"; editor.execCommand("insertstring", "a"); - checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { + checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { editor.execCommand("insertstring", "rr"); - checkInnerHTML('arraysortlocal', function() { + checkInnerHTML('arraysortlocal', function() { editor.execCommand("insertstring", "r"); - checkInnerHTML('arraysortlocal', function() { + checkInnerHTML('arraysortlocal', function() { editor.onCommandKey(null, 0, 13); assert.equal(editor.getValue(), "arraysort\narraysort alooooooooooooooooooooooooooooong_word"); editor.execCommand("insertstring", " looooooooooooooooooooooooooooong_"); - checkInnerHTML('alooooooooooooooooooooooooooooong_wordlocal', function() { + checkInnerHTML('alooooooooooooooooooooooooooooong_wordlocal', function() { editor.onCommandKey(null, 0, 13); editor.destroy(); editor.container.remove(); diff --git a/src/keyboard/textinput.js b/src/keyboard/textinput.js index d11bef59307..1ee56031e2c 100644 --- a/src/keyboard/textinput.js +++ b/src/keyboard/textinput.js @@ -48,7 +48,23 @@ var TextInput = function(parentNode, host) { // FOCUS // ie9 throws error if document.activeElement is accessed too soon try { var isFocused = document.activeElement === text; } catch(e) {} - + + this.setAriaOptions = function(options) { + if (options.activeDescendant) { + text.setAttribute("aria-haspopup", "true"); + text.setAttribute("aria-autocomplete", "list"); + text.setAttribute("aria-activedescendant", options.activeDescendant); + } else { + text.setAttribute("aria-haspopup", "false"); + text.setAttribute("aria-autocomplete", "both"); + text.removeAttribute("aria-activedescendant"); + } + if (options.role) { + text.setAttribute("role", options.role); + } + }; + this.setAriaOptions({role: "textbox"}); + event.addListener(text, "blur", function(e) { if (ignoreFocusEvents) return; host.onBlur(e); diff --git a/src/layer/text.js b/src/layer/text.js index 3e94d48f634..87f50ece9c7 100644 --- a/src/layer/text.js +++ b/src/layer/text.js @@ -293,6 +293,7 @@ var Text = function(parentEl) { lineEl.className = "ace_line_group"; } else { lineEl.className = "ace_line"; + lineEl.setAttribute("role", "option"); } fragment.push(line); From e3f3e7ab3efe540ac345325f06278a8ab1871371 Mon Sep 17 00:00:00 2001 From: Slava Rozhnev Date: Sat, 10 Dec 2022 15:15:49 +0200 Subject: [PATCH 0703/1293] fix: added GREATEST|LEAST logical functions added in SQL Server 2022 (#5009) * added GREATEST|LEAST logical functions added in SQL Server 2022 * functions added in SQL Server 2022 --- src/mode/sqlserver_highlight_rules.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/mode/sqlserver_highlight_rules.js b/src/mode/sqlserver_highlight_rules.js index 6575fc6a9d2..521a3c7a980 100644 --- a/src/mode/sqlserver_highlight_rules.js +++ b/src/mode/sqlserver_highlight_rules.js @@ -30,7 +30,7 @@ var SqlServerHighlightRules = function() { /* https://msdn.microsoft.com/en-us/library/ms186285.aspx */ "@@CURSOR_ROWS|@@FETCH_STATUS|CURSOR_STATUS|" + /* https://msdn.microsoft.com/en-us/library/ms186724.aspx */ - "@@DATEFIRST|@@LANGUAGE|CURRENT_TIMESTAMP|DATEADD|DATEDIFF|DATEFROMPARTS|DATENAME|DATEPART|DATETIME2FROMPARTS|DATETIMEFROMPARTS|DATETIMEOFFSETFROMPARTS|DAY|EOMONTH|GETDATE|GETUTCDATE|ISDATE|MONTH|SET DATEFIRST|SET DATEFORMAT|SET LANGUAGE|SMALLDATETIMEFROMPARTS|SP_HELPLANGUAGE|SWITCHOFFSET|SYSDATETIME|SYSDATETIMEOFFSET|SYSUTCDATETIME|TIMEFROMPARTS|TODATETIMEOFFSET|YEAR|" + + "@@DATEFIRST|@@LANGUAGE|CURRENT_TIMESTAMP|DATEADD|DATEDIFF|DATEFROMPARTS|DATENAME|DATEPART|DATETIME2FROMPARTS|DATETIMEFROMPARTS|DATETIMEOFFSETFROMPARTS|DAY|EOMONTH|GETDATE|GETUTCDATE|ISDATE|MONTH|SET DATEFIRST|SET DATEFORMAT|SET LANGUAGE|SMALLDATETIMEFROMPARTS|SP_HELPLANGUAGE|SWITCHOFFSET|SYSDATETIME|SYSDATETIMEOFFSET|SYSUTCDATETIME|TIMEFROMPARTS|TODATETIMEOFFSET|YEAR|DATETRUNC|" + /* https://msdn.microsoft.com/en-us/library/hh213226.aspx */ "CHOOSE|IIF|" + /* https://msdn.microsoft.com/en-us/library/ms177516.aspx */ @@ -47,6 +47,14 @@ var SqlServerHighlightRules = function() { "@@CONNECTIONS|@@CPU_BUSY|@@IDLE|@@IO_BUSY|@@PACKET_ERRORS|@@PACK_RECEIVED|@@PACK_SENT|@@TIMETICKS|@@TOTAL_ERRORS|@@TOTAL_READ|@@TOTAL_WRITE|FN_VIRTUALFILESTATS|" + /* https://msdn.microsoft.com/en-us/library/ms188353.aspx */ "PATINDEX|TEXTPTR|TEXTVALID|" + + /* logical */ + "GREATEST|LEAST|" + + /* time series functions */ + "GENERATE_SERIES|DATE_BUCKET|" + + /* JSON functions */ + "JSON_ARRAY|JSON_OBJECT|JSON_PATH_EXISTS|ISJSON|" + + /* window functions */ + "FIRST_VALUE|LAST_VALUE|" + /* other */ "COALESCE|NULLIF" ); @@ -61,7 +69,7 @@ var SqlServerHighlightRules = function() { // https://msdn.microsoft.com/en-us/library/ms189822.aspx - var keywords = "ABSOLUTE|ACTION|ADA|ADD|ADMIN|AFTER|AGGREGATE|ALIAS|ALL|ALLOCATE|ALTER|AND|ANY|ARE|ARRAY|AS|ASC|ASENSITIVE|ASSERTION|ASYMMETRIC|AT|ATOMIC|AUTHORIZATION|BACKUP|BEFORE|BEGIN|BETWEEN|BIT_LENGTH|BLOB|BOOLEAN|BOTH|BREADTH|BREAK|BROWSE|BULK|BY|CALL|CALLED|CARDINALITY|CASCADE|CASCADED|CASE|CATALOG|CHARACTER|CHARACTER_LENGTH|CHAR_LENGTH|CHECK|CHECKPOINT|CLASS|CLOB|CLOSE|CLUSTERED|COALESCE|COLLATE|COLLATION|COLLECT|COLUMN|COMMIT|COMPLETION|COMPUTE|CONDITION|CONNECT|CONNECTION|CONSTRAINT|CONSTRAINTS|CONSTRUCTOR|CONTAINS|CONTAINSTABLE|CONTINUE|CORR|CORRESPONDING|COVAR_POP|COVAR_SAMP|CREATE|CROSS|CUBE|CUME_DIST|CURRENT|CURRENT_CATALOG|CURRENT_DATE|CURRENT_DEFAULT_TRANSFORM_GROUP|CURRENT_PATH|CURRENT_ROLE|CURRENT_SCHEMA|CURRENT_TIME|CURRENT_TRANSFORM_GROUP_FOR_TYPE|CYCLE|DATA|DATABASE|DBCC|DEALLOCATE|DEC|DECLARE|DEFAULT|DEFERRABLE|DEFERRED|DELETE|DENY|DEPTH|DEREF|DESC|DESCRIBE|DESCRIPTOR|DESTROY|DESTRUCTOR|DETERMINISTIC|DIAGNOSTICS|DICTIONARY|DISCONNECT|DISK|DISTINCT|DISTRIBUTED|DOMAIN|DOUBLE|DROP|DUMP|DYNAMIC|EACH|ELEMENT|ELSE|END|END-EXEC|EQUALS|ERRLVL|ESCAPE|EVERY|EXCEPT|EXCEPTION|EXEC|EXECUTE|EXISTS|EXIT|EXTERNAL|EXTRACT|FETCH|FILE|FILLFACTOR|FILTER|FIRST|FOR|FOREIGN|FORTRAN|FOUND|FREE|FREETEXT|FREETEXTTABLE|FROM|FULL|FULLTEXTTABLE|FUNCTION|FUSION|GENERAL|GET|GLOBAL|GO|GOTO|GRANT|GROUP|HAVING|HOLD|HOLDLOCK|HOST|HOUR|IDENTITY|IDENTITYCOL|IDENTITY_INSERT|IF|IGNORE|IMMEDIATE|IN|INCLUDE|INDEX|INDICATOR|INITIALIZE|INITIALLY|INNER|INOUT|INPUT|INSENSITIVE|INSERT|INTEGER|INTERSECT|INTERSECTION|INTERVAL|INTO|IS|ISOLATION|ITERATE|JOIN|KEY|KILL|LANGUAGE|LARGE|LAST|LATERAL|LEADING|LESS|LEVEL|LIKE|LIKE_REGEX|LIMIT|LINENO|LN|LOAD|LOCAL|LOCALTIME|LOCALTIMESTAMP|LOCATOR|MAP|MATCH|MEMBER|MERGE|METHOD|MINUTE|MOD|MODIFIES|MODIFY|MODULE|MULTISET|NAMES|NATIONAL|NATURAL|NCLOB|NEW|NEXT|NO|NOCHECK|NONCLUSTERED|NONE|NORMALIZE|NOT|NULL|NULLIF|OBJECT|OCCURRENCES_REGEX|OCTET_LENGTH|OF|OFF|OFFSETS|OLD|ON|ONLY|OPEN|OPERATION|OPTION|OR|ORDER|ORDINALITY|OUT|OUTER|OUTPUT|OVER|OVERLAPS|OVERLAY|PAD|PARAMETER|PARAMETERS|PARTIAL|PARTITION|PASCAL|PATH|PERCENT|PERCENTILE_CONT|PERCENTILE_DISC|PERCENT_RANK|PIVOT|PLAN|POSITION|POSITION_REGEX|POSTFIX|PRECISION|PREFIX|PREORDER|PREPARE|PRESERVE|PRIMARY|PRINT|PRIOR|PRIVILEGES|PROC|PROCEDURE|PUBLIC|RAISERROR|RANGE|READ|READS|READTEXT|RECONFIGURE|RECURSIVE|REF|REFERENCES|REFERENCING|REGR_AVGX|REGR_AVGY|REGR_COUNT|REGR_INTERCEPT|REGR_R2|REGR_SLOPE|REGR_SXX|REGR_SXY|REGR_SYY|RELATIVE|RELEASE|REPLICATION|RESTORE|RESTRICT|RESULT|RETURN|RETURNS|REVERT|REVOKE|ROLE|ROLLBACK|ROLLUP|ROUTINE|ROW|ROWCOUNT|ROWGUIDCOL|ROWS|RULE|SAVE|SAVEPOINT|SCHEMA|SCOPE|SCROLL|SEARCH|SECOND|SECTION|SECURITYAUDIT|SELECT|SEMANTICKEYPHRASETABLE|SEMANTICSIMILARITYDETAILSTABLE|SEMANTICSIMILARITYTABLE|SENSITIVE|SEQUENCE|SESSION|SET|SETS|SETUSER|SHUTDOWN|SIMILAR|SIZE|SOME|SPECIFIC|SPECIFICTYPE|SQL|SQLCA|SQLCODE|SQLERROR|SQLEXCEPTION|SQLSTATE|SQLWARNING|START|STATE|STATEMENT|STATIC|STATISTICS|STDDEV_POP|STDDEV_SAMP|STRUCTURE|SUBMULTISET|SUBSTRING_REGEX|SYMMETRIC|SYSTEM|TABLESAMPLE|TEMPORARY|TERMINATE|TEXTSIZE|THAN|THEN|TIMEZONE_HOUR|TIMEZONE_MINUTE|TO|TOP|TRAILING|TRAN|TRANSACTION|TRANSLATE|TRANSLATE_REGEX|TRANSLATION|TREAT|TRIGGER|TRIM|TRUNCATE|TSEQUAL|UESCAPE|UNDER|UNION|UNIQUE|UNKNOWN|UNNEST|UNPIVOT|UPDATE|UPDATETEXT|USAGE|USE|USER|USING|VALUE|VALUES|VARIABLE|VARYING|VAR_POP|VAR_SAMP|VIEW|WAITFOR|WHEN|WHENEVER|WHERE|WHILE|WIDTH_BUCKET|WINDOW|WITH|WITHIN|WITHIN GROUP|WITHOUT|WORK|WRITE|WRITETEXT|XMLAGG|XMLATTRIBUTES|XMLBINARY|XMLCAST|XMLCOMMENT|XMLCONCAT|XMLDOCUMENT|XMLELEMENT|XMLEXISTS|XMLFOREST|XMLITERATE|XMLNAMESPACES|XMLPARSE|XMLPI|XMLQUERY|XMLSERIALIZE|XMLTABLE|XMLTEXT|XMLVALIDATE|ZONE"; + var keywords = "ABSOLUTE|ACTION|ADA|ADD|ADMIN|AFTER|AGGREGATE|ALIAS|ALL|ALLOCATE|ALTER|AND|ANY|ARE|ARRAY|AS|ASC|ASENSITIVE|ASSERTION|ASYMMETRIC|AT|ATOMIC|AUTHORIZATION|BACKUP|BEFORE|BEGIN|BETWEEN|BIT_LENGTH|BLOB|BOOLEAN|BOTH|BREADTH|BREAK|BROWSE|BULK|BY|CALL|CALLED|CARDINALITY|CASCADE|CASCADED|CASE|CATALOG|CHARACTER|CHARACTER_LENGTH|CHAR_LENGTH|CHECK|CHECKPOINT|CLASS|CLOB|CLOSE|CLUSTERED|COALESCE|COLLATE|COLLATION|COLLECT|COLUMN|COMMIT|COMPLETION|COMPUTE|CONDITION|CONNECT|CONNECTION|CONSTRAINT|CONSTRAINTS|CONSTRUCTOR|CONTAINS|CONTAINSTABLE|CONTINUE|CORR|CORRESPONDING|COVAR_POP|COVAR_SAMP|CREATE|CROSS|CUBE|CUME_DIST|CURRENT|CURRENT_CATALOG|CURRENT_DATE|CURRENT_DEFAULT_TRANSFORM_GROUP|CURRENT_PATH|CURRENT_ROLE|CURRENT_SCHEMA|CURRENT_TIME|CURRENT_TRANSFORM_GROUP_FOR_TYPE|CYCLE|DATA|DATABASE|DBCC|DEALLOCATE|DEC|DECLARE|DEFAULT|DEFERRABLE|DEFERRED|DELETE|DENY|DEPTH|DEREF|DESC|DESCRIBE|DESCRIPTOR|DESTROY|DESTRUCTOR|DETERMINISTIC|DIAGNOSTICS|DICTIONARY|DISCONNECT|DISK|DISTINCT|DISTRIBUTED|DOMAIN|DOUBLE|DROP|DUMP|DYNAMIC|EACH|ELEMENT|ELSE|END|END-EXEC|EQUALS|ERRLVL|ESCAPE|EVERY|EXCEPT|EXCEPTION|EXEC|EXECUTE|EXISTS|EXIT|EXTERNAL|EXTRACT|FETCH|FILE|FILLFACTOR|FILTER|FIRST|FOR|FOREIGN|FORTRAN|FOUND|FREE|FREETEXT|FREETEXTTABLE|FROM|FULL|FULLTEXTTABLE|FUNCTION|FUSION|GENERAL|GET|GLOBAL|GO|GOTO|GRANT|GROUP|HAVING|HOLD|HOLDLOCK|HOST|HOUR|IDENTITY|IDENTITYCOL|IDENTITY_INSERT|IF|IGNORE|IMMEDIATE|IN|INCLUDE|INDEX|INDICATOR|INITIALIZE|INITIALLY|INNER|INOUT|INPUT|INSENSITIVE|INSERT|INTEGER|INTERSECT|INTERSECTION|INTERVAL|INTO|IS|ISOLATION|ITERATE|JOIN|KEY|KILL|LANGUAGE|LARGE|LAST|LATERAL|LEADING|LESS|LEVEL|LIKE|LIKE_REGEX|LIMIT|LINENO|LN|LOAD|LOCAL|LOCALTIME|LOCALTIMESTAMP|LOCATOR|MAP|MATCH|MEMBER|MERGE|METHOD|MINUTE|MOD|MODIFIES|MODIFY|MODULE|MULTISET|NAMES|NATIONAL|NATURAL|NCLOB|NEW|NEXT|NO|NOCHECK|NONCLUSTERED|NONE|NORMALIZE|NOT|NULL|NULLIF|OBJECT|OCCURRENCES_REGEX|OCTET_LENGTH|OF|OFF|OFFSETS|OLD|ON|ONLY|OPEN|OPERATION|OPTION|OR|ORDER|ORDINALITY|OUT|OUTER|OUTPUT|OVER|OVERLAPS|OVERLAY|PAD|PARAMETER|PARAMETERS|PARTIAL|PARTITION|PASCAL|PATH|PERCENT|PERCENTILE_CONT|PERCENTILE_DISC|PERCENT_RANK|PIVOT|PLAN|POSITION|POSITION_REGEX|POSTFIX|PRECISION|PREFIX|PREORDER|PREPARE|PRESERVE|PRIMARY|PRINT|PRIOR|PRIVILEGES|PROC|PROCEDURE|PUBLIC|RAISERROR|RANGE|READ|READS|READTEXT|RECONFIGURE|RECURSIVE|REF|REFERENCES|REFERENCING|REGR_AVGX|REGR_AVGY|REGR_COUNT|REGR_INTERCEPT|REGR_R2|REGR_SLOPE|REGR_SXX|REGR_SXY|REGR_SYY|RELATIVE|RELEASE|REPLICATION|RESTORE|RESTRICT|RESULT|RETURN|RETURNS|REVERT|REVOKE|ROLE|ROLLBACK|ROLLUP|ROUTINE|ROW|ROWCOUNT|ROWGUIDCOL|ROWS|RULE|SAVE|SAVEPOINT|SCHEMA|SCOPE|SCROLL|SEARCH|SECOND|SECTION|SECURITYAUDIT|SELECT|SEMANTICKEYPHRASETABLE|SEMANTICSIMILARITYDETAILSTABLE|SEMANTICSIMILARITYTABLE|SENSITIVE|SEQUENCE|SESSION|SET|SETS|SETUSER|SHUTDOWN|SIMILAR|SIZE|SOME|SPECIFIC|SPECIFICTYPE|SQL|SQLCA|SQLCODE|SQLERROR|SQLEXCEPTION|SQLSTATE|SQLWARNING|START|STATE|STATEMENT|STATIC|STATISTICS|STDDEV_POP|STDDEV_SAMP|STRUCTURE|SUBMULTISET|SUBSTRING_REGEX|STRING_SPLIT|SYMMETRIC|SYSTEM|TABLESAMPLE|TEMPORARY|TERMINATE|TEXTSIZE|THAN|THEN|TIMEZONE_HOUR|TIMEZONE_MINUTE|TO|TOP|TRAILING|TRAN|TRANSACTION|TRANSLATE|TRANSLATE_REGEX|TRANSLATION|TREAT|TRIGGER|TRIM|TRUNCATE|TSEQUAL|UESCAPE|UNDER|UNION|UNIQUE|UNKNOWN|UNNEST|UNPIVOT|UPDATE|UPDATETEXT|USAGE|USE|USER|USING|VALUE|VALUES|VARIABLE|VARYING|VAR_POP|VAR_SAMP|VIEW|WAITFOR|WHEN|WHENEVER|WHERE|WHILE|WIDTH_BUCKET|WINDOW|WITH|WITHIN|WITHIN GROUP|WITHOUT|WORK|WRITE|WRITETEXT|XMLAGG|XMLATTRIBUTES|XMLBINARY|XMLCAST|XMLCOMMENT|XMLCONCAT|XMLDOCUMENT|XMLELEMENT|XMLEXISTS|XMLFOREST|XMLITERATE|XMLNAMESPACES|XMLPARSE|XMLPI|XMLQUERY|XMLSERIALIZE|XMLTABLE|XMLTEXT|XMLVALIDATE|ZONE"; // Microsoft's keyword list is missing a lot of things that are located on various other pages From a30270990cc0041edb6985059915f96524ebb154 Mon Sep 17 00:00:00 2001 From: sadnub Date: Mon, 12 Dec 2022 10:12:55 -0500 Subject: [PATCH 0704/1293] fix: Update ace.d.ts typings for navigate (#5011) * Update ace.d.ts * make times argument optional --- ace.d.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index 222b68b43e4..0e6ec5a42ba 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -883,10 +883,10 @@ export namespace Ace { jumpToMatching(select: boolean, expand: boolean): void; gotoLine(lineNumber: number, column: number, animate: boolean): void; navigateTo(row: number, column: number): void; - navigateUp(): void; - navigateDown(): void; - navigateLeft(): void; - navigateRight(): void; + navigateUp(times?: number): void; + navigateDown(times?: number): void; + navigateLeft(times?: number): void; + navigateRight(times?: number): void; navigateLineStart(): void; navigateLineEnd(): void; navigateFileEnd(): void; From 1abd491c7536f3806e9174f44743b7bd57c72f83 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Mon, 12 Dec 2022 16:18:13 +0100 Subject: [PATCH 0705/1293] release v1.14.0 --- CHANGELOG.md | 17 +++++++++++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5727e7c5e56..08de528542d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.14.0](https://github.com/ajaxorg/ace/compare/v1.13.1...v1.14.0) (2022-12-12) + + +### Features + +* Autocomplete accessibility features ([#5008](https://github.com/ajaxorg/ace/issues/5008)) ([3b7bb5e](https://github.com/ajaxorg/ace/commit/3b7bb5e4afbad0f2bdbc7f8487442a5cb78b8284)) + + +### Bug Fixes + +* Add missing options to `EditorOptions` ([#5003](https://github.com/ajaxorg/ace/issues/5003)) ([451b63f](https://github.com/ajaxorg/ace/commit/451b63f2243762d6de2fc5b9ee8c580c348b933c)) +* added GREATEST|LEAST logical functions added in SQL Server 2022 ([#5009](https://github.com/ajaxorg/ace/issues/5009)) ([e3f3e7a](https://github.com/ajaxorg/ace/commit/e3f3e7ab3efe540ac345325f06278a8ab1871371)) +* Better ES6 support for JavaScript Mode ([6fb39e3](https://github.com/ajaxorg/ace/commit/6fb39e38c79dd966233e48ed06be800c59c4c101)) +* Fix vim keybindings scroll to the selected line ([#4980](https://github.com/ajaxorg/ace/issues/4980)) ([8562f94](https://github.com/ajaxorg/ace/commit/8562f9493e0ebef865064992f0526fdc6df8535a)) +* show 2 context characters of a line when moving to it ([#4998](https://github.com/ajaxorg/ace/issues/4998)) ([743190e](https://github.com/ajaxorg/ace/commit/743190ea71841c0186b2f513b3d1e1a9e30d3de3)) +* Update ace.d.ts typings for navigate ([#5011](https://github.com/ajaxorg/ace/issues/5011)) ([a302709](https://github.com/ajaxorg/ace/commit/a30270990cc0041edb6985059915f96524ebb154)) + ### [1.13.2](https://github.com/ajaxorg/ace/compare/v1.13.1...v1.13.2) (2022-12-07) diff --git a/build b/build index 44279f41911..62b5377d9d1 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 44279f4191129f1cad89f4c550ea98c2c2fd2203 +Subproject commit 62b5377d9d115313fc07dc74926b292cc7683497 diff --git a/package.json b/package.json index e240e09fa36..1b00032d7d9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.13.2", + "version": "1.14.0", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index cd7319bb43d..eb3f01deba4 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.13.2"; +exports.version = "1.14.0"; From 1e0b5a92e3e3ca3803ba8ca1d55fe216652e7ed2 Mon Sep 17 00:00:00 2001 From: Slava Rozhnev Date: Mon, 19 Dec 2022 13:47:49 +0200 Subject: [PATCH 0706/1293] chore: Added links to SQLize.online & PHPize.online (#5014) --- index.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/index.html b/index.html index 02d6311ee14..6124cd30054 100644 --- a/index.html +++ b/index.html @@ -1213,6 +1213,14 @@

    Projects Using Ace

  • GoOnlineTools
  • +
  • + + SQLize.online +
  • +
  • + + PHPize.online +
  • +

    Your Site Here From ab4f788455ae182ae133fa202d737efa5461ff79 Mon Sep 17 00:00:00 2001 From: Zakhar Date: Wed, 18 Jan 2023 14:55:43 +0100 Subject: [PATCH 0707/1293] fix: editor shadow appears under the selected line background when horizontal scroll is active (#5020) Co-authored-by: Zakhar Kozlov --- Readme.md | 2 +- src/css/editor.css.js | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 80e7775121b..0a5efe64031 100644 --- a/Readme.md +++ b/Readme.md @@ -152,7 +152,7 @@ npm run test You can also run the tests in your browser by serving: - http://localhost:8888/lib/ace/test/tests.html + http://localhost:8888/src/test/tests.html This makes debugging failing tests way more easier. diff --git a/src/css/editor.css.js b/src/css/editor.css.js index c1e6c809aff..9495bd70ad5 100644 --- a/src/css/editor.css.js +++ b/src/css/editor.css.js @@ -93,8 +93,15 @@ styles.join("\\n") right: 0; } -.ace_scroller.ace_scroll-left { +.ace_scroller.ace_scroll-left:after { + content: ""; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset; + pointer-events: none; } .ace_gutter-cell { From 958d57383c4ebfacd414eb817aecc2e0982d1b36 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Tue, 24 Jan 2023 22:12:44 +0100 Subject: [PATCH 0708/1293] feat: Added Editor API to set the ghost text (#5036) --- ace.d.ts | 4 ++++ src/css/editor.css.js | 5 +++++ src/editor.js | 26 +++++++++++++++++++++++ src/line_widgets.js | 7 ++++++ src/virtual_renderer.js | 41 +++++++++++++++++++++++++++++++++++- src/virtual_renderer_test.js | 29 +++++++++++++++++++++++++ 6 files changed, 111 insertions(+), 1 deletion(-) diff --git a/ace.d.ts b/ace.d.ts index 0e6ec5a42ba..a1774d518d8 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -675,6 +675,8 @@ export namespace Ace { showComposition(position: number): void; setCompositionText(text: string): void; hideComposition(): void; + setGhostText(text: string, position: Point): void; + removeGhostText(): void; setTheme(theme: string, callback?: () => void): void; getTheme(): string; setStyle(style: string, include?: boolean): void; @@ -843,6 +845,8 @@ export namespace Ace { removeWordLeft(): void; removeLineToEnd(): void; splitLine(): void; + setGhostText(text: string, position: Point): void; + removeGhostText(): void; transposeLetters(): void; toLowerCase(): void; toUpperCase(): void; diff --git a/src/css/editor.css.js b/src/css/editor.css.js index 9495bd70ad5..967cf5d7d41 100644 --- a/src/css/editor.css.js +++ b/src/css/editor.css.js @@ -583,4 +583,9 @@ styles.join("\\n") white-space: pre; opacity: 0.7; margin: 0 10px; +} + +.ace_ghost_text { + opacity: 0.5; + font-style: italic; }`; diff --git a/src/editor.js b/src/editor.js index 36902347bc2..83c8589e024 100644 --- a/src/editor.js +++ b/src/editor.js @@ -16,6 +16,7 @@ var CommandManager = require("./commands/command_manager").CommandManager; var defaultCommands = require("./commands/default_commands").commands; var config = require("./config"); var TokenIterator = require("./token_iterator").TokenIterator; +var LineWidgets = require("./line_widgets").LineWidgets; var clipboard = require("./clipboard"); @@ -1425,6 +1426,31 @@ Editor.$uid = 0; this.moveCursorToPosition(cursor); }; + /** + * Set the "ghost" text in provided position. "Ghost" text is a kind of + * preview text inside the editor which can be used to preview some code + * inline in the editor such as, for example, code completions. + * + * @param {String} text Text to be inserted as "ghost" text + * @param {object} position Position to insert text to + */ + this.setGhostText = function(text, position) { + if (!this.session.widgetManager) { + this.session.widgetManager = new LineWidgets(this.session); + this.session.widgetManager.attach(this); + } + this.renderer.setGhostText(text, position); + }; + + /** + * Removes "ghost" text currently displayed in the editor. + */ + this.removeGhostText = function() { + if (!this.session.widgetManager) return; + + this.renderer.removeGhostText(); + }; + /** * Transposes current line. **/ diff --git a/src/line_widgets.js b/src/line_widgets.js index e0009a7b7e5..f512d9ec13e 100644 --- a/src/line_widgets.js +++ b/src/line_widgets.js @@ -182,8 +182,15 @@ function LineWidgets(session) { w.el = dom.createElement("div"); w.el.innerHTML = w.html; } + if (w.text && !w.el) { + w.el = dom.createElement("div"); + w.el.textContent = w.text; + } if (w.el) { dom.addCssClass(w.el, "ace_lineWidgetContainer"); + if (w.className) { + dom.addCssClass(w.el, w.className); + } w.el.style.position = "absolute"; w.el.style.zIndex = 5; renderer.container.appendChild(w.el); diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 58d214a525c..5a9b442025b 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -1617,7 +1617,46 @@ var VirtualRenderer = function(container, theme) { this.$composition = null; this.$cursorLayer.element.style.display = ""; }; - + + this.setGhostText = function(text, position) { + var cursor = this.session.selection.cursor; + var insertPosition = position || { row: cursor.row, column: cursor.column }; + + this.removeGhostText(); + + var textLines = text.split("\n"); + this.addToken(textLines[0], "ghost_text", insertPosition.row, insertPosition.column); + this.$ghostText = { + text: text, + position: { + row: insertPosition.row, + column: insertPosition. column + } + }; + if (textLines.length > 1) { + this.$ghostTextWidget = { + text: textLines.slice(1).join("\n"), + row: insertPosition.row, + column: insertPosition.column, + className: "ace_ghost_text" + }; + this.session.widgetManager.addLineWidget(this.$ghostTextWidget); + } + + }; + + this.removeGhostText = function() { + if (!this.$ghostText) return; + + var position = this.$ghostText.position; + this.removeExtraToken(position.row, position.column); + if (this.$ghostTextWidget) { + this.session.widgetManager.removeLineWidget(this.$ghostTextWidget); + this.$ghostTextWidget = null; + } + this.$ghostText = null; + }; + this.addToken = function(text, type, row, column) { var session = this.session; session.bgTokenizer.lines[row] = null; diff --git a/src/virtual_renderer_test.js b/src/virtual_renderer_test.js index e307fa1b685..d0754ab169e 100644 --- a/src/virtual_renderer_test.js +++ b/src/virtual_renderer_test.js @@ -300,6 +300,35 @@ module.exports = { ]; assertCoordsColor(values, imageData.data); }, + "test ghost text": function() { + editor.session.setValue("abcdef"); + editor.setGhostText("Ghost"); + + editor.renderer.$loop._flush(); + assert.equal(editor.renderer.content.textContent, "Ghostabcdef"); + + editor.setGhostText("Ghost", {row: 0, column: 3}); + + editor.renderer.$loop._flush(); + assert.equal(editor.renderer.content.textContent, "abcGhostdef"); + + editor.setGhostText("Ghost", {row: 0, column: 6}); + + editor.renderer.$loop._flush(); + assert.equal(editor.renderer.content.textContent, "abcdefGhost"); + }, + + "test multiline ghost text": function() { + editor.session.setValue("abcdef"); + editor.renderer.$loop._flush(); + + editor.setGhostText("Ghost1\nGhost2\nGhost3", {row: 0, column: 6}); + + editor.renderer.$loop._flush(); + assert.equal(editor.renderer.content.textContent, "abcdefGhost1"); + + assert.equal(editor.session.lineWidgets[0].el.textContent, "Ghost2\nGhost3"); + }, "test: brackets highlighting": function (done) { var renderer = editor.renderer; editor.session.setValue( From 68ff964a214cc2da66e4a35b313ff66dd4490e34 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Wed, 25 Jan 2023 01:17:29 +0400 Subject: [PATCH 0709/1293] fix: Remove broken keybinding from vscode mode (#5032) --- src/keyboard/vscode.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/keyboard/vscode.js b/src/keyboard/vscode.js index d66bc8f14e3..c369ea989e0 100644 --- a/src/keyboard/vscode.js +++ b/src/keyboard/vscode.js @@ -129,9 +129,6 @@ exports.handler.addCommands([{ }, { bindKey: {mac: "Command-Shift-P|F1", win: "Ctrl-Shift-P|F1"}, name: "openCommandPallete" -}, { - bindKey: {mac: "Command-K|Command-S", win: "Ctrl-K|Ctrl-S"}, - name: "showKeyboardShortcuts" }, { bindKey: {mac: "Shift-Option-Up", win: "Alt-Shift-Up"}, name: "copylinesup" From 95880868c2a9912f7c6a2c3942d67fc2a980094e Mon Sep 17 00:00:00 2001 From: Slava Rozhnev Date: Tue, 24 Jan 2023 23:21:16 +0200 Subject: [PATCH 0710/1293] fix: Added highlighting for TIES keyword introduced in PostgreSQL 13 (#5033) --- src/mode/pgsql_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mode/pgsql_highlight_rules.js b/src/mode/pgsql_highlight_rules.js index 9f1496d1ccb..56ebe531bc1 100644 --- a/src/mode/pgsql_highlight_rules.js +++ b/src/mode/pgsql_highlight_rules.js @@ -53,7 +53,7 @@ var PgsqlHighlightRules = function() { "unlogged|until|update|user|using|uuid|vacuum|valid|validate|validator|value|values|varbit|" + "varchar|variadic|varying|verbose|version|view|void|volatile|when|where|whitespace|window|" + "with|without|work|wrapper|write|xid|xml|xmlattributes|xmlconcat|xmlelement|xmlexists|" + - "xmlforest|xmlparse|xmlpi|xmlroot|xmlserialize|year|yes|zone" + "xmlforest|xmlparse|xmlpi|xmlroot|xmlserialize|year|yes|zone|ties" ); From 95e9664a28096606c77cc0569260550b705623e0 Mon Sep 17 00:00:00 2001 From: Zakhar Kozlov Date: Wed, 25 Jan 2023 16:17:25 +0100 Subject: [PATCH 0711/1293] release v1.15.0 --- CHANGELOG.md | 14 ++++++++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08de528542d..ea6e99f1e92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.15.0](https://github.com/ajaxorg/ace/compare/v1.14.0...v1.15.0) (2023-01-25) + + +### Features + +* Added Editor API to set the ghost text ([#5036](https://github.com/ajaxorg/ace/issues/5036)) ([958d573](https://github.com/ajaxorg/ace/commit/958d57383c4ebfacd414eb817aecc2e0982d1b36)) + + +### Bug Fixes + +* Added highlighting for TIES keyword introduced in PostgreSQL 13 ([#5033](https://github.com/ajaxorg/ace/issues/5033)) ([9588086](https://github.com/ajaxorg/ace/commit/95880868c2a9912f7c6a2c3942d67fc2a980094e)) +* editor shadow appears under the selected line background when horizontal scroll is active ([#5020](https://github.com/ajaxorg/ace/issues/5020)) ([ab4f788](https://github.com/ajaxorg/ace/commit/ab4f788455ae182ae133fa202d737efa5461ff79)) +* Remove broken keybinding from vscode mode ([#5032](https://github.com/ajaxorg/ace/issues/5032)) ([68ff964](https://github.com/ajaxorg/ace/commit/68ff964a214cc2da66e4a35b313ff66dd4490e34)) + ## [1.14.0](https://github.com/ajaxorg/ace/compare/v1.13.1...v1.14.0) (2022-12-12) diff --git a/build b/build index 62b5377d9d1..4686b2a71f8 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 62b5377d9d115313fc07dc74926b292cc7683497 +Subproject commit 4686b2a71f81c66fc7f7b5541b544fce4703bd4a diff --git a/package.json b/package.json index 1b00032d7d9..97c6f593b12 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.14.0", + "version": "1.15.0", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index eb3f01deba4..17aa374c293 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.14.0"; +exports.version = "1.15.0"; From 159aa70d551530f2866fb0006fad37bd75e60dda Mon Sep 17 00:00:00 2001 From: Slava Rozhnev Date: Mon, 30 Jan 2023 13:20:03 +0200 Subject: [PATCH 0712/1293] fix: Implement highlight mode for PL/SQL (Oracle) dialect (#5037) --- demo/kitchen-sink/docs/plsql.plsql | 18 +++++ src/ext/modelist.js | 3 +- src/mode/plsql.js | 55 +++++++++++++++ src/mode/plsql_highlight_rules.js | 110 +++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 demo/kitchen-sink/docs/plsql.plsql create mode 100644 src/mode/plsql.js create mode 100644 src/mode/plsql_highlight_rules.js diff --git a/demo/kitchen-sink/docs/plsql.plsql b/demo/kitchen-sink/docs/plsql.plsql new file mode 100644 index 00000000000..b51ac5471dc --- /dev/null +++ b/demo/kitchen-sink/docs/plsql.plsql @@ -0,0 +1,18 @@ +create table t ( + id integer, + month varchar(3), + value integer +); + +insert into t (month, value) values ('jan', 1); +insert into t (month, value) values ('jan', 1); +insert into t (month, value) values ('oct', 3); +insert into t (month, value) values ('dec', 96); + + +select * from (select month, value from t) +pivot +( + sum(value) + for month in ('jan', 'oct', 'dec') +); \ No newline at end of file diff --git a/src/ext/modelist.js b/src/ext/modelist.js index 9a91896114a..903538e164c 100644 --- a/src/ext/modelist.js +++ b/src/ext/modelist.js @@ -155,9 +155,10 @@ var supportedModes = { Pascal: ["pas|p"], Perl: ["pl|pm"], pgSQL: ["pgsql"], - PHP_Laravel_blade: ["blade.php"], PHP: ["php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"], + PHP_Laravel_blade: ["blade.php"], Pig: ["pig"], + PLSQL: ["plsql"], Powershell: ["ps1"], Praat: ["praat|praatscript|psc|proc"], Prisma: ["prisma"], diff --git a/src/mode/plsql.js b/src/mode/plsql.js new file mode 100644 index 00000000000..7505883a454 --- /dev/null +++ b/src/mode/plsql.js @@ -0,0 +1,55 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js +*/ + +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var PLSqlHighlightRules = require("./plsql_highlight_rules").plsqlHighlightRules; +var FoldMode = require("./folding/sql").FoldMode; + +var Mode = function() { + this.HighlightRules = PLSqlHighlightRules; + this.foldingRules = new FoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + this.lineCommentStart = "--"; + this.blockComment = {start: "/*", end: "*/"}; + + this.$id = "ace/mode/plsql"; +}).call(Mode.prototype); + +exports.Mode = Mode; \ No newline at end of file diff --git a/src/mode/plsql_highlight_rules.js b/src/mode/plsql_highlight_rules.js new file mode 100644 index 00000000000..e411fcde024 --- /dev/null +++ b/src/mode/plsql_highlight_rules.js @@ -0,0 +1,110 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +/* This file was autogenerated from (uuid: ) */ +/**************************************************************************************** + * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. * + * fileTypes * + ****************************************************************************************/ + +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var plsqlHighlightRules = function() { + var keywords = ( + "all|alter|and|any|array|arrow|as|asc|at|begin|between|by|case|check|clusters|cluster|colauth|columns|compress|connect|crash|create|cross|current|database|declare|default|delete|desc|distinct|drop|else|end|exception|exclusive|exists|fetch|form|for|foreign|from|goto|grant|group|having|identified|if|in|inner|indexes|index|insert|intersect|into|is|join|key|left|like|lock|minus|mode|natural|nocompress|not|nowait|null|of|on|option|or|order,overlaps|outer|primary|prior|procedure|public|range|record|references|resource|revoke|right|select|share|size|sql|start|subtype|tabauth|table|then|to|type|union|unique|update|use|values|view|views|when|where|with" + ); + + var builtinConstants = ( + "true|false" + ); + + var builtinFunctions = ( + "abs|acos|add_months|ascii|asciistr|asin|atan|atan2|avg|bfilename|bin_to_num|bitand|cardinality|case|cast|ceil|chartorowid|chr|coalesce|compose|concat|convert|corr|cos|cosh|count|covar_pop|covar_samp|cume_dist|current_date|current_timestamp|dbtimezone|decode|decompose|dense_rank|dump|empty_blob|empty_clob|exp|extract|first_value|floor|from_tz|greatest|group_id|hextoraw|initcap|instr|instr2|instr4|instrb|instrc|lag|last_day|last_value|lead|least|length|length2|length4|lengthb|lengthc|listagg|ln|lnnvl|localtimestamp|log|lower|lpad|ltrim|max|median|min|mod|months_between|nanvl|nchr|new_time|next_day|nth_value|nullif|numtodsinterval|numtoyminterval|nvl|nvl2|power|rank|rawtohex|regexp_count|regexp_instr|regexp_replace|regexp_substr|remainder|replace|round|rownum|rpad|rtrim|sessiontimezone|sign|sin|sinh|soundex|sqrt|stddev|substr|sum|sys_context|sysdate|systimestamp|tan|tanh|to_char|to_clob|to_date|to_dsinterval|to_lob|to_multi_byte|to_nclob|to_number|to_single_byte|to_timestamp|to_timestamp_tz|to_yminterval|translate|trim|trunc|tz_offset|uid|upper|user|userenv|var_pop|var_samp|variance|vsize" + ); + + var dataTypes = ( + "char|nchar|nvarchar2|varchar2|long|raw|" + + "number|numeric|float|dec|decimal|integer|int|smallint|real|double|precision|" + + "date|timestamp|interval|year|day|" + + "bfile|blob|clob|nclob|" + + "rowid|urowid" + ); + + var keywordMapper = this.createKeywordMapper({ + "support.function": builtinFunctions, + "keyword": keywords, + "constant.language": builtinConstants, + "storage.type": dataTypes + }, "identifier", true); + + this.$rules = { + "start" : [ { + token : "comment", + regex : "--.*$" + }, { + token : "comment", + start : "/\\*", + end : "\\*/" + }, { + token : "string", // " string + regex : '".*?"' + }, { + token : "string", // ' string + regex : "'.*?'" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, { + token : keywordMapper, + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token : "keyword.operator", + regex : "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=" + }, { + token : "paren.lparen", + regex : "[\\(]" + }, { + token : "paren.rparen", + regex : "[\\)]" + }, { + token : "text", + regex : "\\s+" + } ] + }; + + this.normalizeRules(); +}; + +oop.inherits(plsqlHighlightRules, TextHighlightRules); + +exports.plsqlHighlightRules = plsqlHighlightRules; \ No newline at end of file From 0f30e9c80786afe352247f2a7a97adae2a9c9a9e Mon Sep 17 00:00:00 2001 From: mkslanc Date: Wed, 1 Feb 2023 17:56:30 +0400 Subject: [PATCH 0713/1293] add dynamic modules loading --- src/config.js | 63 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/src/config.js b/src/config.js index 17aa374c293..f2a58dce6d8 100644 --- a/src/config.js +++ b/src/config.js @@ -49,7 +49,7 @@ exports.moduleUrl = function(name, component) { var parts = name.split("/"); component = component || parts[parts.length - 2] || ""; - + // todo make this configurable or get rid of '-' var sep = component == "snippets" ? "/" : "-"; var base = parts[parts.length - 1]; @@ -85,6 +85,7 @@ exports.setLoader = function(cb) { loader = cb; }; +exports.dynamicModules = {}; exports.$loading = {}; exports.loadModule = function(moduleName, onLoad) { var module, moduleType; @@ -93,42 +94,52 @@ exports.loadModule = function(moduleName, onLoad) { moduleName = moduleName[1]; } - try { - module = require(moduleName); - } catch (e) {} - // require(moduleName) can return empty object if called after require([moduleName], callback) - if (module && !exports.$loading[moduleName]) - return onLoad && onLoad(module); + var load = function (module) { + // require(moduleName) can return empty object if called after require([moduleName], callback) + if (module && !exports.$loading[moduleName]) return onLoad && onLoad(module); - if (!exports.$loading[moduleName]) - exports.$loading[moduleName] = []; + if (!exports.$loading[moduleName]) exports.$loading[moduleName] = []; - exports.$loading[moduleName].push(onLoad); + exports.$loading[moduleName].push(onLoad); - if (exports.$loading[moduleName].length > 1) - return; + if (exports.$loading[moduleName].length > 1) return; - var afterLoad = function() { - loader(moduleName, function(err, module) { - exports._emit("load.module", {name: moduleName, module: module}); - var listeners = exports.$loading[moduleName]; - exports.$loading[moduleName] = null; - listeners.forEach(function(onLoad) { - onLoad && onLoad(module); + var afterLoad = function() { + loader(moduleName, function(err, module) { + exports._emit("load.module", {name: moduleName, module: module}); + var listeners = exports.$loading[moduleName]; + exports.$loading[moduleName] = null; + listeners.forEach(function(onLoad) { + onLoad && onLoad(module); + }); }); - }); + }; + + if (!exports.get("packaged")) return afterLoad(); + + net.loadScript(exports.moduleUrl(moduleName, moduleType), afterLoad); + reportErrorIfPathIsNotConfigured(); }; - if (!exports.get("packaged")) - return afterLoad(); - - net.loadScript(exports.moduleUrl(moduleName, moduleType), afterLoad); - reportErrorIfPathIsNotConfigured(); + if (exports.dynamicModules[moduleName]) { + exports.dynamicModules[moduleName]().then(function(module) { + load(module); + }); + } else { + try { + module = require(moduleName); + } catch (e) {} + load(module); + } +}; + +exports.setModuleLoader = function (moduleName, onLoad) { + exports.dynamicModules[moduleName] = onLoad; }; var reportErrorIfPathIsNotConfigured = function() { if ( - !options.basePath && !options.workerPath + !options.basePath && !options.workerPath && !options.modePath && !options.themePath && !Object.keys(options.$moduleUrls).length ) { From 00f60890a36121d7c705445514dcf79a81055f55 Mon Sep 17 00:00:00 2001 From: Slava Rozhnev Date: Sun, 5 Feb 2023 19:02:53 +0200 Subject: [PATCH 0714/1293] fix: Improve MySQL highlighting mode (#5050) --- src/mode/mysql_highlight_rules.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/mode/mysql_highlight_rules.js b/src/mode/mysql_highlight_rules.js index 33ab97f165a..12f195069cd 100644 --- a/src/mode/mysql_highlight_rules.js +++ b/src/mode/mysql_highlight_rules.js @@ -6,16 +6,21 @@ var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var MysqlHighlightRules = function() { var mySqlKeywords = /*sql*/ "alter|and|as|asc|between|count|create|delete|desc|distinct|drop|from|having|in|insert|into|is|join|like|not|on|or|order|select|set|table|union|update|values|where" - /*mysql*/ + "|accessible|action|add|after|algorithm|all|analyze|asensitive|at|authors|auto_increment|autocommit|avg|avg_row_length|before|binary|binlog|both|btree|cache|call|cascade|cascaded|case|catalog_name|chain|change|changed|character|check|checkpoint|checksum|class_origin|client_statistics|close|coalesce|code|collate|collation|collations|column|columns|comment|commit|committed|completion|concurrent|condition|connection|consistent|constraint|contains|continue|contributors|convert|cross|current_date|current_time|current_timestamp|current_user|cursor|data|database|databases|day_hour|day_microsecond|day_minute|day_second|deallocate|dec|declare|default|delay_key_write|delayed|delimiter|des_key_file|describe|deterministic|dev_pop|dev_samp|deviance|directory|disable|discard|distinctrow|div|dual|dumpfile|each|elseif|enable|enclosed|end|ends|engine|engines|enum|errors|escape|escaped|even|event|events|every|execute|exists|exit|explain|extended|fast|fetch|field|fields|first|flush|for|force|foreign|found_rows|full|fulltext|function|general|global|grant|grants|group|groupby_concat|handler|hash|help|high_priority|hosts|hour_microsecond|hour_minute|hour_second|if|ignore|ignore_server_ids|import|index|index_statistics|infile|inner|innodb|inout|insensitive|insert_method|install|interval|invoker|isolation|iterate|key|keys|kill|language|last|leading|leave|left|level|limit|linear|lines|list|load|local|localtime|localtimestamp|lock|logs|low_priority|master|master_heartbeat_period|master_ssl_verify_server_cert|masters|match|max|max_rows|maxvalue|message_text|middleint|migrate|min|min_rows|minute_microsecond|minute_second|mod|mode|modifies|modify|mutex|mysql_errno|natural|next|no|no_write_to_binlog|offline|offset|one|online|open|optimize|option|optionally|out|outer|outfile|pack_keys|parser|partition|partitions|password|phase|plugin|plugins|prepare|preserve|prev|primary|privileges|procedure|processlist|profile|profiles|purge|query|quick|range|read|read_write|reads|real|rebuild|recover|references|regexp|relaylog|release|remove|rename|reorganize|repair|repeatable|replace|require|resignal|restrict|resume|return|returns|revoke|right|rlike|rollback|rollup|row|row_format|rtree|savepoint|schedule|schema|schema_name|schemas|second_microsecond|security|sensitive|separator|serializable|server|session|share|show|signal|slave|slow|smallint|snapshot|soname|spatial|specific|sql|sql_big_result|sql_buffer_result|sql_cache|sql_calc_found_rows|sql_no_cache|sql_small_result|sqlexception|sqlstate|sqlwarning|ssl|start|starting|starts|status|std|stddev|stddev_pop|stddev_samp|storage|straight_join|subclass_origin|sum|suspend|table_name|table_statistics|tables|tablespace|temporary|terminated|to|trailing|transaction|trigger|triggers|truncate|uncommitted|undo|uninstall|unique|unlock|upgrade|usage|use|use_frm|user|user_resources|user_statistics|using|utc_date|utc_time|utc_timestamp|value|variables|varying|view|views|warnings|when|while|with|work|write|xa|xor|year_month|zerofill|begin|do|then|else|loop|repeat"; - var builtins = "by|bool|boolean|bit|blob|decimal|double|enum|float|long|longblob|longtext|medium|mediumblob|mediumint|mediumtext|time|timestamp|tinyblob|tinyint|tinytext|text|bigint|int|int1|int2|int3|int4|int8|integer|float|float4|float8|double|char|varbinary|varchar|varcharacter|precision|date|datetime|year|unsigned|signed|numeric|ucase|lcase|mid|len|round|rank|now|format|coalesce|ifnull|isnull|nvl"; + /*mysql*/ + "|accessible|action|add|after|algorithm|all|analyze|asensitive|at|authors|auto_increment|autocommit|avg|avg_row_length|before|binary|binlog|both|btree|cache|call|cascade|cascaded|case|catalog_name|chain|change|changed|character|check|checkpoint|checksum|class_origin|client_statistics|close|coalesce|code|collate|collation|collations|column|columns|comment|commit|committed|completion|concurrent|condition|connection|consistent|constraint|contains|continue|contributors|convert|cross|current_date|current_time|current_timestamp|current_user|cursor|data|database|databases|day_hour|day_microsecond|day_minute|day_second|deallocate|dec|declare|default|delay_key_write|delayed|delimiter|des_key_file|describe|deterministic|dev_pop|dev_samp|deviance|directory|disable|discard|distinctrow|div|dual|dumpfile|each|elseif|enable|enclosed|end|ends|engine|engines|enum|errors|escape|escaped|even|event|events|every|execute|exists|exit|explain|extended|fast|fetch|field|fields|first|flush|for|force|foreign|found_rows|full|fulltext|function|general|global|grant|grants|group|by|groupby_concat|handler|hash|help|high_priority|hosts|hour_microsecond|hour_minute|hour_second|if|ignore|ignore_server_ids|import|index|index_statistics|infile|inner|innodb|inout|insensitive|insert_method|install|interval|invoker|isolation|iterate|key|keys|kill|language|last|leading|leave|left|level|limit|linear|lines|list|load|local|localtime|localtimestamp|lock|logs|low_priority|master|master_heartbeat_period|master_ssl_verify_server_cert|masters|match|max|max_rows|maxvalue|message_text|middleint|migrate|min|min_rows|minute_microsecond|minute_second|mod|mode|modifies|modify|mutex|mysql_errno|natural|next|no|no_write_to_binlog|offline|offset|one|online|open|optimize|option|optionally|out|outer|outfile|pack_keys|parser|partition|partitions|password|phase|plugin|plugins|prepare|preserve|prev|primary|privileges|procedure|processlist|profile|profiles|purge|query|quick|range|read|read_write|reads|real|rebuild|recover|references|regexp|relaylog|release|remove|rename|reorganize|repair|repeatable|replace|require|resignal|restrict|resume|return|returns|revoke|right|rlike|rollback|rollup|row|row_format|rtree|savepoint|schedule|schema|schema_name|schemas|second_microsecond|security|sensitive|separator|serializable|server|session|share|show|signal|slave|slow|smallint|snapshot|soname|spatial|specific|sql|sql_big_result|sql_buffer_result|sql_cache|sql_calc_found_rows|sql_no_cache|sql_small_result|sqlexception|sqlstate|sqlwarning|ssl|start|starting|starts|status|std|stddev|stddev_pop|stddev_samp|storage|straight_join|subclass_origin|sum|suspend|table_name|table_statistics|tables|tablespace|temporary|terminated|to|trailing|transaction|trigger|triggers|truncate|uncommitted|undo|uninstall|unique|unlock|upgrade|usage|use|use_frm|user|user_resources|user_statistics|using|utc_date|utc_time|utc_timestamp|value|variables|varying|view|views|warnings|when|while|with|work|write|xa|xor|year_month|zerofill|begin|do|then|else|loop|repeat"; + var builtins = "ucase|lcase|mid|len|round|rank|now|format|coalesce|ifnull|isnull|nvl|date|time|timestamp"; var variable = "charset|clear|connect|edit|ego|exit|go|help|nopager|notee|nowarning|pager|print|prompt|quit|rehash|source|status|system|tee"; //operatorChars: /^[*+\-%<>!=&|^]/, - + var dataTypes = ( + "bool|boolean|bit|blob|decimal|double|enum|float|long|longblob|longtext|medium|mediumblob|mediumint|mediumtext|time|timestamp|tinyblob|tinyint|tinytext|text|" + + "bigint|int|int1|int2|int3|int4|int8|integer|float|float4|float8|double|char|varbinary|varchar|varcharacter|precision|date|datetime|year|unsigned|signed|numeric" + ); + var keywordMapper = this.createKeywordMapper({ "support.function": builtins, "keyword": mySqlKeywords, - "constant": "false|true|null|unknown|date|time|timestamp|ODBCdotTable|zerolessFloat", + "storage.type": dataTypes, + "constant": "false|true|null|unknown|ODBCdotTable|zerolessFloat", "variable.language": variable }, "identifier", true); From 7f6fb3bc2a023049994bda8f221d42b7270a5f26 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 5 Feb 2023 23:08:58 +0400 Subject: [PATCH 0715/1293] Revert "fix: incorrect cursor position for very long lines (#4996)" This reverts commit e57a9d9eef0c056cd38a07c77c460bea39cc9551. # Conflicts: # src/ext/static_highlight_test.js --- src/ext/static_highlight_test.js | 12 +++--- src/layer/font_metrics.js | 66 ++++++++++++++------------------ src/layer/text.js | 49 ++++++++---------------- src/layer/text_test.js | 18 ++++----- src/virtual_renderer.js | 2 +- 5 files changed, 60 insertions(+), 87 deletions(-) diff --git a/src/ext/static_highlight_test.js b/src/ext/static_highlight_test.js index f28d7833cca..cbea4bae369 100644 --- a/src/ext/static_highlight_test.js +++ b/src/ext/static_highlight_test.js @@ -44,10 +44,10 @@ module.exports = { + "
    *\n
    " + "
    */\n
    " + "
    \n
    " - + "
    function hello (a, b, c) {\n
    " - + "
    console.log(a * b + c + 'sup$');\n
    " - + "
    //\n
    " - + "
    //\n
    " + + "
    function hello (a, b, c) {\n
    " + + "
    console.log(a * b + c + 'sup$');\n
    " + + "
    //\n
    " + + "
    //\n
    " + "
    }\n
    " + ""); assert.ok(!!result.css); @@ -97,7 +97,7 @@ module.exports = { var mode = new TextMode(); var result = highlighter.render(snippet, mode, theme); - assert.ok(result.html.indexOf("$'$1$2$$$&\n") != -1); + assert.ok(result.html.indexOf("$'$1$2$$$&\n") != -1); next(); }, @@ -108,7 +108,7 @@ module.exports = { var mode = new TextMode(); var result = highlighter.render(snippet, mode, theme); - assert.ok(result.html.indexOf("&<>'"\n") != -1); + assert.ok(result.html.indexOf("&<>'"\n") != -1); var mode = new JavaScriptMode(); var result = highlighter.render("/*" + snippet, mode, theme); diff --git a/src/layer/font_metrics.js b/src/layer/font_metrics.js index 2fbc2e44e40..6a438946c0c 100644 --- a/src/layer/font_metrics.js +++ b/src/layer/font_metrics.js @@ -5,30 +5,30 @@ var event = require("../lib/event"); var useragent = require("../lib/useragent"); var EventEmitter = require("../lib/event_emitter").EventEmitter; -var DEFAULT_CHAR_COUNT = 250; +var CHAR_COUNT = 256; var USE_OBSERVER = typeof ResizeObserver == "function"; var L = 200; -var FontMetrics = exports.FontMetrics = function(parentEl, charCount) { - this.charCount = charCount || DEFAULT_CHAR_COUNT; - +var FontMetrics = exports.FontMetrics = function(parentEl) { this.el = dom.createElement("div"); this.$setMeasureNodeStyles(this.el.style, true); - + this.$main = dom.createElement("div"); this.$setMeasureNodeStyles(this.$main.style); - + this.$measureNode = dom.createElement("div"); this.$setMeasureNodeStyles(this.$measureNode.style); - + + this.el.appendChild(this.$main); this.el.appendChild(this.$measureNode); parentEl.appendChild(this.el); - - this.$measureNode.textContent = lang.stringRepeat("X", this.charCount); - + + this.$measureNode.textContent = lang.stringRepeat("X", CHAR_COUNT); + this.$characterSize = {width: 0, height: 0}; - + + if (USE_OBSERVER) this.$addObserver(); else @@ -38,9 +38,9 @@ var FontMetrics = exports.FontMetrics = function(parentEl, charCount) { (function() { oop.implement(this, EventEmitter); - + this.$characterSize = {width: 0, height: 0}; - + this.$setMeasureNodeStyles = function(style, isRoot) { style.width = style.height = "auto"; style.left = style.top = "0px"; @@ -69,7 +69,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl, charCount) { this._emit("changeCharacterSize", {data: size}); } }; - + this.$addObserver = function() { var self = this; this.$observer = new window.ResizeObserver(function(e) { @@ -83,13 +83,13 @@ var FontMetrics = exports.FontMetrics = function(parentEl, charCount) { if (this.$pollSizeChangesTimer || this.$observer) return this.$pollSizeChangesTimer; var self = this; - + return this.$pollSizeChangesTimer = event.onIdle(function cb() { self.checkForSizeChanges(); event.onIdle(cb, 500); }, 500); }; - + this.setPolling = function(val) { if (val) { this.$pollSizeChanges(); @@ -100,32 +100,24 @@ var FontMetrics = exports.FontMetrics = function(parentEl, charCount) { }; this.$measureSizes = function(node) { - node = node || this.$measureNode; - - // Avoid `Element.clientWidth` since it is rounded to an integer (see - // https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth). - // Using it here can result in a noticeable cursor offset for long lines. - const rect = node.getBoundingClientRect(); - const charSize = { - height: rect.height, - width: rect.width / this.charCount + var size = { + height: (node || this.$measureNode).clientHeight, + width: (node || this.$measureNode).clientWidth / CHAR_COUNT }; - + // Size and width can be null if the editor is not visible or // detached from the document - if (charSize.width === 0 || charSize.height === 0) + if (size.width === 0 || size.height === 0) return null; - return charSize; + return size; }; this.$measureCharWidth = function(ch) { - this.$main.textContent = lang.stringRepeat(ch, this.charCount); - // Avoid `Element.clientWidth` since it is rounded to an integer (see - // https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth). + this.$main.textContent = lang.stringRepeat(ch, CHAR_COUNT); var rect = this.$main.getBoundingClientRect(); - return rect.width / this.charCount; + return rect.width / CHAR_COUNT; }; - + this.getCharacterWidth = function(ch) { var w = this.charSizes[ch]; if (w === undefined) { @@ -142,7 +134,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl, charCount) { this.el.parentNode.removeChild(this.el); }; - + this.$getZoom = function getZoom(element) { if (!element || !element.parentElement) return 1; return (window.getComputedStyle(element).zoom || 1) * getZoom(element.parentElement); @@ -179,7 +171,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl, charCount) { if (!this.els) this.$initTransformMeasureNodes(); - + function p(el) { var r = el.getBoundingClientRect(); return [r.left, r.top]; @@ -194,7 +186,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl, charCount) { var m1 = mul(1 + h[0], sub(b, a)); var m2 = mul(1 + h[1], sub(c, a)); - + if (elPos) { var x = elPos; var k = h[0] * x[0] / L + h[1] * x[1] / L + 1; @@ -205,5 +197,5 @@ var FontMetrics = exports.FontMetrics = function(parentEl, charCount) { var f = solve(sub(m1, mul(h[0], u)), sub(m2, mul(h[1], u)), u); return mul(L, f); }; - + }).call(FontMetrics.prototype); diff --git a/src/layer/text.js b/src/layer/text.js index 87f50ece9c7..f8ea79c98ac 100644 --- a/src/layer/text.js +++ b/src/layer/text.js @@ -27,8 +27,6 @@ var Text = function(parentEl) { this.SPACE_CHAR = "\xB7"; this.$padding = 0; this.MAX_LINE_LENGTH = 10000; - // Smaller chunks result in higher cursor precision at the cost of more DOM nodes - this.MAX_CHUNK_LENGTH = 250; this.$updateEolChar = function() { var doc = this.session.doc; @@ -323,19 +321,6 @@ var Text = function(parentEl) { "lparen": true }; - this.$renderTokenInChunks = function(parent, screenColumn, token, value) { - var newScreenColumn; - for (var i = 0; i < value.length; i += this.MAX_CHUNK_LENGTH) { - var valueChunk = value.substring(i, i + this.MAX_CHUNK_LENGTH); - var tokenChunk = { - type: token.type, - value: valueChunk - }; - newScreenColumn = this.$renderToken(parent, screenColumn + i, tokenChunk, valueChunk); - } - return newScreenColumn; - }; - this.$renderToken = function(parent, screenColumn, token, value) { var self = this; var re = /(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC\u2066\u2067\u2068\u202A\u202B\u202D\u202E\u202C\u2069]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g; @@ -401,16 +386,20 @@ var Text = function(parentEl) { valueFragment.appendChild(this.dom.createTextNode(i ? value.slice(i) : value, this.element)); - var span = this.dom.createElement("span"); if (!this.$textToken[token.type]) { var classes = "ace_" + token.type.replace(/\./g, " ace_"); + var span = this.dom.createElement("span"); if (token.type == "fold") span.style.width = (token.value.length * this.config.characterWidth) + "px"; span.className = classes; + span.appendChild(valueFragment); + + parent.appendChild(span); + } + else { + parent.appendChild(valueFragment); } - span.appendChild(valueFragment); - parent.appendChild(span); return screenColumn + value.length; }; @@ -577,11 +566,11 @@ var Text = function(parentEl) { } if (chars + value.length < splitChars) { - screenColumn = this.$renderTokenInChunks(lineEl, screenColumn, token, value); + screenColumn = this.$renderToken(lineEl, screenColumn, token, value); chars += value.length; } else { while (chars + value.length >= splitChars) { - screenColumn = this.$renderTokenInChunks( + screenColumn = this.$renderToken( lineEl, screenColumn, token, value.substring(0, splitChars - chars) ); @@ -599,7 +588,7 @@ var Text = function(parentEl) { } if (value.length != 0) { chars += value.length; - screenColumn = this.$renderTokenInChunks( + screenColumn = this.$renderToken( lineEl, screenColumn, token, value ); } @@ -621,23 +610,15 @@ var Text = function(parentEl) { if (!value) continue; } - if (screenColumn + value.length > this.MAX_LINE_LENGTH) { - this.$renderOverflowMessage(parent, screenColumn, token, value); - return; - } - screenColumn = this.$renderTokenInChunks(parent, screenColumn, token, value); + if (screenColumn + value.length > this.MAX_LINE_LENGTH) + return this.$renderOverflowMessage(parent, screenColumn, token, value); + screenColumn = this.$renderToken(parent, screenColumn, token, value); } }; this.$renderOverflowMessage = function(parent, screenColumn, token, value, hide) { - if (token) { - this.$renderTokenInChunks( - parent, - screenColumn, - token, - value.slice(0, this.MAX_LINE_LENGTH - screenColumn) - ); - } + token && this.$renderToken(parent, screenColumn, token, + value.slice(0, this.MAX_LINE_LENGTH - screenColumn)); var overflowEl = this.dom.createElement("span"); overflowEl.className = "ace_inline_button ace_keyword ace_toggle_wrap"; diff --git a/src/layer/text_test.js b/src/layer/text_test.js index 15bfebcb62b..7276fa840dd 100644 --- a/src/layer/text_test.js +++ b/src/layer/text_test.js @@ -44,13 +44,13 @@ module.exports = { var parent = dom.createElement("div"); this.textLayer.$renderLine(parent, 0); - assert.domNode(parent, ["div", {}, ["span", {}, ["span", {class: "ace_cjk", style: "width: 20px;"}, "\u3000"]]]); + assert.domNode(parent, ["div", {}, ["span", {class: "ace_cjk", style: "width: 20px;"}, "\u3000"]]); this.textLayer.setShowInvisibles(true); var parent = dom.createElement("div"); this.textLayer.$renderLine(parent, 0); assert.domNode(parent, ["div", {}, - ["span", {}, ["span", {class: "ace_cjk ace_invisible ace_invisible_space", style: "width: 20px;"}, this.textLayer.SPACE_CHAR]], + ["span", {class: "ace_cjk ace_invisible ace_invisible_space", style: "width: 20px;"}, this.textLayer.SPACE_CHAR], ["span", {class: "ace_invisible ace_invisible_eol"}, "\xB6"] ]); }, @@ -72,21 +72,21 @@ module.exports = { this.session.setValue(" \n\t\tf\n "); testRender([ - "" + SPACE(4) + "" + SPACE(2) + "", - "" + SPACE(4) + "" + SPACE(4) + "f", - "" + SPACE(3) + "" + "" + SPACE(4) + "" + SPACE(2), + "" + SPACE(4) + "" + SPACE(4) + "f", + SPACE(3) ]); this.textLayer.setShowInvisibles(true); testRender([ - "" + DOT(4) + "" + DOT(2) + "" + EOL, - "" + TAB(4) + "" + TAB(4) + "f" + EOL + "" + DOT(4) + "" + DOT(2) + "" + EOL, + "" + TAB(4) + "" + TAB(4) + "f" + EOL ]); this.textLayer.setDisplayIndentGuides(false); testRender([ - "" + DOT(6) + "" + EOL, - "" + TAB(4) + "" + TAB(4) + "f" + EOL + "" + DOT(6) + "" + EOL, + "" + TAB(4) + "" + TAB(4) + "f" + EOL ]); } }; diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 5a9b442025b..76d99adf144 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -98,7 +98,7 @@ var VirtualRenderer = function(container, theme) { column : 0 }; - this.$fontMetrics = new FontMetrics(this.container, this.$textLayer.MAX_CHUNK_LENGTH); + this.$fontMetrics = new FontMetrics(this.container); this.$textLayer.$setFontMetrics(this.$fontMetrics); this.$textLayer.on("changeCharacterSize", function(e) { _self.updateCharacterSize(); From d4496c7d77919aa0c59028a8cc9420a463a1ec1e Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 7 Feb 2023 14:46:42 +0400 Subject: [PATCH 0716/1293] fix tests --- src/autocomplete_test.js | 8 ++++---- src/ext/static_highlight_test.js | 2 +- src/layer/text.js | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index 8352f52f7e5..97251398ffb 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -26,16 +26,16 @@ module.exports = { editor.renderer.$themeId = "./theme/textmate"; editor.execCommand("insertstring", "a"); - checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { + checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { editor.execCommand("insertstring", "rr"); - checkInnerHTML('arraysortlocal', function() { + checkInnerHTML('arraysortlocal', function() { editor.execCommand("insertstring", "r"); - checkInnerHTML('arraysortlocal', function() { + checkInnerHTML('arraysortlocal', function() { editor.onCommandKey(null, 0, 13); assert.equal(editor.getValue(), "arraysort\narraysort alooooooooooooooooooooooooooooong_word"); editor.execCommand("insertstring", " looooooooooooooooooooooooooooong_"); - checkInnerHTML('alooooooooooooooooooooooooooooong_wordlocal', function() { + checkInnerHTML('alooooooooooooooooooooooooooooong_wordlocal', function() { editor.onCommandKey(null, 0, 13); editor.destroy(); editor.container.remove(); diff --git a/src/ext/static_highlight_test.js b/src/ext/static_highlight_test.js index cbea4bae369..e9f4a8cb690 100644 --- a/src/ext/static_highlight_test.js +++ b/src/ext/static_highlight_test.js @@ -44,7 +44,7 @@ module.exports = { + "
    *\n
    " + "
    */\n
    " + "
    \n
    " - + "
    function hello (a, b, c) {\n
    " + + "
    function hello (a, b, c) {\n
    " + "
    console.log(a * b + c + 'sup$');\n
    " + "
    //\n
    " + "
    //\n
    " diff --git a/src/layer/text.js b/src/layer/text.js index f8ea79c98ac..aa3be47f9cf 100644 --- a/src/layer/text.js +++ b/src/layer/text.js @@ -291,7 +291,6 @@ var Text = function(parentEl) { lineEl.className = "ace_line_group"; } else { lineEl.className = "ace_line"; - lineEl.setAttribute("role", "option"); } fragment.push(line); From 75f5294aa984b4205ec7d0527dc2cba456bd2c68 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 7 Feb 2023 14:47:05 +0400 Subject: [PATCH 0717/1293] increase CHAR_COUNT of font_metrics --- src/layer/font_metrics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layer/font_metrics.js b/src/layer/font_metrics.js index 6a438946c0c..459d982146a 100644 --- a/src/layer/font_metrics.js +++ b/src/layer/font_metrics.js @@ -5,7 +5,7 @@ var event = require("../lib/event"); var useragent = require("../lib/useragent"); var EventEmitter = require("../lib/event_emitter").EventEmitter; -var CHAR_COUNT = 256; +var CHAR_COUNT = 512; var USE_OBSERVER = typeof ResizeObserver == "function"; var L = 200; From 32509568010d8b881cc9f1a6d6bd76e6f69360ea Mon Sep 17 00:00:00 2001 From: Slava Rozhnev Date: Thu, 9 Feb 2023 12:26:46 +0200 Subject: [PATCH 0718/1293] fix: Added lateral keyword introduced in MySQL 8.0.14 (#5053) --- src/mode/mysql_highlight_rules.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mode/mysql_highlight_rules.js b/src/mode/mysql_highlight_rules.js index 12f195069cd..5ccf55308e5 100644 --- a/src/mode/mysql_highlight_rules.js +++ b/src/mode/mysql_highlight_rules.js @@ -4,8 +4,7 @@ var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocComme var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var MysqlHighlightRules = function() { - - var mySqlKeywords = /*sql*/ "alter|and|as|asc|between|count|create|delete|desc|distinct|drop|from|having|in|insert|into|is|join|like|not|on|or|order|select|set|table|union|update|values|where" + var mySqlKeywords = /*sql*/ "alter|and|as|asc|between|count|create|delete|desc|distinct|drop|from|lateral|having|in|insert|into|is|join|like|not|on|or|order|select|set|table|union|update|values|where" /*mysql*/ + "|accessible|action|add|after|algorithm|all|analyze|asensitive|at|authors|auto_increment|autocommit|avg|avg_row_length|before|binary|binlog|both|btree|cache|call|cascade|cascaded|case|catalog_name|chain|change|changed|character|check|checkpoint|checksum|class_origin|client_statistics|close|coalesce|code|collate|collation|collations|column|columns|comment|commit|committed|completion|concurrent|condition|connection|consistent|constraint|contains|continue|contributors|convert|cross|current_date|current_time|current_timestamp|current_user|cursor|data|database|databases|day_hour|day_microsecond|day_minute|day_second|deallocate|dec|declare|default|delay_key_write|delayed|delimiter|des_key_file|describe|deterministic|dev_pop|dev_samp|deviance|directory|disable|discard|distinctrow|div|dual|dumpfile|each|elseif|enable|enclosed|end|ends|engine|engines|enum|errors|escape|escaped|even|event|events|every|execute|exists|exit|explain|extended|fast|fetch|field|fields|first|flush|for|force|foreign|found_rows|full|fulltext|function|general|global|grant|grants|group|by|groupby_concat|handler|hash|help|high_priority|hosts|hour_microsecond|hour_minute|hour_second|if|ignore|ignore_server_ids|import|index|index_statistics|infile|inner|innodb|inout|insensitive|insert_method|install|interval|invoker|isolation|iterate|key|keys|kill|language|last|leading|leave|left|level|limit|linear|lines|list|load|local|localtime|localtimestamp|lock|logs|low_priority|master|master_heartbeat_period|master_ssl_verify_server_cert|masters|match|max|max_rows|maxvalue|message_text|middleint|migrate|min|min_rows|minute_microsecond|minute_second|mod|mode|modifies|modify|mutex|mysql_errno|natural|next|no|no_write_to_binlog|offline|offset|one|online|open|optimize|option|optionally|out|outer|outfile|pack_keys|parser|partition|partitions|password|phase|plugin|plugins|prepare|preserve|prev|primary|privileges|procedure|processlist|profile|profiles|purge|query|quick|range|read|read_write|reads|real|rebuild|recover|references|regexp|relaylog|release|remove|rename|reorganize|repair|repeatable|replace|require|resignal|restrict|resume|return|returns|revoke|right|rlike|rollback|rollup|row|row_format|rtree|savepoint|schedule|schema|schema_name|schemas|second_microsecond|security|sensitive|separator|serializable|server|session|share|show|signal|slave|slow|smallint|snapshot|soname|spatial|specific|sql|sql_big_result|sql_buffer_result|sql_cache|sql_calc_found_rows|sql_no_cache|sql_small_result|sqlexception|sqlstate|sqlwarning|ssl|start|starting|starts|status|std|stddev|stddev_pop|stddev_samp|storage|straight_join|subclass_origin|sum|suspend|table_name|table_statistics|tables|tablespace|temporary|terminated|to|trailing|transaction|trigger|triggers|truncate|uncommitted|undo|uninstall|unique|unlock|upgrade|usage|use|use_frm|user|user_resources|user_statistics|using|utc_date|utc_time|utc_timestamp|value|variables|varying|view|views|warnings|when|while|with|work|write|xa|xor|year_month|zerofill|begin|do|then|else|loop|repeat"; var builtins = "ucase|lcase|mid|len|round|rank|now|format|coalesce|ifnull|isnull|nvl|date|time|timestamp"; var variable = "charset|clear|connect|edit|ego|exit|go|help|nopager|notee|nowarning|pager|print|prompt|quit|rehash|source|status|system|tee"; From 7d5adc88525617d89fae905943c876da4c8b80c7 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 13 Feb 2023 23:19:19 +0400 Subject: [PATCH 0719/1293] fix command palette in kitchen-sink demo --- src/commands/default_commands.js | 4 ++-- src/editor.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/default_commands.js b/src/commands/default_commands.js index d7c6413247d..bbe8b830ca7 100644 --- a/src/commands/default_commands.js +++ b/src/commands/default_commands.js @@ -28,7 +28,7 @@ exports.commands = [{ description: "Go to next error", bindKey: bindKey("Alt-E", "F4"), exec: function(editor) { - config.loadModule("./ext/error_marker", function(module) { + config.loadModule("ace/ext/error_marker", function(module) { module.showErrorMarker(editor, 1); }); }, @@ -39,7 +39,7 @@ exports.commands = [{ description: "Go to previous error", bindKey: bindKey("Alt-Shift-E", "Shift-F4"), exec: function(editor) { - config.loadModule("./ext/error_marker", function(module) { + config.loadModule("ace/ext/error_marker", function(module) { module.showErrorMarker(editor, -1); }); }, diff --git a/src/editor.js b/src/editor.js index 83c8589e024..8fc5808b14d 100644 --- a/src/editor.js +++ b/src/editor.js @@ -2756,7 +2756,7 @@ Editor.$uid = 0; **/ this.prompt = function(message, options, callback) { var editor = this; - config.loadModule("./ext/prompt", function (module) { + config.loadModule("ace/ext/prompt", function (module) { module.prompt(editor, message, options, callback); }); }; From 23c3c6067ed55518b4560214f35b5f03378c441a Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 14 Feb 2023 01:26:31 +0400 Subject: [PATCH 0720/1293] release v1.15.1 --- CHANGELOG.md | 9 +++++++++ build | 2 +- package.json | 2 +- src/autocomplete.js | 3 ++- src/config.js | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea6e99f1e92..cfa148784e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.15.1](https://github.com/ajaxorg/ace/compare/v1.15.0...v1.15.1) (2023-02-13) + + +### Bug Fixes + +* Added lateral keyword introduced in MySQL 8.0.14 ([#5053](https://github.com/ajaxorg/ace/issues/5053)) ([3250956](https://github.com/ajaxorg/ace/commit/32509568010d8b881cc9f1a6d6bd76e6f69360ea)) +* Implement highlight mode for PL/SQL (Oracle) dialect ([#5037](https://github.com/ajaxorg/ace/issues/5037)) ([159aa70](https://github.com/ajaxorg/ace/commit/159aa70d551530f2866fb0006fad37bd75e60dda)) +* Improve MySQL highlighting mode ([#5050](https://github.com/ajaxorg/ace/issues/5050)) ([00f6089](https://github.com/ajaxorg/ace/commit/00f60890a36121d7c705445514dcf79a81055f55)) + ## [1.15.0](https://github.com/ajaxorg/ace/compare/v1.14.0...v1.15.0) (2023-01-25) diff --git a/build b/build index 4686b2a71f8..06edf043d6f 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 4686b2a71f81c66fc7f7b5541b544fce4703bd4a +Subproject commit 06edf043d6ff4049e2c522f425a3c4853d44974f diff --git a/package.json b/package.json index 97c6f593b12..9b8defa6038 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.15.0", + "version": "1.15.1", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/autocomplete.js b/src/autocomplete.js index 546c3538c36..079c80c2300 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -55,7 +55,8 @@ var Autocomplete = function() { this.popup.autoSelect = this.autoSelect; this.popup.setData(this.completions.filtered, this.completions.filterText); - this.editor.textInput.setAriaOptions({activeDescendant: getAriaId(this.popup.getRow())}); + if (this.editor.textInput.setAriaOptions) + this.editor.textInput.setAriaOptions({activeDescendant: getAriaId(this.popup.getRow())}); editor.keyBinding.addKeyboardHandler(this.keyboardHandler); diff --git a/src/config.js b/src/config.js index 17aa374c293..4bdce0d1e05 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.15.0"; +exports.version = "1.15.1"; From ae92532c3f2a18197e548aeea18268b7f6f48a0a Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 14 Feb 2023 01:42:40 +0400 Subject: [PATCH 0721/1293] chore: remove usage of deprecated setCapture api --- src/css/editor.css.js | 3 ++- src/mouse/default_handlers.js | 6 ------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/css/editor.css.js b/src/css/editor.css.js index 967cf5d7d41..eaad5d28cb7 100644 --- a/src/css/editor.css.js +++ b/src/css/editor.css.js @@ -1,4 +1,4 @@ -module.exports = `/* +/* styles = [] for (var i = 1; i < 16; i++) { styles.push(".ace_br" + i + "{" + ( @@ -9,6 +9,7 @@ for (var i = 1; i < 16; i++) { } styles.join("\\n") */ +module.exports = ` .ace_br1 {border-top-left-radius : 3px;} .ace_br2 {border-top-right-radius : 3px;} .ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;} diff --git a/src/mouse/default_handlers.js b/src/mouse/default_handlers.js index f15e4792566..e0c511b55dc 100644 --- a/src/mouse/default_handlers.js +++ b/src/mouse/default_handlers.js @@ -79,9 +79,6 @@ function DefaultHandlers(mouseHandler) { editor.selection.moveToPosition(pos); if (!waitForClickSelection) this.select(); - if (editor.renderer.scroller.setCapture) { - editor.renderer.scroller.setCapture(); - } editor.setStyle("ace_selecting"); this.setState("select"); }; @@ -143,9 +140,6 @@ function DefaultHandlers(mouseHandler) { this.selectByLinesEnd = function() { this.$clickSelection = null; this.editor.unsetStyle("ace_selecting"); - if (this.editor.renderer.scroller.releaseCapture) { - this.editor.renderer.scroller.releaseCapture(); - } }; this.focusWait = function() { From 674e82e81f22ef8e9a20d8ff12301c84b0130e7e Mon Sep 17 00:00:00 2001 From: Oyku Yilmaz Date: Thu, 2 Feb 2023 10:58:49 +0000 Subject: [PATCH 0722/1293] set role=option only for selected autocomplete ace lines --- src/autocomplete/popup.js | 1 + src/autocomplete_test.js | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js index 494166fa976..479895b9d18 100644 --- a/src/autocomplete/popup.js +++ b/src/autocomplete/popup.js @@ -135,6 +135,7 @@ var AcePopup = function(parentNode) { selected.id = ariaId; popup.renderer.container.setAttribute("aria-activedescendant", ariaId); el.setAttribute("aria-activedescendant", ariaId); + selected.setAttribute("role", "option"); selected.setAttribute("aria-label", popup.getData(row).value); } }); diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index 97251398ffb..419c2eaff98 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -26,16 +26,16 @@ module.exports = { editor.renderer.$themeId = "./theme/textmate"; editor.execCommand("insertstring", "a"); - checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { + checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { editor.execCommand("insertstring", "rr"); - checkInnerHTML('arraysortlocal', function() { + checkInnerHTML('arraysortlocal', function() { editor.execCommand("insertstring", "r"); - checkInnerHTML('arraysortlocal', function() { + checkInnerHTML('arraysortlocal', function() { editor.onCommandKey(null, 0, 13); assert.equal(editor.getValue(), "arraysort\narraysort alooooooooooooooooooooooooooooong_word"); editor.execCommand("insertstring", " looooooooooooooooooooooooooooong_"); - checkInnerHTML('alooooooooooooooooooooooooooooong_wordlocal', function() { + checkInnerHTML('alooooooooooooooooooooooooooooong_wordlocal', function() { editor.onCommandKey(null, 0, 13); editor.destroy(); editor.container.remove(); From aff5902fc22a9ac2eb96feabe578fc294461902d Mon Sep 17 00:00:00 2001 From: Oyku Yilmaz Date: Tue, 14 Feb 2023 10:40:49 +0000 Subject: [PATCH 0723/1293] rev 2 --- ace.d.ts | 1 + src/autocomplete/popup.js | 2 ++ src/autocomplete_test.js | 8 ++++---- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index a1774d518d8..9d92a7e9430 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -752,6 +752,7 @@ export namespace Ace { export interface TextInput { resetSelection(): void; + setAriaOption(activeDescendant: string, role: string): void; } export interface Editor extends OptionsProvider, EventEmitter { diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js index 479895b9d18..920f4178de0 100644 --- a/src/autocomplete/popup.js +++ b/src/autocomplete/popup.js @@ -137,6 +137,8 @@ var AcePopup = function(parentNode) { el.setAttribute("aria-activedescendant", ariaId); selected.setAttribute("role", "option"); selected.setAttribute("aria-label", popup.getData(row).value); + selected.setAttribute("aria-setsize", popup.data.length); + selected.setAttribute("aria-posinset", row); } }); var hideHoverMarker = function() { setHoverMarker(-1); }; diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index 419c2eaff98..0c450d9de1c 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -26,16 +26,16 @@ module.exports = { editor.renderer.$themeId = "./theme/textmate"; editor.execCommand("insertstring", "a"); - checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { + checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { editor.execCommand("insertstring", "rr"); - checkInnerHTML('arraysortlocal', function() { + checkInnerHTML('arraysortlocal', function() { editor.execCommand("insertstring", "r"); - checkInnerHTML('arraysortlocal', function() { + checkInnerHTML('arraysortlocal', function() { editor.onCommandKey(null, 0, 13); assert.equal(editor.getValue(), "arraysort\narraysort alooooooooooooooooooooooooooooong_word"); editor.execCommand("insertstring", " looooooooooooooooooooooooooooong_"); - checkInnerHTML('alooooooooooooooooooooooooooooong_wordlocal', function() { + checkInnerHTML('alooooooooooooooooooooooooooooong_wordlocal', function() { editor.onCommandKey(null, 0, 13); editor.destroy(); editor.container.remove(); From bab115acacb7476f1db4495ca61e381ea72cddd7 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 15 Feb 2023 12:49:04 +0400 Subject: [PATCH 0724/1293] fix error_marker test --- src/config_test.js | 6 +++--- src/ext/error_marker_test.js | 24 ++++++++++++++++++------ src/virtual_renderer_test.js | 8 ++++++-- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/config_test.js b/src/config_test.js index 3fd950bec74..2b474da8ccf 100644 --- a/src/config_test.js +++ b/src/config_test.js @@ -4,14 +4,13 @@ if (typeof process !== "undefined") { "use strict"; -var dom = require("./config"); var config = require("./config"); var assert = require("./test/assertions"); module.exports = { "test: path resolution" : function() { - config.set("packaged", "true"); + config.set("packaged", true); var url = config.moduleUrl("kr_theme", "theme"); assert.equal(url, "theme-kr_theme.js"); @@ -38,7 +37,8 @@ module.exports = { assert.equal(url, "_.js"); url = config.moduleUrl("ace/ext/textarea"); - assert.equal(url, "a/b/ext-textarea.js"); + assert.equal(url, "a/b/ext-textarea.js"); + config.set("packaged", false); }, "test: define options" : function() { var o = {}; diff --git a/src/ext/error_marker_test.js b/src/ext/error_marker_test.js index 97e0950a30b..c7abfe81caf 100644 --- a/src/ext/error_marker_test.js +++ b/src/ext/error_marker_test.js @@ -1,5 +1,3 @@ -/*global CustomEvent*/ - if (typeof process !== "undefined") { require("amd-loader"); } @@ -9,10 +7,14 @@ if (typeof process !== "undefined") { var assert = require("./../test/assertions"); require("./../test/mockdom"); var ace = require("../ace"); -var editor, changes, textarea; +var editor, changes; module.exports = { setUp: function() { + ace.config.setLoader(function(moduleName, cb) { + if (moduleName == "ace/ext/error_marker") + return cb(null, require("../ext/error_marker")); + }); if (!editor) { editor = ace.edit(null); document.body.appendChild(editor.container); @@ -31,10 +33,10 @@ module.exports = { if (editor) { editor.destroy(); editor.container.remove(); - editor = textarea = null; + editor = null; } }, - "test: simple text input": function() { + "test: go to next error": function() { editor.session.setValue("1\nerror 2 warning\n3\n4 info\n5\n6\n"); editor.execCommand("goToNextError"); editor.resize(true); @@ -52,9 +54,19 @@ module.exports = { type: type }; })); + + editor.execCommand("goToNextError"); + editor.renderer.$loop._flush(); + assert.ok(/error_widget\s+ace_error/.test(editor.container.innerHTML)); + editor.execCommand("goToNextError"); editor.renderer.$loop._flush(); - assert.ok(/error_widget/.test(editor.container.innerHTML)); + assert.ok(/error_widget\s+ace_info/.test(editor.container.innerHTML)); + + editor.execCommand("goToPreviousError"); + editor.renderer.$loop._flush(); + assert.ok(/error_widget\s+ace_error/.test(editor.container.innerHTML)); + editor.execCommand("insertstring", "\n"); editor.renderer.$loop._flush(); assert.notOk(/error_widget/.test(editor.container.innerHTML)); diff --git a/src/virtual_renderer_test.js b/src/virtual_renderer_test.js index d0754ab169e..e08e4f916dc 100644 --- a/src/virtual_renderer_test.js +++ b/src/virtual_renderer_test.js @@ -11,7 +11,6 @@ var EditSession = require("./edit_session").EditSession; var VirtualRenderer = require("./virtual_renderer").VirtualRenderer; var vim = require("./keyboard/vim"); var assert = require("./test/assertions"); -require("./ext/error_marker"); function setScreenPosition(node, rect) { node.style.left = rect[0] + "px"; @@ -23,6 +22,11 @@ function setScreenPosition(node, rect) { var editor = null; module.exports = { setUp: function() { + require("./config").setLoader(function(moduleName, cb) { + if (moduleName == "ace/ext/error_marker") + return cb(null, require("./ext/error_marker")); + }); + if (editor) editor.destroy(); var el = document.createElement("div"); @@ -255,7 +259,7 @@ module.exports = { } ]); renderer.$loop._flush(); - var context = renderer.$scrollDecorator.canvas.getContext(); + var context = renderer.$scrollDecorator.canvas.getContext("2d"); var imageData = context.getImageData(0, 0, 50, 50); var scrollDecoratorColors = renderer.$scrollDecorator.colors.light; var values = [ From e7d37fadab5119c876759925b446d008b6298cd6 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:05:00 +0400 Subject: [PATCH 0725/1293] add `deprecated` flag for old methods; rename `setSelectionAnchor` to `setAnchor` according to declaration (#5062) --- src/selection.js | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/selection.js b/src/selection.js index 410b180f003..12cb18ca525 100644 --- a/src/selection.js +++ b/src/selection.js @@ -20,13 +20,13 @@ var Range = require("./range").Range; **/ /** * Emitted when the cursor selection changes. - * + * * @event changeSelection **/ /** * Creates a new `Selection` object. * @param {EditSession} session The session to use - * + * * @constructor **/ var Selection = function(session) { @@ -93,25 +93,36 @@ var Selection = function(session) { * @param {Number} column The new column * **/ - this.setSelectionAnchor = function(row, column) { + this.setAnchor = function(row, column) { this.$isEmpty = false; this.anchor.setPosition(row, column); }; + /** + * Left for backward compatibility + * @deprecated + */ + this.setSelectionAnchor = this.setAnchor; + /** * Returns an object containing the `row` and `column` of the calling selection anchor. * * @returns {Object} * @related Anchor.getPosition **/ - this.getAnchor = - this.getSelectionAnchor = function() { + this.getAnchor = function() { if (this.$isEmpty) return this.getSelectionLead(); - + return this.anchor.getPosition(); }; + /** + * Left for backward compatibility + * @deprecated + */ + this.getSelectionAnchor = this.getAnchor; + /** * Returns an object containing the `row` and `column` of the calling selection lead. * @returns {Object} @@ -735,7 +746,7 @@ var Selection = function(session) { else this.$desiredColumn = screenPos.column; } - + if (rows != 0 && this.session.lineWidgets && this.session.lineWidgets[this.lead.row]) { var widget = this.session.lineWidgets[this.lead.row]; if (rows < 0) @@ -743,11 +754,11 @@ var Selection = function(session) { else if (rows > 0) rows += widget.rowCount - (widget.rowsAbove || 0); } - + var docPos = this.session.screenToDocumentPosition(screenPos.row + rows, screenPos.column, offsetX); - + if (rows !== 0 && chars === 0 && docPos.row === this.lead.row && docPos.column === this.lead.column) { - + } // move the cursor and update the desired column From 16a13ce278295549db55496b518a01da203c460c Mon Sep 17 00:00:00 2001 From: Zakhar Kozlov Date: Thu, 16 Feb 2023 14:38:32 +0100 Subject: [PATCH 0726/1293] release v1.15.2 --- CHANGELOG.md | 2 ++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfa148784e3..c808aee30a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.15.2](https://github.com/ajaxorg/ace/compare/v1.15.1...v1.15.2) (2023-02-16) + ### [1.15.1](https://github.com/ajaxorg/ace/compare/v1.15.0...v1.15.1) (2023-02-13) diff --git a/build b/build index 06edf043d6f..f74d3c7e203 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 06edf043d6ff4049e2c522f425a3c4853d44974f +Subproject commit f74d3c7e20367e5c8eaa5cabb9a8a21702bc9715 diff --git a/package.json b/package.json index 9b8defa6038..47eae307c4d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.15.1", + "version": "1.15.2", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 4bdce0d1e05..6286608c102 100644 --- a/src/config.js +++ b/src/config.js @@ -141,6 +141,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.15.1"; +exports.version = "1.15.2"; From cc98bdcb76a1a24cef3997af52d78c4880590508 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 20 Feb 2023 13:24:06 +0400 Subject: [PATCH 0727/1293] restore Folding interface in typings --- ace.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ace.d.ts b/ace.d.ts index 9d92a7e9430..ca8d6e1e83a 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -414,7 +414,7 @@ export namespace Ace { column: number } - export interface EditSession extends EventEmitter, OptionsProvider { + export interface EditSession extends EventEmitter, OptionsProvider, Folding { selection: Selection; // TODO: define BackgroundTokenizer From aa522eff1650a343a915dad5171a073de7a8aa81 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Thu, 23 Feb 2023 16:45:23 +0400 Subject: [PATCH 0728/1293] add load default from modules (for some bundlers this is mandatory); add esm resolver generator for `ace-code` package --- ace.d.ts | 1 + package.json | 3 +- src/config.js | 11 ++++-- tool/esm_resolver_generator.js | 65 ++++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 tool/esm_resolver_generator.js diff --git a/ace.d.ts b/ace.d.ts index a1774d518d8..d689ec85793 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -371,6 +371,7 @@ export namespace Ace { all(): { [key: string]: any }; moduleUrl(name: string, component?: string): string; setModuleUrl(name: string, subst: string): string; + setModuleLoader(name: string, onLoad: Function): void; loadModule(moduleName: string | [string, string], onLoad?: (module: any) => void): void; init(packaged: any): any; diff --git a/package.json b/package.json index 97c6f593b12..6197bb3528c 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ "cover": "istanbul cover src/test/all.js", "lint": "eslint \"src/**/*.js\"", "fix": "eslint --fix \"src/**/*.js\"", - "changelog": "standard-version" + "changelog": "standard-version", + "prepack": "node tool/esm_resolver_generator.js" }, "standard-version": { "skip": { diff --git a/src/config.js b/src/config.js index f2a58dce6d8..1eb89d2210a 100644 --- a/src/config.js +++ b/src/config.js @@ -76,7 +76,7 @@ exports.setModuleUrl = function(name, subst) { }; var loader = function(moduleName, cb) { - if (moduleName == "ace/theme/textmate") + if (moduleName === "ace/theme/textmate" || moduleName === "./theme/textmate") return cb(null, require("./theme/textmate")); return console.error("loader is not configured"); }; @@ -122,8 +122,13 @@ exports.loadModule = function(moduleName, onLoad) { }; if (exports.dynamicModules[moduleName]) { - exports.dynamicModules[moduleName]().then(function(module) { - load(module); + exports.dynamicModules[moduleName]().then(function (module) { + if (module.default) { + load(module.default); + } + else { + load(module); + } }); } else { try { diff --git a/tool/esm_resolver_generator.js b/tool/esm_resolver_generator.js new file mode 100644 index 00000000000..a19e18eff09 --- /dev/null +++ b/tool/esm_resolver_generator.js @@ -0,0 +1,65 @@ +var fs = require("fs"); + +function buildResolver() { + var moduleNames = getModuleNames(); + var loader = "import ace from \"./src/ace\";\n"; + loader = loader + moduleNames.map(function (moduleName) { + return `ace.config.setModuleLoader('${moduleName}', () => import('./${moduleName.replace("ace", "src") + ".js"}'));`; + }).join('\n') + "\n\nexport * as default from \"./src/ace\";"; + + fs.writeFileSync(__dirname + '/../esm-resolver.js', loader, "utf8"); +} + +function jsFileList(path, filter) { + path = "./" + path; + if (!filter) filter = /_test/; + + return fs.readdirSync(path).map(function (x) { + if (x.slice(-3) == ".js" && !filter.test(x) && !/\s|BASE|(\b|_)dummy(\b|_)|\.css\.js$/.test(x)) return x.slice(0, -3); + }).filter(Boolean); +} + +function getModuleNames() { + let paths = []; + var modeNames = modeList(); + // modes + let modeNamePaths = modeNames.map(function (name) { + return "ace/mode/" + name; + }); + // snippets + let snippetsPaths = jsFileList("src/snippets").map(function (name) { + return "ace/snippets/" + name; + }); + // themes + let themesPaths = jsFileList("src/theme").map(function (name) { + return "ace/theme/" + name; + }); + // keybindings + let keyBindingsPaths = ["vim", "emacs", "sublime", "vscode"].map(function (name) { + return "ace/keyboard/" + name; + }); + // extensions + let extPaths = jsFileList("src/ext").map(function (name) { + return "ace/ext/" + name; + }); + // workers + let workersPath = workers("src/mode").map(function (name) { + return "src/mode/" + name + "_worker"; + }); + paths.push(...modeNamePaths, ...snippetsPaths, ...themesPaths, ...keyBindingsPaths, ...extPaths, ...workersPath); + return paths; +} + +function modeList() { + return jsFileList("src/mode", /_highlight_rules|_test|_worker|xml_util|_outdent|behaviour|completions/); +} + +function workers(path) { + return jsFileList(path).map(function (x) { + if (x.slice(-7) == "_worker") return x.slice(0, -7); + }).filter(function (x) { + return !!x; + }); +} + +buildResolver(); From b97fc87344329bd816aa55b0560e32f3e397c2b7 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Thu, 23 Feb 2023 16:46:03 +0400 Subject: [PATCH 0729/1293] add esm resolver generator for `ace-builds` --- Makefile.dryice.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 46823a45f42..f96e1fb54f9 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -194,17 +194,22 @@ function buildTypes() { fs.writeFileSync(BUILD_DIR + '/ace.d.ts', moduleRef + '\n' + definitions); fs.writeFileSync(BUILD_DIR + '/ace-modules.d.ts', pathModules); + var esmUrls = []; var loader = paths.map(function(path) { if (/\.js$/.test(path) && !/^ace\.js$/.test(path)) { var moduleName = path.split('.')[0].replace(/-/, "/"); if (/^worker/.test(moduleName)) moduleName = "mode" + moduleName.slice(6) + "_worker"; moduleName = moduleName.replace(/keybinding/, "keyboard"); - return "ace.config.setModuleUrl('ace/" + moduleName + "', require('file-loader?esModule=false!./src-noconflict/" + path + "'))"; + + esmUrls.push("ace.config.setModuleLoader('ace/" + moduleName + "', () => import('./src-noconflict/" + path + "'));"); + return "ace.config.setModuleUrl('ace/" + moduleName + "', require('file-loader?esModule=false!./src-noconflict/" + path + "'));"; } }).join('\n'); + var esmLoader = esmUrls.join('\n'); fs.writeFileSync(BUILD_DIR + '/webpack-resolver.js', loader, "utf8"); + fs.writeFileSync(BUILD_DIR + '/esm-resolver.js', esmLoader, "utf8"); } function demo() { From f5b42cbcdfe2886c2ea314cd6cb4ab6ddb706492 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Thu, 23 Feb 2023 19:11:14 +0400 Subject: [PATCH 0730/1293] add `setModuleLoader` test --- src/config_test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/config_test.js b/src/config_test.js index 3fd950bec74..32ea59b54c0 100644 --- a/src/config_test.js +++ b/src/config_test.js @@ -38,7 +38,11 @@ module.exports = { assert.equal(url, "_.js"); url = config.moduleUrl("ace/ext/textarea"); - assert.equal(url, "a/b/ext-textarea.js"); + assert.equal(url, "a/b/ext-textarea.js"); + + var callback = () => "testCallback"; + config.setModuleLoader("ace/test-module", callback); + assert.equal(config.dynamicModules["ace/test-module"], callback); }, "test: define options" : function() { var o = {}; From 00fed1ebe615cdefe36c732c7ffc8ba5ce24f39c Mon Sep 17 00:00:00 2001 From: mkslanc Date: Sun, 26 Feb 2023 13:38:31 +0400 Subject: [PATCH 0731/1293] expand test for `loadModule`; small refactoring of generator --- Makefile.dryice.js | 10 +++++++--- ace.d.ts | 1 + src/config.js | 2 +- src/config_test.js | 9 +++++++-- tool/esm_resolver_generator.js | 28 ++-------------------------- 5 files changed, 18 insertions(+), 32 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index f96e1fb54f9..7a060aea269 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -870,7 +870,11 @@ function sanityCheck(opts, callback) { }); } -if (!module.parent) - main(process.argv); -else +if (!module.parent) + main(process.argv); +else { exports.buildAce = buildAce; + exports.jsFileList = jsFileList; + exports.modeList = modeList; +} + diff --git a/ace.d.ts b/ace.d.ts index b73cc9d9ee5..ba6d2c70cd1 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -371,6 +371,7 @@ export namespace Ace { all(): { [key: string]: any }; moduleUrl(name: string, component?: string): string; setModuleUrl(name: string, subst: string): string; + setLoader(cb: Function): void; setModuleLoader(name: string, onLoad: Function): void; loadModule(moduleName: string | [string, string], onLoad?: (module: any) => void): void; diff --git a/src/config.js b/src/config.js index 363a7b0ceeb..7600fc90933 100644 --- a/src/config.js +++ b/src/config.js @@ -85,7 +85,7 @@ exports.setLoader = function(cb) { loader = cb; }; -exports.dynamicModules = {}; +exports.dynamicModules = Object.create(null); exports.$loading = {}; exports.loadModule = function(moduleName, onLoad) { var module, moduleType; diff --git a/src/config_test.js b/src/config_test.js index 62cb130eede..faadab6cce5 100644 --- a/src/config_test.js +++ b/src/config_test.js @@ -9,7 +9,7 @@ var assert = require("./test/assertions"); module.exports = { - "test: path resolution" : function() { + "test: path resolution" : function(done) { config.set("packaged", true); var url = config.moduleUrl("kr_theme", "theme"); assert.equal(url, "theme-kr_theme.js"); @@ -40,9 +40,14 @@ module.exports = { assert.equal(url, "a/b/ext-textarea.js"); config.set("packaged", false); - var callback = () => "testCallback"; + /* global Promise*/ + var callback = () => Promise.resolve("success"); config.setModuleLoader("ace/test-module", callback); assert.equal(config.dynamicModules["ace/test-module"], callback); + config.loadModule("ace/test-module", (module) => { + assert.equal(module, "success"); + done(); + }); }, "test: define options" : function() { var o = {}; diff --git a/tool/esm_resolver_generator.js b/tool/esm_resolver_generator.js index a19e18eff09..dcaacd0303f 100644 --- a/tool/esm_resolver_generator.js +++ b/tool/esm_resolver_generator.js @@ -1,4 +1,5 @@ var fs = require("fs"); +const {modeList, jsFileList} = require("../Makefile.dryice"); function buildResolver() { var moduleNames = getModuleNames(); @@ -10,15 +11,6 @@ function buildResolver() { fs.writeFileSync(__dirname + '/../esm-resolver.js', loader, "utf8"); } -function jsFileList(path, filter) { - path = "./" + path; - if (!filter) filter = /_test/; - - return fs.readdirSync(path).map(function (x) { - if (x.slice(-3) == ".js" && !filter.test(x) && !/\s|BASE|(\b|_)dummy(\b|_)|\.css\.js$/.test(x)) return x.slice(0, -3); - }).filter(Boolean); -} - function getModuleNames() { let paths = []; var modeNames = modeList(); @@ -42,24 +34,8 @@ function getModuleNames() { let extPaths = jsFileList("src/ext").map(function (name) { return "ace/ext/" + name; }); - // workers - let workersPath = workers("src/mode").map(function (name) { - return "src/mode/" + name + "_worker"; - }); - paths.push(...modeNamePaths, ...snippetsPaths, ...themesPaths, ...keyBindingsPaths, ...extPaths, ...workersPath); + paths.push(...modeNamePaths, ...snippetsPaths, ...themesPaths, ...keyBindingsPaths, ...extPaths); return paths; } -function modeList() { - return jsFileList("src/mode", /_highlight_rules|_test|_worker|xml_util|_outdent|behaviour|completions/); -} - -function workers(path) { - return jsFileList(path).map(function (x) { - if (x.slice(-7) == "_worker") return x.slice(0, -7); - }).filter(function (x) { - return !!x; - }); -} - buildResolver(); From 4b013b08a288bddfab5388691ae5e7b6b1849f7e Mon Sep 17 00:00:00 2001 From: Nanne <184182+whazor@users.noreply.github.com> Date: Tue, 28 Feb 2023 16:32:51 +0100 Subject: [PATCH 0732/1293] Add CFML CFC support By adding `.cfc` extension to mode list, we support CFML CFC. As CFML CFC is mostly ColdFusion. --- src/ext/modelist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ext/modelist.js b/src/ext/modelist.js index 903538e164c..b0092c112a7 100644 --- a/src/ext/modelist.js +++ b/src/ext/modelist.js @@ -62,7 +62,7 @@ var supportedModes = { Clojure: ["clj|cljs"], Cobol: ["CBL|COB"], coffee: ["coffee|cf|cson|^Cakefile"], - ColdFusion: ["cfm"], + ColdFusion: ["cfm|cfc"], Crystal: ["cr"], CSharp: ["cs"], Csound_Document: ["csd"], From c4ef4031f1dba1b065b7840cf1b16fbb0e6c78e6 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 3 Mar 2023 00:35:04 +0400 Subject: [PATCH 0733/1293] more robust detection of baseUrl --- lib/ace/loader_build.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/ace/loader_build.js b/lib/ace/loader_build.js index a9497dacd80..9b9fd068560 100644 --- a/lib/ace/loader_build.js +++ b/lib/ace/loader_build.js @@ -43,6 +43,10 @@ function init(packaged) { var currentScript = (document.currentScript || document._currentScript ); // native or polyfill var currentDocument = currentScript && currentScript.ownerDocument || document; + if (currentScript && currentScript.src) { + scriptUrl = currentScript.src.split(/[?#]/)[0].split("/").slice(0, -1).join("/") || ""; + } + var scripts = currentDocument.getElementsByTagName("script"); for (var i=0; i Date: Fri, 3 Mar 2023 01:32:14 +0400 Subject: [PATCH 0734/1293] cleanup --- doc/site/images/ac-logo.png | Bin 2662 -> 0 bytes doc/site/images/crunchapp-logo.png | Bin 15917 -> 0 bytes doc/site/images/pixie-logo.png | Bin 5632 -> 0 bytes doc/site/images/processwire-logo.svg | 44 ------------ doc/site/images/repl.it-logo.png | Bin 4291 -> 0 bytes doc/site/images/spandexio-logo.png | Bin 10621 -> 0 bytes doc/site/images/wolf_3d_logo_trans.png | Bin 46064 -> 0 bytes index.html | 92 +------------------------ src/commands/multi_select_commands.js | 2 +- 9 files changed, 4 insertions(+), 134 deletions(-) delete mode 100644 doc/site/images/ac-logo.png delete mode 100644 doc/site/images/crunchapp-logo.png delete mode 100644 doc/site/images/pixie-logo.png delete mode 100644 doc/site/images/processwire-logo.svg delete mode 100644 doc/site/images/repl.it-logo.png delete mode 100644 doc/site/images/spandexio-logo.png delete mode 100644 doc/site/images/wolf_3d_logo_trans.png diff --git a/doc/site/images/ac-logo.png b/doc/site/images/ac-logo.png deleted file mode 100644 index 6ca069a37c6a87d6169e44e37244efd024f1eebf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2662 zcmV-s3YqnZP)(_`g8%^e{{R4h=l}px2mk>USO5SzmjD14Z`WEM zkN^M)>`6pHRCwClntN~+)g8w_XLs+tNk|B=gq|s6yr51Sv2*f~=d$W5_|JdJ! zb=lo}ZxXH3@66`joOA9uXV3Td-c?p2K>!v5mB2Id|2Ke}fxW;qpb3}*^aWM{&jS5{ zdw?GTHlSq8GGGhP2bd2u13vmz%tmi+@@CzDM6UQeda?aBTzFD z^KLn?wZKXl(+IpGH&FoG2Bd+{$y|OiX2=yI7`uSEvKKGL2!T!hADm9AAp^>rN7gr~ z+FggO>E%WmLxEv{p+G5xVS!46QlQWnhJs*1YJkUs$oQIkb`@#g1?(0Hd_xWm-~`Ye zSPC=%3DKOSXRZUlVL61}KtI6o^pBIz(SQYP0A7-|?eck0<^Z@z_5qN&D+_oJxLl-v zzwdq~0Y4=g`+-vd?ZahnEBzf#nkLI&*0p_7ciCyi?x~5b=w9le(11cKEkZAU6`(bi zQl71Y2-yvQHhgOo0(Stv6jgml+WP}1f$<`l329p)#1uR! z>zpT2_lOYnP5Di4xiTo13lWA*aswNsZGdRpT%es#`V}yn>}VI!SDN`!Qfd;9DblXA z*C%a7%I4|eeN)AKyETtJTxZgdR3vSXK2nY%ghs1R|XXO1brAAq-oe7tsA@LeGh zk)S8#knfSUExiaJJ)X;00e=Ce$m zFO7EI2<|D zOhMtfN0%WaX|rT#pHxBbGW#os>kJx_il!8mcAC+OU?PIZm<>EHA!0u0FX7*`h%rA9 ziM=d``Mxhv*{~Lxzu$TjM%fP9(Fz?xhu2Kal1#QWcuds(319nHB?`&~%Yjaw9K?^Kz;XHB zMXn&+4=l=Iy_a(cZ!;(T0;FkdNMo8RVpzt9sKtXnlX|dYQF>I|gu=KcZb8h{D5cL) z5yKO9&djov8VNy@|B>Fb(P1Y zMFlfWz)~k=PwUX7fWgi{C~NzzRsv3&#jM@U~#27D0se8gczfE49|MYt)tN-Eh1eES5jaCeP#9b7sg!2J2C0nR;mHS- zEF9)js&kmPgV^@FB7Dv#id0hLIJ%`;u}REnDvFGtDB?t(3oVq(k697sCR+(+1MUN< zY&a~>F#3OrYh;_V5s`^Fg0k@Q+h`MEN}VmEUKT-wBM$yq34t$?YQd)!TXG>HqZ#!9 zA>er;orhYv5#55{43e^jAE(4@y%3ODe z|3{KEJfwX*@bi!oM%*4V5A!xsvgENZ+)O`2FKX=YY2Nai2ki zVN^g{17{zGwFVA=GGeS+R?E)qrzz`ZWh3RSd^EyK#^MOOz8?4OjjMBTx^0D^+boJ0 ze@lp2`xov@6s?8(JR@#Ue=^B)&(zYPvxN?4W2*>pGT(&^-16}9h%r-fUw_#rS!=G> z<1N{crwHgp7u+JGKO&nVWsM-L&c{SVU;<#GUF}%0)VJ7BZ7=4kOE!^ zVaiiY7||9c(Vy_`mB{3FQS)Rg=I)H=og*KLv;4Li_uZ?Fd91gAv#;`;Ne%K?|0HlL zZYe*iGLS(}(c-+Lrfg=)kLTp-F1G&?NvxW4oVQRCo?5xN)4qdPo5LJcVuQbcTc#g~ z`VE_OC07*qoM6N<$f*oYr9{>OV diff --git a/doc/site/images/crunchapp-logo.png b/doc/site/images/crunchapp-logo.png deleted file mode 100644 index 1ed8d2f7e962764cda27eae40df34c8ec1536036..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15917 zcmV+|KGMO7P)Z#Rki+itGlO{*(aGy zHb_F)F$5xr5eNbzpgsk~?FsxvSw$8RQJy0De6A=W5RgsQ=MxlH7FmKO1V~5-0Rq{# z$xLRF*=Kt1s=EKXR^6)ZNdhL3z|`+oGd?8w|>*BY}bAW`=s{i!Z*o?7|B# zyo6iD|J-xWVbY|@*l)l64qC8a!94aqYUj4n zo{m*?^M==H+q&1p&L3}STS*7HHn0PR_+fPZ{P|Dsz4zWz6Nv=wyYIe==YQ#?mxKZw zbIdV&{Iz<=VSwwezaFz@&BAfVeemp;Utav&QAZwhY*+hoY--(vp58tT4h>=`okcp6 zV|x}uLuvH%4Px`ARt)sC;^?D~KJk@TUw!_JGd}g1v(G*o7hQA_ipAmx2zoREzYcxkz z{{Xr=)}XGsYRvujKk(q~x8Hu_U3cA;;wydCs#PNj@OIs}$>;vKb`HWR!{U2vC2_*W+EC(+-Y2vg{==k1b%TsDWT9j(X?b>qDA&bx$} z`+w$gx#@==emEX{@Ii^3qtOuscspzi#pCBc|2a-L;RJl@Q)gVV@P%jpx!>gG=^YzZ zGIKwGe6axAWh-8nJDA{!Q~~iAkbjFmIUa%whgpU~v4sBKZuEDzVcN85M=n~t_}O#L z`QrJX``qVn)m2x$qg(>nlZ!ztdc*N2oG|9DJMX;dw9`)eOs20DJw1KGoI8#!Rz0X8 zcqVJYeh?xaC~E-!xrj6i{CO58A`*!p9*?7G^jJhu1*rt=e8rND{=RPXb#KBxQzjiaXU;QEf9-2u`}#Y<73?uCU|?VX=bn2m z7B5~r(=9sKknrIEgR9#5PqHs!gZwJh0W&@6sw;oX-XF$S35WN`ZFsd1ms#@H6=UtyY`|PtGs;a6QQGi{V&Rwt&XP$i)4nF9h zPu~5T+h;e`C&zZQZ$dhqLrIu>7Sf5VmWS;WxRd7H{H<|-d~C^uFMoKeKcD~sOTk{l za6x^2J?ck|MWJB-g+&CXajfvJss*fBvqt2@ISO~!%G(tizoJ%o&6qK5W=HE9q=z!hC$qSohj$F<39GNA&K@`(l#@cF$`){0N;wlLT%io=pZpP( zE1&xM;{BAmL6maH_o2e-lxQUSE>r-W2;r5mYp=a_=lLTh0G@-NGiMII^yM$(?6d## zOF#bM_pXn?tzWltB@6Eg!s-ZwFN8>?U#GsnDD{1}aPSl!CLl_hl)c848o;5RFI-RN z)XNWe|A%rh`Y)bK$DYrp{FhQ%+yd~`x-++%Zn_D-_{Gl~e(?QoUw`(QpF5|seKY#{ z`cN#|0+9<}&n~>h1#PJ{PJH2#klFVEp%x<%Rzs)&U-5)^mV(=UqLM_OaH)X~LKc9b z!gsd%y7=6eJ6zbVd`vaU z_x!b7rxp#m2dO($3S3wY>L~&AW4XKo;UFcx1yBG%U;&GSVd6+0;4N*77A+E`)zMAW zS3LdqKRwgb*l@^7Cj5axUc`|K;Aph(>S7KRXry8NZ4m#{&v`|lz$6foKD{nsi6Ce9z z>!vmg4W<>)bA>QvR3;NRzCYJ~TgCO3tE>a{!#FdnBgDWO5)4v)EI$`B6^Udud*6Ps z$~gdaY{z?z8A@^mNM|w_KW-e_J32e2&-eghvFL~bym^y9gbOab5L-64p7O_s?zweL z^XSRTmouPO$cu|FRP`dG+eG7+^|~&*eq6&E~}%#}Q^;?6xC8pfJC#jQ^E|;QyEIz*fH< z!^FGNEvREXSKyfLfC>fS5k_xM52~wEsH>|%ZA~?5+2iV(6l$ugQN#Y0zf&w)Nirpg z?D28HZnpq8-gp!4y7TsZul@GdZ#(AbqfS`AeuH4`%K&9gNgDL1cVcTsAz;pQ*U;I_{ z_jZ2v{=09!DV0n%FJG}*Wb|y?fd*4V6=tNs4Rg=Imv#pt@K@D50}BvK`)m~&63b8K zC?rn^Da$<&6(Kk~64j_skb}~9!nRvnz~aR(;nY)4P3<#j%uTa@^|RkGp*OE%D}N}R zMn0bxtDl>Eo>t~1SZVt8V@=;O+(F31yZZl*8~DHDI3eU;zKi#y$~`!~B5rHr$MDbV zL(LHjFzj~Q?RVh*d+$2zic8MB{jllNj$FHTy@>5?71rtGjHT-Ga`i))dq>ssi6zZ9 zF~A=;`NXmiEcg)5DtM6tF-p7&9EOEPl;HK}30sMf(-7{$E)`*B3q}+mjPlv)zVgZ| z(Yv+nykB1T{a>&cx_0F%Zt_c#tpnI&ERDE;;kK8SEWxMG_+-#(G)s^Z|?jx zTeoaRQGB*iCAVMZ0!pQK1}|`@TYx+6xDyXO_`tCjop;vllP6C)aP7Jcl9Fu{al$5= zXmCb+luzN4Hl+Edg59Gng{dQDb-kEc zXW=XryE{U_uCxduz3YlHtSTLC5X5l+NXi4;Ep6~i3cQA%{U--T2Wz~ zVV-#xC_vhYU~B?ouRFN+mX97-efsjw$MDxy7T-^tj=je=DZx^opQoL_rrhXC43&V8 zdW9M90ZcJinzI)m^jSXN!#h|KJGA97WBY9`XXQ3@^-=F8CJ4W5S8*ZV_6qRG({qu0 z&iTUW_cMJQD!AgP26i`Z!)g=o{>CtaYljt}z`pD)zr5aZ z9{KTifApTjck?7c)(+Sxu&|k5u1F$+V`7^ywtE0C=4PN_%0U=YUo9@GX6+Kghj?XL zKZRqgG+#k9O^aXeWHN<9u^|2sWK4A)zcAz{eA4M5WV4waLiPfFa)l9{!nSAxiE-D& zl+KFCW>Q*a9iTFiJ9oSF)?0Dsop+M1t}fp8hR2?qLlfKJoyL!OoLRB}LwXpGTZi2s{Sf{ZqwBu!#g}YirQd z*n~G$ZCHKGPILqObIhJSoAQ-<`lrsol(Dr*%s%0E+f7d{G7#)I65N`8iRPHK!rwkS zrLpDvQ)XTE9n3uImN)gD!=dB?NBO_LC4s;G&ksMpk99?wB+#96P;hu`O=Y}o8gE0G zgqf^FT?AFIv8KNoi)xNQ?UZR~u1`o@Kz*8(FMCDoR3%+YR(znldHAP1_&tYXUI6t$#?<%8oMUN`OkT{`VUr*EFjtnXU_fg85;;-Q~hdC1JxKizTU z{`E6E@)m}Q(&W2_!dURTZH&b#q?Kdf(5a1L|CRzq_sz%i%q47^{635yGYS!o&f&rr zyN?UJ(9belfdX%)k5>bZyyA@X&8`vp$(lX&0HzVs1si^3YM2R|j}p4?w}1HD)~@b$ z4**I(qtelG&DeHnXj9wf6*Fhf+;v47`DQWOaY=!F_yYU1rC`^JDuyv%P;}7Q>LNcj zjzh-wd@B0vHAmcd@2@VNb>)qZo_6vHZ%zT`KEDvJ-gM~~KUcNpm$efb8`h`Uo3mA0 z;=+g2KoYuumT5}irR7mdJ4lxzXdE5EDcRStWNi=DWsX71q{&Dz^U6({Ct!rhn(032oQBrBBh~c{ zZE5N6i;7xJ>G0V!VqAN@Tg(qT?Dgp$8zfbQnPa;!v->ght#}E2Sz7=qoy#W`I(hxa zK|cvXOg%CBI1S<`Pc?H30BttuHa@dFA18k@Q@_KVE~7_}-qi{aVfH8L1=F-VM@?0Y zlPiG3zQa&|3G0>(BF|ja*FN6zt?3JX{PYjc`^+qPC#06s)9$KIj)`M({x?<3!s zcglEjZl~@0ds}DJh*?1O-+Wui6~*Kd53}7R?^krQWnGd9Oi&fyh*K^$x#=_O_4DXVNj- zjrj>JuR+OFX8$>zu;L)Srz4Ntkc|oZjA^=ZbnpGY{n;7E+`IDHD?fMsMQL8eSh8dZ zqBEO{(^HTB;NG6Rljm`vf^OGxOi6pm6%T_jD#&*e$ zrkBn8c+RniZTNp*__Ts6F#hFA*N|r6!@8A&XdaiqSu`+x#dY(@{XYsS1-PyBM|Q zA9&%l&6r;phX_-ys71Y!Esw=x(U^FzsZ;l3t1u=68t~u4#MD%^eCcLSzj|ntgH@a# zk09}4GH{lB5vT&=w zTyQ2EVdy_9!fxuqD{-5`Hw;5SOZ-|2MUiPxM{5@8`WU7k*gT`~@(pvzD+iy8MD2so zqsAvs>|$nuMH0&22WvJoU}~umf{-$kuaBXwBy!RUR={%)Y-tyJi=c%FYQ|UL#DNuP z>h8k})O{&vNrWIq~j_4*k^@rv#JeMRK67DlDwHRKOh-)A@c$NDIH{~9iQPs_sfnqa^bQifm; zy)O*94Rq*-iHJ&LUyWwq`Ft7C@b7E$@Rk9^1pB*nQ+wylx88YaI-L=Tok^1>?Q~2R6T>7dn_Jo( z+w+d=g>nIbx&}U>=AxuQw@=}59DUvJ=NFiAl=y%t9lPF?g$r>yRMoQKfgeQs(j}f> zh=~qb(DKR}%y9{{VvO$f(3i#SG*IjbkKXYVhP^)9mWMN{3KJ*UIE^X6g4}*s9^IdP zrijP-(F!1Wgl+|`@(mLA=gCAIt!?c~e(|ecf86_cfu2DXdoWxuG{gd^lAYIQ<6~!c z$tF6MC0f^%iQwv|{_hYpFqb~12npCsjKRY;K}#W{xdLsE`vxsZ>`4t#Sm<)5nFLBJ4bK3FG28VQ>}3_w{3O z^azwl9TG&hag$)!H%ywJD-2KJvfqWFp>*e)kDlhx3 zWaY^st-ZWh#4*I1*``dHg1hdzOJIjxB7Wg+r8$OiE#(ilTumfz-KVot-{*(>6-9kW z_c6LOG#i0>c>>3kd%oz}(NfWkJ^FkXjy+-&T1Ll^$=hDW&tv0S23Loc=TnJJ5o;?! z^gJEn=>suMG=C5)~@%icCl=zJE-(g$N}({b!v(ZCQ0?MA{$DPp8} z1NCzji<`rqd4i{@sYwX_;~)Px_=tEu25whvPRS)4d$=UH>Jb8UzBQm_As{tPy5TYc ziJ`#UBm^d(@aZa+6-Du(V{jQdHxFU?=vl~9CP1fXq>E+W zfX;~Ni$N+xq<{S5A2EIU^gs=sCwu;-VULbup?m#A_U7t?c#{hPj@-@kOvtQw?n4C< z7dXH~^Z^u4Lq48TBepkzA@u;G{+}B#`$1*Vic%GmK6p)gKZ`ZkKT}c3uUoXdA6xqh z_`tMAq!N~}2BIND&(h){i6UQkLzlENsHvNQsK9V!!5Kd0mk;p(%yfcI9JS_=WKqI| z>NZqwc^G{q1`zF0NWw-`#Ppgz=6cj_f3QSwf&)+GPM9!ZC#Gw&Dg5Kghp~0xEV%5w zbk@c-95~Oca;`*wE;*ETP~;RDVb()2JT>w{0W)v>?fMhSs0kWHdwX!jo7g}fo2-g5 zR~yBO)_&v*MHYy$Cz$(3iR})%m~CA-JoafTnb59buJSgguBOH?I(cIr0RIti=io>F2$&9iu_GxU4S#(h>FssIF zziy5?ETedLdh0d=OL?;`0N8 z9)Nnm2C0zQ;ZXul9634e5|a2}btlGm4C3$k{n1})L~U(UFmApM}EK*T6*Vn;SnZ2+ncBu#I1M>!{ivYlttmaTyN8NIP z8^3*UNxg|E@mNHJ#O?hhZ0gAi4nS=+vjnyy9+#N+tBM$_H5!#HoTaMhY zR~^S-w%`%@iN~0uBK+fge#_@^3I%Zu#Slv330{Fj7i!iY0-+>DkS#>?0qjF^myq3< zLwsxk2TmzqZ0Bouw0B~9&MWcfC$=<=X=-SQB$5fYvA*8g(Aw5>&wao95sU)QE|_e} z7CNOR_6hmK0NWc@4R5BQ8HUl2pVwyH&)k`&KD45>GPyK#9MvTRFQU+qTx~MWu4@b{ zI`SCE*>c_yU+59uT+3w5kB`tG%S47`Y{eu9I(zf@%iK;JJ$)3WPE28l--3miF#f!y zIVrB3(j__h5(_8;A!uV3@#9l(%9lp(n)M5lCrEve2xHEp8Ue$f&2P@ZX^5e5uNcm% z-dI)I(7X0~cXxd@Q*`@>lN29C$D@Fqt^qo!6H4iVRw$kGa4Zn(Q9Z3T;PYu1)afA> zG(55ydjYgD zQFZ0%6E6Dag;W1|#KhElhZ7VZM7c{gmj+Vk^6y|wufKb=OUYR|LJ^dvx-^)CaDzNOVXllA-lcB9>`CB5gWxAn@$gNfPHDL;gdJ+l zqC4y0h{Nlr&%JctxtGiu^OdlSzWUX#3Jb9F6FbDVOH`~d>Q<=8QR6!!xO!c~jJx5a zjuyV2e-Ks>H~6<~!U3AbO*oN7mpNT z)i-`&uh|cNamxQT*TkC4irh|L_-r3&TRV=0Q$*4al@cTD2F$EqaG`iUyn;~6R{Ai< z@Ks;MfF75}mH`(FR}L_=?}+~qBdnsPK~)oPqwM(-`>VBdDSfALghrfQS%W-O=NEgbxrOLF@iO?fa?a-`&e- zI#jqro-^HFM2UUzhB0w`=9tF+oG~#uQ|y&osYTS?w0Esi`D;k z8JtX$K(c10PRICsnB`zL;w*XkTj_6!_FeNeu7NeQHBq3j zp(eqsbQPAaOQW5w`UDT}B4$B`l+_n_=|9HBa%}_YA5BR8MxF~`i-Z$qbRQn2p;V%g z+u$E4SKuZmh7*r$#<)>2^bTf)HgeXDr8;&Zsw^u9J^43o65Tu&3EZ?v%m5-VZsueZ zmWW?IB&59hXp%$tm#=B8!l?QvoUB{C_U~K2^TQ`QuH(ntdFP$@@|VB7Z3TGYXV>G^ zo4>|M8@yJkEtH2}93G80u$kM*m11mXILW4pdS;|$HH|(XNa}$#EqphS%cp_k!ph?s zio*Rmcg6i_iY03XkYS%GnTU#}n205-oR+%ImPNeta&E*vDHlmvu*uc+WJ?PnW4Hpi zTmd3d0ZgJn7@wJztx%GZ_`rLbFyp{Fq;q-Xaz*b=Mdywh`Y4q`-G7JpN}->FDR>=1 z5`!^pvVQ|DWno5u3}X{4)@@{wLV~%eCte%+^Ot|S;VX8-$P{%MGcdlHCUp>lB!XgmA-9oJv|G}_jn8<6+3rn z5B@fP3wvCJriN;jB6s~s-o{Qt{*1b&DGXM(0=U67t&(dTW4Kyf@nU-}ZKG>T0sVs| zoP2Q2Y0rOk%5$e3lsGA4Z>Om<)8CY1zAMWcTzJ(?G-j~h{4x7J{5Nmb;BOEOI7MSxb>qk>o8=YkutJ!)fV&M&cG=oj!s<;KG&d$Nv87s2ph{v&mq7|C ztKZXM|MuUX1acHKa4#PNFq#9Ty-F$*RKaDs?xHyrZT!T3))(TmV3EC#oG<3nlp#B& z9WUN}Wv;ikIp+{@kyK=7q*rOc3WA18wW@04dcNBYS_sz+`%Ks11`|83!D3(xRt->fUw29~TOCg-IR5%?%(ynh`BmgkV-F$Up)ucU5wx59iCfq8uAp zH~)i?_C+V4<-nz=851On6w|ft!h61v8A{jW*>`YE-)~m$!X;bR6h1X9s&C!{pwF;^ z(rN^A0@TR+^Y>|B;ax*bHC|aWgaxnni&!HOS0R2x*5qb87wXp22ww>ggv79~s>UxTLl1XB!KwrY{eCp4`JHA{+m zP(vE=hOzHW1zn*63 zuEZ>WM-0;CmQl%mFduxG?pj@(WabNY)d2tyI6`@Yv!I{t$*$$jGDTP zG)`#8(AM$kd3RsVz#rk^t{YhAsj8Q zk+?=0JQVwLrA)@FFm5ypr`d{pdT|#vbYziYg6A>6CveNS=`|r0t%0}ljn5^=@rrvL z!D0%Ku#k^*yLhAC!jy>w(@U<7YavR7v~m|^Kr`qtoYz2~fN}}FLpEODFeC;@?K81X z)S?Q-lBx)ja=vVUL|Q@oMupOk;ysiS}Bz83E8LInTa$@-QLE$Bf5z- zY}*x`NPGqoWx`Lf=kqo;h)VE!2ahpa(J%ox3d#})W|O1YDHQ;lIpVdvIjADS<1T@> zDJ|ca!4UIj`|Vwe+UhuS54K27l%Ir_83a@Cw320@v;rB@unIje6hGKJsR=y730@+MAXbrp!p8{hMwzNkxpjTg;#B1w@@Q&YeQ1kGZ8hwCW0)&$&0)!nZTMt&3GER+I_$&~PsAHNYDQa2X5fRT#bu^EYUxZ`xrz>*+rMQfJfgA%4rs6k_W0;QshQppaS zgM@J*t+bL6NPPyZKv_qPp&&He@M4^&jF?F)RP=&Err|=5nd@f;5>1cKueK++k;B~%y@Q1RC7!!jx@Nk41rE@E|C z7A=i&>@~JVP>1>5MLcHhFlL2@xC6naMiUQ&6vCiWn{j-3{T^k4he6ed9s)veIMLZUhu|4}vi&hR`?km0GBz37MqF!hhT5RTw3@ku_gfklU>ICLD){~F=zzAw+!}Dav8pY{Rz?w1#-%X2 zF~zwT0w7WvY%HN6L4C38cHoJAg5~3xOGpB# zN-lxY3MIoG-E=pRCHKzWB35n6ps6N?N#kl*cpeow1I>N&SG_6RP|7$kMyI@W+KUV- zx&j1CyKaTFZ-}H}(zdzDk8;9BJ;OD%DHieM@c5!G^f9c%zmrVt1n*K}PFN%69Z^Dg zGS^u3TKJC0tTKGTjvdW_9*eTuf7698%p1fl)aW`r@W2Cw%RlOT^0|4Obx0$Qo8BbQNl$+U*=*h?lz4sq+8u=elDB&N#6@5*{#)4dwcuvqhhyi-HNGGry`wBS6Zym83g}5jpAxY zx(VI!C49N31W^^rSmgkb8dUVK0_f+oBJdFQzzHdQ^r&VuH&mf-Fo%J`j5ja9zhI%+ z1mOgV*P%=T>>?Aicx@_X7SiMa49oG8!so)RuSqemmlOorIZJ!d(UWJZKFV-_RVG~T zCe~z_Ryyi+h)dx+Mu_LgHl!+L^4aBfA0NQAPY&RRm2fkkd$4NNs({rQmKVhdl*1_p zUz{&d{MS~3h3^MuS5r*LDwn`}D0=(TqOe4adk*?{m?vJB5mD_$o^S~@RvR@rs9uIJm~u8}^aSezeyNxF z-l{5*&P~RnSkCW*ds2+s+}Cpf_jZp=Y;XQ&%1*9M*)f&Gk$PvKY!_jT=8J6R+=BVz!nUf>vXH zy){2v+*)ZAi|Gzzc*lShTlG!M*Ymderr7Q*jqk(a_+alGJy{B6BP6*|5 zpvSvw zK|~6JSe2uJZCL{->Nm4XnD=@=Hun_pk@tayV?VB$JA~`rs{G!P0`M-|TrL;*=&w?IpSgtjGlARd zDE83+k$(voOAu`X>{GAVlEb}Eci_W^H{tMo>)6F^K<_{X>1-}| zQz;m$+`M&>$vPv$WSVF=wH!46HOU0?^(leqm#!Vcyk&g?43A?tC2C>V+Bq3U@X%3} zm&ezuUV=S~qkMMWCLSe~u>7HZoV&4z=fmgcO)xupPouYV&l8?NxbVUY%l_XSRvvgA_uO$?0{CPna{>FBGeqK=< z)lkQPp`1i+CQ7_wj2rAy3Uu34=(nS;8*IUHC1Infu9gAPTJUtqV~e`k%I`snfxPD0 zs1$yXT)9niPmSc7T*@{D?~IG_uz(%Hp>-cjK5!!oT|JtMTCve|X1x z+uw=;@D^)6`t;gsuPu8nPtiG-;*$#ruHbyolzI~g*1kKfJf6!rVD^)cb|hx7N9QX^j0*+pQrbHNMYm-wyi9mIGp-x3Yjncw&0qTlu5 z3ptl3YW~Zr&5uGO8Yp^|kVbP{u$; zl-2b8K}=@o=>}G&q_6QjKF{d!^S`)i0KcEV1-ZP9@r}~o4@;Lqki=|e9UWb{Ggduk zONsP1yD0qH@refQc`TjXg%2*w;@9DG^Z5SJM<2!c=b!IIa62l`=D!qyvx7 zz71h<4L_rRv>)KI2i~Hb9K44Y}&M`q5|+LQh1cwz`%g0C|1&Z zeugXl<6{>@-dKJevlX>Dl`|l!BplI6Bc%jh_D}&dT4@?~CCsLVAo7!sZ;a!V_cmdl zu_-a~rhhPt!AvfALrCvl1QlXtMN{L14W88DV^-F6WbxF}UKVziFh-;NPy(v5&nIQ| z1}S(1!aK*2SBp)RoRACA_gOAkAi;I3wh8Cex2h{a1(t{~>;3ruT3D^Nj(VV$XYh4KJ? zTbfyiG~lQM>g2ryvjy}IWyKi0U?sCW7Z8s{MMkeS6&K2|aOEIgSl*8WQ`E-lsO-Mg zpcEDEFgjdPhe|9VOutQ45l5qZDi}L;?7MF$;f06#@a2g!-n)F+ON)1zT%y=bTa114 zG_dq3;JCvHesTcC#ayck3Lv_+%ou7*Fq})M6f%-ZE`gICneXQ-w!No-lbB23z>VJ} zjJpG#K`hzwPNDiH6ug;|4|L{t3`?-%5>*lOr%M9iuVt&hsXBt1ctm0k__wVk##D_; zRP|s+PltE1Tgg^HmFMz#^^QkQ^D_A5(^>o%GZ6WyyZHXZyG;S$hlJ@xz*oBn790Wm zDn-%6t%0p_1{U>qVrCCXdAA7JPU48)UY;w`>zmTp+Fuk(u>bfJsv>bzvnauA#qt^} zxHYom?^W#?k=V&Hpf`qvckw6*W){qTM5BwT4D7ikVFQA&QL?FbYh6CbjrF19|L z!Btcd=ON_K6R|L*l-qK&dE9=vEePae}!DDoFL=?GbsAeGF z$LAF4q>^S*2dj5#)hn~_P+6Pc<=a}euP)-5M>06S-^JS9DTm#r0HMsG*oG)pJOg}a z8o>_^q_`@gDvR1Bh+#&qatqYA1{Dfu74blTaKZ#-Gl2EdnjtJ>g5?Up_nL&9rosJi zI_IE!sD$ppk_a8^5*CtCHRa5pUlBFykeVx>RNxi5C^PvbhpJpYkZ@!u{74@E!>r=> z5NOF!srF3fouL4H{{ByY`qOf>4HRFY_$G4+&%GD;HFF8$v`gS9IpQjppm2eBY=u0+ z4p7gu@#YbS!vxUTSHR}pLI6l`TM%Q)z=2+zg?CXaXwE&sBlOrTZ5w%f3G|>=zDD^J zJY`VLo{x=c+W6Y&y)Moa@#vw$+-c|Ypa1+WmCJ660{C{*O*i54%P+4OTJkMLFnIQ@#mVh~QYkwPX$9YM>}Qo^=WM~zl0{&!T2nTLl5EcipRJZcsR z@(!rM)X`>N`g$sSy=_w!R!Wo4!QR3FJaWK!=U({B+wW-qxB20>nhJia8>gN<^2j41 zb5&`}Qf!z{@v+wku4OW|6Y2tsG_qr)kZm<{-wjR%d21W>X;@wkAjldH06HKr%Ffj} zd~NDWJe4ccxrKtv>~V%JzfB#_moi*adNPl1v1sT&GL-yVg}>VsfN!Usda9tG&zd!B zSc$Bl`0wWkPR32EI|0e2q^yD+ip`pKBu4GJW;1AIS-NZ(=_ok zyme7L!_&wNAl@{Q;*5fF34&)(k^oC{44|U~YuizR*7}r z7nQUUh}hniGm6BZDz+!taj!Y}?K1^jny2W&+i2Tu3UJj`S7GhiHy7csMbx<%_%sU_ zFF%Ol$IK-p3JNN_ntI0FfFhh|zrMXT_OiR+5n3U2hY-bGfxa@~n?O$zIJn~QL}9he zdu0Az!na;6;by!Ix80@yl`4iix~-?Up^xB&LxDT$D5e!uln}UwQB+kNEjP^oh6WW?>K6`Y9GZPcf^N z;2xeX)wM2>4l<<@A<(Tv+(_88@K)^2qHJL^`geZbwX6D&T&rMIPW zxtSUl*ouhiHFQRdTiRIViKF2BT)#~0O%#D5r(ip=6TRr-x)*I+W-SVaz$QjlmWg9GKNbw?fEh%tsRbUWIr% z-!Du)+cyyWeXfHGG8CGRw6hyv`aElaUx5peQ;1mEA6;@c5fRhBNn303JVr3i{y z?6s#;KNsvOvZ|MMRxeSkI_G)dyGtGXczZEMb93{sx3A^x*&_*)aL++^gqPT+~4^XM3OLiYu|;?HR;!*Fj`Xv@w^q2=?)_%QjT!q0c9B@o4!F_QB$9~=Ph$Ir*?ub9PhtD}ftQ%+|LBgMlLNgy z_4@5rO4zR4xZhp0Xwmkf1Y!F5YOevN)Ds+53%rM|_-6ie4ruKK7BLVx-e46-2Q3uJ5*LE1!S`5iN=sfd=vb!b5omLI{vaCa;;f z_n!UzF}X8$Zf24I(LQvqb=KVHIp^-**?XV8&pt!Uj4z4E_Di;Nc9gF)sb6sY1V8~G zY{d=?kN`opA4>qH?fff6;tQ%*0pJ4QNm1OLTyr~)T}S}eBQ#+Cr{12ducwK6SY-(S z8e)>C*os{`QVjx2T}dP)#F7%D{aD9IO3aiwP-}ClRsdYdLY=q$=HWFbQ{NXsJp~9M z0fbeYfGFr_KPW|gJHJ6YarPUMN@Z0 zIhTkBfiVbDHUo$QGG=b2k2U2Mn*k%!Fw4_?5RI5${xVpCZvV#gFB6oLwIKotU2he4 z7sYNjoc1KueYd@hU%a!w@OyvSb=uFKh34!Gvm9d`6VoU5dlh$#ZV?LI$H4yB19*AI z%rOU@br3)!9xre0^nU?)6F@Ii-5U7J+2O4>7q2J?j{FwDb96L6<-AV-1s*GV9>O)< zy2hIOCxLmT&zvZej+ahUWm#&t_2nKsR*2d;mMeYuwa z0JYYyknhaBYWvzHO+D2{XLKTfXh;u;hGYY82PBnYw|nT8gctzKO^4dD%W7H+N9B8V zPZ;1kgajz|5^4VpqX!MI1quC`b z5E-zqF+9=l7U2m4e8<|Kb%t3i5R+8b$x_8Due6N1>Z<>VG&PCO)-M0jzyOY4Led#; z>(>s3)1Ek;L_1kdphQd(%<6`ydsi^(AKc4*Xkd;OM7zpDOe!qNh}zD>?e+Xe)A0a8 z=r|>H0%QT=H1-xCmMux;hghIk4xo63tc*f^DX+x-r^kbb)tQQ^a(wt8N{6@eqHBN-1Yy76>X5060T4DtgeC{3}Rx zA3OG-%*wyc6bvB+L=>pa>4U(6EzN)o0vr^KV3x;qxPP|x&LbBMSTiKwZ3o6)Qu!mP zRF?oCDr#%LM?`Ia_h7bLF)lnUt3suCq}ZYk(onL$rSDmV?iy89ouG8-=nkK^v-gf) z4m*0%oa-hHpI_0Rgm#7?sQ}8BZNb1Uo}FHbY2wYAMzN6#8?+OtU5jg)Hl1PB5I5M?)n&1+VD*7W-H#d}^_v$werovSgY3iAN))P#;*UYMoA@8(>| zY@Za^OI-RwQR%t+-RcMTHtIhWg0wAW{#|db`t(#JPo*u%?LZ?IR1Rn0X%J<}{Gm@5 z&sn)}=+L3=)GX!UER>Nfl##^d2qA>8a|mKIW^Sb~uyD&u4EzOxE_H$d01SAbsAJ&D zd^<3A!=Fd|en*!5zRGZnlHDJF+wQ7$j2Kr~R}b&lG;-Xy)E+*QOiVdgDvHwORCM?gTgM1Z{1u>~@r%*cZK5qyMd9Ec zs9vvhXAOn7*O{y+IRF5c??+^|P8d7=uF>T$|GotPRB*CBWQRZ(wGv6O`h7?`H=Zs=qZRf1fKV zvk@_T@MO5*_jtj~$nomfP}6#5#PF6E`qgT;BJ2h`Y4qPdso#Qo-#>6lqltk45LSHS zfA?|i%?k?(e&_f5Q-x#z0G?3uLJ*Cz&XtU@22rH|L|1l{F|!zNE%PB)dy}nVXxdUwg&* z>&A)w3&3EjhTZj%Z#wI<`fysVd*9)fUX|Q#BA6{lJmz8?Yg15qXuzHV|L8xQKd8@Y zO^{tu?RD~XOys}J$w_7i?>fEp5P+K9Az3TX}Dw+p_BVY~#Xa#c{m?Nlb zVKnPSZ%;g>@8Vpq(&Tv0p05=@e&o`DFZeY1v2`(``OkTHGyQt~`t zkZA_JoBnp|hGnmB?ut>d`Vv}$nA7?UW9C-+nCKGgTn$#QJbLu#q3*N+0HkQ|#!rN+ zz|0!ZONC>WrDmoC#GWG+XHp;#2xjl9tgM4Kz|3F}YMS&uWBPfIAlbV%_5`Cvg}$I4 zP{AxASp|Us=n#;|bSXh35*nPjS)8g5vo1Jg*4^*!dy|180BFuEy5aU^n@Z}}XZb<6 zI`$+R+U_-X(~b}RkHDki6Pw)HUngh#op+Lrvkn7GvmZd+S|IEm7cDYyQez^}_Us zMl^;^FJhj#73sBuV+SRv+;(=~ZADqiEN&kZrciqW^x5oX4;d!3@Xb+`S9B3LEHkk5Ud=NmSDBE?wrHp=j z^WnCkNUV=ri&1t^?8OO+X+UAgG9m7y`1NyU+&N{+lx5!+CW1xOv%Vn<)?*yR|66w+#b0N zhjqiKYoozYlTnoIu0nF8*10rmmy&dnV%)H#di>F5^C43*q+}?Ecg}}2V~iq@Svcy! zQ8zER_;~qZJ0@M%Q-)-uprq-PQ804qaki7P;qGRaCymS{W!3)8k(@gW$JJ z!b%Mykzo#=^!(^6?-<-&rclyxdI?dbvLxOP0GZY2yTdNKEKLNtdnCB~fN*=`#vAMR zd7k)Z{R?fZ4m8`P!$bPItH<@(gw)az0T8J=(sp{(WN0w=sYGo^0OACrOHj&do3+q+Xrig#RfpQ4Zd-peB=PtNS-mx{z8$TZEA zJlZm|xSov22k{GAW|kE)U@!(s43yocpG91Np|VzN_|!}MSCmD4>^y<|s?epccChQgA(5>+cL>`%Y>WaWa zA5Bm9PG_VNI~H_2`fbJYD{>ep1fc*#gF(tbsImB&1fWX>5#VWST>P`~8MCgOI3SFU z>)=Uwx@-0{o*gk=Pzc6Ffr3)R7~KBNDYHrJX{7Pl*H7NwH|20k^e(-9Kp4RTue<)S z@VUwqORT$QoY5FqxOpm=OJd<=60&IQBcp!y=r#Z!reg}(=Dmcjzyr4a>fDzCbN_h- zTp2N=PUJyG?-v7)ZJZ8L=53!jc6oQVG^oz@2=o9eok%qsjocVqonZ!FS##g_-$P=( z+{sjlM8dQ<(2Vgq7%pM#&2ftmQg8Z91xOs2dsfv9-+rWRkztZBB*Tm}SNh(2^xh4f zgwwa(diuuV`Q>-AqAdUb2qnuHHs!^!SKT(H{EY>BQ+^`IrnX5KhS4P`%=(W-v^keu znUiC$fuMS(0GJYZykbv)c@;>hW}zGeaEKs7kZ`dO9wOGZ-7<0+0I1x_EF#_|DO;#D z_>l-5ddt23PfJTzFSWd1ODfW(cq#zQEeC_y4TdtDh|x=!73i4I*5&T0r%I3It=SuT z#W3O3CBra`kSP7@%ncu}+TB(Et7eW}7?@vv5ftq^007l9C_3&3FO8f$`SPtFe%RdM zdx69P2tnx%AlvUer-|mwxhN2s^gGV%dmD)2O93p@!2o8&s!PZoMC_cR;i_}aIp>p- zl9GBAERz~j>i0iK(dKGITWdu$bVxKDtZ~(p?%VLe2lX)>eU<(3C^|-gom&cw7uOy5 zcG&c)0zjUh)*)sm?BtA*bpT|=_TbqOgZt=`V-tz}n;tYPSF8md?TS|b0L`QPSdYrB zAkil5=Fq$~NDYX+4(EnXW9ijH zUOn&0ikcQfyds*8e3(`8%=0D3k(yI^%Iu=^+3g?8s@4la^|Mf8nIJXF@Z zPoFRVs7}X6m)eQ!s&aEDh?bO;)E{prt7eY+XzcwfM`nER$bpj5(zI*pzCX|SfvT$U?bF`8ytK=)ozc4G z%R>NG09ZjpV&cS!ZXtvk3WZd!*DDl7;kLFm>GS!_)oa%p0HCr%LJZkdR#-fnzL^!8tl-UFQY4zu$6F8K`iUDD|@rKP3T z)V;^3J;5REAh1XUC;K6u6O#}-*_o*BYQ&|wH`Yid>1&WM=+=fEi|mFy9!+*U^IuP@ zGtz9b(o_HLAOS?1;JT0u2_izKTU&vIggBqIeocJEK(Ld5!-kj~?Xkbx7%XxZ9YZB{&-^PV5l#|L$55(Wd#2qb&d8oBT8^&Jwyl^{^_z=l^i;k7 z&7_jUhPYYnF$vK&zxCIgx^0VAuU>87>AQNW+W%_m;D?w}^cW!JZ#?;L_vbGE?j)Rm zNa$bGUp9SB-5|k^(23S_v#hV_1gL|An692vSzpuflPZqwEw|QVSaY|T?!w~^NqkK` aNB - - - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/doc/site/images/repl.it-logo.png b/doc/site/images/repl.it-logo.png deleted file mode 100644 index bf383a623eedc37e16148baed0b988619968d100..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4291 zcmV;!5IpaRP)Px#32;bRa{vG?BLDy{BLR4&KXw2B00(qQO+^RW2>}K&4B^TrumAu624YJ`L;(K) z{{a7>y{D4^01!h-L_t(|+U;ElcoanzCJ6+R5E3C8R793bSQZo^D55|D3L3#xKv~x1 z3?!3DfCLPgBgb@4CL}>X5L{eWM07E(0;?>r;KAX?f+C0ULJ<{30Z~CY6_Wj5PffOI zrjJQF1jc&b_kTU!Uc0nRz;euyEEe^4Z z#V$@rbBMF>dpU^vA7BNrDAguR1BP3i?p~I>qWF{<1x>wA>F%9Iq;igw{Znpaa+>7Wug2mC^WhDopuCc~)dMe`cr?{*;R z3PpJ;dkhc7N|3k{?{O}*61=+q05ZL1fT%hUY5QNGk2TK|hc-+Oon!_e}{s&U#XNM@57CpdYrV{t}ItcB#2Td*_d@h zSRcqXUXq^Yjsj`#foA>5Pnom88ffIsoPM0N>K+1zm`bC1qvXSDp4?art||}^`(4J# z>kx9h=M}P4&tVtJab4Uk#!2gE(B*Isz)1gu4$*MjMSj)|Aky>LmH@fAKffy@Q zNCj=_S^xsxj&e<8q-+He-GsqZUmUv=WMVZ@?NUTcWWj-Lz+T|6 z*JO~0b`T(wA%jK2I$DuqP`GGmLslOqfH2jMSAv2I<+hSJ6nrR9wW%FqB{c5y6CWvz zyvR2o6u1>A237#ufUUsufB^IZLQFbWBj9e}FXP0--Ci!HE@b4j%+Zo3O;P*GGr1c)Vx27G3-**Df0G|Lyfu0)mLx2&$USB&J zr~oDcVFs>i2kL@`o51 z<*({zv4u_Q?t|mYnN3^eM?3Dpz->Cx51R#Y-WNCT3W4d+hiUS&5@~J1_t-Zqqo6nr z``*_IPT(P0G}%=W6UYr?q*&~y1AD5}jRDpKcryrVf#!h_3EM8fdo?&05qv;>55z7i zX`u~cEZ)QxHrNp=K|=D2-Uv*>-~0W$xg^4_N0~mg)bfdF=Tp}1Nt|y6Gb1)?y4mcK zX73&#Y0G54D}mkYbsO)eUOe!DqNCpd(tyrvFcJlH1jYexD9U~gbTD{bZGdkT_32@m z0CWPH0nzMSV}O;4vS)!w^-S6s?7HMQC%Z=Fv86R9jnmx?H@`wgh|euf@fK!xYPqY* zEq3>HCYdKAm?l31(#~h3eMZMkMi0|qVd1kO0g%>*rNFg1HsvN+c`_j$(z96ydgW_b zy`4Z41K0JD!o;}M0C~Ct+hz5LAcKDsE-xt;R%WB(^_&b64c7|aLd(6FmMiGKnv;{0 zLx&C>8a8Oqps<951Wo@c+MLHU{j#j0*-gCuUQN;-z;zB;U9mq<(iRyYpG)!j?Ha&M zZ3TQLt3N-0hiSDDSCXua2sTiYKV0!aO&UHkU!TY&9bz+PYvupY?n-@m`#y6_0JMBDp7-nGa@h{k}+u0z_dfgx)@IuHnH zcj^t2aQrGoojYrAW4i*UWo>jbK-yhoZq(phk<7E8`j7+_X`#)cfDMcUdoUZ}257I1 zIz;*76tT>&)_mZB2f{$ivB1YbB~YaV$h-sF;eM_qj1qJ}+D%i0(ioPkqea>;ajk>I z#pQvJHqAgs7s$#ltHsTA%i39NfV4eoajqV+c7CA;FPKSt1)Ft1@qatK1e0~LvYxOw zT&iXPwCETR@&t%k<&Us396{Mpej;cCK-w237na20_dFfa?xkQyfCDij<+tm36%5|o zIN*%T#0b;4u9YT`X_c(KalvdJT*C0BrglBz$ zgdf~pn{U%0wb zv?E}yWG|tl#WpshPA5MDvDpC*#C`2~h7?)&f(W5k7e4&mbzcbUcx3GC)%+@xSz#I`h}0&zR~YcnY+DH{L$c;IPZIj{m)1i}ti zalQ3Woy-U~9Bk@sX|ShR+3D4$f?X8tvloTe0cmNrLb;3#6pqaR8tT*;st71-pu}?n zr2SC#d#jPGGN#RUn3bBy2wQbokQT0^rh23WIkP3w+THE&_a+u0t7ICll~(((b)#Sk zsHWRV({Ajp3Y9_ENt*JLW_R~sWk*Yi;@wrb)D_(~UAokdp$dfwc!`3)Hf-}e{Pz_G1BiZ#DDj=9^0 z0bj_%xa**4udmCFL!HJd({uE&QJHC_cU{b^sHnlY4g>wo>;o+VUoz_+z*g*4{o41B zLsNvZXo)-y(X9ygo(8cOpp7d62x_!Q^#%}*DyE8`0~s;75z($ZkEFr>wt7=2_TQK4 zP3rNH`#6~iGs+$hyBHmZx=D(`jv7c?rqj%anp_uqNN8s7j|R^5Gb5S)N4bYmr0P?n{m&^-+E35H@>5k@Tqdks0$i0^8 zCF@Vj3$PD~-%DxAxx&_sz(YclE)S>LSmKU%HtzPci@dfMvso#*JC9A`+rs9UtpgSS z$pH?cRBtFF?|tM60A689-tRE8U>&a6D|W2?=QbS|FCzEC8Wf0SVBklw~%D zEe7(X>gqB!;X@1t+cXFQ;hNS&$t*05C8xa#5oy_^iEQxJT_=j>)6kWvQaKl`wD^OR zXl`>IM3CU1WUJbRAAsZV#h%k?>w7#fw>1b7xztE|*$W8L1$bM9Jo}(2d$0cFyAar; zQ&P2~SZ3in>APezgfLE8E)6uC{)r&u7PXKnH0ABqf|;b1i|cH~aEIvqXo$^~ZFLky z1XKTV($A^Ia!shth5Um=Y+(nx?tz9)KrTTX?=3D|xNzaZ lg$oxhT)1%I!sQZ?{{eW9oU^wsmqY*n002ovPDHLkV1lrfBe?(o diff --git a/doc/site/images/spandexio-logo.png b/doc/site/images/spandexio-logo.png deleted file mode 100644 index e2fdb79d56aea5a419deb8ae1a3b8cf36f5d43dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10621 zcmV-@DT3CCP)KLZ*U+WL4C3H$Cs9yLTL;A{{h}Ew%(6h0-ENR3cDua~5XDi*4?bTJ z0M8qCqt@ha%mj(jzyzrD!ZZM30fP&jXb@w-^aqIsaR->{xKju502KR~zW_x)^EaTV z9M=Q!0hoQq^}r|qrl0vTVCwKv1JvVWq)z)MT2?H}l6EilLwPhxbvR7rUKGSCiB(sJ zJs|rJfcb2()2hkU^3Klo8vl&rdNQ;3Lj)ieAM=(IoT>9~6-M>7!G0)Q_qqxyijZj0-L_ z+dx7I5N9d*_S=Mnk_{mw*(78s31kzpSs>Klr3BW6ZfuOf4L7;TR_{8}>3#ZqKV%y> zY|D~u`CC8N^gvuom;C_*0MO9TfR(FO!e+C=YOz37)ypUxBf74G<2aa1CcOLZyQc%?WIgMn$wEUz z16HkC1-s1#QPq%)r@+wkWfTsZEVG$|(P)IKsvt=c$z&4AWD?h3e?7{|$_5sY0|)kF z?b@|47!0u4tO$l<#$+PxVrcrZihv*$Mbd0GW4F<0RF7DVUQkj)CxjLKy*rPHda!fG2b$7r;DDvILK&v@Phf?)9Z z=bKSjSOoes7Nt*s*zHab1kwACGzWk*%aRO+X6Va+=ui{|1i_dok^^~ycjkFF{Qdx{ ztM_B<*s6g61kiEB#A%ueKvyY>1WA&(42TYjA^}}jG+l$PYbSgTm`q00)YM|ch)S?5 zivf$WF3Y)z$z((z5W?QQHQ)F*mjSuJT4XkxP*YP2Ns=xDGFY@E5{Y8Rjy;zF87x}D z^LFgpS92MV!6Y1K7zjX!Q;drziYz0YPD9rLNs=InBKpcaT(mTjAO<4rJvJd%0B9Es z6oMe2>pDbHgdhko8jUcUEvkhg+Z06!ah!nzke^DWtf^EABuT<#GJWG0AFR^nJml2J z=N}AF6p>B~aJyZBQB@;fibTR|GCg_ws;a7jFZ}I4amB3JaJyXG_U+q?GBPq|bosh( z>*(m5Dl0OK90!V`E(z_S&;8Gt!xm3JzgnSb2uGu^m@U!SvuEA!bUL1QWH_*6`*zR- zV6iA*4B{HV6u%so@)qFo%=yR0%_vGS$OCwKpV_pEpC`N z4UvWx#1tCadln+tp@JYfVY4~*O_@A(nke>0V}lhGdN687AP~ct(IxBexMSJ_KoAqB z=qN3{8rNRy#lJn=g{_TF(8-itZLPb}Nw!b9D$(X~t8I~F!m`U6}<6g zIUak}iM@L}F>^*C09&=$V!ZjKmtKC|yb?HFp}iA$&N1{?`o)e$-VTNyLdNbz=hjy zb7IG?-pQXk=gJk;)zwR@tM@L=@?=6AWKNzOY_>`e1Pren@?;_!JG7_zeLVP}jPHNn z2mnY#fV$6r^@*?cyDoBdLu(9L*X32CwPix4}$il<-0hz@>s`j5= z`S{H@<~XuO9S&dhlXxP=z(VILQMa)+{}$T~YnB8)9KX+LMw@2DC$0OD)8vQlbnP$n zdf#bmYFaYb+Ls2EhNMy{hn*6P z;}lI-K-f!QRjbEsTl35VPp$->eHM7?4J$M`0!d1tsHkw|Wv6~7K+}Yu;O)jG4h@GQbJdxKjy5>S$oR7`^e6<r$e zb=3;l=r12pRb6HAj;T&Z!`QpE2|LmWFf7}|amJ=ZB2jc%Lr&#CGz}z4qOi2IJuAN$ zF@HNYulpl(DFK2u#vLl6Xv9yv@cE-r>F7GquGQ;^dEkQ7g}wh@qJ0ux{eer_WDzGEpL=4ZswxCQ1Wi*Q$lh?5A}MVDYKJ@M??ECS$Cn51 zKvx$7t10R$vb_{%S<$L$hO^fYLW7ZsV^hQ3o$;orptJ})*|jj4HiIB6NG4NuQ4|o1 z$6&MCU@)-IH0@|_?j-=ovHfr|`ce-eh~BVNl4MAd1e3|66cps`QWSMJMbQDf-9`oj z!J~{M*cHS0kYiUO^En(=;3hdvr2Z5j;N+N=&!r()X z9qu9(J+cF~hHGD(C~sIGAm=O}9U4TU2}80g-(EhiH3D)cKx%mQg9JXR0o+U+9;@|{ zkt2s=()bC`phA>oIP5%FhIS;9$(uVmyMEH+>&|647DmnpP16P&Ak+!R#2JCmbsfP_ z2$^noqO7dsc2&hYUauE|kcO%XkYyRMxQbLVjYKkyXiS3@BnryM;4{4x)%$^n2u!cM z{Vf~0_Pyl6FBeg^+|!#worYa$K-^hc_Zffh_YcxlkWwg6LL5pu z1&shCS%fU4px7)hm~A1i)A^^0^720&tgZd=-aY%C42Q#TI2`A_)4v}+ggh-EM|ivL z?rxL~8S+KdsF8CxmKOKzYeX_BfudNnG$vrPWT2vK3(}GSG*g5nSNDJ>Zbk9XVOYj@ zAg<>^jsZy<0fM|{iLr6}wrD(9Wwf~tE2w^g4%4v6hrruP+u!!AoVuom7tsvB1~6H` zTP+_WgEC_0*iwWNB-VvhIB)tc0wtBOmX(6;X@-GfkRSnuCQ(#e^i;)=@|B-&+_<5w ztu2S=?Kqzn?7U^_1VN&!s|(YnPF?-bgAYsxp^1Kf6o3f~Ex_Y$LL%Y^OQ+z?6QS!7 zWO+=OJKKVSq8yauc4Eh?@8Yq?fNl#A2m_?3NJV4jkM|Um???n1dQm@yu~i8g*3==G z>_zP#7p)v~D9-z#0w@3|e*k+wyaCs`cc9zgg|V~(2~Rl=B_#Mi+k{joiImNQq(sBL zc^@*vX=p|cozV!&E6VD}j~`c>Or{Pbld1FS@cU6Q{AM3Q5(K*aeiT(!Zo225yROlp z!`B^z+bLsoRUD!q0eS)ylLyVTL4eh{g;^B~_>-i>@9cdTL}0<$Xx%fFQ)d zP^vusy2r-llrLT@gc_miz0saVFt86}$!s2Q?G zz%JLqXvu5;sBGn!28+w@N&xCmdMOA+B6UW-ixF9Bn5RB%HaJ`SgDv=iPSz07XSbT?-amb*CVR=gpV&!>Q9a zRg(ij5QwG)%o$esiwaq8X?*=zXj~CE!xTvBZtx5VqhZVa;ov7vxZMfJGL3lL1cvd$ z#0e9cnsF1uM*f|lm(HN5%oafdM4d#L_!>HlLm-FEkfJF_F2FHt^0lT!%d1kX?$$Kn z?fl5|_Sh~i)9;J}P1ykFlkwG)<1s2webmDcycPf1o%Q(omdppFWC|PsC}uM#QAAT3 zm0vKfYu04|tP< zAc)Ax;5*%ArBAQbWpocKLtw}}*xdj}G7wW+UNLiTJ&{fm5JfjMjR(W904z{cHz+C- zinP0+;n2ee)9Jt%jsaxd1R+JCv}y#hhI^qYI@A;(Cj?ZC9QU0J@6=yBpM2)}`gBfD zw$clRL6GsmW8*Qdr~2!g3ktZ!G5w>}S(Ohk=_E249Tr*#FQ#FI1}Ci}TNlwm8f?Gl zz$crUdX^)>0jD814cjKQ*h z7g{0#WM<_eKRdq>B#i>x8X_Vk{dhlrwx%*@P4Nm20*-Xvo4b`$n?4n@(J$yjjB zq1!TSQAU=HXO-bolmba|p`+V~&W=?t3#sP&4O|8o#sQUN5vl(vpnn02$pXx3I)K;zd=qTSF>AtYW<2c6 z{rT(FTmL1K5kON^pOQL;0H722jN+$VY2|l^1QmNf`wUHu4KPIGO%{uJz@x2xvc1P= z%DS$BHE^M5Jcaru7Q-rb;;Q-EAWA%1nx%qp*otphT6fw&f+RVBrqI#)`u#?WtK4qO zxTbd=%pk2Fz*II7%<3psXNm|GUk6=P;Eso}u449YUQnm})J1oKB?)MHU#|>g1iG+( zFi0Lm=FXCWYKntnc#!vQr}G)*IwNZO;JAQ;kzw$=&Q zzjr=Vl|oVBUmHxOeHDu0>@x+UC~25XKD7A%`GK_hf1YI7{{R5AwNj|x@+DfCt$1;K zH_Eq}@mN2Y1bG+s z-FqiGi-tpMX|W1|U>ax|Wk54^P18V-C@L(;H%^+CgGjs-Pyb;m{`kj9Xlxq#vD+Ph zu2X%O5E_acfu_cgn>+O`O)q&e5eI-ER1Fw6wi+L=E<#@ZAtZSP_RlEbkut!Z1gr^k zgwj|ty71-aW*1zaPHXTo3T%EMl>^>tIdo$o4klR-TVw#oHd_WM@FvZhW=7^POKPN+5$_oH#iP zII*Hg!)Wxwf4tOc>wZU-V<;*M18`&P*cIpr41>40H<-`?=ym`xJMhb)z)$x< z(@E4s3EYvd{7>$X)KRH06m*0_DO@wR@^7;j&T9eyWzTMW{>A6W z@?@jt;Gv1oaa=dOewe8^GS0h(=!X}?9~r$inK+I%iA17sIGl^WebcS@_P55Nxd~Xl z9C-AX-tfjRzW1Qj(g|IcPD|Zu8U?dC0O%2H+WO2~x98?}1fd-T1z|)Y45mz3kLul5 z_C5pzz>t*Lz?kTxbFSfTnBEH1(`TzX1`%~FI1&O)yD)lm3x&n4J)I;xbI%#*!kJ+#+HXF zK{*xhE)5VZn6DoEaIs68s2c5Bw@g9P^^+<*l1`var9ciFAwF0C>HPA)JQKj)y*LnT z!vRu-RR5^ zP{ZBc4?kJ-xhw-_x*NW(9Ne+|RtV|d>pb}=@cKVCn>#YT`%yz%fLgcxoj)G(ty^^L zz0`m1!rfQrz%Pn`O+i{@!JCZRt}n8V9%7W*gQO90QHM-XNa+N+bq1orh&ie5_x_rz zWsjDkI{^TbC&RgGH)cw7Wck0uoU3tt;R&;kO;ZN6Xhuvm6?#9e!Gko3M z{Hw41{iVC_zH4zf6vn)(YB71n2t)%4G{iwbLOeNiO z1(r+nCSWN)WT_KIBLTCC0?jhW$p+T12R3ZzecDC=c=DgaSU2pR=U2YmakZQ(1IzYC zYb2!r8V_Hm!o0io?JuWQEgWeOOPf;yz_GyYLkmz~3WCkkAzN%vDH4K8pj#x-DX6gO z3?iBWCXobdcf$~GMPTA^#6t!>6M`VXFbo>%>%-AV z7=j?4aXwGA!(5*L88RgA=&{9Ofz?KJwzf7NZ38_X6dg{d6Wu*Mx3es3Eh{Ts${NfN z1sx_+8j%E$g)aD8Y25c?3G=R;f%f(UzWQoEoURbeW&I+m1y4)81o1IMAIwe_L*Klre&tE($JBO~J*D}=hHfuiU(ieghF$>3~8zfD#{bJH>O zI0a49T8u_xTPl^xKULGMuInHO0ydis(P%99op;{dSXNfHv81T@F{_jR0F)UfvwoN- z2kdqd9A`u%Vu7kg@SA@RprkYxLL5lqH4GfZp0q*O@z<4MWxeQ5?5m7t zzxHT8`=dv@f`Eww;%qwvHUmaYf)NB%iycXgh0K^>rCAs>1^!ezv$eJDwn%I11A#!m z!?G-RoO`=O9pfpA&Szk8|xb# z-NryoG!k+~qrtp3Ssoh-herurJ`hB&X(kBbjCBuLmceK6dvkI;h{a+ThB~PjQhppD zJa0#HbIZ<##-_O@lktqzM3N+NBwS3yV)iIST}=U3|NZZ8LJ&k)t!9j>8ok+Kwry5a z1-#1vL5w0Ai=eT!eWuaCpA{HKhzw1&K~W=l^RIbpa$#20#&{}@gM0Fkh-blUHlViV z(A=8+H4|u>g27;bDyvXw3LMMA#F5Ys(;sKk$e?K&@(c2|my{GC7z|w)K+>tyaX)h` zi@faYjSNjcbi_QJ9cf5_HGJL0?(t+E{?Z!a3AtHJD>Jec_k*bfX}~arNwnQC>U~vK~h$7-;Qk_f4=^dLzYSm0a%w7bVLwc%DyZ zWqQ5}1;R+Dg$n~n^aKJ(lmr;Fvo`V>84)Qh@Qi^)|AYWdsTPKjpdbw~9S5P)P-K}p znPxe=GK!`Vu)C6^$s$0I1RU7D7tLFBFeU+sNW#RK4Ct>Ul1U7!DF3{y$m>s~(=ag9 zg#o0sw)Uj5k;QC^*{qh2J7e)1`wK`o9L3C;GYeO9F(By>#t&6taf(n>8loiSpUB1a`4J)jXasDT_LXhXR)hlK zv$hoZg+=`X#ACOg=onz#uUcX7vx8BGSxu=b=j^mcZG$Qj*($ijv3@M2T!&1mC)zQ_NaBttXqpZIh z=%|7Si<1XGcJfC)3lD*?U$}b6v}w~%CLB2fN=wV$IdGunsc1BsX*QeB{bmd_e7^4K zrVcC22_uYfp}2~L&1r?JYvwDfH?O;qqf`(iaTdmpf-k2PSFgQg#j;hS(}=~O|4c*k zco{?_2b~@DQ+xb9oYU#-mv%%AG)fcJm6Lz}eq$Ok`qYE+!cY4L$QN6`IOXr{c3X;f z*k9}E@&CwbwVrcpjM>1Uqt!RMZeeV6&h+A4;dnbLO&PH1R+MGm_Fh}_S8r}_{@}(e zzUZXl*ooSfO!vUS7IzhR?)kaj0K{E36iif+3p-ezMMG2Lwf*lHAt5Jp44-!BWt*i9 zLPQ7Mr-p}q0+L@)bjom+&)~6evH8DRTmJJ$q9~s8B1(#+kr0A7ShwSznd3&^9Wbb% z(;ToH01I3_@}6&XskOyHU)wmd!3CD#PB4)KbX`R}8G+G6>yr%EUDr0RAok%LV0I-? z?4bZq=<4e9?%i8`o1N$Tp&h-&xLjB6-m7j}_%6#tVL|`v>wV+0ii*G4zhpQM4KFWy zZR6H$x8~>Oo|Bg7(7`)-?EZB3T`gl;{^Tw9?u8M+2mrN!fnoJo!h`N(CO;_B#bP_bw@g|Ww!A6Bn^|EJ+_gvvd~`#d7? zcof%Nx9Ay`xdMRz(ARDthvO7L_r(eKw6uIe3|L)M_OIu5==v zUFRwDyf&)Bxj~gv=!pQX=J5TyFYnfi}X+Ix6YSf-d6UP2!?b^@o^?D1=>FLun4VjslsI9G={>p2A zfBN2g@A_d!T_;*P+EKtbV4>Yes1am4_=fhjnLo2z3qV%>0op&V!J)b#Fioh3Mm0i8 za_~BaL!=I3+tx$KD7Y35p7O4E{f!kSlL<6U_e(pX(Fm@+_UeD5C<^DgOWmmgpuQ!B zQSr3Y2+wnvbLCaP`0A_OwpH}3|(g6 zZ^%GOkinDzCX)&6ogH&O_~4_}q9hvn0|wCBP!0e$EL-+aZf+h1TKWWtBNZ(m_LEN$^G%!B8k`$Mzk6t~q#c3BxeRaAfog43Z?_@9|^$ z^l6U`9a{NSJRa}Y`S?>rd3|!~{_vTTK2=kZl0oPk9o67AQvv!$h_{R5<-XY1KbASuJ?sKlx_HvI7Y zmH+rdZhl_B*Ww+aWm2is(S<=A#|aEgw^B5vXqv8Tn&uD$AzMfb&~zOv%Yb2+0lBsy z2nfaE_{l@}PZ~LN=+=Q)6>=&liSxOShoZ=M?01jO)hqtiswV&Sgz1xg51;i7_ZCG&5Qe1rD0Re#aj=G}X{qE^Kk_3y* zX1R1;DM6Cx>hfVoS;@vne)jMTk|d95ff)#!MV^%z8*s_X&21VtcJz!$G^QmIiHo)u zRo{3u62VXiHkWh%HH#O|KI*(la^S{=_90(q-x4$p*tf4{&ePBQ=@W{g;B@j()xm1M zC`1xHaOg_Q12-)nlR0}v=t5ojf@layvY=@eqefM&z5mBQm`5`t5{cxX-0GVoNyHP~ zP}S_#TW|c=v6;En&;`Bzh5o|BhY$bcmTxbZ8jFcaDw!H|ua5`>g2>NvAG-ba`$ltI zNf3Gx|6c z&G+1KX9Z_4)P+Lf3qAn^K|oOzL?ba|y4@>oShi%2-DX2P9tTNY9RGIF3^)ND>9h!v zVnQ=#OfRpf7_uP{2=uPxy#T-*ebHDdjahSMJXJMv#Lekc8j>Vk)L`SHd(>ni0RzYC z_uPHgtjfyD*Lr&VhhKwDoL4Xep?3q$;^N|eo;Y^G{Qv=3kq0IN?}uFUovlfdL^7F# zrfHZtW5#U-`FRZ=eZ2Njv)Kfb$u!_p3q?_gL?R$b5=)j`wtyZ1z+aVUy&cAA5Rb?4O$&s2lRXvjL;^WEIr|qbSeTcU z#cUMB7*us|`HM>s5F9PdrqgNU=jUyhK7DE~Z|CkkwNgyQ%5JeGXCB-jI zn>uy4#bOSm(;}b~xD;OGP2v)gw2+1@$)P3JFR8j>=B(%9@dVQ8UdEUt2}GiC5E?LR z#>BhFjvanyBGH?9UrIt>N;i9i?hr*0bFZ9p7iZ))u3!JzE3w1s&XW2V_{`Be2WLge~LI9y(a$sCE zKr~J6-#a)60?>h2EC!d$Sv$OPn2R--G|p&{6W!eaYe2vD-2C4Lh^jJ>WwGD12to8N zNrsNJrs+@>c~HMA{d@pIicv59cYRi1wp6}soyJ`zBll8ejjM(>jVf44CHh3^6+!8 zd*{UG?dwu-BuxVVFagw+6byq34|+h|tbdGFZ=|kPOnoD65MTH9j`oh+c{AllelkV5 z)?&TBq*C9YHf{C4L2xDz8iOssI4P`#%Q}Nz z+cjh1Uw7HQIWFVSdsTe%Qs_+Cc`F3+-rvYSu;|gy#ko74R*VH10+;CR!W0xbnm=?? zQc4u%4}Lm12q4fc?mn0oPj+d$f%cw^H_F`ZzQ21Z?^E)ya_rfSjPB%3Itt})kK>ID zW^fIra)|V^&0u8)i@1SD%{2kv+zHSk^Fk4@XkIQM_pkvnD5)XAfuHk{4kyMEgpr$6SsV$%Xp@ z-3Wk-9cPP45Ce#V;r7u9hyw(gVHt2LK|it4bbiAAsTTEYOmmHw(=!~L+ALK@K5sKK zMKgbMRn-eond)jR`q0&7u4`1;`yD@x$o^f8dfc9;pR|!*gnP&l=Ru*(2ALsTeF?cBCKZ|CaPFqdkD;>6QRYIuw5!s%o{q8r81P zOSFb>qM3Bq)Kvzz5U=DCoz zq9N2?MQT+{2|U&s+;iCa43Do8qh^fALU_ITxVWviQcwkSY;w->!Ju7nv{Q>JFQobxHLg*gr!^>b2|lt0m57 znI@xwqlR2Bx&rnx!yJjOrK}$%Q6pmFhFrO`lSi$_%78B33XXJ$x%O8MUt&3lW7NScev7Of%dafPl|FVl>m1VwBI; z)R?W*`$;}ns{ekW_&q&_JLX*$P()QyQ)BF7`d4iErQLnI?EvRyIVzPkRmp*)4clZp zPkV@t(A>nmz)ackzHi4{nxv0m@0TJR-H?a?TuFY|@cb*^f^U7WBXt9y%6ch%QPP4IyQ5@EGnR zGiydfj=Z*2a2%z=PJ0#kd}^jnNIpG}ib()JJH5{m(~>yN(ODh#DOPW=K39z-4a4~- zjF5!$l_MC)#mLuD)g?36HJ;{94d>?-7}{0c5Wd;<^1dSa{Oh)Me+X8X*{b7Tn;C2O zWqhkyBKWoyv`Khk(kfL7{}UdW6Zb~stKm$iNk^S|ZCD)nS&`EF)r(?wp-#%0Q)epG z92K9S1hBe%rl21l6PCUPj5Ak=f(6TO43@_<)>qg}Y%mXoMCCMUqt0$aVw{r2?(811v8`BfwN#dvBc@QS+9KK%}CNbhEt`!A?#Ril=uX@ z0G3sS!4v$9$e!Oa#TyJpKwhikF#Byi+J`0ufonZ>Drt3jR<^aC%Lkt1je24PJU%cm za3W^tdOF9BR6-W;%3_HZs2m0{-@v8i200Bzy*Fn|TU ze6(#ufIanf8jRDTz?`|YS+oV{UIEDl?uCkfCGTh3@YywvS$hxbWU^Nu92jMN!Hk(W zdbf0zAb>FcYNlB&z_((qS#3xP(<&BJqLEA@!2_R3E_u0 zq}cYv%8s5&N@Z9q_Q?VtrA6g2ImrZuVTD|rLLOSqtq36QhGcSb#fYRvo*r&pX0rw- zcZiI!Qlai^v>`nVdD)G(k6}}-2;nEFIN2{#&HTL25W_;X3^!iwT2@PNRhuzaRi>!Q zGfsNf!w(|`j~Kp_ngp4Hn?|HY?pq6W?p0$s!O4NEO6Ohf(<*Y3pH!ZF+Pm&tNO4~? zu{hWpa8+G!jP;vqGs*pdtp7u`9JN8bObx_N})X5^$b$ zEC+IZJP_tZAU|8-$ZPt68u%fbNhr z;WG2}4@}p_)%GsMZ-p=_jG>d@VlgDvk=XEkaJ_hhjC%TM>s){9ypaQkpo-%~=cGBl zjYl4+_Y? z>F$S%6n1no5fudSF_1LgoN4jo7Uz~)cCLq3i=!><`*A{)S#mz>F$Y(7zlq+s98ONX zoYgptt4dvst-~zLYY|BJ_58yRp$gUo^wdZRwsOIFCA4~a!KwIobo`h~f2CxhUq8Uw z^@4eIhHb9WK|Xvzgy+&D$V7EOh#m!aw<249pN z8WJqy)y2h8>6jWYOXkvkMZ-SJSKFVCZ&hisZgX-Tem~=MyohYH9YSRYgacE(p3l2V z934KQ<6`+~x#eR*8^uIL-wPH-Nc?zgM(g?e^QXFeYYKfv7L%SASl`TQ<=T#O>nW!0 zfJF!q6KxyxRcf!O4e=3RkFAKV$VMY5Kni=wM)Rz^&z(MXLkV+mu+Y>2xY3!HQ!N=l zw~?e$&0git<^WABy@A4!#UgQSyJkpY+Ib7xesj&A(xFoja=)v45u4QVTv8tMNR~#M zrtTYw^Kmn_^r}}R%4uhi?Am>l|{u*RU68hCF^*F<*%NvZ8J^9Bv$Y zEJLEn&)l;@bo?(>yB;ok6UzT~zoOwR7qCsHRZqvx`Xn2${W;u`pbN{IVddc!(QUY0 z=YHo=&p55k2KQBu()r)n%q)x*>WgA~kC)giEO-LNT{5IfZ;FH7DUh3%M@DimUfVVE zXws=tvire84wkk}Qbq?Hg+?1XwT zBJpO9=0wdrv@t$Q_$n1%b#woo$6?5Hm}q5qiF3vz4JSor={qJOf5j3@muMVN`jh|A zoi-$AzZy*57!me2#bu0aj7-NG%kEHAG)(Bg+op-B=QW|V(Qlkt`BG`#k$?OtPgQ|5 z{9Rqwot^Wdfg)xtF|!c6TYfcv`@6?i&u>3d%7K8bi=O|IRCL0e!aQqNLg$oRyVm;% z9Xy3`v1=qNRtyje0C~)E5avDY!ebC z^KDxAg~W_Hgp1o8UsvOzQ>+)X^{xekOKgMwcNQ^UF*N_i*7~J_6U*8&g<|4<5=C)9 z-^P@HEf+xs^(wW11+gpXfVpSA_MiE|4`g-PnQlErY@>fT5=y8Ev1^KD1Gi6E@dkLt zKa=;1Yvh%S?{+ri*#wn;Khp{?`iUhD`?AV1t(q@BG;X9_-b~F*5P|5k#LzE_ z`69-BF*iGY5l2@g+OREVTMz0Kqv;L|oPW?9UWh_Nf2NdKtque`b8~ZVZxR3MbyR@+ zoyMX0tX=y^&=F?sfR3U)0>d(Zd&`*ST|jEY!k1p0AT=d4jF$o_YZT>h7>2sAJ+n$? zwfN1Y+J9ml-dw}C)^n+HMk2#>e@7Vb%9 z8*Q;8mAm-aVsk%j9MbO4ib&3s^rMr}R+okc^{l`?3H22Zm&D0_G0gnrpvtkOhzm!D zI`QFebH#l5u^<`0XX_>WHEB+i>q4w!Ov3kt98Q7bsA{_u_^QgSdqR=GiZeP=LMNRS zJnJ6(y8r0a{<4j4DLmx#@bJ)5JEGLQwnsJfx|2K04xDtm_7}g%?n%9k&5;RniWr6g z2qV7uAsq=pJ(Ax_%x1I$xva?Udh(CKyPeLmmAnlc89clRtm>PKjKQuOCp}lt{>ncC z9|mbr1ya#J5$Eim%x^7&CgcQ=gWSk#Zy~89mnN;%=tf+L9T$g!65Hy}r$^FPX`XcK zl>Hp{mJyRrg9bLCmnpXoD}7v99p)}(`R;I^YV*PSFiv-31>$&NZDp`=1{ZGOqz|12 zDI84$`%7x3k*NiSK8BLNv)2r2X7Cu%+JuPo3Hb$5C9U)>uRL;a&Wf3dro))O&ax(N zyxr)>lF6gFOCMjh0hYqK_k08Ao^j9qZrVy>)B`?{0k)!(U7Uq*<5G?j)(0xV(;rm;8&<7oN7ZAIkGRyhKJxNny^pUhF;demmQb@w>zG0O)F zw)mNaQ5ch&#DuOVB6~Lj*;BTfuCk8lg~|S4SnOQLMXMeooe^@>>W(c&+kAWihh^!bj&eUrROjaHg|xlfS*HE)BTW2 z)uXY32}5K>(qrA>(NQl!%e7fsKq?8A68S6j^oE88=Ng@&*Fg!fXZ+75cd*)phLbtH zg?$l(tA6Fcuc49g&;t!8R~?T^r)wqC<4f<13YCSdn@seSX;)-9(#OxzN?|ar`QB znh#CA#cfphJ)++zNwkQHD)9{(!>Knn$X>LYJN)KI{?8jkT+dJIhJIf>JP2+m_$F98 z+RRguh481d;LFh#tV!9({lG+g!I55}p`0M_p1H~;K_k6G5oip7_^Z#@+K!T(otXO_ z9y&Fin_DV`*ln*dQFXhx%s)`&-o1s%quCXA>1Kiwb8rv%gC}>oCfZUMj2iYkhx2Jy z54d)A0EUE;E6v)S11l9p`cKs8ip~tA`i$}^kqvf78N^{8Fg0Q<<-P%d84wlT!E-h@ z)`WUSxudXwxzLGcEH_DtpL)xL{7Rhmf9c7`3UmNwo#x^dS1d6-n>ph`?{CJ|Y4Pr? zx7U!8Fa@Z|Q6-5fro@D2$rLug!IJ{>hs{yjBIC^xrR-CPSvHn!GI+oG6?i)IM}oa! zX2^|n{Z-hizR!UvO9Wmwv52SV8)9C;Z-(4+(D#s)`$dhf7tzoV0NtxoZ>#y9^YHX$ z439hWF?n2)Dz|)Srs55y$S(ey3*Rc=)xEWnOvUiytYo5$-Hsx!eW8V2*?4q;E8fXh z+kEPOUchA90$dYROwgrmLf6aqpU$>$lI5;>HAcLr^TH=hEvm}rV0O&t6FXf$Jup7$ zTuTnN*Nu-O%XfaZk294tx|A`5xV>pYTaa>TDjU0+H78OXSYvN*ZLu&oQciD zq0ZkuRBqzUU3m_C;5PK@H{3U3IM${XvBdtL?Y!~IXJ>EEEcUk+EaG?j)YTSt+1on7 zf$Zw<^Xm`a#M|*GT?6s9Y+6exjV`1OZLH;d>#aRQQ{$oQr4C7g1Ir3`(*qphai{NQ z(1fmVcTG#*z+}|^@FzDkZ~02n5o)`UmSe~lhoo@5xJZs$xqp=vyb-5S^?Sg0AEKzy zjpK@TcJqxgceL8O{yIRvv=sn%Ce=YI6X(_*XH{T7Zbm&5r@-dsIxM$2Jsi@PR9!t8{OO0ye~hLw9&JzhI_8w`8|ZtZ7oSfbR}j}KU^ET?9}`g4%abV zjLsa0=lE^T9!JFZiw)zgwIS#(5&K;ECI|#N)az+GkK(>aQdJN2s%v>rcbFh{;9sc{ z{OhSOBbcG5O^SsVFRuPuS`PCPK!lo_;MJ4Mr)p!qC;sf47vFfUNH@!Mi#AvBnM$^| z=3YWc6ecV06*IpDG7Qc8Pz<(H<5ElSXrrdAD4AHFFY|3~W|PUL{YcG4VXIHY)Je+@ zztw$UO-a}-KgEO$JPPNs^Yw$k`wAq#k~i;8%6lU-VJ3q?%>tQrfLNmIHbK9pd5l-!prPyL>iR=Cbb38m;Z9ofc^? zp1z9gN~_2NO5qZJ$wnZMu$NnEO8O&PzQB}no@1_Qa{~s7$0V`tQ}F)&zT6tug*#h( z9&2!Vv;pCo?E0e7))vUDZ(eifv2ZBF6u@$IBvEM~J7itJw$o&Aa%L$JM=|Z2xV~sz z)nF1@pvj8|l34Wk7v|9ktVP4HPByPVzdK+4NzQ58r&xnGbiK`7P7-~LuP z@zQe(zV2ER%*`jouJ>krFg*=H(&|+w= zZSSE1zhd}XmQH%v;MIcA#`Ar^-W|P5{qw-vt`gk-DJ<-dnCEN^p*c})Se@V68i(xc zc&3F%2hO{Ry6J}ZE{J+=W&`OZ@9}5dFE&}f^M03MigRM)@6|Zi6G5J2rpTe`0yp;f_A=`NDIAwEv&H)(G0 zDtWf9cT?%`hY9r7W_AzajW)1sfcQpy_HQ-PEa;MKb-T3s{(+pYnA4T$V=e#3BLAI` z^4zUDMskDt+a%Ieyy8&)y?LqWx2-mB<*D$Q;f+K9!GYKNUhQ{MB@ydQHYlOA;pHF) z^QT-1YmM~Q+}<7Tt6S*tiR-2m)W*(XkHVGo8%w3-s%t}p2dc7n`_V28?&qL+STJtC zs0*Nb9w4C|HQ#g+5yr!vd4Clltuy|?kQAq{nutC!e6 ziE)Y1Suxf0qFU`S1;R&TMcN3eo7!7p#2LtMO&vjyxiafW@Rx4*&KAdvKR@Ye-9YGf z*@qx{)Ix|mh*iWtTp-x|3D5hrK*?`?->xf-96Y87(fDGVxHE859th7JuQW`GViRlx zn0gx1c)vvy9Fr^ENu~-Ugu8eIA|I%~aYrWWyH{dI>&@-|%M)@D_Hvl_)|^aCEs+hL z@v)kdX$##w?f^arUxLizoeGXF7fKFPD}<;n-^U#8D!f?fFJ2AK6HAm zbt`>=pa?(@U`U3?d;ctG#`UEW;MnFGY*$_jeXOBng06i^rA!{TiJsbREDpNNyK3$1 z(rpraqf9O?A2X^*rhHrsx91VeX+C8t_?WwS7+!m}H=yYu#}qpsn3l+@{kUnrzuxO? zJ1h_g-XKuwW&ES^vZE+&VkMw-Cv_)mQ-kw3YPRdK>E%|+Vc_Q`w)wZ-5Bh~{;DoO$ zB=U&~0d|L|{H|FrY?KZNrWp1q+_JaGcIrn;Umbb}kEeja;D<L66`AuMJ`3R?iaj-LHSL2pz?<52`2`Nv+`V7!P!_G9|RqjeB#j zY9ny!*+zJ$2)&Y_a`+uk^I#EiGgBK;Gu=^S7~{X zdDpjwszVHcM_pc4Ut8eTOUw716)l<{I~?d;n5qcCkapgK_7}SbBf7|0;_ zJ>BTlZ=5?WpiXGUJ@eruB3~VHznKrg=S1RnNe>nU&q%xj@j#={JPufSb`siQOPDS(k&44*ZUx z?@pI$><;@#lcdYP?Jh_C(UWy*z^!us2r?6ByiE>)mu)3I{n7s=c;K+GTf^VhzLLdu zYWA%4B_|GWj95POU|#THnCs++(vF_Hq0}hpNW&W{!Lnza*6bz=qd% z>C7uIZw&%Lu1^MR(3rGRH70s`1NYIj40yxlTrUyQ;QvpxMOeaxuIA8U5l+YconGe7 z6YW-*J>uHV=l0yq1^osmmiT!7IG0tko&V7KHrM%x%#UcpG89Kis@}gKbC0@8MM>Cb z7MbT1*n4J_MAmqlZsRty?@et2NMx2%3+3M2Qo>~3VpXCH(Ics5F=Oc0AuM)(ZxFU* zZt5|_QrKit91u+X_NT@#(DjEoUZo46b=q&Z<=sbqN#j}^ze4VG#)8TQ+t*K#Nx!w! zpi$p>{Fz;BfsBXbs%l-YyEcM;rT-^m#W2X;iIq$0);1k}5cU$DwOO}i@M7it9`LeGK4DK&0fmUI5c zHeLIN`{U!i99i}1oPv++->$;%b=97U{NX!0%sBccxQYoRRjl<9qu!3F+<1DS!2d{$ z_PM9s$<(1bf?ERc9%o+aHa9JWcfH(UpUylYw=cCC?&T8 zqnw`9o)&Q=pik>CQUewN7=DmXiN)F7~NP_j?)e6g29qNK59;rN(gP8W}UZ( z;ok9}EQQjKr}ptXlYx54AAmP<&(P%Yp23mwANZp0vCIhFA14*Z zg^owB2(5Ua6QZnG{89$L9@iHyHn$R0MkaD(kTT?Jzq}b2@A=-i1YiBzDSkW!7lGl= zhW|Aq268zpe>JlfZXT+q>w&}#Yk}eRp0ioaWqGLN<#ug*L8`8554xZ)M-}=-WcPlx zf58*uz1lw1Maz(i*4u`nl(HtDK`z{K)Ed70eSe;IJp88p8~htewvvXRo)USI-UkKvZ1Cna=SM5u6{_1&#CV_zbL#0fNpNH>1_anHY0KYDc3$H=pD9gO(KyQ|czh zugF$$mA?z{ZdAv6`(eS~Si{C$lJl~&Rw+LU2AnVbafvuvM^wqdaey64QFZ>(L|r~~ z{P_g+WzP;&O$Z+z(oKS?5+?%UdTb8P7oUFOHi6?MCxa)&*tqJA{if}DjY<>A*mcwn z4!%z$RW#NbyZ7RkcDO!qB*3j)y&nb9Fa+8aTD4&oD)IDrPM+z$sr+{aTv=Lto%DRO zHWqv);TiIC=Y7y}bx!@S#(E9LLyV4z~@&FWJY}Ei1YE87wUFcpRJhmEw-gq|Q>Lhb^dHy%zVll9HRIzmQV^9(`f` zM^Hug+D|wS9zIRk_`MdDDwRlsfR^9i{pg8s+9*c#AZ>6HYx1kjI{nK0Pl*m4x2e%A zvO$S4^At+-cAj!+ueGLy{jKJ<6LD60S}*lRPs3lxZ%FPx+Y3a2KrYr#IlZA?vI$P`O0IV+6o%FOG^&Fd6( z%9Cqd3TIyQ)nB*iTFZvOW)rl~@rkRigcge~e?@HZzl~qc2?n=Ezye(PnIMEdX!(Z!bq7@m|0^|#I zKdgn?58%HQ!#W?o9joH%vESJBK5BoBN_xBJJJ0VDrg&)@x7vOxz9mJ9k{xPnTN8E= ze*i-^I~zit_R@|6s)G3mO@Vt%WWaJu`ViQ^6Qk`gQ~(i3Lc|Z?`jG#~FF0Gaa<1}y zHtYT(%N=Xh{6+E3n#TH~*1XKJ>AZ1#NTW*V;v$h>+919VM>Ull59z8i6F-BTC-IQ7 ze^*h8?B$ZdaWsV2{%Ap%UIYBnsy8B6*_&Vf;crqslU{D)?k%FAe4UjVZ&} zeey$Z?~kgk@NCJ<+ktb3Hwpq=T&H3Kb*ns+SZs9zrXCOf#g&(@X60;J8=VTQ7nX0M zIg-TOmUN*LeQbi>3h~+B+H$yFY_`D9WY2JnQ|`aLoRu56cwa)Iz?ooPfz}Jmf1mOq zA{Af0q`Mu#GX6SdfTa06_F{d`J$b(r2rf4Vmm1go;GdAa48t4!EXDBTy=UMuC_t|G zujiqG-LaQtbNbSa;z&8#zJV30&0LbG@%=>Rwa~|kAH$3x>rGdVN>b>%^Q_cd4*j6{ zEFg5h(Ohi z+oRExMuwZU2b$!%FN}0><%$mBU&B~dY`d`N;wSlfLDYciQzhLEdA}T?%-ip96{d0J z5z(tPW=F1FQLa`CPY|5Eucrgwm00M&nA8feFnwDaG$*b)toFk->r4}A#LP_t$71LQws=lmxu~o|V zSgZC-$%FNy(@Aj>ymQ`2ExX;{;H6StnPJ{T68}>Ir;)Hv-ib5^_Yl(>o!+}UUD>;t zJKIAY*%K$(&sVo$>}k!I!?hN+W~83=BF4}v>xQto@;lG^KeAnZr^8?oml((*svxrr zj4#M+f{cShb##jl&?1Xg7Drp zE)H}ExtzwrOZxxS=sLKB;HZ=H$4IAy3*Ia$jzo2ctn#h06a7Kbe@exW-WYWY?!z3S z^Bv;ZoW`wS`a3aKaupX^-3)U@u<<~ zOlb%~!}+Pz2G0p`Iz5c+mX-_G3FY47xjU~uG4|Mxc7d1Nc#_&LqSHJ6VX`5A&B#}m z>FeKXb4gc|#tGR@6A!q$oq9smh$kK1J^D{Miw~Eo^^gJ{B~905+ShRzKZN;Bp^qPe z&h4#_l2m@B-Hw@X)IRW`@zK=GvGeWC#N(4$M{jb@!$?M`U6g`N3t3R~{P3oLiQdCu)p%`n8tyGQvuz z(X5nHrZHb4dG+|Jh*kXyuolG)3+dM>r}}b4>NuarUY0(z5bP>nwV~J+i&5?pVx@5= zcaG9^@#MMVtE~YC1{-2{_<#cc=2rRQ;a7J*|Bm(BCx*U$oaMtysfg^o`Zut!AKj?J zORKdGO#jBZ?q}3-3j3GACUd#atA{M#3o#%1XuFt9j=8U<=4K2bXAh0`x5;^Fuc)z? z8P)|pgr$AloAWTsE`u!h3+c)x?G%FumjiH|e@|K^UW>MDTRe86YSGW31s|6)Qp21L zmu4JvAGPs#KY0r|!4kZME(*MZ&frRCBSUG&a^203vxD94&GmVmUbFsI-r{s$Q8rJx z<_c?1$8*?&<34mq#eYy$T|1ehSk`6noh$HI)m3E3R+><%?SxwfSk3haJX>o#7Y}DRM!Mmw6t^>*yNdnR|D z4G`z>S@s*~N+;m&{CY{1G-P)s3zERI&e&9%BJiGS8Ek=txK-Z@8q9< z2lqR|nsP0>vRs@*o;-~abxzj$N}Bl{V=(C4u@t*bVUWVv1#N!C4)fjV=;v04tKPk1 zRL>=R3R?SXVaI|p0&c#DHARR)iS}3H=&wlB#EWuvmALB-L>SEtIGfJU~5fJWR8#?2<-8gg2D>D z0^8)g@>H4j1ix{!X}-WHOjca5|7wkq0ELgFf>((Y`wS6iir2J76^WNk z4$UZ{1=w>#2B2t2>5ciS7;o&?)yXkCNd&;Fvv|8hb|`3 z@A2hTxD;9)g)5u+T#)!Vw?b+4x@AY9vJwftps;)(ak4Dg;F>pYr%kf&k%b#i1TTg* zo4X^zIAMgFC~j}_ImNaY?k-lA6-tTldm1Yf(_rrPoPt(x1XWWK6k|=L4(&G{Z-YAC zkiW}kQ$F?FI9a~xNWSxa2j-&0@PxBB=#Aw!la9-a+g;)<-w|sQd!W^W3yf-K&`F;-91cGhe# z6^XJ>Z6;?`ki>Y52{>yX)okq(;W|*-_{owzXS@bldBN=Byvy^ZahYD1w`T%%v4|h1 z%VM*h?;2ORWWTKm-~)W`gYEFOiAC^D{}F1hFV3FYzkGMuAvE6|^h{m)sJ!c|f}jZ} z^ptK1ZW4-Or3^;!oiK<4!HhT7CK6Y~NIY5t-8}B%oem#5d;mwzxHG4A2G1u&fve|> z#t}0SPvs%3YKC(;#=Qw(&;Esv!qw)?XFXFR5-30tz~mKU(yPylZ6zLViR#hNSxcRT zDV^^rOZmqwt3pID02suOyf3^_gz6G{eOlHlNa;X_ixFMoDVr|DnA)qR?l$yZ!+cq0 zC!2BR)kCI)a>@ZUu_J=6lEn30I^AL5SU(CV)u{ijJy z=IsBLqTI+E)Q$+~5iwS!p?Bcq!?dvG)BC9h&X6jxnXy^^7xH9E7qErbT@7=G0kZ=e zEpo@ikDw^)TnE1H@KrOg@R3g@@@3+scJuo>S^^!isrbCE0J^q7+e4;|*QLVRXWjqx z2e0?i+SNIGkIna4vy>b_)K%_VpHhW{ezPhEw#zX53dRUwvc?rcR2LK-${i=&mavz; z*>LFzB=93b5Y}%Hq&h{D?@A~hq(h{JcKs}t5%AZ3@9Or60Q%$(`@h+K70JYfHxl9V z1!)$e9p?WOvxvM79&GPW!ND)x8I5=a54l*5JAPzK_sxo`f-UTY-*k>Plc@h$JUoP! zuPK`0&iVf$kJ6^Vz3p06}s)#!h{XN}yuCnRV?W&6{Z zG1(oeN}g!%h5g{kKXgAfcw_<#SraV(%NXV|a`2f^RlmL``F6&!1MIV~&g7!!%cP7& zhBHH#0VFt)k*NGH3Rj|3;$@JVZShE=cIU)kR@$T{lNhkGoqo?jUxUwVu1_j6MSZan z*FQbu4RLb&v|L2-t3)Dk%{Cr|pNx;!Ffha(;>3G*@Q#fm75SpWx0iC>l;~cM2HJcT zSwYnE7qM=?z@5^A+6Xr6$J%kAwok2Id8V`0Iuia__@P$g@`3d>N%`uHy8rtyw~I#n z(r3(jA3JJcP}wHp!LBz6&Et+IpqNd8G(Z9+D?z-)&pmxLC5rOto>fx~)X~VM9q}uC%bl zw}%bRN1Wv(k>c9Z2g^d{>sg4+IIG@LwviZf$I0 zbA2vZ;=lx$EQl$z5_QhSBRO-_R|SjQK#!%r`&6jcIU8^H1sCbFFFm$;s`dc_JI+TyU*ZB0XwEG@!omLl^ zm{;2s8^$`iRk0r!CM4KsTK-CqddoOr!wr}578(#aq9(!OA+ zq1-aJ&Xl6kdsgKOx<66TVoCoo)+7}+NHVHl84Hn7pIJC)Tk*(?YrkE%Y!UzT z4dg?1xNPO>DG)tZ-hEGlBCFPhU;J!m*$k-mq4owFef8$c;cB$ErB0C7u|15Bp$hTi4B;8nL)U+W`<|gW2ersMT5sXFrr$3SXcr2# zK$V_9xmM|*sDD}&?TZR@%Iz|nfXU~#aCe6VX=^&ag536c;zfb#D)3>j;%7_n#_a4Y z=Vrzm>PQ(BS|F;aS)2L#L*^U&_Zh5`QUq~NJK(ObbuG5!w#fBY=bfnTDBjJjEa=AQ zlQ+)R7OHADcwUBk(`v=!A9OLT`Uut)<2qlk8P)Sk*C%ZFeY$&0%%eXgv+tnIxgwZ5}^LfBjL9z+eA z5^=eARD;t||3VZC9tv^1l!0$@-N}s8vR4t~o9xWDlPbNlq@0+2!Qnsow$+DEoPmH$ zXZFwHpVuf6SK*iwyYs^rWhE(MdsUj2f(|b@nf=VHq-bm$Isl;i7D&J-6Sm+AMpY@z z=0xhXM>^hDs4ZDxM+mFsS!yANc}825pH>-Ivt|fSineEqJtTVg&>fm~ogH_oJR;~u zE+g0kL17vYPZP{iy~P!Z+8C!#?nD}I8gEzLg6~7~)SKAQwVq?sSh-;9K;!5+ zi*t_xmktB&I&r2frxlPZ-PrmD8V?W3cgf{{|FLQ=+A@6TV2>oMJfP)N{Ukv+ptpnJ zU|4%#WclRsE~%~^k9pG4>f=sGpKKDHkS;S(T*YFzfR@*x!WF*Ou5RaKfSulnS9=)>!gB|+jWzzc!N`lOq+{kuCn3MwKku=NhN*Fxl}aM{azhZg z%p}U4C*5cIRpm#L@2>*MruG|ZNl~(FT{*Cko~qfxLvZ&(fQGF7g879S$!u^Ta#uw+cVvRvnpBC7~h}Qq+!BBwaN86(* zR>vIqKG<~AK@w})_}0Ql;I9-bkDpoT8y#CX=Q$Q0Bm^I+F0uK)8rh);*6HaGv42&O znPG7p^7(A)6@o~DM&;BU(VIoXLJVRH6!(7>7z}SjVPCqezcjqE19?vu!GJ*&rw8dc?lMmf-octZH`FsxeUKxRmO1crfs zt`;Bl!d?k6l*Kf8BQzdYl|Icg8(w$`I$D5cQJ_Pruq{_t#T;=WSwBr3zqdQ@HwyF8 zoK}fLZCl$s&5bU0I!c3t34sQ^E%{t(bW5PcI2Wf=(>2=p)wQeF(j?~`VMTS&vr%(X%lCqk=Y35a8s323Z5|(Y?c-W`Q9o;_==g62k|g;V z9KRAUJ>E74v@@hHEAfdY(lD7N@#)l=>GGUw{nRdAO?;^(ym1*e^#ecB2UGLCH@Gy zGwmb%n+MQNwe-8EXo1y`3N_EOqr4wuz4c0U#UM_Al@{9{pgx^(CZt z%(<$H!gjOGy`>YL#q81bcQ)%}#P7ykjQ63go;mZW-Z)Yr{t5#I#3~kp-*c_mZHGh> zB%I3=n7NcH^Dl$#Hpq+_^6>Arx2p{wpmSW@8Cd^g0fuxlsRC<$9z=wRnjk}&Sg4+> zQXMifeZ1B?J4{m-Oi_T+&)r{XhscnhNn{6W%JubqP4J0Tz8x#n4er5#NFwWbs^_?l z!)p&0Zi^nTNRfC-*+D-{B7oq>d76g@l>&C7EOybGv^EE4r_(Z|S4uqFjH@5*#ymiI z#IHAp6@6x*yQ}%J!R|358-G?W_d%22FWnK8hiRB_mFL8K>Dt#nEzWN82@d zed8v%{H0(RfRj2RC7wwfO86ZIoNQ?(F=PC|$7&P{zpq>d*-5c5#cyrp$&Hl{UZ%ebCE)j}3bzT9o*uTyXUr+Kc z(^Oa2{g7g}tu4-sL((uZbk%bdzQASbql9aOe+r}h_Po?c@$_C`bPI`8ywnI56x#h7 zwXyhh$pWa0h+WrA^Y;^AynhySn>ZAs00CvG3DAyjpV)J3JdX-FNt30$@#*K6{das5 z3ZZ({UB;wk@h&EPX<4D>g?!<=8dsR@_Q5{R-db9V)1i0A#?v_t0sePMFAQ`31V~FV zkT9(Th4RKf$b9eH{JB`HRIUE7jrq$U=a#!`uG=|@%z}a-4Fd#$|H=D2jVEC-p5;xA z*DaQpr_vK{lW)iNUqAbK;BDMm0OyG{43Eg`rtWw$TLR=r2QY*Y$~~RqF*@pWpu3Qw zmXdxuyIZAi^Nm~T3nlq~I~GA_Q6u^_sBH%@1VY0|OvVwyd!zV1=$MOhBccC_y7z}+ za!BpQaVQQrUAgp8pk^XoZ=--Dl>GJN8^nR6VRivm5?0lCmW3!XpdQjpDk?`TV{i!egMvxj@VN@y>{Gs2ka$JGH`clepJTR0*?)nW;ZXeCe zZ?(XW!-UMYVfV**cIz4c3_r6FuL(2%i;?^e#iqBKtqeDYYb z<*mK!Lhnvv56@=Ihrfi=up#@j*LJVTc5?U#ZrpqSxev8&%lG_!sJTw>4SidMPH_4Y zlC7A~AP8J4^NyXfSl zi9CVuiB~e>!!wn7+Ol?%|AJYCcBZU#yYTVBs>O^RYjzo z;!k-{8Vbr$Bdxy>2g$0JAopo9T@ulcG4i9^o(538z`TdR(q%hnz?O*&h|`oOw*BT| zSon68aCApSLDa?J@H930@(%6wLmFTd2x1rYAI4ac}dZ{WQGM zA^D-x1)tK!UERsYPX$cDk}WW$rcfC`wA@8QJeJk<*ayI4y3BbmH|FgT2YPc-tP)3a z!dNJQ8#u~@uUm1$*yDbcDsrR1>||{0UIxzv+2SQlRpti!>u7{x54!zT4a;uM6G@AD zQ4myRc>6xZEfK(vPM4V+f8mMMVXd}&>_h7L>u$#3Cy*gfHYcsAz$J%W^U{r3R8{Mk z-l@}K0`rc2n`cm81meNH=!o#Oep3B&bx)msPct)fgkwc8Do2 z4fuFuv1j*rW@_WDsx#Uq%(GUx5<5RNsBg0BDXL@gm zDZ4CR2cwf`=!f>o6NZ9_n8w}p=~f3u&C_sh{%ZA%su2@pN!5VN;VZemFVz0aM@wP> zqmP_M{|!#&-B z@QX!R5|+F|+&xHx>eZ>C2Eh(S8$bOrFdP@6NkF4sDiRy=mY+pDiDfA^Z{8 z2A5FF4>Gwprm**-K|ScW9por^%OS6Dhf>&;)2l{wA@Ammj=dyUko!_zsII$#7XRD4 z^;R;^#PED9iQgs?$A5mGZ4JCn_DH0>+Fcr3Y*Zt6G8Q>+&J3Xfr_D#5a;gb)6z=!$ zqd1D?2~yL_j;-@T_q2%|6p}gjUz5K0i6Y0v@4Vv=60dX+U%5HVb25jKGdXSe!Yr%9 zfJp+{&OzSlafY*3np6QB;%QBGlX%;~HsJ?d6RRJ+&L&$=%pSj_cm&|`Yf&v#L;>a5 ze&5axwMG|h90W_k@K~p*=lCEHJz_lD7moCagAEiVY=xPWDWS8X@6$`E$#c41j!A1D zlY6F1h_w>GF#ow{d&d#RHIXGYKM|4;^O%FhCZvQb3M2B3UCXSi-P5oJ2^7A>s zPbS(c6nmtJ^MoHI6oNkM-r?xU|mPZMJNy=&zlxGur26NV62bq@YSJuWkLx{DBw`)uigQ z@eX_{HLT8JdxaMPr851-`O60lH2Y=hAoF=^;-Q;gXHD6r;$jYwDEVHuuQJo@0|cLy zYfMJqy)mU#&D^WWXqpta)zvt6n}Mv&`k(ByPwVNkP6a+fji`EqgYV`yFvk<^rr)z1 zKyu{oYCw5Cs2qF4&RlHW-h1U@QJdvi_<=)N@Z-tPpi}jVx6`vAZEb(_rOV}x!!?4? z%MkHOZqV+eZ} z&T7VSG}&~ieqiQ2A7;K{k}dyfFwr*>Si4;~37HL~H`Km|w22qB9$1-vH#5awyo*z? zd?kewEK*(}7agxGI}s$yx=$psY5yzN(8$OTy5;83&f@+iC#X`c2>b!Bobo?nR>;2B zzg1`RKl$HQPH9DD|FVlkWKA(%C8WcqmkT5o*8+>gs?}nL<44kbn_b1c6T?=T8W$;( zx})<-w3c!h{$Y`+L#$Q2HRNe){>(2|q(9uc8?3g5{5hPX(bqHK6D$EL;w?U7^`&Z~ zjj2r;LQHx6o0RDYystYZMu$lB*WXnyprs0p+&pD!2MRu8KIrMC1?tWh>G1iG4$rLD zqt-Q`jT*#ZBd=U3kBR>W@QZr981CcU?#U!a{csYP;0!R3RA^&GSmIfBwmHD&_A z0M*A)W;(%oqT)dN5#dDJ?Si01|IWVq4UhG;@IxS&jVf#Gbk9#J!OhuKrkQV5sO__Y z$I0Pb6_#7ifg(K0dMUHf*}QAR_LpcFJ@_gKXiA@e4n0`z&XMhr75^(v=3f|j?hpZI zMG|P==y)<>uKC0CaVH`ysudzCkP zc~OGe>UgUk-5#UXp)!1&VqN{F0DL2&+v^}_Qs2;Z{KuogN!kfyudjgkUl+Ks(ka#( zU~xOV5YY= zPQJ~Lq;+eZ=laNj9U}PcRx)?uQ!43Ml;$P<%CN-7o5_z9g&zd%9JCjK*jV2MMyUz@=`h#sq@wEy#a=p;Ev_4XaQRDJtU_DDTH$jGZ4n)RCF!f>~ zPXk>8$Jh2bUXSnf^VyA;P2)UheIH}_hVg#0G;;ok z9%F25Jb7QdH;+TMNyyw50O2?9;qB_AZyIJ_l&T{v78J5Yvd(;$QjBA(OgQpH?eJM{k2>~1C!F4Hlvz$It(y8|(71l!EVUR%9u1~xd2nOp~8lG-P69m9_M zrG5R3fCv~g-P_KR^4mi(c}*BMPLiMi6)KoxnQSiDRbosdu)E$c z!)t!evZeJc1mQ2@W%hS#x=dA&fkdH>Tgt|e1Iz)o#mfw{C$=!bmF;N=+zXIB3Yl4+ zJ|yK7^)LLo@9;yY?a%D#)%pq(Q&7L$`#n^kcBTPj%BX7TBTYqjew_(|i6dmG{szfL z0a%?3G#AQEaHT8Gl~;1fUY={*@yy_#K_Zb!OhIxbniU_Olg${Lxrwa2+B*rW#MUC$ z0y`1u)m*SY4GiP8%SyKy9t|7TYdQ@suHyQnPF_m%j22Z^WOk+gD(aOlfRaa$1Jw{4 zH;@@al_l!^`&AtevyP2VJW3Obz=}81p8-q)+!nCRrcgC z$S|*D@C|H!q`6ocTal_Ot#uJ&gOq$W?p~Jz*3jDBi3Z+%Uu4pcNKaTY)4sBwaC4vk>Q0##*F(&$R z#+2LAX8RQ_9UZqZL~mtY+2hQP1+A{G5>vaao-MU|?mo#>PLCHy20ydRsp*D>)A#=) z1DUTdo<44`1o}SO!p_Sq_GDi-vP+W|mLR=SxqXrB?P%MRiqrCMsq@HwBlC_6%aB`1 z=8-7_TxYdpy}6>gUf8?06{CQffJujZuCXgqmlVy>rDp&ttanccAvKNc=Xsx9>fo_( z8gc63tiKm2CQ?}5zk_PWOE862Kv4=5byif1#+!=`BcJb}`9$h}V%KCyz@qCw0awZL z6^V3#9y3CZO@S_Vz-wrB!h86Dl`Mk#-4M0A+AkYVPoW<4dSF7HXDn!{DF&noL`_ zSc!G2pN8BCiYe$@SK{s5Rtc_uFFBSP4S7jS@zOts;|nDfSugqhY)+E#Jy}gEkKq@5 zzI5|SzjkP@O26;sa*r{rQ8G)-B~HP3k79LB@mEPdsq4x5gE3!Q6<60kiub)U-9vKt zatXjjc6ApjHhsuD!*mB*O5USk?GC(4B}5kYO-*pj#vRT|QU$#}+*0^cQ*uxp7E> zlkkpfes&3m5IqQ~TQxix_LXCrchn17dxQC=V3sywWGvvBRDMuBb3i$KbLr~jH0tK; z+$^ddq}@=thBbs~Hmxo%U))HZ>M9h%W)Avc3$zZZ zujz?S=8-*Reg=8L$z+@`MyT*NI5#U_KfXc};48<$3c#a3lS2DYUg_U7IcC}4gE@MX z;Q7z z6#g%h+~40@)Wm~#o@vA2;hz$H(Wm!wtqU8ss*(CBg`?9~U2q?{)Cg|Rc}`4FO|SL~ zs}EqY;0Nu(`B4rJ-x=nYMSwN{L7)xN$XLRz8u4D<*)v`vgWtSdXx($jv#;NLrltPB zG+*ru8lI_CHWFp>#!W3iA)Lo3Ch6|J?8S$>!7WQ>PU}1pIj_p`;9XSbqbBYIv0g8I z;mIlk8&t=ba=3wEN8z|tAUp4C^z!*^aa8@6J=e91F%x!WLC9$|-XaGoaK_{M&IZyW z%u!xI`B`07bGm7jK(h7kfsb(Vui(tv!%-Jcc4vK-Wb7g4WRE!I^{tA_qENGR-GL#8 zI0xf@CJ^ZE2u=-dcXre9H&4sZAF^mw)vj6NTOYtdiivR1$$$TWfk_>U+b^e3p6sIj zm%o>DWSQYOjviTQ;-i;R?SAK5NzWygKT(+6ei-~uWEcBUR$53=J~`3>w5C0Gzr9BfP0v)v2OF}hlz>Ec z+6@yMq!+s3JQtYP5j60}e=V|5(hq`3WxmpRZK;-Ka3tik9Ymo@5T5JF*)SZa8SulI z#!&CEx{614;DC2cYX3^Mca|FY5tlx4krzGzl^ik?w#3i#nJmk-epJ_e@l&r3o7`zquJpPg>jSjr_>Hg95U9y^9%-)zj4^k~VN;(L zgK>u|u_70lt+qx8(`@{eh8W4NY6<9}J+&@^O!ru1{&)EeNa zbpK!|H!S<4a`v}4lY&N(XhC1Sp|mgRcPNR|2IcAGSCFb{VM@6}hxg{EffPhl$jka) z+57YJdLJj+pK$9yk)X)qVxCYGnA%Ui9?2KM9ic=ARfEROf2oJfI=3Sv5PF}`AY?Q_ zhx$SkHwP-xN-dck#1bif8Dd`2n`lHoNONPkyolRd2Y(yW1rHEGN;*Mp0T{0A|)F#RYi&di#!v_mW+KLT1diG-F+?M3FcifY6z=`W*{;!HVMRas*Mj9*#7 zfhg2taJ*SM2QEZKUSPI1ey-io9MUZq`21EX;+y2(BB6-6(+JQJvr&Wp`WJ`njSG-R%lmjR##z8NC-T&Csmf5=Q>KLA!rwgm7Hl4I0NekED?YrqyikQ6vpF1;y)9SZNsa zm$PJglVuB?5{JRz#XxM*j(a_pXH%p_bcS(nrBtckA(RmQml#`x*&^FR8;%SV4oM=rm^%Pw8T`p;Il zx-0jdIi)}xyxX09e*~k-wPC$yWpvH#l;V0co5w+@?)foe_vI)G({55sekIYz3gw?vB z>!kAcTSs-pdZAFy59xMIz-}}#rOfAzHwOr5x6=7qpf+}K>N{s3XpM$+SlFq?$ccl7 z0#f!moy6&Pm~IV26CugtgN&TMLLrb%=-hFo^EtZ)M5GY3hU2LeN5-jRtj|5rL4cw0 zY=3rYUi9ct7!j?ref~Q;dflaDaPay*29vRQgCL*Uth#+k~Y+H~G$RK;4%J<1I)5v8?+ z3UV}-I?mCg&_G9`fb=-u4aug>5@Gfq4O|>8E8$$shQ$QBcuFxm zu~ig#mGceeyK_D#3v%A zfilLt87Xrvx;I0pfP}*#-{~OqU^NXd_I^CpJkXcexMk~pfn61Ar8yW(JFNRKST_&X~VTdpql&{DmE$RmiKdud39K2-CYA z4b^?8_oIsv(n$er+=UBf(0{(7nmO#i+OM36$?|;rF4yVhm;2<1XYM0l#jJP`5=MXv zfuFd!e+DTQk5sx~Tcv=$YuSh(4It@?nA9B={2jq?`O9xl2LR(asShAb0(>ofI3-ic z7Nqbl&?;g>0wDf{PKTqhX6yHQtP(g$IM|BfmtLy}sWWS9?RudcJ$^)5PBjv!utu*G z_}?_My>PxYev!pYUOYESfzlD}$nj;mpI#h-V=7=e$a@zLtEE!HdO>$MFN$;l{kXTQf-nCWLn%NkhfR6)+;ODKi^?S zm^Vm@Ij{mQ&6eJ2k14p+A*oMgy!`#!PqdQRL)_ZXyCZk=coF=sh;vA=#^BZQQb=5; z;6a+*CAE@%_m!Le)VFEhWD2mpdUZzcF)g3zWSpKL8gPrZQkAsP$Ituz6^c?9&2mbI z?Z;#iaQIOJg0T#e_THp-M4Uz*hGpFmdR6ky{IIZ~(;=ygz3KTXRno`%B@f6D=5cfq z|M;^1tSlu&W73HRML9+cU4%EzhrYpPo%Rrvv6tOoHyRas^_}%UxJtD6rH!GEi6Kkg zI4m>JIq+$CRFex}m^e*zB@cYI}uTM%XG%O8UfW z$1DAbAPl{htMm)b1CVZO3f}7tz5Bf)YrB}gj3P}Wf~w8iTj_9^0FJ~nSNX7C4-+2%0E#kjKYT z0pbYldf&=&TSF0QHt9zr`f`KX1JCi5|2dw!3#1CWX?ss7hZ5jFT)KZ17BSqD|8dHv>-OC9L^ ze0e9&>ywvELQW(w?3orong}NvB&e%gV-u5vp+QVUD1%4}Im2H3TedgF+k*DVjE!;K z+ep2R$a+Rb>u6OmZknsmU=84VKFJ zccCoXX$P`@AcY8iCv)i{aBL2^!$@d=Vswmv`j*d)ywpKn5FL5{e?hjQ<2Yf$+4pS+ zd^*N|K*%MckCPe$T63_^EO{yXq=9X9gwIG8O$Wx`iCs&;mD{a+JIKvL4;6hS^!+Q92}ym}+6aCUc8b@WI^A**e8 zPEEx!A4Rhdtwt#hqh5QI7n2`6L~jjY4Mw%uCw&lfR!hBmxd>l&{BR4jt=s)~&P=Y# z3lb5a2;)H-{Tg25nGN^y!;xX#7bQ168JIewhWl=nQ)+OnBOlJX=hPm$4#QMWhBO{D-Gkf+GOLx6vXGNHO3+4rNqjDmPt6z zEZ>7&HAj|CgFfC@g%10pr<7%9H2=u-Ymp@p6jFZD1C#E+VFcbV7;G9JRrw4nObOao zLY8FZ+p5tf-qmFD6wuU?Gl8@P5Fi-{{fz}e^{6<)&9Yq53-Gk%mH#YA5++63lKwCS zw0YqA{gHPfwP;9O!2?dNw_(~A5T%(I)fpTtALX5djK67B3$lNwMj+-A2O^<5ey6Hf zktn)uxKTkU|7lCdOTuTFT+Je%CWvYaaUEwmEoZ;9z!EG~ewHp+_F&m=p3WPIuyA9+ zOF6g0%yI#e3Wa=Ou(0%)}S=-0ADeO~nrR1Ls$ezM4 ze#DbL9xilyp7WO~Ux0U!nsjhFEoz@{Yi+jyiS}NF8bYng%PuL}khGf{mC`e_ALu`S zH+w4|=u%yX8j$6LV+e7F^eOjvnf#o`Wtl-IhIerd%yZmuZ5V4bbNS1H;9Z1hDBz3x zHO58>DF1QET9D&3TE3YG)d@l#iJh1{g2-s|uL2656qBbaF|)!NT28WknVnP+<4H6t zJ)!#a@qER)#&{}VNBSDqOR0sA=vpN2ho}joBW=)vfAjeBHnp@^sG;O{OTLphn1%@G zLJHVb@QIroxJN4Ha&1#^wQQz4CL&2^+3R;+jOr`WTdz|85D%7kY1@Vf-mA-#y}J%o z09UYHaTezv#)(ZKqu5wQ@bP1t?66ihG_9&#*8IxD@C&Cie?MVpARsaHl~GG~6IxSO zfj@!Fb4t6NV|M=;3pWlc`6*pa(DlLE=L`zIzu!b{C57JOZh;{M)t3WR(eEsK1OC9x zI=qyd0?}IH_$lQCU}1)nd!u~Y(8qY8qfnHvH8osC&L!aeEE$csYYUEdws^#{Z|3}N zij&KWk^t5k0I%5P?6ZYEjXQ-~U1O*uz#!goMz_~5EDox-ms@#Qqv^X;hsSeTQA(%G zPN*&Hy>`;B7+N#O6#h;q1k;k-8W&p=K+5OR3)Pca>|LL%70{~>KAuHp+#0}mG{P5C z{bSYGku(iNm?G$IR)ExqOZ#toK}Z`@nRsY@gL{Fu7*dH~(`SXjFq`)qkEdz$NF@(C zG3#Wk`iVVd`}yq2cU3}2JnNK5Twp0p8Jq_(KjL2STV%O`CS(OerMmUplnb$>9kBV3iDj8+eQmwtVe^sZ9f`(myR0)M1jNn^ceF_Q&H{T$X!u*V zi%)*~pdN(EYZ2!$XXMsCCXDU>Ird}h7EdeZ#5Ze>GAi!cx0OnQjX}KwH1C6Dpp6i8 zLr))^-F_-?J-nD~l%xxmt24oEb_g|ngu=&1?Rwz{bp=l@1HEy-5*Zu6 z1;a-&vpx&Nem4W_h&`Ab4uPfzm?R9gOh^%Xo-S<{Ttyoz%(sCF;2*&w_Be@)^^tikd~NIjCT#T=$IQ*fkOD3*I$aradn>k z$B?OH8-GJOX6WnWt;gjA*6v=q9vEs0GJQv`gRqK=XJydWBOw|S^1N@T+-tk5uUk06 zg2fKX=ijm32re%Ajdz5~^Ole1OZrX(o>oQLkIa)io0^C}mXwvvR}Z-NL4lHdev@Xf!-)#g6vZP84$+Jt^JEe;Y@~4(VZr2LagPdGr9Y9+V-ne{iS6ifOD)Cj^cosv}ax>F8YzkuFc zC2ROm3u;PWaDaOv_$_06zrcGYsFNSB@-zg-aBbcK$_D-yQDdq=Ak(%HN-}vhE05)3 zWHKJzGvOH;U>|8JDkcU+bp3XTi!zWTQEue_zDDZidT*nhm3t+D_1#}=9_efcakC;` zUvAq+VrHaY{U_Q$ZM;ViqJ~&H*`r&dqZt43gJlmIzC1`W1|Qopxq%$Y(xgnzcp1j< zQW!pOz|O4YnWTF=*{G&KP&_eE%pFp);gopPi>H-=Vxvm(S2{+7$hBI-k{ zl!+`Q>%r}F{gd_1`__rP`>}!w=%1+qu@U$xevNeVrLdn92cCtF%%l)SB54w>hnBjf zz2}imzOF&qMRP(OViimQ&G50Hu7na%%=r|Y6h@L&ovbbQ+-VM`Oikur zN!Sf|B|0{(RlyQjBKwy!*<%25hUv|R($P|4YO~oyT9Dm`)qi4R`B~fNXRDhF&J)?E zzfV`0S>L0Bm4Rf=$t0QWM9fr4?6HfB2WN1!Njk@_f9;(zYYT5lOhX(fWcM#a-QYbI z;L0dP_5-ir`DOR-=a~%%1)Sf(yUX~Y8~*4Y%H24G`^`MQSZ^TSpO@&N|Ha*KlU1lF z6CmjVdtCAzKr8yp0!bM(5&xrqwzo8t@WNiHKUcSMNu^P6KA*{gP4X7_N5jaiG~z(> z0d9T&;ZfVpPcPGCMW8J&X=MjL5V`E!S*8V;Z68>M$7En8eZKmc-!|q3B(dOhww|or zbTa2EMNa}1ia-(^9u_{VTYVtp|L=A;HaGtFnQ76k4lY;~ivuu&bkl9OKb_q54-xLd z1Ni5Uj?pwABY}OKpv}JqhotLNbEz<$SWpaW`5}5-sy}_Nz0`qjh9-D7cEdhr`wz1L zlw5c!$vMQK)gZRI6Csd$R1tN% zKu6w*II9X7^f^pNl=I-Vz$u2z!cb?zoU7fwd-_;P7}oZ7eA_SI*4CR72{tWqXh z$3Z#jCoh3=JB5d{G_s_Vug%^}&fsHGr?qf$e`dXJ{asYcen|e_(UTqK5g4Z7yUg=s zJ6E!qm?Vzu)Fe}P*Npfa6=TQV6~;Dsfn}Ui1t){XIq1Yf;nQRf0 zQ2K#sUYy3+c|X3%t}KV$^3LKE*;&y2agyc^wKdKn-`LT0d-Cw{@i|zKKN)3ct8dq& zAkU{vKCBz@W$KPb)a9as;2n{li~pY{^tErV%Cm+ntlYt&-7?k4@r5ho%#*p_Tv)%> z)=Y)Y)~iFW|7)MD?mm~rOb@vMCT07df2xaZT*T3SI!6dktGu0EHV~1=*n88Cjt2Gg zdd(YMo}8cd!iOFnPP{oi;6}-yG>(hqAl`N3p~hUI4l}H)pkyT-$P|uD9MKx!Iolo1dpbjHg<#w!Wq@ zkeQn00t6WtZ7rTLg28oSEmDx5WvUr};|lLkff)}+yrYjotXHxR&2|w7&Ml;KgkY*L zayXwlxjFWf=zmM8exgoJZb6~OUA^2@5rsM)F1HIzL}UfV^brUT8y2`{sfTv{o{j{y z=XZU`%>eIcFZ%D!nk!lgis|gwtT>Orp4oi(wd?C{F#IRzz;?`n=#{I-VWNE%v6>PY`XlRr6m8he+T zmz>?im>9uui(2E{$l1!}sJp+*??XEZHwV7_^LEP%9i$04Ev3c*^iBO3$8|A-gZStu z0w$i)vDRMYo7UOYAVMRJZ`nz?N^;+=I#?M-M<6=o$2DJEL|{mPw=DaPsF(;n z2?x7!8^+3@9Hx<|=~^?KaU0=jl;Ytp!0GPbNJ?QRD(20v%&wYT$U0Y@c|R@GWnS?d znQ84`9~AQN<7(`i>IZsgDf&pkjOcC#C(UMfLH6HB9?kA6uI^0Wrvf!DNkU3&N{pXb zf7wKoIGH|#3NkwS?_@dWlnyH68API;)_uQ5Z&3?KwRZW2Z2M(GQ{mvOV@}#&k3PaH zyh9YcASa`i|4V4(Gg@7n>rX0|@HxD7eZ|o~i+cNjZ}d}a8>w6H6_L>$E9uxJJTa}T zY!YioF0}!qO!vt!CTTE(zxVk?1ukZoh7=WY+{Z%WWfQ}H6cmeVD2N2B^r83LsK z0qbONax&NOF}y__-njY&&Vj}8ZJy4we^;4&S~%}+FZ#cb)gKGO>SfKMv7nxd6JH~m zU|#;$p^RV;juA3>B(iiuyopBhG;R>Y8RH8P@t6p1aLLyX-tk92n`IiqFr6}r#((Z? z&GNsX+8gW6XU{g{Yxv_UQbIo_PX_qk@yWu5M_y*k%g8@rlD_T&$!N4NfqxFV(j?}MaVMPSun?BRImmf%Q=zt<3fdBefrcj2l|H2 z4F6Z@gF&iRjgC{Wom9f;=;$Y?^+{3T0}!>UrEWM$QCN=Cx+ z^R5o}-a-CSDuZVd2MkvdzPrE={hPvMc6at(f#7cPGK=~hh)$i$mmcdi0e9lv9>$C1 zHu&O2bY$} zeX=dlYM$@c*b7I|)SVB5HfB8@{@uLE8ON?le|i}iejnJm(tABHzVSeG*B8OBJ8{f& zHg+_8e0*w(ul4m%Eynf(SDjUD;L9K|jF`4tU!7qX8w)*7Kl$ zY!Biec@s!xC71Y0zj=Y>%Z!enp&v1|!`(t6)57uf#I9kFS%5DoE912c0`Bv|c2rF4 z&-IF%>P8?FY~((o`*HiYb^T$&?p#3gRkg@V3LDnsdbkLBuAbeFSp^t|d52CsY6ggdp5ZhyVeY{cXjP&#k|Ej6usW(#X@pxJ7a+y&`(%AWLdbUpM6i(+JpB_j?E#3=<6lVjV>SC z`)QrfGg>Rr0w1iBsgD&GAy1NC3TeLcc7%-Xcb~ps7;+ZCAl9)lpL?g?2U+G~{E!)O zv6ZEj9=u}tceedfALe+flGtbZ)!HIUGLau4?=zzcT#lRnJLSIGSr`cO}|&{Nd{ zA4arKYp=@pxEM|zLCa#pwDL3zakuby&#r54Ry?O{sdo;8V*Jj?U_3SS#TvAkZxLhN zXk|>4%#`i=-Fg`d_PPQD5524w0_#}kJ_`R^Y8iQs`P`c1mmWE)X@)Nc@sIY454Hu- ziWg#tjCOQ>*jB`mv22Y|t8Iw%Az4HsVP-jp$TyyWw6ul)?o%5KTu>ObE~vJ;t@eSIr^)u$pE#G+_77}CJxizJUJs{x z2T|trt5h2#{oY~ssAiXW!L*XhuoP?UqNn(UQ8`IOsD*uHumO=E{KCC_Zmkd3x=Hz~ zIypNQkX;Kvh2KYYV@~xT3k@UPdrIdRf0yw;v@jmSw4Gen|EkD)>%)q_0 zvFJ%w!cZYq}j5TT>kdq8(1J(yQ%%~W_{sw>9;hVidS+NkU)oU z;FKv~X}HYoaQ#~#Q~SYzgNw_?3nCWmi>`7_-8uQxADJ9hJxGAQI(>juzGZ*b%``&R ze{ZZ)mT6FX*EQ6qtg$0(EMLwU;HkhIKme=^=65XFjVMw}ob5 z1u0(Dd&hrumYfL4&(F^8c)7ejrCwO)y)o==^@JcoV4pFV|9Jrv6=yNQ9j41(##lN7 z-|nF%#O3+h!&w7;`pew7?e-m@@Q!gUNcZy;XE>jJo~2NYkL=vDyPcg<+PthON53~Z zDmORG_F+f!yr|eD58OCI!7-w-AgZ`_>@m;qg1P-m9t%ED)HrfGj6&AImdyN}{$x2XEOmu&y`I z^vk;YM&6rwHA+a;oGdsj=i*bAmrrTt=&2lwV1I7Q_9CKqi13q~2H@Au4ts`6PV*5b z$kV{cRGjJE)PdQ;tu2E)`QXvmkMfh0w%7LU7q*U$DwAVl>@Gx1qGWXnbugaiTZ9DK z$zuzEUydb9Z-O7TZbIK$|0kKXt=g2K@j2Z5)4a9~=5i_}7O80o4R6Cs=8P14Wd6;l zJnR9n0I0ZTM1mWMbE&QB>4NK_icmiyXGDQua@hG|;7s46k*<{pU}Fp{#59 z%!|y9@aUGPg8Y09)ZQMnN;ftNSi~RszGver7-Gd20aWGPm2d9|_`N(=W!|>Nz+b~_ z`ttSbob0c?aBQ!Nqz4lQfz* zPpZ95&Vr?dMc(E0ep}dBrnvgEiZO!jSw6ZMusWw*aK}>~;T5WQOYj~yoa%E?CP2>D zF}7Px(WwR+Lu1k-bw9^VSaCXFEj?mo+Xo;96W0hWin4?f7~upF1ptJkrE3OJdlYuo z?9SMKkuCJkt)iOE-WE^qRyBn#UeQ&|ch)lfjlZPk?-~bCS@W^U(Pq6G$>eNv%_REN z?`?YcWHa9%b(3hA{>P)v>2*d%1s1b4ATcJJ;8&B)yO?eE-52V-PTs0t))|BGQD+xp zWueai!$uomf+8R3_9NpY@#rx_D-C>=CCu5|{QE|ur8`26hLc533AVm9y;X;eE$g*$ z!$QKzDQEqJ+4=1RY-sKMf%D;yn9e6Izeo`#fkGa~M%Vz$X?s6wL+`#WLL_fqj?5zw zGV?ax^NUFhgt}rP|A8>Y5U-yDV1RnQFM{(6x8;h@%m@UJoow?tQ_ezU7ZhuZlhR(OE z7qk@hKy_UqpJzAXX@%nr+3+i1YEg#Eu(+f*k?vK zHpV`-SHpQs_$(Kn#ho%g2ofI$0f&(N{deD5n3dS&3M1_&O!Mw+0EN#iOqfQPQF`l5 zcl84z^=>Eh=rhE%ALc%f(o`9`4;ip3vtQSEC|cxoit#H{K>1${PD0QTNH}YlXf#HY<{-Au><8G>^k?shI3! z^sVK<;lflOS`{&5Y|wUFyC;$;7 zfpR456}TAyxKt8Wl{c~Nrv>NYhWRIZBmqX84ZYQp1x9RBUXD2 zE_GdLsk^-Kv#>>e-(iomckU6BBKA)H-?V zxI|%g+(iEsO6%!n+UV%aAEWJ~?%F?Xqzar^fUWuVwp3=1upu1+OqR|0?k4A*w`==3 zIvO!AA(${jX{7(OkT;Eo<+51UF$rNdFJGPPvS7lxK|_%^F}AM^AQ>D4QG9lsT;Jn# z9=tKAyMsEkd%dM!dxGK=STKa)J>84~Sn?4hhlhuItC}qwYKYbD$ro98ai$QUv{(ZW z0mr0)Yuz{UANtLyu>4t7B+&2M9r3vHe>ht5yTrAIiv zoCPbjhPwJf!Yqj^Zl2HGm(Rsq_D|_>kkHr-(;vQnKlD@185KvGI}R@FV|HLdR@vn; zA?1drp@6`%XU}uC?ccsC2tS}ZotZo8J$ksWm9iPZII}@xP+WT+>ZVY!BQfcxMX%+M zX?b$CJ8RMHrZ8IwUOgJEQ0KJb84p zf5KSOJ6MHF=TkViSyfn3GX0y5|SeU4N+GNsy?gh%LXIG8^O3qRR`)6|P?y{AT z#`!T$rQ2;MJHIK&L`8qYOQYX7Lz3~aGGqF7kI@5GdtO++#lUQq>Rie*-0zYfNQUaR zinV*wwYevNAYmdEp4F5b-Ko0ln+0kA)(>PK%wCxo=;DxN$E+709v*IQ)(H?%5VBOD z9ck9K!c`vzMMRyp*L^>~W{b;*An~Gz^a)saTwG$#|LJDOg@uqL<&`EkeKYgAKrduly#cd|O(bZ9*Bj zTSz^xb2n4Bk<})hPEI}E(HaaQg`QPH9;hX= za%I1wF{$6mZexH(giTTQk0)t8zSmj0PGgdYJ$K84U>f`sdr{huWYUx+K0Oxk@J~IK z>tO8uy&(GAWB+-=59rPhDfU(v>GatxUVK(+gnzl#hWadJDxTq9m{I@Nxkg8mUCPIm zd)F=r*Y5;~ZtPeg6LCL({=~WsyafZbp0oFMc3Fad7Z`Vm-+$QFAA{d6pb20oP0Otv zHQA`&eiv*U-p>5kUQv(;0Aq1eV93$;?iY*>GJ=Avp9}`*7OT%297WDW{pWGr7#{3r zOL~N1NC97$fO{{bWq6%&UdL5&E!`4~u?ax@Pq>JJD z#y{$OoeY4d6%Q`HCRC{))$k!5ZgckUFXIKXNU{C&E}4r)?G!gXzX1Usz69;vG?-eh z6->71X-HM>YK4X>Uei{RhV{(C>^$-bNf{q5;Nr<`<6wNt$@DuXthGPQj%@CpZDvwX zAp|Of@zp1tE3*8aj@PZ32Lu>N3>12q?R(&QbpBf0es|7ZCV?t!b5-lL=7J)Jqeg5*J&>l;!|Rvi4w zkF|ds5Zc}0vUsJO0j8$8U{dr5zyuk`mb<)Y>JAnnYDY(!((d@^mYOFzv}FpaTa>nr_B68Ve-_kImzNOB>^4fuMiqAsG!T16sA}Fk?qae_Va9bLLie0hi z*7C{aAVu}Nsfml6H=d8E>RI*rm9omN^LeoWL1BrnjLw^xsYy427nThI2D6FVL+ zWZVc_p3&rS1HDu3(bm4iX00cU|l6k8>Tj%7{Yw3%40Q5)9Ips(-y>{n3@b$E}om6A#TXcXM%~4fTYmo@j~>#ON94^ zaz;l+Mn0=yZPm*PUFhqwS&)%-0(aX>dTnFB7MJ$gdR!|a?emeAfli{rVKPU9tqpK6 zj*0pG-boU~Lw>zZ?(T^amtLV$ur+S_YWK6b>BR=W-L3ue#=U$nV`>1XMocJweIJD_ z=wfj45@!5UluJ+d+piv_pz9>b``BcmS%(%qJv~(${vSTchPy>2L>0ffl8HUW$x%_r zx7wWS%px`ms^{1z^dbZFOcU9SULu7iWjg$SOf#+rO!l1-2>;xf>qR0Gl4cgjHAZEg zk?3eqvSG3ISVu<~VCy8#NJS7eCc)lk4`~CxV8GUxWNX9s@2(qf4cAB|;KiPC7}!{N ztmqn`Vt!?$K~khvew_GSu{OM`>XS`3=}pAyn2tx|{3$QH2R)&Yr z8EGUV_#62)y=Ks*b^U?Xc|Xdh=|J;yyl1pYe8bg3`1zehse$zLwz0a374y{n^5So6 zk0xw6*+G`9_6SOywDS8#h6v=W<7-se!(U%vnY0F>cic zmuM`KoQ#T08LmPH#Qpf)1Hxn(J`3V^ zwNo2(^(>}uJE-tq<8V1pqaM~8pDCUT0F$NHl{Uj({}o83;)u6ppQOBwiW1rF&KlR9 zCV#8F`f()wsG|a7<0bm&$?)mYoID^k)>1Yh5m#`c*(*`|R@VJyL$>@|Su?XY}|0c0VSwb%4v|TP1=2rXCWJrOr zl82&6193l&jvRtXF>r`IWI0pVP|07xD4WX4?Fv#NqI9vi6(to@$T&?U5e!`)_v2I} zO%>gK-V}M06O`9>XMQgL3d6l%A_;I4+)*4oaQ&`-CKi669$}sEZ^D zJpymhLz4>CO;*hmGQIc)&*iZw)2s&1&3k|Cqn+tj*70Ocuo~=yDn~>6(&tT;Ruo6X zdA0HFTVIc_>I2qXsBy1?8OZ#F{yn3QZGX9NB_uo!G1C#^#~K#G_(p)X7eN)(#zm~J z@6R^=Fg$;7Qf4e@2af8trECwDur!TrThPfACFlbmh zQ10`uz9lyu$?UiiPJxWqr>oub1A~15-(CpGE-Wm31=dS=Z(C|rh>FfH&P*_f?B;$lCwj(NdLAV~r#;GKf$vxYTQRJev(G1Jm2BRR)X$0=bt>WNf|?uWf|{dymnb8i~N zqBFN~I+%`Lilp^f2~7t9t~HQ4>R%&eJl9FESB@_hm@^w$nHd>%DjK(boD6FOc>8Ym zloPV)bzYKm<^`Gz7rDCi+_g?Ndw$60A0;q-F6ib|3OtFmm*v*_8#J5L4iVN zKvyqSMayPT{gx0aG%va26R|7S@bSmZmh809_tghKrSKFe8BnisAw1Ldz&H^<9{ zPek3_qFC;v@(!#I6~vftQwIa?DQ4?~$--Uz2P_iVfB$7$yim#4G_^z!2=J4c<0DhS zdeSw<#&rwUm*I>If0JcD$$6ilCN1a5ENz2z$w_Rvch=5lL#r98rV7{)q$qK>n-G7? z$ z3){X_X<&%}LCGQk=i-U8*nF3RQ2THvHy#pzDd)V{GLH$I^9TGpWoDccIyr_bHBH`t zt9yp?7ccB<4H{kmI&wP^0S{t|JK-`zOS1;jkPi#BCZdd@vkE5#RyvR5F30?Bf_x5V ze(6mTzL}28&hfQdW|nQRII-xFf+?IlfK8iJkoNb}K%O9Qx z{Y9?uJ@>YwC@4SJb!i`p+IZ$OL*sFCQCVJ|the@^SX>|t(NF-pw2HJ89LIH$LT}E-={sC$Y2j59n}J z#-4-*_ApK^L`v8fI>KRgl&hsBd&Z|v0i0k;l-v-8ANKl;8h1p)uP$C@nWKq8KBML< zFUR?7QDU$*1YVy9I}h$vYCP^&B&Zy$|7Mg6clOD-eJvU365Tl^$RUT`!hZdNRfT-X zVALV!b_;aF+6FA{Vsc^!gV)d1gUqw)p4=%BMCYw$x{;Z?H z#xP%^yxKEdf4|S8w+3$Fni<$fspy|w9ADp^H~Z&YeY0kQyUjf`(0!6D^gvbh>`jvq z^$dpGRMn$0VO)da2+J~rU|-LVHsCnvaopY3zsmgk-t(K8_PVWUqq?C**$Rq`YV7zz zG4E2&Dv|l~>-;BrjHKSrCvxAdp6Yd-$$0d*X*Eq`m9&w*7rnpPHZ`%;KN=_b#{!G0 zHBsg**}@zCW;;)O8OY<(oZou>_GV}Ap>HAMcugX^1>{4IR1d73zvbfSzQV)vM7ScZ zTcv9wLp80%bF06YU(j41Q`?iquQ#0qWU)gsXod0Ra4{+b1w%mCG+pOJp{Zh@{eYE# zJa15dRE5%zWGDDu-^e6>qh`Omo`m|~3^M*u!DGaC>|*VCw@HmjCp^l8aAU>P~=u}d8&v`Tg-HlIlla)DgqRvV&gFAfl+nI_8c1=7lC+*uDQe>)2q1hE%ZcRX;5kZ2)d^>}n=**B z#*!yFfXL%+yuV$N7nGKsC-x`Hz)iR9ySwENTFj}eY{jg{d+}`hl&3q6>COmk&|sU+ zQ-Fa77Im&V3FUk$$-)l-?iKHp(n zth4BTIHzqt*tpnFBn&RvkP14w$m*Fh>mcxqev3?HZ?jj>_6oCghV@`D32gxT?F-Yz z`Lk8@Yx2r9tCxqji;`z2qrqx(m}g?q&Bel6vhP3^4XpOzwPlgWJH*82+`i4-(b2Wn zC3P6xAfpVDwslUkbB>Lv+tzLA46M{3C6R$Uvf2M9Doy4nFjP@7A4%#Q%kW(DqC5Bm zSJpnJg$U3qfTIx&VBUbWwKe&aoakUa%2_WEWF>UDsnE&pExY--H-DFx+SUsofBY6z z`vbhUPJW+1`Q(qAPCvD&z-I7%;)$S@NMQ~+YLh(tZC`~^x!)|O$LWwf?svW&teziM ziynjbwMAz#$ENsP6JDjrp8kRU0K21$;l*U2q*CzNgC*tCcFrs{92}fik^-0%6ci|< zCw(#NTo$u&I7;|yj!>8hl$th=83X4Yv|353U+GR7=o?5Jt%)w&Xgc)^LB?a?Y5?AfSR6R^o(zpqGTJvC^{uR+;KiJi zUVPTxPAE_FSJYvgcnBGsjh7Zzb<*H6P@5e3d)07rw}YToYLjaH`=i{O;g5pHF|bb> zH74fW#a!t3V3{NaC+pNL%o`jYP+Ph^jM8iM?>k7%)l1d+KK=|-7B7w===$|LuT^e= z$vmsyX>!O%0@lw3^j`P+v7;A@ef{5b3izOiu_W3ChJ69oSV22hn7rUQ*70kZEdQGhe3!R9@)0=mmIs1>J2`T12*{(rCS0 zqhl)rXI=_E9t0KfYgRO!0uq5lc}Li^gC2vQa=07We!^V^&lCSWGM7~n$Ah&q``@nI z_w}4PUAvra(_1W;=#||>=693atNt{KP5%0U%)FN|VWwJS zn38f|Z=RqyHL9(PlC}~L=q&0w3vzcHoO&$WV00JsgCu2qd?fgCEB8(q_6dV^O@8~4 z`=1^w-#+K(ef!#c-Hu35Lb`7Ju-#0{;-i{jpPXGi`$ zbCzq-a=ch=LU_Ylau#J(PNEfXd@mX1!5@oxRc~2wrx1BqClT35xWe`)%ne}xi=`tq za8Txc9*n#`@loNLG_J=2p3=pZ*bKh9t?u&>?si0F%AZimwShF##NPZwvu;V$A2m#% zjBtsg%QAtJP=ONhWe6jvJ1L)kccylG1*`>Z3Uf^iQo`-It%s+kTq)EG3LWC@Kk|^= zYC!OQt-~QJP@UlN4HsRD@Zs+yiIKkDsbiE3V$JGn#;oU(FyKq$i6m{kwaJ+@3P1ZC z2~_-o@esYvpHY}Ts>Pe=iZgB_kx-1pP;nzo2Y}CIZ&t{~v)w4kL7o1oFAkLoa^u@{H z$g=iNBQV;ZpR77CS*Q`9svB-3Qop-dlzTfyp&@lxlciEh-`PyhXVT<-2?E@^YS`0! zU=719+^D`%U(VxL;)m8nBEI6YDi6KGjCD{N_*{N5uYfcxRQgRL0j|Yr(9+sxdJd5O zpNpO`6sn#m`Jx?O>+D%2X1pmJ@zRn+gm(iFeJCncn@OddF#^zPbMs?dg}f8U>f86b zJ^gq)Z*IEi#I_Q$uUA;af3wqY{^vhT>_hUYNFb)&Qv$q=tiPoA;3CfFFJIAcuQuv3 z4y&;?W^#tY#FK?^k?&Y~>wgZ$#_k3NuE%9l1Y%)@G8aA!kNM1hf5?2J-G06pu8X1e z`)%16@ZMztGt&g&vk?E&ZD&&Uvbc3rRN$bMyRUIK@$0lLc2aj-K%kw~C3ijCM#nif zoCBiwMTb(WI?UGF@AtKc?bVL=%upWI+$XFQkoo;;B~GG=lhP|F$1FsOc|7D$9(dvc zqVsiC*XtSAC;a@(;_m-;b8RF3>WCD6h6HvpC{T8qaO4YT5P2b705dU}IL4)6H%IDU zZ()-HMG2fd1^sj=2D}7ZloWI=I(+$0rL;vkDTx#9!0K@W>Cw4qi?7|$#=pP8QOIh9 zuMVN+A77JEW0N=$KVZYeUb^jAo}~n|NI5R23_8zC90fOU`K)If?f1^jrR2YCJ@ir= zvt94jD_10WP2I1f{k5!psNLwvm_hePg&`+tC*L8A3GHWUuaM#45Bk8)D9Diwv7#~` zUg{8j4Q>GtREEiG14JyxOG%R6Ep@^7gu&8DeG5W?m;eNfe3BKt4$pr{8XOY-#SkvS z)&Z6rBM5slqC7S>N`MHIZ*@l9c7DJ`Fuq5KKko<6qx>2#UIN=11It>xcv|1;OYi*| zVZjn?*Hw~5KbhMwK|G5dC#jLE{rnY`27F{wosu(T`bA5qwsAg=qEhj>*uKMZj`;wRD z(hI5|vB5*Beu0hHNfw~9fTs%5D)2%)WQ9nfZA&jXOfFj(^YhD<(9ZNMgaN@`f49bi z{R57AToNE^jNLMYa17y>w1cCJOY_BCe=uAhn@wWKC>5n7k92Xm)3Bf+T4O4MR`KGh z{o<6+(0+ZK9V#DBke`Gdjx!fFEq;ZdMo&{b9HrO7UvN3&Tyl)R*ddj zaGb@aNUGlDJeCklnluf#WHXG2xYHEL4QA}Tdalj*$n9IvV6OlEe6dy%00BH0$sDF+ zhLa7+P6?FsC*gho#J)5iRQ{N1Pks5Nh4OsH9OiT0q-F`&gu%rzH&=%_J4bMakq^dC+FhVZLd+)6!3`_AG>tal~(BL=-+=JH(+jlNXk7B1DV+ zHAJp59kzjq;z=JJ+Y;1Z^N27!00W6a0XrNeS-~nN$G%j)rVpJhrI!IM>3=Ne_7)x1 zj?gX)GB;=I7-kC)zFu$j!2N~h!_SJ5OdmF`Gv~Y?Z@+i2VCQeWi`sv3c7CfQlIBmn zmlv3Z^bOkUz4;fF@6xTQjRgZs3@0o+rWg+)#HAy@MrSww8j$I7qqM62z0u!)>XZvG zW&d}{?s-_>Oq+Jd(G;j}k6O54~y0-eMNDF$1@e5BrAPs;M#Zv=z*6R7m zb|M_a3I#MQ5Bk-6y*xl!D{yjXX{gTJ)a{F=i;>?ky~`a6_|6f-WoN-n3k=$)b;$H~ z3Og8k*fy-cDH#vjzpgqpi1^ce|EvDyV|Ysov*&2>u8-et%Ia!w)Jpe)i7_9)5F!#u zY+VMGdw{_`Hd9>Nt1t$NTf&jXv9CY=pxU2c!w2EXyb^kMR;Nh0Qyo15G917aBu^Hs ztXDmKQAM+xVx?Z6@Y@UC&UV!~H9D_;eh@(U zoF?M)#+!GNaVa&tJTVsZ;jX|i228Im&*$@LIyt}vxDr)|A_)vd^@(z|G0lSZj{#Kq&{QxJ@f#tX}^~7I*x}dEB1we*Vfn}=#S)QK@9e* zS(b%BsGJo^V9(;K)D1)*Xu38tqnbZrNSSM%&Tb|=XwKhT&b+MSA&s+m*>CszlX5}7 zY6n#CoK5q70qk3;>mULo5zRL7@d&9UkSaGacyprx2I1T&2ot3~kVEvd(o=NTl?vw+ zN$M`RF?buNN!k>7eG7OJXO%plA{nP+sh|3aoG{!rq}&VlZUS(P*B7idgJA)zgu?)e zj$DTVoe86ii;aEs@%{EfJ0GrXrvdD7)^IL6D&se&Wc1kGLsJ<6v6|J$JPlD!{`!mFL2>8{*RB`5pmJ`x9|nyyQ9b5uru zgE^=w*?ksFB~wtg#s}J9_?%Q*VrP=`zMwC6##VZe@$}21)}MU)ydI#}Q_^)m@UCri z_Qi`kU5>PCPws5LW#>DTSaf1TMxXHGB6UVkCyyxg^2LIb;JrqRY_M2m$JlWKrUH@k zDGBto+dC$kl>lR&PieJQiN5I5V#w+nX?yH>9oxgY5}ZD0TrOXcA*+?3$`I5KX)5yw`_u9>Nn z=tKwrWZjm^#nb8OBb#p=7=3V~nYK(Un?JYQ`BpH#-sZJwctz*u zWMvB7mu*YMc9Xdyy75lp{C06C?BIe(J3D=S0gi6ub2(liO-&Z+^L_un!cAv8@A$Ht zC6_`le!N(*Z}@SvI%-oGRNYeb1L`PgX<-g--p~-@dIFPjSEfb?ISK$Zz6H8iq&KhP%eWCNe{I zN+&QmvwaW|ZNYC}q$;`kXa1cVqWj@N9Frv2{r4^18M^<}e4U0XC9BQoIFeVk0ng2z z>@A-Es^4Xz_vg!Q@JMT6vrrPXuRT6B*e$)hY*@_7Zgt1VV9WP1ca*GLc@wEZJ6ktk zaDV|M!{@}Gd+pkNRpHvB+-ETG_)5`++p4+m+Io@WuoF78g}(tNt~`!HMn5Nep5U1T z14~h>_Yzv;A7QwQhD}wujeCZm(fXIahEeJ7-o331SnJ*Vi*MBM^Q)()=&$&cAArq1q(q|Kxkr5rBJ_f7N_h5}e-Mb>%MJ3|H*!HIZ^Ve_gV z$Ck{t+7@hD`LYIsIZ{-blY0w%2v~O|FEXUjwS^AH$Am>1t&;ksx~TwYO=gBB2v zdU4nzAYLr?5OXb-D{_{D^mfp7>@e~7V{;aWTAqQZ#o&A&qfL0%EPMMp)zvr)Vyy5= zdF>UhF9gbuLC|kB^{nw4J#5@$%1p-;^s8#jiKk+M0!wZKm#TbPYSQ-U-ObUeYOBxb z%nb^yjY@*erlKv-F+`YEVJsS4aFv8_y85g~2KBAg3;PA96JJNY{gX(T!d~RNVeMoS zVaV}-qQbGeg0My6AR+Wu%mkE`JZhyUK|xURY-}``D|axsBuk|^zPF&BkaY|9^!#S$^cIroSH+v{OtFNnqr4(K(Bfjpqd?;l>TKUl4>fE zEm3nPCVo5e`?k$3tDX|2Vf%}~4{B&+sl@4fSU-iwpSs;Un;gHjm02ID%Yel;xx;p* zgpPiOEBQwR`Qc*G)}d{!OYatnGo~|st9aGEt(m|~NKWQROw^{Kd-UiMo(Op_si<4R zSMt#}5Nb8c1^}G3%uV$xf-t`HjKizR+gmx<6s?^FwxGqb*vKPtjlC)Hr%#_sCH%HL z)2};Db~2RYon6=}gokqOEl};B`f2x-43y}tum3R?3zj%(#sOe4G%VHKK#ncdkEe1- z3Hnh>)=bRdBuz@ZNn-jgScbqW34~8kpM>m6`(4h*uPt_R`?k9gA;%ULRaznA#6Qf{ z9k@J{lARQDUm|!}t*@gycL!x|=N`WVv3YiH!M@m_e~}7m>LbebS=356XUr4a&%xmS z`oQ&@)y?VxFKAdEXY?Bua%h#UVjPk;%&hfR+*2A8aHZd&6ecGV5+)ZG5{kHSnI zv4E12Wg({6QH2VQ@sJ#Ka^{TCz39$8jsnFj#A2R{#E|5cNh|XXh7{gk8btEA`anXm zzGaJy5|UTQ#(Qrr&}=YAnwfS+Ldsmf-dX)}$lOe^OCW(mF%wA+jgI16p0H4YflvI> zm@}sM}+radQf9jDfI4a{4u_+BXJ3|HnVkQH|4Yr|Izg0 zV1?5fr+gT%Bt@mR=1rrBzttIP(oq|O#Tko92(kD?=d|KMeIy{mdWAXs5+MiFY*EHU z)oydVrQtAc!VDb6ncmZ0JjwH^p}yEFD^{ofiiBo`yVA0t0eHtJYPj_mi%krJqR#{g zRR#SZ7hw|s3U)c5h4`w^=;noGq@;c{1?L5GW(^j}SW3Al_Sg;# zylCeKhq#gDHdB|RuJ0zD zBD6hD=7<^O@ASR}Y^;t|bxmJK{YezWu$M4Veag#Ka4x%;KBu9E@sw0d;GyB5hvV#T zXWE$~OVdghcGDhGYoTcciKO2J!gep`_iOKrqmg1Kp;PD0Lk@le*43IN3bM$=-yxy%#k&K7T!!wRw3XDOD0Drn>Vwe_q8pF=q-9|6<;_A zy~tu$CSN?h{qGy=I;@V5r-1JxAq+@eUHSylwy|v@CLM1rJ;MTm!t${+(3Qeo!z+kE zh?}qVK%?c0r);z1S31-gwn^qnQlEp5pnccUlA5M^6RNg-`?&`Hig8O&-A*$Dlf0SCz~c77vDZ$E|#Mh7yQI2@r*XiclMb7BJg+qhf6i zD8SxRkKvFJQ`o&2doTVL7OTMC_DR44D&eqC{ZCN%t zsf6981Y>z5NQPnF?M@%C_-IltxdMVuZU=#~uE7Yvydnh!TjgW{&3>o6Ce^@F&PJ1! zT>Gc5I;+0;x5t^dVu6R2zZU;0QoDQ}PU78gp6xwm#L&l{`_P-R80JvyX!xj$v#-k1 zJSGv&Z4pBb=Z3=HD}9Dg*D_HF@(kB)^zh27{Onf{AjE;R#qgp5>yER@A*>UUIm8rq z2o}p0LIW0NTcLxrNLM0ceM*}@E8sxBeATMVRXaSx$>o*E-jxV{%vUimvzF~#(X@3c z`Zq{!2K$!DzByZ)T*{YId$i!i2wh zzw3;10D!W}XM^ME%Do1uo2{cPo4-t6Ya40V^~9MV<0$WQ8B{`c=-iS zl^N){u#L<6^m;Gga32fx^Dg={(gIU8k`1) zBYK4JlvI>kAO($dPK}bgesaVWBvU|^t1S3gcL>kNl9j;R)Z+ZSyofCk9dxYUHoCKJ zl6aC{QzF-9_H<|Lo#VY}(W%aVrf-AmMTz|5PkS7+T-ZKldwZGN05RbDMYKPQ+CS8e z;v}*FOhNQ(p=H?dqX0JMbqNmctf?GCOE+}S|A=G{Hl5dPJNq{i_cymJVEc#KQ=AYN z&epUpI7=28-Y)u4+{%lTPhnq?frs^Dx{M?9O|~t?a<|64tdI$Y{iM~BDFD8dpR2>l I6wKcL4}#~W;s5{u diff --git a/index.html b/index.html index 6124cd30054..30dbdbeba23 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,6 @@ Ace - The High Performance Code Editor for the Web - @@ -871,10 +870,6 @@

    Projects Using Ace

    Code Combat
  • -
  • - - ShareLaTeX -
  • Papeeria @@ -884,25 +879,6 @@

    Projects Using Ace

    style="left: -15px;top: 27px;width: 127px;background: black;" /> CodinGame
  • -
  • - - ProcessWire -
  • -
  • - - Crunch -
  • -
  • - - Drive Notepad -
  • -
  • - - Textor -
  • Dillinger @@ -945,11 +921,6 @@

    Projects Using Ace

    Debuggex
  • -
  • - - Decor -
  • - - - - + + diff --git a/src/commands/multi_select_commands.js b/src/commands/multi_select_commands.js index a5a3ab21b43..2cba5d95b56 100644 --- a/src/commands/multi_select_commands.js +++ b/src/commands/multi_select_commands.js @@ -57,7 +57,7 @@ exports.defaultCommands = [{ readOnly: true }, { name: "toggleSplitSelectionIntoLines", - description: "Split into lines", + description: "Split selection into lines", exec: function(editor) { if (editor.multiSelect.rangeCount > 1) editor.multiSelect.joinSelections(); From 7f0ed13e2be33f9a238c5fb985e6a7b6f60ff12a Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 3 Mar 2023 02:44:59 +0400 Subject: [PATCH 0735/1293] less horrible active indent guide colors for dark themes --- demo/kitchen-sink/doclist.js | 8 ++++---- src/theme/ambiance.css.js | 2 +- src/theme/cloud9_night.css.js | 2 +- src/theme/cloud9_night_low_color.css.js | 2 +- src/theme/clouds_midnight.css.js | 2 +- src/theme/cobalt.css.js | 2 +- src/theme/gob.css.js | 2 +- src/theme/gruvbox.css.js | 2 +- src/theme/gruvbox_dark_hard.css.js | 2 +- src/theme/idle_fingers.css.js | 2 +- src/theme/kr_theme.css.js | 2 +- src/theme/merbivore.css.js | 2 +- src/theme/merbivore_soft.css.js | 2 +- src/theme/mono_industrial.css.js | 2 +- src/theme/monokai.css.js | 2 +- src/theme/one_dark.css.js | 2 +- src/theme/pastel_on_dark.css.js | 2 +- src/theme/solarized_dark.css.js | 2 +- src/theme/terminal.css.js | 2 +- src/theme/tomorrow_night.css.js | 2 +- src/theme/tomorrow_night_blue.css.js | 2 +- src/theme/tomorrow_night_bright.css.js | 2 +- src/theme/tomorrow_night_eighties.css.js | 2 +- src/theme/twilight.css.js | 2 +- src/theme/vibrant_ink.css.js | 2 +- 25 files changed, 28 insertions(+), 28 deletions(-) diff --git a/demo/kitchen-sink/doclist.js b/demo/kitchen-sink/doclist.js index 2ca6a81c468..238bdf43421 100644 --- a/demo/kitchen-sink/doclist.js +++ b/demo/kitchen-sink/doclist.js @@ -79,8 +79,8 @@ modelist.modes.forEach(function(m) { -if (window.require && window.require.s) try { - for (var path in window.require.s.contexts._.defined) { +if (window.define && window.define.modules) try { + for (var path in window.define.modules) { if (path.indexOf("!") != -1) path = path.split("!").pop(); else @@ -129,7 +129,7 @@ function loadDoc(name, callback) { if (parts[0] == "docs") path = "demo/kitchen-sink/" + path; else if (parts[0] == "ace") - path = "lib/" + path; + path = "src/" + parts.slice(1).join("/"); net.get(path, function(x) { initDoc(x, path, doc); @@ -150,7 +150,7 @@ function saveDoc(name, callback) { if (parts[0] == "docs") path = "demo/kitchen-sink/" + path; else if (parts[0] == "ace") - path = "lib/" + path; + path = "src/" + parts.slice(1).join("/"); upload(path, doc.session.getValue(), callback); } diff --git a/src/theme/ambiance.css.js b/src/theme/ambiance.css.js index 49b32141bad..90a803b6e0b 100644 --- a/src/theme/ambiance.css.js +++ b/src/theme/ambiance.css.js @@ -216,6 +216,6 @@ module.exports = `.ace-ambiance .ace_gutter { } .ace-ambiance .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACAQMAAACjTyRkAAAABlBMVEUAAADCwsK76u2xAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjYGBoAAAAhACBGFbxzQAAAABJRU5ErkJggg==") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/cloud9_night.css.js b/src/theme/cloud9_night.css.js index b287f6f8af7..a43e5508171 100644 --- a/src/theme/cloud9_night.css.js +++ b/src/theme/cloud9_night.css.js @@ -142,6 +142,6 @@ module.exports = `.ace-cloud9-night .ace_gutter { } .ace-cloud9-night .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/cloud9_night_low_color.css.js b/src/theme/cloud9_night_low_color.css.js index aeb8ac2beaa..fc2d55e9b7b 100644 --- a/src/theme/cloud9_night_low_color.css.js +++ b/src/theme/cloud9_night_low_color.css.js @@ -130,6 +130,6 @@ module.exports = `.ace-cloud9-night-low-color .ace_gutter { } .ace-cloud9-night-low-color .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/clouds_midnight.css.js b/src/theme/clouds_midnight.css.js index 3eeff4dc2e6..59a9ed6821c 100644 --- a/src/theme/clouds_midnight.css.js +++ b/src/theme/clouds_midnight.css.js @@ -112,6 +112,6 @@ module.exports = `.ace-clouds-midnight .ace_gutter { } .ace-clouds-midnight .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/cobalt.css.js b/src/theme/cobalt.css.js index f71ee24355f..c03a84d41ae 100644 --- a/src/theme/cobalt.css.js +++ b/src/theme/cobalt.css.js @@ -133,6 +133,6 @@ module.exports = `.ace-cobalt .ace_gutter { } .ace-cobalt .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/gob.css.js b/src/theme/gob.css.js index 1e72cff638d..56f17f37b9d 100644 --- a/src/theme/gob.css.js +++ b/src/theme/gob.css.js @@ -129,6 +129,6 @@ module.exports = `.ace-gob .ace_gutter { } .ace-gob .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/gruvbox.css.js b/src/theme/gruvbox.css.js index 05f64f0aa2d..1ecc918c22c 100644 --- a/src/theme/gruvbox.css.js +++ b/src/theme/gruvbox.css.js @@ -95,6 +95,6 @@ module.exports = `.ace-gruvbox .ace_gutter-active-line { } .ace-gruvbox .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/gruvbox_dark_hard.css.js b/src/theme/gruvbox_dark_hard.css.js index baf47e9fac2..79910b634de 100644 --- a/src/theme/gruvbox_dark_hard.css.js +++ b/src/theme/gruvbox_dark_hard.css.js @@ -159,6 +159,6 @@ module.exports = `.ace-gruvbox-dark-hard .ace_gutter { } .ace-gruvbox-dark-hard .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/idle_fingers.css.js b/src/theme/idle_fingers.css.js index d2c29990f38..bb371fb12dc 100644 --- a/src/theme/idle_fingers.css.js +++ b/src/theme/idle_fingers.css.js @@ -112,6 +112,6 @@ module.exports = `.ace-idle-fingers .ace_gutter { } .ace-idle-fingers .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/kr_theme.css.js b/src/theme/kr_theme.css.js index cc911ec5551..3f7d001d2ab 100644 --- a/src/theme/kr_theme.css.js +++ b/src/theme/kr_theme.css.js @@ -123,6 +123,6 @@ module.exports = `.ace-kr-theme .ace_gutter { } .ace-kr-theme .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/merbivore.css.js b/src/theme/merbivore.css.js index 0178e9d6182..2dba7da1391 100644 --- a/src/theme/merbivore.css.js +++ b/src/theme/merbivore.css.js @@ -109,6 +109,6 @@ module.exports = `.ace-merbivore .ace_gutter { } .ace-merbivore .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/merbivore_soft.css.js b/src/theme/merbivore_soft.css.js index aaa93787310..14acf11e779 100644 --- a/src/theme/merbivore_soft.css.js +++ b/src/theme/merbivore_soft.css.js @@ -110,6 +110,6 @@ module.exports = `.ace-merbivore-soft .ace_gutter { } .ace-merbivore-soft .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/mono_industrial.css.js b/src/theme/mono_industrial.css.js index 6e1cdfc9e44..507facfd00b 100644 --- a/src/theme/mono_industrial.css.js +++ b/src/theme/mono_industrial.css.js @@ -125,6 +125,6 @@ module.exports = `.ace-mono-industrial .ace_gutter { } .ace-mono-industrial .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/monokai.css.js b/src/theme/monokai.css.js index 1a42c504f9c..26b925e3f92 100644 --- a/src/theme/monokai.css.js +++ b/src/theme/monokai.css.js @@ -121,6 +121,6 @@ module.exports = `.ace-monokai .ace_gutter { } .ace-monokai .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/one_dark.css.js b/src/theme/one_dark.css.js index aaa2ca579bc..eaa251981f0 100644 --- a/src/theme/one_dark.css.js +++ b/src/theme/one_dark.css.js @@ -160,6 +160,6 @@ module.exports = `.ace-one-dark .ace_gutter { } .ace-one-dark .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/pastel_on_dark.css.js b/src/theme/pastel_on_dark.css.js index 16b2a1fabba..a7eb58a309b 100644 --- a/src/theme/pastel_on_dark.css.js +++ b/src/theme/pastel_on_dark.css.js @@ -128,6 +128,6 @@ module.exports = `.ace-pastel-on-dark .ace_gutter { } .ace-pastel-on-dark .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/solarized_dark.css.js b/src/theme/solarized_dark.css.js index 1b4bfc85e60..3c61f8329c2 100644 --- a/src/theme/solarized_dark.css.js +++ b/src/theme/solarized_dark.css.js @@ -100,6 +100,6 @@ module.exports = `.ace-solarized-dark .ace_gutter { } .ace-solarized-dark .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/terminal.css.js b/src/theme/terminal.css.js index 8c38e6d7a98..ec889ae9034 100644 --- a/src/theme/terminal.css.js +++ b/src/theme/terminal.css.js @@ -131,6 +131,6 @@ module.exports = `.ace-terminal-theme .ace_gutter { } .ace-terminal-theme .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/tomorrow_night.css.js b/src/theme/tomorrow_night.css.js index c07322a42f9..abea28029c4 100644 --- a/src/theme/tomorrow_night.css.js +++ b/src/theme/tomorrow_night.css.js @@ -124,6 +124,6 @@ module.exports = `.ace-tomorrow-night .ace_gutter { } .ace-tomorrow-night .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/tomorrow_night_blue.css.js b/src/theme/tomorrow_night_blue.css.js index 3dc51338f6f..b801bf5da7d 100644 --- a/src/theme/tomorrow_night_blue.css.js +++ b/src/theme/tomorrow_night_blue.css.js @@ -121,6 +121,6 @@ module.exports = `.ace-tomorrow-night-blue .ace_gutter { } .ace-tomorrow-night-blue .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/tomorrow_night_bright.css.js b/src/theme/tomorrow_night_bright.css.js index 33bd85b6766..1d0b5989583 100644 --- a/src/theme/tomorrow_night_bright.css.js +++ b/src/theme/tomorrow_night_bright.css.js @@ -140,6 +140,6 @@ module.exports = `.ace-tomorrow-night-bright .ace_gutter { } .ace-tomorrow-night-bright .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/tomorrow_night_eighties.css.js b/src/theme/tomorrow_night_eighties.css.js index 8c883dba23b..881f369d0ed 100644 --- a/src/theme/tomorrow_night_eighties.css.js +++ b/src/theme/tomorrow_night_eighties.css.js @@ -124,6 +124,6 @@ module.exports = `.ace-tomorrow-night-eighties .ace_gutter { } .ace-tomorrow-night-eighties .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/twilight.css.js b/src/theme/twilight.css.js index 99d526f9fb3..bf76dda502d 100644 --- a/src/theme/twilight.css.js +++ b/src/theme/twilight.css.js @@ -126,6 +126,6 @@ module.exports = `.ace-twilight .ace_gutter { } .ace-twilight .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; diff --git a/src/theme/vibrant_ink.css.js b/src/theme/vibrant_ink.css.js index da8c51af50e..87b296cb710 100644 --- a/src/theme/vibrant_ink.css.js +++ b/src/theme/vibrant_ink.css.js @@ -109,6 +109,6 @@ module.exports = `.ace-vibrant-ink .ace_gutter { } .ace-vibrant-ink .ace_indent-guide-active { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQIW2PQ1dX9zzBz5sz/ABCcBFFentLlAAAAAElFTkSuQmCC) right repeat-y; } `; From d53da8e39f7ae6362d9d1262dbbb4cae61229aa1 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 3 Mar 2023 03:00:25 +0400 Subject: [PATCH 0736/1293] release v1.15.3 --- CHANGELOG.md | 2 ++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c808aee30a5..6be8ce62be5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.15.3](https://github.com/ajaxorg/ace/compare/v1.15.2...v1.15.3) (2023-03-02) + ### [1.15.2](https://github.com/ajaxorg/ace/compare/v1.15.1...v1.15.2) (2023-02-16) ### [1.15.1](https://github.com/ajaxorg/ace/compare/v1.15.0...v1.15.1) (2023-02-13) diff --git a/build b/build index f74d3c7e203..a6f05db4a35 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit f74d3c7e20367e5c8eaa5cabb9a8a21702bc9715 +Subproject commit a6f05db4a359a66152afc29b6382caeb09a84cbd diff --git a/package.json b/package.json index 71172cf23ea..745850ecf16 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.15.2", + "version": "1.15.3", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 7600fc90933..86e4001ff1f 100644 --- a/src/config.js +++ b/src/config.js @@ -157,6 +157,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.15.2"; +exports.version = "1.15.3"; From 48f94f3d716011abb85d84076107daf09e5af25f Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 3 Mar 2023 11:22:32 +0300 Subject: [PATCH 0737/1293] Fix typo in naming openCommandPalette action --- src/commands/default_commands.js | 2 +- src/keyboard/vscode.js | 2 +- src/mouse/touch_handler.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/default_commands.js b/src/commands/default_commands.js index bbe8b830ca7..99d75d4f106 100644 --- a/src/commands/default_commands.js +++ b/src/commands/default_commands.js @@ -854,7 +854,7 @@ exports.commands = [{ multiSelectAction: "forEach", scrollIntoView: "cursor" }, { - name: "openCommandPallete", + name: "openCommandPalette", description: "Open command palette", bindKey: bindKey("F1", "F1"), exec: function(editor) { diff --git a/src/keyboard/vscode.js b/src/keyboard/vscode.js index c369ea989e0..75f25052242 100644 --- a/src/keyboard/vscode.js +++ b/src/keyboard/vscode.js @@ -128,7 +128,7 @@ exports.handler.addCommands([{ name: "goToNextError" }, { bindKey: {mac: "Command-Shift-P|F1", win: "Ctrl-Shift-P|F1"}, - name: "openCommandPallete" + name: "openCommandPalette" }, { bindKey: {mac: "Shift-Option-Up", win: "Alt-Shift-Up"}, name: "copylinesup" diff --git a/src/mouse/touch_handler.js b/src/mouse/touch_handler.js index 75178980cdf..0151412e966 100644 --- a/src/mouse/touch_handler.js +++ b/src/mouse/touch_handler.js @@ -34,7 +34,7 @@ exports.addTouchListeners = function(el, editor) { clipboard && ["span", { class: "ace_mobile-button", action: "paste" }, "Paste"], hasUndo && ["span", { class: "ace_mobile-button", action: "undo" }, "Undo"], ["span", { class: "ace_mobile-button", action: "find" }, "Find"], - ["span", { class: "ace_mobile-button", action: "openCommandPallete" }, "Palette"] + ["span", { class: "ace_mobile-button", action: "openCommandPalette" }, "Palette"] ] : ["span"]), contextMenu.firstChild ); @@ -62,7 +62,7 @@ exports.addTouchListeners = function(el, editor) { } contextMenu.firstChild.style.display = "none"; isOpen = false; - if (action != "openCommandPallete") + if (action != "openCommandPalette") editor.focus(); }; contextMenu = dom.buildDom(["div", From e0b79e04e408eaa1b42b868516c4bbeffbb487f6 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Fri, 3 Mar 2023 15:23:08 +0400 Subject: [PATCH 0738/1293] fix `Completer` declaration; fix small bugs in autocomplete --- ace.d.ts | 4 ++-- src/autocomplete.js | 36 ++++++++++++++++++++++-------------- src/ext/language_tools.js | 8 +++++--- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index ef22ecf3441..9d717efa3ee 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -916,7 +916,7 @@ export namespace Ace { position: Point, prefix: string, callback: CompleterCallback): void; - getDocTooltip(item: Completion): void; + getDocTooltip?(item: Completion): undefined | string | Completion; id?: string; } } @@ -940,4 +940,4 @@ export const Range: { new(startRow: number, startColumn: number, endRow: number, endColumn: number): Ace.Range; fromPoints(start: Ace.Point, end: Ace.Point): Ace.Range; comparePoints(p1: Ace.Point, p2: Ace.Point): number; -}; \ No newline at end of file +}; diff --git a/src/autocomplete.js b/src/autocomplete.js index d7cf964bf5a..5ce95428456 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -11,16 +11,20 @@ var config = require("./config"); /** * Completion represents a text snippet that is proposed to complete text * @typedef Completion - * @property {string} [value] - text that would be inserted when selecting this completion (if `type` is "value") - * @property {string} [snippet] - snippet that would be inserted, if completion's type is "snippet" - * @property {number} [score] - determine order in which completions would be displayed, less score - further from start - * @property {string} [meta] - small description of completion - * @property {string} [caption] - text that would be displayed in completion list, if omitted `value` or `snippet` - * would be shown instead - * @property {string} [docHTML] - html string that would be displayed as additional popup - * @property {string} [docText] - plain text that would be displayed as additional popup. If `docHtml` exists, it would - * be used instead of `docText` - * @property {string} [completerId] - completer's identifier + * @property {string} [snippet] - a text snippet that would be inserted when the completion is selected + * @property {string} [value] - The text that would be inserted when selecting this completion. If a `snippet` is + * provided, it will be used instead of `value` + * @property {number} [score] - a numerical value that determines the order in which completions would be displayed. + * A lower score means that the completion would be displayed further from the start + * @property {string} [meta] - a short description of the completion + * @property {string} [caption] - the text that would be displayed in the completion list. If omitted, value or snippet + * would be shown instead. + * @property {string} [docHTML] - an HTML string that would be displayed as an additional popup + * @property {string} [docText] - a plain text that would be displayed as an additional popup. If `docHTML` exists, + * it would be used instead of `docText`. + * @property {string} [completerId] - the identifier of the completer + * @property {Ace.Range} [range] - an object that determines which range should be replaced in the text with new values (experimental) + * @property {string} [command] - A command that needs to be executed after the insertion of the completion (experimental) */ var Autocomplete = function() { @@ -379,11 +383,15 @@ var Autocomplete = function() { var doc = null; if (!selected || !this.editor || !this.popup.isOpen) return this.hideDocTooltip(); - this.editor.completers.some(function(completer) { - if (completer.getDocTooltip && selected.completerId === completer.id) + + var completersLength = this.editor.completers.length; + for (var i = 0; i < completersLength; i++) { + var completer = this.editor.completers[i]; + if (completer.getDocTooltip && selected.completerId === completer.id) { doc = completer.getDocTooltip(selected); - return doc; - }); + break; + } + } if (!doc && typeof selected != "string") doc = selected; diff --git a/src/ext/language_tools.js b/src/ext/language_tools.js index f34c2c741eb..b3c9954825a 100644 --- a/src/ext/language_tools.js +++ b/src/ext/language_tools.js @@ -14,7 +14,10 @@ var keyWordCompleter = { } var state = editor.session.getState(pos.row); var completions = session.$mode.getCompletions(state, session, pos, prefix); - completions = completions.map((el) => el.completerId = keyWordCompleter.id); + completions = completions.map((el) => { + el.completerId = keyWordCompleter.id; + return el; + }); callback(null, completions); }, id: "keywordCompleter" @@ -53,7 +56,6 @@ var snippetCompleter = { caption: caption, snippet: s.content, meta: s.tabTrigger && !s.name ? s.tabTrigger + "\u21E5 " : "snippet", - type: "snippet", completerId: snippetCompleter.id }); } @@ -61,7 +63,7 @@ var snippetCompleter = { callback(null, completions); }, getDocTooltip: function(item) { - if (item.type == "snippet" && !item.docHTML) { + if (item.snippet && !item.docHTML) { item.docHTML = [ "", lang.escapeHTML(item.caption), "", "
    ", lang.escapeHTML(transformSnippetTooltip(item.snippet)) From a4f1f3f014b492311adfeb64c071c36f8c6e9c36 Mon Sep 17 00:00:00 2001 From: Nanne <184182+whazor@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:32:47 +0100 Subject: [PATCH 0739/1293] Support TM include: $self Used by mediawiki, robot, mel, pig, elixir, logiql, alda --- src/mode/_test/tokens_mel.json | 20 +++++++++++++++++++- src/mode/text_highlight_rules.js | 2 ++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/mode/_test/tokens_mel.json b/src/mode/_test/tokens_mel.json index d5bb79bd356..8a9d275b943 100644 --- a/src/mode/_test/tokens_mel.json +++ b/src/mode/_test/tokens_mel.json @@ -8,7 +8,25 @@ ["storage.type.mel"," "], ["entity.name.function.mel","animatedDuplication"], ["punctuation.section.function.mel"," ("], - ["meta.function.mel","int $rangeStart, int $rangeEnd, int $numOfDuplicates, int $duplicateOrInstance"], + ["storage.type.mel","int"], + ["meta.function.mel"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","rangeStart"], + ["meta.function.mel",", "], + ["storage.type.mel","int"], + ["meta.function.mel"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","rangeEnd"], + ["meta.function.mel",", "], + ["storage.type.mel","int"], + ["meta.function.mel"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","numOfDuplicates"], + ["meta.function.mel",", "], + ["storage.type.mel","int"], + ["meta.function.mel"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","duplicateOrInstance"], ["punctuation.section.function.mel",")"] ],[ "start", diff --git a/src/mode/text_highlight_rules.js b/src/mode/text_highlight_rules.js index d8d109bed49..e44f201f6fe 100644 --- a/src/mode/text_highlight_rules.js +++ b/src/mode/text_highlight_rules.js @@ -149,6 +149,8 @@ var TextHighlightRules = function() { } var includeName = typeof rule == "string" ? rule : rule.include; if (includeName) { + if (includeName === "$self") + includeName = "start"; if (Array.isArray(includeName)) toInsert = includeName.map(function(x) { return rules[x]; }); else From de6c10d37f190b2078d967af7a3ddd2f3aacf3d4 Mon Sep 17 00:00:00 2001 From: Ruslan Batdalov Date: Sat, 4 Mar 2023 08:55:53 +0100 Subject: [PATCH 0740/1293] Fix a typo in a MIXAL command name to highlight. --- src/mode/mixal_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mode/mixal_highlight_rules.js b/src/mode/mixal_highlight_rules.js index 98641c58af2..8a6d41a7677 100644 --- a/src/mode/mixal_highlight_rules.js +++ b/src/mode/mixal_highlight_rules.js @@ -18,7 +18,7 @@ var MixalHighlightRules = function() { 'JAN', 'JAZ', 'JAP', 'JANN', 'JANZ', 'JANP', 'J1N', 'J1Z', 'J1P', 'J1NN', 'J1NZ', 'J1NP', 'J2N', 'J2Z', 'J2P', 'J2NN', 'J2NZ', 'J2NP','J3N', 'J3Z', 'J3P', 'J3NN', 'J3NZ', 'J3NP', 'J4N', 'J4Z', 'J4P', 'J4NN', 'J4NZ', 'J4NP', 'J5N', 'J5Z', 'J5P', 'J5NN', - 'J5NZ', 'J5NP','J6N', 'J6Z', 'J6P', 'J6NN', 'J6NZ', 'J6NP', 'JXAN', 'JXZ', 'JXP', + 'J5NZ', 'J5NP','J6N', 'J6Z', 'J6P', 'J6NN', 'J6NZ', 'J6NP', 'JXN', 'JXZ', 'JXP', 'JXNN', 'JXNZ', 'JXNP', 'INCA', 'DECA', 'ENTA', 'ENNA', 'INC1', 'DEC1', 'ENT1', 'ENN1', 'INC2', 'DEC2', 'ENT2', 'ENN2', 'INC3', 'DEC3', 'ENT3', 'ENN3', 'INC4', 'DEC4', 'ENT4', 'ENN4', 'INC5', 'DEC5', 'ENT5', 'ENN5', 'INC6', 'DEC6', 'ENT6', 'ENN6', 'INCX', 'DECX', From 9f2341ebaebcb4213994376b54135fe038dab6f5 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 12 Mar 2023 00:14:15 +0400 Subject: [PATCH 0741/1293] prevent unwanted zoom on mobile when viewport is not specified --- src/virtual_renderer.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 76d99adf144..33c320b9e65 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -18,7 +18,6 @@ var editorCss = require("./css/editor.css"); var Decorator = require("./layer/decorators").Decorator; var useragent = require("./lib/useragent"); -var HIDE_TEXTAREA = useragent.isIE; dom.importCssString(editorCss, "ace_editor.css", false); @@ -632,7 +631,7 @@ var VirtualRenderer = function(container, theme) { var posLeft = pixelPos.left; posTop -= config.offset; - var h = composition && composition.useTextareaForIME ? this.lineHeight : HIDE_TEXTAREA ? 0 : 1; + var h = composition && composition.useTextareaForIME || useragent.isMobile ? this.lineHeight : 1; if (posTop < 0 || posTop > config.height - h) { dom.translate(this.textarea, 0, 0); return; From 4f7bf17e659f6531ebae8336b19c7a54fcce781d Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 12 Mar 2023 00:44:11 +0400 Subject: [PATCH 0742/1293] cleanup demo --- demo/kitchen-sink/demo.js | 3 ++- kitchen-sink.html | 8 -------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 08c66c910bd..95269ec1d1b 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -376,6 +376,7 @@ optionsPanel.add({ var optionsPanelContainer = document.getElementById("optionsPanel"); optionsPanel.render(); optionsPanelContainer.insertBefore(optionsPanel.container, optionsPanelContainer.firstChild); +optionsPanel.container.style.width = "80%"; optionsPanel.on("setOption", function(e) { util.saveOption(e.name, e.value); }); @@ -451,7 +452,7 @@ env.editSnippets = function() { }; optionsPanelContainer.insertBefore( - dom.buildDom(["div", {style: "text-align:right;margin-right: 60px"}, + dom.buildDom(["div", {style: "text-align:right;width: 80%"}, ["div", {}, ["button", {onclick: env.editSnippets}, "Edit Snippets"]], ["div", {}, diff --git a/kitchen-sink.html b/kitchen-sink.html index a40166f128c..8ac0386ca76 100644 --- a/kitchen-sink.html +++ b/kitchen-sink.html @@ -6,16 +6,8 @@ Ace Kitchen Sink - - From a9819722cec6ff60b028deaa7b70d7fefabac531 Mon Sep 17 00:00:00 2001 From: Zakhar Kozlov Date: Wed, 15 Mar 2023 12:38:54 +0200 Subject: [PATCH 0743/1293] fix: add updated monospace font for Windows (#5091) --- src/css/editor.css.js | 2 +- src/ext/static.css.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/css/editor.css.js b/src/css/editor.css.js index eaad5d28cb7..910a481e6b5 100644 --- a/src/css/editor.css.js +++ b/src/css/editor.css.js @@ -31,7 +31,7 @@ module.exports = ` position: relative; overflow: hidden; padding: 0; - font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace; + font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'Source Code Pro', 'source-code-pro', monospace; direction: ltr; text-align: left; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); diff --git a/src/ext/static.css.js b/src/ext/static.css.js index f2db582663c..9a785492e5a 100644 --- a/src/ext/static.css.js +++ b/src/ext/static.css.js @@ -1,5 +1,5 @@ module.exports = `.ace_static_highlight { - font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'Source Code Pro', 'source-code-pro', 'Droid Sans Mono', monospace; font-size: 12px; white-space: pre-wrap } From 44b3a3ef2de40f5cc71c3dedc1ed8d596cfadeec Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Thu, 16 Mar 2023 16:37:45 +0400 Subject: [PATCH 0744/1293] fix: Fix bug with missing token in latex folding (#5093) * fix bug with missing token * add test for latex folding Issue #5090 --- src/mode/folding/latex.js | 2 +- src/mode/folding/latex_test.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/mode/folding/latex_test.js diff --git a/src/mode/folding/latex.js b/src/mode/folding/latex.js index afd9e320f8c..adb553497bf 100644 --- a/src/mode/folding/latex.js +++ b/src/mode/folding/latex.js @@ -63,7 +63,7 @@ oop.inherits(FoldMode, BaseFoldMode); var getType = function() { var token = stream.stepForward(); - var type = token.type == "lparen" ?stream.stepForward().value : ""; + var type = token && token.type == "lparen" ? stream.stepForward().value : ""; if (dir === -1) { stream.stepBackward(); if (type) diff --git a/src/mode/folding/latex_test.js b/src/mode/folding/latex_test.js new file mode 100644 index 00000000000..f4ce60ff4f6 --- /dev/null +++ b/src/mode/folding/latex_test.js @@ -0,0 +1,31 @@ +if (typeof process !== "undefined") require("amd-loader"); + +"use strict"; + +var LatexMode = require("../latex").Mode; +var EditSession = require("../../edit_session").EditSession; +var assert = require("../../test/assertions"); + +module.exports = { + "test: latex block folding": function () { + var session = new EditSession([ + '\\usepackage{amsmath}', '\\title{\\LaTeX}', '\\date{}', '\\begin' + ]); + + var mode = new LatexMode(); + session.setFoldStyle("markbegin"); + session.setMode(mode); + + assert.equal(session.getFoldWidget(0), ""); + assert.equal(session.getFoldWidget(1), ""); + assert.equal(session.getFoldWidget(2), ""); + assert.equal(session.getFoldWidget(3), "start"); + assert.equal(session.getFoldWidgetRange(3), null); + + session.setValue(session.getValue() + '{test}\nsome text here \n\\end{test}'); + + assert.range(session.getFoldWidgetRange(3), 3, 12, 5, 0); + } +}; + +if (typeof module !== "undefined" && module === require.main) require("asyncjs").test.testcase(module.exports).exec(); From 9fcf79a3d366903c71a726e37e1938e89d4ee0f7 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Thu, 16 Mar 2023 16:57:11 +0400 Subject: [PATCH 0745/1293] build: include esm-resolver.js in npm package (#5086) --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 745850ecf16..874209b4815 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "files": [ "src", "ace.d.ts", + "esm-resolver.js", "!**/*_test.js", "!_test" ], From 34e769c5b29a68a3c4201fecc75d1287c99f9d51 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Thu, 16 Mar 2023 17:32:24 +0400 Subject: [PATCH 0746/1293] fix: Option to determine specific prefixes for quote insertion (#5067) * add new behaviour option to determine specific prefixes for quote insertion * make quotes check more generic; add auto quote insertion for javascript (backtick) * change cstyle behaviours option to more suitable * add type definition for Mode; move `$pairQuotesAfter` from options to mode property Issue #5063 --- src/edit_session.js | 11 ++++++++--- src/mode/behaviour/behaviour_test.js | 22 ++++++++++++++++++++++ src/mode/behaviour/cstyle.js | 15 ++++++++++++--- src/mode/javascript.js | 5 ++++- src/mode/python.js | 4 ++++ src/mode/text.js | 14 ++++++++++++++ 6 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/edit_session.js b/src/edit_session.js index b8a37a7d02f..371ec62f3f4 100644 --- a/src/edit_session.js +++ b/src/edit_session.js @@ -820,14 +820,19 @@ EditSession.$uid = 0; this.$modes = config.$modes; + /** + * + * @type {TextMode|null} + */ + this.$mode = null; + this.$modeId = null; + /** * Sets a new text mode for the `EditSession`. This method also emits the `'changeMode'` event. If a [[BackgroundTokenizer `BackgroundTokenizer`]] is set, the `'tokenizerUpdate'` event is also emitted. * @param {TextMode} mode Set a new text mode - * @param {cb} optional callback + * @param {Function} cb optional callback * **/ - this.$mode = null; - this.$modeId = null; this.setMode = function(mode, cb) { if (mode && typeof mode === "object") { if (mode.getTokenizer) diff --git a/src/mode/behaviour/behaviour_test.js b/src/mode/behaviour/behaviour_test.js index 4a5cb7a4cb0..64ed9765793 100644 --- a/src/mode/behaviour/behaviour_test.js +++ b/src/mode/behaviour/behaviour_test.js @@ -18,6 +18,7 @@ var XMLMode = require("../xml").Mode; var HTMLMode = require("../html").Mode; var CSSMode = require("../css").Mode; var MarkdownMode = require("../markdown").Mode; +var PythonMode = require("../python").Mode; var editor; var exec = function(name, times, args) { do { @@ -286,6 +287,16 @@ module.exports = { exec("insertstring", 1, '`'); exec("insertstring", 1, 'b'); assert.equal(editor.getValue(), "`b`"); + + editor.setValue(""); + exec("insertstring", 1, 'a'); + exec("insertstring", 1, "'"); + assert.equal(editor.getValue(), "a'"); + + editor.setValue(""); + exec("insertstring", 1, 'b'); + exec("insertstring", 1, "`"); + assert.equal(editor.getValue(), "b``"); }, "test: css": function() { editor.session.setMode(new CSSMode()); @@ -393,6 +404,17 @@ module.exports = { exec("insertstring", 1, "`"); exec("insertstring", 1, "`"); assert.equal(editor.getValue(), "``-``"); + }, + "test: python": function() { + editor.session.setMode(new PythonMode()); + editor.setValue("f", 1); + exec("insertstring", 1, '"'); + assert.equal(editor.getValue(), 'f""'); + + // there is no such prefix for python + editor.setValue("p", 1); + exec("insertstring", 1, '"'); + assert.equal(editor.getValue(), 'p"'); } }; diff --git a/src/mode/behaviour/cstyle.js b/src/mode/behaviour/cstyle.js index 617a00a87db..cd107c70b5c 100644 --- a/src/mode/behaviour/cstyle.js +++ b/src/mode/behaviour/cstyle.js @@ -46,7 +46,12 @@ var getWrapped = function(selection, selected, opening, closing) { ] }; }; - +/** + * Creates a new Cstyle behaviour object with the specified options. + * @constructor + * @param {Object} [options] - The options for the Cstyle behaviour object. + * @param {boolean} [options.braces] - Whether to force braces auto-pairing. + */ var CstyleBehaviour = function(options) { this.add("braces", "insertion", function(state, action, editor, session, text) { var cursor = editor.getCursorPosition(); @@ -260,8 +265,12 @@ var CstyleBehaviour = function(options) { wordRe.lastIndex = 0; var isWordBefore = wordRe.test(leftChar); wordRe.lastIndex = 0; - var isWordAfter = wordRe.test(leftChar); - if (isWordBefore || isWordAfter) + var isWordAfter = wordRe.test(rightChar); + + var pairQuotesAfter = session.$mode.$pairQuotesAfter; + var shouldPairQuotes = pairQuotesAfter && pairQuotesAfter[quote] && pairQuotesAfter[quote].test(leftChar); + + if ((!shouldPairQuotes && isWordBefore) || isWordAfter) return null; // before or after alphanumeric if (rightChar && !/[\s;,.})\]\\]/.test(rightChar)) return null; // there is rightChar and it isn't closing diff --git a/src/mode/javascript.js b/src/mode/javascript.js index 469b8d9e9af..8f3ba56da7c 100644 --- a/src/mode/javascript.js +++ b/src/mode/javascript.js @@ -10,7 +10,7 @@ var CStyleFoldMode = require("./folding/cstyle").FoldMode; var Mode = function() { this.HighlightRules = JavaScriptHighlightRules; - + this.$outdent = new MatchingBraceOutdent(); this.$behaviour = new CstyleBehaviour(); this.foldingRules = new CStyleFoldMode(); @@ -22,6 +22,9 @@ oop.inherits(Mode, TextMode); this.lineCommentStart = "//"; this.blockComment = {start: "/*", end: "*/"}; this.$quotes = {'"': '"', "'": "'", "`": "`"}; + this.$pairQuotesAfter = { + "`": /\w/ + }; this.getNextLineIndent = function(state, line, tab) { var indent = this.$getIndent(line); diff --git a/src/mode/python.js b/src/mode/python.js index 95b2ca84524..078f4254980 100644 --- a/src/mode/python.js +++ b/src/mode/python.js @@ -16,6 +16,10 @@ oop.inherits(Mode, TextMode); (function() { this.lineCommentStart = "#"; + this.$pairQuotesAfter = { + "'": /[ruf]/i, + '"': /[ruf]/i + }; this.getNextLineIndent = function(state, line, tab) { var indent = this.$getIndent(line); diff --git a/src/mode/text.js b/src/mode/text.js index 607ef227df8..05c3c8cd14a 100644 --- a/src/mode/text.js +++ b/src/mode/text.js @@ -9,6 +9,20 @@ var lang = require("../lib/lang"); var TokenIterator = require("../token_iterator").TokenIterator; var Range = require("../range").Range; +/** + * + * @constructor + * @alias TextMode + * @property {{[quote: string]: string}} [$quotes] - quotes used by language mode + * @property {string} lineCommentStart - characters that indicate the start of a line comment + * @property {{start: string, end: string}} [blockComment] - characters that indicate the start and end of a block comment + * @property {TextHighlightRules} HighlightRules - language specific highlighters + * @property {FoldMode} foldingRules - language specific folding rules + * @property {MatchingBraceOutdent} $outdent + * @property {RegExp} tokenRe + * @property {RegExp} nonTokenRe + * @property {{[quote: string]: RegExp}} [$pairQuotesAfter] - An object containing conditions to determine whether to apply matching quote or not. + */ var Mode = function() { this.HighlightRules = TextHighlightRules; }; From 99713bbeec0c68e787948f066bc5d08bb542fcd7 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 12 Mar 2023 01:15:24 +0400 Subject: [PATCH 0747/1293] fix spacebar swipe not moving selection on android --- src/keyboard/textinput.js | 24 ++++++++++++++++++++ src/keyboard/textinput_test.js | 40 ++++++++++++++++++++++++++++++++++ src/test/mockdom.js | 2 +- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/keyboard/textinput.js b/src/keyboard/textinput.js index 1ee56031e2c..9858babc247 100644 --- a/src/keyboard/textinput.js +++ b/src/keyboard/textinput.js @@ -69,6 +69,8 @@ var TextInput = function(parentNode, host) { if (ignoreFocusEvents) return; host.onBlur(e); isFocused = false; + if (isMobile && !isIOS) + document.removeEventListener("selectionchange", detectSelectionChange); }, host); event.addListener(text, "focus", function(e) { if (ignoreFocusEvents) return; @@ -85,6 +87,8 @@ var TextInput = function(parentNode, host) { setTimeout(resetSelection); else resetSelection(); + if (isMobile && !isIOS) + document.addEventListener("selectionchange", detectSelectionChange); }, host); this.$focusScroll = false; this.focus = function() { @@ -270,6 +274,26 @@ var TextInput = function(parentNode, host) { } }; + function detectSelectionChange(e) { + if (!text || !text.parentNode) + document.removeEventListener("selectionchange", detectSelectionChange); + if (inComposition) return; + + if (text.selectionStart !== text.selectionEnd) return; + var startDiff = text.selectionStart - lastSelectionStart; + var oldLenght = lastSelectionEnd - lastSelectionStart; + if (startDiff > 0) { + startDiff = Math.max(startDiff - oldLenght, 1); + } else if (startDiff === 0 && oldLenght) { + startDiff = -1; + } + var repeat = Math.abs(startDiff); + var key = startDiff > 0 ? KEYS.right : KEYS.left; + for (var i = 0; i < repeat; i++) { + host.onCommandKey({}, 0, key); + } + } + var inputHandler = null; this.setInputHandler = function(cb) {inputHandler = cb;}; this.getInputHandler = function() {return inputHandler;}; diff --git a/src/keyboard/textinput_test.js b/src/keyboard/textinput_test.js index dc49019271b..9cf3f385f1b 100644 --- a/src/keyboard/textinput_test.js +++ b/src/keyboard/textinput_test.js @@ -153,6 +153,46 @@ module.exports = { assert.equal(editor.getValue(), "y"); }, + "test: android spacebar moves cursor": function() { + setUserAgentForTests(true, false); + var value = "Juhu kinners!"; + editor.setValue(value); + editor.blur(); + editor.focus(); + var lastCommand = ""; + editor.commands.on("exec", function(e) { + lastCommand += e.command.name; + }); + + textarea.selectionStart = textarea.selectionEnd; + document.dispatchEvent(new CustomEvent("selectionchange")); + assert.equal(lastCommand, "gotoright"); + lastCommand = ""; + + textarea.selectionStart = + textarea.selectionEnd = textarea.selectionStart - 1; + document.dispatchEvent(new CustomEvent("selectionchange")); + assert.equal(lastCommand, "gotoleft"); + lastCommand = ""; + + assert.equal(editor.getSelectedText(), ""); + textarea.selectionStart = 0; + textarea.selectionEnd = textarea.value.length; + textarea.dispatchEvent(new CustomEvent("select")); + assert.equal(editor.getSelectedText(), value); + + textarea.selectionEnd = textarea.selectionStart; + document.dispatchEvent(new CustomEvent("selectionchange")); + assert.equal(lastCommand, "gotoleft"); + lastCommand = ""; + + textarea.selectionStart = + textarea.selectionEnd = textarea.selectionEnd + 2; + document.dispatchEvent(new CustomEvent("selectionchange")); + assert.equal(lastCommand, "gotorightgotoright"); + lastCommand = ""; + }, + "test: composition with visible textarea": function() { var data = [ // select ll diff --git a/src/test/mockdom.js b/src/test/mockdom.js index e0c65ddddae..ef879f51245 100644 --- a/src/test/mockdom.js +++ b/src/test/mockdom.js @@ -443,7 +443,7 @@ function Node(name) { if (!e.timeStamp) e.timeStamp = Date.now(); e.currentTarget = this; var events = this._events && this._events[e.type]; - events && events.forEach(function(listener) { + events && events.slice().forEach(function(listener) { listener.call(this, e); }, this); if (this["on" + e.type]) From a5cc588e8ee90d036ca049dab10c208817c05cf7 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Fri, 17 Mar 2023 16:49:35 +0400 Subject: [PATCH 0748/1293] Tooltip (#5088) * add right aligned mode for autocomplete popup * fix tooltip style --- src/autocomplete/popup.js | 15 +++++++++++++-- src/css/editor.css.js | 7 +++++-- src/ext/prompt.js | 3 ++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js index 920f4178de0..c3f76248c93 100644 --- a/src/autocomplete/popup.js +++ b/src/autocomplete/popup.js @@ -340,7 +340,7 @@ dom.importCssString(` } .ace_completion-meta { opacity: 0.5; - margin: 0.9em; + margin: 0 0.9em; } .ace_completion-message { color: blue; @@ -367,7 +367,18 @@ dom.importCssString(` line-height: 1.4; background: #25282c; color: #c1c1c1; -}`, "autocompletion.css", false); +} +.ace_autocomplete_right .ace_text-layer { + width: calc(100% - 8px); +} +.ace_autocomplete_right .ace_line { + display: flex; +} +.ace_autocomplete_right .ace_completion-meta { + flex: 1; + text-align: right; +} +`, "autocompletion.css", false); exports.AcePopup = AcePopup; exports.$singleLineEditor = $singleLineEditor; diff --git a/src/css/editor.css.js b/src/css/editor.css.js index 910a481e6b5..7a37877e2a3 100644 --- a/src/css/editor.css.js +++ b/src/css/editor.css.js @@ -399,8 +399,7 @@ module.exports = ` } .ace_tooltip { - background-color: #FFF; - background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1)); + background-color: #f5f5f5; border: 1px solid gray; border-radius: 1px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); @@ -420,6 +419,10 @@ module.exports = ` pointer-events: none; } +.ace_tooltip:focus { + outline: 1px solid black; +} + .ace_folding-enabled > .ace_gutter-cell { padding-right: 13px; } diff --git a/src/ext/prompt.js b/src/ext/prompt.js index 4d93bdef5e4..57f7aa48b3f 100644 --- a/src/ext/prompt.js +++ b/src/ext/prompt.js @@ -72,6 +72,7 @@ function prompt(editor, message, options, callback) { if (options.getCompletions) { var popup = new AcePopup(); popup.renderer.setStyle("ace_autocomplete_inline"); + popup.renderer.setStyle("ace_autocomplete_right"); popup.container.style.display = "block"; popup.container.style.maxWidth = "600px"; popup.container.style.width = "100%"; @@ -470,7 +471,7 @@ prompt.modes = function(editor, callback) { }; dom.importCssString(`.ace_prompt_container { - max-width: 600px; + max-width: 603px; width: 100%; margin: 20px auto; padding: 3px; From eb834a1f1ca7f922437a90f2f14d935d75f31ac8 Mon Sep 17 00:00:00 2001 From: azmkercso <126491695+azmkercso@users.noreply.github.com> Date: Fri, 17 Mar 2023 15:28:05 +0100 Subject: [PATCH 0749/1293] feat: Inline autocompletion (#5084) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Inline ghost-text autocompletion Added optional ghost-text preview to popup-based autocompletion (disabled by default) New external inline-autocompletion widget which supports ghost-text only autocompletion * Autocomplete bugfixes Added the inline autocompletion to the kitchen sink demo Added kitchen sink demo option to enable inline preview for popup-based autocomplete Inline completion and command bar tooltip are changed to be editor scoped * Update src/ext/inline_autocomplete.js Co-authored-by: André Oliveira * Fix styling and add cross-editor tests * Fix for popup display positioning for autocompletion * Add popup display unit tests --------- Co-authored-by: André Oliveira --- ace.d.ts | 106 ++++ demo/inline_autocompletion.html | 48 ++ demo/kitchen-sink/demo.js | 27 + src/autocomplete.js | 442 +++++++++----- src/autocomplete/inline.js | 73 +++ src/autocomplete/inline_test.js | 236 ++++++++ src/autocomplete/popup.js | 95 ++- src/autocomplete/popup_test.js | 217 +++++++ src/css/editor.css.js | 1 + src/ext/inline_autocomplete.js | 610 ++++++++++++++++++++ src/ext/inline_autocomplete_test.js | 285 +++++++++ src/ext/inline_autocomplete_tooltip_test.js | 174 ++++++ src/keyboard/textinput.js | 2 +- src/snippets.js | 22 +- src/test/all_browser.js | 3 + src/test/mockdom.js | 2 +- src/virtual_renderer.js | 3 +- src/virtual_renderer_test.js | 12 + 18 files changed, 2195 insertions(+), 163 deletions(-) create mode 100644 demo/inline_autocompletion.html create mode 100644 src/autocomplete/inline.js create mode 100644 src/autocomplete/inline_test.js create mode 100644 src/autocomplete/popup_test.js create mode 100644 src/ext/inline_autocomplete.js create mode 100644 src/ext/inline_autocomplete_test.js create mode 100644 src/ext/inline_autocomplete_tooltip_test.js diff --git a/ace.d.ts b/ace.d.ts index 5028508a228..7fb8b3293a9 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -924,6 +924,72 @@ export namespace Ace { prefix: string, callback: CompleterCallback): void; } + + export class AceInline { + show(editor: Editor, completion: Completion, prefix: string): void; + isOpen(): void; + hide(): void; + destroy(): void; + } + + interface CompletionOptions { + matches?: Completion[]; + } + + type CompletionProviderOptions = { + exactMatch?: boolean; + ignoreCaption?: boolean; + } + + type CompletionRecord = { + all: Completion[]; + filtered: Completion[]; + filterText: string; + } | CompletionProviderOptions + + type GatherCompletionRecord = { + prefix: string; + matches: Completion[]; + finished: boolean; + } + + type CompletionCallbackFunction = (err: Error | undefined, data: GatherCompletionRecord) => void; + type CompletionProviderCallback = (err: Error | undefined, completions: CompletionRecord, finished: boolean) => void; + + export class CompletionProvider { + insertByIndex(editor: Editor, index: number, options: CompletionProviderOptions): boolean; + insertMatch(editor: Editor, data: Completion, options: CompletionProviderOptions): boolean; + completions: CompletionRecord; + gatherCompletions(editor: Editor, callback: CompletionCallbackFunction): boolean; + provideCompletions(editor: Editor, options: CompletionProviderOptions, callback: CompletionProviderCallback): void; + detach(): void; + } + + export class Autocomplete { + constructor(); + autoInsert?: boolean; + autoSelect?: boolean; + exactMatch?: boolean; + inlineEnabled?: boolean; + getPopup(): AcePopup; + showPopup(editor: Editor, options: CompletionOptions): void; + detach(): void; + destroy(): void; + } + + type AcePopupNavigation = "up" | "down" | "start" | "end"; + + export class AcePopup { + constructor(parentNode: HTMLElement); + setData(list: Completion[], filterText: string): void; + getData(row: number): Completion; + getRow(): number; + getRow(line: number): void; + hide(): void; + show(pos: Point, lineHeight: number, topdownOnly: boolean): void; + tryShow(pos: Point, lineHeight: number, anchor: "top" | "bottom" | undefined, forceShow?: boolean): boolean; + goTo(where: AcePopupNavigation): void; + } } @@ -946,3 +1012,43 @@ export const Range: { fromPoints(start: Ace.Point, end: Ace.Point): Ace.Range; comparePoints(p1: Ace.Point, p2: Ace.Point): number; }; + + +type InlineAutocompleteAction = "prev" | "next" | "first" | "last"; + +type TooltipCommandEnabledFunction = (editor: Ace.Editor) => boolean; + +interface TooltipCommand extends Ace.Command { + enabled: TooltipCommandEnabledFunction | boolean, + position?: number; +} + +export class InlineAutocomplete { + constructor(); + getInlineRenderer(): Ace.AceInline; + getInlineTooltip(): InlineTooltip; + getCompletionProvider(): Ace.CompletionProvider; + show(editor: Ace.Editor): void; + isOpen(): boolean; + detach(): void; + destroy(): void; + goTo(action: InlineAutocompleteAction): void; + tooltipEnabled: boolean; + commands: Record + getIndex(): number; + setIndex(value: number): void; + getLength(): number; + getData(index?: number): Ace.Completion | undefined; + updateCompletions(options: Ace.CompletionOptions): void; +} + +export class InlineTooltip { + constructor(parentElement: HTMLElement); + setCommands(commands: Record): void; + show(editor: Ace.Editor): void; + updatePosition(): void; + updateButtons(force?: boolean): void; + isShown(): boolean; + detach(): void; + destroy(): void; +} diff --git a/demo/inline_autocompletion.html b/demo/inline_autocompletion.html new file mode 100644 index 00000000000..b514f670e5f --- /dev/null +++ b/demo/inline_autocompletion.html @@ -0,0 +1,48 @@ + + + + + ACE Inline Autocompletion demo + + + + +
    
    +
    +
    +
    +
    +
    +
    +
    diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js
    index 08c66c910bd..27272d3c4d4 100644
    --- a/demo/kitchen-sink/demo.js
    +++ b/demo/kitchen-sink/demo.js
    @@ -312,6 +312,8 @@ doclist.pickDocument = function(name) {
     var OptionPanel = require("ace/ext/options").OptionPanel;
     var optionsPanel = new OptionPanel(env.editor);
     
    +var originalAutocompleteCommand = null;
    +
     optionsPanel.add({
         Main: {
             Document: {
    @@ -368,6 +370,29 @@ optionsPanel.add({
                 path: "showTokenInfo",
                 position: 2000
             },
    +        "Inline preview for autocomplete": {
    +            path: "inlineEnabledForAutocomplete",
    +            position: 2000,
    +            onchange: function(value) {
    +                var Autocomplete = require("ace/autocomplete").Autocomplete;
    +                if (value && !originalAutocompleteCommand) {
    +                    originalAutocompleteCommand = Autocomplete.startCommand.exec;
    +                    Autocomplete.startCommand.exec = function(editor) {
    +                        var autocomplete = Autocomplete.for(editor);
    +                        autocomplete.inlineEnabled = true;
    +                        originalAutocompleteCommand(...arguments);
    +                    }
    +                } else if (!value) {
    +                    var autocomplete = Autocomplete.for(editor);
    +                    autocomplete.destroy();
    +                    Autocomplete.startCommand.exec = originalAutocompleteCommand;
    +                    originalAutocompleteCommand = null;
    +                }
    +            },
    +            getValue: function() {
    +                return !!originalAutocompleteCommand;
    +            }
    +        },
             "Show Textarea Position": devUtil.textPositionDebugger,
             "Text Input Debugger": devUtil.textInputDebugger,
         }
    @@ -468,8 +493,10 @@ optionsPanelContainer.insertBefore(
     );
     
     require("ace/ext/language_tools");
    +require("ace/ext/inline_autocomplete");
     env.editor.setOptions({
         enableBasicAutocompletion: true,
    +    enableInlineAutocompletion: true,
         enableSnippets: true
     });
     
    diff --git a/src/autocomplete.js b/src/autocomplete.js
    index 079c80c2300..91a35f159b4 100644
    --- a/src/autocomplete.js
    +++ b/src/autocomplete.js
    @@ -2,6 +2,7 @@
     
     var HashHandler = require("./keyboard/hash_handler").HashHandler;
     var AcePopup = require("./autocomplete/popup").AcePopup;
    +var AceInline = require("./autocomplete/inline").AceInline;
     var getAriaId = require("./autocomplete/popup").getAriaId;
     var util = require("./autocomplete/util");
     var lang = require("./lib/lang");
    @@ -9,11 +10,22 @@ var dom = require("./lib/dom");
     var snippetManager = require("./snippets").snippetManager;
     var config = require("./config");
     
    +var destroyCompleter = function(e, editor) {
    +    editor.completer && editor.completer.destroy();
    +};
    +
    +
    +/**
    + * This object controls the autocompletion components and their lifecycle.
    + * There is an autocompletion popup, an optional inline ghost text renderer and a docuent tooltip popup inside.
    + * @class
    + */
    +
     var Autocomplete = function() {
         this.autoInsert = false;
         this.autoSelect = true;
         this.exactMatch = false;
    -    this.gatherCompletionsId = 0;
    +    this.inlineEnabled = false;
         this.keyboardHandler = new HashHandler();
         this.keyboardHandler.bindKeys(this.commands);
     
    @@ -38,68 +50,138 @@ var Autocomplete = function() {
                 e.stop();
             }.bind(this));
             this.popup.focus = this.editor.focus.bind(this.editor);
    -        this.popup.on("show", this.tooltipTimer.bind(null, null));
    -        this.popup.on("select", this.tooltipTimer.bind(null, null));
    +        this.popup.on("show", this.$onPopupChange.bind(this));
    +        this.popup.on("hide", this.$onHidePopup.bind(this));
    +        this.popup.on("select", this.$onPopupChange.bind(this));
             this.popup.on("changeHoverMarker", this.tooltipTimer.bind(null, null));
             return this.popup;
         };
     
    +    this.$initInline = function() {
    +        if (!this.inlineEnabled || this.inlineRenderer)
    +            return;
    +        this.inlineRenderer = new AceInline();
    +        return this.inlineRenderer;
    +    };
    +
         this.getPopup = function() {
             return this.popup || this.$init();
         };
     
    +    this.$onHidePopup = function() {
    +        if (this.inlineRenderer) {
    +            this.inlineRenderer.hide();
    +        }
    +        this.hideDocTooltip();
    +    };
    +
    +    this.$onPopupChange = function(hide) {
    +        if (this.inlineRenderer && this.inlineEnabled) {
    +            var completion = hide ? null : this.popup.getData(this.popup.getRow());
    +            var prefix = util.getCompletionPrefix(this.editor);
    +            if (!this.inlineRenderer.show(this.editor, completion, prefix)) {
    +                this.inlineRenderer.hide();
    +            }
    +            this.$updatePopupPosition();
    +        }
    +        this.tooltipTimer.call(null, null);
    +    };
    +
    +    this.$updatePopupPosition = function() {
    +        var editor = this.editor;
    +        var renderer = editor.renderer;
    +
    +        var lineHeight = renderer.layerConfig.lineHeight;
    +        var pos = renderer.$cursorLayer.getPixelPosition(this.base, true);
    +        pos.left -= this.popup.getTextLeftOffset();
    +
    +        var rect = editor.container.getBoundingClientRect();
    +        pos.top += rect.top - renderer.layerConfig.offset;
    +        pos.left += rect.left - editor.renderer.scrollLeft;
    +        pos.left += renderer.gutterWidth;
    +
    +        var posGhostText = {
    +            top: pos.top,
    +            left: pos.left
    +        };
    +
    +        if (renderer.$ghostText && renderer.$ghostTextWidget) {
    +            if (this.base.row === renderer.$ghostText.position.row) {
    +                posGhostText.top += renderer.$ghostTextWidget.el.offsetHeight;
    +            }
    +        }
    +
    +        // Try to render below ghost text, then above ghost text, then over ghost text
    +        if (this.popup.tryShow(posGhostText, lineHeight, "bottom")) {
    +            return;
    +        }
    +
    +        if (this.popup.tryShow(pos, lineHeight, "top")) {
    +            return;
    +        }
    +        
    +        this.popup.show(pos, lineHeight);
    +    };
    +
         this.openPopup = function(editor, prefix, keepPopupPosition) {
             if (!this.popup)
                 this.$init();
     
    +        if (this.inlineEnabled && !this.inlineRenderer)
    +            this.$initInline();
    +
             this.popup.autoSelect = this.autoSelect;
     
             this.popup.setData(this.completions.filtered, this.completions.filterText);
    -        if (this.editor.textInput.setAriaOptions)
    -            this.editor.textInput.setAriaOptions({activeDescendant: getAriaId(this.popup.getRow())});
    +        if (this.editor.textInput.setAriaOptions) {
    +            this.editor.textInput.setAriaOptions({
    +                activeDescendant: getAriaId(this.popup.getRow()),
    +                inline: this.inlineEnabled
    +            });
    +        }
     
             editor.keyBinding.addKeyboardHandler(this.keyboardHandler);
             
    -        var renderer = editor.renderer;
             this.popup.setRow(this.autoSelect ? 0 : -1);
             if (!keepPopupPosition) {
                 this.popup.setTheme(editor.getTheme());
                 this.popup.setFontSize(editor.getFontSize());
     
    -            var lineHeight = renderer.layerConfig.lineHeight;
    -
    -            var pos = renderer.$cursorLayer.getPixelPosition(this.base, true);
    -            pos.left -= this.popup.getTextLeftOffset();
    -
    -            var rect = editor.container.getBoundingClientRect();
    -            pos.top += rect.top - renderer.layerConfig.offset;
    -            pos.left += rect.left - editor.renderer.scrollLeft;
    -            pos.left += renderer.gutterWidth;
    -
    -            this.popup.show(pos, lineHeight);
    +            this.$updatePopupPosition();
    +            if (this.tooltipNode) {
    +                this.updateDocTooltip();
    +            }
             } else if (keepPopupPosition && !prefix) {
                 this.detach();
             }
             this.changeTimer.cancel();
         };
     
    +    /**
    +     * Detaches all elements from the editor, and cleans up the data for the session
    +     */
         this.detach = function() {
    -        this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler);
    -        this.editor.off("changeSelection", this.changeListener);
    -        this.editor.off("blur", this.blurListener);
    -        this.editor.off("mousedown", this.mousedownListener);
    -        this.editor.off("mousewheel", this.mousewheelListener);
    +        if (this.editor) {
    +            this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler);
    +            this.editor.off("changeSelection", this.changeListener);
    +            this.editor.off("blur", this.blurListener);
    +            this.editor.off("mousedown", this.mousedownListener);
    +            this.editor.off("mousewheel", this.mousewheelListener);
    +        }
             this.changeTimer.cancel();
             this.hideDocTooltip();
     
    -        this.gatherCompletionsId += 1;
    +        if (this.completionProvider) {
    +            this.completionProvider.detach();
    +        }
    +
             if (this.popup && this.popup.isOpen)
                 this.popup.hide();
     
             if (this.base)
                 this.base.detach();
             this.activated = false;
    -        this.completions = this.base = null;
    +        this.completionProvider = this.completions = this.base = null;
         };
     
         this.changeListener = function(e) {
    @@ -144,34 +226,14 @@ var Autocomplete = function() {
                 data = this.popup.getData(this.popup.getRow());
             if (!data)
                 return false;
    -
             var completions = this.completions;
    -        this.editor.startOperation({command: {name: "insertMatch"}});
    -        if (data.completer && data.completer.insertMatch) {
    -            data.completer.insertMatch(this.editor, data);
    -        } else {
    -            // TODO add support for options.deleteSuffix
    -            if (!completions)
    -                return false;
    -            if (completions.filterText) {
    -                var ranges = this.editor.selection.getAllRanges();
    -                for (var i = 0, range; range = ranges[i]; i++) {
    -                    range.start.column -= completions.filterText.length;
    -                    this.editor.session.remove(range);
    -                }
    -            }
    -            if (data.snippet)
    -                snippetManager.insertSnippet(this.editor, data.snippet);
    -            else
    -                this.editor.execCommand("insertstring", data.value || data);
    -        }
    +        var result = this.getCompletionProvider().insertMatch(this.editor, data, completions.filterText, options);
             // detach only if new popup was not opened while inserting match
             if (this.completions == completions)
                 this.detach();
    -        this.editor.endOperation();
    +        return result;
         };
     
    -
         this.commands = {
             "Up": function(editor) { editor.completer.goTo("up"); },
             "Down": function(editor) { editor.completer.goTo("down"); },
    @@ -193,32 +255,11 @@ var Autocomplete = function() {
             "PageDown": function(editor) { editor.completer.popup.gotoPageDown(); }
         };
     
    -    this.gatherCompletions = function(editor, callback) {
    -        var session = editor.getSession();
    -        var pos = editor.getCursorPosition();
    -
    -        var prefix = util.getCompletionPrefix(editor);
    -
    -        this.base = session.doc.createAnchor(pos.row, pos.column - prefix.length);
    -        this.base.$insertRight = true;
    -
    -        var matches = [];
    -        var total = editor.completers.length;
    -        editor.completers.forEach(function(completer, i) {
    -            completer.getCompletions(editor, session, pos, prefix, function(err, results) {
    -                if (!err && results)
    -                    matches = matches.concat(results);
    -                // Fetch prefix again, because they may have changed by now
    -                callback(null, {
    -                    prefix: util.getCompletionPrefix(editor),
    -                    matches: matches,
    -                    finished: (--total === 0)
    -                });
    -            });
    -        });
    -        return true;
    -    };
    -
    +    /**
    +     * This is the entry point for the autocompletion class, triggers the actions which collect and display suggestions
    +     * @param {Editor} editor
    +     * @param {CompletionOptions} options
    +     */
         this.showPopup = function(editor, options) {
             if (this.editor)
                 this.detach();
    @@ -240,6 +281,21 @@ var Autocomplete = function() {
             this.updateCompletions(false, options);
         };
     
    +    this.getCompletionProvider = function() {
    +        if (!this.completionProvider)
    +            this.completionProvider = new CompletionProvider();
    +        return this.completionProvider;
    +    };
    +
    +    /**
    +     * This method is deprecated, it is only kept for backwards compatibility.
    +     * Use the same method include CompletionProvider instead for the same functionality.
    +     * @deprecated
    +     */
    +    this.gatherCompletions = function(editor, callback) {
    +        return this.getCompletionProvider().gatherCompletions(editor, callback);
    +    };
    +
         this.updateCompletions = function(keepPopupPosition, options) {
             if (keepPopupPosition && this.base && this.completions) {
                 var pos = this.editor.getCursorPosition();
    @@ -265,70 +321,32 @@ var Autocomplete = function() {
                 return this.openPopup(this.editor, "", keepPopupPosition);
             }
     
    -        // Save current gatherCompletions session, session is close when a match is insert
    -        var _id = this.gatherCompletionsId;
    -
    -        // Only detach if result gathering is finished
    -        var detachIfFinished = function(results) {
    -            if (!results.finished) return;
    -            return this.detach();
    -        }.bind(this);
    -
    -        var processResults = function(results) {
    -            var prefix = results.prefix;
    -            var matches = results.matches;
    -
    -            this.completions = new FilteredList(matches);
    -
    -            if (this.exactMatch)
    -                this.completions.exactMatch = true;
    -
    -            this.completions.setFilter(prefix);
    -            var filtered = this.completions.filtered;
    -
    -            // No results
    -            if (!filtered.length)
    -                return detachIfFinished(results);
    -
    -            // One result equals to the prefix
    -            if (filtered.length == 1 && filtered[0].value == prefix && !filtered[0].snippet)
    -                return detachIfFinished(results);
    -
    -            // Autoinsert if one result
    -            if (this.autoInsert && filtered.length == 1 && results.finished)
    -                return this.insertMatch(filtered[0]);
    -
    -            this.openPopup(this.editor, prefix, keepPopupPosition);
    -        }.bind(this);
    -
    -        var isImmediate = true;
    -        var immediateResults = null;
    -        this.gatherCompletions(this.editor, function(err, results) {
    -            var prefix = results.prefix;
    -            var matches = results && results.matches;
    -
    -            if (!matches || !matches.length)
    -                return detachIfFinished(results);
    -
    -            // Wrong prefix or wrong session -> ignore
    -            if (prefix.indexOf(results.prefix) !== 0 || _id != this.gatherCompletionsId)
    -                return;
    -
    -            // If multiple completers return their results immediately, we want to process them together
    -            if (isImmediate) {
    -                immediateResults = results;
    -                return;
    +        var session = this.editor.getSession();
    +        var pos = this.editor.getCursorPosition();
    +        var prefix = util.getCompletionPrefix(this.editor);
    +        this.base = session.doc.createAnchor(pos.row, pos.column - prefix.length);
    +        this.base.$insertRight = true;
    +        var completionOptions = { exactMatch: this.exactMatch };
    +        this.getCompletionProvider().provideCompletions(this.editor, completionOptions, function(err, completions, finished) {
    +            var filtered = completions.filtered;
    +            var prefix = util.getCompletionPrefix(this.editor);
    +
    +            if (finished) {
    +                // No results
    +                if (!filtered.length)
    +                    return this.detach();
    +
    +                // One result equals to the prefix
    +                if (filtered.length == 1 && filtered[0].value == prefix && !filtered[0].snippet)
    +                    return this.detach();
    +
    +                // Autoinsert if one result
    +                if (this.autoInsert && filtered.length == 1)
    +                    return this.insertMatch(filtered[0]);
                 }
    -
    -            processResults(results);
    +            this.completions = completions;
    +            this.openPopup(this.editor, prefix, keepPopupPosition);
             }.bind(this));
    -        
    -        isImmediate = false;
    -        if (immediateResults) {
    -            var results = immediateResults;
    -            immediateResults = null;
    -            processResults(results);
    -        }
         };
     
         this.cancelContextMenu = function() {
    @@ -437,27 +455,31 @@ var Autocomplete = function() {
                 if (el && el.parentNode)
                     el.parentNode.removeChild(el);
             }
    -        if (this.editor && this.editor.completer == this)
    -            this.editor.completer == null;
    -        this.popup = null;
    +        if (this.editor && this.editor.completer == this) {
    +            this.editor.off("destroy", destroyCompleter);
    +            this.editor.completer = null;
    +        }
    +        this.inlineRenderer = this.popup = this.editor = null;
         };
     
     }).call(Autocomplete.prototype);
     
     
     Autocomplete.for = function(editor) {
    -    if (editor.completer) {
    +    if (editor.completer instanceof Autocomplete) {
             return editor.completer;
         }
    +    if (editor.completer) {
    +        editor.completer.destroy();
    +        editor.completer = null;
    +    }
         if (config.get("sharedPopups")) {
    -        if (!Autocomplete.$shared)
    +        if (!Autocomplete.$sharedInstance)
                 Autocomplete.$sharedInstance = new Autocomplete();
             editor.completer = Autocomplete.$sharedInstance;
         } else {
             editor.completer = new Autocomplete();
    -        editor.once("destroy", function(e, editor) {
    -            editor.completer.destroy();
    -        });
    +        editor.once("destroy", destroyCompleter);
         }
         return editor.completer;
     };
    @@ -475,11 +497,143 @@ Autocomplete.startCommand = {
         bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space"
     };
     
    +/**
    + * This class is responsible for providing completions and inserting them to the editor
    + * @class
    + */
    +
    +var CompletionProvider = function() {
    +    this.active = true;
    +};
    +
    +(function() {
    +    this.insertByIndex = function(editor, index, options) {
    +        if (!this.completions || !this.completions.filtered) {
    +            return false;
    +        }
    +        return this.insertMatch(editor, this.completions.filtered[index], options);
    +    };
    +
    +    this.insertMatch = function(editor, data, options) {
    +        if (!data)
    +            return false;
    +
    +        editor.startOperation({command: {name: "insertMatch"}});
    +        if (data.completer && data.completer.insertMatch) {
    +            data.completer.insertMatch(editor, data);
    +        } else {
    +            // TODO add support for options.deleteSuffix
    +            if (!this.completions) {
    +                return false;
    +            }
    +            if (this.completions.filterText) {
    +                var ranges = editor.selection.getAllRanges();
    +                for (var i = 0, range; range = ranges[i]; i++) {
    +                    range.start.column -= this.completions.filterText.length;
    +                    editor.session.remove(range);
    +                }
    +            }
    +            if (data.snippet)
    +                snippetManager.insertSnippet(editor, data.snippet);
    +            else
    +                editor.execCommand("insertstring", data.value || data);
    +        }
    +        editor.endOperation();
    +        return true;
    +    };
    +
    +    this.gatherCompletions = function(editor, callback) {
    +        var session = editor.getSession();
    +        var pos = editor.getCursorPosition();
    +    
    +        var prefix = util.getCompletionPrefix(editor);
    +    
    +        var matches = [];
    +        var total = editor.completers.length;
    +        editor.completers.forEach(function(completer, i) {
    +            completer.getCompletions(editor, session, pos, prefix, function(err, results) {
    +                if (!err && results)
    +                    matches = matches.concat(results);
    +                // Fetch prefix again, because they may have changed by now
    +                callback(null, {
    +                    prefix: util.getCompletionPrefix(editor),
    +                    matches: matches,
    +                    finished: (--total === 0)
    +                });
    +            });
    +        });
    +        return true;
    +    };
    +
    +    /**
    +     * This is the entry point to the class, it gathers, then provides the completions asynchronously via callback.
    +     * The callback function may be called multiple times, the last invokation is marked with a `finished` flag
    +     * @param {Editor} editor
    +     * @param {CompletionProviderOptions} options
    +     * @param {CompletionProviderCallback} callback
    +     */
    +    this.provideCompletions = function(editor, options, callback) {
    +        var processResults = function(results) {
    +            var prefix = results.prefix;
    +            var matches = results.matches;
    +
    +            this.completions = new FilteredList(matches);
    +
    +            if (options.exactMatch)
    +                this.completions.exactMatch = true;
    +
    +            if (options.ignoreCaption)
    +                this.completions.ignoreCaption = true;
    +
    +            this.completions.setFilter(prefix);
    +
    +            callback(null, this.completions, results.finished);
    +        }.bind(this);
    +
    +        var isImmediate = true;
    +        var immediateResults = null;
    +        this.gatherCompletions(editor, function(err, results) {
    +            if (!this.active) {
    +                return;
    +            }
    +            if (err) {
    +                callback(err, [], true);
    +                this.detach();
    +            }
    +            var prefix = results.prefix;
    +
    +            // Wrong prefix or wrong session -> ignore
    +            if (prefix.indexOf(results.prefix) !== 0)
    +                return;
    +
    +            // If multiple completers return their results immediately, we want to process them together
    +            if (isImmediate) {
    +                immediateResults = results;
    +                return;
    +            }
    +
    +            processResults(results);
    +        }.bind(this));
    +        
    +        isImmediate = false;
    +        if (immediateResults) {
    +            var results = immediateResults;
    +            immediateResults = null;
    +            processResults(results);
    +        }
    +    };
    +
    +    this.detach = function() {
    +        this.active = false;
    +    };
    +}).call(CompletionProvider.prototype);
    +
     var FilteredList = function(array, filterText) {
         this.all = array;
         this.filtered = array;
         this.filterText = filterText || "";
         this.exactMatch = false;
    +    this.ignoreCaption = false;
     };
     (function(){
         this.setFilter = function(str) {
    @@ -506,12 +660,13 @@ var FilteredList = function(array, filterText) {
     
             this.filtered = matches;
         };
    +
         this.filterCompletions = function(items, needle) {
             var results = [];
             var upper = needle.toUpperCase();
             var lower = needle.toLowerCase();
             loop: for (var i = 0, item; item = items[i]; i++) {
    -            var caption = item.caption || item.value || item.snippet;
    +            var caption = (!this.ignoreCaption && item.caption) || item.value || item.snippet;
                 if (!caption) continue;
                 var lastIndex = -1;
                 var matchMask = 0;
    @@ -560,4 +715,5 @@ var FilteredList = function(array, filterText) {
     }).call(FilteredList.prototype);
     
     exports.Autocomplete = Autocomplete;
    +exports.CompletionProvider = CompletionProvider;
     exports.FilteredList = FilteredList;
    diff --git a/src/autocomplete/inline.js b/src/autocomplete/inline.js
    new file mode 100644
    index 00000000000..e161b4df5e1
    --- /dev/null
    +++ b/src/autocomplete/inline.js
    @@ -0,0 +1,73 @@
    +"use strict";
    +
    +var snippetManager = require("../snippets").snippetManager;
    +
    +/**
    + * This object is used to manage inline code completions rendered into an editor with ghost text.
    + * @class
    + */
    +
    +/**
    + * Creates the inline completion renderer which renders the inline code completions directly in the target editor.
    + * @constructor
    + */
    +
    +var AceInline = function() {
    +    this.editor = null;
    +};
    +
    +(function() {
    +
    +    /**
    +     * Renders the completion as ghost text to the current cursor position
    +     * @param {Editor} editor
    +     * @param {Completion} completion
    +     * @param {string} prefix
    +     * @returns {boolean} True if the completion could be rendered to the editor, false otherwise
    +     */
    +    this.show = function(editor, completion, prefix) {
    +        prefix = prefix || "";
    +        if (editor && this.editor && this.editor !== editor) {
    +            this.hide();
    +            this.editor = null;
    +        }
    +        if (!editor || !completion) {
    +            return false;
    +        }
    +        var displayText = completion.snippet ? snippetManager.getDisplayTextForSnippet(editor, completion.snippet) : completion.value;
    +        if (!displayText || !displayText.startsWith(prefix)) {
    +            return false;
    +        }
    +        this.editor = editor;
    +        displayText = displayText.slice(prefix.length);
    +        if (displayText === "") {
    +            editor.removeGhostText();
    +        } else {
    +            editor.setGhostText(displayText);
    +        }
    +        return true;
    +    };
    +
    +    this.isOpen = function() {
    +        if (!this.editor) {
    +            return false;
    +        }
    +        return !!this.editor.renderer.$ghostText;
    +    };
    +
    +    this.hide = function() {
    +        if (!this.editor) {
    +            return false;
    +        }
    +        this.editor.removeGhostText();
    +        return true;
    +    };
    +
    +    this.destroy = function() {
    +        this.hide();
    +        this.editor = null;
    +    };
    +}).call(AceInline.prototype);
    +
    +
    +exports.AceInline = AceInline;
    diff --git a/src/autocomplete/inline_test.js b/src/autocomplete/inline_test.js
    new file mode 100644
    index 00000000000..18b9e6d7e00
    --- /dev/null
    +++ b/src/autocomplete/inline_test.js
    @@ -0,0 +1,236 @@
    +if (typeof process !== "undefined") {
    +    require("amd-loader");
    +    require("../test/mockdom");
    +}
    +
    +"use strict";
    +
    +var assert = require("../test/assertions");
    +var AceInline = require("./inline").AceInline;
    +var Editor = require("../ace").Editor;
    +var EditSession = require("../ace").EditSession;
    +var VirtualRenderer = require("../ace").VirtualRenderer;
    +
    +var editor;
    +var editor2;
    +var inline;
    +
    +var textBase = "abc123\n\n    ";
    +
    +var completions = [
    +    {
    +        value: "foo",
    +        score: 4
    +    },
    +    {
    +        value: "function",
    +        score: 3
    +    },
    +    {
    +        value: "foobar",
    +        score: 2
    +    },
    +    {
    +        snippet: "function foo() {\n    console.log('test');\n}",
    +        score: 1
    +    },
    +    {
    +        snippet: "foobar2",
    +        score: 0
    +    }
    +];
    +
    +var getAllLines = function(editorOverride) {
    +    editorOverride = editorOverride || editor;
    +    return editorOverride.renderer.$textLayer.element.childNodes.map(function (node) {
    +        return node.textContent;
    +    }).join("\n");
    +};
    +
    +var createEditor = function(element) {
    +    var renderer = new VirtualRenderer(element);
    +    var session = new EditSession("");
    +    return new Editor(renderer, session);
    +};
    +
    +module.exports = {
    +    setUp: function(done) {
    +        var el = document.createElement("div");
    +        el.style.left = "20px";
    +        el.style.top = "30px";
    +        el.style.width = "500px";
    +        el.style.height = "500px";
    +        document.body.appendChild(el);
    +        editor = createEditor(el);
    +        editor.execCommand("insertstring", textBase + "f");
    +        inline = new AceInline();
    +        editor.getSelection().moveCursorFileEnd();
    +        editor.renderer.$loop._flush();
    +        done();
    +    },
    +    "test: displays the ghost text in the editor on show": function(done) {
    +        inline.show(editor, completions[0], "f");
    +        editor.renderer.$loop._flush();
    +        assert.equal(getAllLines(), textBase + "foo");
    +        done();
    +    },
    +    "test: replaces the ghost text in the editor with the latest show": function(done) {
    +        inline.show(editor, completions[0], "f");
    +        editor.renderer.$loop._flush();
    +        assert.equal(getAllLines(), textBase + "foo");
    +        inline.show(editor, completions[1], "f");
    +        editor.renderer.$loop._flush();
    +        assert.equal(getAllLines(), textBase + "function");
    +        done();
    +    },
    +    "test: renders multi-line ghost text indentation": function(done) {
    +        assert.equal(editor.renderer.$ghostTextWidget, null);
    +        inline.show(editor, completions[3], "f");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(getAllLines(), textBase + "function foo() {");
    +        assert.strictEqual(editor.renderer.$ghostTextWidget.text, "        console.log('test');\n    }");
    +        assert.strictEqual(editor.renderer.$ghostTextWidget.el.textContent, "        console.log('test');\n    }");
    +        done();
    +    },
    +    "test: boundary tests": function(done) {
    +        var noRenderTestCases = [
    +            [null, null, null],
    +            [editor, null, null],
    +            [editor, null, ""],
    +            [null, completions[3], ""]
    +        ];
    +        var result;
    +        noRenderTestCases.forEach(function(params) {
    +            result = inline.show(params[0], params[1], params[2]);
    +            editor.renderer.$loop._flush();
    +            assert.notOk(result);
    +            assert.equal(editor.renderer.$ghostText, null);
    +            assert.equal(editor.renderer.$ghostTextWidget, null);
    +        });
    +
    +        var renderTestCases = [
    +            [editor, completions[1], undefined],
    +            [editor, completions[1], null],
    +            [editor, completions[1], ""]
    +        ];
    +        renderTestCases.forEach(function(params) {
    +            result = inline.show(params[0], params[1], params[2]);
    +            editor.renderer.$loop._flush();
    +            assert.ok(result);
    +            assert.strictEqual(editor.renderer.$ghostText.text, "function");
    +            assert.strictEqual(getAllLines(), textBase + "ffunction");
    +            assert.equal(editor.renderer.$ghostTextWidget, null);
    +        });
    +
    +        result = inline.show(editor, completions[0], "foo");
    +        editor.renderer.$loop._flush();
    +        assert.ok(result);
    +        assert.equal(editor.renderer.$ghostText, null);
    +        assert.equal(editor.renderer.$ghostTextWidget, null);
    +        
    +        done();
    +    },
    +    "test: only renders the ghost text without the prefix": function(done) {
    +        inline.show(editor, completions[1], "fun");
    +        editor.renderer.$loop._flush();
    +        assert.equal(getAllLines(), textBase + "fction");
    +        done();
    +    },
    +    "test: verify explicit and implicit hide": function(done) {
    +        inline.show(editor, completions[1], "f");
    +        editor.renderer.$loop._flush();
    +        assert.equal(getAllLines(), textBase + "function");
    +        assert.strictEqual(inline.isOpen(), true);
    +        inline.hide();
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(getAllLines(), textBase + "f");
    +        assert.strictEqual(inline.isOpen(), false);
    +
    +        inline.show(editor, completions[1], "function");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(getAllLines(), textBase + "f");
    +        assert.strictEqual(inline.isOpen(), false);
    +        done();
    +    },
    +    "test: does not hide previous ghost text if cannot show current one": function(done) {
    +        inline.show(editor, completions[1], "f");
    +        editor.renderer.$loop._flush();
    +        assert.equal(getAllLines(), textBase + "function");
    +        assert.strictEqual(inline.isOpen(), true);
    +        inline.show(editor, null, "");
    +        editor.renderer.$loop._flush();
    +        assert.equal(getAllLines(), textBase + "function");
    +        assert.strictEqual(inline.isOpen(), true);
    +        inline.hide();
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(getAllLines(), textBase + "f");
    +        assert.strictEqual(inline.isOpen(), false);
    +        done();
    +    },
    +    "test: removes ghost text from previous editor if new valid editor is passed to show function": function(done) {
    +        var el = document.createElement("div");
    +        el.style.left = "520px";
    +        el.style.top = "530px";
    +        el.style.width = "500px";
    +        el.style.height = "500px";
    +        document.body.appendChild(el);
    +        editor2 = createEditor(el);
    +        var editor2Text = "different text\n\n    f";
    +        editor2.execCommand("insertstring", editor2Text);
    +
    +        inline.show(editor, completions[1], "f");
    +        editor.renderer.$loop._flush();
    +        editor2.renderer.$loop._flush();
    +        assert.strictEqual(getAllLines(), textBase + "function");
    +        assert.strictEqual(getAllLines(editor2), editor2Text);
    +        assert.strictEqual(inline.isOpen(), true);
    +
    +        inline.show(editor2, completions[2], "f");
    +        editor.renderer.$loop._flush();
    +        editor2.renderer.$loop._flush();
    +        assert.strictEqual(getAllLines(), textBase + "f");
    +        assert.strictEqual(getAllLines(editor2), editor2Text + "oobar");
    +        assert.strictEqual(inline.isOpen(), true);
    +
    +        inline.show(null, completions[2], "f");
    +        editor.renderer.$loop._flush();
    +        editor2.renderer.$loop._flush();
    +        assert.strictEqual(getAllLines(), textBase + "f");
    +        assert.strictEqual(getAllLines(editor2), editor2Text + "oobar");
    +        assert.strictEqual(inline.isOpen(), true);
    +
    +        done();
    +    },
    +    "test: verify destroy": function(done) {
    +        inline.show(editor, completions[0], "f");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(getAllLines(), textBase + "foo");
    +
    +        inline.destroy();
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(inline.isOpen(), false);
    +        assert.strictEqual(getAllLines(), textBase + "f");
    +
    +        inline.destroy();
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(inline.isOpen(), false);
    +        assert.strictEqual(getAllLines(), textBase + "f");
    +
    +        inline.hide();
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(inline.isOpen(), false);
    +        assert.strictEqual(getAllLines(), textBase + "f");
    +        done();
    +    },
    +    tearDown: function() {
    +        inline.destroy();
    +        editor.destroy();
    +        if (editor2) {
    +            editor2.destroy();
    +        }
    +    }
    +};
    +
    +if (typeof module !== "undefined" && module === require.main) {
    +    require("asyncjs").test.testcase(module.exports).exec();
    +}
    diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js
    index c3f76248c93..8e0dc400118 100644
    --- a/src/autocomplete/popup.js
    +++ b/src/autocomplete/popup.js
    @@ -256,27 +256,82 @@ var AcePopup = function(parentNode) {
     
         popup.hide = function() {
             this.container.style.display = "none";
    -        this._signal("hide");
    -        popup.isOpen = false;
    +        popup.anchorPos = null;
    +        popup.anchor = null;
    +        if (popup.isOpen) {
    +            popup.isOpen = false;
    +            this._signal("hide");
    +        }
         };
    -    popup.show = function(pos, lineHeight, topdownOnly) {
    +
    +    /**
    +     * Tries to show the popup anchored to the given position and anchors.
    +     * If the anchor is not specified it tries to align to bottom and right as much as possible.
    +     * If the popup does not have enough space to be rendered with the given anchors, it returns false without rendering the popup.
    +     * The forceShow flag can be used to render the popup in these cases, which slides the popup so it entirely fits on the screen.
    +     * @param {Point} pos
    +     * @param {number} lineHeight
    +     * @param {"top" | "bottom" | undefined} anchor
    +     * @param {boolean} forceShow
    +     * @returns {boolean}
    +     */
    +    popup.tryShow = function(pos, lineHeight, anchor, forceShow) {
    +        if (!forceShow && popup.isOpen && popup.anchorPos && popup.anchor &&
    +            popup.anchorPos.top === pos.top && popup.anchorPos.left === pos.left &&
    +            popup.anchor === anchor
    +        ) {
    +            return true;
    +        }
    +
             var el = this.container;
             var screenHeight = window.innerHeight;
             var screenWidth = window.innerWidth;
             var renderer = this.renderer;
             // var maxLines = Math.min(renderer.$maxLines, this.session.getLength());
             var maxH = renderer.$maxLines * lineHeight * 1.4;
    -        var top = pos.top + this.$borderSize;
    -        var allowTopdown = top > screenHeight / 2 && !topdownOnly;
    -        if (allowTopdown && top + lineHeight + maxH > screenHeight) {
    -            renderer.$maxPixelHeight = top - 2 * this.$borderSize;
    +        var dims = { top: 0, bottom: 0, left: 0 };
    +
    +        var spaceBelow = screenHeight - pos.top - 3 * this.$borderSize - lineHeight;
    +        var spaceAbove = pos.top - 3 * this.$borderSize;
    +        if (!anchor) {
    +            if (spaceAbove <= spaceBelow || spaceBelow >= maxH) {
    +                anchor = "bottom";
    +            } else {
    +                anchor = "top";
    +            }
    +        }
    +
    +        if (anchor === "top") {
    +            dims.bottom = pos.top - this.$borderSize;
    +            dims.top = dims.bottom - maxH;
    +        } else if (anchor === "bottom") {
    +            dims.top = pos.top + lineHeight + this.$borderSize;
    +            dims.bottom = dims.top + maxH;
    +        }
    +
    +        var fitsX = dims.top >= 0 && dims.bottom <= screenHeight;
    +
    +        if (!forceShow && !fitsX) {
    +            return false;
    +        }
    +
    +        if (!fitsX) {
    +            if (anchor === "top") {
    +                renderer.$maxPixelHeight = spaceAbove;
    +            } else {
    +                renderer.$maxPixelHeight = spaceBelow;
    +            }
    +        } else {
    +            renderer.$maxPixelHeight = null;
    +        }
    +
    +
    +        if (anchor === "top") {
                 el.style.top = "";
    -            el.style.bottom = screenHeight - top + "px";
    +            el.style.bottom = (screenHeight - dims.bottom) + "px";
                 popup.isTopdown = false;
             } else {
    -            top += lineHeight;
    -            renderer.$maxPixelHeight = screenHeight - top - 0.2 * lineHeight;
    -            el.style.top = top + "px";
    +            el.style.top = dims.top + "px";
                 el.style.bottom = "";
                 popup.isTopdown = true;
             }
    @@ -288,10 +343,22 @@ var AcePopup = function(parentNode) {
                 left = screenWidth - el.offsetWidth;
     
             el.style.left = left + "px";
    +        el.style.right = "";
     
    -        this._signal("show");
    -        lastMouseEvent = null;
    -        popup.isOpen = true;
    +        if (!popup.isOpen) {
    +            popup.isOpen = true;
    +            this._signal("show");
    +            lastMouseEvent = null;
    +        }
    +
    +        popup.anchorPos = pos;
    +        popup.anchor = anchor;
    +
    +        return true;
    +    };
    +
    +    popup.show = function(pos, lineHeight, topdownOnly) {
    +        this.tryShow(pos, lineHeight, topdownOnly ? "bottom" : undefined, true);
         };
     
         popup.goTo = function(where) {
    diff --git a/src/autocomplete/popup_test.js b/src/autocomplete/popup_test.js
    new file mode 100644
    index 00000000000..8c4ee962ee4
    --- /dev/null
    +++ b/src/autocomplete/popup_test.js
    @@ -0,0 +1,217 @@
    +if (typeof process !== "undefined") {
    +    require("amd-loader");
    +    require("../test/mockdom");
    +}
    +
    +"use strict";
    +
    +var assert = require("../test/assertions");
    +var AcePopup = require("./popup").AcePopup;
    +
    +var popup;
    +var lineHeight = 14;
    +var renderHeight = 8 * lineHeight;
    +var renderWidth = 300;
    +var iframe;
    +
    +var notEnoughSpaceOnRight = window.innerWidth - 50;
    +var notEnoughSpaceOnBottom = window.innerHeight - 50;
    +
    +var originalDocument;
    +
    +var completions = [];
    +
    +for (var i = 0; i < 8; i++) {
    +    completions.push({ value: "foo" + i, caption: "foo" + i, name: "foo" + i, score: 4 });
    +}
    +
    +var tryShowAndRender = function(pos, lineHeight, anchor, forceShow) {
    +    var result = popup.tryShow(pos, lineHeight, anchor, forceShow);
    +    popup.renderer.updateFull(true);
    +    return result;
    +};
    +
    +
    +var setupPopup = function() {
    +    popup = new AcePopup(document.body);
    +
    +    // Mock the CSS behaviour
    +    popup.container.style.width = "300px";
    +    popup.setData(completions, "");
    +};
    +
    +var tearDown = function(done) {
    +    if (popup) {
    +        var el = popup.container;
    +        if (el && el.parentNode)
    +            el.parentNode.removeChild(el);
    +    }
    +    if (iframe)
    +        document.body.removeChild(iframe);
    +    if (originalDocument) {
    +        window.document = originalDocument;
    +        originalDocument = null;
    +    }
    +    done && done();
    +};
    +
    +module.exports = {
    +    "test: verify width and height": function(done) {
    +        setupPopup();
    +        tryShowAndRender({ top: 0, left: 0 }, lineHeight, "bottom");
    +        renderHeight = popup.container.offsetHeight;
    +        assert.strictEqual(popup.isOpen, true);
    +        assert.strictEqual(renderHeight > 0, true);
    +        popup.hide();
    +        assert.strictEqual(popup.isOpen, false);
    +        done();
    +    },
    +    "test: tryShow does not display popup if there is not enough space on the anchor side": function(done) {
    +        setupPopup();
    +        var result = tryShowAndRender({ top: notEnoughSpaceOnBottom, left: 0}, lineHeight, "bottom");
    +        assert.strictEqual(result, false);
    +        assert.strictEqual(popup.isOpen, false);
    +        result = tryShowAndRender({ top: 50, left: 0}, lineHeight, "top");
    +        assert.strictEqual(result, false);
    +        assert.strictEqual(popup.isOpen, false);
    +        done();
    +    },
    +    "test: tryShow slides popup on the X axis if there are not enough space on the right": function(done) {
    +        setupPopup();
    +        
    +        var result = tryShowAndRender({ top: 0, left: notEnoughSpaceOnRight }, lineHeight, "bottom");
    +        assert.strictEqual(result, true);
    +        assert.strictEqual(popup.isOpen, true);
    +        assert.strictEqual(popup.container.getBoundingClientRect().right, window.innerWidth);
    +        assert.strictEqual(Math.abs(popup.container.getBoundingClientRect().width - renderWidth) < 5, true);
    +        popup.hide();
    +        assert.strictEqual(popup.isOpen, false);
    +
    +        result = tryShowAndRender({ top: notEnoughSpaceOnBottom, left: notEnoughSpaceOnRight }, lineHeight, "top");
    +        assert.strictEqual(result, true);
    +        assert.strictEqual(popup.isOpen, true);
    +        assert.strictEqual(popup.container.getBoundingClientRect().right, window.innerWidth);
    +        assert.strictEqual(Math.abs(popup.container.getBoundingClientRect().width - renderWidth) < 5, true);
    +        popup.hide();
    +        assert.strictEqual(popup.isOpen, false);
    +        done();
    +    },
    +    "test: tryShow called with forceShow resizes popup height to fit popup": function(done) {
    +        setupPopup();
    +        
    +        var result = tryShowAndRender({ top: notEnoughSpaceOnBottom, left: 0 }, lineHeight, "bottom", true);
    +        assert.strictEqual(result, true);
    +        assert.strictEqual(popup.isOpen, true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.strictEqual(popup.container.getBoundingClientRect().height <= 50, true);
    +        assert.strictEqual(popup.container.getBoundingClientRect().top > notEnoughSpaceOnBottom + lineHeight, true);
    +        assert.strictEqual(Math.abs(popup.container.getBoundingClientRect().width - renderWidth) < 5, true);
    +        popup.hide();
    +        assert.strictEqual(popup.isOpen, false);
    +
    +        result = tryShowAndRender({ top: 50, left: 0 }, lineHeight, "top", true);
    +        assert.strictEqual(result, true);
    +        assert.strictEqual(popup.isOpen, true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.strictEqual(popup.container.getBoundingClientRect().height <= 50, true);
    +        assert.strictEqual(popup.container.getBoundingClientRect().bottom <= 50, true);
    +        assert.strictEqual(Math.abs(popup.container.getBoundingClientRect().width - renderWidth) < 5, true);
    +        popup.hide();
    +        assert.strictEqual(popup.isOpen, false);
    +        done();
    +    },
    +    "test: show displays popup in all 4 corners correctly without topdownOnly specified": function(done) {
    +        setupPopup();
    +        popup.show({ top: 50, left: 0 }, lineHeight);
    +        popup.renderer.updateFull(true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.strictEqual(popup.container.getBoundingClientRect().height, renderHeight);
    +        assert.ok(popup.container.getBoundingClientRect().top >= 50 + lineHeight);
    +        popup.hide();
    +        assert.strictEqual(popup.container.style.display, "none");
    +
    +        popup.show({ top: notEnoughSpaceOnBottom, left: 0 }, lineHeight);
    +        popup.renderer.updateFull(true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.strictEqual(popup.container.getBoundingClientRect().height, renderHeight);
    +        assert.ok(popup.container.getBoundingClientRect().bottom <= notEnoughSpaceOnBottom);
    +        popup.hide();
    +        assert.strictEqual(popup.container.style.display, "none");
    +
    +        popup.show({ top: 50, left: notEnoughSpaceOnRight }, lineHeight);
    +        popup.renderer.updateFull(true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.strictEqual(popup.container.getBoundingClientRect().height, renderHeight);
    +        assert.ok(popup.container.getBoundingClientRect().top >= 50 + lineHeight);
    +        popup.hide();
    +        assert.strictEqual(popup.container.style.display, "none");
    +
    +        popup.show({ top: notEnoughSpaceOnBottom, left: notEnoughSpaceOnRight }, lineHeight);
    +        popup.renderer.updateFull(true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.strictEqual(popup.container.getBoundingClientRect().height, renderHeight);
    +        assert.ok(popup.container.getBoundingClientRect().bottom <= notEnoughSpaceOnBottom);
    +        popup.hide();
    +        assert.strictEqual(popup.container.style.display, "none");
    +        done();
    +    },
    +    "test: show displays popup in all 4 corners correctly with topdownOnly specified": function(done) {
    +        setupPopup();
    +        popup.show({ top: 50, left: 0 }, lineHeight, true);
    +        popup.renderer.updateFull(true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.strictEqual(popup.container.getBoundingClientRect().height, renderHeight);
    +        assert.ok(popup.container.getBoundingClientRect().top >= 50 + lineHeight);
    +        popup.hide();
    +        assert.strictEqual(popup.container.style.display, "none");
    +
    +        popup.show({ top: 50, left: notEnoughSpaceOnRight }, lineHeight);
    +        popup.renderer.updateFull(true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.strictEqual(popup.container.getBoundingClientRect().height, renderHeight);
    +        assert.ok(popup.container.getBoundingClientRect().top >= 50 + lineHeight);
    +        popup.hide();
    +        assert.strictEqual(popup.container.style.display, "none");
    +
    +        popup.show({ top: notEnoughSpaceOnBottom, left: 0 }, lineHeight, true);
    +        popup.renderer.updateFull(true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.ok(popup.container.getBoundingClientRect().height <= 50);
    +        assert.ok(popup.container.getBoundingClientRect().top >= notEnoughSpaceOnBottom + lineHeight);
    +        popup.hide();
    +        assert.strictEqual(popup.container.style.display, "none");
    +
    +        popup.show({ top: notEnoughSpaceOnBottom, left: notEnoughSpaceOnRight }, lineHeight, true);
    +        popup.renderer.updateFull(true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.ok(popup.container.getBoundingClientRect().height <= 50);
    +        assert.ok(popup.container.getBoundingClientRect().top >= notEnoughSpaceOnBottom + lineHeight);
    +        popup.hide();
    +        assert.strictEqual(popup.container.style.display, "none");
    +        done();
    +    },
    +    "test: resets popup size if space is available again": function(done) {
    +        setupPopup();
    +        popup.show({ top: notEnoughSpaceOnBottom, left: notEnoughSpaceOnRight }, lineHeight, true);
    +        popup.renderer.updateFull(true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.ok(popup.container.getBoundingClientRect().height <= 50);
    +        assert.ok(popup.container.getBoundingClientRect().top >= notEnoughSpaceOnBottom + lineHeight);
    +        popup.hide();
    +        assert.strictEqual(popup.container.style.display, "none");
    +
    +        popup.show({ top: 50, left: notEnoughSpaceOnRight }, lineHeight);
    +        popup.renderer.updateFull(true);
    +        assert.notEqual(popup.container.style.display, "none");
    +        assert.ok(popup.container.getBoundingClientRect().height, renderHeight);
    +        assert.ok(popup.container.getBoundingClientRect().top >= 50 + lineHeight);
    +        popup.hide();
    +        assert.strictEqual(popup.container.style.display, "none");
    +        done();
    +    },
    +    tearDown: tearDown
    +};
    +
    +if (typeof module !== "undefined" && module === require.main) {
    +    require("asyncjs").test.testcase(module.exports).exec();
    +}
    diff --git a/src/css/editor.css.js b/src/css/editor.css.js
    index 7a37877e2a3..505545fde4f 100644
    --- a/src/css/editor.css.js
    +++ b/src/css/editor.css.js
    @@ -592,4 +592,5 @@ module.exports = `
     .ace_ghost_text {
         opacity: 0.5;
         font-style: italic;
    +    white-space: pre;
     }`;
    diff --git a/src/ext/inline_autocomplete.js b/src/ext/inline_autocomplete.js
    new file mode 100644
    index 00000000000..5c855da7cb3
    --- /dev/null
    +++ b/src/ext/inline_autocomplete.js
    @@ -0,0 +1,610 @@
    +"use strict";
    +
    +var HashHandler = require("../keyboard/hash_handler").HashHandler;
    +var AceInline = require("../autocomplete/inline").AceInline;
    +var FilteredList = require("../autocomplete").FilteredList;
    +var CompletionProvider = require("../autocomplete").CompletionProvider;
    +var Editor = require("../editor").Editor;
    +var util = require("../autocomplete/util");
    +var lang = require("../lib/lang");
    +var dom = require("../lib/dom");
    +var useragent = require("../lib/useragent");
    +var snippetCompleter = require("./language_tools").snippetCompleter;
    +var textCompleter = require("./language_tools").textCompleter;
    +var keyWordCompleter = require("./language_tools").keyWordCompleter;
    +
    +var destroyCompleter = function(e, editor) {
    +    editor.completer && editor.completer.destroy();
    +};
    +
    +var minPosition = function (posA, posB) {
    +    if (posB.row > posA.row) {
    +        return posA;
    +    } else if (posB.row === posA.row && posB.column > posA.column) {
    +        return posA;
    +    }
    +    return posB;
    +};
    +
    +
    +/**
    + * This class controls the inline-only autocompletion components and their lifecycle.
    + * This is more lightweight than the popup-based autocompletion, as it can only work with exact prefix matches.
    + * There is an inline ghost text renderer and an optional command bar tooltip inside.
    + * @class
    + */
    +
    +var InlineAutocomplete = function(editor) {
    +    this.editor = editor;
    +    this.tooltipEnabled = true;
    +    this.keyboardHandler = new HashHandler(this.commands);
    +    this.$index = -1;
    +
    +    this.blurListener = this.blurListener.bind(this);
    +    this.changeListener = this.changeListener.bind(this);
    +    this.mousewheelListener = this.mousewheelListener.bind(this);
    +
    +    this.changeTimer = lang.delayedCall(function() {
    +        this.updateCompletions();
    +    }.bind(this));
    +};
    +
    +(function() {
    +    this.getInlineRenderer = function() {
    +        if (!this.inlineRenderer)
    +            this.inlineRenderer = new AceInline();
    +        return this.inlineRenderer;
    +    };
    +
    +    this.getInlineTooltip = function() {
    +        if (!this.inlineTooltip) {
    +            this.inlineTooltip = new InlineTooltip(this.editor, document.body || document.documentElement);
    +            this.inlineTooltip.setCommands(this.commands);
    +        }
    +        return this.inlineTooltip;
    +    };
    +
    +
    +    /**
    +     * This function is the entry point to the class. This triggers the gathering of the autocompletion and displaying the results;
    +     * @param {Editor} editor
    +     * @param {CompletionOptions} options
    +     */
    +    this.show = function(options) {
    +        this.activated = true;
    +
    +        if (this.editor.completer !== this) {
    +            if (this.editor.completer)
    +                this.editor.completer.detach();
    +            this.editor.completer = this;
    +        }
    +
    +        this.editor.on("changeSelection", this.changeListener);
    +        this.editor.on("blur", this.blurListener);
    +        this.editor.on("mousewheel", this.mousewheelListener);
    +
    +        this.updateCompletions(options);
    +    };
    +
    +    this.$open = function() {
    +        if (this.editor.textInput.setAriaOptions) {
    +            this.editor.textInput.setAriaOptions({});
    +        }
    +
    +        if (this.tooltipEnabled) {
    +            this.getInlineTooltip().show(this.editor);
    +        } else if (this.tooltipEnabled === "hover") {
    +        }
    +
    +        this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler);
    +
    +        if (this.$index === -1) {
    +            this.setIndex(0);
    +        } else {
    +            this.$showCompletion();
    +        }
    +        
    +        this.changeTimer.cancel();
    +    };
    +    
    +    this.insertMatch = function() {
    +        var result = this.getCompletionProvider().insertByIndex(this.editor, this.$index);
    +        this.detach();
    +        return result;
    +    };
    +
    +    this.commands = {
    +        "Previous": {
    +            bindKey: "Alt-[",
    +            name: "Previous",
    +            exec: function(editor) {
    +                editor.completer.goTo("prev");
    +            },
    +            enabled: function(editor) {
    +                return editor.completer.getIndex() > 0;
    +            },
    +            position: 10
    +        },
    +        "Next": {
    +            bindKey: "Alt-]",
    +            name: "Next",
    +            exec: function(editor) {
    +                editor.completer.goTo("next");
    +            },
    +            enabled: function(editor) {
    +                return editor.completer.getIndex() < editor.completer.getLength() - 1;
    +            },
    +            position: 20
    +        },
    +        "Accept": {
    +            bindKey: { win: "Tab|Ctrl-Right", mac: "Tab|Cmd-Right" },
    +            name: "Accept",
    +            exec: function(editor) {
    +                return editor.completer.insertMatch();
    +            },
    +            enabled: function(editor) {
    +                return editor.completer.getIndex() >= 0;
    +            },
    +            position: 30
    +        },
    +        "Close": {
    +            bindKey: "Esc",
    +            name: "Close",
    +            exec: function(editor) {
    +                editor.completer.detach();
    +            },
    +            enabled: true,
    +            position: 40
    +        }
    +    };
    +
    +    this.changeListener = function(e) {
    +        var cursor = this.editor.selection.lead;
    +        if (cursor.row != this.base.row || cursor.column < this.base.column) {
    +            this.detach();
    +        }
    +        if (this.activated)
    +            this.changeTimer.schedule();
    +        else
    +            this.detach();
    +    };
    +
    +    this.blurListener = function(e) {
    +        this.detach();
    +    };
    +
    +    this.mousewheelListener = function(e) {
    +        if (this.inlineTooltip && this.inlineTooltip.isShown()) {
    +            this.inlineTooltip.updatePosition();
    +        }
    +    };
    +
    +    this.goTo = function(where) {
    +        if (!this.completions || !this.completions.filtered) {
    +            return;
    +        }
    +        switch(where.toLowerCase()) {
    +            case "prev":
    +                this.setIndex(Math.max(0, this.$index - 1));
    +                break;
    +            case "next":
    +                this.setIndex(this.$index + 1);
    +                break;
    +            case "first":
    +                this.setIndex(0);
    +                break;
    +            case "last":
    +                this.setIndex(this.completions.filtered.length - 1);
    +                break;
    +        }
    +    };
    +
    +    this.getLength = function() {
    +        if (!this.completions || !this.completions.filtered) {
    +            return 0;
    +        }
    +        return this.completions.filtered.length;
    +    };
    +
    +    this.getData = function(index) {
    +        if (index == undefined || index === null) {
    +            return this.completions.filtered[this.$index];
    +        } else {
    +            return this.completions.filtered[index];
    +        }
    +    };
    +
    +    this.getIndex = function() {
    +        return this.$index;
    +    };
    +
    +    this.isOpen = function() {
    +        return this.$index >= 0;
    +    };
    +
    +    this.setIndex = function(value) {
    +        if (!this.completions || !this.completions.filtered) {
    +            return;
    +        }
    +        var newIndex = Math.max(-1, Math.min(this.completions.filtered.length - 1, value));
    +        if (newIndex !== this.$index) {
    +            this.$index = newIndex;
    +            this.$showCompletion();
    +        }
    +    };
    +
    +    this.getCompletionProvider = function() {
    +        if (!this.completionProvider)
    +            this.completionProvider = new CompletionProvider();
    +        return this.completionProvider;
    +    };
    +
    +    this.$showCompletion = function() {
    +        if (!this.getInlineRenderer().show(this.editor, this.completions.filtered[this.$index], this.completions.filterText)) {
    +            // Not able to show the completion, hide the previous one
    +            this.getInlineRenderer().hide();
    +        }
    +        if (this.inlineTooltip && this.inlineTooltip.isShown()) {
    +            this.inlineTooltip.updateButtons();
    +        }
    +    };
    +
    +    this.$updatePrefix = function() {
    +        var pos = this.editor.getCursorPosition();
    +        var prefix = this.editor.session.getTextRange({start: this.base, end: pos});
    +        this.completions.setFilter(prefix);
    +        if (!this.completions.filtered.length)
    +            return this.detach();
    +        if (this.completions.filtered.length == 1
    +        && this.completions.filtered[0].value == prefix
    +        && !this.completions.filtered[0].snippet)
    +            return this.detach();
    +        this.$open(this.editor, prefix);
    +        return prefix;
    +    };
    +
    +    this.updateCompletions = function(options) {
    +        var prefix = "";
    +        
    +        if (options && options.matches) {
    +            var pos = this.editor.getSelectionRange().start;
    +            this.base = this.editor.session.doc.createAnchor(pos.row, pos.column);
    +            this.base.$insertRight = true;
    +            this.completions = new FilteredList(options.matches);
    +            return this.$open(this.editor, "");
    +        }
    +
    +        if (this.base && this.completions) {
    +            prefix = this.$updatePrefix();
    +        }
    +
    +        var session = this.editor.getSession();
    +        var pos = this.editor.getCursorPosition();
    +        var prefix = util.getCompletionPrefix(this.editor);
    +        this.base = session.doc.createAnchor(pos.row, pos.column - prefix.length);
    +        this.base.$insertRight = true;
    +        var options = {
    +            exactMatch: true,
    +            ignoreCaption: true
    +        };
    +        this.getCompletionProvider().provideCompletions(this.editor, options, function(err, completions, finished) {
    +            var filtered = completions.filtered;
    +            var prefix = util.getCompletionPrefix(this.editor);
    +
    +            if (finished) {
    +                // No results
    +                if (!filtered.length)
    +                    return this.detach();
    +
    +                // One result equals to the prefix
    +                if (filtered.length == 1 && filtered[0].value == prefix && !filtered[0].snippet)
    +                    return this.detach();
    +            }
    +            this.completions = completions;
    +            this.$open(this.editor, prefix);
    +        }.bind(this));
    +    };
    +
    +    this.detach = function() {
    +        if (this.editor) {
    +            this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler);
    +            this.editor.off("changeSelection", this.changeListener);
    +            this.editor.off("blur", this.blurListener);
    +            this.editor.off("mousewheel", this.mousewheelListener);
    +        }
    +        this.changeTimer.cancel();
    +        if (this.inlineTooltip) {
    +            this.inlineTooltip.detach();
    +        }
    +        
    +        this.setIndex(-1);
    +
    +        if (this.completionProvider) {
    +            this.completionProvider.detach();
    +        }
    +
    +        if (this.inlineRenderer && this.inlineRenderer.isOpen()) {
    +            this.inlineRenderer.hide();
    +        }
    +
    +        if (this.base)
    +            this.base.detach();
    +        this.activated = false;
    +        this.completionProvider = this.completions = this.base = null;
    +    };
    +
    +    this.destroy = function() {
    +        this.detach();
    +        if (this.inlineRenderer)
    +            this.inlineRenderer.destroy();
    +        if (this.inlineTooltip)
    +            this.inlineTooltip.destroy();
    +        if (this.editor && this.editor.completer == this) {
    +            this.editor.off("destroy", destroyCompleter);
    +            this.editor.completer = null;
    +        }
    +        this.inlineTooltip = this.editor = this.inlineRenderer = null;
    +    };
    +
    +}).call(InlineAutocomplete.prototype);
    +
    +InlineAutocomplete.for = function(editor) {
    +    if (editor.completer instanceof InlineAutocomplete) {
    +        return editor.completer;
    +    }
    +    if (editor.completer) {
    +        editor.completer.destroy();
    +        editor.completer = null;
    +    }
    +
    +    editor.completer = new InlineAutocomplete(editor);
    +    editor.once("destroy", destroyCompleter);
    +    return editor.completer;
    +};
    +
    +InlineAutocomplete.startCommand = {
    +    name: "startInlineAutocomplete",
    +    exec: function(editor, options) {
    +        var completer = InlineAutocomplete.for(editor);
    +        completer.show(options);
    +    },
    +    bindKey: { win: "Alt-C", mac: "Option-C" }
    +};
    +
    +
    +var completers = [snippetCompleter, textCompleter, keyWordCompleter];
    +
    +require("../config").defineOptions(Editor.prototype, "editor", {
    +    enableInlineAutocompletion: {
    +        set: function(val) {
    +            if (val) {
    +                if (!this.completers)
    +                    this.completers = Array.isArray(val)? val : completers;
    +                this.commands.addCommand(InlineAutocomplete.startCommand);
    +            } else {
    +                this.commands.removeCommand(InlineAutocomplete.startCommand);
    +            }
    +        },
    +        value: false
    +    }
    +});
    +
    +/**
    + * Displays a command tooltip above the selection, with clickable elements.
    + * @class
    + */
    +
    +/**
    + * Creates the inline command tooltip helper which displays the available keyboard commands for the user.
    + * @param {HTMLElement} parentElement
    + * @constructor
    + */
    +
    +var ENTRY_CLASS_NAME = 'inline_autocomplete_tooltip_entry';
    +var BUTTON_CLASS_NAME = 'inline_autocomplete_tooltip_button';
    +var TOOLTIP_CLASS_NAME = 'ace_tooltip ace_inline_autocomplete_tooltip';
    +var TOOLTIP_ID = 'inline_autocomplete_tooltip';
    +
    +function InlineTooltip(editor, parentElement) {
    +    this.editor = editor;
    +    this.htmlElement = document.createElement('div');
    +    var el = this.htmlElement;
    +    el.style.display = 'none';
    +    if (parentElement) {
    +        parentElement.appendChild(el);
    +    }
    +    el.id = TOOLTIP_ID;
    +    el.style['pointer-events'] = 'auto';
    +    el.className = TOOLTIP_CLASS_NAME;
    +    this.commands = {};
    +    this.buttons = {};
    +    this.eventListeners = {};
    +}
    +
    +(function() {
    +
    +    var captureMousedown = function(e) {
    +        e.preventDefault();
    +    };
    +
    +    /**
    +     * This function sets the commands. Note that it is advised to call this before calling show, otherwise there are no buttons to render
    +     * @param {Record} commands
    +     */
    +    this.setCommands = function(commands) {
    +        if (!commands || !this.htmlElement) {
    +            return;
    +        }
    +        this.detach();
    +        var el = this.htmlElement;
    +        while (el.hasChildNodes()) {
    +            el.removeChild(el.firstChild);
    +        }
    +
    +        this.commands = commands;
    +        this.buttons = {};
    +        this.eventListeners = {};
    +    
    +        Object.keys(commands)
    +            .map(function(key) { return [key, commands[key]]; })
    +            .filter(function (entry) { return entry[1].position > 0; })
    +            .sort(function (a, b) { return a[1].position - b[1].position; })
    +            .forEach(function (entry) {
    +                var key = entry[0];
    +                var command = entry[1];
    +                dom.buildDom(["div", { class: ENTRY_CLASS_NAME }, [['div', { class: BUTTON_CLASS_NAME, ref: key }, this.buttons]]], el, this.buttons);
    +                var bindKey = command.bindKey;
    +                if (typeof bindKey === 'object') {
    +                    bindKey = useragent.isMac ? bindKey.mac : bindKey.win;
    +                }
    +                bindKey = bindKey.replace("|", " / ");
    +                var buttonText = dom.createTextNode([command.name, "(", bindKey, ")"].join(" "));
    +                this.buttons[key].appendChild(buttonText);
    +            }.bind(this));
    +    };
    +
    +    /**
    +     * Displays the clickable command bar tooltip
    +     * @param {Editor} editor
    +     */
    +    this.show = function() {
    +        this.detach();
    +
    +        this.htmlElement.style.display = '';
    +        this.htmlElement.addEventListener('mousedown', captureMousedown.bind(this));
    +
    +        this.updatePosition();
    +        this.updateButtons(true);
    +    };
    +
    +    this.isShown = function() {
    +        return !!this.htmlElement && window.getComputedStyle(this.htmlElement).display !== "none";
    +    };
    +
    +    /**
    +     * Updates the position of the command bar tooltip. It aligns itself above the topmost selection in the editor.
    +     */
    +    this.updatePosition = function() {
    +        if (!this.editor) {
    +            return;
    +        }
    +        var renderer = this.editor.renderer;
    +
    +        var ranges;
    +        if (this.editor.selection.getAllRanges) {
    +            ranges = this.editor.selection.getAllRanges();
    +        } else {
    +            ranges = [this.editor.getSelection()];
    +        }
    +        if (!ranges.length) {
    +            return;
    +        }
    +        var minPos = minPosition(ranges[0].start, ranges[0].end);
    +        for (var i = 0, range; range = ranges[i]; i++) {
    +            minPos = minPosition(minPos, minPosition(range.start, range.end));
    +        }
    +
    +        var pos = renderer.$cursorLayer.getPixelPosition(minPos, true);
    +
    +        var el = this.htmlElement;
    +        var screenWidth = window.innerWidth;
    +        var rect = this.editor.container.getBoundingClientRect();
    +
    +        pos.top += rect.top - renderer.layerConfig.offset;
    +        pos.left += rect.left - this.editor.renderer.scrollLeft;
    +        pos.left += renderer.gutterWidth;
    +
    +        var top = pos.top - el.offsetHeight;
    +
    +        el.style.top = top + "px";
    +        el.style.bottom = "";
    +        el.style.left = Math.min(screenWidth - el.offsetWidth, pos.left) + "px";
    +    };
    +
    +    /**
    +     * Updates the buttons in the command bar tooltip. Should be called every time when any of the buttons can become disabled or enabled.
    +     */
    +    this.updateButtons = function(force) {
    +        Object.keys(this.buttons).forEach(function(key) {
    +            var commandEnabled = this.commands[key].enabled;
    +            if (typeof commandEnabled === 'function') {
    +                commandEnabled = commandEnabled(this.editor);
    +            }
    +
    +            if (commandEnabled && (force || !this.eventListeners[key])) {
    +                this.buttons[key].className = BUTTON_CLASS_NAME;
    +                this.buttons[key].ariaDisabled = this.buttons[key].disabled = false;
    +                this.buttons[key].removeAttribute("disabled");
    +                var eventListener = function(e) {
    +                    this.commands[key].exec(this.editor);
    +                    e.preventDefault();
    +                }.bind(this);
    +                this.eventListeners[key] = eventListener;
    +                this.buttons[key].addEventListener('mousedown', eventListener);
    +            }
    +            if (!commandEnabled && (force || this.eventListeners[key])) {
    +                this.buttons[key].className = BUTTON_CLASS_NAME + "_disabled";
    +                this.buttons[key].ariaDisabled = this.buttons[key].disabled = true;
    +                this.buttons[key].setAttribute("disabled", "");
    +                this.buttons[key].removeEventListener('mousedown', this.eventListeners[key]);
    +                delete this.eventListeners[key];
    +            }
    +        }.bind(this));
    +    };
    +    
    +    this.detach = function() {
    +        var listenerKeys = Object.keys(this.eventListeners);
    +        if (this.eventListeners && listenerKeys.length) {
    +            listenerKeys.forEach(function(key) {
    +                this.buttons[key].removeEventListener('mousedown', this.eventListeners[key]);
    +                delete this.eventListeners[key];
    +            }.bind(this));
    +        }
    +        if (this.htmlElement) {
    +            this.htmlElement.removeEventListener('mousedown', captureMousedown.bind(this));
    +            this.htmlElement.style.display = 'none';
    +        }
    +    };
    +
    +    this.destroy = function() {
    +        this.detach();
    +        if (this.htmlElement) {
    +            this.htmlElement.parentNode.removeChild(this.htmlElement);
    +        }
    +        this.editor = null;
    +        this.buttons = null;
    +        this.htmlElement = null;
    +        this.controls = null;
    +    };
    +}).call(InlineTooltip.prototype);
    +
    +dom.importCssString(`
    +.ace_inline_autocomplete_tooltip {
    +    display: inline-block;
    +}
    +.${ENTRY_CLASS_NAME} {
    +    display: inline-block;
    +    padding: 0 5px;
    +}
    +
    +.${BUTTON_CLASS_NAME} {
    +    display: inline-block;
    +    cursor: pointer;
    +    padding: 5px;
    +}
    +
    +.${BUTTON_CLASS_NAME}:hover {
    +    background-color: rgba(0, 0, 0, 0.1);
    +}
    +
    +div.${BUTTON_CLASS_NAME}_disabled {
    +    display: inline-block;
    +    padding: 5px;
    +    cursor: default;
    +    color: #777;
    +}`, "inlinetooltip.css", false);
    +
    +exports.InlineAutocomplete = InlineAutocomplete;
    +exports.InlineTooltip = InlineTooltip;
    +exports.TOOLTIP_ID = TOOLTIP_ID;
    +exports.BUTTON_CLASS_NAME = BUTTON_CLASS_NAME;
    diff --git a/src/ext/inline_autocomplete_test.js b/src/ext/inline_autocomplete_test.js
    new file mode 100644
    index 00000000000..3bdcea986e1
    --- /dev/null
    +++ b/src/ext/inline_autocomplete_test.js
    @@ -0,0 +1,285 @@
    +
    +if (typeof process !== "undefined") {
    +    require("amd-loader");
    +    require("../test/mockdom");
    +}
    +
    +"use strict";
    +
    +var Editor = require("../editor").Editor;
    +var EditSession = require("../edit_session").EditSession;
    +var InlineAutocomplete = require("./inline_autocomplete").InlineAutocomplete;
    +var assert = require("../test/assertions");
    +var type = require("../test/user").type;
    +var VirtualRenderer = require("../virtual_renderer").VirtualRenderer;
    +
    +var editor;
    +var autocomplete;
    +
    +var getAllLines = function() {
    +    var text = Array.from(editor.renderer.$textLayer.element.childNodes).map(function (node) {
    +        return node.textContent;
    +    }).join("\n");
    +    if (editor.renderer.$ghostTextWidget) {
    +        return text + "\n" + editor.renderer.$ghostTextWidget.text;
    +    }
    +    return text;
    +};
    +
    +var typeAndChange = function(...args) {
    +    assert.equal(autocomplete.changeTimer.isPending(), null);
    +    type(args);
    +    assert.ok(autocomplete.changeTimer.isPending);
    +    autocomplete.changeTimer.call();
    +};
    +
    +var completions = [
    +    {
    +        value: "foo"
    +    },
    +    {
    +        value: "foobar"
    +    },
    +    {
    +        value: "function"
    +    },
    +    {
    +        value: "fundraiser"
    +    },
    +    {
    +        snippet: "function foo() {\n    console.log('test');\n}",
    +        caption: "func"
    +    },
    +    {
    +        value: "foobar2"
    +    }
    +];
    +
    +var mockCompleter = {
    +    getCompletions: function(_1, _2, _3, _4, callback) {
    +        callback(null, completions);
    +    }
    +};
    +
    +module.exports = {
    +    setUp: function(done) {
    +        var el = document.createElement("div");
    +        el.style.left = "20px";
    +        el.style.top = "30px";
    +        el.style.width = "500px";
    +        el.style.height = "500px";
    +        document.body.appendChild(el);
    +        var renderer = new VirtualRenderer(el);
    +        var session = new EditSession("");
    +        editor = new Editor(renderer, session);
    +        editor.execCommand("insertstring", "f");
    +        editor.getSelection().moveCursorFileEnd();
    +        editor.renderer.$loop._flush();
    +        editor.completers = [mockCompleter];
    +        autocomplete = InlineAutocomplete.for(editor);
    +        editor.focus();
    +        done();
    +    },
    +    "test: autocomplete completion shows up": function(done) {
    +        autocomplete.show(editor);
    +        assert.strictEqual(autocomplete.getIndex(), 0);
    +        assert.strictEqual(autocomplete.getData().value, "foo");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(getAllLines(), "foo");
    +        done();
    +    },
    +    "test: autocomplete tooltip is shown according to the selected option": function(done) {
    +        assert.equal(autocomplete.inlineTooltip, null);
    +
    +        autocomplete.show(editor);
    +        assert.strictEqual(autocomplete.inlineTooltip.isShown(), true);
    +
    +        autocomplete.detach();
    +        assert.strictEqual(autocomplete.inlineTooltip.isShown(), false);
    +        done();
    +    },
    +    "test: autocomplete navigation works": function(done) {
    +        autocomplete.show(editor);
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 0);
    +        assert.strictEqual(autocomplete.getData().value, "foo");
    +        assert.equal(getAllLines(), "foo");
    +
    +        type("Alt-]");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 1);
    +        assert.strictEqual(autocomplete.getData().value, "foobar");
    +        assert.equal(getAllLines(), "foobar");
    +
    +        type("Alt-[");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 0);
    +        assert.strictEqual(autocomplete.getData().value, "foo");
    +        assert.equal(getAllLines(), "foo");
    +        done();
    +    },
    +    "test: verify goTo commands": function(done) {
    +        autocomplete.show(editor);
    +        autocomplete.setIndex(1);
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getData().value, "foobar");
    +        assert.equal(getAllLines(), "foobar");
    +
    +        autocomplete.goTo("next");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 2);
    +        assert.strictEqual(autocomplete.getData().value, "foobar2");
    +        assert.strictEqual(getAllLines(), "foobar2");
    +
    +        autocomplete.goTo("prev");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 1);
    +        assert.strictEqual(autocomplete.getData().value, "foobar");
    +        assert.strictEqual(getAllLines(), "foobar");
    +
    +        autocomplete.goTo("last");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 5);
    +        assert.strictEqual(autocomplete.getData().value, "fundraiser");
    +        assert.strictEqual(getAllLines(), "fundraiser");
    +
    +        autocomplete.goTo("next");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 5);
    +        assert.strictEqual(autocomplete.getData().value, "fundraiser");
    +        assert.strictEqual(getAllLines(), "fundraiser");
    +
    +        autocomplete.goTo("first");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 0);
    +        assert.strictEqual(autocomplete.getData().value, "foo");
    +        assert.strictEqual(getAllLines(), "foo");
    +
    +        autocomplete.goTo("prev");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 0);
    +        assert.strictEqual(autocomplete.getData().value, "foo");
    +        assert.strictEqual(getAllLines(), "foo");
    +        done();
    +    },
    +    "test: set index to negative value hides suggestions": function(done) {
    +        autocomplete.show(editor);
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 0);
    +        assert.strictEqual(getAllLines(), "foo");
    +
    +        autocomplete.setIndex(-1);
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.isOpen(), false);
    +        assert.strictEqual(getAllLines(), "f");
    +        done();
    +    },
    +    "test: autocomplete can be closed": function(done) {
    +        autocomplete.show(editor);
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.isOpen(), true);
    +        assert.equal(getAllLines(), "foo");
    +
    +        type("Escape");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.isOpen(), false);
    +        assert.equal(getAllLines(), "f");
    +        done();
    +    },
    +    "test: autocomplete can be accepted": function(done) {
    +        autocomplete.show(editor);
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.isOpen(), true);
    +        assert.ok(document.querySelectorAll(".ace_ghost_text").length > 0);
    +        assert.strictEqual(getAllLines(), "foo");
    +
    +        type("Tab");
    +        editor.renderer.$loop._flush();
    +        assert.equal(autocomplete.inlineCompleter, null);
    +        assert.equal(autocomplete.inlineTooltip.isShown(), false);
    +        assert.strictEqual(autocomplete.isOpen(), false);
    +        assert.equal(editor.renderer.$ghostText, null);
    +        assert.equal(editor.renderer.$ghostTextWidget, null);
    +        assert.strictEqual(document.querySelectorAll(".ace_ghost_text").length, 0);
    +        assert.strictEqual(getAllLines(), "foo");
    +        done();
    +    },
    +    "test: incremental typing filters results": function(done) {
    +        autocomplete.show(editor);
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.isOpen(), true);
    +        assert.equal(getAllLines(), "foo");
    +
    +        typeAndChange("u", "n");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.isOpen(), true);
    +        assert.equal(getAllLines(), "function foo() {\n    console.log('test');\n}");
    +
    +        typeAndChange("d");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.isOpen(), true);
    +        assert.equal(getAllLines(), "fundraiser");
    +
    +        typeAndChange("Backspace", "Backspace", "Backspace");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.isOpen(), true);
    +        assert.equal(getAllLines(), "foo");
    +
    +        typeAndChange("r");
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.isOpen(), false);
    +        assert.equal(getAllLines(), "fr");
    +
    +        done();
    +    },
    +    "test: verify detach": function(done) {
    +        autocomplete.show(editor);
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 0);
    +        assert.strictEqual(getAllLines(), "foo");
    +
    +        autocomplete.detach();
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), -1);
    +        assert.strictEqual(autocomplete.getLength(), 0);
    +        assert.strictEqual(autocomplete.isOpen(), false);
    +        assert.equal(autocomplete.base, null);
    +        assert.equal(autocomplete.completions, null);
    +        assert.equal(autocomplete.completionProvider, null);
    +        assert.strictEqual(getAllLines(), "f");
    +        done();
    +    },
    +    "test: verify destroy": function(done) {
    +        autocomplete.show(editor);
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), 0);
    +        assert.strictEqual(getAllLines(), "foo");
    +        assert.strictEqual(editor.completer, autocomplete);
    +
    +        autocomplete.destroy();
    +        editor.renderer.$loop._flush();
    +        assert.strictEqual(autocomplete.getIndex(), -1);
    +        assert.strictEqual(autocomplete.getLength(), 0);
    +        assert.strictEqual(autocomplete.isOpen(), false);
    +        assert.equal(autocomplete.base, null);
    +        assert.equal(autocomplete.completions, null);
    +        assert.equal(autocomplete.completionProvider, null);
    +        assert.equal(autocomplete.editor, null);
    +        assert.equal(autocomplete.inlineTooltip, null);
    +        assert.equal(autocomplete.inlineRenderer, null);
    +        assert.strictEqual(editor.completer, null);
    +        assert.strictEqual(getAllLines(), "f");
    +
    +        autocomplete.destroy();
    +        editor.renderer.$loop._flush();
    +        done();
    +    },
    +    tearDown: function() {
    +        autocomplete.destroy();
    +        editor.destroy();
    +    }
    +};
    +
    +if (typeof module !== "undefined" && module === require.main) {
    +    require("asyncjs").test.testcase(module.exports).exec();
    +}
    diff --git a/src/ext/inline_autocomplete_tooltip_test.js b/src/ext/inline_autocomplete_tooltip_test.js
    new file mode 100644
    index 00000000000..bee40330e0c
    --- /dev/null
    +++ b/src/ext/inline_autocomplete_tooltip_test.js
    @@ -0,0 +1,174 @@
    +if (typeof process !== "undefined") {
    +    require("amd-loader");
    +    require("../test/mockdom");
    +}
    +
    +"use strict";
    +
    +var TOOLTIP_ID = require("./inline_autocomplete").TOOLTIP_ID;
    +var BUTTON_CLASS_NAME = require("./inline_autocomplete").BUTTON_CLASS_NAME;
    +var InlineTooltip = require("./inline_autocomplete").InlineTooltip;
    +var Editor = require("../ace").Editor;
    +var EditSession = require("../ace").EditSession;
    +var VirtualRenderer = require("../ace").VirtualRenderer;
    +var assert = require("../test/assertions");
    +
    +function mousedown(node) {
    +    node.dispatchEvent(new window.CustomEvent("mousedown", { bubbles: true }));
    +}
    +
    +var editor;
    +var counters = {};
    +var inlineTooltip;
    +var testCommand2Enabled = true;
    +var commands = {
    +    "testCommand1": {
    +        name: "testCommand1",
    +        bindKey: "Alt-K",
    +        exec: function(editor) {
    +            if (!editor) {
    +                return;
    +            }
    +            if (!counters["testCommand1"]) {
    +            counters["testCommand1"] = 0;
    +            }
    +            counters["testCommand1"]++;
    +        },
    +        enabled: function(editor) {
    +            if (!editor) {
    +                return;
    +            }
    +            if (!counters["testEnabled1"]) {
    +                counters["testEnabled1"] = 0;
    +            }
    +            counters["testEnabled1"]++;
    +            return true;
    +        },
    +        position: 10
    +    },
    +    "testCommand2": {
    +        name: "testCommand2",
    +        bindKey: "Alt-L",
    +        exec: function(editor) {
    +            if (!editor) {
    +                return;
    +            }
    +            if (!counters["testCommand2"]) {
    +            counters["testCommand2"] = 0;
    +            }
    +            counters["testCommand2"]++;
    +        },
    +        enabled: function(editor) {
    +            if (!editor) {
    +                return;
    +            }
    +            if (!counters["testEnabled2"]) {
    +                counters["testEnabled2"] = 0;
    +            }
    +            counters["testEnabled2"]++;
    +            return testCommand2Enabled;
    +        },
    +        position: 20
    +    }
    +};
    +
    +module.exports = {
    +    setUp: function() {
    +        var el = document.createElement("div");
    +        el.style.left = "20px";
    +        el.style.top = "30px";
    +        el.style.width = "500px";
    +        el.style.height = "500px";
    +        document.body.appendChild(el);
    +        var renderer = new VirtualRenderer(el);
    +        var session = new EditSession("abc123\n\nfunc");
    +        editor = new Editor(renderer, session);
    +        counters = {};
    +        inlineTooltip = new InlineTooltip(editor, document.body);
    +        inlineTooltip.setCommands(commands);
    +        testCommand2Enabled = true;
    +        editor.getSelection().moveCursorFileEnd();
    +        editor.renderer.$loop._flush();
    +    },
    +    "test: displays inline tooltip above cursor with commands": function(done) {
    +        var tooltipDomElement = document.getElementById(TOOLTIP_ID);
    +        assert.strictEqual(inlineTooltip.isShown(), false);
    +        assert.strictEqual(window.getComputedStyle(tooltipDomElement).display, "none");
    +
    +        inlineTooltip.show(editor);
    +        tooltipDomElement = document.getElementById(TOOLTIP_ID);
    +        assert.strictEqual(window.getComputedStyle(tooltipDomElement).display, "");
    +        assert.strictEqual(inlineTooltip.isShown(), true);
    +        done();
    +    },
    +    "test: commands are clickable": function(done) {
    +        inlineTooltip.show(editor);
    +        assert.strictEqual(inlineTooltip.isShown(), true);
    +        assert.strictEqual(counters["testCommand1"], undefined);
    +        var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME));
    +        assert.strictEqual(buttonElements.length, 2);
    +        mousedown(buttonElements[0]);
    +        mousedown(buttonElements[1]);
    +        assert.strictEqual(counters["testCommand1"], 1);
    +        done();
    +    },
    +    "test: commands are disabled when enable check is falsy": function(done) {
    +        inlineTooltip.show(editor);
    +        var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME));
    +        var disabledButtonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME + "_disabled"));
    +        assert.strictEqual(buttonElements.length, 2);
    +        assert.strictEqual(disabledButtonElements.length, 0);
    +        assert.strictEqual(buttonElements.filter(function (button) { return !button.disabled; }).length, 2);
    +        assert.strictEqual(counters["testEnabled1"], 1);
    +        assert.strictEqual(counters["testEnabled2"], 1);
    +
    +        testCommand2Enabled = false;
    +        inlineTooltip.updateButtons();
    +        buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME));
    +        disabledButtonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME + "_disabled"));
    +        assert.strictEqual(buttonElements.length, 1);
    +        assert.strictEqual(disabledButtonElements.length, 1);
    +        assert.strictEqual(disabledButtonElements.filter(function (button) { return button.disabled; }).length, 1);
    +        assert.strictEqual(buttonElements.filter(function (button) { return !button.disabled; }).length, 1);
    +        assert.strictEqual(counters["testEnabled1"], 2);
    +        assert.strictEqual(counters["testEnabled2"], 2);
    +        done();
    +    },
    +    "test: verify detach": function(done) {
    +        inlineTooltip.show(editor);
    +        var tooltipDomElement = document.getElementById(TOOLTIP_ID);
    +        assert.strictEqual(inlineTooltip.isShown(), true);
    +
    +        inlineTooltip.detach();
    +        assert.strictEqual(inlineTooltip.isShown(), false);
    +        var tooltipDomElement = document.getElementById(TOOLTIP_ID);
    +        assert.strictEqual(window.getComputedStyle(tooltipDomElement).display, "none");
    +        done();
    +    },
    +    "test: verify destroy": function(done) {
    +        inlineTooltip.show(editor);
    +        var tooltipDomElement = document.getElementById(TOOLTIP_ID);
    +        assert.strictEqual(inlineTooltip.isShown(), true);
    +        assert.ok(tooltipDomElement);
    +
    +        inlineTooltip.destroy();
    +        assert.strictEqual(inlineTooltip.isShown(), false);
    +        tooltipDomElement = document.getElementById(TOOLTIP_ID);
    +        assert.equal(tooltipDomElement, null);
    +
    +        // Intentionally called twice
    +        inlineTooltip.destroy();
    +        assert.strictEqual(inlineTooltip.isShown(), false);
    +        tooltipDomElement = document.getElementById(TOOLTIP_ID);
    +        assert.equal(tooltipDomElement, null);
    +        done();
    +    },
    +    tearDown: function() {
    +        inlineTooltip.destroy();
    +        editor.destroy();
    +    }
    +};
    +
    +if (typeof module !== "undefined" && module === require.main) {
    +    require("asyncjs").test.testcase(module.exports).exec();
    +}
    diff --git a/src/keyboard/textinput.js b/src/keyboard/textinput.js
    index 1ee56031e2c..8953353d78c 100644
    --- a/src/keyboard/textinput.js
    +++ b/src/keyboard/textinput.js
    @@ -52,7 +52,7 @@ var TextInput = function(parentNode, host) {
         this.setAriaOptions = function(options) {
             if (options.activeDescendant) {
                 text.setAttribute("aria-haspopup", "true");
    -            text.setAttribute("aria-autocomplete", "list");
    +            text.setAttribute("aria-autocomplete", options.inline ? "both" : "list");
                 text.setAttribute("aria-activedescendant", options.activeDescendant);
             } else {
                 text.setAttribute("aria-haspopup", "false");
    diff --git a/src/snippets.js b/src/snippets.js
    index d54e3ead65c..7947a49d877 100644
    --- a/src/snippets.js
    +++ b/src/snippets.js
    @@ -349,7 +349,7 @@ var SnippetManager = function() {
             return result;
         };
     
    -    this.insertSnippetForSelection = function(editor, snippetText) {
    +    var processSnippetText = function(editor, snippetText) {
             var cursor = editor.getCursorPosition();
             var line = editor.session.getLine(cursor.row);
             var tabString = editor.session.getTabString();
    @@ -466,12 +466,28 @@ var SnippetManager = function() {
                         t.end = {row: row, column: column};
                 }
             });
    +
    +        return {
    +            text,
    +            tabstops,
    +            tokens
    +        };
    +    };
    +
    +    this.getDisplayTextForSnippet = function(editor, snippetText) {
    +        var processedSnippet = processSnippetText.call(this, editor, snippetText);
    +        return processedSnippet.text;
    +    };
    +
    +    this.insertSnippetForSelection = function(editor, snippetText) {
    +        var processedSnippet = processSnippetText.call(this, editor, snippetText);
    +        
             var range = editor.getSelectionRange();
    -        var end = editor.session.replace(range, text);
    +        var end = editor.session.replace(range, processedSnippet.text);
     
             var tabstopManager = new TabstopManager(editor);
             var selectionId = editor.inVirtualSelectionMode && editor.selection.index;
    -        tabstopManager.addTabstops(tabstops, range.start, end, selectionId);
    +        tabstopManager.addTabstops(processedSnippet.tabstops, range.start, end, selectionId);
         };
         
         this.insertSnippet = function(editor, snippetText) {
    diff --git a/src/test/all_browser.js b/src/test/all_browser.js
    index 76f32465fa7..944889212b2 100644
    --- a/src/test/all_browser.js
    +++ b/src/test/all_browser.js
    @@ -13,6 +13,7 @@ var el = document.createElement.bind(document);
     var testNames = [
         "ace/ace_test",
         "ace/anchor_test",
    +    "ace/autocomplete/popup_test",
         "ace/autocomplete_test",
         "ace/background_tokenizer_test",
         "ace/commands/command_manager_test",
    @@ -25,6 +26,8 @@ var testNames = [
         "ace/editor_text_edit_test",
         "ace/editor_commands_test",
         "ace/ext/hardwrap_test",
    +    "ace/ext/inline_autocomplete_test",
    +    "ace/ext/inline_autocomplete_tooltip_test",
         "ace/ext/static_highlight_test",
         "ace/ext/whitespace_test",
         "ace/ext/error_marker_test",
    diff --git a/src/test/mockdom.js b/src/test/mockdom.js
    index e0c65ddddae..fa81e9d692c 100644
    --- a/src/test/mockdom.js
    +++ b/src/test/mockdom.js
    @@ -375,7 +375,7 @@ function Node(name) {
                 else
                     width = rect.width - right - left;
                 
    -            if (this.style.width)
    +            if (this.style.height)
                     height = parseCssLength(this.style.height || "100%", rect.height);
                 else
                     height = rect.height - top - bottom;
    diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js
    index 76d99adf144..f73f4271273 100644
    --- a/src/virtual_renderer.js
    +++ b/src/virtual_renderer.js
    @@ -1662,7 +1662,7 @@ var VirtualRenderer = function(container, theme) {
             session.bgTokenizer.lines[row] = null;
             var newToken = {type: type, value: text};
             var tokens = session.getTokens(row);
    -        if (column == null) {
    +        if (column == null || !tokens.length) {
                 tokens.push(newToken);
             } else {
                 var l = 0;
    @@ -1683,6 +1683,7 @@ var VirtualRenderer = function(container, theme) {
         };
     
         this.removeExtraToken = function(row, column) {
    +        this.session.bgTokenizer.lines[row] = null;
             this.updateLines(row, row);
         };
     
    diff --git a/src/virtual_renderer_test.js b/src/virtual_renderer_test.js
    index e08e4f916dc..aaf35d49cd6 100644
    --- a/src/virtual_renderer_test.js
    +++ b/src/virtual_renderer_test.js
    @@ -320,6 +320,11 @@ module.exports = {
     
             editor.renderer.$loop._flush();
             assert.equal(editor.renderer.content.textContent, "abcdefGhost");
    +
    +        editor.removeGhostText();
    +
    +        editor.renderer.$loop._flush();
    +        assert.equal(editor.renderer.content.textContent, "abcdef");
         },
     
         "test multiline ghost text": function() {
    @@ -332,6 +337,13 @@ module.exports = {
             assert.equal(editor.renderer.content.textContent, "abcdefGhost1");
             
             assert.equal(editor.session.lineWidgets[0].el.textContent, "Ghost2\nGhost3");
    +
    +        editor.removeGhostText();
    +
    +        editor.renderer.$loop._flush();
    +        assert.equal(editor.renderer.content.textContent, "abcdef");
    +        
    +        assert.equal(editor.session.lineWidgets, null);
         },
         "test: brackets highlighting": function (done) {
             var renderer = editor.renderer;
    
    From 469ea5dc7c5484d3714043b8837637996d5bd877 Mon Sep 17 00:00:00 2001
    From: Andrew Nester 
    Date: Fri, 17 Mar 2023 15:32:05 +0100
    Subject: [PATCH 0750/1293] release v1.16.0
    
    ---
     CHANGELOG.md  | 21 +++++++++++++++++++++
     build         |  2 +-
     package.json  |  2 +-
     src/config.js |  2 +-
     4 files changed, 24 insertions(+), 3 deletions(-)
    
    diff --git a/CHANGELOG.md b/CHANGELOG.md
    index 6be8ce62be5..2cfa7c982c0 100644
    --- a/CHANGELOG.md
    +++ b/CHANGELOG.md
    @@ -2,6 +2,27 @@
     
     All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
     
    +## [1.16.0](https://github.com/ajaxorg/ace/compare/v1.14.0...v1.16.0) (2023-03-17)
    +
    +
    +### Features
    +
    +* Added Editor API to set the ghost text ([#5036](https://github.com/ajaxorg/ace/issues/5036)) ([958d573](https://github.com/ajaxorg/ace/commit/958d57383c4ebfacd414eb817aecc2e0982d1b36))
    +* Inline autocompletion ([#5084](https://github.com/ajaxorg/ace/issues/5084)) ([eb834a1](https://github.com/ajaxorg/ace/commit/eb834a1f1ca7f922437a90f2f14d935d75f31ac8))
    +
    +
    +### Bug Fixes
    +
    +* add updated monospace font for Windows ([#5091](https://github.com/ajaxorg/ace/issues/5091)) ([a981972](https://github.com/ajaxorg/ace/commit/a9819722cec6ff60b028deaa7b70d7fefabac531))
    +* Added highlighting for TIES keyword introduced in PostgreSQL 13 ([#5033](https://github.com/ajaxorg/ace/issues/5033)) ([9588086](https://github.com/ajaxorg/ace/commit/95880868c2a9912f7c6a2c3942d67fc2a980094e))
    +* Added lateral keyword introduced in MySQL 8.0.14 ([#5053](https://github.com/ajaxorg/ace/issues/5053)) ([3250956](https://github.com/ajaxorg/ace/commit/32509568010d8b881cc9f1a6d6bd76e6f69360ea))
    +* editor shadow appears under the selected line background when horizontal scroll is active ([#5020](https://github.com/ajaxorg/ace/issues/5020)) ([ab4f788](https://github.com/ajaxorg/ace/commit/ab4f788455ae182ae133fa202d737efa5461ff79))
    +* Fix bug with missing token in latex folding ([#5093](https://github.com/ajaxorg/ace/issues/5093)) ([44b3a3e](https://github.com/ajaxorg/ace/commit/44b3a3ef2de40f5cc71c3dedc1ed8d596cfadeec)), closes [#5090](https://github.com/ajaxorg/ace/issues/5090)
    +* Implement highlight mode for PL/SQL (Oracle) dialect ([#5037](https://github.com/ajaxorg/ace/issues/5037)) ([159aa70](https://github.com/ajaxorg/ace/commit/159aa70d551530f2866fb0006fad37bd75e60dda))
    +* Improve MySQL highlighting mode ([#5050](https://github.com/ajaxorg/ace/issues/5050)) ([00f6089](https://github.com/ajaxorg/ace/commit/00f60890a36121d7c705445514dcf79a81055f55))
    +* Option to determine specific prefixes for quote insertion ([#5067](https://github.com/ajaxorg/ace/issues/5067)) ([34e769c](https://github.com/ajaxorg/ace/commit/34e769c5b29a68a3c4201fecc75d1287c99f9d51)), closes [#5063](https://github.com/ajaxorg/ace/issues/5063)
    +* Remove broken keybinding from vscode mode ([#5032](https://github.com/ajaxorg/ace/issues/5032)) ([68ff964](https://github.com/ajaxorg/ace/commit/68ff964a214cc2da66e4a35b313ff66dd4490e34))
    +
     ### [1.15.3](https://github.com/ajaxorg/ace/compare/v1.15.2...v1.15.3) (2023-03-02)
     
     ### [1.15.2](https://github.com/ajaxorg/ace/compare/v1.15.1...v1.15.2) (2023-02-16)
    diff --git a/build b/build
    index a6f05db4a35..10aa96811ed 160000
    --- a/build
    +++ b/build
    @@ -1 +1 @@
    -Subproject commit a6f05db4a359a66152afc29b6382caeb09a84cbd
    +Subproject commit 10aa96811ed49898e9e677545471da73260b98aa
    diff --git a/package.json b/package.json
    index 874209b4815..8c09db4c9ce 100644
    --- a/package.json
    +++ b/package.json
    @@ -1,7 +1,7 @@
     {
         "name": "ace-code",
         "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE",
    -    "version": "1.15.3",
    +    "version": "1.16.0",
         "homepage": "http://github.com/ajaxorg/ace",
         "engines": {
             "node": ">= 0.6.0"
    diff --git a/src/config.js b/src/config.js
    index 86e4001ff1f..3b12f54bb61 100644
    --- a/src/config.js
    +++ b/src/config.js
    @@ -157,6 +157,6 @@ var reportErrorIfPathIsNotConfigured = function() {
         }
     };
     
    -exports.version = "1.15.3";
    +exports.version = "1.16.0";
     
     
    
    From 4fd434a3f7dcf6857ddf9aee78b88ef6993bf383 Mon Sep 17 00:00:00 2001
    From: nightwing 
    Date: Sun, 19 Mar 2023 18:30:29 +0400
    Subject: [PATCH 0751/1293] remove will-change as it causes animations on
     chrome to hang
    
    ---
     demo/kitchen-sink/demo.js | 69 ++++++++++++++++++++++++++++++++++++++-
     src/css/editor.css.js     |  1 -
     2 files changed, 68 insertions(+), 2 deletions(-)
    
    diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js
    index 27272d3c4d4..1ca1589d492 100644
    --- a/demo/kitchen-sink/demo.js
    +++ b/demo/kitchen-sink/demo.js
    @@ -487,11 +487,78 @@ optionsPanelContainer.insertBefore(
                     env.editor.setValue(info, -1);
                     env.editor.setOption("wrap", 80);
                 }}, "Show Browser Info"]],
    -        devUtil.getUI()
    +        devUtil.getUI(),
    +        ["div", {},
    +            "Open Dialog ",
    +            ["button",  {onclick: openTestDialog.bind(null, false)}, "Scale"],
    +            ["button",  {onclick: openTestDialog.bind(null, true)}, "Height"]
    +        ]
         ]),
         optionsPanelContainer.children[1]
     );
     
    +function openTestDialog(animateHeight) {
    +    if (window.dialogEditor) 
    +        window.dialogEditor.destroy();
    +    var editor = ace.edit(null, {
    +        value: "test editor", 
    +        mode: "ace/mode/javascript"
    +    });
    +    window.dialogEditor = editor;
    +
    +    var dialog = dom.buildDom(["div", {
    +        style: "transition: all 1s; position: fixed; z-index: 100000;"
    +          + "background: darkblue; border: solid 1px black; display: flex; flex-direction: column"
    +        }, 
    +        ["div", {}, "test dialog"],
    +        editor.container
    +    ], document.body);
    +    editor.container.style.flex = "1";
    +    if (animateHeight) {
    +        dialog.style.width = "0vw";
    +        dialog.style.height = "0vh";
    +        dialog.style.left = "20vw";
    +        dialog.style.top = "20vh";
    +        setTimeout(function() {            
    +            dialog.style.width = "80vw";
    +            dialog.style.height = "80vh";
    +            dialog.style.left = "10vw";
    +            dialog.style.top = "10vh";
    +        }, 0);
    +        
    +    } else {
    +        dialog.style.width = "80vw";
    +        dialog.style.height = "80vh";
    +        dialog.style.left = "10vw";
    +        dialog.style.top = "10vh";
    +        dialog.style.transform = "scale(0)";
    +        setTimeout(function() {
    +            dialog.style.transform = "scale(1)"
    +        }, 0);
    +    }
    +    function close(e) {
    +        if (!e || !dialog.contains(e.target)) {
    +            if (animateHeight) {
    +                dialog.style.width = "0vw";
    +                dialog.style.height = "0vh";
    +                dialog.style.left = "80vw";
    +                dialog.style.top = "80vh";
    +            } else {
    +                dialog.style.transform = "scale(0)"
    +            }
    +            window.removeEventListener("mousedown", close);
    +            dialog.addEventListener("transitionend", function() {
    +                dialog.remove();
    +                editor.destroy();
    +            });
    +        }
    +    }
    +    window.addEventListener("mousedown", close);
    +    editor.focus()
    +    editor.commands.bindKey("Esc", function() { close(); });
    +}
    +
    +
     require("ace/ext/language_tools");
     require("ace/ext/inline_autocomplete");
     env.editor.setOptions({
    diff --git a/src/css/editor.css.js b/src/css/editor.css.js
    index 505545fde4f..66150be103a 100644
    --- a/src/css/editor.css.js
    +++ b/src/css/editor.css.js
    @@ -260,7 +260,6 @@ module.exports = `
     .ace_hidpi .ace_content,
     .ace_hidpi .ace_gutter {
         contain: strict;
    -    will-change: transform;
     }
     .ace_hidpi .ace_text-layer > .ace_line, 
     .ace_hidpi .ace_text-layer > .ace_line_group {
    
    From 51d5e4d4308ba98921b1d6ea8cf946d0e17d0a7a Mon Sep 17 00:00:00 2001
    From: nightwing 
    Date: Sun, 19 Mar 2023 20:54:47 +0400
    Subject: [PATCH 0752/1293] feat: add ResizeObserver to make calling
     editor.resize optional
    
    ---
     doc/site/js/main.js     |  6 -----
     doc/site/style.css      |  4 ++-
     src/ace.js              |  3 ---
     src/ace_test.js         | 56 ++++++++++++++++++++++++++++++++++++++++-
     src/editor.js           |  1 +
     src/virtual_renderer.js | 36 ++++++++++++++++++++++++++
     6 files changed, 95 insertions(+), 11 deletions(-)
    
    diff --git a/doc/site/js/main.js b/doc/site/js/main.js
    index ffea39e5976..3c11442cc88 100644
    --- a/doc/site/js/main.js
    +++ b/doc/site/js/main.js
    @@ -153,12 +153,6 @@ $(function() {
                 $.bbq.pushState(state);
          });
     
    -    $('#tabnav a[data-toggle="tab"]').on('shown', function (e) {
    -        $(".tab-content .tab-pane.active .ace_editor").each(function(i, el){
    -            el.env.onResize();
    -        });
    -    });
    -
         $(window).on("hashchange", function(e) {
             _gaq.push(['_trackPageview',location.pathname + location.search  + location.hash]);
             tabs.each(function() {
    diff --git a/doc/site/style.css b/doc/site/style.css
    index af9c0d3ec1d..54d2ed15130 100644
    --- a/doc/site/style.css
    +++ b/doc/site/style.css
    @@ -496,4 +496,6 @@ img {
     
     .nav>li>a.external-nav:hover {
         text-decoration: underline;
    -}
    \ No newline at end of file
    +}
    +
    +pre { background-color: white!important }
    \ No newline at end of file
    diff --git a/src/ace.js b/src/ace.js
    index fa1bf05fd35..5198e4cf6cb 100644
    --- a/src/ace.js
    +++ b/src/ace.js
    @@ -8,7 +8,6 @@
     "include loader_build";
     
     var dom = require("./lib/dom");
    -var event = require("./lib/event");
     
     var Range = require("./range").Range;
     var Editor = require("./editor").Editor;
    @@ -66,9 +65,7 @@ exports.edit = function(el, options) {
             onResize: editor.resize.bind(editor, null)
         };
         if (oldNode) env.textarea = oldNode;
    -    event.addListener(window, "resize", env.onResize);
         editor.on("destroy", function() {
    -        event.removeListener(window, "resize", env.onResize);
             env.editor.container.env = null; // prevent memory leak on old ie
         });
         editor.container.env = editor.env = env;
    diff --git a/src/ace_test.js b/src/ace_test.js
    index fa9462e01e8..1917b7ac039 100644
    --- a/src/ace_test.js
    +++ b/src/ace_test.js
    @@ -1,5 +1,4 @@
     if (typeof process !== "undefined") {
    -    require("amd-loader");
         require("./test/mockdom");
     }
     
    @@ -102,6 +101,61 @@ module.exports = {
             ace.config.set("useStrictCSP", false);
             assert.ok(getStyleNode());
         },
    +    "test: resizeObserver": function(done) {
    +        var mockObserver = {
    +            disconnect: function() { mockObserver.target = null; },
    +            observe: function(el) {
    +                mockObserver.target = el;
    +            },
    +            $create: function(fn) {
    +                mockObserver.callback = fn;
    +                return mockObserver;
    +            },
    +            call: function() {
    +                setTimeout(function() {
    +                    if (mockObserver.target)
    +                        mockObserver.callback([{contentRect: mockObserver.target.getBoundingClientRect()}]);
    +                });
    +            }
    +        };
    +        if (!window.ResizeObserver) {
    +            window.ResizeObserver = mockObserver.$create;
    +        }
    +        var editor = ace.edit(null);
    +        document.body.appendChild(editor.container);
    +        editor.container.style.width = "100px";
    +        editor.container.style.height = "100px";
    +        mockObserver.call();
    +        editor.resize(true);
    +        assert.ok(!editor.renderer.$resizeTimer.isPending());
    +        assert.equal(editor.renderer.$size.width, 100);
    +        editor.container.style.width = "200px";
    +        mockObserver.call();
    +        setTimeout(function() {
    +            if (editor.renderer.$resizeTimer.isPending())
    +                editor.renderer.$resizeTimer.call();
    +            assert.equal(editor.renderer.$size.width, 200);
    +            editor.container.style.height = "200px";
    +            mockObserver.call();
    +            setTimeout(function() {
    +                assert.ok(editor.renderer.$resizeTimer.isPending());
    +                editor.container.style.height = "100px";
    +                mockObserver.call();
    +                setTimeout(function() {
    +                    assert.ok(!editor.renderer.$resizeTimer.isPending());
    +                    editor.setOption("useResizeObserver", false);
    +                    editor.container.style.height = "300px";
    +                    mockObserver.call();
    +                    assert.ok(!editor.renderer.$resizeObserver);
    +                    editor.setOption("useResizeObserver", true);
    +                    assert.ok(editor.renderer.$resizeObserver);
    +                    if (window.ResizeObserver === mockObserver.$create)
    +                        window.ResizeObserver = undefined;
    +                    done();
    +                }, 15);
    +            }, 15);
    +        }, 15);
    +    },
         "test: edit template" : function() {
             var template = document.createElement("template");
             var div = document.createElement("div");
    diff --git a/src/editor.js b/src/editor.js
    index 8fc5808b14d..9b8ee510617 100644
    --- a/src/editor.js
    +++ b/src/editor.js
    @@ -2897,6 +2897,7 @@ config.defineOptions(Editor.prototype, "editor", {
         hasCssTransforms: "renderer",
         maxPixelHeight: "renderer",
         useTextareaForIME: "renderer",
    +    useResizeObserver: "renderer",
     
         scrollSpeed: "$mouseHandler",
         dragDelay: "$mouseHandler",
    diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js
    index f73f4271273..dc465a2976a 100644
    --- a/src/virtual_renderer.js
    +++ b/src/virtual_renderer.js
    @@ -2,6 +2,7 @@
     
     var oop = require("./lib/oop");
     var dom = require("./lib/dom");
    +var lang = require("./lib/lang");
     var config = require("./config");
     var GutterLayer = require("./layer/gutter").Gutter;
     var MarkerLayer = require("./layer/marker").Marker;
    @@ -157,6 +158,7 @@ var VirtualRenderer = function(container, theme) {
     
         this.updateCharacterSize();
         this.setPadding(4);
    +    this.$addResizeObserver();
         config.resetOptions(this);
         config._signal("renderer", this);
     };
    @@ -344,6 +346,7 @@ var VirtualRenderer = function(container, theme) {
                 width = el.clientWidth || el.scrollWidth;
             var changes = this.$updateCachedSize(force, gutterWidth, width, height);
     
    +        if (this.$resizeTimer) this.$resizeTimer.cancel();
             
             if (!this.$size.scrollerHeight || (!width && !height))
                 return this.resizing = 0;
    @@ -1799,6 +1802,7 @@ var VirtualRenderer = function(container, theme) {
             this.$cursorLayer.destroy();
             this.removeAllListeners();
             this.container.textContent = "";
    +        this.setOption("useResizeObserver", false);
         };
     
         this.$updateCustomScrollbar = function (val) {
    @@ -1836,10 +1840,42 @@ var VirtualRenderer = function(container, theme) {
             }
         };
     
    +    this.$addResizeObserver = function() {
    +        if (!window.ResizeObserver || this.$resizeObserver) return;
    +        var self = this;
    +        this.$resizeTimer = lang.delayedCall(function() {
    +            if (!self.destroyed)  self.onResize();
    +        }, 50);
    +        this.$resizeObserver = new window.ResizeObserver(function(e) {
    +            var w = e[0].contentRect.width;
    +            var h = e[0].contentRect.height;
    +            if (
    +                Math.abs(self.$size.width - w) > 1
    +                || Math.abs(self.$size.height - h) > 1
    +            ) {
    +                self.$resizeTimer.delay();
    +            } else {
    +                self.$resizeTimer.cancel();
    +            }
    +        });
    +        this.$resizeObserver.observe(this.container);
    +    };
    +
     }).call(VirtualRenderer.prototype);
     
     
     config.defineOptions(VirtualRenderer.prototype, "renderer", {
    +    useResizeObserver: {
    +        set: function(value) {
    +            if (!value && this.$resizeObserver) {
    +                this.$resizeObserver.disconnect();
    +                this.$resizeTimer.cancel();
    +                this.$resizeTimer = this.$resizeObserver = null;
    +            } else if (value && !this.$resizeObserver) {
    +                this.$addResizeObserver();
    +            }
    +        }
    +    },
         animatedScroll: {initialValue: false},
         showInvisibles: {
             set: function(value) {
    
    From afdccf8cbe613b7a043f23fa4d3c58db4c35c76c Mon Sep 17 00:00:00 2001
    From: mkslanc 
    Date: Thu, 23 Mar 2023 13:41:16 +0400
    Subject: [PATCH 0753/1293] convert to es6 classes
    
    ---
     demo/kitchen-sink/token_tooltip.js  |  48 +--
     src/anchor.js                       | 141 +++---
     src/autocomplete.js                 | 142 +++----
     src/autocomplete/inline.js          |  31 +-
     src/autocomplete/popup.js           | 637 ++++++++++++++--------------
     src/autocomplete/text_completer.js  |  84 ++--
     src/background_tokenizer.js         | 130 +++---
     src/bidihandler.js                  | 104 +++--
     src/commands/command_manager.js     |  57 +--
     src/document.js                     | 149 +++----
     src/edit_session.js                 | 490 ++++++++++-----------
     src/edit_session/fold.js            |  42 +-
     src/edit_session/fold_line.js       |  63 ++-
     src/editor.js                       | 474 ++++++++++-----------
     src/ext/elastic_tabstops_lite.js    |  68 +--
     src/ext/emmet.js                    |  63 ++-
     src/ext/inline_autocomplete.js      | 153 ++++---
     src/ext/modelist.js                 |  39 +-
     src/ext/options.js                  |  36 +-
     src/ext/searchbox.js                | 272 ++++++------
     src/ext/static_highlight.js         |  82 ++--
     src/ext/statusbar.js                |  35 +-
     src/incremental_search.js           |  81 ++--
     src/keyboard/keybinding.js          |  37 +-
     src/layer/cursor.js                 |  76 ++--
     src/layer/decorators.js             |  76 ++--
     src/layer/font_metrics.js           |  85 ++--
     src/layer/gutter.js                 |  81 ++--
     src/layer/lines.js                  |  47 +-
     src/layer/marker.js                 |  48 ++-
     src/layer/text.js                   | 126 +++---
     src/lib/app_config.js               |  30 +-
     src/line_widgets.js                 |  66 +--
     src/mouse/default_gutter_handler.js |  14 +-
     src/mouse/default_handlers.js       |  66 +--
     src/mouse/fold_handler.js           | 104 ++---
     src/mouse/mouse_event.js            |  53 +--
     src/mouse/mouse_handler.js          | 138 +++---
     src/occur.js                        |  31 +-
     src/placeholder.js                  |  94 ++--
     src/range.js                        |  95 ++---
     src/range_list.js                   |  43 +-
     src/renderloop.js                   |  68 ++-
     src/scrollbar.js                    | 196 ++++-----
     src/scrollbar_custom.js             | 162 ++++---
     src/search.js                       |  68 ++-
     src/search_highlight.js             |  22 +-
     src/token_iterator.js               |  53 +--
     src/tokenizer.js                    | 191 ++++-----
     src/tokenizer_dev.js                |   9 +-
     src/tooltip.js                      |  51 +--
     src/undomanager.js                  |  82 ++--
     src/virtual_renderer.js             | 499 +++++++++++-----------
     53 files changed, 2969 insertions(+), 3163 deletions(-)
    
    diff --git a/demo/kitchen-sink/token_tooltip.js b/demo/kitchen-sink/token_tooltip.js
    index d3260bf33c6..c2bbccdbbbf 100644
    --- a/demo/kitchen-sink/token_tooltip.js
    +++ b/demo/kitchen-sink/token_tooltip.js
    @@ -6,27 +6,25 @@ var event = require("ace/lib/event");
     var Range = require("ace/range").Range;
     var Tooltip = require("ace/tooltip").Tooltip;
     
    -function TokenTooltip (editor) {
    -    if (editor.tokenTooltip)
    -        return;
    -    Tooltip.call(this, editor.container);
    -    editor.tokenTooltip = this;
    -    this.editor = editor;
    -
    -    this.update = this.update.bind(this);
    -    this.onMouseMove = this.onMouseMove.bind(this);
    -    this.onMouseOut = this.onMouseOut.bind(this);
    -    event.addListener(editor.renderer.scroller, "mousemove", this.onMouseMove);
    -    event.addListener(editor.renderer.content, "mouseout", this.onMouseOut);
    -}
    -
    -oop.inherits(TokenTooltip, Tooltip);
    -
    -(function(){
    -    this.token = {};
    -    this.range = new Range();
    +class TokenTooltip extends Tooltip {
    +    constructor(editor) {
    +        if (editor.tokenTooltip)
    +            return;
    +        super(editor.container);
    +        editor.tokenTooltip = this;
    +        this.editor = editor;
    +
    +        this.update = this.update.bind(this);
    +        this.onMouseMove = this.onMouseMove.bind(this);
    +        this.onMouseOut = this.onMouseOut.bind(this);
    +        event.addListener(editor.renderer.scroller, "mousemove", this.onMouseMove);
    +        event.addListener(editor.renderer.content, "mouseout", this.onMouseOut);
    +    }
    +    token = {};
    +    
    +    range = new Range();
         
    -    this.update = function() {
    +    update() {
             this.$timer = null;
             
             var r = this.editor.renderer;
    @@ -83,7 +81,7 @@ oop.inherits(TokenTooltip, Tooltip);
             this.marker = session.addMarker(this.range, "ace_bracket", "text");
         };
         
    -    this.onMouseMove = function(e) {
    +    onMouseMove(e) {
             this.x = e.clientX;
             this.y = e.clientY;
             if (this.isOpen) {
    @@ -94,7 +92,7 @@ oop.inherits(TokenTooltip, Tooltip);
                 this.$timer = setTimeout(this.update, 100);
         };
     
    -    this.onMouseOut = function(e) {
    +    onMouseOut(e) {
             if (e && e.currentTarget.contains(e.relatedTarget))
                 return;
             this.hide();
    @@ -102,7 +100,7 @@ oop.inherits(TokenTooltip, Tooltip);
             this.$timer = clearTimeout(this.$timer);
         };
     
    -    this.setPosition = function(x, y) {
    +    setPosition(x, y) {
             if (x + 10 + this.width > this.maxWidth)
                 x = window.innerWidth - this.width - 10;
             if (y > window.innerHeight * 0.75 || y + 20 + this.height > this.maxHeight)
    @@ -111,13 +109,13 @@ oop.inherits(TokenTooltip, Tooltip);
             Tooltip.prototype.setPosition.call(this, x + 10, y + 20);
         };
     
    -    this.destroy = function() {
    +    destroy() {
             this.onMouseOut();
             event.removeListener(this.editor.renderer.scroller, "mousemove", this.onMouseMove);
             event.removeListener(this.editor.renderer.content, "mouseout", this.onMouseOut);
             delete this.editor.tokenTooltip;
         };
     
    -}).call(TokenTooltip.prototype);
    +}
     
     exports.TokenTooltip = TokenTooltip;
    diff --git a/src/anchor.js b/src/anchor.js
    index 870dc897159..d81f8bb9140 100644
    --- a/src/anchor.js
    +++ b/src/anchor.js
    @@ -4,41 +4,31 @@ var oop = require("./lib/oop");
     var EventEmitter = require("./lib/event_emitter").EventEmitter;
     
     /**
    - *
      * Defines a floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the anchor is updated.
    - *
    - * @class Anchor
      **/
    -
    -/**
    - * Creates a new `Anchor` and associates it with a document.
    - *
    - * @param {Document} doc The document to associate with the anchor
    - * @param {Number} row The starting row position
    - * @param {Number} column The starting column position
    - *
    - * @constructor
    - **/
    -
    -var Anchor = exports.Anchor = function(doc, row, column) {
    -    this.$onChange = this.onChange.bind(this);
    -    this.attach(doc);
    +class Anchor {
    +    /**
    +     * Creates a new `Anchor` and associates it with a document.
    +     *
    +     * @param {Document} doc The document to associate with the anchor
    +     * @param {Number} row The starting row position
    +     * @param {Number} column The starting column position
    +     **/
    +    constructor(doc, row, column) {
    +        this.$onChange = this.onChange.bind(this);
    +        this.attach(doc);
    +
    +        if (typeof column == "undefined")
    +            this.setPosition(row.row, row.column);
    +        else
    +            this.setPosition(row, column);
    +    };
         
    -    if (typeof column == "undefined")
    -        this.setPosition(row.row, row.column);
    -    else
    -        this.setPosition(row, column);
    -};
    -
    -(function() {
    -
    -    oop.implement(this, EventEmitter);
    -
         /**
          * Returns an object identifying the `row` and `column` position of the current anchor.
          * @returns {Ace.Point}
          **/
    -    this.getPosition = function() {
    +    getPosition() {
             return this.$clipPositionToDocument(this.row, this.column);
         };
     
    @@ -47,14 +37,14 @@ var Anchor = exports.Anchor = function(doc, row, column) {
          * Returns the current document.
          * @returns {Document}
          **/
    -    this.getDocument = function() {
    +    getDocument() {
             return this.document;
         };
     
         /**
          * experimental: allows anchor to stick to the next on the left
          */
    -    this.$insertRight = false;
    +    $insertRight = false;
         /**
          * Fires whenever the anchor position changes.
          *
    @@ -72,7 +62,7 @@ var Anchor = exports.Anchor = function(doc, row, column) {
          * Internal function called when `"change"` event fired.
          * @param {Ace.Delta} delta
          */
    -    this.onChange = function(delta) {
    +    onChange(delta) {
             if (delta.start.row == delta.end.row && delta.start.row != this.row)
                 return;
     
    @@ -82,44 +72,6 @@ var Anchor = exports.Anchor = function(doc, row, column) {
             var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight);
             this.setPosition(point.row, point.column, true);
         };
    -    
    -    function $pointsInOrder(point1, point2, equalPointsInOrder) {
    -        var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column;
    -        return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter);
    -    }
    -            
    -    function $getTransformedPoint(delta, point, moveIfEqual) {
    -        // Get delta info.
    -        var deltaIsInsert = delta.action == "insert";
    -        var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row    - delta.start.row);
    -        var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column);
    -        var deltaStart = delta.start;
    -        var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range.
    -        
    -        // DELTA AFTER POINT: No change needed.
    -        if ($pointsInOrder(point, deltaStart, moveIfEqual)) {
    -            return {
    -                row: point.row,
    -                column: point.column
    -            };
    -        }
    -        
    -        // DELTA BEFORE POINT: Move point by delta shift.
    -        if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) {
    -            return {
    -                row: point.row + deltaRowShift,
    -                column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0)
    -            };
    -        }
    -        
    -        // DELTA ENVELOPS POINT (delete only): Move point to delta start.
    -        // TODO warn if delta.action != "remove" ?
    -        
    -        return {
    -            row: deltaStart.row,
    -            column: deltaStart.column
    -        };
    -    }
     
         /**
          * Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not clipped.
    @@ -128,7 +80,7 @@ var Anchor = exports.Anchor = function(doc, row, column) {
          * @param {Boolean} noClip Identifies if you want the position to be clipped
          *
          **/
    -    this.setPosition = function(row, column, noClip) {
    +    setPosition(row, column, noClip) {
             var pos;
             if (noClip) {
                 pos = {
    @@ -159,7 +111,7 @@ var Anchor = exports.Anchor = function(doc, row, column) {
          * When called, the `"change"` event listener is removed.
          *
          **/
    -    this.detach = function() {
    +    detach() {
             this.document.off("change", this.$onChange);
         };
     
    @@ -168,7 +120,7 @@ var Anchor = exports.Anchor = function(doc, row, column) {
          * @param {Document} doc The document to associate with
          *
          **/
    -    this.attach = function(doc) {
    +    attach(doc) {
             this.document = doc || this.document;
             this.document.on("change", this.$onChange);
         };
    @@ -180,7 +132,7 @@ var Anchor = exports.Anchor = function(doc, row, column) {
          * @returns {Ace.Point}
          *
          **/
    -    this.$clipPositionToDocument = function(row, column) {
    +    $clipPositionToDocument(row, column) {
             var pos = {};
     
             if (row >= this.document.getLength()) {
    @@ -201,5 +153,46 @@ var Anchor = exports.Anchor = function(doc, row, column) {
     
             return pos;
         };
    +}
    +
    +oop.implement(Anchor.prototype, EventEmitter);
    +
    +function $pointsInOrder(point1, point2, equalPointsInOrder) {
    +    var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column;
    +    return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter);
    +}
    +
    +function $getTransformedPoint(delta, point, moveIfEqual) {
    +    // Get delta info.
    +    var deltaIsInsert = delta.action == "insert";
    +    var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row    - delta.start.row);
    +    var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column);
    +    var deltaStart = delta.start;
    +    var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range.
    +
    +    // DELTA AFTER POINT: No change needed.
    +    if ($pointsInOrder(point, deltaStart, moveIfEqual)) {
    +        return {
    +            row: point.row,
    +            column: point.column
    +        };
    +    }
    +
    +    // DELTA BEFORE POINT: Move point by delta shift.
    +    if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) {
    +        return {
    +            row: point.row + deltaRowShift,
    +            column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0)
    +        };
    +    }
    +
    +    // DELTA ENVELOPS POINT (delete only): Move point to delta start.
    +    // TODO warn if delta.action != "remove" ?
    +
    +    return {
    +        row: deltaStart.row,
    +        column: deltaStart.column
    +    };
    +}
     
    -}).call(Anchor.prototype);
    +exports.Anchor = Anchor;
    diff --git a/src/autocomplete.js b/src/autocomplete.js
    index 91a35f159b4..dfdc947237c 100644
    --- a/src/autocomplete.js
    +++ b/src/autocomplete.js
    @@ -14,36 +14,32 @@ var destroyCompleter = function(e, editor) {
         editor.completer && editor.completer.destroy();
     };
     
    -
     /**
      * This object controls the autocompletion components and their lifecycle.
      * There is an autocompletion popup, an optional inline ghost text renderer and a docuent tooltip popup inside.
    - * @class
      */
    +class Autocomplete {
    +    constructor() {
    +        this.autoInsert = false;
    +        this.autoSelect = true;
    +        this.exactMatch = false;
    +        this.inlineEnabled = false;
    +        this.keyboardHandler = new HashHandler();
    +        this.keyboardHandler.bindKeys(this.commands);
    +
    +        this.blurListener = this.blurListener.bind(this);
    +        this.changeListener = this.changeListener.bind(this);
    +        this.mousedownListener = this.mousedownListener.bind(this);
    +        this.mousewheelListener = this.mousewheelListener.bind(this);
    +
    +        this.changeTimer = lang.delayedCall(function() {
    +            this.updateCompletions(true);
    +        }.bind(this));
     
    -var Autocomplete = function() {
    -    this.autoInsert = false;
    -    this.autoSelect = true;
    -    this.exactMatch = false;
    -    this.inlineEnabled = false;
    -    this.keyboardHandler = new HashHandler();
    -    this.keyboardHandler.bindKeys(this.commands);
    -
    -    this.blurListener = this.blurListener.bind(this);
    -    this.changeListener = this.changeListener.bind(this);
    -    this.mousedownListener = this.mousedownListener.bind(this);
    -    this.mousewheelListener = this.mousewheelListener.bind(this);
    -
    -    this.changeTimer = lang.delayedCall(function() {
    -        this.updateCompletions(true);
    -    }.bind(this));
    -
    -    this.tooltipTimer = lang.delayedCall(this.updateDocTooltip.bind(this), 50);
    -};
    -
    -(function() {
    +        this.tooltipTimer = lang.delayedCall(this.updateDocTooltip.bind(this), 50);
    +    };
     
    -    this.$init = function() {
    +    $init() {
             this.popup = new AcePopup(document.body || document.documentElement);
             this.popup.on("click", function(e) {
                 this.insertMatch();
    @@ -57,25 +53,25 @@ var Autocomplete = function() {
             return this.popup;
         };
     
    -    this.$initInline = function() {
    +    $initInline() {
             if (!this.inlineEnabled || this.inlineRenderer)
                 return;
             this.inlineRenderer = new AceInline();
             return this.inlineRenderer;
         };
     
    -    this.getPopup = function() {
    +    getPopup() {
             return this.popup || this.$init();
         };
     
    -    this.$onHidePopup = function() {
    +    $onHidePopup() {
             if (this.inlineRenderer) {
                 this.inlineRenderer.hide();
             }
             this.hideDocTooltip();
         };
     
    -    this.$onPopupChange = function(hide) {
    +    $onPopupChange(hide) {
             if (this.inlineRenderer && this.inlineEnabled) {
                 var completion = hide ? null : this.popup.getData(this.popup.getRow());
                 var prefix = util.getCompletionPrefix(this.editor);
    @@ -87,7 +83,7 @@ var Autocomplete = function() {
             this.tooltipTimer.call(null, null);
         };
     
    -    this.$updatePopupPosition = function() {
    +    $updatePopupPosition() {
             var editor = this.editor;
             var renderer = editor.renderer;
     
    @@ -123,7 +119,7 @@ var Autocomplete = function() {
             this.popup.show(pos, lineHeight);
         };
     
    -    this.openPopup = function(editor, prefix, keepPopupPosition) {
    +    openPopup(editor, prefix, keepPopupPosition) {
             if (!this.popup)
                 this.$init();
     
    @@ -160,7 +156,7 @@ var Autocomplete = function() {
         /**
          * Detaches all elements from the editor, and cleans up the data for the session
          */
    -    this.detach = function() {
    +    detach() {
             if (this.editor) {
                 this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler);
                 this.editor.off("changeSelection", this.changeListener);
    @@ -184,7 +180,7 @@ var Autocomplete = function() {
             this.completionProvider = this.completions = this.base = null;
         };
     
    -    this.changeListener = function(e) {
    +    changeListener(e) {
             var cursor = this.editor.selection.lead;
             if (cursor.row != this.base.row || cursor.column < this.base.column) {
                 this.detach();
    @@ -195,7 +191,7 @@ var Autocomplete = function() {
                 this.detach();
         };
     
    -    this.blurListener = function(e) {
    +    blurListener(e) {
             // we have to check if activeElement is a child of popup because
             // on IE preventDefault doesn't stop scrollbar from being focussed
             var el = document.activeElement;
    @@ -209,19 +205,19 @@ var Autocomplete = function() {
             }
         };
     
    -    this.mousedownListener = function(e) {
    +    mousedownListener(e) {
             this.detach();
         };
     
    -    this.mousewheelListener = function(e) {
    +    mousewheelListener(e) {
             this.detach();
         };
     
    -    this.goTo = function(where) {
    +   goTo(where) {
             this.popup.goTo(where);
         };
     
    -    this.insertMatch = function(data, options) {
    +    insertMatch(data, options) {
             if (!data)
                 data = this.popup.getData(this.popup.getRow());
             if (!data)
    @@ -234,7 +230,7 @@ var Autocomplete = function() {
             return result;
         };
     
    -    this.commands = {
    +    commands = {
             "Up": function(editor) { editor.completer.goTo("up"); },
             "Down": function(editor) { editor.completer.goTo("down"); },
             "Ctrl-Up|Ctrl-Home": function(editor) { editor.completer.goTo("start"); },
    @@ -260,7 +256,7 @@ var Autocomplete = function() {
          * @param {Editor} editor
          * @param {CompletionOptions} options
          */
    -    this.showPopup = function(editor, options) {
    +    showPopup(editor, options) {
             if (this.editor)
                 this.detach();
     
    @@ -281,7 +277,7 @@ var Autocomplete = function() {
             this.updateCompletions(false, options);
         };
     
    -    this.getCompletionProvider = function() {
    +    getCompletionProvider() {
             if (!this.completionProvider)
                 this.completionProvider = new CompletionProvider();
             return this.completionProvider;
    @@ -292,11 +288,11 @@ var Autocomplete = function() {
          * Use the same method include CompletionProvider instead for the same functionality.
          * @deprecated
          */
    -    this.gatherCompletions = function(editor, callback) {
    +    gatherCompletions(editor, callback) {
             return this.getCompletionProvider().gatherCompletions(editor, callback);
         };
     
    -    this.updateCompletions = function(keepPopupPosition, options) {
    +    updateCompletions(keepPopupPosition, options) {
             if (keepPopupPosition && this.base && this.completions) {
                 var pos = this.editor.getCursorPosition();
                 var prefix = this.editor.session.getTextRange({start: this.base, end: pos});
    @@ -349,11 +345,11 @@ var Autocomplete = function() {
             }.bind(this));
         };
     
    -    this.cancelContextMenu = function() {
    +    cancelContextMenu() {
             this.editor.$mouseHandler.cancelContextMenu();
         };
     
    -    this.updateDocTooltip = function() {
    +    updateDocTooltip() {
             var popup = this.popup;
             var all = popup.data;
             var selected = all && (all[popup.getHoveredRow()] || all[popup.getRow()]);
    @@ -375,7 +371,7 @@ var Autocomplete = function() {
             this.showDocTooltip(doc);
         };
     
    -    this.showDocTooltip = function(item) {
    +    showDocTooltip(item) {
             if (!this.tooltipNode) {
                 this.tooltipNode = dom.createElement("div");
                 this.tooltipNode.className = "ace_tooltip ace_doc-tooltip";
    @@ -424,7 +420,7 @@ var Autocomplete = function() {
             }
         };
     
    -    this.hideDocTooltip = function() {
    +    hideDocTooltip() {
             this.tooltipTimer.cancel();
             if (!this.tooltipNode) return;
             var el = this.tooltipNode;
    @@ -435,7 +431,7 @@ var Autocomplete = function() {
                 el.parentNode.removeChild(el);
         };
         
    -    this.onTooltipClick = function(e) {
    +    onTooltipClick(e) {
             var a = e.target;
             while (a && a != this.tooltipNode) {
                 if (a.nodeName == "A" && a.href) {
    @@ -447,7 +443,7 @@ var Autocomplete = function() {
             }
         };
     
    -    this.destroy = function() {
    +    destroy() {
             this.detach();
             if (this.popup) {
                 this.popup.destroy();
    @@ -462,7 +458,7 @@ var Autocomplete = function() {
             this.inlineRenderer = this.popup = this.editor = null;
         };
     
    -}).call(Autocomplete.prototype);
    +}
     
     
     Autocomplete.for = function(editor) {
    @@ -499,22 +495,21 @@ Autocomplete.startCommand = {
     
     /**
      * This class is responsible for providing completions and inserting them to the editor
    - * @class
      */
    -
    -var CompletionProvider = function() {
    -    this.active = true;
    -};
    -
    -(function() {
    -    this.insertByIndex = function(editor, index, options) {
    +class CompletionProvider {
    +    
    +    constructor() {
    +        this.active = true;
    +    };
    +    
    +    insertByIndex(editor, index, options) {
             if (!this.completions || !this.completions.filtered) {
                 return false;
             }
             return this.insertMatch(editor, this.completions.filtered[index], options);
         };
     
    -    this.insertMatch = function(editor, data, options) {
    +    insertMatch(editor, data, options) {
             if (!data)
                 return false;
     
    @@ -542,7 +537,7 @@ var CompletionProvider = function() {
             return true;
         };
     
    -    this.gatherCompletions = function(editor, callback) {
    +    gatherCompletions(editor, callback) {
             var session = editor.getSession();
             var pos = editor.getCursorPosition();
         
    @@ -572,7 +567,7 @@ var CompletionProvider = function() {
          * @param {CompletionProviderOptions} options
          * @param {CompletionProviderCallback} callback
          */
    -    this.provideCompletions = function(editor, options, callback) {
    +    provideCompletions(editor, options, callback) {
             var processResults = function(results) {
                 var prefix = results.prefix;
                 var matches = results.matches;
    @@ -623,20 +618,21 @@ var CompletionProvider = function() {
             }
         };
     
    -    this.detach = function() {
    +    detach() {
             this.active = false;
         };
    -}).call(CompletionProvider.prototype);
    +}
     
    -var FilteredList = function(array, filterText) {
    -    this.all = array;
    -    this.filtered = array;
    -    this.filterText = filterText || "";
    -    this.exactMatch = false;
    -    this.ignoreCaption = false;
    -};
    -(function(){
    -    this.setFilter = function(str) {
    +class FilteredList {
    +    constructor(array, filterText) {
    +        this.all = array;
    +        this.filtered = array;
    +        this.filterText = filterText || "";
    +        this.exactMatch = false;
    +        this.ignoreCaption = false;
    +    };
    +    
    +    setFilter(str) {
             if (str.length > this.filterText && str.lastIndexOf(this.filterText, 0) === 0)
                 var matches = this.filtered;
             else
    @@ -661,7 +657,7 @@ var FilteredList = function(array, filterText) {
             this.filtered = matches;
         };
     
    -    this.filterCompletions = function(items, needle) {
    +    filterCompletions(items, needle) {
             var results = [];
             var upper = needle.toUpperCase();
             var lower = needle.toLowerCase();
    @@ -712,7 +708,7 @@ var FilteredList = function(array, filterText) {
             }
             return results;
         };
    -}).call(FilteredList.prototype);
    +}
     
     exports.Autocomplete = Autocomplete;
     exports.CompletionProvider = CompletionProvider;
    diff --git a/src/autocomplete/inline.js b/src/autocomplete/inline.js
    index e161b4df5e1..b8853e14014 100644
    --- a/src/autocomplete/inline.js
    +++ b/src/autocomplete/inline.js
    @@ -4,20 +4,15 @@ var snippetManager = require("../snippets").snippetManager;
     
     /**
      * This object is used to manage inline code completions rendered into an editor with ghost text.
    - * @class
      */
    -
    -/**
    - * Creates the inline completion renderer which renders the inline code completions directly in the target editor.
    - * @constructor
    - */
    -
    -var AceInline = function() {
    -    this.editor = null;
    -};
    -
    -(function() {
    -
    +class AceInline {
    +    /**
    +     * Creates the inline completion renderer which renders the inline code completions directly in the target editor.
    +     */
    +    constructor() {
    +        this.editor = null;
    +    };
    +    
         /**
          * Renders the completion as ghost text to the current cursor position
          * @param {Editor} editor
    @@ -25,7 +20,7 @@ var AceInline = function() {
          * @param {string} prefix
          * @returns {boolean} True if the completion could be rendered to the editor, false otherwise
          */
    -    this.show = function(editor, completion, prefix) {
    +    show(editor, completion, prefix) {
             prefix = prefix || "";
             if (editor && this.editor && this.editor !== editor) {
                 this.hide();
    @@ -48,14 +43,14 @@ var AceInline = function() {
             return true;
         };
     
    -    this.isOpen = function() {
    +    isOpen() {
             if (!this.editor) {
                 return false;
             }
             return !!this.editor.renderer.$ghostText;
         };
     
    -    this.hide = function() {
    +    hide() {
             if (!this.editor) {
                 return false;
             }
    @@ -63,11 +58,11 @@ var AceInline = function() {
             return true;
         };
     
    -    this.destroy = function() {
    +    destroy() {
             this.hide();
             this.editor = null;
         };
    -}).call(AceInline.prototype);
    +}
     
     
     exports.AceInline = AceInline;
    diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js
    index 8e0dc400118..f58e84a3aa8 100644
    --- a/src/autocomplete/popup.js
    +++ b/src/autocomplete/popup.js
    @@ -31,360 +31,359 @@ var $singleLineEditor = function(el) {
     
     /**
      * This object is used in some places where needed to show popups - like prompt; autocomplete etc.
    - * @class
      */
    -
    -/**
    - * Creates and renders single line editor in popup window. If `parentNode` param is isset, then attaching it to this element.
    - * @param {Element} parentNode
    - * @constructor
    - */
    -var AcePopup = function(parentNode) {
    -    var el = dom.createElement("div");
    -    var popup = new $singleLineEditor(el);
    -
    -    if (parentNode)
    -        parentNode.appendChild(el);
    -    el.style.display = "none";
    -    popup.renderer.content.style.cursor = "default";
    -    popup.renderer.setStyle("ace_autocomplete");
    -
    -    // Set aria attributes for the popup
    -    popup.renderer.container.setAttribute("role", "listbox");
    -    popup.renderer.container.setAttribute("aria-label", "Autocomplete suggestions");
    -
    -    popup.setOption("displayIndentGuides", false);
    -    popup.setOption("dragDelay", 150);
    -
    -    var noop = function(){};
    -
    -    popup.focus = noop;
    -    popup.$isFocused = true;
    -
    -    popup.renderer.$cursorLayer.restartTimer = noop;
    -    popup.renderer.$cursorLayer.element.style.opacity = 0;
    -
    -    popup.renderer.$maxLines = 8;
    -    popup.renderer.$keepTextAreaAtCursor = false;
    -
    -    popup.setHighlightActiveLine(false);
    -    // set default highlight color
    -    popup.session.highlight("");
    -    popup.session.$searchHighlight.clazz = "ace_highlight-marker";
    -
    -    popup.on("mousedown", function(e) {
    -        var pos = e.getDocumentPosition();
    -        popup.selection.moveToPosition(pos);
    -        selectionMarker.start.row = selectionMarker.end.row = pos.row;
    -        e.stop();
    -    });
    -
    -    var lastMouseEvent;
    -    var hoverMarker = new Range(-1,0,-1,Infinity);
    -    var selectionMarker = new Range(-1,0,-1,Infinity);
    -    selectionMarker.id = popup.session.addMarker(selectionMarker, "ace_active-line", "fullLine");
    -    popup.setSelectOnHover = function(val) {
    -        if (!val) {
    -            hoverMarker.id = popup.session.addMarker(hoverMarker, "ace_line-hover", "fullLine");
    -        } else if (hoverMarker.id) {
    -            popup.session.removeMarker(hoverMarker.id);
    -            hoverMarker.id = null;
    -        }
    -    };
    -    popup.setSelectOnHover(false);
    -    popup.on("mousemove", function(e) {
    -        if (!lastMouseEvent) {
    +class AcePopup {
    +    /**
    +     * Creates and renders single line editor in popup window. If `parentNode` param is isset, then attaching it to this element.
    +     * @param {Element} parentNode
    +     */
    +    constructor(parentNode) {
    +        var el = dom.createElement("div");
    +        var popup = new $singleLineEditor(el);
    +
    +        if (parentNode)
    +            parentNode.appendChild(el);
    +        el.style.display = "none";
    +        popup.renderer.content.style.cursor = "default";
    +        popup.renderer.setStyle("ace_autocomplete");
    +
    +        // Set aria attributes for the popup
    +        popup.renderer.container.setAttribute("role", "listbox");
    +        popup.renderer.container.setAttribute("aria-label", "Autocomplete suggestions");
    +
    +        popup.setOption("displayIndentGuides", false);
    +        popup.setOption("dragDelay", 150);
    +
    +        var noop = function(){};
    +
    +        popup.focus = noop;
    +        popup.$isFocused = true;
    +
    +        popup.renderer.$cursorLayer.restartTimer = noop;
    +        popup.renderer.$cursorLayer.element.style.opacity = 0;
    +
    +        popup.renderer.$maxLines = 8;
    +        popup.renderer.$keepTextAreaAtCursor = false;
    +
    +        popup.setHighlightActiveLine(false);
    +        // set default highlight color
    +        popup.session.highlight("");
    +        popup.session.$searchHighlight.clazz = "ace_highlight-marker";
    +
    +        popup.on("mousedown", function(e) {
    +            var pos = e.getDocumentPosition();
    +            popup.selection.moveToPosition(pos);
    +            selectionMarker.start.row = selectionMarker.end.row = pos.row;
    +            e.stop();
    +        });
    +
    +        var lastMouseEvent;
    +        var hoverMarker = new Range(-1,0,-1,Infinity);
    +        var selectionMarker = new Range(-1,0,-1,Infinity);
    +        selectionMarker.id = popup.session.addMarker(selectionMarker, "ace_active-line", "fullLine");
    +        popup.setSelectOnHover = function(val) {
    +            if (!val) {
    +                hoverMarker.id = popup.session.addMarker(hoverMarker, "ace_line-hover", "fullLine");
    +            } else if (hoverMarker.id) {
    +                popup.session.removeMarker(hoverMarker.id);
    +                hoverMarker.id = null;
    +            }
    +        };
    +        popup.setSelectOnHover(false);
    +        popup.on("mousemove", function(e) {
    +            if (!lastMouseEvent) {
    +                lastMouseEvent = e;
    +                return;
    +            }
    +            if (lastMouseEvent.x == e.x && lastMouseEvent.y == e.y) {
    +                return;
    +            }
                 lastMouseEvent = e;
    -            return;
    -        }
    -        if (lastMouseEvent.x == e.x && lastMouseEvent.y == e.y) {
    -            return;
    -        }
    -        lastMouseEvent = e;
    -        lastMouseEvent.scrollTop = popup.renderer.scrollTop;
    -        var row = lastMouseEvent.getDocumentPosition().row;
    -        if (hoverMarker.start.row != row) {
    -            if (!hoverMarker.id)
    -                popup.setRow(row);
    -            setHoverMarker(row);
    -        }
    -    });
    -    popup.renderer.on("beforeRender", function() {
    -        if (lastMouseEvent && hoverMarker.start.row != -1) {
    -            lastMouseEvent.$pos = null;
    +            lastMouseEvent.scrollTop = popup.renderer.scrollTop;
                 var row = lastMouseEvent.getDocumentPosition().row;
    -            if (!hoverMarker.id)
    -                popup.setRow(row);
    -            setHoverMarker(row, true);
    -        }
    -    });
    -    popup.renderer.on("afterRender", function() {
    -        var row = popup.getRow();
    -        var t = popup.renderer.$textLayer;
    -        var selected = t.element.childNodes[row - t.config.firstRow];
    -        var el = document.activeElement; // Active element is textarea of main editor
    -        if (selected !== t.selectedNode && t.selectedNode) {
    -            dom.removeCssClass(t.selectedNode, "ace_selected");
    -            el.removeAttribute("aria-activedescendant");
    -            t.selectedNode.removeAttribute("id");
    -        }
    -        t.selectedNode = selected;
    -        if (selected) {
    -            dom.addCssClass(selected, "ace_selected");
    -            var ariaId = getAriaId(row);
    -            selected.id = ariaId;
    -            popup.renderer.container.setAttribute("aria-activedescendant", ariaId);
    -            el.setAttribute("aria-activedescendant", ariaId);
    -            selected.setAttribute("role", "option");
    -            selected.setAttribute("aria-label", popup.getData(row).value);
    -            selected.setAttribute("aria-setsize", popup.data.length);
    -            selected.setAttribute("aria-posinset", row);
    -        }
    -    });
    -    var hideHoverMarker = function() { setHoverMarker(-1); };
    -    var setHoverMarker = function(row, suppressRedraw) {
    -        if (row !== hoverMarker.start.row) {
    -            hoverMarker.start.row = hoverMarker.end.row = row;
    -            if (!suppressRedraw)
    -                popup.session._emit("changeBackMarker");
    -            popup._emit("changeHoverMarker");
    -        }
    -    };
    -    popup.getHoveredRow = function() {
    -        return hoverMarker.start.row;
    -    };
    +            if (hoverMarker.start.row != row) {
    +                if (!hoverMarker.id)
    +                    popup.setRow(row);
    +                setHoverMarker(row);
    +            }
    +        });
    +        popup.renderer.on("beforeRender", function() {
    +            if (lastMouseEvent && hoverMarker.start.row != -1) {
    +                lastMouseEvent.$pos = null;
    +                var row = lastMouseEvent.getDocumentPosition().row;
    +                if (!hoverMarker.id)
    +                    popup.setRow(row);
    +                setHoverMarker(row, true);
    +            }
    +        });
    +        popup.renderer.on("afterRender", function() {
    +            var row = popup.getRow();
    +            var t = popup.renderer.$textLayer;
    +            var selected = t.element.childNodes[row - t.config.firstRow];
    +            var el = document.activeElement; // Active element is textarea of main editor
    +            if (selected !== t.selectedNode && t.selectedNode) {
    +                dom.removeCssClass(t.selectedNode, "ace_selected");
    +                el.removeAttribute("aria-activedescendant");
    +                t.selectedNode.removeAttribute("id");
    +            }
    +            t.selectedNode = selected;
    +            if (selected) {
    +                dom.addCssClass(selected, "ace_selected");
    +                var ariaId = getAriaId(row);
    +                selected.id = ariaId;
    +                popup.renderer.container.setAttribute("aria-activedescendant", ariaId);
    +                el.setAttribute("aria-activedescendant", ariaId);
    +                selected.setAttribute("role", "option");
    +                selected.setAttribute("aria-label", popup.getData(row).value);
    +                selected.setAttribute("aria-setsize", popup.data.length);
    +                selected.setAttribute("aria-posinset", row);
    +            }
    +        });
    +        var hideHoverMarker = function() { setHoverMarker(-1); };
    +        var setHoverMarker = function(row, suppressRedraw) {
    +            if (row !== hoverMarker.start.row) {
    +                hoverMarker.start.row = hoverMarker.end.row = row;
    +                if (!suppressRedraw)
    +                    popup.session._emit("changeBackMarker");
    +                popup._emit("changeHoverMarker");
    +            }
    +        };
    +        popup.getHoveredRow = function() {
    +            return hoverMarker.start.row;
    +        };
    +
    +        event.addListener(popup.container, "mouseout", hideHoverMarker);
    +        popup.on("hide", hideHoverMarker);
    +        popup.on("changeSelection", hideHoverMarker);
    +
    +        popup.session.doc.getLength = function() {
    +            return popup.data.length;
    +        };
    +        popup.session.doc.getLine = function(i) {
    +            var data = popup.data[i];
    +            if (typeof data == "string")
    +                return data;
    +            return (data && data.value) || "";
    +        };
    +
    +        var bgTokenizer = popup.session.bgTokenizer;
    +        bgTokenizer.$tokenizeRow = function(row) {
    +            var data = popup.data[row];
    +            var tokens = [];
    +            if (!data)
    +                return tokens;
    +            if (typeof data == "string")
    +                data = {value: data};
    +            var caption = data.caption || data.value || data.name;
    +
    +            function addToken(value, className) {
    +                value && tokens.push({
    +                    type: (data.className || "") + (className || ""),
    +                    value: value
    +                });
    +            }
     
    -    event.addListener(popup.container, "mouseout", hideHoverMarker);
    -    popup.on("hide", hideHoverMarker);
    -    popup.on("changeSelection", hideHoverMarker);
    +            var lower = caption.toLowerCase();
    +            var filterText = (popup.filterText || "").toLowerCase();
    +            var lastIndex = 0;
    +            var lastI = 0;
    +            for (var i = 0; i <= filterText.length; i++) {
    +                if (i != lastI && (data.matchMask & (1 << i) || i == filterText.length)) {
    +                    var sub = filterText.slice(lastI, i);
    +                    lastI = i;
    +                    var index = lower.indexOf(sub, lastIndex);
    +                    if (index == -1) continue;
    +                    addToken(caption.slice(lastIndex, index), "");
    +                    lastIndex = index + sub.length;
    +                    addToken(caption.slice(index, lastIndex), "completion-highlight");
    +                }
    +            }
    +            addToken(caption.slice(lastIndex, caption.length), "");
     
    -    popup.session.doc.getLength = function() {
    -        return popup.data.length;
    -    };
    -    popup.session.doc.getLine = function(i) {
    -        var data = popup.data[i];
    -        if (typeof data == "string")
    -            return data;
    -        return (data && data.value) || "";
    -    };
    +            if (data.meta)
    +                tokens.push({type: "completion-meta", value: data.meta});
    +            if (data.message)
    +                tokens.push({type: "completion-message", value: data.message});
     
    -    var bgTokenizer = popup.session.bgTokenizer;
    -    bgTokenizer.$tokenizeRow = function(row) {
    -        var data = popup.data[row];
    -        var tokens = [];
    -        if (!data)
                 return tokens;
    -        if (typeof data == "string")
    -            data = {value: data};
    -        var caption = data.caption || data.value || data.name;
    -
    -        function addToken(value, className) {
    -            value && tokens.push({
    -                type: (data.className || "") + (className || ""), 
    -                value: value
    -            });
    -        }
    -        
    -        var lower = caption.toLowerCase();
    -        var filterText = (popup.filterText || "").toLowerCase();
    -        var lastIndex = 0;
    -        var lastI = 0;
    -        for (var i = 0; i <= filterText.length; i++) {
    -            if (i != lastI && (data.matchMask & (1 << i) || i == filterText.length)) {
    -                var sub = filterText.slice(lastI, i);
    -                lastI = i;
    -                var index = lower.indexOf(sub, lastIndex);
    -                if (index == -1) continue;
    -                addToken(caption.slice(lastIndex, index), "");
    -                lastIndex = index + sub.length;
    -                addToken(caption.slice(index, lastIndex), "completion-highlight");
    +        };
    +        bgTokenizer.$updateOnChange = noop;
    +        bgTokenizer.start = noop;
    +
    +        popup.session.$computeWidth = function() {
    +            return this.screenWidth = 0;
    +        };
    +
    +        // public
    +        popup.isOpen = false;
    +        popup.isTopdown = false;
    +        popup.autoSelect = true;
    +        popup.filterText = "";
    +
    +        popup.data = [];
    +        popup.setData = function(list, filterText) {
    +            popup.filterText = filterText || "";
    +            popup.setValue(lang.stringRepeat("\n", list.length), -1);
    +            popup.data = list || [];
    +            popup.setRow(0);
    +        };
    +        popup.getData = function(row) {
    +            return popup.data[row];
    +        };
    +
    +        popup.getRow = function() {
    +            return selectionMarker.start.row;
    +        };
    +        popup.setRow = function(line) {
    +            line = Math.max(this.autoSelect ? 0 : -1, Math.min(this.data.length, line));
    +            if (selectionMarker.start.row != line) {
    +                popup.selection.clearSelection();
    +                selectionMarker.start.row = selectionMarker.end.row = line || 0;
    +                popup.session._emit("changeBackMarker");
    +                popup.moveCursorTo(line || 0, 0);
    +                if (popup.isOpen)
    +                    popup._signal("select");
                 }
    -        }
    -        addToken(caption.slice(lastIndex, caption.length), "");
    -        
    -        if (data.meta)
    -            tokens.push({type: "completion-meta", value: data.meta});
    -        if (data.message)
    -            tokens.push({type: "completion-message", value: data.message});
    -
    -        return tokens;
    -    };
    -    bgTokenizer.$updateOnChange = noop;
    -    bgTokenizer.start = noop;
    -
    -    popup.session.$computeWidth = function() {
    -        return this.screenWidth = 0;
    -    };
    -
    -    // public
    -    popup.isOpen = false;
    -    popup.isTopdown = false;
    -    popup.autoSelect = true;
    -    popup.filterText = "";
    -
    -    popup.data = [];
    -    popup.setData = function(list, filterText) {
    -        popup.filterText = filterText || "";
    -        popup.setValue(lang.stringRepeat("\n", list.length), -1);
    -        popup.data = list || [];
    -        popup.setRow(0);
    -    };
    -    popup.getData = function(row) {
    -        return popup.data[row];
    -    };
    +        };
     
    -    popup.getRow = function() {
    -        return selectionMarker.start.row;
    -    };
    -    popup.setRow = function(line) {
    -        line = Math.max(this.autoSelect ? 0 : -1, Math.min(this.data.length, line));
    -        if (selectionMarker.start.row != line) {
    -            popup.selection.clearSelection();
    -            selectionMarker.start.row = selectionMarker.end.row = line || 0;
    -            popup.session._emit("changeBackMarker");
    -            popup.moveCursorTo(line || 0, 0);
    +        popup.on("changeSelection", function() {
                 if (popup.isOpen)
    -                popup._signal("select");
    -        }
    -    };
    +                popup.setRow(popup.selection.lead.row);
    +            popup.renderer.scrollCursorIntoView();
    +        });
    +
    +        popup.hide = function() {
    +            this.container.style.display = "none";
    +            popup.anchorPos = null;
    +            popup.anchor = null;
    +            if (popup.isOpen) {
    +                popup.isOpen = false;
    +                this._signal("hide");
    +            }
    +        };
    +
    +        /**
    +         * Tries to show the popup anchored to the given position and anchors.
    +         * If the anchor is not specified it tries to align to bottom and right as much as possible.
    +         * If the popup does not have enough space to be rendered with the given anchors, it returns false without rendering the popup.
    +         * The forceShow flag can be used to render the popup in these cases, which slides the popup so it entirely fits on the screen.
    +         * @param {Point} pos
    +         * @param {number} lineHeight
    +         * @param {"top" | "bottom" | undefined} anchor
    +         * @param {boolean} forceShow
    +         * @returns {boolean}
    +         */
    +        popup.tryShow = function(pos, lineHeight, anchor, forceShow) {
    +            if (!forceShow && popup.isOpen && popup.anchorPos && popup.anchor &&
    +                popup.anchorPos.top === pos.top && popup.anchorPos.left === pos.left &&
    +                popup.anchor === anchor
    +            ) {
    +                return true;
    +            }
     
    -    popup.on("changeSelection", function() {
    -        if (popup.isOpen)
    -            popup.setRow(popup.selection.lead.row);
    -        popup.renderer.scrollCursorIntoView();
    -    });
    -
    -    popup.hide = function() {
    -        this.container.style.display = "none";
    -        popup.anchorPos = null;
    -        popup.anchor = null;
    -        if (popup.isOpen) {
    -            popup.isOpen = false;
    -            this._signal("hide");
    -        }
    -    };
    +            var el = this.container;
    +            var screenHeight = window.innerHeight;
    +            var screenWidth = window.innerWidth;
    +            var renderer = this.renderer;
    +            // var maxLines = Math.min(renderer.$maxLines, this.session.getLength());
    +            var maxH = renderer.$maxLines * lineHeight * 1.4;
    +            var dims = { top: 0, bottom: 0, left: 0 };
    +
    +            var spaceBelow = screenHeight - pos.top - 3 * this.$borderSize - lineHeight;
    +            var spaceAbove = pos.top - 3 * this.$borderSize;
    +            if (!anchor) {
    +                if (spaceAbove <= spaceBelow || spaceBelow >= maxH) {
    +                    anchor = "bottom";
    +                } else {
    +                    anchor = "top";
    +                }
    +            }
     
    -    /**
    -     * Tries to show the popup anchored to the given position and anchors.
    -     * If the anchor is not specified it tries to align to bottom and right as much as possible.
    -     * If the popup does not have enough space to be rendered with the given anchors, it returns false without rendering the popup.
    -     * The forceShow flag can be used to render the popup in these cases, which slides the popup so it entirely fits on the screen.
    -     * @param {Point} pos
    -     * @param {number} lineHeight
    -     * @param {"top" | "bottom" | undefined} anchor
    -     * @param {boolean} forceShow
    -     * @returns {boolean}
    -     */
    -    popup.tryShow = function(pos, lineHeight, anchor, forceShow) {
    -        if (!forceShow && popup.isOpen && popup.anchorPos && popup.anchor &&
    -            popup.anchorPos.top === pos.top && popup.anchorPos.left === pos.left &&
    -            popup.anchor === anchor
    -        ) {
    -            return true;
    -        }
    -
    -        var el = this.container;
    -        var screenHeight = window.innerHeight;
    -        var screenWidth = window.innerWidth;
    -        var renderer = this.renderer;
    -        // var maxLines = Math.min(renderer.$maxLines, this.session.getLength());
    -        var maxH = renderer.$maxLines * lineHeight * 1.4;
    -        var dims = { top: 0, bottom: 0, left: 0 };
    -
    -        var spaceBelow = screenHeight - pos.top - 3 * this.$borderSize - lineHeight;
    -        var spaceAbove = pos.top - 3 * this.$borderSize;
    -        if (!anchor) {
    -            if (spaceAbove <= spaceBelow || spaceBelow >= maxH) {
    -                anchor = "bottom";
    -            } else {
    -                anchor = "top";
    +            if (anchor === "top") {
    +                dims.bottom = pos.top - this.$borderSize;
    +                dims.top = dims.bottom - maxH;
    +            } else if (anchor === "bottom") {
    +                dims.top = pos.top + lineHeight + this.$borderSize;
    +                dims.bottom = dims.top + maxH;
                 }
    -        }
     
    -        if (anchor === "top") {
    -            dims.bottom = pos.top - this.$borderSize;
    -            dims.top = dims.bottom - maxH;
    -        } else if (anchor === "bottom") {
    -            dims.top = pos.top + lineHeight + this.$borderSize;
    -            dims.bottom = dims.top + maxH;
    -        }
    +            var fitsX = dims.top >= 0 && dims.bottom <= screenHeight;
     
    -        var fitsX = dims.top >= 0 && dims.bottom <= screenHeight;
    +            if (!forceShow && !fitsX) {
    +                return false;
    +            }
    +
    +            if (!fitsX) {
    +                if (anchor === "top") {
    +                    renderer.$maxPixelHeight = spaceAbove;
    +                } else {
    +                    renderer.$maxPixelHeight = spaceBelow;
    +                }
    +            } else {
    +                renderer.$maxPixelHeight = null;
    +            }
     
    -        if (!forceShow && !fitsX) {
    -            return false;
    -        }
     
    -        if (!fitsX) {
                 if (anchor === "top") {
    -                renderer.$maxPixelHeight = spaceAbove;
    +                el.style.top = "";
    +                el.style.bottom = (screenHeight - dims.bottom) + "px";
    +                popup.isTopdown = false;
                 } else {
    -                renderer.$maxPixelHeight = spaceBelow;
    +                el.style.top = dims.top + "px";
    +                el.style.bottom = "";
    +                popup.isTopdown = true;
                 }
    -        } else {
    -            renderer.$maxPixelHeight = null;
    -        }
     
    +            el.style.display = "";
     
    -        if (anchor === "top") {
    -            el.style.top = "";
    -            el.style.bottom = (screenHeight - dims.bottom) + "px";
    -            popup.isTopdown = false;
    -        } else {
    -            el.style.top = dims.top + "px";
    -            el.style.bottom = "";
    -            popup.isTopdown = true;
    -        }
    +            var left = pos.left;
    +            if (left + el.offsetWidth > screenWidth)
    +                left = screenWidth - el.offsetWidth;
     
    -        el.style.display = "";
    +            el.style.left = left + "px";
    +            el.style.right = "";
     
    -        var left = pos.left;
    -        if (left + el.offsetWidth > screenWidth)
    -            left = screenWidth - el.offsetWidth;
    +            if (!popup.isOpen) {
    +                popup.isOpen = true;
    +                this._signal("show");
    +                lastMouseEvent = null;
    +            }
     
    -        el.style.left = left + "px";
    -        el.style.right = "";
    +            popup.anchorPos = pos;
    +            popup.anchor = anchor;
     
    -        if (!popup.isOpen) {
    -            popup.isOpen = true;
    -            this._signal("show");
    -            lastMouseEvent = null;
    -        }
    +            return true;
    +        };
     
    -        popup.anchorPos = pos;
    -        popup.anchor = anchor;
    +        popup.show = function(pos, lineHeight, topdownOnly) {
    +            this.tryShow(pos, lineHeight, topdownOnly ? "bottom" : undefined, true);
    +        };
     
    -        return true;
    -    };
    +        popup.goTo = function(where) {
    +            var row = this.getRow();
    +            var max = this.session.getLength() - 1;
     
    -    popup.show = function(pos, lineHeight, topdownOnly) {
    -        this.tryShow(pos, lineHeight, topdownOnly ? "bottom" : undefined, true);
    -    };
    +            switch(where) {
    +                case "up": row = row <= 0 ? max : row - 1; break;
    +                case "down": row = row >= max ? -1 : row + 1; break;
    +                case "start": row = 0; break;
    +                case "end": row = max; break;
    +            }
     
    -    popup.goTo = function(where) {
    -        var row = this.getRow();
    -        var max = this.session.getLength() - 1;
    +            this.setRow(row);
    +        };
     
    -        switch(where) {
    -            case "up": row = row <= 0 ? max : row - 1; break;
    -            case "down": row = row >= max ? -1 : row + 1; break;
    -            case "start": row = 0; break;
    -            case "end": row = max; break;
    -        }
     
    -        this.setRow(row);
    -    };
    +        popup.getTextLeftOffset = function() {
    +            return this.$borderSize + this.renderer.$padding + this.$imageSize;
    +        };
     
    +        popup.$imageSize = 0;
    +        popup.$borderSize = 1;
     
    -    popup.getTextLeftOffset = function() {
    -        return this.$borderSize + this.renderer.$padding + this.$imageSize;
    +        return popup;
         };
    -
    -    popup.$imageSize = 0;
    -    popup.$borderSize = 1;
    -
    -    return popup;
    -};
    +} 
     
     dom.importCssString(`
     .ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {
    diff --git a/src/autocomplete/text_completer.js b/src/autocomplete/text_completer.js
    index bb334513a4a..59791376dc4 100644
    --- a/src/autocomplete/text_completer.js
    +++ b/src/autocomplete/text_completer.js
    @@ -1,46 +1,50 @@
     var Range = require("../range").Range;
    -    
    -    var splitRegex = /[^a-zA-Z_0-9\$\-\u00C0-\u1FFF\u2C00-\uD7FF\w]+/;
     
    -    function getWordIndex(doc, pos) {
    -        var textBefore = doc.getTextRange(Range.fromPoints({row: 0, column:0}, pos));
    -        return textBefore.split(splitRegex).length - 1;
    -    }
    +var splitRegex = /[^a-zA-Z_0-9\$\-\u00C0-\u1FFF\u2C00-\uD7FF\w]+/;
     
    -    /**
    -     * Does a distance analysis of the word `prefix` at position `pos` in `doc`.
    -     * @return Map
    -     */
    -    function wordDistance(doc, pos) {
    -        var prefixPos = getWordIndex(doc, pos);
    -        var words = doc.getValue().split(splitRegex);
    -        var wordScores = Object.create(null);
    -        
    -        var currentWord = words[prefixPos];
    +function getWordIndex(doc, pos) {
    +    var textBefore = doc.getTextRange(Range.fromPoints({
    +        row: 0,
    +        column: 0
    +    }, pos));
    +    return textBefore.split(splitRegex).length - 1;
    +}
     
    -        words.forEach(function(word, idx) {
    -            if (!word || word === currentWord) return;
    +/**
    + * Does a distance analysis of the word `prefix` at position `pos` in `doc`.
    + * @return Map
    + */
    +function wordDistance(doc, pos) {
    +    var prefixPos = getWordIndex(doc, pos);
    +    var words = doc.getValue().split(splitRegex);
    +    var wordScores = Object.create(null);
     
    -            var distance = Math.abs(prefixPos - idx);
    -            var score = words.length - distance;
    -            if (wordScores[word]) {
    -                wordScores[word] = Math.max(score, wordScores[word]);
    -            } else {
    -                wordScores[word] = score;
    -            }
    -        });
    -        return wordScores;
    -    }
    +    var currentWord = words[prefixPos];
     
    -    exports.getCompletions = function(editor, session, pos, prefix, callback) {
    -        var wordScore = wordDistance(session, pos);
    -        var wordList = Object.keys(wordScore);
    -        callback(null, wordList.map(function(word) {
    -            return {
    -                caption: word,
    -                value: word,
    -                score: wordScore[word],
    -                meta: "local"
    -            };
    -        }));
    -    };
    +    words.forEach(function (word, idx) {
    +        if (!word || word === currentWord) return;
    +
    +        var distance = Math.abs(prefixPos - idx);
    +        var score = words.length - distance;
    +        if (wordScores[word]) {
    +            wordScores[word] = Math.max(score, wordScores[word]);
    +        }
    +        else {
    +            wordScores[word] = score;
    +        }
    +    });
    +    return wordScores;
    +}
    +
    +exports.getCompletions = function (editor, session, pos, prefix, callback) {
    +    var wordScore = wordDistance(session, pos);
    +    var wordList = Object.keys(wordScore);
    +    callback(null, wordList.map(function (word) {
    +        return {
    +            caption: word,
    +            value: word,
    +            score: wordScore[word],
    +            meta: "local"
    +        };
    +    }));
    +};
    diff --git a/src/background_tokenizer.js b/src/background_tokenizer.js
    index f8064bf287b..d31b3c289b1 100644
    --- a/src/background_tokenizer.js
    +++ b/src/background_tokenizer.js
    @@ -8,75 +8,67 @@ var EventEmitter = require("./lib/event_emitter").EventEmitter;
      * Tokenizes the current [[Document `Document`]] in the background, and caches the tokenized rows for future use. 
      * 
      * If a certain row is changed, everything below that row is re-tokenized.
    - *
    - * @class BackgroundTokenizer
      **/
    +class BackgroundTokenizer {
    +    
    +    /**
    +     * Creates a new `BackgroundTokenizer` object.
    +     * @param {Tokenizer} tokenizer The tokenizer to use
    +     * @param {Editor} editor The editor to associate with
    +     **/
    +    constructor(tokenizer, editor) {
    +        this.running = false;
    +        this.lines = [];
    +        this.states = [];
    +        this.currentLine = 0;
    +        this.tokenizer = tokenizer;
     
    -/**
    - * Creates a new `BackgroundTokenizer` object.
    - * @param {Tokenizer} tokenizer The tokenizer to use
    - * @param {Editor} editor The editor to associate with
    - *
    - * @constructor
    - **/
    +        var self = this;
     
    -var BackgroundTokenizer = function(tokenizer, editor) {
    -    this.running = false;
    -    this.lines = [];
    -    this.states = [];
    -    this.currentLine = 0;
    -    this.tokenizer = tokenizer;
    -
    -    var self = this;
    -
    -    this.$worker = function() {
    -        if (!self.running) { return; }
    -
    -        var workerStart = new Date();
    -        var currentLine = self.currentLine;
    -        var endLine = -1;
    -        var doc = self.doc;
    -
    -        var startLine = currentLine;
    -        while (self.lines[currentLine])
    -            currentLine++;
    -        
    -        var len = doc.getLength();
    -        var processedLines = 0;
    -        self.running = false;
    -        while (currentLine < len) {
    -            self.$tokenizeRow(currentLine);
    -            endLine = currentLine;
    -            do {
    +        this.$worker = function() {
    +            if (!self.running) { return; }
    +
    +            var workerStart = new Date();
    +            var currentLine = self.currentLine;
    +            var endLine = -1;
    +            var doc = self.doc;
    +
    +            var startLine = currentLine;
    +            while (self.lines[currentLine])
                     currentLine++;
    -            } while (self.lines[currentLine]);
     
    -            // only check every 5 lines
    -            processedLines ++;
    -            if ((processedLines % 5 === 0) && (new Date() - workerStart) > 20) {
    -                self.running = setTimeout(self.$worker, 20);
    -                break;
    +            var len = doc.getLength();
    +            var processedLines = 0;
    +            self.running = false;
    +            while (currentLine < len) {
    +                self.$tokenizeRow(currentLine);
    +                endLine = currentLine;
    +                do {
    +                    currentLine++;
    +                } while (self.lines[currentLine]);
    +
    +                // only check every 5 lines
    +                processedLines ++;
    +                if ((processedLines % 5 === 0) && (new Date() - workerStart) > 20) {
    +                    self.running = setTimeout(self.$worker, 20);
    +                    break;
    +                }
                 }
    -        }
    -        self.currentLine = currentLine;
    -        
    -        if (endLine == -1)
    -            endLine = currentLine;
    -        
    -        if (startLine <= endLine)
    -            self.fireUpdateEvent(startLine, endLine);
    -    };
    -};
    +            self.currentLine = currentLine;
     
    -(function(){
    -
    -    oop.implement(this, EventEmitter);
    +            if (endLine == -1)
    +                endLine = currentLine;
     
    +            if (startLine <= endLine)
    +                self.fireUpdateEvent(startLine, endLine);
    +        };
    +    };
    +    
         /**
          * Sets a new tokenizer for this object.
          * @param {Tokenizer} tokenizer The new tokenizer to use
          **/
    -    this.setTokenizer = function(tokenizer) {
    +    setTokenizer(tokenizer) {
             this.tokenizer = tokenizer;
             this.lines = [];
             this.states = [];
    @@ -88,7 +80,7 @@ var BackgroundTokenizer = function(tokenizer, editor) {
          * Sets a new document to associate with this object.
          * @param {Document} doc The new document to associate with
          **/
    -    this.setDocument = function(doc) {
    +    setDocument(doc) {
             this.doc = doc;
             this.lines = [];
             this.states = [];
    @@ -108,7 +100,7 @@ var BackgroundTokenizer = function(tokenizer, editor) {
          * @param {Number} firstRow The starting row region
          * @param {Number} lastRow The final row region
          **/
    -    this.fireUpdateEvent = function(firstRow, lastRow) {
    +    fireUpdateEvent(firstRow, lastRow) {
             var data = {
                 first: firstRow,
                 last: lastRow
    @@ -120,7 +112,7 @@ var BackgroundTokenizer = function(tokenizer, editor) {
          * Starts tokenizing at the row indicated.
          * @param {Number} startRow The row to start at
          **/
    -    this.start = function(startRow) {
    +    start(startRow) {
             this.currentLine = Math.min(startRow || 0, this.currentLine, this.doc.getLength());
     
             // remove all cached items below this line
    @@ -135,12 +127,12 @@ var BackgroundTokenizer = function(tokenizer, editor) {
         /**
          * Sets pretty long delay to prevent the tokenizer from interfering with the user
          */
    -    this.scheduleStart = function() {
    +    scheduleStart() {
             if (!this.running)
                 this.running = setTimeout(this.$worker, 700);
         };
     
    -    this.$updateOnChange = function(delta) {
    +    $updateOnChange(delta) {
             var startRow = delta.start.row;
             var len = delta.end.row - startRow;
     
    @@ -164,7 +156,7 @@ var BackgroundTokenizer = function(tokenizer, editor) {
         /**
          * Stops tokenizing.
          **/
    -    this.stop = function() {
    +    stop() {
             if (this.running)
                 clearTimeout(this.running);
             this.running = false;
    @@ -175,7 +167,7 @@ var BackgroundTokenizer = function(tokenizer, editor) {
          * @param {Number} row The row to get tokens at
          * @returns {Token[]}
          **/
    -    this.getTokens = function(row) {
    +    getTokens(row) {
             return this.lines[row] || this.$tokenizeRow(row);
         };
     
    @@ -184,13 +176,13 @@ var BackgroundTokenizer = function(tokenizer, editor) {
          * @param {Number} row The row to get state at
          * @returns {string}
          **/
    -    this.getState = function(row) {
    +    getState(row) {
             if (this.currentLine == row)
                 this.$tokenizeRow(row);
             return this.states[row] || "start";
         };
     
    -    this.$tokenizeRow = function(row) {
    +    $tokenizeRow(row) {
             var line = this.doc.getLine(row);
             var state = this.states[row - 1];
     
    @@ -208,7 +200,7 @@ var BackgroundTokenizer = function(tokenizer, editor) {
             return this.lines[row] = data.tokens;
         };
     
    -    this.cleanup = function() {
    +    cleanup = function() {
             this.running = false;
             this.lines = [];
             this.states = [];
    @@ -216,6 +208,8 @@ var BackgroundTokenizer = function(tokenizer, editor) {
             this.removeAllListeners();
         };
     
    -}).call(BackgroundTokenizer.prototype);
    +}
    +
    +oop.implement(BackgroundTokenizer.prototype, EventEmitter);
     
     exports.BackgroundTokenizer = BackgroundTokenizer;
    diff --git a/src/bidihandler.js b/src/bidihandler.js
    index ac9e793c774..348d5fd0d28 100644
    --- a/src/bidihandler.js
    +++ b/src/bidihandler.js
    @@ -7,49 +7,45 @@ var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\u202B]/;
     /**
      * This object is used to ensure Bi-Directional support (for languages with text flowing from right to left, like Arabic or Hebrew)
      * including correct caret positioning, text selection mouse and keyboard arrows functioning
    - * @class BidiHandler
      **/
    -
    -/**
    - * Creates a new `BidiHandler` object
    - * @param {EditSession} session The session to use
    - *
    - * @constructor
    - **/
    -var BidiHandler = function(session) {
    -    this.session = session;
    -    this.bidiMap = {};
    -    /* current screen row */
    -    this.currentRow = null;
    -    this.bidiUtil = bidiUtil;
    -    /* Arabic/Hebrew character width differs from regular character width */
    -    this.charWidths = [];
    -    this.EOL = "\xAC";
    -    this.showInvisibles = true;
    -    this.isRtlDir = false;
    -    this.$isRtl = false;
    -    this.line = "";
    -    this.wrapIndent = 0;
    -    this.EOF = "\xB6";
    -    this.RLE = "\u202B";
    -    this.contentWidth = 0;
    -    this.fontMetrics = null;
    -    this.rtlLineOffset = 0;
    -    this.wrapOffset = 0;
    -    this.isMoveLeftOperation = false;
    -    this.seenBidi = bidiRE.test(session.getValue());
    -};
    -
    -(function() {
    +class BidiHandler {
    +    /**
    +     * Creates a new `BidiHandler` object
    +     * @param {EditSession} session The session to use
    +     **/
    +    constructor(session) {
    +        this.session = session;
    +        this.bidiMap = {};
    +        /* current screen row */
    +        this.currentRow = null;
    +        this.bidiUtil = bidiUtil;
    +        /* Arabic/Hebrew character width differs from regular character width */
    +        this.charWidths = [];
    +        this.EOL = "\xAC";
    +        this.showInvisibles = true;
    +        this.isRtlDir = false;
    +        this.$isRtl = false;
    +        this.line = "";
    +        this.wrapIndent = 0;
    +        this.EOF = "\xB6";
    +        this.RLE = "\u202B";
    +        this.contentWidth = 0;
    +        this.fontMetrics = null;
    +        this.rtlLineOffset = 0;
    +        this.wrapOffset = 0;
    +        this.isMoveLeftOperation = false;
    +        this.seenBidi = bidiRE.test(session.getValue());
    +    };
    +    
         /**
          * Returns 'true' if row contains Bidi characters, in such case
          * creates Bidi map to be used in operations related to selection
          * (keyboard arrays, mouse click, select)
    -     * @param {Number} the screen row to be checked
    -     * @param {Number} the document row to be checked [optional]
    -     * @param {Number} the wrapped screen line index [ optional]
    +     * @param {Number} screenRow the screen row to be checked
    +     * @param {Number} docRow the document row to be checked [optional]
    +     * @param {Number} splitIndex the wrapped screen line index [ optional]
         **/
    -    this.isBidiRow = function(screenRow, docRow, splitIndex) {
    +    isBidiRow(screenRow, docRow, splitIndex) {
             if (!this.seenBidi)
                 return false;
             if (screenRow !== this.currentRow) {
    @@ -60,7 +56,7 @@ var BidiHandler = function(session) {
             return this.bidiMap.bidiLevels;
         };
     
    -    this.onChange = function(delta) {
    +    onChange(delta) {
             if (!this.seenBidi) {
                 if (delta.action == "insert" && bidiRE.test(delta.lines.join("\n"))) {
                     this.seenBidi = true;
    @@ -72,7 +68,7 @@ var BidiHandler = function(session) {
             }
         };
     
    -    this.getDocumentRow = function() {
    +    getDocumentRow() {
             var docRow = 0;
             var rowCache = this.session.$screenRowCache;
             if (rowCache.length) {
    @@ -84,7 +80,7 @@ var BidiHandler = function(session) {
             return docRow;
         };
     
    -    this.getSplitIndex = function() {
    +    getSplitIndex() {
             var splitIndex = 0;
             var rowCache = this.session.$screenRowCache;
             if (rowCache.length) {
    @@ -104,7 +100,7 @@ var BidiHandler = function(session) {
             return splitIndex;
         };
     
    -    this.updateRowLine = function(docRow, splitIndex) {
    +    updateRowLine(docRow, splitIndex) {
             if (docRow === undefined)
                 docRow = this.getDocumentRow();
                 
    @@ -155,7 +151,7 @@ var BidiHandler = function(session) {
             }
         };
         
    -    this.updateBidiMap = function() {
    +    updateBidiMap() {
             var textCharTypes = [];
             if (bidiUtil.hasBidiCharacters(this.line, textCharTypes) || this.isRtlDir) {
                  this.bidiMap = bidiUtil.doBidiReorder(this.line, textCharTypes, this.isRtlDir);
    @@ -167,16 +163,16 @@ var BidiHandler = function(session) {
         /**
          * Resets stored info related to current screen row
         **/
    -    this.markAsDirty = function() {
    +    markAsDirty() {
             this.currentRow = null;
         };
     
         /**
          * Updates array of character widths
    -     * @param {Object} font metrics
    +     * @param {Object} fontMetrics metrics
          *
         **/
    -    this.updateCharacterWidths = function(fontMetrics) {
    +    updateCharacterWidths(fontMetrics) {
             if (this.characterWidth === fontMetrics.$characterSize.width)
                 return;
     
    @@ -192,20 +188,20 @@ var BidiHandler = function(session) {
             this.currentRow = null;
         };
     
    -    this.setShowInvisibles = function(showInvisibles) {
    +    setShowInvisibles(showInvisibles) {
             this.showInvisibles = showInvisibles;
             this.currentRow = null;
         };
     
    -    this.setEolChar = function(eolChar) {
    +    setEolChar(eolChar) {
             this.EOL = eolChar; 
         };
     
    -    this.setContentWidth = function(width) {
    +    setContentWidth(width) {
             this.contentWidth = width;
         };
     
    -    this.isRtlLine = function(row) {
    +    isRtlLine(row) {
             if (this.$isRtl) return true;
             if (row != undefined)
                 return (this.session.getLine(row).charAt(0) == this.RLE);
    @@ -213,7 +209,7 @@ var BidiHandler = function(session) {
                 return this.isRtlDir; 
         };
     
    -    this.setRtlDirection = function(editor, isRtlDir) {
    +    setRtlDirection(editor, isRtlDir) {
             var cursor = editor.getCursorPosition(); 
             for (var row = editor.selection.getSelectionAnchor().row; row <= cursor.row; row++) {
                 if (!isRtlDir && editor.session.getLine(row).charAt(0) === editor.session.$bidiHandler.RLE)
    @@ -230,7 +226,7 @@ var BidiHandler = function(session) {
          *
          * @return {Number} horizontal pixel offset of given screen column
          **/
    -    this.getPosLeft = function(col) {
    +    getPosLeft = function(col) {
             col -= this.wrapIndent;
             var leftBoundary = (this.line.charAt(0) === this.RLE) ? 1 : 0;
             var logicalIdx = (col > leftBoundary) ? (this.session.getOverwrite() ? col : col - 1) : leftBoundary;
    @@ -263,7 +259,7 @@ var BidiHandler = function(session) {
          *
          * @return {Object[]} Each object contains 'left' and 'width' values defining selection rectangle.
         **/
    -    this.getSelections = function(startCol, endCol) {
    +    getSelections = function(startCol, endCol) {
             var map = this.bidiMap, levels = map.bidiLevels, level, selections = [], offset = 0,
                 selColMin = Math.min(startCol, endCol) - this.wrapIndent, selColMax = Math.max(startCol, endCol) - this.wrapIndent,
                     isSelected = false, isSelectedPrev = false, selectionStart = 0;
    @@ -302,7 +298,7 @@ var BidiHandler = function(session) {
          *
          * @return {Number} screen column number corresponding to given pixel offset
         **/
    -    this.offsetToCol = function(posX) {
    +    offsetToCol(posX) {
             if(this.isRtlDir)
                 posX -= this.rtlLineOffset;
     
    @@ -354,6 +350,6 @@ var BidiHandler = function(session) {
             return (logicalIdx + this.wrapIndent);
         };
     
    -}).call(BidiHandler.prototype);
    +}
     
     exports.BidiHandler = BidiHandler;
    diff --git a/src/commands/command_manager.js b/src/commands/command_manager.js
    index 472b92d0260..2e20962f9b9 100644
    --- a/src/commands/command_manager.js
    +++ b/src/commands/command_manager.js
    @@ -4,36 +4,24 @@ var oop = require("../lib/oop");
     var MultiHashHandler = require("../keyboard/hash_handler").MultiHashHandler;
     var EventEmitter = require("../lib/event_emitter").EventEmitter;
     
    -/**
    - * @class CommandManager
    - *
    - **/
    -
    -/**
    - * new CommandManager(platform, commands)
    - * @param {String} platform Identifier for the platform; must be either `"mac"` or `"win"`
    - * @param {Array} commands A list of commands
    - *
    - **/
    -
    -var CommandManager = function(platform, commands) {
    -    MultiHashHandler.call(this, commands, platform);
    -    this.byName = this.commands;
    -    this.setDefaultHandler("exec", function(e) {
    -        if (!e.args) {
    -            return e.command.exec(e.editor, {}, e.event, true);
    -        }
    -        return e.command.exec(e.editor, e.args, e.event, false);
    -    });
    -};
    -
    -oop.inherits(CommandManager, MultiHashHandler);
    -
    -(function() {
    -
    -    oop.implement(this, EventEmitter);
    -
    -    this.exec = function(command, editor, args) {
    +class CommandManager extends MultiHashHandler{
    +    /**
    +     * new CommandManager(platform, commands)
    +     * @param {String} platform Identifier for the platform; must be either `"mac"` or `"win"`
    +     * @param {Array} commands A list of commands
    +     **/
    +    constructor(platform, commands) {
    +        super(commands, platform);
    +        this.byName = this.commands;
    +        this.setDefaultHandler("exec", function(e) {
    +            if (!e.args) {
    +                return e.command.exec(e.editor, {}, e.event, true);
    +            }
    +            return e.command.exec(e.editor, e.args, e.event, false);
    +        });
    +    };
    +    
    +    exec(command, editor, args) {
             if (Array.isArray(command)) {
                 for (var i = command.length; i--; ) {
                     if (this.exec(command[i], editor, args)) return true;
    @@ -60,7 +48,7 @@ oop.inherits(CommandManager, MultiHashHandler);
             return e.returnValue === false ? false : true;
         };
     
    -    this.toggleRecording = function(editor) {
    +    toggleRecording(editor) {
             if (this.$inReplay)
                 return;
     
    @@ -86,7 +74,7 @@ oop.inherits(CommandManager, MultiHashHandler);
             return this.recording = true;
         };
     
    -    this.replay = function(editor) {
    +    replay(editor) {
             if (this.$inReplay || !this.macro)
                 return;
     
    @@ -106,7 +94,7 @@ oop.inherits(CommandManager, MultiHashHandler);
             }
         };
     
    -    this.trimMacro = function(m) {
    +    trimMacro(m) {
             return m.map(function(x){
                 if (typeof x[0] != "string")
                     x[0] = x[0].name;
    @@ -116,6 +104,7 @@ oop.inherits(CommandManager, MultiHashHandler);
             });
         };
     
    -}).call(CommandManager.prototype);
    +}
    +oop.implement(CommandManager.prototype, EventEmitter);
     
     exports.CommandManager = CommandManager;
    diff --git a/src/document.js b/src/document.js
    index 94e8b9c0dbf..a3cac10f84f 100644
    --- a/src/document.js
    +++ b/src/document.js
    @@ -9,41 +9,33 @@ var Anchor = require("./anchor").Anchor;
     /**
      * Contains the text of the document. Document can be attached to several [[EditSession `EditSession`]]s. 
      * At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index.
    - *
    - * @class Document
      **/
    -
    -/**
    - *
    - * Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty.
    - * @param {String | String[]} textOrLines text The starting text
    - * @constructor
    - **/
    -
    -var Document = function(textOrLines) {
    -    this.$lines = [""];
    -
    -    // There has to be one line at least in the document. If you pass an empty
    -    // string to the insert function, nothing will happen. Workaround.
    -    if (textOrLines.length === 0) {
    +class Document {
    +    /**
    +     *
    +     * Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty.
    +     * @param {String | String[]} textOrLines text The starting text
    +     **/
    +    constructor(textOrLines) {
             this.$lines = [""];
    -    } else if (Array.isArray(textOrLines)) {
    -        this.insertMergedLines({row: 0, column: 0}, textOrLines);
    -    } else {
    -        this.insert({row: 0, column:0}, textOrLines);
    -    }
    -};
    -
    -(function() {
    -
    -    oop.implement(this, EventEmitter);
     
    +        // There has to be one line at least in the document. If you pass an empty
    +        // string to the insert function, nothing will happen. Workaround.
    +        if (textOrLines.length === 0) {
    +            this.$lines = [""];
    +        } else if (Array.isArray(textOrLines)) {
    +            this.insertMergedLines({row: 0, column: 0}, textOrLines);
    +        } else {
    +            this.insert({row: 0, column:0}, textOrLines);
    +        }
    +    };
    +    
         /**
          * Replaces all the lines in the current `Document` with the value of `text`.
          *
          * @param {String} text The text to use
          **/
    -    this.setValue = function(text) {
    +    setValue(text) {
             var len = this.getLength() - 1;
             this.remove(new Range(0, 0, len, this.getLine(len).length));
             this.insert({row: 0, column: 0}, text || "");
    @@ -52,7 +44,7 @@ var Document = function(textOrLines) {
         /**
          * Returns all the lines in the document as a single string, joined by the new line character.
          **/
    -    this.getValue = function() {
    +   getValue() {
             return this.getAllLines().join(this.getNewLineCharacter());
         };
     
    @@ -62,7 +54,7 @@ var Document = function(textOrLines) {
          * @param {Number} column The column number to use
          *
          **/
    -    this.createAnchor = function(row, column) {
    +    createAnchor(row, column) {
             return new Anchor(this, row, column);
         };
     
    @@ -74,20 +66,14 @@ var Document = function(textOrLines) {
          * @returns {String} A String array, with each index containing a piece of the original `text` string.
          *
          **/
    -
         // check for IE split bug
    -    if ("aaa".split(/a/).length === 0) {
    -        this.$split = function(text) {
    -            return text.replace(/\r\n|\r/g, "\n").split("\n");
    -        };
    -    } else {
    -        this.$split = function(text) {
    -            return text.split(/\r\n|\r|\n/);
    -        };
    -    }
    -
    +    $split = ("aaa".split(/a/).length === 0) ? function (text) {
    +        return text.replace(/\r\n|\r/g, "\n").split("\n");
    +    } : function (text) {
    +        return text.split(/\r\n|\r|\n/);
    +    };
     
    -    this.$detectNewLine = function(text) {
    +    $detectNewLine(text) {
             var match = text.match(/^.*?(\r\n|\r|\n)/m);
             this.$autoNewLine = match ? match[1] : "\n";
             this._signal("changeNewLineMode");
    @@ -100,7 +86,7 @@ var Document = function(textOrLines) {
          *  If `newLineMode == auto`, the value of `autoNewLine` is returned.
          *
          **/
    -    this.getNewLineCharacter = function() {
    +    getNewLineCharacter() {
             switch (this.$newLineMode) {
               case "windows":
                 return "\r\n";
    @@ -111,14 +97,14 @@ var Document = function(textOrLines) {
             }
         };
     
    -    this.$autoNewLine = "";
    -    this.$newLineMode = "auto";
    +    $autoNewLine = "";
    +    $newLineMode = "auto";
         /**
          * [Sets the new line mode.]{: #Document.setNewLineMode.desc}
          * @param {String} newLineMode [The newline mode to use; can be either `windows`, `unix`, or `auto`]{: #Document.setNewLineMode.param}
          *
          **/
    -    this.setNewLineMode = function(newLineMode) {
    +    setNewLineMode(newLineMode) {
             if (this.$newLineMode === newLineMode)
                 return;
     
    @@ -130,7 +116,7 @@ var Document = function(textOrLines) {
          * [Returns the type of newlines being used; either `windows`, `unix`, or `auto`]{: #Document.getNewLineMode}
          * @returns {String}
          **/
    -    this.getNewLineMode = function() {
    +    getNewLineMode() {
             return this.$newLineMode;
         };
     
    @@ -139,7 +125,7 @@ var Document = function(textOrLines) {
          * @param {String} text The text to check
          *
          **/
    -    this.isNewLine = function(text) {
    +    isNewLine(text) {
             return (text == "\r\n" || text == "\r" || text == "\n");
         };
     
    @@ -148,7 +134,7 @@ var Document = function(textOrLines) {
          * @param {Number} row The row index to retrieve
          *
          **/
    -    this.getLine = function(row) {
    +    getLine(row) {
             return this.$lines[row] || "";
         };
     
    @@ -158,21 +144,21 @@ var Document = function(textOrLines) {
          * @param {Number} lastRow The final row index to retrieve
          *
          **/
    -    this.getLines = function(firstRow, lastRow) {
    +    getLines(firstRow, lastRow) {
             return this.$lines.slice(firstRow, lastRow + 1);
         };
     
         /**
          * Returns all lines in the document as string array.
          **/
    -    this.getAllLines = function() {
    +    getAllLines() {
             return this.getLines(0, this.getLength());
         };
     
         /**
          * Returns the number of rows in the document.
          **/
    -    this.getLength = function() {
    +    getLength() {
             return this.$lines.length;
         };
     
    @@ -182,7 +168,7 @@ var Document = function(textOrLines) {
          * 
          * @returns {String}
          **/
    -    this.getTextRange = function(range) {
    +    getTextRange(range) {
             return this.getLinesForRange(range).join(this.getNewLineCharacter());
         };
         
    @@ -192,7 +178,7 @@ var Document = function(textOrLines) {
          * 
          * @returns {string[]}
          **/
    -    this.getLinesForRange = function(range) {
    +    getLinesForRange(range) {
             var lines;
             if (range.start.row === range.end.row) {
                 // Handle a single-line range.
    @@ -209,27 +195,27 @@ var Document = function(textOrLines) {
         };
     
         // Deprecated methods retained for backwards compatibility.
    -    this.insertLines = function(row, lines) {
    +    insertLines(row, lines) {
             console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead.");
             return this.insertFullLines(row, lines);
         };
    -    this.removeLines = function(firstRow, lastRow) {
    +    removeLines(firstRow, lastRow) {
             console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead.");
             return this.removeFullLines(firstRow, lastRow);
         };
    -    this.insertNewLine = function(position) {
    +    insertNewLine(position) {
             console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead.");
             return this.insertMergedLines(position, ["", ""]);
         };
     
         /**
          * Inserts a block of `text` at the indicated `position`.
    -     * @param {Object} position The position to start inserting at; it's an object that looks like `{ row: row, column: column}`
    +     * @param {Position} position The position to start inserting at; it's an object that looks like `{ row: row, column: column}`
          * @param {String} text A chunk of text to insert
          * @returns {Object} The position ({row, column}) of the last line of `text`. If the length of `text` is 0, this function simply returns `position`. 
          *
          **/
    -    this.insert = function(position, text) {
    +    insert(position, text) {
             // Only detect new lines if the document has no line break yet.
             if (this.getLength() <= 1)
                 this.$detectNewLine(text);
    @@ -251,7 +237,7 @@ var Document = function(textOrLines) {
          *     {row: endRow, column: 0}
          *     ```
          **/
    -    this.insertInLine = function(position, text) {
    +    insertInLine(position, text) {
             var start = this.clippedPos(position.row, position.column);
             var end = this.pos(position.row, position.column + text.length);
             
    @@ -265,7 +251,7 @@ var Document = function(textOrLines) {
             return this.clonePos(end);
         };
         
    -    this.clippedPos = function(row, column) {
    +    clippedPos(row, column) {
             var length = this.getLength();
             if (row === undefined) {
                 row = length;
    @@ -282,15 +268,15 @@ var Document = function(textOrLines) {
             return {row: row, column: column};
         };
         
    -    this.clonePos = function(pos) {
    +    clonePos(pos) {
             return {row: pos.row, column: pos.column};
         };
         
    -    this.pos = function(row, column) {
    +    pos(row, column) {
             return {row: row, column: column};
         };
         
    -    this.$clipPosition = function(position) {
    +    $clipPosition(position) {
             var length = this.getLength();
             if (position.row >= length) {
                 position.row = Math.max(0, length - 1);
    @@ -333,7 +319,7 @@ var Document = function(textOrLines) {
          *   ```
          *
          **/
    -    this.insertFullLines = function(row, lines) {
    +    insertFullLines(row, lines) {
             // Clip to document.
             // Allow one past the document end.
             row = Math.min(Math.max(row, 0), this.getLength());
    @@ -357,7 +343,7 @@ var Document = function(textOrLines) {
     
         /**
          * Inserts the elements in `lines` into the document, starting at the position index given by `row`. This method also triggers the `"change"` event.
    -     * @param {Number} row The index of the row to insert at
    +     * @param {Position} position
          * @param {string[]} lines An array of strings
          * @returns {Object} Contains the final row and column, like this:  
          *   ```
    @@ -369,7 +355,7 @@ var Document = function(textOrLines) {
          *   ```
          *
          **/    
    -    this.insertMergedLines = function(position, lines) {
    +    insertMergedLines(position, lines) {
             var start = this.clippedPos(position.row, position.column);
             var end = {
                 row: start.row + lines.length - 1,
    @@ -392,7 +378,7 @@ var Document = function(textOrLines) {
          * @returns {Object} Returns the new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`.
          *
          **/
    -    this.remove = function(range) {
    +    remove(range) {
             var start = this.clippedPos(range.start.row, range.start.column);
             var end = this.clippedPos(range.end.row, range.end.column);
             this.applyDelta({
    @@ -412,7 +398,7 @@ var Document = function(textOrLines) {
          * @returns {Object} Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.
    If `startColumn` is equal to `endColumn`, this function returns nothing. * **/ - this.removeInLine = function(row, startColumn, endColumn) { + removeInLine(row, startColumn, endColumn) { var start = this.clippedPos(row, startColumn); var end = this.clippedPos(row, endColumn); @@ -433,7 +419,7 @@ var Document = function(textOrLines) { * @returns {[String]} Returns all the removed lines. * **/ - this.removeFullLines = function(firstRow, lastRow) { + removeFullLines(firstRow, lastRow) { // Clip to document. firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1); lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1); @@ -468,7 +454,7 @@ var Document = function(textOrLines) { * @param {Number} row The row to check * **/ - this.removeNewLine = function(row) { + removeNewLine(row) { if (row < this.getLength() - 1 && row >= 0) { this.applyDelta({ start: this.pos(row, this.getLine(row).length), @@ -489,7 +475,7 @@ var Document = function(textOrLines) { * If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value. * **/ - this.replace = function(range, text) { + replace(range, text) { if (!(range instanceof Range)) range = Range.fromPoints(range.start, range.end); if (text.length === 0 && range.isEmpty()) @@ -516,7 +502,7 @@ var Document = function(textOrLines) { * Applies all changes in `deltas` to the document. * @param {Delta[]} deltas An array of delta objects (can include "insert" and "remove" actions) **/ - this.applyDeltas = function(deltas) { + applyDeltas(deltas) { for (var i=0; i=0; i--) { this.revertDelta(deltas[i]); } @@ -535,8 +521,9 @@ var Document = function(textOrLines) { /** * Applies `delta` to the document. * @param {Object} delta A delta object (can include "insert" and "remove" actions) + * @param [doNotValidate] **/ - this.applyDelta = function(delta, doNotValidate) { + applyDelta(delta, doNotValidate) { var isInsert = delta.action == "insert"; // An empty range is a NOOP. if (isInsert ? delta.lines.length <= 1 && !delta.lines[0] @@ -553,7 +540,7 @@ var Document = function(textOrLines) { } }; - this.$safeApplyDelta = function(delta) { + $safeApplyDelta(delta) { var docLength = this.$lines.length; // verify that delta is in the document to prevent applyDelta from corrupting lines array if ( @@ -564,7 +551,7 @@ var Document = function(textOrLines) { } }; - this.$splitAndapplyLargeDelta = function(delta, MAX) { + $splitAndapplyLargeDelta(delta, MAX) { // Split large insert deltas. This is necessary because: // 1. We need to support splicing delta lines into the document via $lines.splice.apply(...) // 2. fn.apply() doesn't work for a large number of params. The smallest threshold is on chrome 40 ~42000. @@ -600,7 +587,7 @@ var Document = function(textOrLines) { * Reverts `delta` from the document. * @param {Object} delta A delta object (can include "insert" and "remove" actions) **/ - this.revertDelta = function(delta) { + revertDelta(delta) { this.$safeApplyDelta({ start: this.clonePos(delta.start), end: this.clonePos(delta.end), @@ -625,7 +612,7 @@ var Document = function(textOrLines) { * @param {Number} startRow=0 The row from which to start the conversion * @returns {Object} A `{row, column}` object of the `index` position */ - this.indexToPosition = function(index, startRow) { + indexToPosition(index, startRow) { var lines = this.$lines || this.getAllLines(); var newlineLength = this.getNewLineCharacter().length; for (var i = startRow || 0, l = lines.length; i < l; i++) { @@ -652,7 +639,7 @@ var Document = function(textOrLines) { * @param {Number} startRow=0 The row from which to start the conversion * @returns {Number} The index position in the document */ - this.positionToIndex = function(pos, startRow) { + positionToIndex(pos, startRow) { var lines = this.$lines || this.getAllLines(); var newlineLength = this.getNewLineCharacter().length; var index = 0; @@ -663,6 +650,8 @@ var Document = function(textOrLines) { return index + pos.column; }; -}).call(Document.prototype); +} + +oop.implement(Document.prototype, EventEmitter); exports.Document = Document; diff --git a/src/edit_session.js b/src/edit_session.js index 371ec62f3f4..eb9c93f9c58 100644 --- a/src/edit_session.js +++ b/src/edit_session.js @@ -12,13 +12,6 @@ var Document = require("./document").Document; var BackgroundTokenizer = require("./background_tokenizer").BackgroundTokenizer; var SearchHighlight = require("./search_highlight").SearchHighlight; -/** - * Stores all the data about [[Editor `Editor`]] state providing easy way to change editors state. - * - * `EditSession` can be attached to only one [[Document `Document`]]. Same `Document` can be attached to several `EditSession`s. - * @class EditSession - **/ - //{ events /** * @@ -102,58 +95,57 @@ var SearchHighlight = require("./search_highlight").SearchHighlight; //} /** - * Sets up a new `EditSession` and associates it with the given `Document` and `Mode`. - * @param {Document | String} text [If `text` is a `Document`, it associates the `EditSession` with it. Otherwise, a new `Document` is created, with the initial text]{: #textParam} - * @param {Mode} mode [The initial language mode to use for the document]{: #modeParam} + * Stores all the data about [[Editor `Editor`]] state providing easy way to change editors state. * - * @constructor + * `EditSession` can be attached to only one [[Document `Document`]]. Same `Document` can be attached to several `EditSession`s. **/ -var EditSession = function(text, mode) { - this.$breakpoints = []; - this.$decorations = []; - this.$frontMarkers = {}; - this.$backMarkers = {}; - this.$markerId = 1; - this.$undoSelect = true; - - this.$foldData = []; - this.id = "session" + (++EditSession.$uid); - this.$foldData.toString = function() { - return this.join("\n"); - }; - - // Set default background tokenizer with Text mode until editor session mode is set - this.bgTokenizer = new BackgroundTokenizer((new TextMode()).getTokenizer(), this); - - var _self = this; - this.bgTokenizer.on("update", function(e) { - _self._signal("tokenizerUpdate", e); - }); - - this.on("changeFold", this.onChangeFold.bind(this)); - this.$onChange = this.onChange.bind(this); - - if (typeof text != "object" || !text.getLine) - text = new Document(text); +class EditSession { + static $uid = 0; + + /** + * Sets up a new `EditSession` and associates it with the given `Document` and `Mode`. + * @param {Document | String} text [If `text` is a `Document`, it associates the `EditSession` with it. Otherwise, a new `Document` is created, with the initial text]{: #textParam} + * @param {Mode} mode [The initial language mode to use for the document]{: #modeParam} + **/ + constructor(text, mode) { + this.$breakpoints = []; + this.$decorations = []; + this.$frontMarkers = {}; + this.$backMarkers = {}; + this.$markerId = 1; + this.$undoSelect = true; + + this.$foldData = []; + this.id = "session" + (++EditSession.$uid); + this.$foldData.toString = function() { + return this.join("\n"); + }; - this.setDocument(text); - this.selection = new Selection(this); - this.$bidiHandler = new BidiHandler(this); + // Set default background tokenizer with Text mode until editor session mode is set + this.bgTokenizer = new BackgroundTokenizer((new TextMode()).getTokenizer(), this); - config.resetOptions(this); - this.setMode(mode); - config._signal("session", this); + var _self = this; + this.bgTokenizer.on("update", function(e) { + _self._signal("tokenizerUpdate", e); + }); - this.destroyed = false; -}; + this.on("changeFold", this.onChangeFold.bind(this)); + this.$onChange = this.onChange.bind(this); + if (typeof text != "object" || !text.getLine) + text = new Document(text); -EditSession.$uid = 0; + this.setDocument(text); + this.selection = new Selection(this); + this.$bidiHandler = new BidiHandler(this); -(function() { + config.resetOptions(this); + this.setMode(mode); + config._signal("session", this); - oop.implement(this, EventEmitter); + this.destroyed = false; + }; /** * Sets the `EditSession` to point to a new `Document`. If a `BackgroundTokenizer` exists, it also points to `doc`. @@ -161,7 +153,7 @@ EditSession.$uid = 0; * @param {Document} doc The new `Document` to use * **/ - this.setDocument = function(doc) { + setDocument(doc) { if (this.doc) this.doc.off("change", this.$onChange); @@ -177,15 +169,15 @@ EditSession.$uid = 0; * Returns the `Document` associated with this session. * @return {Document} **/ - this.getDocument = function() { + getDocument() { return this.doc; }; /** - * @param {Number} row The row to work with + * @param {Number} docRow The row to work with * **/ - this.$resetRowCache = function(docRow) { + $resetRowCache(docRow) { if (!docRow) { this.$docRowCache = []; this.$screenRowCache = []; @@ -199,7 +191,7 @@ EditSession.$uid = 0; } }; - this.$getRowCacheIndex = function(cacheArray, val) { + $getRowCacheIndex(cacheArray, val) { var low = 0; var hi = cacheArray.length - 1; @@ -218,7 +210,7 @@ EditSession.$uid = 0; return low -1; }; - this.resetCaches = function() { + resetCaches() { this.$modified = true; this.$wrapData = []; this.$rowLengthCache = []; @@ -227,12 +219,12 @@ EditSession.$uid = 0; this.bgTokenizer.start(0); }; - this.onChangeFold = function(e) { + onChangeFold(e) { var fold = e.data; this.$resetRowCache(fold.start.row); }; - this.onChange = function(delta) { + onChange(delta) { this.$modified = true; this.$bidiHandler.onChange(delta); this.$resetRowCache(delta.start.row); @@ -261,7 +253,7 @@ EditSession.$uid = 0; * @param {String} text The new text to place * **/ - this.setValue = function(text) { + setValue(text) { this.doc.setValue(text); this.selection.moveTo(0, 0); @@ -269,7 +261,7 @@ EditSession.$uid = 0; this.setUndoManager(this.$undoManager); this.getUndoManager().reset(); }; - + /** * Returns the current [[Document `Document`]] as a string. * @method toString @@ -277,6 +269,9 @@ EditSession.$uid = 0; * @alias EditSession.getValue * **/ + toString = function() { + return this.doc.getValue(); + }; /** * Returns the current [[Document `Document`]] as a string. @@ -284,15 +279,12 @@ EditSession.$uid = 0; * @returns {String} * @alias EditSession.toString **/ - this.getValue = - this.toString = function() { - return this.doc.getValue(); - }; + getValue = this.toString; /** * Returns selection object. **/ - this.getSelection = function() { + getSelection() { return this.selection; }; @@ -302,7 +294,7 @@ EditSession.$uid = 0; * * @related BackgroundTokenizer.getState **/ - this.getState = function(row) { + getState(row) { return this.bgTokenizer.getState(row); }; @@ -311,7 +303,7 @@ EditSession.$uid = 0; * @param {Number} row The row to start at * @returns {Token[]} **/ - this.getTokens = function(row) { + getTokens(row) { return this.bgTokenizer.getTokens(row); }; @@ -322,7 +314,7 @@ EditSession.$uid = 0; * @returns {Token} * **/ - this.getTokenAt = function(row, column) { + getTokenAt(row, column) { var tokens = this.bgTokenizer.getTokens(row); var token, c = 0; if (column == null) { @@ -349,7 +341,7 @@ EditSession.$uid = 0; * * **/ - this.setUndoManager = function(undoManager) { + setUndoManager(undoManager) { this.$undoManager = undoManager; if (this.$informUndoManager) @@ -371,12 +363,12 @@ EditSession.$uid = 0; /** * starts a new group in undo history **/ - this.markUndoGroup = function() { + markUndoGroup() { if (this.$syncInformUndoManager) this.$syncInformUndoManager(); }; - this.$defaultUndoManager = { + $defaultUndoManager = { undo: function() {}, redo: function() {}, hasUndo: function() {}, @@ -391,14 +383,14 @@ EditSession.$uid = 0; /** * Returns the current undo manager. **/ - this.getUndoManager = function() { + getUndoManager() { return this.$undoManager || this.$defaultUndoManager; }; /** * Returns the current value for tabs. If the user is using soft tabs, this will be a series of spaces (defined by [[EditSession.getTabSize `getTabSize()`]]); otherwise it's simply `'\t'`. **/ - this.getTabString = function() { + getTabString() { if (this.getUseSoftTabs()) { return lang.stringRepeat(" ", this.getTabSize()); } else { @@ -408,16 +400,17 @@ EditSession.$uid = 0; /** * Pass `true` to enable the use of soft tabs. Soft tabs means you're using spaces instead of the tab character (`'\t'`). - * @param {Boolean} useSoftTabs Value indicating whether or not to use soft tabs + * @param {Boolean} val Value indicating whether or not to use soft tabs **/ - this.setUseSoftTabs = function(val) { + setUseSoftTabs(val) { this.setOption("useSoftTabs", val); }; + /** * Returns `true` if soft tabs are being used, `false` otherwise. * @returns {Boolean} **/ - this.getUseSoftTabs = function() { + getUseSoftTabs() { // todo might need more general way for changing settings from mode, but this is ok for now return this.$useSoftTabs && !this.$mode.$indentWithTabs; }; @@ -425,13 +418,13 @@ EditSession.$uid = 0; * Set the number of spaces that define a soft tab; for example, passing in `4` transforms the soft tabs to be equivalent to four spaces. This function also emits the `changeTabSize` event. * @param {Number} tabSize The new tab size **/ - this.setTabSize = function(tabSize) { + setTabSize(tabSize) { this.setOption("tabSize", tabSize); }; /** * Returns the current tab size. **/ - this.getTabSize = function() { + getTabSize() { return this.$tabSize; }; @@ -440,7 +433,7 @@ EditSession.$uid = 0; * @param {Object} position The position to check * **/ - this.isTabStop = function(position) { + isTabStop(position) { return this.$useSoftTabs && (position.column % this.$tabSize === 0); }; @@ -448,18 +441,18 @@ EditSession.$uid = 0; * Set whether keyboard navigation of soft tabs moves the cursor within the soft tab, rather than over * @param {Boolean} navigateWithinSoftTabs Value indicating whether or not to navigate within soft tabs **/ - this.setNavigateWithinSoftTabs = function (navigateWithinSoftTabs) { + setNavigateWithinSoftTabs(navigateWithinSoftTabs) { this.setOption("navigateWithinSoftTabs", navigateWithinSoftTabs); }; /** * Returns `true` if keyboard navigation moves the cursor within soft tabs, `false` if it moves the cursor over soft tabs. * @returns {Boolean} **/ - this.getNavigateWithinSoftTabs = function() { + getNavigateWithinSoftTabs() { return this.$navigateWithinSoftTabs; }; - this.$overwrite = false; + $overwrite = false; /** * Pass in `true` to enable overwrites in your session, or `false` to disable. * @@ -469,21 +462,21 @@ EditSession.$uid = 0; * * **/ - this.setOverwrite = function(overwrite) { + setOverwrite(overwrite) { this.setOption("overwrite", overwrite); }; /** * Returns `true` if overwrites are enabled; `false` otherwise. **/ - this.getOverwrite = function() { + getOverwrite() { return this.$overwrite; }; /** * Sets the value of overwrite to the opposite of whatever it currently is. **/ - this.toggleOverwrite = function() { + toggleOverwrite() { this.setOverwrite(!this.$overwrite); }; @@ -493,7 +486,7 @@ EditSession.$uid = 0; * @param {String} className The class to add * **/ - this.addGutterDecoration = function(row, className) { + addGutterDecoration(row, className) { if (!this.$decorations[row]) this.$decorations[row] = ""; this.$decorations[row] += " " + className; @@ -506,7 +499,7 @@ EditSession.$uid = 0; * @param {String} className The class to add * **/ - this.removeGutterDecoration = function(row, className) { + removeGutterDecoration(row, className) { this.$decorations[row] = (this.$decorations[row] || "").replace(" " + className, ""); this._signal("changeBreakpoint", {}); }; @@ -515,7 +508,7 @@ EditSession.$uid = 0; * Returns an array of strings, indicating the breakpoint class (if any) applied to each row. * @returns {[String]} **/ - this.getBreakpoints = function() { + getBreakpoints() { return this.$breakpoints; }; @@ -524,7 +517,7 @@ EditSession.$uid = 0; * @param {Array} rows An array of row indices * **/ - this.setBreakpoints = function(rows) { + setBreakpoints(rows) { this.$breakpoints = []; for (var i=0; i * The first position indicates the number of columns for `str` on screen.
    * The second value contains the position of the document column that this function read until. - * **/ - this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) { + $getStringScreenWidth(str, maxScreenColumn, screenColumn) { if (maxScreenColumn == 0) return [0, 0]; if (maxScreenColumn == null) @@ -1975,14 +1946,14 @@ EditSession.$uid = 0; return [screenColumn, column]; }; - this.lineWidgets = null; + lineWidgets = null; /** * Returns number of screenrows in a wrapped line. * @param {Number} row The row number to check * * @returns {Number} **/ - this.getRowLength = function(row) { + getRowLength(row) { var h = 1; if (this.lineWidgets) h += this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0; @@ -1992,7 +1963,7 @@ EditSession.$uid = 0; else return this.$wrapData[row].length + h; }; - this.getRowLineCount = function(row) { + getRowLineCount(row) { if (!this.$useWrapMode || !this.$wrapData[row]) { return 1; } else { @@ -2000,7 +1971,7 @@ EditSession.$uid = 0; } }; - this.getRowWrapIndent = function(screenRow) { + getRowWrapIndent(screenRow) { if (this.$useWrapMode) { var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE); var splits = this.$wrapData[pos.row]; @@ -2017,7 +1988,7 @@ EditSession.$uid = 0; * * @related EditSession.documentToScreenColumn **/ - this.getScreenLastRowColumn = function(screenRow) { + getScreenLastRowColumn(screenRow) { var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE); return this.documentToScreenColumn(pos.row, pos.column); }; @@ -2028,7 +1999,7 @@ EditSession.$uid = 0; * * @param {Number} docColumn **/ - this.getDocumentLastRowColumn = function(docRow, docColumn) { + getDocumentLastRowColumn(docRow, docColumn) { var screenRow = this.documentToScreenRow(docRow, docColumn); return this.getScreenLastRowColumn(screenRow); }; @@ -2039,7 +2010,7 @@ EditSession.$uid = 0; * @param {Number} docColumn * **/ - this.getDocumentLastRowColumnPosition = function(docRow, docColumn) { + getDocumentLastRowColumnPosition(docRow, docColumn) { var screenRow = this.documentToScreenRow(docRow, docColumn); return this.screenToDocumentPosition(screenRow, Number.MAX_VALUE / 10); }; @@ -2048,7 +2019,7 @@ EditSession.$uid = 0; * For the given row, this returns the split data. * @returns {String} **/ - this.getRowSplitData = function(row) { + getRowSplitData(row) { if (!this.$useWrapMode) { return undefined; } else { @@ -2062,17 +2033,17 @@ EditSession.$uid = 0; * * @returns {Number} **/ - this.getScreenTabSize = function(screenColumn) { + getScreenTabSize(screenColumn) { return this.$tabSize - (screenColumn % this.$tabSize | 0); }; - this.screenToDocumentRow = function(screenRow, screenColumn) { + screenToDocumentRow(screenRow, screenColumn) { return this.screenToDocumentPosition(screenRow, screenColumn).row; }; - this.screenToDocumentColumn = function(screenRow, screenColumn) { + screenToDocumentColumn(screenRow, screenColumn) { return this.screenToDocumentPosition(screenRow, screenColumn).column; }; @@ -2086,7 +2057,7 @@ EditSession.$uid = 0; * * @related EditSession.documentToScreenPosition **/ - this.screenToDocumentPosition = function(screenRow, screenColumn, offsetX) { + screenToDocumentPosition(screenRow, screenColumn, offsetX) { if (screenRow < 0) return {row: 0, column: 0}; @@ -2176,13 +2147,13 @@ EditSession.$uid = 0; /** * Converts document coordinates to screen coordinates. {:conversionConsiderations} - * @param {Number} docRow The document row to check - * @param {Number} docColumn The document column to check - * @returns {Object} The object returned by this method has two properties: `row` and `column`. + * @param {Number|Position} docRow The document row to check + * @param {Number|undefined} [docColumn] The document column to check + * @returns {Position} The object returned by this method has two properties: `row` and `column`. * * @related EditSession.screenToDocumentPosition **/ - this.documentToScreenPosition = function(docRow, docColumn) { + documentToScreenPosition(docRow, docColumn) { // Normalize the passed in arguments. if (typeof docColumn === "undefined") var pos = this.$clipPositionToDocument(docRow.row, docRow.column); @@ -2284,7 +2255,7 @@ EditSession.$uid = 0; * @returns {Number} * **/ - this.documentToScreenColumn = function(row, docColumn) { + documentToScreenColumn(row, docColumn) { return this.documentToScreenPosition(row, docColumn).column; }; @@ -2294,7 +2265,7 @@ EditSession.$uid = 0; * @param {Number} docColumn * **/ - this.documentToScreenRow = function(docRow, docColumn) { + documentToScreenRow(docRow, docColumn) { return this.documentToScreenPosition(docRow, docColumn).row; }; @@ -2302,7 +2273,7 @@ EditSession.$uid = 0; * Returns the length of the screen. * @returns {Number} **/ - this.getScreenLength = function() { + getScreenLength() { var screenRows = 0; var fold = null; if (!this.$useWrapMode) { @@ -2343,7 +2314,7 @@ EditSession.$uid = 0; * @private * */ - this.$setFontMetrics = function(fm) { + $setFontMetrics(fm) { if (!this.$enableVarChar) return; this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) { if (maxScreenColumn === 0) @@ -2370,7 +2341,7 @@ EditSession.$uid = 0; }; }; - this.destroy = function() { + destroy() { if (!this.destroyed) { this.bgTokenizer.setDocument(null); this.bgTokenizer.cleanup(); @@ -2384,49 +2355,58 @@ EditSession.$uid = 0; this.selection.detach(); }; - this.isFullWidth = isFullWidth; - - // For every keystroke this gets called once per char in the whole doc!! - // Wouldn't hurt to make it a bit faster for c >= 0x1100 - function isFullWidth(c) { - if (c < 0x1100) - return false; - return c >= 0x1100 && c <= 0x115F || - c >= 0x11A3 && c <= 0x11A7 || - c >= 0x11FA && c <= 0x11FF || - c >= 0x2329 && c <= 0x232A || - c >= 0x2E80 && c <= 0x2E99 || - c >= 0x2E9B && c <= 0x2EF3 || - c >= 0x2F00 && c <= 0x2FD5 || - c >= 0x2FF0 && c <= 0x2FFB || - c >= 0x3000 && c <= 0x303E || - c >= 0x3041 && c <= 0x3096 || - c >= 0x3099 && c <= 0x30FF || - c >= 0x3105 && c <= 0x312D || - c >= 0x3131 && c <= 0x318E || - c >= 0x3190 && c <= 0x31BA || - c >= 0x31C0 && c <= 0x31E3 || - c >= 0x31F0 && c <= 0x321E || - c >= 0x3220 && c <= 0x3247 || - c >= 0x3250 && c <= 0x32FE || - c >= 0x3300 && c <= 0x4DBF || - c >= 0x4E00 && c <= 0xA48C || - c >= 0xA490 && c <= 0xA4C6 || - c >= 0xA960 && c <= 0xA97C || - c >= 0xAC00 && c <= 0xD7A3 || - c >= 0xD7B0 && c <= 0xD7C6 || - c >= 0xD7CB && c <= 0xD7FB || - c >= 0xF900 && c <= 0xFAFF || - c >= 0xFE10 && c <= 0xFE19 || - c >= 0xFE30 && c <= 0xFE52 || - c >= 0xFE54 && c <= 0xFE66 || - c >= 0xFE68 && c <= 0xFE6B || - c >= 0xFF01 && c <= 0xFF60 || - c >= 0xFFE0 && c <= 0xFFE6; - } - -}).call(EditSession.prototype); - + isFullWidth = isFullWidth; + +} +oop.implement(EditSession.prototype, EventEmitter); + +// "Tokens" +var CHAR = 1, + CHAR_EXT = 2, + PLACEHOLDER_START = 3, + PLACEHOLDER_BODY = 4, + PUNCTUATION = 9, + SPACE = 10, + TAB = 11, + TAB_SPACE = 12; +// For every keystroke this gets called once per char in the whole doc!! +// Wouldn't hurt to make it a bit faster for c >= 0x1100 +function isFullWidth(c) { + if (c < 0x1100) + return false; + return c >= 0x1100 && c <= 0x115F || + c >= 0x11A3 && c <= 0x11A7 || + c >= 0x11FA && c <= 0x11FF || + c >= 0x2329 && c <= 0x232A || + c >= 0x2E80 && c <= 0x2E99 || + c >= 0x2E9B && c <= 0x2EF3 || + c >= 0x2F00 && c <= 0x2FD5 || + c >= 0x2FF0 && c <= 0x2FFB || + c >= 0x3000 && c <= 0x303E || + c >= 0x3041 && c <= 0x3096 || + c >= 0x3099 && c <= 0x30FF || + c >= 0x3105 && c <= 0x312D || + c >= 0x3131 && c <= 0x318E || + c >= 0x3190 && c <= 0x31BA || + c >= 0x31C0 && c <= 0x31E3 || + c >= 0x31F0 && c <= 0x321E || + c >= 0x3220 && c <= 0x3247 || + c >= 0x3250 && c <= 0x32FE || + c >= 0x3300 && c <= 0x4DBF || + c >= 0x4E00 && c <= 0xA48C || + c >= 0xA490 && c <= 0xA4C6 || + c >= 0xA960 && c <= 0xA97C || + c >= 0xAC00 && c <= 0xD7A3 || + c >= 0xD7B0 && c <= 0xD7C6 || + c >= 0xD7CB && c <= 0xD7FB || + c >= 0xF900 && c <= 0xFAFF || + c >= 0xFE10 && c <= 0xFE19 || + c >= 0xFE30 && c <= 0xFE52 || + c >= 0xFE54 && c <= 0xFE66 || + c >= 0xFE68 && c <= 0xFE6B || + c >= 0xFF01 && c <= 0xFF60 || + c >= 0xFFE0 && c <= 0xFFE6; +} require("./edit_session/folding").Folding.call(EditSession.prototype); require("./edit_session/bracket_match").BracketMatch.call(EditSession.prototype); diff --git a/src/edit_session/fold.js b/src/edit_session/fold.js index dbf74d6607d..690cad36b43 100644 --- a/src/edit_session/fold.js +++ b/src/edit_session/fold.js @@ -1,37 +1,35 @@ "use strict"; var RangeList = require("../range_list").RangeList; -var oop = require("../lib/oop"); + /* * Simple fold-data struct. **/ -var Fold = exports.Fold = function(range, placeholder) { - this.foldLine = null; - this.placeholder = placeholder; - this.range = range; - this.start = range.start; - this.end = range.end; - - this.sameRow = range.start.row == range.end.row; - this.subFolds = this.ranges = []; -}; - -oop.inherits(Fold, RangeList); - -(function() { +class Fold extends RangeList { + constructor(range, placeholder) { + super(); + this.foldLine = null; + this.placeholder = placeholder; + this.range = range; + this.start = range.start; + this.end = range.end; - this.toString = function() { + this.sameRow = range.start.row == range.end.row; + this.subFolds = this.ranges = []; + }; + + toString() { return '"' + this.placeholder + '" ' + this.range.toString(); }; - this.setFoldLine = function(foldLine) { + setFoldLine(foldLine) { this.foldLine = foldLine; this.subFolds.forEach(function(fold) { fold.setFoldLine(foldLine); }); }; - this.clone = function() { + clone() { var range = this.range.clone(); var fold = new Fold(range, this.placeholder); this.subFolds.forEach(function(subFold) { @@ -41,7 +39,7 @@ oop.inherits(Fold, RangeList); return fold; }; - this.addSubFold = function(fold) { + addSubFold(fold) { if (this.range.isEqual(fold)) return; @@ -82,11 +80,11 @@ oop.inherits(Fold, RangeList); return fold; }; - this.restoreRange = function(range) { + restoreRange(range) { return restoreRange(range, this.start); }; -}).call(Fold.prototype); +} function consumePoint(point, anchor) { point.row -= anchor.row; @@ -106,3 +104,5 @@ function restoreRange(range, anchor) { restorePoint(range.start, anchor); restorePoint(range.end, anchor); } + +exports.Fold = Fold; diff --git a/src/edit_session/fold_line.js b/src/edit_session/fold_line.js index 67daf431528..392eab38334 100644 --- a/src/edit_session/fold_line.js +++ b/src/edit_session/fold_line.js @@ -2,33 +2,32 @@ var Range = require("../range").Range; -/* - * If an array is passed in, the folds are expected to be sorted already. - */ -function FoldLine(foldData, folds) { - this.foldData = foldData; - if (Array.isArray(folds)) { - this.folds = folds; - } else { - folds = this.folds = [ folds ]; - } +class FoldLine { + /** + * If an array is passed in, the folds are expected to be sorted already. + */ + constructor(foldData, folds) { + this.foldData = foldData; + if (Array.isArray(folds)) { + this.folds = folds; + } else { + folds = this.folds = [ folds ]; + } - var last = folds[folds.length - 1]; - this.range = new Range(folds[0].start.row, folds[0].start.column, - last.end.row, last.end.column); - this.start = this.range.start; - this.end = this.range.end; + var last = folds[folds.length - 1]; + this.range = new Range(folds[0].start.row, folds[0].start.column, + last.end.row, last.end.column); + this.start = this.range.start; + this.end = this.range.end; - this.folds.forEach(function(fold) { - fold.setFoldLine(this); - }, this); -} - -(function() { + this.folds.forEach(function(fold) { + fold.setFoldLine(this); + }, this); + } /* * Note: This doesn't update wrapData! */ - this.shiftRow = function(shift) { + shiftRow(shift) { this.start.row += shift; this.end.row += shift; this.folds.forEach(function(fold) { @@ -37,7 +36,7 @@ function FoldLine(foldData, folds) { }); }; - this.addFold = function(fold) { + addFold(fold) { if (fold.sameRow) { if (fold.start.row < this.startRow || fold.endRow > this.endRow) { throw new Error("Can't add a fold to this FoldLine as it has no connection"); @@ -67,11 +66,11 @@ function FoldLine(foldData, folds) { fold.foldLine = this; }; - this.containsRow = function(row) { + containsRow(row) { return row >= this.start.row && row <= this.end.row; }; - this.walk = function(callback, endRow, endColumn) { + walk(callback, endRow, endColumn) { var lastEnd = 0, folds = this.folds, fold, @@ -109,7 +108,7 @@ function FoldLine(foldData, folds) { callback(null, endRow, endColumn, lastEnd, isNewRow); }; - this.getNextFoldTo = function(row, column) { + getNextFoldTo(row, column) { var fold, cmp; for (var i = 0; i < this.folds.length; i++) { fold = this.folds[i]; @@ -129,7 +128,7 @@ function FoldLine(foldData, folds) { return null; }; - this.addRemoveChars = function(row, column, len) { + addRemoveChars(row, column, len) { var ret = this.getNextFoldTo(row, column), fold, folds; if (ret) { @@ -160,7 +159,7 @@ function FoldLine(foldData, folds) { } }; - this.split = function(row, column) { + split(row, column) { var pos = this.getNextFoldTo(row, column); if (!pos || pos.kind == "inside") @@ -184,7 +183,7 @@ function FoldLine(foldData, folds) { return newFoldLine; }; - this.merge = function(foldLineNext) { + merge(foldLineNext) { var folds = foldLineNext.folds; for (var i = 0; i < folds.length; i++) { this.addFold(folds[i]); @@ -195,7 +194,7 @@ function FoldLine(foldData, folds) { foldData.splice(foldData.indexOf(foldLineNext), 1); }; - this.toString = function() { + toString() { var ret = [this.range.toString() + ": [" ]; this.folds.forEach(function(fold) { @@ -205,7 +204,7 @@ function FoldLine(foldData, folds) { return ret.join("\n"); }; - this.idxToPosition = function(idx) { + idxToPosition(idx) { var lastFoldEndColumn = 0; for (var i = 0; i < this.folds.length; i++) { @@ -232,6 +231,6 @@ function FoldLine(foldData, folds) { column: this.end.column + idx }; }; -}).call(FoldLine.prototype); +} exports.FoldLine = FoldLine; diff --git a/src/editor.js b/src/editor.js index 8fc5808b14d..b72832f4649 100644 --- a/src/editor.js +++ b/src/editor.js @@ -26,69 +26,61 @@ var clipboard = require("./clipboard"); * The `Editor` manages the [[EditSession]] (which manages [[Document]]s), as well as the [[VirtualRenderer]], which draws everything to the screen. * * Event sessions dealing with the mouse and keyboard are bubbled up from `Document` to the `Editor`, which decides what to do with them. - * @class Editor **/ +class Editor { + static $uid = 0; + + /** + * Creates a new `Editor` object. + * + * @param {VirtualRenderer} renderer Associated `VirtualRenderer` that draws everything + * @param {EditSession} session The `EditSession` to refer to + **/ + constructor(renderer, session, options) { + this.$toDestroy = []; + var container = renderer.getContainerElement(); + this.container = container; + this.renderer = renderer; + this.id = "editor" + (++Editor.$uid); -/** - * Creates a new `Editor` object. - * - * @param {VirtualRenderer} renderer Associated `VirtualRenderer` that draws everything - * @param {EditSession} session The `EditSession` to refer to - * - * - * @constructor - **/ -var Editor = function(renderer, session, options) { - this.$toDestroy = []; - var container = renderer.getContainerElement(); - this.container = container; - this.renderer = renderer; - this.id = "editor" + (++Editor.$uid); - - this.commands = new CommandManager(useragent.isMac ? "mac" : "win", defaultCommands); - if (typeof document == "object") { - this.textInput = new TextInput(renderer.getTextAreaContainer(), this); - this.renderer.textarea = this.textInput.getElement(); - // TODO detect touch event support - this.$mouseHandler = new MouseHandler(this); - new FoldHandler(this); - } + this.commands = new CommandManager(useragent.isMac ? "mac" : "win", defaultCommands); + if (typeof document == "object") { + this.textInput = new TextInput(renderer.getTextAreaContainer(), this); + this.renderer.textarea = this.textInput.getElement(); + // TODO detect touch event support + this.$mouseHandler = new MouseHandler(this); + new FoldHandler(this); + } - this.keyBinding = new KeyBinding(this); + this.keyBinding = new KeyBinding(this); - this.$search = new Search().set({ - wrap: true - }); + this.$search = new Search().set({ + wrap: true + }); - this.$historyTracker = this.$historyTracker.bind(this); - this.commands.on("exec", this.$historyTracker); + this.$historyTracker = this.$historyTracker.bind(this); + this.commands.on("exec", this.$historyTracker); - this.$initOperationListeners(); - - this._$emitInputEvent = lang.delayedCall(function() { - this._signal("input", {}); - if (this.session && !this.session.destroyed) - this.session.bgTokenizer.scheduleStart(); - }.bind(this)); - - this.on("change", function(_, _self) { - _self._$emitInputEvent.schedule(31); - }); - - this.setSession(session || options && options.session || new EditSession("")); - config.resetOptions(this); - if (options) - this.setOptions(options); - config._signal("editor", this); -}; + this.$initOperationListeners(); -Editor.$uid = 0; + this._$emitInputEvent = lang.delayedCall(function() { + this._signal("input", {}); + if (this.session && !this.session.destroyed) + this.session.bgTokenizer.scheduleStart(); + }.bind(this)); -(function(){ + this.on("change", function(_, _self) { + _self._$emitInputEvent.schedule(31); + }); - oop.implement(this, EventEmitter); + this.setSession(session || options && options.session || new EditSession("")); + config.resetOptions(this); + if (options) + this.setOptions(options); + config._signal("editor", this); + }; - this.$initOperationListeners = function() { + $initOperationListeners() { this.commands.on("exec", this.startOperation.bind(this), true); this.commands.on("afterExec", this.endOperation.bind(this), true); @@ -112,9 +104,9 @@ Editor.$uid = 0; }.bind(this), true); }; - this.curOp = null; - this.prevOp = {}; - this.startOperation = function(commandEvent) { + curOp = null; + prevOp = {}; + startOperation(commandEvent) { if (this.curOp) { if (!commandEvent || this.curOp.command) return; @@ -134,7 +126,7 @@ Editor.$uid = 0; this.curOp.selectionBefore = this.selection.toJSON(); }; - this.endOperation = function(e) { + endOperation(e) { if (this.curOp && this.session) { if (e && e.returnValue === false || !this.session) return (this.curOp = null); @@ -181,8 +173,8 @@ Editor.$uid = 0; }; // TODO use property on commands instead of this - this.$mergeableCommands = ["backspace", "del", "insertstring"]; - this.$historyTracker = function(e) { + $mergeableCommands = ["backspace", "del", "insertstring"]; + $historyTracker(e) { if (!this.$mergeUndoDeltas) return; @@ -223,7 +215,7 @@ Editor.$uid = 0; * @param {String} keyboardHandler The new key handler * **/ - this.setKeyboardHandler = function(keyboardHandler, cb) { + setKeyboardHandler(keyboardHandler, cb) { if (keyboardHandler && typeof keyboardHandler === "string" && keyboardHandler != "ace") { this.$keybindingId = keyboardHandler; var _self = this; @@ -245,7 +237,7 @@ Editor.$uid = 0; * @returns {String} * **/ - this.getKeyboardHandler = function() { + getKeyboardHandler() { return this.keyBinding.getKeyboardHandler(); }; @@ -261,7 +253,7 @@ Editor.$uid = 0; * @param {EditSession} session The new session to use * **/ - this.setSession = function(session) { + setSession(session) { if (this.session == session) return; @@ -378,7 +370,7 @@ Editor.$uid = 0; * Returns the current session being used. * @returns {EditSession} **/ - this.getSession = function() { + getSession() { return this.session; }; @@ -390,7 +382,7 @@ Editor.$uid = 0; * @returns {String} The current document value * @related Document.setValue **/ - this.setValue = function(val, cursorPos) { + setValue(val, cursorPos) { this.session.doc.setValue(val); if (!cursorPos) @@ -409,7 +401,7 @@ Editor.$uid = 0; * @returns {String} * @related EditSession.getValue **/ - this.getValue = function() { + getValue() { return this.session.getValue(); }; @@ -418,7 +410,7 @@ Editor.$uid = 0; * Returns the currently highlighted selection. * @returns {Selection} The selection object **/ - this.getSelection = function() { + getSelection() { return this.selection; }; @@ -429,7 +421,7 @@ Editor.$uid = 0; * * @related VirtualRenderer.onResize **/ - this.resize = function(force) { + resize(force) { this.renderer.onResize(force); }; @@ -438,7 +430,7 @@ Editor.$uid = 0; * @param {String} theme The path to a theme * @param {Function} cb optional callback called when theme is loaded **/ - this.setTheme = function(theme, cb) { + setTheme(theme, cb) { this.renderer.setTheme(theme, cb); }; @@ -448,7 +440,7 @@ Editor.$uid = 0; * @returns {String} The set theme * @related VirtualRenderer.getTheme **/ - this.getTheme = function() { + getTheme() { return this.renderer.getTheme(); }; @@ -459,7 +451,7 @@ Editor.$uid = 0; * * @related VirtualRenderer.setStyle **/ - this.setStyle = function(style) { + setStyle(style) { this.renderer.setStyle(style); }; @@ -467,14 +459,14 @@ Editor.$uid = 0; * {:VirtualRenderer.unsetStyle} * @related VirtualRenderer.unsetStyle **/ - this.unsetStyle = function(style) { + unsetStyle(style) { this.renderer.unsetStyle(style); }; /** * Gets the current font size of the editor text. */ - this.getFontSize = function () { + getFontSize() { return this.getOption("fontSize") || dom.computedStyle(this.container).fontSize; }; @@ -485,11 +477,11 @@ Editor.$uid = 0; * * **/ - this.setFontSize = function(size) { + setFontSize(size) { this.setOption("fontSize", size); }; - this.$highlightBrackets = function() { + $highlightBrackets() { if (this.$highlightPending) { return; } @@ -557,7 +549,7 @@ Editor.$uid = 0; * * Brings the current `textInput` into focus. **/ - this.focus = function() { + focus() { this.textInput.focus(); }; @@ -565,7 +557,7 @@ Editor.$uid = 0; * Returns `true` if the current `textInput` is in focus. * @return {Boolean} **/ - this.isFocused = function() { + isFocused() { return this.textInput.isFocused(); }; @@ -573,7 +565,7 @@ Editor.$uid = 0; * * Blurs the current `textInput`. **/ - this.blur = function() { + blur() { this.textInput.blur(); }; @@ -583,7 +575,7 @@ Editor.$uid = 0; * * **/ - this.onFocus = function(e) { + onFocus(e) { if (this.$isFocused) return; this.$isFocused = true; @@ -598,7 +590,7 @@ Editor.$uid = 0; * * **/ - this.onBlur = function(e) { + onBlur(e) { if (!this.$isFocused) return; this.$isFocused = false; @@ -607,7 +599,7 @@ Editor.$uid = 0; this._emit("blur", e); }; - this.$cursorChange = function() { + $cursorChange() { this.renderer.updateCursor(); this.$highlightBrackets(); this.$updateHighlightActiveLine(); @@ -616,12 +608,12 @@ Editor.$uid = 0; /** * Emitted whenever the document is changed. * @event change - * @param {Object} e Contains a single property, `data`, which has the delta of changes + * @param {Object} delta Contains a single property, `data`, which has the delta of changes * * * **/ - this.onDocumentChange = function(delta) { + onDocumentChange(delta) { // Rerender and emit "change" event. var wrap = this.session.$useWrapMode; var lastRow = (delta.start.row == delta.end.row ? delta.end.row : Infinity); @@ -633,17 +625,17 @@ Editor.$uid = 0; this.$cursorChange(); }; - this.onTokenizerUpdate = function(e) { + onTokenizerUpdate(e) { var rows = e.data; this.renderer.updateLines(rows.first, rows.last); }; - this.onScrollTopChange = function() { + onScrollTopChange() { this.renderer.scrollToY(this.session.getScrollTop()); }; - this.onScrollLeftChange = function() { + onScrollLeftChange() { this.renderer.scrollToX(this.session.getScrollLeft()); }; @@ -651,12 +643,12 @@ Editor.$uid = 0; * Emitted when the selection changes. * **/ - this.onCursorChange = function() { + onCursorChange() { this.$cursorChange(); this._signal("changeSelection"); }; - this.$updateHighlightActiveLine = function() { + $updateHighlightActiveLine() { var session = this.getSession(); var highlight; @@ -684,7 +676,7 @@ Editor.$uid = 0; } }; - this.onSelectionChange = function(e) { + onSelectionChange(e) { var session = this.session; if (session.$selectionMarker) { @@ -706,7 +698,7 @@ Editor.$uid = 0; this._signal("changeSelection"); }; - this.$getSelectionHighLightRegexp = function() { + $getSelectionHighLightRegexp() { var session = this.session; var selection = this.getSelectionRange(); @@ -737,40 +729,40 @@ Editor.$uid = 0; }; - this.onChangeFrontMarker = function() { + onChangeFrontMarker() { this.renderer.updateFrontMarkers(); }; - this.onChangeBackMarker = function() { + onChangeBackMarker() { this.renderer.updateBackMarkers(); }; - this.onChangeBreakpoint = function() { + onChangeBreakpoint() { this.renderer.updateBreakpoints(); }; - this.onChangeAnnotation = function() { + onChangeAnnotation() { this.renderer.setAnnotations(this.session.getAnnotations()); }; - this.onChangeMode = function(e) { + onChangeMode (e) { this.renderer.updateText(); this._emit("changeMode", e); }; - this.onChangeWrapLimit = function() { + onChangeWrapLimit() { this.renderer.updateFull(); }; - this.onChangeWrapMode = function() { + onChangeWrapMode() { this.renderer.onResize(true); }; - this.onChangeFold = function() { + onChangeFold() { // Update the active line marker as due to folding changes the current // line range on the screen might have changed. this.$updateHighlightActiveLine(); @@ -783,7 +775,7 @@ Editor.$uid = 0; * Returns the string of text currently highlighted. * @returns {String} **/ - this.getSelectedText = function() { + getSelectedText() { return this.session.getTextRange(this.getSelectionRange()); }; @@ -797,7 +789,7 @@ Editor.$uid = 0; * Returns the string of text currently highlighted. * @returns {String} **/ - this.getCopyText = function() { + getCopyText () { var text = this.getSelectedText(); var nl = this.session.doc.getNewLineCharacter(); var copyLine= false; @@ -820,14 +812,14 @@ Editor.$uid = 0; /** * Called whenever a text "copy" happens. **/ - this.onCopy = function() { + onCopy() { this.commands.exec("copy", this); }; /** * Called whenever a text "cut" happens. **/ - this.onCut = function() { + onCut() { this.commands.exec("cut", this); }; @@ -844,12 +836,12 @@ Editor.$uid = 0; * * **/ - this.onPaste = function(text, event) { + onPaste(text, event) { var e = {text: text, event: event}; this.commands.exec("paste", this, e); }; - this.$handlePaste = function(e) { + $handlePaste(e) { if (typeof e == "string") e = {text: e}; this._signal("paste", e); @@ -884,7 +876,7 @@ Editor.$uid = 0; } }; - this.execCommand = function(command, args) { + execCommand(command, args) { return this.commands.exec(command, this, args); }; @@ -893,7 +885,7 @@ Editor.$uid = 0; * @param {String} text The new text to add * **/ - this.insert = function(text, pasted) { + insert(text, pasted) { var session = this.session; var mode = session.getMode(); var cursor = this.getCursorPosition(); @@ -968,7 +960,7 @@ Editor.$uid = 0; } }; - this.autoIndent = function () { + autoIndent() { var session = this.session; var mode = session.getMode(); @@ -1013,7 +1005,7 @@ Editor.$uid = 0; }; - this.onTextInput = function(text, composition) { + onTextInput(text, composition) { if (!composition) return this.keyBinding.onTextInput(text); @@ -1026,7 +1018,7 @@ Editor.$uid = 0; this.endOperation(); }; - this.applyComposition = function(text, composition) { + applyComposition(text, composition) { if (composition.extendLeft || composition.extendRight) { var r = this.selection.getRange(); r.start.column -= composition.extendLeft; @@ -1049,7 +1041,7 @@ Editor.$uid = 0; } }; - this.onCommandKey = function(e, hashId, keyCode) { + onCommandKey(e, hashId, keyCode) { return this.keyBinding.onCommandKey(e, hashId, keyCode); }; @@ -1060,7 +1052,7 @@ Editor.$uid = 0; * * @related EditSession.setOverwrite **/ - this.setOverwrite = function(overwrite) { + setOverwrite(overwrite) { this.session.setOverwrite(overwrite); }; @@ -1069,7 +1061,7 @@ Editor.$uid = 0; * @returns {Boolean} * @related EditSession.getOverwrite **/ - this.getOverwrite = function() { + getOverwrite() { return this.session.getOverwrite(); }; @@ -1077,7 +1069,7 @@ Editor.$uid = 0; * Sets the value of overwrite to the opposite of whatever it currently is. * @related EditSession.toggleOverwrite **/ - this.toggleOverwrite = function() { + toggleOverwrite() { this.session.toggleOverwrite(); }; @@ -1085,7 +1077,7 @@ Editor.$uid = 0; * Sets how fast the mouse scrolling should do. * @param {Number} speed A value indicating the new speed (in milliseconds) **/ - this.setScrollSpeed = function(speed) { + setScrollSpeed(speed) { this.setOption("scrollSpeed", speed); }; @@ -1093,7 +1085,7 @@ Editor.$uid = 0; * Returns the value indicating how fast the mouse scroll speed is (in milliseconds). * @returns {Number} **/ - this.getScrollSpeed = function() { + getScrollSpeed() { return this.getOption("scrollSpeed"); }; @@ -1101,7 +1093,7 @@ Editor.$uid = 0; * Sets the delay (in milliseconds) of the mouse drag. * @param {Number} dragDelay A value indicating the new delay **/ - this.setDragDelay = function(dragDelay) { + setDragDelay(dragDelay) { this.setOption("dragDelay", dragDelay); }; @@ -1109,7 +1101,7 @@ Editor.$uid = 0; * Returns the current mouse drag delay. * @returns {Number} **/ - this.getDragDelay = function() { + getDragDelay() { return this.getOption("dragDelay"); }; @@ -1120,10 +1112,10 @@ Editor.$uid = 0; **/ /** * Draw selection markers spanning whole line, or only over selected text. Default value is "line" - * @param {String} style The new selection style "line"|"text" + * @param {String} val The new selection style "line"|"text" * **/ - this.setSelectionStyle = function(val) { + setSelectionStyle(val) { this.setOption("selectionStyle", val); }; @@ -1131,7 +1123,7 @@ Editor.$uid = 0; * Returns the current selection style. * @returns {String} **/ - this.getSelectionStyle = function() { + getSelectionStyle() { return this.getOption("selectionStyle"); }; @@ -1139,21 +1131,21 @@ Editor.$uid = 0; * Determines whether or not the current line should be highlighted. * @param {Boolean} shouldHighlight Set to `true` to highlight the current line **/ - this.setHighlightActiveLine = function(shouldHighlight) { + setHighlightActiveLine(shouldHighlight) { this.setOption("highlightActiveLine", shouldHighlight); }; /** * Returns `true` if current lines are always highlighted. * @return {Boolean} **/ - this.getHighlightActiveLine = function() { + getHighlightActiveLine() { return this.getOption("highlightActiveLine"); }; - this.setHighlightGutterLine = function(shouldHighlight) { + setHighlightGutterLine(shouldHighlight) { this.setOption("highlightGutterLine", shouldHighlight); }; - this.getHighlightGutterLine = function() { + getHighlightGutterLine() { return this.getOption("highlightGutterLine"); }; @@ -1162,7 +1154,7 @@ Editor.$uid = 0; * @param {Boolean} shouldHighlight Set to `true` to highlight the currently selected word * **/ - this.setHighlightSelectedWord = function(shouldHighlight) { + setHighlightSelectedWord(shouldHighlight) { this.setOption("highlightSelectedWord", shouldHighlight); }; @@ -1170,15 +1162,15 @@ Editor.$uid = 0; * Returns `true` if currently highlighted words are to be highlighted. * @returns {Boolean} **/ - this.getHighlightSelectedWord = function() { + getHighlightSelectedWord() { return this.$highlightSelectedWord; }; - this.setAnimatedScroll = function(shouldAnimate){ + setAnimatedScroll(shouldAnimate){ this.renderer.setAnimatedScroll(shouldAnimate); }; - this.getAnimatedScroll = function(){ + getAnimatedScroll(){ return this.renderer.getAnimatedScroll(); }; @@ -1187,7 +1179,7 @@ Editor.$uid = 0; * @param {Boolean} showInvisibles Specifies whether or not to show invisible characters * **/ - this.setShowInvisibles = function(showInvisibles) { + setShowInvisibles(showInvisibles) { this.renderer.setShowInvisibles(showInvisibles); }; @@ -1195,23 +1187,23 @@ Editor.$uid = 0; * Returns `true` if invisible characters are being shown. * @returns {Boolean} **/ - this.getShowInvisibles = function() { + getShowInvisibles() { return this.renderer.getShowInvisibles(); }; - this.setDisplayIndentGuides = function(display) { + setDisplayIndentGuides(display) { this.renderer.setDisplayIndentGuides(display); }; - this.getDisplayIndentGuides = function() { + getDisplayIndentGuides() { return this.renderer.getDisplayIndentGuides(); }; - this.setHighlightIndentGuides = function(highlight) { + setHighlightIndentGuides(highlight) { this.renderer.setHighlightIndentGuides(highlight); }; - this.getHighlightIndentGuides = function() { + getHighlightIndentGuides() { return this.renderer.getHighlightIndentGuides(); }; @@ -1220,7 +1212,7 @@ Editor.$uid = 0; * @param {Boolean} showPrintMargin Specifies whether or not to show the print margin * **/ - this.setShowPrintMargin = function(showPrintMargin) { + setShowPrintMargin(showPrintMargin) { this.renderer.setShowPrintMargin(showPrintMargin); }; @@ -1228,7 +1220,7 @@ Editor.$uid = 0; * Returns `true` if the print margin is being shown. * @returns {Boolean} **/ - this.getShowPrintMargin = function() { + getShowPrintMargin() { return this.renderer.getShowPrintMargin(); }; @@ -1237,7 +1229,7 @@ Editor.$uid = 0; * @param {Number} showPrintMargin Specifies the new print margin * **/ - this.setPrintMarginColumn = function(showPrintMargin) { + setPrintMarginColumn(showPrintMargin) { this.renderer.setPrintMarginColumn(showPrintMargin); }; @@ -1245,7 +1237,7 @@ Editor.$uid = 0; * Returns the column number of where the print margin is. * @returns {Number} **/ - this.getPrintMarginColumn = function() { + getPrintMarginColumn() { return this.renderer.getPrintMarginColumn(); }; @@ -1254,7 +1246,7 @@ Editor.$uid = 0; * @param {Boolean} readOnly Specifies whether the editor can be modified or not * **/ - this.setReadOnly = function(readOnly) { + setReadOnly(readOnly) { this.setOption("readOnly", readOnly); }; @@ -1262,7 +1254,7 @@ Editor.$uid = 0; * Returns `true` if the editor is set to read-only mode. * @returns {Boolean} **/ - this.getReadOnly = function() { + getReadOnly() { return this.getOption("readOnly"); }; @@ -1271,7 +1263,7 @@ Editor.$uid = 0; * @param {Boolean} enabled Enables or disables behaviors * **/ - this.setBehavioursEnabled = function (enabled) { + setBehavioursEnabled(enabled) { this.setOption("behavioursEnabled", enabled); }; @@ -1280,7 +1272,7 @@ Editor.$uid = 0; * * @returns {Boolean} **/ - this.getBehavioursEnabled = function () { + getBehavioursEnabled() { return this.getOption("behavioursEnabled"); }; @@ -1290,14 +1282,14 @@ Editor.$uid = 0; * @param {Boolean} enabled Enables or disables wrapping behaviors * **/ - this.setWrapBehavioursEnabled = function (enabled) { + setWrapBehavioursEnabled(enabled) { this.setOption("wrapBehavioursEnabled", enabled); }; /** * Returns `true` if the wrapping behaviors are currently enabled. **/ - this.getWrapBehavioursEnabled = function () { + getWrapBehavioursEnabled() { return this.getOption("wrapBehavioursEnabled"); }; @@ -1305,7 +1297,7 @@ Editor.$uid = 0; * Indicates whether the fold widgets should be shown or not. * @param {Boolean} show Specifies whether the fold widgets are shown **/ - this.setShowFoldWidgets = function(show) { + setShowFoldWidgets(show) { this.setOption("showFoldWidgets", show); }; @@ -1313,15 +1305,15 @@ Editor.$uid = 0; * Returns `true` if the fold widgets are shown. * @return {Boolean} **/ - this.getShowFoldWidgets = function() { + getShowFoldWidgets() { return this.getOption("showFoldWidgets"); }; - this.setFadeFoldWidgets = function(fade) { + setFadeFoldWidgets(fade) { this.setOption("fadeFoldWidgets", fade); }; - this.getFadeFoldWidgets = function() { + getFadeFoldWidgets() { return this.getOption("fadeFoldWidgets"); }; @@ -1330,7 +1322,7 @@ Editor.$uid = 0; * @param {String} dir The direction of the deletion to occur, either "left" or "right" * **/ - this.remove = function(dir) { + remove(dir) { if (this.selection.isEmpty()){ if (dir == "left") this.selection.selectLeft(); @@ -1364,7 +1356,7 @@ Editor.$uid = 0; /** * Removes the word directly to the right of the current selection. **/ - this.removeWordRight = function() { + removeWordRight() { if (this.selection.isEmpty()) this.selection.selectWordRight(); @@ -1375,7 +1367,7 @@ Editor.$uid = 0; /** * Removes the word directly to the left of the current selection. **/ - this.removeWordLeft = function() { + removeWordLeft() { if (this.selection.isEmpty()) this.selection.selectWordLeft(); @@ -1386,7 +1378,7 @@ Editor.$uid = 0; /** * Removes all the words to the left of the current selection, until the start of the line. **/ - this.removeToLineStart = function() { + removeToLineStart() { if (this.selection.isEmpty()) this.selection.selectLineStart(); if (this.selection.isEmpty()) @@ -1398,7 +1390,7 @@ Editor.$uid = 0; /** * Removes all the words to the right of the current selection, until the end of the line. **/ - this.removeToLineEnd = function() { + removeToLineEnd() { if (this.selection.isEmpty()) this.selection.selectLineEnd(); @@ -1415,7 +1407,7 @@ Editor.$uid = 0; /** * Splits the line at the current selection (by inserting an `'\n'`). **/ - this.splitLine = function() { + splitLine() { if (!this.selection.isEmpty()) { this.session.remove(this.getSelectionRange()); this.clearSelection(); @@ -1434,7 +1426,7 @@ Editor.$uid = 0; * @param {String} text Text to be inserted as "ghost" text * @param {object} position Position to insert text to */ - this.setGhostText = function(text, position) { + setGhostText(text, position) { if (!this.session.widgetManager) { this.session.widgetManager = new LineWidgets(this.session); this.session.widgetManager.attach(this); @@ -1445,7 +1437,7 @@ Editor.$uid = 0; /** * Removes "ghost" text currently displayed in the editor. */ - this.removeGhostText = function() { + removeGhostText() { if (!this.session.widgetManager) return; this.renderer.removeGhostText(); @@ -1454,7 +1446,7 @@ Editor.$uid = 0; /** * Transposes current line. **/ - this.transposeLetters = function() { + transposeLetters() { if (!this.selection.isEmpty()) { return; } @@ -1481,7 +1473,7 @@ Editor.$uid = 0; /** * Converts the current selection entirely into lowercase. **/ - this.toLowerCase = function() { + toLowerCase() { var originalRange = this.getSelectionRange(); if (this.selection.isEmpty()) { this.selection.selectWord(); @@ -1496,7 +1488,7 @@ Editor.$uid = 0; /** * Converts the current selection entirely into uppercase. **/ - this.toUpperCase = function() { + toUpperCase() { var originalRange = this.getSelectionRange(); if (this.selection.isEmpty()) { this.selection.selectWord(); @@ -1513,7 +1505,7 @@ Editor.$uid = 0; * * @related EditSession.indentRows **/ - this.indent = function() { + indent() { var session = this.session; var range = this.getSelectionRange(); @@ -1554,7 +1546,7 @@ Editor.$uid = 0; * Indents the current line. * @related EditSession.indentRows **/ - this.blockIndent = function() { + blockIndent() { var rows = this.$getSelectedRows(); this.session.indentRows(rows.first, rows.last, "\t"); }; @@ -1563,13 +1555,13 @@ Editor.$uid = 0; * Outdents the current line. * @related EditSession.outdentRows **/ - this.blockOutdent = function() { + blockOutdent() { var selection = this.session.getSelection(); this.session.outdentRows(selection.getRange()); }; // TODO: move out of core when we have good mechanism for managing extensions - this.sortLines = function() { + sortLines() { var rows = this.$getSelectedRows(); var session = this.session; @@ -1596,13 +1588,13 @@ Editor.$uid = 0; /** * Given the currently selected range, this function either comments all the lines, or uncomments all of them. **/ - this.toggleCommentLines = function() { + toggleCommentLines() { var state = this.session.getState(this.getCursorPosition().row); var rows = this.$getSelectedRows(); this.session.getMode().toggleCommentLines(state, this.session, rows.first, rows.last); }; - this.toggleBlockComment = function() { + toggleBlockComment() { var cursor = this.getCursorPosition(); var state = this.session.getState(cursor.row); var range = this.getSelectionRange(); @@ -1613,7 +1605,7 @@ Editor.$uid = 0; * Works like [[EditSession.getTokenAt]], except it returns a number. * @returns {Number} **/ - this.getNumberAt = function(row, column) { + getNumberAt(row, column) { var _numberRx = /[\-]?[0-9]+(?:\.[0-9]+)?/g; _numberRx.lastIndex = 0; @@ -1637,7 +1629,7 @@ Editor.$uid = 0; * @param {Number} amount The value to change the numeral by (can be negative to decrease value) * **/ - this.modifyNumber = function(amount) { + modifyNumber(amount) { var row = this.selection.getCursor().row; var column = this.selection.getCursor().column; @@ -1681,7 +1673,7 @@ Editor.$uid = 0; } }; - this.$toggleWordPairs = [ + $toggleWordPairs = [ ["first", "last"], ["true", "false"], ["yes", "no"], @@ -1707,7 +1699,7 @@ Editor.$uid = 0; ["==", "!="] ]; - this.toggleWord = function () { + toggleWord() { var row = this.selection.getCursor().row; var column = this.selection.getCursor().column; this.selection.selectWord(); @@ -1762,7 +1754,7 @@ Editor.$uid = 0; * Finds link at defined {row} and {column} * @returns {String} **/ - this.findLinkAt = function (row, column) { + findLinkAt(row, column) { var line = this.session.getLine(row); var wordParts = line.split(/((?:https?|ftp):\/\/[\S]+)/); var columnPosition = column; @@ -1785,7 +1777,7 @@ Editor.$uid = 0; * Open valid url under cursor in another tab * @returns {Boolean} **/ - this.openLink = function () { + openLink() { var cursor = this.selection.getCursor(); var url = this.findLinkAt(cursor.row, cursor.column); if (url) @@ -1797,13 +1789,13 @@ Editor.$uid = 0; * Removes all the lines in the current selection * @related EditSession.remove **/ - this.removeLines = function() { + removeLines() { var rows = this.$getSelectedRows(); this.session.removeFullLines(rows.first, rows.last); this.clearSelection(); }; - this.duplicateSelection = function() { + duplicateSelection() { var sel = this.selection; var doc = this.session; var range = sel.getRange(); @@ -1827,7 +1819,7 @@ Editor.$uid = 0; * @returns {Number} On success, it returns -1. * @related EditSession.moveLinesUp **/ - this.moveLinesDown = function() { + moveLinesDown() { this.$moveLines(1, false); }; @@ -1836,7 +1828,7 @@ Editor.$uid = 0; * @returns {Number} On success, it returns -1. * @related EditSession.moveLinesDown **/ - this.moveLinesUp = function() { + moveLinesUp() { this.$moveLines(-1, false); }; @@ -1845,13 +1837,13 @@ Editor.$uid = 0; * ```json * { row: newRowLocation, column: newColumnLocation } * ``` - * @param {Range} fromRange The range of text you want moved within the document + * @param {Range} range The range of text you want moved within the document * @param {Object} toPosition The location (row and column) where you want to move the text to * * @returns {Range} The new range where the text was moved to. * @related EditSession.moveText **/ - this.moveText = function(range, toPosition, copy) { + moveText(range, toPosition, copy) { return this.session.moveText(range, toPosition, copy); }; @@ -1860,7 +1852,7 @@ Editor.$uid = 0; * @returns {Number} On success, returns 0. * **/ - this.copyLinesUp = function() { + copyLinesUp() { this.$moveLines(-1, true); }; @@ -1870,7 +1862,7 @@ Editor.$uid = 0; * @related EditSession.duplicateLines * **/ - this.copyLinesDown = function() { + copyLinesDown() { this.$moveLines(1, true); }; @@ -1879,7 +1871,7 @@ Editor.$uid = 0; * @ignore * **/ - this.$moveLines = function(dir, copy) { + $moveLines(dir, copy) { var rows, moved; var selection = this.selection; if (!selection.inMultiSelectMode || this.inVirtualSelectionMode) { @@ -1938,7 +1930,7 @@ Editor.$uid = 0; * * @returns {Object} **/ - this.$getSelectedRows = function(range) { + $getSelectedRows(range) { range = (range || this.getSelectionRange()).collapseRows(); return { @@ -1947,15 +1939,15 @@ Editor.$uid = 0; }; }; - this.onCompositionStart = function(compositionState) { + onCompositionStart(compositionState) { this.renderer.showComposition(compositionState); }; - this.onCompositionUpdate = function(text) { + onCompositionUpdate(text) { this.renderer.setCompositionText(text); }; - this.onCompositionEnd = function() { + onCompositionEnd() { this.renderer.hideComposition(); }; @@ -1965,7 +1957,7 @@ Editor.$uid = 0; * @returns {Number} * @related VirtualRenderer.getFirstVisibleRow **/ - this.getFirstVisibleRow = function() { + getFirstVisibleRow() { return this.renderer.getFirstVisibleRow(); }; @@ -1975,7 +1967,7 @@ Editor.$uid = 0; * @returns {Number} * @related VirtualRenderer.getLastVisibleRow **/ - this.getLastVisibleRow = function() { + getLastVisibleRow() { return this.renderer.getLastVisibleRow(); }; @@ -1985,7 +1977,7 @@ Editor.$uid = 0; * * @returns {Boolean} **/ - this.isRowVisible = function(row) { + isRowVisible(row) { return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow()); }; @@ -1996,7 +1988,7 @@ Editor.$uid = 0; * * @returns {Boolean} **/ - this.isRowFullyVisible = function(row) { + isRowFullyVisible(row) { return (row >= this.renderer.getFirstFullyVisibleRow() && row <= this.renderer.getLastFullyVisibleRow()); }; @@ -2004,11 +1996,11 @@ Editor.$uid = 0; * Returns the number of currently visible rows. * @returns {Number} **/ - this.$getVisibleRowCount = function() { + $getVisibleRowCount() { return this.renderer.getScrollBottomRow() - this.renderer.getScrollTopRow() + 1; }; - this.$moveByPage = function(dir, select) { + $moveByPage(dir, select) { var renderer = this.renderer; var config = this.renderer.layerConfig; var rows = dir * Math.floor(config.height / config.lineHeight); @@ -2034,42 +2026,42 @@ Editor.$uid = 0; /** * Selects the text from the current position of the document until where a "page down" finishes. **/ - this.selectPageDown = function() { + selectPageDown() { this.$moveByPage(1, true); }; /** * Selects the text from the current position of the document until where a "page up" finishes. **/ - this.selectPageUp = function() { + selectPageUp() { this.$moveByPage(-1, true); }; /** * Shifts the document to wherever "page down" is, as well as moving the cursor position. **/ - this.gotoPageDown = function() { + gotoPageDown() { this.$moveByPage(1, false); }; /** * Shifts the document to wherever "page up" is, as well as moving the cursor position. **/ - this.gotoPageUp = function() { + gotoPageUp() { this.$moveByPage(-1, false); }; /** * Scrolls the document to wherever "page down" is, without changing the cursor position. **/ - this.scrollPageDown = function() { + scrollPageDown() { this.$moveByPage(1); }; /** * Scrolls the document to wherever "page up" is, without changing the cursor position. **/ - this.scrollPageUp = function() { + scrollPageUp() { this.$moveByPage(-1); }; @@ -2077,7 +2069,7 @@ Editor.$uid = 0; * Moves the editor to the specified row. * @related VirtualRenderer.scrollToRow **/ - this.scrollToRow = function(row) { + scrollToRow(row) { this.renderer.scrollToRow(row); }; @@ -2091,14 +2083,14 @@ Editor.$uid = 0; * * @related VirtualRenderer.scrollToLine **/ - this.scrollToLine = function(line, center, animate, callback) { + scrollToLine(line, center, animate, callback) { this.renderer.scrollToLine(line, center, animate, callback); }; /** * Attempts to center the current selection on the screen. **/ - this.centerSelection = function() { + centerSelection() { var range = this.getSelectionRange(); var pos = { row: Math.floor(range.start.row + (range.end.row - range.start.row) / 2), @@ -2117,16 +2109,16 @@ Editor.$uid = 0; * * @related Selection.getCursor **/ - this.getCursorPosition = function() { + getCursorPosition() { return this.selection.getCursor(); }; /** * Returns the screen position of the cursor. - * @returns {Number} + * @returns {Position} * @related EditSession.documentToScreenPosition **/ - this.getCursorPositionScreen = function() { + getCursorPositionScreen() { return this.session.documentToScreenPosition(this.getCursorPosition()); }; @@ -2135,16 +2127,15 @@ Editor.$uid = 0; * @returns {Range} * @related Selection.getRange **/ - this.getSelectionRange = function() { + getSelectionRange() { return this.selection.getRange(); }; - - + /** * Selects all the text in editor. * @related Selection.selectAll **/ - this.selectAll = function() { + selectAll() { this.selection.selectAll(); }; @@ -2152,7 +2143,7 @@ Editor.$uid = 0; * {:Selection.clearSelection} * @related Selection.clearSelection **/ - this.clearSelection = function() { + clearSelection() { this.selection.clearSelection(); }; @@ -2160,22 +2151,18 @@ Editor.$uid = 0; * Moves the cursor to the specified row and column. Note that this does not de-select the current selection. * @param {Number} row The new row number * @param {Number} column The new column number - * - * * @related Selection.moveCursorTo **/ - this.moveCursorTo = function(row, column) { + moveCursorTo(row, column) { this.selection.moveCursorTo(row, column); }; /** * Moves the cursor to the position indicated by `pos.row` and `pos.column`. - * @param {Object} pos An object with two properties, row and column - * - * + * @param {Position} pos An object with two properties, row and column * @related Selection.moveCursorToPosition **/ - this.moveCursorToPosition = function(pos) { + moveCursorToPosition(pos) { this.selection.moveCursorToPosition(pos); }; @@ -2183,7 +2170,7 @@ Editor.$uid = 0; * Moves the cursor's row and column to the next matching bracket or HTML tag. * **/ - this.jumpToMatching = function (select, expand) { + jumpToMatching(select, expand) { var cursor = this.getCursorPosition(); var iterator = new TokenIterator(this.session, cursor.row, cursor.column); var prevToken = iterator.getCurrentToken(); @@ -2335,7 +2322,7 @@ Editor.$uid = 0; * @param {Boolean} animate If `true` animates scolling * **/ - this.gotoLine = function(lineNumber, column, animate) { + gotoLine(lineNumber, column, animate) { this.selection.clearSelection(); this.session.unfold({row: lineNumber - 1, column: column || 0}); @@ -2355,7 +2342,7 @@ Editor.$uid = 0; * * @related Editor.moveCursorTo **/ - this.navigateTo = function(row, column) { + navigateTo(row, column) { this.selection.moveTo(row, column); }; @@ -2365,7 +2352,7 @@ Editor.$uid = 0; * * **/ - this.navigateUp = function(times) { + navigateUp(times) { if (this.selection.isMultiLine() && !this.selection.isBackwards()) { var selectionStart = this.selection.anchor.getPosition(); return this.moveCursorToPosition(selectionStart); @@ -2380,7 +2367,7 @@ Editor.$uid = 0; * * **/ - this.navigateDown = function(times) { + navigateDown(times) { if (this.selection.isMultiLine() && this.selection.isBackwards()) { var selectionEnd = this.selection.anchor.getPosition(); return this.moveCursorToPosition(selectionEnd); @@ -2395,7 +2382,7 @@ Editor.$uid = 0; * * **/ - this.navigateLeft = function(times) { + navigateLeft(times) { if (!this.selection.isEmpty()) { var selectionStart = this.getSelectionRange().start; this.moveCursorToPosition(selectionStart); @@ -2415,7 +2402,7 @@ Editor.$uid = 0; * * **/ - this.navigateRight = function(times) { + navigateRight(times) { if (!this.selection.isEmpty()) { var selectionEnd = this.getSelectionRange().end; this.moveCursorToPosition(selectionEnd); @@ -2433,7 +2420,7 @@ Editor.$uid = 0; * * Moves the cursor to the start of the current line. Note that this does de-select the current selection. **/ - this.navigateLineStart = function() { + navigateLineStart() { this.selection.moveCursorLineStart(); this.clearSelection(); }; @@ -2442,7 +2429,7 @@ Editor.$uid = 0; * * Moves the cursor to the end of the current line. Note that this does de-select the current selection. **/ - this.navigateLineEnd = function() { + navigateLineEnd() { this.selection.moveCursorLineEnd(); this.clearSelection(); }; @@ -2451,7 +2438,7 @@ Editor.$uid = 0; * * Moves the cursor to the end of the current file. Note that this does de-select the current selection. **/ - this.navigateFileEnd = function() { + navigateFileEnd() { this.selection.moveCursorFileEnd(); this.clearSelection(); }; @@ -2460,7 +2447,7 @@ Editor.$uid = 0; * * Moves the cursor to the start of the current file. Note that this does de-select the current selection. **/ - this.navigateFileStart = function() { + navigateFileStart() { this.selection.moveCursorFileStart(); this.clearSelection(); }; @@ -2469,7 +2456,7 @@ Editor.$uid = 0; * * Moves the cursor to the word immediately to the right of the current position. Note that this does de-select the current selection. **/ - this.navigateWordRight = function() { + navigateWordRight() { this.selection.moveCursorWordRight(); this.clearSelection(); }; @@ -2478,7 +2465,7 @@ Editor.$uid = 0; * * Moves the cursor to the word immediately to the left of the current position. Note that this does de-select the current selection. **/ - this.navigateWordLeft = function() { + navigateWordLeft() { this.selection.moveCursorWordLeft(); this.clearSelection(); }; @@ -2490,7 +2477,7 @@ Editor.$uid = 0; * * **/ - this.replace = function(replacement, options) { + replace(replacement, options) { if (options) this.$search.set(options); @@ -2516,7 +2503,7 @@ Editor.$uid = 0; * * **/ - this.replaceAll = function(replacement, options) { + replaceAll(replacement, options) { if (options) { this.$search.set(options); } @@ -2540,7 +2527,7 @@ Editor.$uid = 0; return replaced; }; - this.$tryReplace = function(range, replacement) { + $tryReplace(range, replacement) { var input = this.session.getTextRange(range); replacement = this.$search.replace(input, replacement); if (replacement !== null) { @@ -2556,20 +2543,18 @@ Editor.$uid = 0; * @related Search.getOptions * @returns {Object} **/ - this.getLastSearchOptions = function() { + getLastSearchOptions() { return this.$search.getOptions(); }; /** * Attempts to find `needle` within the document. For more information on `options`, see [[Search `Search`]]. - * @param {String} needle The text to search for (optional) + * @param {String|RegExp|Object} needle The text to search for (optional) * @param {Object} options An object defining various search properties * @param {Boolean} animate If `true` animate scrolling - * - * * @related Search.find **/ - this.find = function(needle, options, animate) { + find(needle, options, animate) { if (!options) options = {}; @@ -2616,7 +2601,7 @@ Editor.$uid = 0; * * @related Editor.find **/ - this.findNext = function(options, animate) { + findNext(options, animate) { this.find({skipCurrent: true, backwards: false}, options, animate); }; @@ -2628,11 +2613,11 @@ Editor.$uid = 0; * * @related Editor.find **/ - this.findPrevious = function(options, animate) { + findPrevious(options, animate) { this.find(options, {skipCurrent: true, backwards: true}, animate); }; - this.revealRange = function(range, animate) { + revealRange(range, animate) { this.session.unfold(range); this.selection.setSelectionRange(range); @@ -2646,7 +2631,7 @@ Editor.$uid = 0; * {:UndoManager.undo} * @related UndoManager.undo **/ - this.undo = function() { + undo() { this.session.getUndoManager().undo(this.session); this.renderer.scrollCursorIntoView(null, 0.5); }; @@ -2655,7 +2640,7 @@ Editor.$uid = 0; * {:UndoManager.redo} * @related UndoManager.redo **/ - this.redo = function() { + redo() { this.session.getUndoManager().redo(this.session); this.renderer.scrollCursorIntoView(null, 0.5); }; @@ -2664,7 +2649,7 @@ Editor.$uid = 0; * * Cleans up the entire editor. **/ - this.destroy = function() { + destroy() { if (this.$toDestroy) { this.$toDestroy.forEach(function(el) { el.destroy(); @@ -2686,7 +2671,7 @@ Editor.$uid = 0; * Enables automatic scrolling of the cursor into view when editor itself is inside scrollable element * @param {Boolean} enable default true **/ - this.setAutoScrollEditorIntoView = function(enable) { + setAutoScrollEditorIntoView(enable) { if (!enable) return; var rect; @@ -2741,7 +2726,7 @@ Editor.$uid = 0; }; - this.$resetCursorStyle = function() { + $resetCursorStyle() { var style = this.$cursorStyle || "ace"; var cursorLayer = this.renderer.$cursorLayer; if (!cursorLayer) @@ -2754,15 +2739,16 @@ Editor.$uid = 0; /** * opens a prompt displaying message **/ - this.prompt = function(message, options, callback) { + prompt(message, options, callback) { var editor = this; config.loadModule("ace/ext/prompt", function (module) { module.prompt(editor, message, options, callback); }); }; -}).call(Editor.prototype); +} +oop.implement(Editor.prototype, EventEmitter); config.defineOptions(Editor.prototype, "editor", { diff --git a/src/ext/elastic_tabstops_lite.js b/src/ext/elastic_tabstops_lite.js index 1abe595a2da..16ee488fda1 100644 --- a/src/ext/elastic_tabstops_lite.js +++ b/src/ext/elastic_tabstops_lite.js @@ -1,30 +1,30 @@ "use strict"; -var ElasticTabstopsLite = function(editor) { - this.$editor = editor; - var self = this; - var changedRows = []; - var recordChanges = false; - this.onAfterExec = function() { - recordChanges = false; - self.processRows(changedRows); - changedRows = []; - }; - this.onExec = function() { - recordChanges = true; - }; - this.onChange = function(delta) { - if (recordChanges) { - if (changedRows.indexOf(delta.start.row) == -1) - changedRows.push(delta.start.row); - if (delta.end.row != delta.start.row) - changedRows.push(delta.end.row); - } +class ElasticTabstopsLite { + constructor(editor) { + this.$editor = editor; + var self = this; + var changedRows = []; + var recordChanges = false; + this.onAfterExec = function() { + recordChanges = false; + self.processRows(changedRows); + changedRows = []; + }; + this.onExec = function() { + recordChanges = true; + }; + this.onChange = function(delta) { + if (recordChanges) { + if (changedRows.indexOf(delta.start.row) == -1) + changedRows.push(delta.start.row); + if (delta.end.row != delta.start.row) + changedRows.push(delta.end.row); + } + }; }; -}; - -(function() { - this.processRows = function(rows) { + + processRows(rows) { this.$inChange = true; var checkedRows = []; @@ -48,7 +48,7 @@ var ElasticTabstopsLite = function(editor) { this.$inChange = false; }; - this.$findCellWidthsForBlock = function(row) { + $findCellWidthsForBlock(row) { var cellWidths = [], widths; // starting row and backward @@ -80,7 +80,7 @@ var ElasticTabstopsLite = function(editor) { return { cellWidths: cellWidths, firstRow: firstRow }; }; - this.$cellWidthsForRow = function(row) { + $cellWidthsForRow(row) { var selectionColumns = this.$selectionColumnsForRow(row); // todo: support multicursor @@ -100,7 +100,7 @@ var ElasticTabstopsLite = function(editor) { return widths; }; - this.$selectionColumnsForRow = function(row) { + $selectionColumnsForRow(row) { var selections = [], cursor = this.$editor.getCursorPosition(); if (this.$editor.session.getSelection().isEmpty()) { // todo: support multicursor @@ -111,7 +111,7 @@ var ElasticTabstopsLite = function(editor) { return selections; }; - this.$setBlockCellWidthsToMax = function(cellWidths) { + $setBlockCellWidthsToMax(cellWidths) { var startingNewBlock = true, blockStartRow, blockEndRow, maxWidth; var columnInfo = this.$izip_longest(cellWidths); @@ -149,7 +149,7 @@ var ElasticTabstopsLite = function(editor) { return cellWidths; }; - this.$rightmostSelectionInCell = function(selectionColumns, cellRightEdge) { + $rightmostSelectionInCell(selectionColumns, cellRightEdge) { var rightmost = 0; if (selectionColumns.length) { @@ -166,7 +166,7 @@ var ElasticTabstopsLite = function(editor) { return rightmost; }; - this.$tabsForRow = function(row) { + $tabsForRow(row) { var rowTabs = [], line = this.$editor.session.getLine(row), re = /\t/g, match; @@ -177,7 +177,7 @@ var ElasticTabstopsLite = function(editor) { return rowTabs; }; - this.$adjustRow = function(row, widths) { + $adjustRow(row, widths) { var rowTabs = this.$tabsForRow(row); if (rowTabs.length == 0) @@ -218,7 +218,7 @@ var ElasticTabstopsLite = function(editor) { }; // the is a (naive) Python port--but works for these purposes - this.$izip_longest = function(iterables) { + $izip_longest(iterables) { if (!iterables[0]) return []; var longest = iterables[0].length; @@ -249,7 +249,7 @@ var ElasticTabstopsLite = function(editor) { }; // an even more (naive) Python port - this.$izip = function(widths, tabs) { + $izip(widths, tabs) { // grab the shorter size var size = widths.length >= tabs.length ? tabs.length : widths.length; @@ -261,7 +261,7 @@ var ElasticTabstopsLite = function(editor) { return expandedSet; }; -}).call(ElasticTabstopsLite.prototype); +} exports.ElasticTabstopsLite = ElasticTabstopsLite; diff --git a/src/ext/emmet.js b/src/ext/emmet.js index f2a252df0f6..ba2ad441fc8 100644 --- a/src/ext/emmet.js +++ b/src/ext/emmet.js @@ -9,10 +9,9 @@ var emmet, emmetPath; /** * Implementation of {@link IEmmetEditor} interface for Ace */ -function AceEmmetEditor() {} -AceEmmetEditor.prototype = { - setupContext: function(editor) { +class AceEmmetEditor { + setupContext(editor) { this.ace = editor; this.indentation = editor.session.getTabString(); if (!emmet) @@ -21,7 +20,7 @@ AceEmmetEditor.prototype = { resources.setVariable("indentation", this.indentation); this.$syntax = null; this.$syntax = this.getSyntax(); - }, + } /** * Returns character indexes of selected text: object with start * and end properties. If there's no selection, should return @@ -32,7 +31,7 @@ AceEmmetEditor.prototype = { * var selection = editor.getSelectionRange(); * alert(selection.start + ', ' + selection.end); */ - getSelectionRange: function() { + getSelectionRange() { // TODO should start be caret position instead? var range = this.ace.getSelectionRange(); var doc = this.ace.session.doc; @@ -40,7 +39,7 @@ AceEmmetEditor.prototype = { start: doc.positionToIndex(range.start), end: doc.positionToIndex(range.end) }; - }, + } /** * Creates selection from start to end character @@ -54,13 +53,13 @@ AceEmmetEditor.prototype = { * //move caret to 15th character * editor.createSelection(15); */ - createSelection: function(start, end) { + createSelection(start, end) { var doc = this.ace.session.doc; this.ace.selection.setRange({ start: doc.indexToPosition(start), end: doc.indexToPosition(end) }); - }, + } /** * Returns current line's start and end indexes as object with start @@ -70,7 +69,7 @@ AceEmmetEditor.prototype = { * var range = editor.getCurrentLineRange(); * alert(range.start + ', ' + range.end); */ - getCurrentLineRange: function() { + getCurrentLineRange() { var ace = this.ace; var row = ace.getCursorPosition().row; var lineLength = ace.session.getLine(row).length; @@ -79,34 +78,34 @@ AceEmmetEditor.prototype = { start: index, end: index + lineLength }; - }, + } /** * Returns current caret position * @return {Number|null} */ - getCaretPos: function(){ + getCaretPos(){ var pos = this.ace.getCursorPosition(); return this.ace.session.doc.positionToIndex(pos); - }, + } /** * Set new caret position * @param {Number} index Caret position */ - setCaretPos: function(index){ + setCaretPos(index){ var pos = this.ace.session.doc.indexToPosition(index); this.ace.selection.moveToPosition(pos); - }, + } /** * Returns content of current line * @return {String} */ - getCurrentLine: function() { + getCurrentLine() { var row = this.ace.getCursorPosition().row; return this.ace.session.getLine(row); - }, + } /** * Replace editor's content or it's part (from start to @@ -128,7 +127,7 @@ AceEmmetEditor.prototype = { * @param {Number} [end] End index of editor's content * @param {Boolean} [noIndent] Do not auto indent value */ - replaceContent: function(value, start, end, noIndent) { + replaceContent(value, start, end, noIndent) { if (end == null) end = start == null ? this.getContent().length : start; if (start == null) @@ -144,21 +143,21 @@ AceEmmetEditor.prototype = { value = this.$updateTabstops(value); snippetManager.insertSnippet(editor, value); - }, + } /** * Returns editor's content * @return {String} */ - getContent: function(){ + getContent(){ return this.ace.getValue(); - }, + } /** * Returns current editor's syntax mode * @return {String} */ - getSyntax: function() { + getSyntax() { if (this.$syntax) return this.$syntax; var syntax = this.ace.session.$modeId.split("/").pop(); @@ -176,13 +175,13 @@ AceEmmetEditor.prototype = { } } return syntax; - }, + } /** * Returns current output profile name (@see emmet#setupProfile) * @return {String} */ - getProfileName: function() { + getProfileName() { var resources = emmet.resources || emmet.require("resources"); switch (this.getSyntax()) { case "css": return "css"; @@ -199,7 +198,7 @@ AceEmmetEditor.prototype = { var mode = this.ace.session.$mode; return mode.emmetConfig && mode.emmetConfig.profile || "xhtml"; } - }, + } /** * Ask user to enter something @@ -207,34 +206,34 @@ AceEmmetEditor.prototype = { * @return {String} Entered data * @since 0.65 */ - prompt: function(title) { + prompt(title) { return prompt(title); // eslint-disable-line no-alert - }, + } /** * Returns current selection * @return {String} * @since 0.65 */ - getSelection: function() { + getSelection() { return this.ace.session.getTextRange(); - }, + } /** * Returns current editor's file path * @return {String} * @since 0.65 */ - getFilePath: function() { + getFilePath() { return ""; - }, + } // update tabstops: make sure all caret placeholders are unique // by default, abbreviation parser generates all unlinked (un-mirrored) // tabstops as ${0}, so we have upgrade all caret tabstops with unique // positions but make sure that all other tabstops are not linked accidentally // based on https://github.com/sergeche/emmet-sublime/blob/master/editor.js#L119-L171 - $updateTabstops: function(value) { + $updateTabstops(value) { var base = 1000; var zeroBase = 0; var lastZero = null; @@ -282,7 +281,7 @@ AceEmmetEditor.prototype = { return value; } -}; +} var keymap = { diff --git a/src/ext/inline_autocomplete.js b/src/ext/inline_autocomplete.js index 5c855da7cb3..1a1c3885f66 100644 --- a/src/ext/inline_autocomplete.js +++ b/src/ext/inline_autocomplete.js @@ -31,32 +31,30 @@ var minPosition = function (posA, posB) { * This class controls the inline-only autocompletion components and their lifecycle. * This is more lightweight than the popup-based autocompletion, as it can only work with exact prefix matches. * There is an inline ghost text renderer and an optional command bar tooltip inside. - * @class */ - -var InlineAutocomplete = function(editor) { - this.editor = editor; - this.tooltipEnabled = true; - this.keyboardHandler = new HashHandler(this.commands); - this.$index = -1; - - this.blurListener = this.blurListener.bind(this); - this.changeListener = this.changeListener.bind(this); - this.mousewheelListener = this.mousewheelListener.bind(this); - - this.changeTimer = lang.delayedCall(function() { - this.updateCompletions(); - }.bind(this)); -}; - -(function() { - this.getInlineRenderer = function() { +class InlineAutocomplete { + constructor(editor) { + this.editor = editor; + this.tooltipEnabled = true; + this.keyboardHandler = new HashHandler(this.commands); + this.$index = -1; + + this.blurListener = this.blurListener.bind(this); + this.changeListener = this.changeListener.bind(this); + this.mousewheelListener = this.mousewheelListener.bind(this); + + this.changeTimer = lang.delayedCall(function() { + this.updateCompletions(); + }.bind(this)); + }; + + getInlineRenderer() { if (!this.inlineRenderer) this.inlineRenderer = new AceInline(); return this.inlineRenderer; }; - this.getInlineTooltip = function() { + getInlineTooltip() { if (!this.inlineTooltip) { this.inlineTooltip = new InlineTooltip(this.editor, document.body || document.documentElement); this.inlineTooltip.setCommands(this.commands); @@ -67,10 +65,9 @@ var InlineAutocomplete = function(editor) { /** * This function is the entry point to the class. This triggers the gathering of the autocompletion and displaying the results; - * @param {Editor} editor * @param {CompletionOptions} options */ - this.show = function(options) { + show(options) { this.activated = true; if (this.editor.completer !== this) { @@ -86,7 +83,7 @@ var InlineAutocomplete = function(editor) { this.updateCompletions(options); }; - this.$open = function() { + $open() { if (this.editor.textInput.setAriaOptions) { this.editor.textInput.setAriaOptions({}); } @@ -107,13 +104,13 @@ var InlineAutocomplete = function(editor) { this.changeTimer.cancel(); }; - this.insertMatch = function() { + insertMatch() { var result = this.getCompletionProvider().insertByIndex(this.editor, this.$index); this.detach(); return result; }; - this.commands = { + commands = { "Previous": { bindKey: "Alt-[", name: "Previous", @@ -158,7 +155,7 @@ var InlineAutocomplete = function(editor) { } }; - this.changeListener = function(e) { + changeListener(e) { var cursor = this.editor.selection.lead; if (cursor.row != this.base.row || cursor.column < this.base.column) { this.detach(); @@ -169,17 +166,17 @@ var InlineAutocomplete = function(editor) { this.detach(); }; - this.blurListener = function(e) { + blurListener(e) { this.detach(); }; - this.mousewheelListener = function(e) { + mousewheelListener(e) { if (this.inlineTooltip && this.inlineTooltip.isShown()) { this.inlineTooltip.updatePosition(); } }; - this.goTo = function(where) { + goTo(where) { if (!this.completions || !this.completions.filtered) { return; } @@ -199,14 +196,14 @@ var InlineAutocomplete = function(editor) { } }; - this.getLength = function() { + getLength() { if (!this.completions || !this.completions.filtered) { return 0; } return this.completions.filtered.length; }; - this.getData = function(index) { + getData(index) { if (index == undefined || index === null) { return this.completions.filtered[this.$index]; } else { @@ -214,15 +211,15 @@ var InlineAutocomplete = function(editor) { } }; - this.getIndex = function() { + getIndex() { return this.$index; }; - this.isOpen = function() { + isOpen() { return this.$index >= 0; }; - this.setIndex = function(value) { + setIndex(value) { if (!this.completions || !this.completions.filtered) { return; } @@ -233,13 +230,13 @@ var InlineAutocomplete = function(editor) { } }; - this.getCompletionProvider = function() { + getCompletionProvider() { if (!this.completionProvider) this.completionProvider = new CompletionProvider(); return this.completionProvider; }; - this.$showCompletion = function() { + $showCompletion() { if (!this.getInlineRenderer().show(this.editor, this.completions.filtered[this.$index], this.completions.filterText)) { // Not able to show the completion, hide the previous one this.getInlineRenderer().hide(); @@ -249,7 +246,7 @@ var InlineAutocomplete = function(editor) { } }; - this.$updatePrefix = function() { + $updatePrefix() { var pos = this.editor.getCursorPosition(); var prefix = this.editor.session.getTextRange({start: this.base, end: pos}); this.completions.setFilter(prefix); @@ -263,7 +260,7 @@ var InlineAutocomplete = function(editor) { return prefix; }; - this.updateCompletions = function(options) { + updateCompletions(options) { var prefix = ""; if (options && options.matches) { @@ -305,7 +302,7 @@ var InlineAutocomplete = function(editor) { }.bind(this)); }; - this.detach = function() { + detach() { if (this.editor) { this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler); this.editor.off("changeSelection", this.changeListener); @@ -333,7 +330,7 @@ var InlineAutocomplete = function(editor) { this.completionProvider = this.completions = this.base = null; }; - this.destroy = function() { + destroy() { this.detach(); if (this.inlineRenderer) this.inlineRenderer.destroy(); @@ -346,7 +343,7 @@ var InlineAutocomplete = function(editor) { this.inlineTooltip = this.editor = this.inlineRenderer = null; }; -}).call(InlineAutocomplete.prototype); +} InlineAutocomplete.for = function(editor) { if (editor.completer instanceof InlineAutocomplete) { @@ -389,49 +386,42 @@ require("../config").defineOptions(Editor.prototype, "editor", { } }); -/** - * Displays a command tooltip above the selection, with clickable elements. - * @class - */ - -/** - * Creates the inline command tooltip helper which displays the available keyboard commands for the user. - * @param {HTMLElement} parentElement - * @constructor - */ var ENTRY_CLASS_NAME = 'inline_autocomplete_tooltip_entry'; var BUTTON_CLASS_NAME = 'inline_autocomplete_tooltip_button'; var TOOLTIP_CLASS_NAME = 'ace_tooltip ace_inline_autocomplete_tooltip'; var TOOLTIP_ID = 'inline_autocomplete_tooltip'; -function InlineTooltip(editor, parentElement) { - this.editor = editor; - this.htmlElement = document.createElement('div'); - var el = this.htmlElement; - el.style.display = 'none'; - if (parentElement) { - parentElement.appendChild(el); +/** + * Displays a command tooltip above the selection, with clickable elements. + */ +class InlineTooltip { + /** + * Creates the inline command tooltip helper which displays the available keyboard commands for the user. + * @param {Editor} editor + * @param {HTMLElement} parentElement + */ + constructor(editor, parentElement) { + this.editor = editor; + this.htmlElement = document.createElement('div'); + var el = this.htmlElement; + el.style.display = 'none'; + if (parentElement) { + parentElement.appendChild(el); + } + el.id = TOOLTIP_ID; + el.style['pointer-events'] = 'auto'; + el.className = TOOLTIP_CLASS_NAME; + this.commands = {}; + this.buttons = {}; + this.eventListeners = {}; } - el.id = TOOLTIP_ID; - el.style['pointer-events'] = 'auto'; - el.className = TOOLTIP_CLASS_NAME; - this.commands = {}; - this.buttons = {}; - this.eventListeners = {}; -} - -(function() { - - var captureMousedown = function(e) { - e.preventDefault(); - }; /** * This function sets the commands. Note that it is advised to call this before calling show, otherwise there are no buttons to render * @param {Record} commands */ - this.setCommands = function(commands) { + setCommands(commands) { if (!commands || !this.htmlElement) { return; } @@ -465,9 +455,8 @@ function InlineTooltip(editor, parentElement) { /** * Displays the clickable command bar tooltip - * @param {Editor} editor */ - this.show = function() { + show() { this.detach(); this.htmlElement.style.display = ''; @@ -477,14 +466,14 @@ function InlineTooltip(editor, parentElement) { this.updateButtons(true); }; - this.isShown = function() { + isShown() { return !!this.htmlElement && window.getComputedStyle(this.htmlElement).display !== "none"; }; /** * Updates the position of the command bar tooltip. It aligns itself above the topmost selection in the editor. */ - this.updatePosition = function() { + updatePosition() { if (!this.editor) { return; } @@ -524,7 +513,7 @@ function InlineTooltip(editor, parentElement) { /** * Updates the buttons in the command bar tooltip. Should be called every time when any of the buttons can become disabled or enabled. */ - this.updateButtons = function(force) { + updateButtons(force) { Object.keys(this.buttons).forEach(function(key) { var commandEnabled = this.commands[key].enabled; if (typeof commandEnabled === 'function') { @@ -552,7 +541,7 @@ function InlineTooltip(editor, parentElement) { }.bind(this)); }; - this.detach = function() { + detach() { var listenerKeys = Object.keys(this.eventListeners); if (this.eventListeners && listenerKeys.length) { listenerKeys.forEach(function(key) { @@ -566,7 +555,7 @@ function InlineTooltip(editor, parentElement) { } }; - this.destroy = function() { + destroy() { this.detach(); if (this.htmlElement) { this.htmlElement.parentNode.removeChild(this.htmlElement); @@ -576,7 +565,11 @@ function InlineTooltip(editor, parentElement) { this.htmlElement = null; this.controls = null; }; -}).call(InlineTooltip.prototype); +} + +var captureMousedown = function(e) { + e.preventDefault(); +}; dom.importCssString(` .ace_inline_autocomplete_tooltip { diff --git a/src/ext/modelist.js b/src/ext/modelist.js index b0092c112a7..db942d1084a 100644 --- a/src/ext/modelist.js +++ b/src/ext/modelist.js @@ -19,26 +19,29 @@ function getModeForPath(path) { return mode; } -var Mode = function(name, caption, extensions) { - this.name = name; - this.caption = caption; - this.mode = "ace/mode/" + name; - this.extensions = extensions; - var re; - if (/\^/.test(extensions)) { - re = extensions.replace(/\|(\^)?/g, function(a, b){ - return "$|" + (b ? "^" : "^.*\\."); - }) + "$"; - } else { - re = "^.*\\.(" + extensions + ")$"; - } +class Mode { + constructor(name, caption, extensions) { + this.name = name; + this.caption = caption; + this.mode = "ace/mode/" + name; + this.extensions = extensions; + var re; + if (/\^/.test(extensions)) { + re = extensions.replace(/\|(\^)?/g, function (a, b) { + return "$|" + (b ? "^" : "^.*\\."); + }) + "$"; + } + else { + re = "^.*\\.(" + extensions + ")$"; + } - this.extRe = new RegExp(re, "gi"); -}; + this.extRe = new RegExp(re, "gi"); + }; -Mode.prototype.supportsFile = function(filename) { - return filename.match(this.extRe); -}; + supportsFile(filename) { + return filename.match(this.extRe); + }; +} // todo firstlinematch var supportedModes = { diff --git a/src/ext/options.js b/src/ext/options.js index 86144039823..99d13dc2153 100644 --- a/src/ext/options.js +++ b/src/ext/options.js @@ -198,26 +198,22 @@ var optionGroups = { } }; - -var OptionPanel = function(editor, element) { - this.editor = editor; - this.container = element || document.createElement("div"); - this.groups = []; - this.options = {}; -}; - -(function() { - - oop.implement(this, EventEmitter); +class OptionPanel { + constructor(editor, element) { + this.editor = editor; + this.container = element || document.createElement("div"); + this.groups = []; + this.options = {}; + }; - this.add = function(config) { + add(config) { if (config.Main) oop.mixin(optionGroups.Main, config.Main); if (config.More) oop.mixin(optionGroups.More, config.More); }; - this.render = function() { + render() { this.container.innerHTML = ""; buildDom(["table", {role: "presentation", id: "controls"}, this.renderOptionGroup(optionGroups.Main), @@ -230,7 +226,7 @@ var OptionPanel = function(editor, element) { ], this.container); }; - this.renderOptionGroup = function(group) { + renderOptionGroup(group) { return Object.keys(group).map(function(key, i) { var item = group[key]; if (!item.position) @@ -245,7 +241,7 @@ var OptionPanel = function(editor, element) { }, this); }; - this.renderOptionControl = function(key, option) { + renderOptionControl(key, option) { var self = this; if (Array.isArray(option)) { return option.map(function(x) { @@ -331,7 +327,7 @@ var OptionPanel = function(editor, element) { return control; }; - this.renderOption = function(key, option) { + renderOption(key, option) { if (option.path && !option.onchange && !this.editor.$options[option.path]) return; var path = Array.isArray(option) ? option[0].path : option.path; @@ -344,7 +340,7 @@ var OptionPanel = function(editor, element) { ], ["td", control]]; }; - this.setOption = function(option, value) { + setOption(option, value) { if (typeof option == "string") option = this.options[option]; if (value == "false") value = false; @@ -360,12 +356,12 @@ var OptionPanel = function(editor, element) { this._signal("setOption", {name: option.path, value: value}); }; - this.getOption = function(option) { + getOption(option) { if (option.getValue) return option.getValue(); return this.editor.getOption(option.path); }; - -}).call(OptionPanel.prototype); +} +oop.implement(OptionPanel.prototype, EventEmitter); exports.OptionPanel = OptionPanel; diff --git a/src/ext/searchbox.js b/src/ext/searchbox.js index cdce490f683..a11e10d05ac 100644 --- a/src/ext/searchbox.js +++ b/src/ext/searchbox.js @@ -11,53 +11,136 @@ var MAX_COUNT = 999; dom.importCssString(searchboxCss, "ace_searchbox", false); -var SearchBox = function(editor, range, showReplaceForm) { - var div = dom.createElement("div"); - dom.buildDom(["div", {class:"ace_search right"}, - ["span", {action: "hide", class: "ace_searchbtn_close"}], - ["div", {class: "ace_search_form"}, - ["input", {class: "ace_search_field", placeholder: "Search for", spellcheck: "false"}], - ["span", {action: "findPrev", class: "ace_searchbtn prev"}, "\u200b"], - ["span", {action: "findNext", class: "ace_searchbtn next"}, "\u200b"], - ["span", {action: "findAll", class: "ace_searchbtn", title: "Alt-Enter"}, "All"] - ], - ["div", {class: "ace_replace_form"}, - ["input", {class: "ace_search_field", placeholder: "Replace with", spellcheck: "false"}], - ["span", {action: "replaceAndFindNext", class: "ace_searchbtn"}, "Replace"], - ["span", {action: "replaceAll", class: "ace_searchbtn"}, "All"] - ], - ["div", {class: "ace_search_options"}, - ["span", {action: "toggleReplace", class: "ace_button", title: "Toggle Replace mode", - style: "float:left;margin-top:-2px;padding:0 5px;"}, "+"], - ["span", {class: "ace_search_counter"}], - ["span", {action: "toggleRegexpMode", class: "ace_button", title: "RegExp Search"}, ".*"], - ["span", {action: "toggleCaseSensitive", class: "ace_button", title: "CaseSensitive Search"}, "Aa"], - ["span", {action: "toggleWholeWords", class: "ace_button", title: "Whole Word Search"}, "\\b"], - ["span", {action: "searchInSelection", class: "ace_button", title: "Search In Selection"}, "S"] - ] - ], div); - this.element = div.firstChild; - - this.setSession = this.setSession.bind(this); +class SearchBox { + constructor(editor, range, showReplaceForm) { + var div = dom.createElement("div"); + dom.buildDom(["div", {class:"ace_search right"}, + ["span", {action: "hide", class: "ace_searchbtn_close"}], + ["div", {class: "ace_search_form"}, + ["input", {class: "ace_search_field", placeholder: "Search for", spellcheck: "false"}], + ["span", {action: "findPrev", class: "ace_searchbtn prev"}, "\u200b"], + ["span", {action: "findNext", class: "ace_searchbtn next"}, "\u200b"], + ["span", {action: "findAll", class: "ace_searchbtn", title: "Alt-Enter"}, "All"] + ], + ["div", {class: "ace_replace_form"}, + ["input", {class: "ace_search_field", placeholder: "Replace with", spellcheck: "false"}], + ["span", {action: "replaceAndFindNext", class: "ace_searchbtn"}, "Replace"], + ["span", {action: "replaceAll", class: "ace_searchbtn"}, "All"] + ], + ["div", {class: "ace_search_options"}, + ["span", {action: "toggleReplace", class: "ace_button", title: "Toggle Replace mode", + style: "float:left;margin-top:-2px;padding:0 5px;"}, "+"], + ["span", {class: "ace_search_counter"}], + ["span", {action: "toggleRegexpMode", class: "ace_button", title: "RegExp Search"}, ".*"], + ["span", {action: "toggleCaseSensitive", class: "ace_button", title: "CaseSensitive Search"}, "Aa"], + ["span", {action: "toggleWholeWords", class: "ace_button", title: "Whole Word Search"}, "\\b"], + ["span", {action: "searchInSelection", class: "ace_button", title: "Search In Selection"}, "S"] + ] + ], div); + this.element = div.firstChild; - this.$init(); - this.setEditor(editor); - dom.importCssString(searchboxCss, "ace_searchbox", editor.container); -}; + this.setSession = this.setSession.bind(this); + + this.$init(); + this.setEditor(editor); + dom.importCssString(searchboxCss, "ace_searchbox", editor.container); + + + //keybinding outside of the searchbox + this.$searchBarKb = new HashHandler(); + this.$searchBarKb.bindKeys({ + "Ctrl-f|Command-f": function(sb) { + var isReplace = sb.isReplace = !sb.isReplace; + sb.replaceBox.style.display = isReplace ? "" : "none"; + sb.replaceOption.checked = false; + sb.$syncOptions(); + sb.searchInput.focus(); + }, + "Ctrl-H|Command-Option-F": function(sb) { + if (sb.editor.getReadOnly()) + return; + sb.replaceOption.checked = true; + sb.$syncOptions(); + sb.replaceInput.focus(); + }, + "Ctrl-G|Command-G": function(sb) { + sb.findNext(); + }, + "Ctrl-Shift-G|Command-Shift-G": function(sb) { + sb.findPrev(); + }, + "esc": function(sb) { + setTimeout(function() { sb.hide();}); + }, + "Return": function(sb) { + if (sb.activeInput == sb.replaceInput) + sb.replace(); + sb.findNext(); + }, + "Shift-Return": function(sb) { + if (sb.activeInput == sb.replaceInput) + sb.replace(); + sb.findPrev(); + }, + "Alt-Return": function(sb) { + if (sb.activeInput == sb.replaceInput) + sb.replaceAll(); + sb.findAll(); + }, + "Tab": function(sb) { + (sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus(); + } + }); -(function() { - this.setEditor = function(editor) { + this.$searchBarKb.addCommands([{ + name: "toggleRegexpMode", + bindKey: {win: "Alt-R|Alt-/", mac: "Ctrl-Alt-R|Ctrl-Alt-/"}, + exec: function(sb) { + sb.regExpOption.checked = !sb.regExpOption.checked; + sb.$syncOptions(); + } + }, { + name: "toggleCaseSensitive", + bindKey: {win: "Alt-C|Alt-I", mac: "Ctrl-Alt-R|Ctrl-Alt-I"}, + exec: function(sb) { + sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked; + sb.$syncOptions(); + } + }, { + name: "toggleWholeWords", + bindKey: {win: "Alt-B|Alt-W", mac: "Ctrl-Alt-B|Ctrl-Alt-W"}, + exec: function(sb) { + sb.wholeWordOption.checked = !sb.wholeWordOption.checked; + sb.$syncOptions(); + } + }, { + name: "toggleReplace", + exec: function(sb) { + sb.replaceOption.checked = !sb.replaceOption.checked; + sb.$syncOptions(); + } + }, { + name: "searchInSelection", + exec: function(sb) { + sb.searchOption.checked = !sb.searchRange; + sb.setSearchRange(sb.searchOption.checked && sb.editor.getSelectionRange()); + sb.$syncOptions(); + } + }]); + }; + + setEditor(editor) { editor.searchBox = this; editor.renderer.scroller.appendChild(this.element); this.editor = editor; }; - this.setSession = function(e) { + setSession(e) { this.searchRange = null; this.$syncOptions(true); }; - this.$initElements = function(sb) { + $initElements(sb) { this.searchBox = sb.querySelector(".ace_search_form"); this.replaceBox = sb.querySelector(".ace_replace_form"); this.searchOption = sb.querySelector("[action=searchInSelection]"); @@ -70,7 +153,7 @@ var SearchBox = function(editor, range, showReplaceForm) { this.searchCounter = sb.querySelector(".ace_search_counter"); }; - this.$init = function() { + $init() { var sb = this.element; this.$initElements(sb); @@ -119,97 +202,15 @@ var SearchBox = function(editor, range, showReplaceForm) { }; //keybinding outside of the searchbox - this.$closeSearchBarKb = new HashHandler([{ + $closeSearchBarKb = new HashHandler([{ bindKey: "Esc", name: "closeSearchBar", exec: function(editor) { editor.searchBox.hide(); } }]); - - //keybinding outside of the searchbox - this.$searchBarKb = new HashHandler(); - this.$searchBarKb.bindKeys({ - "Ctrl-f|Command-f": function(sb) { - var isReplace = sb.isReplace = !sb.isReplace; - sb.replaceBox.style.display = isReplace ? "" : "none"; - sb.replaceOption.checked = false; - sb.$syncOptions(); - sb.searchInput.focus(); - }, - "Ctrl-H|Command-Option-F": function(sb) { - if (sb.editor.getReadOnly()) - return; - sb.replaceOption.checked = true; - sb.$syncOptions(); - sb.replaceInput.focus(); - }, - "Ctrl-G|Command-G": function(sb) { - sb.findNext(); - }, - "Ctrl-Shift-G|Command-Shift-G": function(sb) { - sb.findPrev(); - }, - "esc": function(sb) { - setTimeout(function() { sb.hide();}); - }, - "Return": function(sb) { - if (sb.activeInput == sb.replaceInput) - sb.replace(); - sb.findNext(); - }, - "Shift-Return": function(sb) { - if (sb.activeInput == sb.replaceInput) - sb.replace(); - sb.findPrev(); - }, - "Alt-Return": function(sb) { - if (sb.activeInput == sb.replaceInput) - sb.replaceAll(); - sb.findAll(); - }, - "Tab": function(sb) { - (sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus(); - } - }); - - this.$searchBarKb.addCommands([{ - name: "toggleRegexpMode", - bindKey: {win: "Alt-R|Alt-/", mac: "Ctrl-Alt-R|Ctrl-Alt-/"}, - exec: function(sb) { - sb.regExpOption.checked = !sb.regExpOption.checked; - sb.$syncOptions(); - } - }, { - name: "toggleCaseSensitive", - bindKey: {win: "Alt-C|Alt-I", mac: "Ctrl-Alt-R|Ctrl-Alt-I"}, - exec: function(sb) { - sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked; - sb.$syncOptions(); - } - }, { - name: "toggleWholeWords", - bindKey: {win: "Alt-B|Alt-W", mac: "Ctrl-Alt-B|Ctrl-Alt-W"}, - exec: function(sb) { - sb.wholeWordOption.checked = !sb.wholeWordOption.checked; - sb.$syncOptions(); - } - }, { - name: "toggleReplace", - exec: function(sb) { - sb.replaceOption.checked = !sb.replaceOption.checked; - sb.$syncOptions(); - } - }, { - name: "searchInSelection", - exec: function(sb) { - sb.searchOption.checked = !sb.searchRange; - sb.setSearchRange(sb.searchOption.checked && sb.editor.getSelectionRange()); - sb.$syncOptions(); - } - }]); - this.setSearchRange = function(range) { + setSearchRange(range) { this.searchRange = range; if (range) { this.searchRangeMarker = this.editor.session.addMarker(range, "ace_active-line"); @@ -219,7 +220,7 @@ var SearchBox = function(editor, range, showReplaceForm) { } }; - this.$syncOptions = function(preventScroll) { + $syncOptions(preventScroll) { dom.setCssClass(this.replaceOption, "checked", this.searchRange); dom.setCssClass(this.searchOption, "checked", this.searchOption.checked); this.replaceOption.textContent = this.replaceOption.checked ? "-" : "+"; @@ -232,11 +233,12 @@ var SearchBox = function(editor, range, showReplaceForm) { this.find(false, false, preventScroll); }; - this.highlight = function(re) { + highlight(re) { this.editor.session.highlight(re || this.editor.$search.$options.re); this.editor.renderer.updateBackMarkers(); }; - this.find = function(skipCurrent, backwards, preventScroll) { + + find(skipCurrent, backwards, preventScroll) { var range = this.editor.find(this.searchInput.value, { skipCurrent: skipCurrent, backwards: backwards, @@ -253,7 +255,7 @@ var SearchBox = function(editor, range, showReplaceForm) { this.highlight(); this.updateCounter(); }; - this.updateCounter = function() { + updateCounter() { var editor = this.editor; var regex = editor.$search.$options.re; var all = 0; @@ -285,13 +287,13 @@ var SearchBox = function(editor, range, showReplaceForm) { } this.searchCounter.textContent = before + " of " + (all > MAX_COUNT ? MAX_COUNT + "+" : all); }; - this.findNext = function() { + findNext() { this.find(true, false); }; - this.findPrev = function() { + findPrev() { this.find(true, true); }; - this.findAll = function(){ + findAll(){ var range = this.editor.findAll(this.searchInput.value, { regExp: this.regExpOption.checked, caseSensitive: this.caseSensitiveOption.checked, @@ -303,22 +305,22 @@ var SearchBox = function(editor, range, showReplaceForm) { this.highlight(); this.hide(); }; - this.replace = function() { + replace() { if (!this.editor.getReadOnly()) this.editor.replace(this.replaceInput.value); }; - this.replaceAndFindNext = function() { + replaceAndFindNext() { if (!this.editor.getReadOnly()) { this.editor.replace(this.replaceInput.value); this.findNext(); } }; - this.replaceAll = function() { + replaceAll() { if (!this.editor.getReadOnly()) this.editor.replaceAll(this.replaceInput.value); }; - this.hide = function() { + hide() { this.active = false; this.setSearchRange(null); this.editor.off("changeSession", this.setSession); @@ -327,7 +329,7 @@ var SearchBox = function(editor, range, showReplaceForm) { this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb); this.editor.focus(); }; - this.show = function(value, isReplace) { + show(value, isReplace) { this.active = true; this.editor.on("changeSession", this.setSession); this.element.style.display = ""; @@ -344,11 +346,11 @@ var SearchBox = function(editor, range, showReplaceForm) { this.$syncOptions(true); }; - this.isFocused = function() { + isFocused() { var el = document.activeElement; return el == this.searchInput || el == this.replaceInput; }; -}).call(SearchBox.prototype); +} exports.SearchBox = SearchBox; diff --git a/src/ext/static_highlight.js b/src/ext/static_highlight.js index ae85c767f7c..c6aa860e278 100644 --- a/src/ext/static_highlight.js +++ b/src/ext/static_highlight.js @@ -7,42 +7,47 @@ var config = require("../config"); var dom = require("../lib/dom"); var escapeHTML = require("../lib/lang").escapeHTML; -function Element(type) { - this.type = type; - this.style = {}; - this.textContent = ""; -} -Element.prototype.cloneNode = function() { - return this; -}; -Element.prototype.appendChild = function(child) { - this.textContent += child.toString(); -}; -Element.prototype.toString = function() { - var stringBuilder = []; - if (this.type != "fragment") { - stringBuilder.push("<", this.type); - if (this.className) - stringBuilder.push(" class='", this.className, "'"); - var styleStr = []; - for (var key in this.style) { - styleStr.push(key, ":", this.style[key]); - } - if (styleStr.length) - stringBuilder.push(" style='", styleStr.join(""), "'"); - stringBuilder.push(">"); +class Element { + constructor(type) { + this.type = type; + this.style = {}; + this.textContent = ""; } - if (this.textContent) { - stringBuilder.push(this.textContent); - } + cloneNode() { + return this; + }; - if (this.type != "fragment") { - stringBuilder.push(""); - } - - return stringBuilder.join(""); -}; + appendChild(child) { + this.textContent += child.toString(); + }; + + toString() { + var stringBuilder = []; + if (this.type != "fragment") { + stringBuilder.push("<", this.type); + if (this.className) + stringBuilder.push(" class='", this.className, "'"); + var styleStr = []; + for (var key in this.style) { + styleStr.push(key, ":", this.style[key]); + } + if (styleStr.length) + stringBuilder.push(" style='", styleStr.join(""), "'"); + stringBuilder.push(">"); + } + + if (this.textContent) { + stringBuilder.push(this.textContent); + } + + if (this.type != "fragment") { + stringBuilder.push(""); + } + + return stringBuilder.join(""); + }; +} var simpleDom = { @@ -57,10 +62,13 @@ var simpleDom = { } }; -var SimpleTextLayer = function() { - this.config = {}; - this.dom = simpleDom; -}; + +class SimpleTextLayer { + constructor() { + this.config = {}; + this.dom = simpleDom; + }; +} SimpleTextLayer.prototype = TextLayer.prototype; var highlight = function(el, opts, callback) { diff --git a/src/ext/statusbar.js b/src/ext/statusbar.js index a055faf4ed9..b0d60373caf 100644 --- a/src/ext/statusbar.js +++ b/src/ext/statusbar.js @@ -1,25 +1,26 @@ "use strict"; -/** simple statusbar **/ + var dom = require("../lib/dom"); var lang = require("../lib/lang"); -var StatusBar = function(editor, parentNode) { - this.element = dom.createElement("div"); - this.element.className = "ace_status-indicator"; - this.element.style.cssText = "display: inline-block;"; - parentNode.appendChild(this.element); +/** simple statusbar **/ +class StatusBar{ + constructor(editor, parentNode) { + this.element = dom.createElement("div"); + this.element.className = "ace_status-indicator"; + this.element.style.cssText = "display: inline-block;"; + parentNode.appendChild(this.element); + + var statusUpdate = lang.delayedCall(function(){ + this.updateStatus(editor); + }.bind(this)).schedule.bind(null, 100); - var statusUpdate = lang.delayedCall(function(){ - this.updateStatus(editor); - }.bind(this)).schedule.bind(null, 100); + editor.on("changeStatus", statusUpdate); + editor.on("changeSelection", statusUpdate); + editor.on("keyboardActivity", statusUpdate); + }; - editor.on("changeStatus", statusUpdate); - editor.on("changeSelection", statusUpdate); - editor.on("keyboardActivity", statusUpdate); -}; - -(function(){ - this.updateStatus = function(editor) { + updateStatus(editor) { var status = []; function add(str, separator) { str && status.push(str, separator || "|"); @@ -42,6 +43,6 @@ var StatusBar = function(editor, parentNode) { status.pop(); this.element.textContent = status.join(""); }; -}).call(StatusBar.prototype); +} exports.StatusBar = StatusBar; diff --git a/src/incremental_search.js b/src/incremental_search.js index 569e983f46c..750c5bc3804 100644 --- a/src/incremental_search.js +++ b/src/incremental_search.js @@ -7,32 +7,6 @@ var SearchHighlight = require("./search_highlight").SearchHighlight; var iSearchCommandModule = require("./commands/incremental_search_commands"); var ISearchKbd = iSearchCommandModule.IncrementalSearchKeyboardHandler; -/** - * @class IncrementalSearch - * - * Implements immediate searching while the user is typing. When incremental - * search is activated, keystrokes into the editor will be used for composing - * a search term. Immediately after every keystroke the search is updated: - * - so-far-matching characters are highlighted - * - the cursor is moved to the next match - * - **/ - - -/** - * - * - * Creates a new `IncrementalSearch` object. - * - * @constructor - **/ -function IncrementalSearch() { - this.$options = {wrap: false, skipCurrent: false}; - this.$keyboardHandler = new ISearchKbd(this); -} - -oop.inherits(IncrementalSearch, Search); - // regexp handling function isRegExp(obj) { @@ -59,11 +33,25 @@ function objectToRegExp(obj) { return stringToRegExp(obj.expression, obj.flags); } -// iSearch class - -(function() { - - this.activate = function(editor, backwards) { +/** + * Implements immediate searching while the user is typing. When incremental + * search is activated, keystrokes into the editor will be used for composing + * a search term. Immediately after every keystroke the search is updated: + * - so-far-matching characters are highlighted + * - the cursor is moved to the next match + * + **/ +class IncrementalSearch extends Search { + /** + * Creates a new `IncrementalSearch` object. + **/ + constructor() { + super(); + this.$options = {wrap: false, skipCurrent: false}; + this.$keyboardHandler = new ISearchKbd(this); + } + + activate(editor, backwards) { this.$editor = editor; this.$startPos = this.$currentPos = editor.getCursorPosition(); this.$options.needle = ''; @@ -77,7 +65,7 @@ function objectToRegExp(obj) { this.statusMessage(true); }; - this.deactivate = function(reset) { + deactivate(reset) { this.cancelSearch(reset); var editor = this.$editor; editor.keyBinding.removeKeyboardHandler(this.$keyboardHandler); @@ -89,7 +77,7 @@ function objectToRegExp(obj) { this.message(''); }; - this.selectionFix = function(editor) { + selectionFix(editor) { // Fix selection bug: When clicked inside the editor // editor.selection.$isEmpty is false even if the mouse click did not // open a selection. This is interpreted by the move commands to @@ -100,7 +88,7 @@ function objectToRegExp(obj) { } }; - this.highlight = function(regexp) { + highlight(regexp) { var sess = this.$editor.session, hl = sess.$isearchHighlight = sess.$isearchHighlight || sess.addDynamicMarker( new SearchHighlight(null, "ace_isearch-result", "text")); @@ -108,7 +96,7 @@ function objectToRegExp(obj) { sess._emit("changeBackMarker"); // force highlight layer redraw }; - this.cancelSearch = function(reset) { + cancelSearch(reset) { var e = this.$editor; this.$prevNeedle = this.$options.needle; this.$options.needle = ''; @@ -122,7 +110,7 @@ function objectToRegExp(obj) { return Range.fromPoints(this.$currentPos, this.$currentPos); }; - this.highlightAndFindWithNeedle = function(moveToNext, needleUpdateFunc) { + highlightAndFindWithNeedle(moveToNext, needleUpdateFunc) { if (!this.$editor) return null; var options = this.$options; @@ -154,7 +142,7 @@ function objectToRegExp(obj) { return found; }; - this.addString = function(s) { + addString(s) { return this.highlightAndFindWithNeedle(false, function(needle) { if (!isRegExp(needle)) return needle + s; @@ -164,7 +152,7 @@ function objectToRegExp(obj) { }); }; - this.removeChar = function(c) { + removeChar(c) { return this.highlightAndFindWithNeedle(false, function(needle) { if (!isRegExp(needle)) return needle.substring(0, needle.length-1); @@ -174,7 +162,7 @@ function objectToRegExp(obj) { }); }; - this.next = function(options) { + next(options) { // try to find the next occurrence of whatever we have searched for // earlier. // options = {[backwards: BOOL], [useCurrentOrPrevSearch: BOOL]} @@ -187,29 +175,29 @@ function objectToRegExp(obj) { }); }; - this.onMouseDown = function(evt) { + onMouseDown(evt) { // when mouse interaction happens then we quit incremental search this.deactivate(); return true; }; - this.onPaste = function(text) { + onPaste(text) { this.addString(text); }; - this.convertNeedleToRegExp = function() { + convertNeedleToRegExp() { return this.highlightAndFindWithNeedle(false, function(needle) { return isRegExp(needle) ? needle : stringToRegExp(needle, 'ig'); }); }; - this.convertNeedleToString = function() { + convertNeedleToString() { return this.highlightAndFindWithNeedle(false, function(needle) { return isRegExp(needle) ? regExpToObject(needle).expression : needle; }); }; - this.statusMessage = function(found) { + statusMessage(found) { var options = this.$options, msg = ''; msg += options.backwards ? 'reverse-' : ''; msg += 'isearch: ' + options.needle; @@ -217,15 +205,14 @@ function objectToRegExp(obj) { this.message(msg); }; - this.message = function(msg) { + message(msg) { if (this.$editor.showCommandLine) { this.$editor.showCommandLine(msg); this.$editor.focus(); } }; -}).call(IncrementalSearch.prototype); - +} exports.IncrementalSearch = IncrementalSearch; diff --git a/src/keyboard/keybinding.js b/src/keyboard/keybinding.js index bec1ce43fac..4b375945354 100644 --- a/src/keyboard/keybinding.js +++ b/src/keyboard/keybinding.js @@ -3,21 +3,22 @@ var keyUtil = require("../lib/keys"); var event = require("../lib/event"); -var KeyBinding = function(editor) { - this.$editor = editor; - this.$data = {editor: editor}; - this.$handlers = []; - this.setDefaultHandler(editor.commands); -}; - -(function() { - this.setDefaultHandler = function(kb) { + +class KeyBinding { + constructor(editor) { + this.$editor = editor; + this.$data = {editor: editor}; + this.$handlers = []; + this.setDefaultHandler(editor.commands); + }; + + setDefaultHandler(kb) { this.removeKeyboardHandler(this.$defaultHandler); this.$defaultHandler = kb; this.addKeyboardHandler(kb, 0); }; - this.setKeyboardHandler = function(kb) { + setKeyboardHandler(kb) { var h = this.$handlers; if (h[h.length - 1] == kb) return; @@ -28,7 +29,7 @@ var KeyBinding = function(editor) { this.addKeyboardHandler(kb, 1); }; - this.addKeyboardHandler = function(kb, pos) { + addKeyboardHandler(kb, pos) { if (!kb) return; if (typeof kb == "function" && !kb.handleKeyboard) @@ -46,7 +47,7 @@ var KeyBinding = function(editor) { kb.attach(this.$editor); }; - this.removeKeyboardHandler = function(kb) { + removeKeyboardHandler(kb) { var i = this.$handlers.indexOf(kb); if (i == -1) return false; @@ -55,11 +56,11 @@ var KeyBinding = function(editor) { return true; }; - this.getKeyboardHandler = function() { + getKeyboardHandler() { return this.$handlers[this.$handlers.length - 1]; }; - this.getStatusText = function() { + getStatusText() { var data = this.$data; var editor = data.editor; return this.$handlers.map(function(h) { @@ -67,7 +68,7 @@ var KeyBinding = function(editor) { }).filter(Boolean).join(" "); }; - this.$callKeyboardHandlers = function(hashId, keyString, keyCode, e) { + $callKeyboardHandlers(hashId, keyString, keyCode, e) { var toExecute; var success = false; var commands = this.$editor.commands; @@ -106,15 +107,15 @@ var KeyBinding = function(editor) { return success; }; - this.onCommandKey = function(e, hashId, keyCode) { + onCommandKey(e, hashId, keyCode) { var keyString = keyUtil.keyCodeToString(keyCode); return this.$callKeyboardHandlers(hashId, keyString, keyCode, e); }; - this.onTextInput = function(text) { + onTextInput(text) { return this.$callKeyboardHandlers(-1, text); }; -}).call(KeyBinding.prototype); +} exports.KeyBinding = KeyBinding; diff --git a/src/layer/cursor.js b/src/layer/cursor.js index 069e59f2d1c..828e8988dfb 100644 --- a/src/layer/cursor.js +++ b/src/layer/cursor.js @@ -2,31 +2,31 @@ var dom = require("../lib/dom"); -var Cursor = function(parentEl) { - this.element = dom.createElement("div"); - this.element.className = "ace_layer ace_cursor-layer"; - parentEl.appendChild(this.element); - - this.isVisible = false; - this.isBlinking = true; - this.blinkInterval = 1000; - this.smoothBlinking = false; - - this.cursors = []; - this.cursor = this.addCursor(); - dom.addCssClass(this.element, "ace_hidden-cursors"); - this.$updateCursors = this.$updateOpacity.bind(this); -}; - -(function() { + +class Cursor { + constructor(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_cursor-layer"; + parentEl.appendChild(this.element); + + this.isVisible = false; + this.isBlinking = true; + this.blinkInterval = 1000; + this.smoothBlinking = false; + + this.cursors = []; + this.cursor = this.addCursor(); + dom.addCssClass(this.element, "ace_hidden-cursors"); + this.$updateCursors = this.$updateOpacity.bind(this); + }; - this.$updateOpacity = function(val) { + $updateOpacity(val) { var cursors = this.cursors; for (var i = cursors.length; i--; ) dom.setStyle(cursors[i].style, "opacity", val ? "" : "0"); }; - this.$startCssAnimation = function() { + $startCssAnimation() { var cursors = this.cursors; for (var i = cursors.length; i--; ) cursors[i].style.animationDuration = this.blinkInterval + "ms"; @@ -39,35 +39,35 @@ var Cursor = function(parentEl) { }.bind(this)); }; - this.$stopCssAnimation = function() { + $stopCssAnimation() { this.$isAnimating = false; dom.removeCssClass(this.element, "ace_animate-blinking"); }; - this.$padding = 0; - this.setPadding = function(padding) { + $padding = 0; + setPadding(padding) { this.$padding = padding; }; - this.setSession = function(session) { + setSession(session) { this.session = session; }; - this.setBlinking = function(blinking) { + setBlinking(blinking) { if (blinking != this.isBlinking) { this.isBlinking = blinking; this.restartTimer(); } }; - this.setBlinkInterval = function(blinkInterval) { + setBlinkInterval(blinkInterval) { if (blinkInterval != this.blinkInterval) { this.blinkInterval = blinkInterval; this.restartTimer(); } }; - this.setSmoothBlinking = function(smoothBlinking) { + setSmoothBlinking(smoothBlinking) { if (smoothBlinking != this.smoothBlinking) { this.smoothBlinking = smoothBlinking; dom.setCssClass(this.element, "ace_smooth-blinking", smoothBlinking); @@ -76,7 +76,7 @@ var Cursor = function(parentEl) { } }; - this.addCursor = function() { + addCursor() { var el = dom.createElement("div"); el.className = "ace_cursor"; this.element.appendChild(el); @@ -84,7 +84,7 @@ var Cursor = function(parentEl) { return el; }; - this.removeCursor = function() { + removeCursor() { if (this.cursors.length > 1) { var el = this.cursors.pop(); el.parentNode.removeChild(el); @@ -92,19 +92,19 @@ var Cursor = function(parentEl) { } }; - this.hideCursor = function() { + hideCursor() { this.isVisible = false; dom.addCssClass(this.element, "ace_hidden-cursors"); this.restartTimer(); }; - this.showCursor = function() { + showCursor() { this.isVisible = true; dom.removeCssClass(this.element, "ace_hidden-cursors"); this.restartTimer(); }; - this.restartTimer = function() { + restartTimer() { var update = this.$updateCursors; clearInterval(this.intervalId); clearTimeout(this.timeoutId); @@ -148,7 +148,7 @@ var Cursor = function(parentEl) { } }; - this.getPixelPosition = function(position, onScreen) { + getPixelPosition(position, onScreen) { if (!this.config || !this.session) return {left : 0, top : 0}; @@ -165,11 +165,11 @@ var Cursor = function(parentEl) { return {left : cursorLeft, top : cursorTop}; }; - this.isCursorInView = function(pixelPos, config) { + isCursorInView(pixelPos, config) { return pixelPos.top >= 0 && pixelPos.top < config.maxHeight; }; - this.update = function(config) { + update(config) { this.config = config; var selections = this.session.$selectionMarkers; @@ -213,9 +213,9 @@ var Cursor = function(parentEl) { this.restartTimer(); }; - this.drawCursor = null; + drawCursor = null; - this.$setOverwrite = function(overwrite) { + $setOverwrite(overwrite) { if (overwrite != this.overwrite) { this.overwrite = overwrite; if (overwrite) @@ -225,11 +225,11 @@ var Cursor = function(parentEl) { } }; - this.destroy = function() { + destroy() { clearInterval(this.intervalId); clearTimeout(this.timeoutId); }; -}).call(Cursor.prototype); +} exports.Cursor = Cursor; diff --git a/src/layer/decorators.js b/src/layer/decorators.js index a2be8107540..88d927ba425 100644 --- a/src/layer/decorators.js +++ b/src/layer/decorators.js @@ -3,45 +3,43 @@ var dom = require("../lib/dom"); var oop = require("../lib/oop"); var EventEmitter = require("../lib/event_emitter").EventEmitter; -var Decorator = function (parent, renderer) { - this.canvas = dom.createElement("canvas"); - this.renderer = renderer; - this.pixelRatio = 1; - this.maxHeight = renderer.layerConfig.maxHeight; - this.lineHeight = renderer.layerConfig.lineHeight; - this.canvasHeight = parent.parent.scrollHeight; - this.heightRatio = this.canvasHeight / this.maxHeight; - this.canvasWidth = parent.width; - this.minDecorationHeight = (2 * this.pixelRatio) | 0; - this.halfMinDecorationHeight = (this.minDecorationHeight / 2) | 0; +class Decorator { + constructor(parent, renderer) { + this.canvas = dom.createElement("canvas"); + this.renderer = renderer; + this.pixelRatio = 1; + this.maxHeight = renderer.layerConfig.maxHeight; + this.lineHeight = renderer.layerConfig.lineHeight; + this.canvasHeight = parent.parent.scrollHeight; + this.heightRatio = this.canvasHeight / this.maxHeight; + this.canvasWidth = parent.width; + this.minDecorationHeight = (2 * this.pixelRatio) | 0; + this.halfMinDecorationHeight = (this.minDecorationHeight / 2) | 0; - this.canvas.width = this.canvasWidth; - this.canvas.height = this.canvasHeight; - this.canvas.style.top = 0 + "px"; - this.canvas.style.right = 0 + "px"; - this.canvas.style.zIndex = 7 + "px"; - this.canvas.style.position = "absolute"; - this.colors = {}; - this.colors.dark = { - "error": "rgba(255, 18, 18, 1)", - "warning": "rgba(18, 136, 18, 1)", - "info": "rgba(18, 18, 136, 1)" - }; - - this.colors.light = { - "error": "rgb(255,51,51)", - "warning": "rgb(32,133,72)", - "info": "rgb(35,68,138)" - }; + this.canvas.width = this.canvasWidth; + this.canvas.height = this.canvasHeight; + this.canvas.style.top = 0 + "px"; + this.canvas.style.right = 0 + "px"; + this.canvas.style.zIndex = 7 + "px"; + this.canvas.style.position = "absolute"; + this.colors = {}; + this.colors.dark = { + "error": "rgba(255, 18, 18, 1)", + "warning": "rgba(18, 136, 18, 1)", + "info": "rgba(18, 18, 136, 1)" + }; - parent.element.appendChild(this.canvas); + this.colors.light = { + "error": "rgb(255,51,51)", + "warning": "rgb(32,133,72)", + "info": "rgb(35,68,138)" + }; -}; + parent.element.appendChild(this.canvas); -(function () { - oop.implement(this, EventEmitter); - - this.$updateDecorators = function (config) { + }; + + $updateDecorators(config) { var colors = (this.renderer.theme.isDark === true) ? this.colors.dark : this.colors.light; if (config) { this.maxHeight = config.maxHeight; @@ -110,7 +108,7 @@ var Decorator = function (parent, renderer) { }; - this.compensateFoldRows = function (row, foldData) { + compensateFoldRows(row, foldData) { let compensateFold = 0; if (foldData && foldData.length > 0) { for (let j = 0; j < foldData.length; j++) { @@ -124,6 +122,8 @@ var Decorator = function (parent, renderer) { } return compensateFold; }; -}.call(Decorator.prototype)); +} + +oop.implement(Decorator.prototype, EventEmitter); -exports.Decorator = Decorator; \ No newline at end of file +exports.Decorator = Decorator; diff --git a/src/layer/font_metrics.js b/src/layer/font_metrics.js index 459d982146a..83c56d85d97 100644 --- a/src/layer/font_metrics.js +++ b/src/layer/font_metrics.js @@ -9,39 +9,37 @@ var CHAR_COUNT = 512; var USE_OBSERVER = typeof ResizeObserver == "function"; var L = 200; -var FontMetrics = exports.FontMetrics = function(parentEl) { - this.el = dom.createElement("div"); - this.$setMeasureNodeStyles(this.el.style, true); +class FontMetrics { - this.$main = dom.createElement("div"); - this.$setMeasureNodeStyles(this.$main.style); - - this.$measureNode = dom.createElement("div"); - this.$setMeasureNodeStyles(this.$measureNode.style); - - - this.el.appendChild(this.$main); - this.el.appendChild(this.$measureNode); - parentEl.appendChild(this.el); - - this.$measureNode.textContent = lang.stringRepeat("X", CHAR_COUNT); - - this.$characterSize = {width: 0, height: 0}; - - - if (USE_OBSERVER) - this.$addObserver(); - else - this.checkForSizeChanges(); -}; + constructor(parentEl) { + this.el = dom.createElement("div"); + this.$setMeasureNodeStyles(this.el.style, true); + + this.$main = dom.createElement("div"); + this.$setMeasureNodeStyles(this.$main.style); + + this.$measureNode = dom.createElement("div"); + this.$setMeasureNodeStyles(this.$measureNode.style); -(function() { - oop.implement(this, EventEmitter); + this.el.appendChild(this.$main); + this.el.appendChild(this.$measureNode); + parentEl.appendChild(this.el); + + this.$measureNode.textContent = lang.stringRepeat("X", CHAR_COUNT); + + this.$characterSize = {width: 0, height: 0}; + + + if (USE_OBSERVER) + this.$addObserver(); + else + this.checkForSizeChanges(); + }; - this.$characterSize = {width: 0, height: 0}; + $characterSize = {width: 0, height: 0}; - this.$setMeasureNodeStyles = function(style, isRoot) { + $setMeasureNodeStyles(style, isRoot) { style.width = style.height = "auto"; style.left = style.top = "0px"; style.visibility = "hidden"; @@ -56,7 +54,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { style.overflow = isRoot ? "hidden" : "visible"; }; - this.checkForSizeChanges = function(size) { + checkForSizeChanges(size) { if (size === undefined) size = this.$measureSizes(); if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) { @@ -70,7 +68,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { } }; - this.$addObserver = function() { + $addObserver() { var self = this; this.$observer = new window.ResizeObserver(function(e) { // e[0].contentRect is broken on safari when zoomed; @@ -79,7 +77,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { this.$observer.observe(this.$measureNode); }; - this.$pollSizeChanges = function() { + $pollSizeChanges() { if (this.$pollSizeChangesTimer || this.$observer) return this.$pollSizeChangesTimer; var self = this; @@ -90,7 +88,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { }, 500); }; - this.setPolling = function(val) { + setPolling(val) { if (val) { this.$pollSizeChanges(); } else if (this.$pollSizeChangesTimer) { @@ -99,7 +97,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { } }; - this.$measureSizes = function(node) { + $measureSizes(node) { var size = { height: (node || this.$measureNode).clientHeight, width: (node || this.$measureNode).clientWidth / CHAR_COUNT @@ -112,13 +110,13 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { return size; }; - this.$measureCharWidth = function(ch) { + $measureCharWidth(ch) { this.$main.textContent = lang.stringRepeat(ch, CHAR_COUNT); var rect = this.$main.getBoundingClientRect(); return rect.width / CHAR_COUNT; }; - this.getCharacterWidth = function(ch) { + getCharacterWidth(ch) { var w = this.charSizes[ch]; if (w === undefined) { w = this.charSizes[ch] = this.$measureCharWidth(ch) / this.$characterSize.width; @@ -126,7 +124,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { return w; }; - this.destroy = function() { + destroy() { clearInterval(this.$pollSizeChangesTimer); if (this.$observer) this.$observer.disconnect(); @@ -135,11 +133,12 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { }; - this.$getZoom = function getZoom(element) { + $getZoom(element) { if (!element || !element.parentElement) return 1; - return (window.getComputedStyle(element).zoom || 1) * getZoom(element.parentElement); + return (window.getComputedStyle(element).zoom || 1) * this.$getZoom(element.parentElement); }; - this.$initTransformMeasureNodes = function() { + + $initTransformMeasureNodes() { var t = function(t, l) { return ["div", { style: "position: absolute;top:" + t + "px;left:" + l + "px;" @@ -153,7 +152,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { // | h[0] h[1] 1 | | 1 | | 1 | // this function finds the coeeficients of the matrix using positions of four points // - this.transformCoordinates = function(clientPos, elPos) { + transformCoordinates(clientPos, elPos) { if (clientPos) { var zoom = this.$getZoom(this.el); clientPos = mul(1 / zoom, clientPos); @@ -198,4 +197,8 @@ var FontMetrics = exports.FontMetrics = function(parentEl) { return mul(L, f); }; -}).call(FontMetrics.prototype); +} + +oop.implement(FontMetrics.prototype, EventEmitter); + +exports.FontMetrics = FontMetrics; diff --git a/src/layer/gutter.js b/src/layer/gutter.js index b352752be07..7bb6a01fdae 100644 --- a/src/layer/gutter.js +++ b/src/layer/gutter.js @@ -6,26 +6,23 @@ var lang = require("../lib/lang"); var EventEmitter = require("../lib/event_emitter").EventEmitter; var Lines = require("./lines").Lines; -var Gutter = function(parentEl) { - this.element = dom.createElement("div"); - this.element.className = "ace_layer ace_gutter-layer"; - parentEl.appendChild(this.element); - this.setShowFoldWidgets(this.$showFoldWidgets); - - this.gutterWidth = 0; +class Gutter{ + constructor(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_gutter-layer"; + parentEl.appendChild(this.element); + this.setShowFoldWidgets(this.$showFoldWidgets); - this.$annotations = []; - this.$updateAnnotations = this.$updateAnnotations.bind(this); - - this.$lines = new Lines(this.element); - this.$lines.$offsetCoefficient = 1; -}; + this.gutterWidth = 0; -(function() { + this.$annotations = []; + this.$updateAnnotations = this.$updateAnnotations.bind(this); - oop.implement(this, EventEmitter); + this.$lines = new Lines(this.element); + this.$lines.$offsetCoefficient = 1; + }; - this.setSession = function(session) { + setSession(session) { if (this.session) this.session.off("change", this.$updateAnnotations); this.session = session; @@ -33,19 +30,19 @@ var Gutter = function(parentEl) { session.on("change", this.$updateAnnotations); }; - this.addGutterDecoration = function(row, className) { + addGutterDecoration(row, className) { if (window.console) console.warn && console.warn("deprecated use session.addGutterDecoration"); this.session.addGutterDecoration(row, className); }; - this.removeGutterDecoration = function(row, className) { + removeGutterDecoration(row, className) { if (window.console) console.warn && console.warn("deprecated use session.removeGutterDecoration"); this.session.removeGutterDecoration(row, className); }; - this.setAnnotations = function(annotations) { + setAnnotations(annotations) { // iterate over sparse array this.$annotations = []; for (var i = 0; i < annotations.length; i++) { @@ -74,7 +71,7 @@ var Gutter = function(parentEl) { } }; - this.$updateAnnotations = function (delta) { + $updateAnnotations(delta) { if (!this.$annotations.length) return; var firstRow = delta.start.row; @@ -90,7 +87,7 @@ var Gutter = function(parentEl) { } }; - this.update = function(config) { + update(config) { this.config = config; var session = this.session; @@ -140,7 +137,7 @@ var Gutter = function(parentEl) { this.$updateGutterWidth(config); }; - this.$updateGutterWidth = function(config) { + $updateGutterWidth(config) { var session = this.session; var gutterRenderer = session.gutterRenderer || this.$renderer; @@ -165,7 +162,7 @@ var Gutter = function(parentEl) { } }; - this.$updateCursorRow = function() { + $updateCursorRow() { if (!this.$highlightGutterLine) return; @@ -176,7 +173,7 @@ var Gutter = function(parentEl) { this.$cursorRow = position.row; }; - this.updateLineHighlight = function() { + updateLineHighlight() { if (!this.$highlightGutterLine) return; var row = this.session.selection.cursor.row; @@ -205,7 +202,7 @@ var Gutter = function(parentEl) { } }; - this.scrollLines = function(config) { + scrollLines(config) { var oldConfig = this.config; this.config = config; @@ -248,7 +245,7 @@ var Gutter = function(parentEl) { this.$updateGutterWidth(config); }; - this.$renderLines = function(config, firstRow, lastRow) { + $renderLines(config, firstRow, lastRow) { var fragment = []; var row = firstRow; var foldLine = this.session.getNextFoldLine(row); @@ -272,7 +269,7 @@ var Gutter = function(parentEl) { return fragment; }; - this.$renderCell = function(cell, config, fold, row) { + $renderCell(cell, config, fold, row) { var element = cell.element; var session = this.session; @@ -349,29 +346,29 @@ var Gutter = function(parentEl) { return cell; }; - this.$fixedWidth = false; + $fixedWidth = false; - this.$highlightGutterLine = true; - this.$renderer = ""; - this.setHighlightGutterLine = function(highlightGutterLine) { + $highlightGutterLine = true; + $renderer = ""; + setHighlightGutterLine(highlightGutterLine) { this.$highlightGutterLine = highlightGutterLine; }; - this.$showLineNumbers = true; - this.$renderer = ""; - this.setShowLineNumbers = function(show) { + $showLineNumbers = true; + $renderer = ""; + setShowLineNumbers(show) { this.$renderer = !show && { getWidth: function() {return 0;}, getText: function() {return "";} }; }; - this.getShowLineNumbers = function() { + getShowLineNumbers() { return this.$showLineNumbers; }; - this.$showFoldWidgets = true; - this.setShowFoldWidgets = function(show) { + $showFoldWidgets = true; + setShowFoldWidgets(show) { if (show) dom.addCssClass(this.element, "ace_folding-enabled"); else @@ -381,11 +378,11 @@ var Gutter = function(parentEl) { this.$padding = null; }; - this.getShowFoldWidgets = function() { + getShowFoldWidgets() { return this.$showFoldWidgets; }; - this.$computePadding = function() { + $computePadding() { if (!this.element.firstChild) return {left: 0, right: 0}; var style = dom.computedStyle(this.element.firstChild); @@ -397,7 +394,7 @@ var Gutter = function(parentEl) { return this.$padding; }; - this.getRegion = function(point) { + getRegion(point) { var padding = this.$padding || this.$computePadding(); var rect = this.element.getBoundingClientRect(); if (point.x < padding.left + rect.left) @@ -406,7 +403,9 @@ var Gutter = function(parentEl) { return "foldWidgets"; }; -}).call(Gutter.prototype); +} + +oop.implement(Gutter.prototype, EventEmitter); function onCreateCell(element) { var textNode = document.createTextNode(''); diff --git a/src/layer/lines.js b/src/layer/lines.js index 3a5e9383e21..207d3a12c7b 100644 --- a/src/layer/lines.js +++ b/src/layer/lines.js @@ -2,57 +2,56 @@ var dom = require("../lib/dom"); -var Lines = function(element, canvasHeight) { - this.element = element; - this.canvasHeight = canvasHeight || 500000; - this.element.style.height = (this.canvasHeight * 2) + "px"; - - this.cells = []; - this.cellCache = []; - this.$offsetCoefficient = 0; -}; +class Lines { + constructor(element, canvasHeight) { + this.element = element; + this.canvasHeight = canvasHeight || 500000; + this.element.style.height = (this.canvasHeight * 2) + "px"; -(function() { + this.cells = []; + this.cellCache = []; + this.$offsetCoefficient = 0; + }; - this.moveContainer = function(config) { + moveContainer(config) { dom.translate(this.element, 0, -((config.firstRowScreen * config.lineHeight) % this.canvasHeight) - config.offset * this.$offsetCoefficient); }; - this.pageChanged = function(oldConfig, newConfig) { + pageChanged(oldConfig, newConfig) { return ( Math.floor((oldConfig.firstRowScreen * oldConfig.lineHeight) / this.canvasHeight) !== Math.floor((newConfig.firstRowScreen * newConfig.lineHeight) / this.canvasHeight) ); }; - this.computeLineTop = function(row, config, session) { + computeLineTop(row, config, session) { var screenTop = config.firstRowScreen * config.lineHeight; var screenPage = Math.floor(screenTop / this.canvasHeight); var lineTop = session.documentToScreenRow(row, 0) * config.lineHeight; return lineTop - (screenPage * this.canvasHeight); }; - this.computeLineHeight = function(row, config, session) { + computeLineHeight(row, config, session) { return config.lineHeight * session.getRowLineCount(row); }; - this.getLength = function() { + getLength() { return this.cells.length; }; - this.get = function(index) { + get(index) { return this.cells[index]; }; - this.shift = function() { + shift() { this.$cacheCell(this.cells.shift()); }; - this.pop = function() { + pop() { this.$cacheCell(this.cells.pop()); }; - this.push = function(cell) { + push(cell) { if (Array.isArray(cell)) { this.cells.push.apply(this.cells, cell); var fragment = dom.createFragment(this.element); @@ -66,7 +65,7 @@ var Lines = function(element, canvasHeight) { } }; - this.unshift = function(cell) { + unshift(cell) { if (Array.isArray(cell)) { this.cells.unshift.apply(this.cells, cell); var fragment = dom.createFragment(this.element); @@ -83,14 +82,14 @@ var Lines = function(element, canvasHeight) { } }; - this.last = function() { + last() { if (this.cells.length) return this.cells[this.cells.length-1]; else return null; }; - this.$cacheCell = function(cell) { + $cacheCell(cell) { if (!cell) return; @@ -98,7 +97,7 @@ var Lines = function(element, canvasHeight) { this.cellCache.push(cell); }; - this.createCell = function(row, config, session, initElement) { + createCell(row, config, session, initElement) { var cell = this.cellCache.pop(); if (!cell) { var element = dom.createElement("div"); @@ -118,6 +117,6 @@ var Lines = function(element, canvasHeight) { return cell; }; -}).call(Lines.prototype); +} exports.Lines = Lines; diff --git a/src/layer/marker.js b/src/layer/marker.js index d7b99848a36..50ca4495b82 100644 --- a/src/layer/marker.js +++ b/src/layer/marker.js @@ -3,28 +3,28 @@ var Range = require("../range").Range; var dom = require("../lib/dom"); -var Marker = function(parentEl) { - this.element = dom.createElement("div"); - this.element.className = "ace_layer ace_marker-layer"; - parentEl.appendChild(this.element); -}; -(function() { +class Marker { + constructor(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_marker-layer"; + parentEl.appendChild(this.element); + }; - this.$padding = 0; + $padding = 0; - this.setPadding = function(padding) { + setPadding(padding) { this.$padding = padding; }; - this.setSession = function(session) { + setSession(session) { this.session = session; }; - this.setMarkers = function(markers) { + setMarkers(markers) { this.markers = markers; }; - this.elt = function(className, css) { + elt(className, css) { var x = this.i != -1 && this.element.childNodes[this.i]; if (!x) { x = document.createElement("div"); @@ -37,7 +37,7 @@ var Marker = function(parentEl) { x.className = className; }; - this.update = function(config) { + update(config) { if (!config) return; this.config = config; @@ -79,15 +79,13 @@ var Marker = function(parentEl) { } }; - this.$getTop = function(row, layerConfig) { + $getTop(row, layerConfig) { return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight; }; - function getBorderClass(tl, tr, br, bl) { - return (tl ? 1 : 0) | (tr ? 2 : 0) | (br ? 4 : 0) | (bl ? 8 : 0); - } + // Draws a marker, which spans a range of text on multiple lines - this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) { + drawTextMarker(stringBuilder, range, clazz, layerConfig, extraStyle) { var session = this.session; var start = range.start.row; var end = range.end.row; @@ -111,7 +109,7 @@ var Marker = function(parentEl) { }; // Draws a multi line marker, where lines span the full width - this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { + drawMultiLineMarker(stringBuilder, range, clazz, config, extraStyle) { // from selection start to the end of the line var padding = this.$padding; var height = config.lineHeight; @@ -166,7 +164,7 @@ var Marker = function(parentEl) { }; // Draws a marker which covers part or whole width of a single screen line - this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) { + drawSingleLineMarker(stringBuilder, range, clazz, config, extraLength, extraStyle) { if (this.session.$bidiHandler.isBidiRow(range.start.row)) return this.drawBidiSingleLineMarker(stringBuilder, range, clazz, config, extraLength, extraStyle); var height = config.lineHeight; @@ -185,7 +183,7 @@ var Marker = function(parentEl) { }; // Draws Bidi marker which covers part or whole width of a single screen line - this.drawBidiSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) { + drawBidiSingleLineMarker(stringBuilder, range, clazz, config, extraLength, extraStyle) { var height = config.lineHeight, top = this.$getTop(range.start.row, config), padding = this.$padding; var selections = this.session.$bidiHandler.getSelections(range.start.column, range.end.column); @@ -200,7 +198,7 @@ var Marker = function(parentEl) { }, this); }; - this.drawFullLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { + drawFullLineMarker(stringBuilder, range, clazz, config, extraStyle) { var top = this.$getTop(range.start.row, config); var height = config.lineHeight; if (range.start.row != range.end.row) @@ -214,7 +212,7 @@ var Marker = function(parentEl) { ); }; - this.drawScreenLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { + drawScreenLineMarker(stringBuilder, range, clazz, config, extraStyle) { var top = this.$getTop(range.start.row, config); var height = config.lineHeight; @@ -226,6 +224,10 @@ var Marker = function(parentEl) { ); }; -}).call(Marker.prototype); +} + +function getBorderClass(tl, tr, br, bl) { + return (tl ? 1 : 0) | (tr ? 2 : 0) | (br ? 4 : 0) | (bl ? 8 : 0); +} exports.Marker = Marker; diff --git a/src/layer/text.js b/src/layer/text.js index aa3be47f9cf..0b204ef813b 100644 --- a/src/layer/text.js +++ b/src/layer/text.js @@ -6,29 +6,27 @@ var lang = require("../lib/lang"); var Lines = require("./lines").Lines; var EventEmitter = require("../lib/event_emitter").EventEmitter; -var Text = function(parentEl) { - this.dom = dom; - this.element = this.dom.createElement("div"); - this.element.className = "ace_layer ace_text-layer"; - parentEl.appendChild(this.element); - this.$updateEolChar = this.$updateEolChar.bind(this); - this.$lines = new Lines(this.element); -}; - -(function() { - - oop.implement(this, EventEmitter); - - this.EOF_CHAR = "\xB6"; - this.EOL_CHAR_LF = "\xAC"; - this.EOL_CHAR_CRLF = "\xa4"; - this.EOL_CHAR = this.EOL_CHAR_LF; - this.TAB_CHAR = "\u2014"; //"\u21E5"; - this.SPACE_CHAR = "\xB7"; - this.$padding = 0; - this.MAX_LINE_LENGTH = 10000; - - this.$updateEolChar = function() { + +class Text { + constructor(parentEl) { + this.dom = dom; + this.element = this.dom.createElement("div"); + this.element.className = "ace_layer ace_text-layer"; + parentEl.appendChild(this.element); + this.$updateEolChar = this.$updateEolChar.bind(this); + this.$lines = new Lines(this.element); + }; + + EOF_CHAR = "\xB6"; + EOL_CHAR_LF = "\xAC"; + EOL_CHAR_CRLF = "\xa4"; + EOL_CHAR = this.EOL_CHAR_LF; + TAB_CHAR = "\u2014"; //"\u21E5"; + SPACE_CHAR = "\xB7"; + $padding = 0; + MAX_LINE_LENGTH = 10000; + + $updateEolChar() { var doc = this.session.doc; var unixMode = doc.getNewLineCharacter() == "\n" && doc.getNewLineMode() != "windows"; var EOL_CHAR = unixMode ? this.EOL_CHAR_LF : this.EOL_CHAR_CRLF; @@ -38,20 +36,20 @@ var Text = function(parentEl) { } }; - this.setPadding = function(padding) { + setPadding(padding) { this.$padding = padding; this.element.style.margin = "0 " + padding + "px"; }; - this.getLineHeight = function() { + getLineHeight() { return this.$fontMetrics.$characterSize.height || 0; }; - this.getCharacterWidth = function() { + getCharacterWidth() { return this.$fontMetrics.$characterSize.width || 0; }; - this.$setFontMetrics = function(measure) { + $setFontMetrics(measure) { this.$fontMetrics = measure; this.$fontMetrics.on("changeCharacterSize", function(e) { this._signal("changeCharacterSize", e); @@ -59,23 +57,23 @@ var Text = function(parentEl) { this.$pollSizeChanges(); }; - this.checkForSizeChanges = function() { + checkForSizeChanges() { this.$fontMetrics.checkForSizeChanges(); }; - this.$pollSizeChanges = function() { + $pollSizeChanges() { return this.$pollSizeChangesTimer = this.$fontMetrics.$pollSizeChanges(); }; - this.setSession = function(session) { + setSession(session) { this.session = session; if (session) this.$computeTabString(); }; - this.showInvisibles = false; - this.showSpaces = false; - this.showTabs = false; - this.showEOL = false; - this.setShowInvisibles = function(showInvisibles) { + showInvisibles = false; + showSpaces = false; + showTabs = false; + showEOL = false; + setShowInvisibles(showInvisibles) { if (this.showInvisibles == showInvisibles) return false; @@ -91,8 +89,8 @@ var Text = function(parentEl) { return true; }; - this.displayIndentGuides = true; - this.setDisplayIndentGuides = function(display) { + displayIndentGuides = true; + setDisplayIndentGuides(display) { if (this.displayIndentGuides == display) return false; @@ -101,17 +99,18 @@ var Text = function(parentEl) { return true; }; - this.$highlightIndentGuides = true; - this.setHighlightIndentGuides = function (highlight) { + $highlightIndentGuides = true; + setHighlightIndentGuides(highlight) { if (this.$highlightIndentGuides === highlight) return false; this.$highlightIndentGuides = highlight; return highlight; }; - this.$tabStrings = []; - this.onChangeTabSize = - this.$computeTabString = function() { + $tabStrings = []; + + + $computeTabString() { var tabSize = this.session.getTabSize(); this.tabSize = tabSize; var tabStr = this.$tabStrings = [0]; @@ -149,8 +148,9 @@ var Text = function(parentEl) { this.$tabStrings["\t"] = span; } }; + onChangeTabSize = this.$computeTabString; - this.updateLines = function(config, firstRow, lastRow) { + updateLines(config, firstRow, lastRow) { // Due to wrap line changes there can be new lines if e.g. // the line to updated wrapped in the meantime. if (this.config.lastRow != config.lastRow || @@ -219,7 +219,7 @@ var Text = function(parentEl) { } }; - this.scrollLines = function(config) { + scrollLines(config) { var oldConfig = this.config; this.config = config; @@ -261,7 +261,7 @@ var Text = function(parentEl) { this.$highlightIndentGuide(); }; - this.$renderLinesFragment = function(config, firstRow, lastRow) { + $renderLinesFragment(config, firstRow, lastRow) { var fragment = []; var row = firstRow; var foldLine = this.session.getNextFoldLine(row); @@ -299,7 +299,7 @@ var Text = function(parentEl) { return fragment; }; - this.update = function(config) { + update(config) { this.$lines.moveContainer(config); this.config = config; @@ -314,13 +314,13 @@ var Text = function(parentEl) { lines.push(this.$renderLinesFragment(config, firstRow, lastRow)); }; - this.$textToken = { + $textToken = { "text": true, "rparen": true, "lparen": true }; - this.$renderToken = function(parent, screenColumn, token, value) { + $renderToken(parent, screenColumn, token, value) { var self = this; var re = /(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC\u2066\u2067\u2068\u202A\u202B\u202D\u202E\u202C\u2069]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g; @@ -403,7 +403,7 @@ var Text = function(parentEl) { return screenColumn + value.length; }; - this.renderIndentGuide = function(parent, value, max) { + renderIndentGuide(parent, value, max) { var cols = value.search(this.$indentGuideRe); if (cols <= 0 || cols >= max) return value; @@ -426,7 +426,7 @@ var Text = function(parentEl) { return value; }; - this.$highlightIndentGuide = function () { + $highlightIndentGuide() { if (!this.$highlightIndentGuides || !this.displayIndentGuides) return; this.$highlightIndentGuideMarker = { @@ -480,7 +480,7 @@ var Text = function(parentEl) { this.$renderHighlightIndentGuide(); }; - this.$clearActiveIndentGuide = function () { + $clearActiveIndentGuide() { var cells = this.$lines.cells; for (var i = 0; i < cells.length; i++) { var cell = cells[i]; @@ -496,7 +496,7 @@ var Text = function(parentEl) { } }; - this.$setIndentGuideActive = function (cell, indentLevel) { + $setIndentGuideActive(cell, indentLevel) { var line = this.session.doc.getLine(cell.row); if (line !== "") { var childNodes = cell.element.childNodes; @@ -508,7 +508,7 @@ var Text = function(parentEl) { } }; - this.$renderHighlightIndentGuide = function () { + $renderHighlightIndentGuide() { if (!this.$lines) return; var cells = this.$lines.cells; this.$clearActiveIndentGuide(); @@ -536,7 +536,7 @@ var Text = function(parentEl) { } }; - this.$createLineElement = function(parent) { + $createLineElement(parent) { var lineEl = this.dom.createElement("div"); lineEl.className = "ace_line"; lineEl.style.height = this.config.lineHeight + "px"; @@ -544,7 +544,7 @@ var Text = function(parentEl) { return lineEl; }; - this.$renderWrappedLine = function(parent, tokens, splits) { + $renderWrappedLine(parent, tokens, splits) { var chars = 0; var split = 0; var splitChars = splits[0]; @@ -598,7 +598,7 @@ var Text = function(parentEl) { this.$renderOverflowMessage(lineEl, screenColumn, null, "", true); }; - this.$renderSimpleLine = function(parent, tokens) { + $renderSimpleLine(parent, tokens) { var screenColumn = 0; for (var i = 0; i < tokens.length; i++) { @@ -615,7 +615,7 @@ var Text = function(parentEl) { } }; - this.$renderOverflowMessage = function(parent, screenColumn, token, value, hide) { + $renderOverflowMessage(parent, screenColumn, token, value, hide) { token && this.$renderToken(parent, screenColumn, token, value.slice(0, this.MAX_LINE_LENGTH - screenColumn)); @@ -627,7 +627,7 @@ var Text = function(parentEl) { }; // row is either first row of foldline or not in fold - this.$renderLine = function(parent, row, foldLine) { + $renderLine(parent, row, foldLine) { if (!foldLine && foldLine != false) foldLine = this.session.getFoldLine(row); @@ -667,7 +667,7 @@ var Text = function(parentEl) { } }; - this.$getFoldLineTokens = function(row, foldLine) { + $getFoldLineTokens(row, foldLine) { var session = this.session; var renderTokens = []; @@ -728,7 +728,7 @@ var Text = function(parentEl) { return renderTokens; }; - this.$useLineGroups = function() { + $useLineGroups() { // For the updateLines function to work correctly, it's important that the // child nodes of this.element correspond on a 1-to-1 basis to rows in the // document (as distinct from lines on the screen). For sessions that are @@ -737,7 +737,9 @@ var Text = function(parentEl) { return this.session.getUseWrapMode(); }; - this.destroy = function() {}; -}).call(Text.prototype); + destroy = {}; +} + +oop.implement(Text.prototype, EventEmitter); exports.Text = Text; diff --git a/src/lib/app_config.js b/src/lib/app_config.js index 3b1973d7659..d29a4d66d03 100644 --- a/src/lib/app_config.js +++ b/src/lib/app_config.js @@ -64,17 +64,15 @@ function reportError(msg, data) { setTimeout(function() { throw e; }); } -var AppConfig = function() { - this.$defaultOptions = {}; -}; - -(function() { - // module loading - oop.implement(this, EventEmitter); +class AppConfig { + constructor() { + this.$defaultOptions = {}; + }; + /* * option {name, value, initialValue, setterName, set, get } */ - this.defineOptions = function(obj, path, options) { + defineOptions(obj, path, options) { if (!obj.$options) this.$defaultOptions[path] = obj.$options = {}; @@ -95,7 +93,7 @@ var AppConfig = function() { return this; }; - this.resetOptions = function(obj) { + resetOptions(obj) { Object.keys(obj.$options).forEach(function(key) { var opt = obj.$options[key]; if ("value" in opt) @@ -103,7 +101,7 @@ var AppConfig = function() { }); }; - this.setDefaultValue = function(path, name, value) { + setDefaultValue(path, name, value) { if (!path) { for (path in this.$defaultOptions) if (this.$defaultOptions[path][name]) @@ -120,15 +118,17 @@ var AppConfig = function() { } }; - this.setDefaultValues = function(path, optionHash) { + setDefaultValues(path, optionHash) { Object.keys(optionHash).forEach(function(key) { this.setDefaultValue(path, key, optionHash[key]); }, this); }; - this.warn = warn; - this.reportError = reportError; - -}).call(AppConfig.prototype); + warn = warn; + reportError = reportError; +} + +// module loading +oop.implement(AppConfig.prototype, EventEmitter); exports.AppConfig = AppConfig; diff --git a/src/line_widgets.js b/src/line_widgets.js index f512d9ec13e..d6d9a88a5e2 100644 --- a/src/line_widgets.js +++ b/src/line_widgets.js @@ -2,24 +2,26 @@ var dom = require("./lib/dom"); -function LineWidgets(session) { - this.session = session; - this.session.widgetManager = this; - this.session.getRowLength = this.getRowLength; - this.session.$getWidgetScreenLength = this.$getWidgetScreenLength; - this.updateOnChange = this.updateOnChange.bind(this); - this.renderWidgets = this.renderWidgets.bind(this); - this.measureWidgets = this.measureWidgets.bind(this); - this.session._changedWidgets = []; - this.$onChangeEditor = this.$onChangeEditor.bind(this); - - this.session.on("change", this.updateOnChange); - this.session.on("changeFold", this.updateOnFold); - this.session.on("changeEditor", this.$onChangeEditor); -} -(function() { - this.getRowLength = function(row) { + +class LineWidgets { + constructor(session) { + this.session = session; + this.session.widgetManager = this; + this.session.getRowLength = this.getRowLength; + this.session.$getWidgetScreenLength = this.$getWidgetScreenLength; + this.updateOnChange = this.updateOnChange.bind(this); + this.renderWidgets = this.renderWidgets.bind(this); + this.measureWidgets = this.measureWidgets.bind(this); + this.session._changedWidgets = []; + this.$onChangeEditor = this.$onChangeEditor.bind(this); + + this.session.on("change", this.updateOnChange); + this.session.on("changeFold", this.updateOnFold); + this.session.on("changeEditor", this.$onChangeEditor); + } + + getRowLength(row) { var h; if (this.lineWidgets) h = this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0; @@ -32,7 +34,7 @@ function LineWidgets(session) { } }; - this.$getWidgetScreenLength = function() { + $getWidgetScreenLength() { var screenRows = 0; this.lineWidgets.forEach(function(w){ if (w && w.rowCount && !w.hidden) @@ -41,11 +43,11 @@ function LineWidgets(session) { return screenRows; }; - this.$onChangeEditor = function(e) { + $onChangeEditor(e) { this.attach(e.editor); }; - this.attach = function(editor) { + attach(editor) { if (editor && editor.widgetManager && editor.widgetManager != this) editor.widgetManager.detach(); @@ -61,7 +63,7 @@ function LineWidgets(session) { editor.renderer.on("afterRender", this.renderWidgets); } }; - this.detach = function(e) { + detach(e) { var editor = this.editor; if (!editor) return; @@ -80,7 +82,7 @@ function LineWidgets(session) { }); }; - this.updateOnFold = function(e, session) { + updateOnFold(e, session) { var lineWidgets = session.lineWidgets; if (!lineWidgets || !e.action) return; @@ -106,7 +108,7 @@ function LineWidgets(session) { } }; - this.updateOnChange = function(delta) { + updateOnChange(delta) { var lineWidgets = this.session.lineWidgets; if (!lineWidgets) return; @@ -136,7 +138,7 @@ function LineWidgets(session) { } }; - this.$updateRows = function() { + $updateRows() { var lineWidgets = this.session.lineWidgets; if (!lineWidgets) return; var noWidgets = true; @@ -154,7 +156,7 @@ function LineWidgets(session) { this.session.lineWidgets = null; }; - this.$registerLineWidget = function(w) { + $registerLineWidget(w) { if (!this.session.lineWidgets) this.session.lineWidgets = new Array(this.session.getLength()); @@ -171,7 +173,7 @@ function LineWidgets(session) { return w; }; - this.addLineWidget = function(w) { + addLineWidget(w) { this.$registerLineWidget(w); w.session = this.session; @@ -225,7 +227,7 @@ function LineWidgets(session) { return w; }; - this.removeLineWidget = function(w) { + removeLineWidget(w) { w._inDocument = false; w.session = null; if (w.el && w.el.parentNode) @@ -253,7 +255,7 @@ function LineWidgets(session) { this.$updateRows(); }; - this.getWidgetsAtRow = function(row) { + getWidgetsAtRow(row) { var lineWidgets = this.session.lineWidgets; var w = lineWidgets && lineWidgets[row]; var list = []; @@ -264,12 +266,12 @@ function LineWidgets(session) { return list; }; - this.onWidgetChanged = function(w) { + onWidgetChanged(w) { this.session._changedWidgets.push(w); this.editor && this.editor.renderer.updateFull(); }; - this.measureWidgets = function(e, renderer) { + measureWidgets(e, renderer) { var changedWidgets = this.session._changedWidgets; var config = renderer.layerConfig; @@ -312,7 +314,7 @@ function LineWidgets(session) { this.session._changedWidgets = []; }; - this.renderWidgets = function(e, renderer) { + renderWidgets(e, renderer) { var config = renderer.layerConfig; var lineWidgets = this.session.lineWidgets; if (!lineWidgets) @@ -360,7 +362,7 @@ function LineWidgets(session) { } }; -}).call(LineWidgets.prototype); +} exports.LineWidgets = LineWidgets; diff --git a/src/mouse/default_gutter_handler.js b/src/mouse/default_gutter_handler.js index e86811c005f..c85ea94c9b5 100644 --- a/src/mouse/default_gutter_handler.js +++ b/src/mouse/default_gutter_handler.js @@ -126,14 +126,8 @@ function GutterHandler(mouseHandler) { editor.on("changeSession", hideTooltip); } -function GutterTooltip(parentNode) { - Tooltip.call(this, parentNode); -} - -oop.inherits(GutterTooltip, Tooltip); - -(function(){ - this.setPosition = function(x, y) { +class GutterTooltip extends Tooltip { + setPosition(x, y) { var windowWidth = window.innerWidth || document.documentElement.clientWidth; var windowHeight = window.innerHeight || document.documentElement.clientHeight; var width = this.getWidth(); @@ -149,8 +143,6 @@ oop.inherits(GutterTooltip, Tooltip); Tooltip.prototype.setPosition.call(this, x, y); }; -}).call(GutterTooltip.prototype); - - +} exports.GutterHandler = GutterHandler; diff --git a/src/mouse/default_handlers.js b/src/mouse/default_handlers.js index e0c511b55dc..2daaa002aee 100644 --- a/src/mouse/default_handlers.js +++ b/src/mouse/default_handlers.js @@ -5,30 +5,29 @@ var useragent = require("../lib/useragent"); var DRAG_OFFSET = 0; // pixels var SCROLL_COOLDOWN_T = 550; // milliseconds -function DefaultHandlers(mouseHandler) { - mouseHandler.$clickSelection = null; +class DefaultHandlers { + constructor(mouseHandler) { + mouseHandler.$clickSelection = null; - var editor = mouseHandler.editor; - editor.setDefaultHandler("mousedown", this.onMouseDown.bind(mouseHandler)); - editor.setDefaultHandler("dblclick", this.onDoubleClick.bind(mouseHandler)); - editor.setDefaultHandler("tripleclick", this.onTripleClick.bind(mouseHandler)); - editor.setDefaultHandler("quadclick", this.onQuadClick.bind(mouseHandler)); - editor.setDefaultHandler("mousewheel", this.onMouseWheel.bind(mouseHandler)); + var editor = mouseHandler.editor; + editor.setDefaultHandler("mousedown", this.onMouseDown.bind(mouseHandler)); + editor.setDefaultHandler("dblclick", this.onDoubleClick.bind(mouseHandler)); + editor.setDefaultHandler("tripleclick", this.onTripleClick.bind(mouseHandler)); + editor.setDefaultHandler("quadclick", this.onQuadClick.bind(mouseHandler)); + editor.setDefaultHandler("mousewheel", this.onMouseWheel.bind(mouseHandler)); - var exports = ["select", "startSelect", "selectEnd", "selectAllEnd", "selectByWordsEnd", - "selectByLinesEnd", "dragWait", "dragWaitEnd", "focusWait"]; + var exports = ["select", "startSelect", "selectEnd", "selectAllEnd", "selectByWordsEnd", + "selectByLinesEnd", "dragWait", "dragWaitEnd", "focusWait"]; - exports.forEach(function(x) { - mouseHandler[x] = this[x]; - }, this); + exports.forEach(function(x) { + mouseHandler[x] = this[x]; + }, this); - mouseHandler.selectByLines = this.extendSelectionBy.bind(mouseHandler, "getLineRange"); - mouseHandler.selectByWords = this.extendSelectionBy.bind(mouseHandler, "getWordRange"); -} - -(function() { + mouseHandler.selectByLines = this.extendSelectionBy.bind(mouseHandler, "getLineRange"); + mouseHandler.selectByWords = this.extendSelectionBy.bind(mouseHandler, "getWordRange"); + } - this.onMouseDown = function(ev) { + onMouseDown(ev) { var inSelection = ev.inSelection(); var pos = ev.getDocumentPosition(); this.mousedownEvent = ev; @@ -68,7 +67,7 @@ function DefaultHandlers(mouseHandler) { return ev.preventDefault(); }; - this.startSelect = function(pos, waitForClickSelection) { + startSelect(pos, waitForClickSelection) { pos = pos || this.editor.renderer.screenToTextCoordinates(this.x, this.y); var editor = this.editor; if (!this.mousedownEvent) return; @@ -83,7 +82,7 @@ function DefaultHandlers(mouseHandler) { this.setState("select"); }; - this.select = function() { + select() { var anchor, editor = this.editor; var cursor = editor.renderer.screenToTextCoordinates(this.x, this.y); if (this.$clickSelection) { @@ -104,7 +103,7 @@ function DefaultHandlers(mouseHandler) { editor.renderer.scrollCursorIntoView(); }; - this.extendSelectionBy = function(unitName) { + extendSelectionBy(unitName) { var anchor, editor = this.editor; var cursor = editor.renderer.screenToTextCoordinates(this.x, this.y); var range = editor.selection[unitName](cursor.row, cursor.column); @@ -133,16 +132,17 @@ function DefaultHandlers(mouseHandler) { editor.selection.selectToPosition(cursor); editor.renderer.scrollCursorIntoView(); }; - - this.selectEnd = - this.selectAllEnd = - this.selectByWordsEnd = - this.selectByLinesEnd = function() { + + selectByLinesEnd() { this.$clickSelection = null; this.editor.unsetStyle("ace_selecting"); }; - this.focusWait = function() { + selectEnd = this.selectByLinesEnd; + selectAllEnd = this.selectByLinesEnd; + selectByWordsEnd = this.selectByLinesEnd; + + focusWait() { var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y); var time = Date.now(); @@ -150,7 +150,7 @@ function DefaultHandlers(mouseHandler) { this.startSelect(this.mousedownEvent.getDocumentPosition()); }; - this.onDoubleClick = function(ev) { + onDoubleClick(ev) { var pos = ev.getDocumentPosition(); var editor = this.editor; var session = editor.session; @@ -170,7 +170,7 @@ function DefaultHandlers(mouseHandler) { this.select(); }; - this.onTripleClick = function(ev) { + onTripleClick(ev) { var pos = ev.getDocumentPosition(); var editor = this.editor; @@ -185,7 +185,7 @@ function DefaultHandlers(mouseHandler) { this.select(); }; - this.onQuadClick = function(ev) { + onQuadClick(ev) { var editor = this.editor; editor.selectAll(); @@ -193,7 +193,7 @@ function DefaultHandlers(mouseHandler) { this.setState("selectAll"); }; - this.onMouseWheel = function(ev) { + onMouseWheel(ev) { if (ev.getAccelKey()) return; @@ -253,7 +253,7 @@ function DefaultHandlers(mouseHandler) { } }; -}).call(DefaultHandlers.prototype); +} exports.DefaultHandlers = DefaultHandlers; diff --git a/src/mouse/fold_handler.js b/src/mouse/fold_handler.js index 05d1b49949b..9d16806baa4 100644 --- a/src/mouse/fold_handler.js +++ b/src/mouse/fold_handler.js @@ -1,69 +1,71 @@ "use strict"; var dom = require("../lib/dom"); -function FoldHandler(editor) { +class FoldHandler { + constructor(editor) { - editor.on("click", function(e) { - var position = e.getDocumentPosition(); - var session = editor.session; + editor.on("click", function(e) { + var position = e.getDocumentPosition(); + var session = editor.session; - // If the user clicked on a fold, then expand it. - var fold = session.getFoldAt(position.row, position.column, 1); - if (fold) { - if (e.getAccelKey()) - session.removeFold(fold); - else - session.expandFold(fold); + // If the user clicked on a fold, then expand it. + var fold = session.getFoldAt(position.row, position.column, 1); + if (fold) { + if (e.getAccelKey()) + session.removeFold(fold); + else + session.expandFold(fold); - e.stop(); - } - - var target = e.domEvent && e.domEvent.target; - if (target && dom.hasCssClass(target, "ace_inline_button")) { - if (dom.hasCssClass(target, "ace_toggle_wrap")) { - session.setOption("wrap", !session.getUseWrapMode()); - editor.renderer.scrollCursorIntoView(); + e.stop(); } - } - }); - editor.on("gutterclick", function(e) { - var gutterRegion = editor.renderer.$gutterLayer.getRegion(e); + var target = e.domEvent && e.domEvent.target; + if (target && dom.hasCssClass(target, "ace_inline_button")) { + if (dom.hasCssClass(target, "ace_toggle_wrap")) { + session.setOption("wrap", !session.getUseWrapMode()); + editor.renderer.scrollCursorIntoView(); + } + } + }); - if (gutterRegion == "foldWidgets") { - var row = e.getDocumentPosition().row; - var session = editor.session; - if (session.foldWidgets && session.foldWidgets[row]) - editor.session.onFoldWidgetClick(row, e); - if (!editor.isFocused()) - editor.focus(); - e.stop(); - } - }); + editor.on("gutterclick", function(e) { + var gutterRegion = editor.renderer.$gutterLayer.getRegion(e); - editor.on("gutterdblclick", function(e) { - var gutterRegion = editor.renderer.$gutterLayer.getRegion(e); + if (gutterRegion == "foldWidgets") { + var row = e.getDocumentPosition().row; + var session = editor.session; + if (session.foldWidgets && session.foldWidgets[row]) + editor.session.onFoldWidgetClick(row, e); + if (!editor.isFocused()) + editor.focus(); + e.stop(); + } + }); - if (gutterRegion == "foldWidgets") { - var row = e.getDocumentPosition().row; - var session = editor.session; - var data = session.getParentFoldRangeData(row, true); - var range = data.range || data.firstRange; + editor.on("gutterdblclick", function(e) { + var gutterRegion = editor.renderer.$gutterLayer.getRegion(e); - if (range) { - row = range.start.row; - var fold = session.getFoldAt(row, session.getLine(row).length, 1); + if (gutterRegion == "foldWidgets") { + var row = e.getDocumentPosition().row; + var session = editor.session; + var data = session.getParentFoldRangeData(row, true); + var range = data.range || data.firstRange; - if (fold) { - session.removeFold(fold); - } else { - session.addFold("...", range); - editor.renderer.scrollCursorIntoView({row: range.start.row, column: 0}); + if (range) { + row = range.start.row; + var fold = session.getFoldAt(row, session.getLine(row).length, 1); + + if (fold) { + session.removeFold(fold); + } else { + session.addFold("...", range); + editor.renderer.scrollCursorIntoView({row: range.start.row, column: 0}); + } } + e.stop(); } - e.stop(); - } - }); + }); + } } exports.FoldHandler = FoldHandler; diff --git a/src/mouse/mouse_event.js b/src/mouse/mouse_event.js index ae1e38a7770..2c6ddf668e3 100644 --- a/src/mouse/mouse_event.js +++ b/src/mouse/mouse_event.js @@ -6,43 +6,42 @@ var useragent = require("../lib/useragent"); /* * Custom Ace mouse event */ -var MouseEvent = exports.MouseEvent = function(domEvent, editor) { - this.domEvent = domEvent; - this.editor = editor; - - this.x = this.clientX = domEvent.clientX; - this.y = this.clientY = domEvent.clientY; +class MouseEvent { + constructor(domEvent, editor) { + this.domEvent = domEvent; + this.editor = editor; - this.$pos = null; - this.$inSelection = null; - - this.propagationStopped = false; - this.defaultPrevented = false; -}; + this.x = this.clientX = domEvent.clientX; + this.y = this.clientY = domEvent.clientY; + + this.$pos = null; + this.$inSelection = null; -(function() { + this.propagationStopped = false; + this.defaultPrevented = false; + }; - this.stopPropagation = function() { + stopPropagation() { event.stopPropagation(this.domEvent); this.propagationStopped = true; }; - this.preventDefault = function() { + preventDefault() { event.preventDefault(this.domEvent); this.defaultPrevented = true; }; - this.stop = function() { + stop() { this.stopPropagation(); this.preventDefault(); }; - /* + /** * Get the document position below the mouse cursor * * @return {Object} 'row' and 'column' of the document position */ - this.getDocumentPosition = function() { + getDocumentPosition() { if (this.$pos) return this.$pos; @@ -50,12 +49,12 @@ var MouseEvent = exports.MouseEvent = function(domEvent, editor) { return this.$pos; }; - /* + /** * Check if the mouse cursor is inside of the text selection * * @return {Boolean} whether the mouse cursor is inside of the selection */ - this.inSelection = function() { + inSelection() { if (this.$inSelection !== null) return this.$inSelection; @@ -73,24 +72,26 @@ var MouseEvent = exports.MouseEvent = function(domEvent, editor) { return this.$inSelection; }; - /* + /** * Get the clicked mouse button * * @return {Number} 0 for left button, 1 for middle button, 2 for right button */ - this.getButton = function() { + getButton() { return event.getButton(this.domEvent); }; - /* + /** * @return {Boolean} whether the shift key was pressed when the event was emitted */ - this.getShiftKey = function() { + getShiftKey() { return this.domEvent.shiftKey; }; - this.getAccelKey = useragent.isMac + getAccelKey = useragent.isMac ? function() { return this.domEvent.metaKey; } : function() { return this.domEvent.ctrlKey; }; -}).call(MouseEvent.prototype); +} + +exports.MouseEvent = MouseEvent; diff --git a/src/mouse/mouse_handler.js b/src/mouse/mouse_handler.js index e22e78b4976..9601007fd38 100644 --- a/src/mouse/mouse_handler.js +++ b/src/mouse/mouse_handler.js @@ -9,76 +9,76 @@ var DragdropHandler = require("./dragdrop_handler").DragdropHandler; var addTouchListeners = require("./touch_handler").addTouchListeners; var config = require("../config"); -var MouseHandler = function(editor) { - var _self = this; - this.editor = editor; - - new DefaultHandlers(this); - new DefaultGutterHandler(this); - new DragdropHandler(this); - - var focusEditor = function(e) { - // because we have to call event.preventDefault() any window on ie and iframes - // on other browsers do not get focus, so we have to call window.focus() here - var windowBlurred = !document.hasFocus || !document.hasFocus() - || !editor.isFocused() && document.activeElement == (editor.textInput && editor.textInput.getElement()); - if (windowBlurred) - window.focus(); - editor.focus(); - // Without this editor is blurred after double click - setTimeout(function () { - if (!editor.isFocused()) editor.focus(); - }); - }; +class MouseHandler { + constructor(editor) { + var _self = this; + this.editor = editor; + + new DefaultHandlers(this); + new DefaultGutterHandler(this); + new DragdropHandler(this); + + var focusEditor = function(e) { + // because we have to call event.preventDefault() any window on ie and iframes + // on other browsers do not get focus, so we have to call window.focus() here + var windowBlurred = !document.hasFocus || !document.hasFocus() + || !editor.isFocused() && document.activeElement == (editor.textInput && editor.textInput.getElement()); + if (windowBlurred) + window.focus(); + editor.focus(); + // Without this editor is blurred after double click + setTimeout(function () { + if (!editor.isFocused()) editor.focus(); + }); + }; - var mouseTarget = editor.renderer.getMouseEventTarget(); - event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click"), editor); - event.addListener(mouseTarget, "mousemove", this.onMouseMove.bind(this, "mousemove"), editor); - event.addMultiMouseDownListener([ - mouseTarget, - editor.renderer.scrollBarV && editor.renderer.scrollBarV.inner, - editor.renderer.scrollBarH && editor.renderer.scrollBarH.inner, - editor.textInput && editor.textInput.getElement() - ].filter(Boolean), [400, 300, 250], this, "onMouseEvent", editor); - event.addMouseWheelListener(editor.container, this.onMouseWheel.bind(this, "mousewheel"), editor); - addTouchListeners(editor.container, editor); - - var gutterEl = editor.renderer.$gutter; - event.addListener(gutterEl, "mousedown", this.onMouseEvent.bind(this, "guttermousedown"), editor); - event.addListener(gutterEl, "click", this.onMouseEvent.bind(this, "gutterclick"), editor); - event.addListener(gutterEl, "dblclick", this.onMouseEvent.bind(this, "gutterdblclick"), editor); - event.addListener(gutterEl, "mousemove", this.onMouseEvent.bind(this, "guttermousemove"), editor); - - event.addListener(mouseTarget, "mousedown", focusEditor, editor); - event.addListener(gutterEl, "mousedown", focusEditor, editor); - if (useragent.isIE && editor.renderer.scrollBarV) { - event.addListener(editor.renderer.scrollBarV.element, "mousedown", focusEditor, editor); - event.addListener(editor.renderer.scrollBarH.element, "mousedown", focusEditor, editor); - } - - editor.on("mousemove", function(e){ - if (_self.state || _self.$dragDelay || !_self.$dragEnabled) - return; + var mouseTarget = editor.renderer.getMouseEventTarget(); + event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click"), editor); + event.addListener(mouseTarget, "mousemove", this.onMouseMove.bind(this, "mousemove"), editor); + event.addMultiMouseDownListener([ + mouseTarget, + editor.renderer.scrollBarV && editor.renderer.scrollBarV.inner, + editor.renderer.scrollBarH && editor.renderer.scrollBarH.inner, + editor.textInput && editor.textInput.getElement() + ].filter(Boolean), [400, 300, 250], this, "onMouseEvent", editor); + event.addMouseWheelListener(editor.container, this.onMouseWheel.bind(this, "mousewheel"), editor); + addTouchListeners(editor.container, editor); + + var gutterEl = editor.renderer.$gutter; + event.addListener(gutterEl, "mousedown", this.onMouseEvent.bind(this, "guttermousedown"), editor); + event.addListener(gutterEl, "click", this.onMouseEvent.bind(this, "gutterclick"), editor); + event.addListener(gutterEl, "dblclick", this.onMouseEvent.bind(this, "gutterdblclick"), editor); + event.addListener(gutterEl, "mousemove", this.onMouseEvent.bind(this, "guttermousemove"), editor); + + event.addListener(mouseTarget, "mousedown", focusEditor, editor); + event.addListener(gutterEl, "mousedown", focusEditor, editor); + if (useragent.isIE && editor.renderer.scrollBarV) { + event.addListener(editor.renderer.scrollBarV.element, "mousedown", focusEditor, editor); + event.addListener(editor.renderer.scrollBarH.element, "mousedown", focusEditor, editor); + } - var character = editor.renderer.screenToTextCoordinates(e.x, e.y); - var range = editor.session.selection.getRange(); - var renderer = editor.renderer; + editor.on("mousemove", function(e){ + if (_self.state || _self.$dragDelay || !_self.$dragEnabled) + return; - if (!range.isEmpty() && range.insideStart(character.row, character.column)) { - renderer.setCursorStyle("default"); - } else { - renderer.setCursorStyle(""); - } - }, editor); -}; + var character = editor.renderer.screenToTextCoordinates(e.x, e.y); + var range = editor.session.selection.getRange(); + var renderer = editor.renderer; + + if (!range.isEmpty() && range.insideStart(character.row, character.column)) { + renderer.setCursorStyle("default"); + } else { + renderer.setCursorStyle(""); + } + }, editor); + }; -(function() { - this.onMouseEvent = function(name, e) { + onMouseEvent(name, e) { if (!this.editor.session) return; this.editor._emit(name, new MouseEvent(e, this.editor)); }; - this.onMouseMove = function(name, e) { + onMouseMove(name, e) { // optimization, because mousemove doesn't have a default handler. var listeners = this.editor._eventRegistry && this.editor._eventRegistry.mousemove; if (!listeners || !listeners.length) @@ -87,7 +87,7 @@ var MouseHandler = function(editor) { this.editor._emit(name, new MouseEvent(e, this.editor)); }; - this.onMouseWheel = function(name, e) { + onMouseWheel(name, e) { var mouseEvent = new MouseEvent(e, this.editor); mouseEvent.speed = this.$scrollSpeed * 2; mouseEvent.wheelX = e.wheelX; @@ -96,11 +96,11 @@ var MouseHandler = function(editor) { this.editor._emit(name, mouseEvent); }; - this.setState = function(state) { + setState(state) { this.state = state; }; - this.captureMouse = function(ev, mouseMoveHandler) { + captureMouse(ev, mouseMoveHandler) { this.x = ev.x; this.y = ev.y; @@ -167,8 +167,8 @@ var MouseHandler = function(editor) { self.releaseMouse = event.capture(this.editor.container, onMouseMove, onCaptureEnd); var timerId = setInterval(onCaptureInterval, 20); }; - this.releaseMouse = null; - this.cancelContextMenu = function() { + releaseMouse = null; + cancelContextMenu() { var stop = function(e) { if (e && e.domEvent && e.domEvent.type != "contextmenu") return; @@ -179,10 +179,10 @@ var MouseHandler = function(editor) { setTimeout(stop, 10); this.editor.on("nativecontextmenu", stop); }; - this.destroy = function() { + destroy() { if (this.releaseMouse) this.releaseMouse(); }; -}).call(MouseHandler.prototype); +} config.defineOptions(MouseHandler.prototype, "mouseHandler", { scrollSpeed: {initialValue: 2}, diff --git a/src/occur.js b/src/occur.js index 165ffe8be58..f17bca2ec23 100644 --- a/src/occur.js +++ b/src/occur.js @@ -14,18 +14,7 @@ var SearchHighlight = require("./search_highlight").SearchHighlight; * track of the mapping between the occur doc and the original doc. * **/ - - -/** - * Creates a new `Occur` object. - * - * @constructor - **/ -function Occur() {} - -oop.inherits(Occur, Search); - -(function() { +class Occur extends Search { /** * Enables occur mode. expects that `options.needle` is a search term. @@ -38,7 +27,7 @@ oop.inherits(Occur, Search); * @return {Boolean} Whether occur activation was successful * **/ - this.enter = function(editor, options) { + enter(editor, options) { if (!options.needle) return false; var pos = editor.getCursorPosition(); this.displayOccurContent(editor, options); @@ -56,7 +45,7 @@ oop.inherits(Occur, Search); * @return {Boolean} Whether occur deactivation was successful * **/ - this.exit = function(editor, options) { + exit(editor, options) { var pos = options.translatePosition && editor.getCursorPosition(); var translatedPos = pos && this.occurToOriginalPosition(editor.session, pos); this.displayOriginalContent(editor); @@ -65,14 +54,14 @@ oop.inherits(Occur, Search); return true; }; - this.highlight = function(sess, regexp) { + highlight(sess, regexp) { var hl = sess.$occurHighlight = sess.$occurHighlight || sess.addDynamicMarker( new SearchHighlight(null, "ace_occur-highlight", "text")); hl.setRegexp(regexp); sess._emit("changeBackMarker"); // force highlight layer redraw }; - this.displayOccurContent = function(editor, options) { + displayOccurContent(editor, options) { // this.setSession(session || new EditSession("")) this.$originalSession = editor.session; var found = this.matchingLines(editor.session, options); @@ -87,7 +76,7 @@ oop.inherits(Occur, Search); occurSession._emit('changeBackMarker'); }; - this.displayOriginalContent = function(editor) { + displayOriginalContent(editor) { editor.setSession(this.$originalSession); this.$originalSession.$useEmacsStyleLineStart = this.$useEmacsStyleLineStart; }; @@ -100,7 +89,7 @@ oop.inherits(Occur, Search); * @param {Object} pos The position in the original document * @return {Object} position in occur doc **/ - this.originalToOccurPosition = function(session, pos) { + originalToOccurPosition(session, pos) { var lines = session.$occurMatchingLines; var nullPos = {row: 0, column: 0}; if (!lines) return nullPos; @@ -118,14 +107,14 @@ oop.inherits(Occur, Search); * @param {Object} pos The position in the occur session document * @return {Object} position **/ - this.occurToOriginalPosition = function(session, pos) { + occurToOriginalPosition(session, pos) { var lines = session.$occurMatchingLines; if (!lines || !lines[pos.row]) return pos; return {row: lines[pos.row].row, column: pos.column}; }; - this.matchingLines = function(session, options) { + matchingLines(session, options) { options = oop.mixin({}, options); if (!session || !options.needle) return []; var search = new Search(); @@ -139,7 +128,7 @@ oop.inherits(Occur, Search); }, []); }; -}).call(Occur.prototype); +} var dom = require('./lib/dom'); dom.importCssString(".ace_occur-highlight {\n\ diff --git a/src/placeholder.js b/src/placeholder.js index 4b12469020c..024e999082b 100644 --- a/src/placeholder.js +++ b/src/placeholder.js @@ -4,51 +4,40 @@ var Range = require("./range").Range; var EventEmitter = require("./lib/event_emitter").EventEmitter; var oop = require("./lib/oop"); -/** - * @class PlaceHolder - * - **/ - -/** - * - session (Document): The document to associate with the anchor - * - length (Number): The starting row position - * - pos (Number): The starting column position - * - others (String): - * - mainClass (String): - * - othersClass (String): - * - * @constructor - **/ - -var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) { - var _self = this; - this.length = length; - this.session = session; - this.doc = session.getDocument(); - this.mainClass = mainClass; - this.othersClass = othersClass; - this.$onUpdate = this.onUpdate.bind(this); - this.doc.on("change", this.$onUpdate, true); - this.$others = others; - - this.$onCursorChange = function() { - setTimeout(function() { - _self.onCursorChange(); - }); - }; - - this.$pos = pos; - // Used for reset - var undoStack = session.getUndoManager().$undoStack || session.getUndoManager().$undostack || {length: -1}; - this.$undoStackDepth = undoStack.length; - this.setup(); +class PlaceHolder { + /** + * @param {Document} session The document to associate with the anchor + * @param {Number} length The starting row position + * @param {Number} pos The starting column position + * @param {String} others + * @param {String} mainClass + * @param {String} othersClass + **/ + constructor(session, length, pos, others, mainClass, othersClass) { + var _self = this; + this.length = length; + this.session = session; + this.doc = session.getDocument(); + this.mainClass = mainClass; + this.othersClass = othersClass; + this.$onUpdate = this.onUpdate.bind(this); + this.doc.on("change", this.$onUpdate, true); + this.$others = others; - session.selection.on("changeCursor", this.$onCursorChange); -}; + this.$onCursorChange = function() { + setTimeout(function() { + _self.onCursorChange(); + }); + }; -(function() { + this.$pos = pos; + // Used for reset + var undoStack = session.getUndoManager().$undoStack || session.getUndoManager().$undostack || {length: -1}; + this.$undoStackDepth = undoStack.length; + this.setup(); - oop.implement(this, EventEmitter); + session.selection.on("changeCursor", this.$onCursorChange); + }; /** * PlaceHolder.setup() @@ -56,7 +45,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) * TODO * **/ - this.setup = function() { + setup() { var _self = this; var doc = this.doc; var session = this.session; @@ -86,7 +75,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) * TODO * **/ - this.showOtherMarkers = function() { + showOtherMarkers() { if (this.othersActive) return; var session = this.session; var _self = this; @@ -102,7 +91,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) * Hides all over markers in the [[EditSession `EditSession`]] that are not the currently selected one. * **/ - this.hideOtherMarkers = function() { + hideOtherMarkers() { if (!this.othersActive) return; this.othersActive = false; for (var i = 0; i < this.others.length; i++) { @@ -116,7 +105,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) * Emitted when the place holder updates. * **/ - this.onUpdate = function(delta) { + onUpdate(delta) { if (this.$updating) return this.updateAnchors(delta); @@ -153,14 +142,14 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) this.updateMarkers(); }; - this.updateAnchors = function(delta) { + updateAnchors(delta) { this.pos.onChange(delta); for (var i = this.others.length; i--;) this.others[i].onChange(delta); this.updateMarkers(); }; - this.updateMarkers = function() { + updateMarkers() { if (this.$updating) return; var _self = this; @@ -181,7 +170,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) * **/ - this.onCursorChange = function(event) { + onCursorChange(event) { if (this.$updating || !this.session) return; var pos = this.session.selection.getCursor(); if (pos.row === this.pos.row && pos.column >= this.pos.column && pos.column <= this.pos.column + this.length) { @@ -199,7 +188,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) * TODO * **/ - this.detach = function() { + detach() { this.session.removeMarker(this.pos && this.pos.markerId); this.hideOtherMarkers(); this.doc.off("change", this.$onUpdate); @@ -214,7 +203,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) * TODO * **/ - this.cancel = function() { + cancel() { if (this.$undoStackDepth === -1) return; var undoManager = this.session.getUndoManager(); @@ -225,7 +214,8 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) if (this.selectionBefore) this.session.selection.fromJSON(this.selectionBefore); }; -}).call(PlaceHolder.prototype); +} +oop.implement(PlaceHolder.prototype, EventEmitter); exports.PlaceHolder = PlaceHolder; diff --git a/src/range.js b/src/range.js index 6875ae6644c..8420a0e1579 100644 --- a/src/range.js +++ b/src/range.js @@ -7,33 +7,33 @@ var comparePoints = function(p1, p2) { * @class Range **/ -/** - * Creates a new `Range` object with the given starting and ending rows and columns. - * @param {Number} startRow The starting row - * @param {Number} startColumn The starting column - * @param {Number} endRow The ending row - * @param {Number} endColumn The ending column - * @constructor - **/ -var Range = function(startRow, startColumn, endRow, endColumn) { - this.start = { - row: startRow, - column: startColumn - }; - - this.end = { - row: endRow, - column: endColumn +class Range { + /** + * Creates a new `Range` object with the given starting and ending rows and columns. + * @param {Number} startRow The starting row + * @param {Number} startColumn The starting column + * @param {Number} endRow The ending row + * @param {Number} endColumn The ending column + * @constructor + **/ + constructor(startRow, startColumn, endRow, endColumn) { + this.start = { + row: startRow, + column: startColumn + }; + + this.end = { + row: endRow, + column: endColumn + }; }; -}; - -(function() { + /** * Returns `true` if and only if the starting row and column, and ending row and column, are equivalent to those given by `range`. * @param {Range} range A range to check against * @return {Boolean} **/ - this.isEqual = function(range) { + isEqual(range) { return this.start.row === range.start.row && this.end.row === range.end.row && this.start.column === range.start.column && @@ -47,7 +47,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * ``` * @return {String} **/ - this.toString = function() { + toString() { return ("Range: [" + this.start.row + "/" + this.start.column + "] -> [" + this.end.row + "/" + this.end.column + "]"); }; @@ -64,7 +64,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @related [[Range.compare]] **/ - this.contains = function(row, column) { + contains(row, column) { return this.compare(row, column) == 0; }; @@ -80,7 +80,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * * `+2`: (B) is after (A) and doesn't intersect with (A) * * `42`: FTW state: (B) ends in (A) but starts outside of (A) **/ - this.compareRange = function(range) { + compareRange(range) { var cmp, end = range.end, start = range.start; @@ -115,7 +115,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @related [[Range.compare]] * @returns {Number} **/ - this.comparePoint = function(p) { + comparePoint(p) { return this.compare(p.row, p.column); }; @@ -125,7 +125,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @returns {Boolean} * @related [[Range.comparePoint]] **/ - this.containsRange = function(range) { + containsRange(range) { return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; }; @@ -134,7 +134,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @param {Range} range A range to compare with * @returns {Boolean} **/ - this.intersects = function(range) { + intersects(range) { var cmp = this.compareRange(range); return (cmp == -1 || cmp == 0 || cmp == 1); }; @@ -145,7 +145,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @param {Number} column A column to compare with * @returns {Boolean} **/ - this.isEnd = function(row, column) { + isEnd(row, column) { return this.end.row == row && this.end.column == column; }; @@ -155,7 +155,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @param {Number} column A column to compare with * @returns {Boolean} **/ - this.isStart = function(row, column) { + isStart(row, column) { return this.start.row == row && this.start.column == column; }; @@ -165,7 +165,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @param {Number} column A column to set * **/ - this.setStart = function(row, column) { + setStart(row, column) { if (typeof row == "object") { this.start.column = row.column; this.start.row = row.row; @@ -181,7 +181,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @param {Number} column A column to set * **/ - this.setEnd = function(row, column) { + setEnd(row, column) { if (typeof row == "object") { this.end.column = row.column; this.end.row = row.row; @@ -198,7 +198,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @returns {Boolean} * @related [[Range.compare]] **/ - this.inside = function(row, column) { + inside(row, column) { if (this.compare(row, column) == 0) { if (this.isEnd(row, column) || this.isStart(row, column)) { return false; @@ -216,7 +216,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @returns {Boolean} * @related [[Range.compare]] **/ - this.insideStart = function(row, column) { + insideStart(row, column) { if (this.compare(row, column) == 0) { if (this.isEnd(row, column)) { return false; @@ -235,7 +235,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @related [[Range.compare]] * **/ - this.insideEnd = function(row, column) { + insideEnd(row, column) { if (this.compare(row, column) == 0) { if (this.isStart(row, column)) { return false; @@ -263,7 +263,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * * `column` is less than or equal to the calling range's ending column, this returns `0` * * Otherwise, it returns 1 **/ - this.compare = function(row, column) { + compare(row, column) { if (!this.isMultiLine()) { if (row === this.start.row) { return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0); @@ -293,7 +293,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * * `-1` if calling range's starting column and calling range's starting row are equal `row` and `column` * * Otherwise, it returns the value after calling [[Range.compare `compare()`]]. **/ - this.compareStart = function(row, column) { + compareStart(row, column) { if (this.start.row == row && this.start.column == column) { return -1; } else { @@ -309,7 +309,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * * `1` if calling range's ending column and calling range's ending row are equal `row` and `column`. * * Otherwise, it returns the value after calling [[Range.compare `compare()`]]. */ - this.compareEnd = function(row, column) { + compareEnd(row, column) { if (this.end.row == row && this.end.column == column) { return 1; } else { @@ -326,7 +326,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * * `-1` if the starting row of the calling range is equal to `row`, and the starting column of the calling range is equal to `column` * * Otherwise, it returns the value after calling [[Range.compare `compare()`]]. **/ - this.compareInside = function(row, column) { + compareInside(row, column) { if (this.end.row == row && this.end.column == column) { return 1; } else if (this.start.row == row && this.start.column == column) { @@ -342,7 +342,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @param {Number} lastRow The ending row * @returns {Range} **/ - this.clipRows = function(firstRow, lastRow) { + clipRows(firstRow, lastRow) { if (this.end.row > lastRow) var end = {row: lastRow + 1, column: 0}; else if (this.end.row < firstRow) @@ -362,7 +362,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @param {Number} column A new column to extend to * @returns {Range} The original range with the new row **/ - this.extend = function(row, column) { + extend(row, column) { var cmp = this.compare(row, column); if (cmp == 0) @@ -379,7 +379,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * Returns `true` if the calling range is empty (starting [[Point]] == ending [[Point]]). * @returns {Boolean} **/ - this.isEmpty = function() { + isEmpty() { return (this.start.row === this.end.row && this.start.column === this.end.column); }; @@ -387,7 +387,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * Returns `true` if the range spans across multiple lines. * @returns {Boolean} **/ - this.isMultiLine = function() { + isMultiLine() { return (this.start.row !== this.end.row); }; @@ -395,7 +395,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * Returns a duplicate of the calling range. * @returns {Range} **/ - this.clone = function() { + clone() { return Range.fromPoints(this.start, this.end); }; @@ -403,7 +403,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * Returns a range containing the starting and ending rows of the original range, but with a column value of `0`. * @returns {Range} **/ - this.collapseRows = function() { + collapseRows() { if (this.end.column == 0) return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0); else @@ -415,7 +415,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @param {EditSession} session The `EditSession` to retrieve coordinates from * @returns {Range} **/ - this.toScreenRange = function(session) { + toScreenRange(session) { var screenPosStart = session.documentToScreenPosition(this.start); var screenPosEnd = session.documentToScreenPosition(this.end); @@ -431,14 +431,14 @@ var Range = function(startRow, startColumn, endRow, endColumn) { * @param {Number} column * @experimental */ - this.moveBy = function(row, column) { + moveBy(row, column) { this.start.row += row; this.start.column += column; this.end.row += row; this.end.column += column; }; -}).call(Range.prototype); +} /** * Creates and returns a new `Range` based on the `start` [[Point]] and `end` [[Point]] of the given parameters. @@ -461,5 +461,4 @@ Range.comparePoints = function(p1, p2) { return p1.row - p2.row || p1.column - p2.column; }; - exports.Range = Range; diff --git a/src/range_list.js b/src/range_list.js index c4438d2212d..f50e44cdebc 100644 --- a/src/range_list.js +++ b/src/range_list.js @@ -2,15 +2,16 @@ var Range = require("./range").Range; var comparePoints = Range.comparePoints; -var RangeList = function() { - this.ranges = []; - this.$bias = 1; -}; - -(function() { - this.comparePoints = comparePoints; +class RangeList { + + constructor() { + this.ranges = []; + this.$bias = 1; + } + + comparePoints = comparePoints; - this.pointIndex = function(pos, excludeEdges, startIndex) { + pointIndex(pos, excludeEdges, startIndex) { var list = this.ranges; for (var i = startIndex || 0; i < list.length; i++) { @@ -29,7 +30,7 @@ var RangeList = function() { return -i - 1; }; - this.add = function(range) { + add(range) { var excludeEdges = !range.isEmpty(); var startIndex = this.pointIndex(range.start, excludeEdges); if (startIndex < 0) @@ -44,7 +45,7 @@ var RangeList = function() { return this.ranges.splice(startIndex, endIndex - startIndex, range); }; - this.addList = function(list) { + addList(list) { var removed = []; for (var i = list.length; i--; ) { removed.push.apply(removed, this.add(list[i])); @@ -52,7 +53,7 @@ var RangeList = function() { return removed; }; - this.substractPoint = function(pos) { + substractPoint(pos) { var i = this.pointIndex(pos); if (i >= 0) @@ -60,7 +61,7 @@ var RangeList = function() { }; // merge overlapping ranges - this.merge = function() { + merge() { var removed = []; var list = this.ranges; @@ -95,22 +96,22 @@ var RangeList = function() { return removed; }; - this.contains = function(row, column) { + contains(row, column) { return this.pointIndex({row: row, column: column}) >= 0; }; - this.containsPoint = function(pos) { + containsPoint(pos) { return this.pointIndex(pos) >= 0; }; - this.rangeAtPoint = function(pos) { + rangeAtPoint(pos) { var i = this.pointIndex(pos); if (i >= 0) return this.ranges[i]; }; - this.clipRows = function(startRow, endRow) { + clipRows(startRow, endRow) { var list = this.ranges; if (list[0].start.row > endRow || list[list.length - 1].start.row < startRow) return []; @@ -129,11 +130,11 @@ var RangeList = function() { return clipped; }; - this.removeAll = function() { + removeAll() { return this.ranges.splice(0, this.ranges.length); }; - this.attach = function(session) { + attach(session) { if (this.session) this.detach(); @@ -143,14 +144,14 @@ var RangeList = function() { this.session.on('change', this.onChange); }; - this.detach = function() { + detach() { if (!this.session) return; this.session.removeListener('change', this.onChange); this.session = null; }; - this.$onChange = function(delta) { + $onChange(delta) { var start = delta.start; var end = delta.end; var startRow = start.row; @@ -261,6 +262,6 @@ var RangeList = function() { } }; -}).call(RangeList.prototype); +} exports.RangeList = RangeList; diff --git a/src/renderloop.js b/src/renderloop.js index ffa679e53fc..864b84cdf64 100644 --- a/src/renderloop.js +++ b/src/renderloop.js @@ -2,43 +2,39 @@ var event = require("./lib/event"); -/** - * - * +/** * Batches changes (that force something to be redrawn) in the background. - * @class RenderLoop **/ - - -var RenderLoop = function(onRender, win) { - this.onRender = onRender; - this.pending = false; - this.changes = 0; - this.$recursionLimit = 2; - this.window = win || window; - var _self = this; - this._flush = function(ts) { - _self.pending = false; - var changes = _self.changes; - - if (changes) { - event.blockIdle(100); - _self.changes = 0; - _self.onRender(changes); - } - - if (_self.changes) { - if (_self.$recursionLimit-- < 0) return; - _self.schedule(); - } else { - _self.$recursionLimit = 2; - } +class RenderLoop { + + constructor(onRender, win) { + this.onRender = onRender; + this.pending = false; + this.changes = 0; + this.$recursionLimit = 2; + this.window = win || window; + var _self = this; + this._flush = function (ts) { + _self.pending = false; + var changes = _self.changes; + + if (changes) { + event.blockIdle(100); + _self.changes = 0; + _self.onRender(changes); + } + + if (_self.changes) { + if (_self.$recursionLimit-- < 0) return; + _self.schedule(); + } + else { + _self.$recursionLimit = 2; + } + }; }; -}; -(function() { - - this.schedule = function(change) { + schedule(change) { this.changes = this.changes | change; if (this.changes && !this.pending) { event.nextFrame(this._flush); @@ -46,12 +42,12 @@ var RenderLoop = function(onRender, win) { } }; - this.clear = function(change) { + clear(change) { var changes = this.changes; this.changes = 0; return changes; }; - -}).call(RenderLoop.prototype); + +} exports.RenderLoop = RenderLoop; diff --git a/src/scrollbar.js b/src/scrollbar.js index ca7c4224a0d..feb3d2dbc9b 100644 --- a/src/scrollbar.js +++ b/src/scrollbar.js @@ -11,85 +11,73 @@ var MAX_SCROLL_H = 0x8000; /** * An abstract class representing a native scrollbar control. - * @class ScrollBar **/ +class Scrollbar { + /** + * Creates a new `ScrollBar`. `parent` is the owner of the scroll bar. + * @param {Element} parent A DOM element + * @param {string} classSuffix + **/ + constructor(parent, classSuffix) { + this.element = dom.createElement("div"); + this.element.className = "ace_scrollbar ace_scrollbar" + classSuffix; -/** - * Creates a new `ScrollBar`. `parent` is the owner of the scroll bar. - * @param {Element} parent A DOM element - * - * @constructor - **/ -var ScrollBar = function(parent) { - this.element = dom.createElement("div"); - this.element.className = "ace_scrollbar ace_scrollbar" + this.classSuffix; - - this.inner = dom.createElement("div"); - this.inner.className = "ace_scrollbar-inner"; - // on safari scrollbar is not shown for empty elements - this.inner.textContent = "\xa0"; - this.element.appendChild(this.inner); - - parent.appendChild(this.element); - - this.setVisible(false); - this.skipEvent = false; + this.inner = dom.createElement("div"); + this.inner.className = "ace_scrollbar-inner"; + // on safari scrollbar is not shown for empty elements + this.inner.textContent = "\xa0"; + this.element.appendChild(this.inner); - event.addListener(this.element, "scroll", this.onScroll.bind(this)); - event.addListener(this.element, "mousedown", event.preventDefault); -}; + parent.appendChild(this.element); -(function() { - oop.implement(this, EventEmitter); + this.setVisible(false); + this.skipEvent = false; - this.setVisible = function(isVisible) { + event.addListener(this.element, "scroll", this.onScroll.bind(this)); + event.addListener(this.element, "mousedown", event.preventDefault); + }; + + setVisible(isVisible) { this.element.style.display = isVisible ? "" : "none"; this.isVisible = isVisible; this.coeff = 1; }; -}).call(ScrollBar.prototype); +} +oop.implement(Scrollbar.prototype, EventEmitter); /** * Represents a vertical scroll bar. - * @class VScrollBar **/ - -/** - * Creates a new `VScrollBar`. `parent` is the owner of the scroll bar. - * @param {Element} parent A DOM element - * @param {Object} renderer An editor renderer - * - * @constructor - **/ -var VScrollBar = function(parent, renderer) { - ScrollBar.call(this, parent); - this.scrollTop = 0; - this.scrollHeight = 0; - - // in OSX lion the scrollbars appear to have no width. In this case resize the - // element to show the scrollbar but still pretend that the scrollbar has a width - // of 0px - // in Firefox 6+ scrollbar is hidden if element has the same width as scrollbar - // make element a little bit wider to retain scrollbar when page is zoomed - renderer.$scrollbarWidth = - this.width = dom.scrollbarWidth(parent.ownerDocument); - this.inner.style.width = - this.element.style.width = (this.width || 15) + 5 + "px"; - this.$minWidth = 0; -}; - -oop.inherits(VScrollBar, ScrollBar); - -(function() { - - this.classSuffix = '-v'; +class VScrollBar extends Scrollbar { + /** + * Creates a new `VScrollBar`. `parent` is the owner of the scroll bar. + * @param {Element} parent A DOM element + * @param {Object} renderer An editor renderer + **/ + constructor(parent, renderer) { + super(parent, '-v'); + this.scrollTop = 0; + this.scrollHeight = 0; + + // in OSX lion the scrollbars appear to have no width. In this case resize the + // element to show the scrollbar but still pretend that the scrollbar has a width + // of 0px + // in Firefox 6+ scrollbar is hidden if element has the same width as scrollbar + // make element a little bit wider to retain scrollbar when page is zoomed + renderer.$scrollbarWidth = + this.width = dom.scrollbarWidth(parent.ownerDocument); + this.inner.style.width = + this.element.style.width = (this.width || 15) + 5 + "px"; + this.$minWidth = 0; + }; + /** * Emitted when the scroll bar, well, scrolls. * @event scroll * @param {Object} e Contains one property, `"data"`, which indicates the current scroll top position **/ - this.onScroll = function() { + onScroll() { if (!this.skipEvent) { this.scrollTop = this.element.scrollTop; if (this.coeff != 1) { @@ -105,7 +93,7 @@ oop.inherits(VScrollBar, ScrollBar); * Returns the width of the scroll bar. * @returns {Number} **/ - this.getWidth = function() { + getWidth() { return Math.max(this.isVisible ? this.width : 0, this.$minWidth || 0); }; @@ -113,21 +101,15 @@ oop.inherits(VScrollBar, ScrollBar); * Sets the height of the scroll bar, in pixels. * @param {Number} height The new height **/ - this.setHeight = function(height) { + setHeight(height) { this.element.style.height = height + "px"; }; - - /** - * Sets the inner height of the scroll bar, in pixels. - * @param {Number} height The new inner height - * @deprecated Use setScrollHeight instead - **/ - this.setInnerHeight = + /** * Sets the scroll height of the scroll bar, in pixels. * @param {Number} height The new scroll height **/ - this.setScrollHeight = function(height) { + setScrollHeight(height) { this.scrollHeight = height; if (height > MAX_SCROLL_H) { this.coeff = MAX_SCROLL_H / height; @@ -137,12 +119,19 @@ oop.inherits(VScrollBar, ScrollBar); } this.inner.style.height = height + "px"; }; + + /** + * Sets the inner height of the scroll bar, in pixels. + * @param {Number} height The new inner height + * @deprecated Use setScrollHeight instead + **/ + setInnerHeight = this.setScrollHeight; /** * Sets the scroll top of the scroll bar. * @param {Number} scrollTop The new scroll top **/ - this.setScrollTop = function(scrollTop) { + setScrollTop(scrollTop) { // on chrome 17+ for small zoom levels after calling this function // this.element.scrollTop != scrollTop which makes page to scroll up. if (this.scrollTop != scrollTop) { @@ -152,46 +141,37 @@ oop.inherits(VScrollBar, ScrollBar); } }; -}).call(VScrollBar.prototype); +} /** * Represents a horisontal scroll bar. - * @class HScrollBar - **/ - -/** - * Creates a new `HScrollBar`. `parent` is the owner of the scroll bar. - * @param {Element} parent A DOM element - * @param {Object} renderer An editor renderer - * - * @constructor **/ -var HScrollBar = function(parent, renderer) { - ScrollBar.call(this, parent); - this.scrollLeft = 0; - - // in OSX lion the scrollbars appear to have no width. In this case resize the - // element to show the scrollbar but still pretend that the scrollbar has a width - // of 0px - // in Firefox 6+ scrollbar is hidden if element has the same width as scrollbar - // make element a little bit wider to retain scrollbar when page is zoomed - this.height = renderer.$scrollbarWidth; - this.inner.style.height = - this.element.style.height = (this.height || 15) + 5 + "px"; -}; - -oop.inherits(HScrollBar, ScrollBar); - -(function() { - - this.classSuffix = '-h'; - +class HScrollBar extends Scrollbar { + /** + * Creates a new `HScrollBar`. `parent` is the owner of the scroll bar. + * @param {Element} parent A DOM element + * @param {Object} renderer An editor renderer + **/ + constructor(parent, renderer) { + super(parent, '-h'); + this.scrollLeft = 0; + + // in OSX lion the scrollbars appear to have no width. In this case resize the + // element to show the scrollbar but still pretend that the scrollbar has a width + // of 0px + // in Firefox 6+ scrollbar is hidden if element has the same width as scrollbar + // make element a little bit wider to retain scrollbar when page is zoomed + this.height = renderer.$scrollbarWidth; + this.inner.style.height = + this.element.style.height = (this.height || 15) + 5 + "px"; + }; + /** * Emitted when the scroll bar, well, scrolls. * @event scroll * @param {Object} e Contains one property, `"data"`, which indicates the current scroll left position **/ - this.onScroll = function() { + onScroll() { if (!this.skipEvent) { this.scrollLeft = this.element.scrollLeft; this._emit("scroll", {data: this.scrollLeft}); @@ -203,7 +183,7 @@ oop.inherits(HScrollBar, ScrollBar); * Returns the height of the scroll bar. * @returns {Number} **/ - this.getHeight = function() { + getHeight() { return this.isVisible ? this.height : 0; }; @@ -211,7 +191,7 @@ oop.inherits(HScrollBar, ScrollBar); * Sets the width of the scroll bar, in pixels. * @param {Number} width The new width **/ - this.setWidth = function(width) { + setWidth(width) { this.element.style.width = width + "px"; }; @@ -220,7 +200,7 @@ oop.inherits(HScrollBar, ScrollBar); * @param {Number} width The new inner width * @deprecated Use setScrollWidth instead **/ - this.setInnerWidth = function(width) { + setInnerWidth(width) { this.inner.style.width = width + "px"; }; @@ -228,7 +208,7 @@ oop.inherits(HScrollBar, ScrollBar); * Sets the scroll width of the scroll bar, in pixels. * @param {Number} width The new scroll width **/ - this.setScrollWidth = function(width) { + setScrollWidth(width) { this.inner.style.width = width + "px"; }; @@ -236,7 +216,7 @@ oop.inherits(HScrollBar, ScrollBar); * Sets the scroll left of the scroll bar. * @param {Number} scrollLeft The new scroll left **/ - this.setScrollLeft = function(scrollLeft) { + setScrollLeft(scrollLeft) { // on chrome 17+ for small zoom levels after calling this function // this.element.scrollTop != scrollTop which makes page to scroll up. if (this.scrollLeft != scrollLeft) { @@ -245,7 +225,7 @@ oop.inherits(HScrollBar, ScrollBar); } }; -}).call(HScrollBar.prototype); +} exports.ScrollBar = VScrollBar; // backward compatibility diff --git a/src/scrollbar_custom.js b/src/scrollbar_custom.js index 77edf5c3ddd..cb51213aed9 100644 --- a/src/scrollbar_custom.js +++ b/src/scrollbar_custom.js @@ -47,44 +47,37 @@ dom.importCssString(`.ace_editor>.ace_sb-v div, .ace_editor>.ace_sb-h div{ /** * An abstract class representing a native scrollbar control. - * @class ScrollBar **/ +class ScrollBar { + /** + * Creates a new `ScrollBar`. `parent` is the owner of the scroll bar. + * @param {Element} parent A DOM element + * @param {string} classSuffix + **/ + constructor(parent, classSuffix) { + this.element = dom.createElement("div"); + this.element.className = "ace_sb" + classSuffix; + this.inner = dom.createElement("div"); + this.inner.className = ""; + this.element.appendChild(this.inner); + this.VScrollWidth = 12; + this.HScrollHeight = 12; + + parent.appendChild(this.element); + this.setVisible(false); + this.skipEvent = false; + + event.addMultiMouseDownListener(this.element, [500, 300, 300], this, "onMouseDown"); + }; -/** - * Creates a new `ScrollBar`. `parent` is the owner of the scroll bar. - * @param {Element} parent A DOM element - * - * @constructor - **/ - -var ScrollBar = function (parent) { - this.element = dom.createElement("div"); - this.element.className = "ace_sb" + this.classSuffix; - this.inner = dom.createElement("div"); - this.inner.className = ""; - this.element.appendChild(this.inner); - this.VScrollWidth = 12; - this.HScrollHeight = 12; - - parent.appendChild(this.element); - this.setVisible(false); - this.skipEvent = false; - - event.addMultiMouseDownListener(this.element, [500, 300, 300], this, "onMouseDown"); -}; - -(function () { - oop.implement(this, EventEmitter); - - this.setVisible = function (isVisible) { + setVisible(isVisible) { this.element.style.display = isVisible ? "" : "none"; this.isVisible = isVisible; this.coeff = 1; }; +} - -}).call(ScrollBar.prototype); - +oop.implement(ScrollBar.prototype, EventEmitter); /** * Represents a vertical scroll bar. * @class VScrollBar @@ -97,29 +90,23 @@ var ScrollBar = function (parent) { * * @constructor **/ - -var VScrollBar = function (parent, renderer) { - ScrollBar.call(this, parent); - this.scrollTop = 0; - this.scrollHeight = 0; - this.parent = parent; - this.width = this.VScrollWidth; - this.renderer = renderer; - this.inner.style.width = this.element.style.width = (this.width || 15) + "px"; - this.$minWidth = 0; -}; - -oop.inherits(VScrollBar, ScrollBar); - -(function () { - this.classSuffix = '-v'; - - oop.implement(this, EventEmitter); - +class VScrollBar extends ScrollBar { + + constructor(parent, renderer) { + super(parent, '-v'); + this.scrollTop = 0; + this.scrollHeight = 0; + this.parent = parent; + this.width = this.VScrollWidth; + this.renderer = renderer; + this.inner.style.width = this.element.style.width = (this.width || 15) + "px"; + this.$minWidth = 0; + }; + /** * Emitted when the scroll thumb dragged or scrollbar canvas clicked. **/ - this.onMouseDown = function (eType, e) { + onMouseDown(eType, e) { if (eType !== "mousedown") return; if (event.getButton(e) !== 0 || e.detail === 2) { @@ -156,7 +143,7 @@ oop.inherits(VScrollBar, ScrollBar); return event.preventDefault(e); }; - this.getHeight = function () { + getHeight() { return this.height; }; @@ -165,7 +152,7 @@ oop.inherits(VScrollBar, ScrollBar); * @param {Number}thumbTop * @returns {Number} **/ - this.scrollTopFromThumbTop = function (thumbTop) { + scrollTopFromThumbTop(thumbTop) { var scrollTop = thumbTop * (this.pageHeight - this.viewHeight) / (this.slideHeight - this.thumbHeight); scrollTop = scrollTop >> 0; if (scrollTop < 0) { @@ -181,7 +168,7 @@ oop.inherits(VScrollBar, ScrollBar); * Returns the width of the scroll bar. * @returns {Number} **/ - this.getWidth = function () { + getWidth() { return Math.max(this.isVisible ? this.width : 0, this.$minWidth || 0); }; @@ -189,7 +176,7 @@ oop.inherits(VScrollBar, ScrollBar); * Sets the height of the scroll bar, in pixels. * @param {Number} height The new height **/ - this.setHeight = function (height) { + setHeight(height) { this.height = Math.max(0, height); this.slideHeight = this.height; this.viewHeight = this.height; @@ -203,7 +190,7 @@ oop.inherits(VScrollBar, ScrollBar); * * @param {boolean} force Forcely update height **/ - this.setInnerHeight = this.setScrollHeight = function (height, force) { + setScrollHeight(height, force) { if (this.pageHeight === height && !force) return; this.pageHeight = height; this.thumbHeight = this.slideHeight * this.viewHeight / this.pageHeight; @@ -220,52 +207,43 @@ oop.inherits(VScrollBar, ScrollBar); } }; + setInnerHeight = this.setScrollHeight; + /** * Sets the scroll top of the scroll bar. * @param {Number} scrollTop The new scroll top **/ - this.setScrollTop = function (scrollTop) { + setScrollTop(scrollTop) { this.scrollTop = scrollTop; if (scrollTop < 0) scrollTop = 0; this.thumbTop = scrollTop * (this.slideHeight - this.thumbHeight) / (this.pageHeight - this.viewHeight); this.inner.style.top = this.thumbTop + "px"; }; +} -}).call(VScrollBar.prototype); /** * Represents a horizontal scroll bar. - * @class HScrollBar - **/ - -/** - * Creates a new `HScrollBar`. `parent` is the owner of the scroll bar. - * @param {Element} parent A DOM element - * @param {Object} renderer An editor renderer - * - * @constructor **/ -var HScrollBar = function (parent, renderer) { - ScrollBar.call(this, parent); - this.scrollLeft = 0; - this.scrollWidth = 0; - this.height = this.HScrollHeight; - this.inner.style.height = this.element.style.height = (this.height || 12) + "px"; - this.renderer = renderer; -}; - -oop.inherits(HScrollBar, ScrollBar); - -(function () { - - this.classSuffix = '-h'; - - oop.implement(this, EventEmitter); - +class HScrollBar extends ScrollBar { + /** + * Creates a new `HScrollBar`. `parent` is the owner of the scroll bar. + * @param {Element} parent A DOM element + * @param {Object} renderer An editor renderer + **/ + constructor(parent, renderer) { + super(parent, '-h'); + this.scrollLeft = 0; + this.scrollWidth = 0; + this.height = this.HScrollHeight; + this.inner.style.height = this.element.style.height = (this.height || 12) + "px"; + this.renderer = renderer; + }; + /** * Emitted when the scroll thumb dragged or scrollbar canvas clicked. **/ - this.onMouseDown = function (eType, e) { + onMouseDown(eType, e) { if (eType !== "mousedown") return; if (event.getButton(e) !== 0 || e.detail === 2) { @@ -308,7 +286,7 @@ oop.inherits(HScrollBar, ScrollBar); * Returns the height of the scroll bar. * @returns {Number} **/ - this.getHeight = function () { + getHeight() { return this.isVisible ? this.height : 0; }; @@ -317,7 +295,7 @@ oop.inherits(HScrollBar, ScrollBar); * @param {Number} thumbLeft * @returns {Number} **/ - this.scrollLeftFromThumbLeft = function (thumbLeft) { + scrollLeftFromThumbLeft(thumbLeft) { var scrollLeft = thumbLeft * (this.pageWidth - this.viewWidth) / (this.slideWidth - this.thumbWidth); scrollLeft = scrollLeft >> 0; if (scrollLeft < 0) { @@ -333,7 +311,7 @@ oop.inherits(HScrollBar, ScrollBar); * Sets the width of the scroll bar, in pixels. * @param {Number} width The new width **/ - this.setWidth = function (width) { + setWidth(width) { this.width = Math.max(0, width); this.element.style.width = this.width + "px"; this.slideWidth = this.width; @@ -347,7 +325,7 @@ oop.inherits(HScrollBar, ScrollBar); * @param {Number} width The new inner width * @param {boolean} force Forcely update width **/ - this.setInnerWidth = this.setScrollWidth = function (width, force) { + setScrollWidth(width, force) { if (this.pageWidth === width && !force) return; this.pageWidth = width; this.thumbWidth = this.slideWidth * this.viewWidth / this.pageWidth; @@ -363,18 +341,20 @@ oop.inherits(HScrollBar, ScrollBar); } }; + setInnerWidth = this.setScrollWidth; + /** * Sets the scroll left of the scroll bar. * @param {Number} scrollLeft The new scroll left **/ - this.setScrollLeft = function (scrollLeft) { + setScrollLeft(scrollLeft) { this.scrollLeft = scrollLeft; if (scrollLeft < 0) scrollLeft = 0; this.thumbLeft = scrollLeft * (this.slideWidth - this.thumbWidth) / (this.pageWidth - this.viewWidth); this.inner.style.left = (this.thumbLeft) + "px"; }; -}).call(HScrollBar.prototype); +} exports.ScrollBar = VScrollBar; // backward compatibility exports.ScrollBarV = VScrollBar; // backward compatibility diff --git a/src/search.js b/src/search.js index 366bc17368f..dc82cfa5223 100644 --- a/src/search.js +++ b/src/search.js @@ -5,35 +5,27 @@ var oop = require("./lib/oop"); var Range = require("./range").Range; /** - * @class Search - * * A class designed to handle all sorts of text searches within a [[Document `Document`]]. - * **/ - -/** - * - * - * Creates a new `Search` object. The following search options are available: - * - * - `needle`: The string or regular expression you're looking for - * - `backwards`: Whether to search backwards from where cursor currently is. Defaults to `false`. - * - `wrap`: Whether to wrap the search back to the beginning when it hits the end. Defaults to `false`. - * - `caseSensitive`: Whether the search ought to be case-sensitive. Defaults to `false`. - * - `wholeWord`: Whether the search matches only on whole words. Defaults to `false`. - * - `range`: The [[Range]] to search within. Set this to `null` for the whole document - * - `regExp`: Whether the search is a regular expression or not. Defaults to `false`. - * - `start`: The starting [[Range]] or cursor position to begin the search - * - `skipCurrent`: Whether or not to include the current line in the search. Default to `false`. - * - * @constructor - **/ - -var Search = function() { - this.$options = {}; -}; - -(function() { +class Search { + /** + * Creates a new `Search` object. The following search options are available: + * + * - `needle`: The string or regular expression you're looking for + * - `backwards`: Whether to search backwards from where cursor currently is. Defaults to `false`. + * - `wrap`: Whether to wrap the search back to the beginning when it hits the end. Defaults to `false`. + * - `caseSensitive`: Whether the search ought to be case-sensitive. Defaults to `false`. + * - `wholeWord`: Whether the search matches only on whole words. Defaults to `false`. + * - `range`: The [[Range]] to search within. Set this to `null` for the whole document + * - `regExp`: Whether the search is a regular expression or not. Defaults to `false`. + * - `start`: The starting [[Range]] or cursor position to begin the search + * - `skipCurrent`: Whether or not to include the current line in the search. Default to `false`. + * + **/ + constructor() { + this.$options = {}; + } + /** * Sets the search options via the `options` parameter. * @param {Object} options An object containing all the new search properties @@ -42,7 +34,7 @@ var Search = function() { * @returns {Search} * @chainable **/ - this.set = function(options) { + set(options) { oop.mixin(this.$options, options); return this; }; @@ -51,16 +43,16 @@ var Search = function() { * [Returns an object containing all the search options.]{: #Search.getOptions} * @returns {Object} **/ - this.getOptions = function() { + getOptions() { return lang.copyObject(this.$options); }; /** * Sets the search options via the `options` parameter. - * @param {Object} An object containing all the search propertie + * @param {Object} options object containing all the search propertie * @related Search.set **/ - this.setOptions = function(options) { + setOptions(options) { this.$options = options; }; /** @@ -70,7 +62,7 @@ var Search = function() { * * @returns {Range} **/ - this.find = function(session) { + find(session) { var options = this.$options; var iterator = this.$matchIterator(session, options); if (!iterator) @@ -99,7 +91,7 @@ var Search = function() { * * @returns {[Range]} **/ - this.findAll = function(session) { + findAll(session) { var options = this.$options; if (!options.needle) return []; @@ -178,7 +170,7 @@ var Search = function() { * * @returns {String} **/ - this.replace = function(input, replacement) { + replace(input, replacement) { var options = this.$options; var re = this.$assembleRegExp(options); @@ -208,7 +200,7 @@ var Search = function() { return replacement; }; - this.$assembleRegExp = function(options, $disableFakeMultiline) { + $assembleRegExp(options, $disableFakeMultiline) { if (options.needle instanceof RegExp) return options.re = options.needle; @@ -237,7 +229,7 @@ var Search = function() { return options.re = re; }; - this.$assembleMultilineRegExp = function(needle, modifier) { + $assembleMultilineRegExp(needle, modifier) { var parts = needle.replace(/\r\n|\r|\n/g, "$\n^").split("\n"); var re = []; for (var i = 0; i < parts.length; i++) try { @@ -248,7 +240,7 @@ var Search = function() { return re; }; - this.$matchIterator = function(session, options) { + $matchIterator(session, options) { var re = this.$assembleRegExp(options); if (!re) return false; @@ -362,7 +354,7 @@ var Search = function() { return {forEach: forEach}; }; -}).call(Search.prototype); +} function addWordBoundary(needle, options) { function wordBoundary(c) { diff --git a/src/search_highlight.js b/src/search_highlight.js index e952bae72f4..3258be72e86 100644 --- a/src/search_highlight.js +++ b/src/search_highlight.js @@ -4,24 +4,26 @@ var lang = require("./lib/lang"); var oop = require("./lib/oop"); var Range = require("./range").Range; -var SearchHighlight = function(regExp, clazz, type) { - this.setRegexp(regExp); - this.clazz = clazz; - this.type = type || "text"; -}; +var SearchHighlight = -(function() { +class SearchHighlight { + constructor(regExp, clazz, type = "text") { + this.setRegexp(regExp); + this.clazz = clazz; + this.type = type; + }; + // needed to prevent long lines from freezing the browser - this.MAX_RANGES = 500; + MAX_RANGES = 500; - this.setRegexp = function(regExp) { + setRegexp(regExp) { if (this.regExp+"" == regExp+"") return; this.regExp = regExp; this.cache = []; }; - this.update = function(html, markerLayer, session, config) { + update(html, markerLayer, session, config) { if (!this.regExp) return; var start = config.firstRow, end = config.lastRow; @@ -51,6 +53,6 @@ var SearchHighlight = function(regExp, clazz, type) { } }; -}).call(SearchHighlight.prototype); +}; exports.SearchHighlight = SearchHighlight; diff --git a/src/token_iterator.js b/src/token_iterator.js index da91fb66fc0..da54baf8afe 100644 --- a/src/token_iterator.js +++ b/src/token_iterator.js @@ -3,36 +3,29 @@ var Range = require("./range").Range; /** - * - * * This class provides an essay way to treat the document as a stream of tokens, and provides methods to iterate over these tokens. - * @class TokenIterator **/ +class TokenIterator { + /** + * Creates a new token iterator object. The inital token index is set to the provided row and column coordinates. + * @param {EditSession} session The session to associate with + * @param {Number} initialRow The row to start the tokenizing at + * @param {Number} initialColumn The column to start the tokenizing at + **/ + constructor(session, initialRow, initialColumn) { + this.$session = session; + this.$row = initialRow; + this.$rowTokens = session.getTokens(initialRow); -/** - * Creates a new token iterator object. The inital token index is set to the provided row and column coordinates. - * @param {EditSession} session The session to associate with - * @param {Number} initialRow The row to start the tokenizing at - * @param {Number} initialColumn The column to start the tokenizing at - * - * @constructor - **/ -var TokenIterator = function(session, initialRow, initialColumn) { - this.$session = session; - this.$row = initialRow; - this.$rowTokens = session.getTokens(initialRow); - - var token = session.getTokenAt(initialRow, initialColumn); - this.$tokenIndex = token ? token.index : -1; -}; - -(function() { - + var token = session.getTokenAt(initialRow, initialColumn); + this.$tokenIndex = token ? token.index : -1; + }; + /** * Moves iterator position to the start of previous token. * @returns {Token|null} **/ - this.stepBackward = function() { + stepBackward() { this.$tokenIndex -= 1; while (this.$tokenIndex < 0) { @@ -53,7 +46,7 @@ var TokenIterator = function(session, initialRow, initialColumn) { * Moves iterator position to the start of next token. * @returns {Token|null} **/ - this.stepForward = function() { + stepForward() { this.$tokenIndex += 1; var rowCount; while (this.$tokenIndex >= this.$rowTokens.length) { @@ -77,7 +70,7 @@ var TokenIterator = function(session, initialRow, initialColumn) { * Returns current token. * @returns {Token} **/ - this.getCurrentToken = function () { + getCurrentToken() { return this.$rowTokens[this.$tokenIndex]; }; @@ -86,7 +79,7 @@ var TokenIterator = function(session, initialRow, initialColumn) { * Returns the current row. * @returns {Number} **/ - this.getCurrentTokenRow = function () { + getCurrentTokenRow() { return this.$row; }; @@ -95,7 +88,7 @@ var TokenIterator = function(session, initialRow, initialColumn) { * Returns the current column. * @returns {Number} **/ - this.getCurrentTokenColumn = function() { + getCurrentTokenColumn() { var rowTokens = this.$rowTokens; var tokenIndex = this.$tokenIndex; @@ -117,7 +110,7 @@ var TokenIterator = function(session, initialRow, initialColumn) { * Return the current token position. * @returns {Position} */ - this.getCurrentTokenPosition = function() { + getCurrentTokenPosition() { return {row: this.$row, column: this.getCurrentTokenColumn()}; }; @@ -125,12 +118,12 @@ var TokenIterator = function(session, initialRow, initialColumn) { * Return the current token range. * @returns {Range} */ - this.getCurrentTokenRange = function() { + getCurrentTokenRange() { var token = this.$rowTokens[this.$tokenIndex]; var column = this.getCurrentTokenColumn(); return new Range(this.$row, column, this.$row, column + token.value.length); }; -}).call(TokenIterator.prototype); +} exports.TokenIterator = TokenIterator; diff --git a/src/tokenizer.js b/src/tokenizer.js index f6b1338e8ce..781dcd86f4c 100644 --- a/src/tokenizer.js +++ b/src/tokenizer.js @@ -5,110 +5,107 @@ var config = require("./config"); var MAX_TOKEN_COUNT = 2000; /** * This class takes a set of highlighting rules, and creates a tokenizer out of them. For more information, see [the wiki on extending highlighters](https://github.com/ajaxorg/ace/wiki/Creating-or-Extending-an-Edit-Mode#wiki-extendingTheHighlighter). - * @class Tokenizer **/ +class Tokenizer { + + /** + * Constructs a new tokenizer based on the given rules and flags. + * @param {Object} rules The highlighting rules + **/ + constructor(rules) { + this.states = rules; + + this.regExps = {}; + this.matchMappings = {}; + for (var key in this.states) { + var state = this.states[key]; + var ruleRegExps = []; + var matchTotal = 0; + var mapping = this.matchMappings[key] = {defaultToken: "text"}; + var flag = "g"; + + var splitterRurles = []; + for (var i = 0; i < state.length; i++) { + var rule = state[i]; + if (rule.defaultToken) + mapping.defaultToken = rule.defaultToken; + if (rule.caseInsensitive && flag.indexOf("i") === -1) + flag += "i"; + if (rule.unicode && flag.indexOf("u") === -1) + flag += "u"; + if (rule.regex == null) + continue; -/** - * Constructs a new tokenizer based on the given rules and flags. - * @param {Object} rules The highlighting rules - * - * @constructor - **/ -var Tokenizer = function(rules) { - this.states = rules; - - this.regExps = {}; - this.matchMappings = {}; - for (var key in this.states) { - var state = this.states[key]; - var ruleRegExps = []; - var matchTotal = 0; - var mapping = this.matchMappings[key] = {defaultToken: "text"}; - var flag = "g"; - - var splitterRurles = []; - for (var i = 0; i < state.length; i++) { - var rule = state[i]; - if (rule.defaultToken) - mapping.defaultToken = rule.defaultToken; - if (rule.caseInsensitive && flag.indexOf("i") === -1) - flag += "i"; - if (rule.unicode && flag.indexOf("u") === -1) - flag += "u"; - if (rule.regex == null) - continue; - - if (rule.regex instanceof RegExp) - rule.regex = rule.regex.toString().slice(1, -1); - - // Count number of matching groups. 2 extra groups from the full match - // And the catch-all on the end (used to force a match); - var adjustedregex = rule.regex; - var matchcount = new RegExp("(?:(" + adjustedregex + ")|(.))").exec("a").length - 2; - if (Array.isArray(rule.token)) { - if (rule.token.length == 1 || matchcount == 1) { - rule.token = rule.token[0]; - } else if (matchcount - 1 != rule.token.length) { - this.reportError("number of classes and regexp groups doesn't match", { - rule: rule, - groupCount: matchcount - 1 - }); - rule.token = rule.token[0]; - } else { - rule.tokenArray = rule.token; - rule.token = null; - rule.onMatch = this.$arrayTokens; + if (rule.regex instanceof RegExp) + rule.regex = rule.regex.toString().slice(1, -1); + + // Count number of matching groups. 2 extra groups from the full match + // And the catch-all on the end (used to force a match); + var adjustedregex = rule.regex; + var matchcount = new RegExp("(?:(" + adjustedregex + ")|(.))").exec("a").length - 2; + if (Array.isArray(rule.token)) { + if (rule.token.length == 1 || matchcount == 1) { + rule.token = rule.token[0]; + } else if (matchcount - 1 != rule.token.length) { + this.reportError("number of classes and regexp groups doesn't match", { + rule: rule, + groupCount: matchcount - 1 + }); + rule.token = rule.token[0]; + } else { + rule.tokenArray = rule.token; + rule.token = null; + rule.onMatch = this.$arrayTokens; + } + } else if (typeof rule.token == "function" && !rule.onMatch) { + if (matchcount > 1) + rule.onMatch = this.$applyToken; + else + rule.onMatch = rule.token; } - } else if (typeof rule.token == "function" && !rule.onMatch) { - if (matchcount > 1) - rule.onMatch = this.$applyToken; - else - rule.onMatch = rule.token; - } - if (matchcount > 1) { - if (/\\\d/.test(rule.regex)) { - // Replace any backreferences and offset appropriately. - adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function(match, digit) { - return "\\" + (parseInt(digit, 10) + matchTotal + 1); - }); - } else { - matchcount = 1; - adjustedregex = this.removeCapturingGroups(rule.regex); + if (matchcount > 1) { + if (/\\\d/.test(rule.regex)) { + // Replace any backreferences and offset appropriately. + adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function(match, digit) { + return "\\" + (parseInt(digit, 10) + matchTotal + 1); + }); + } else { + matchcount = 1; + adjustedregex = this.removeCapturingGroups(rule.regex); + } + if (!rule.splitRegex && typeof rule.token != "string") + splitterRurles.push(rule); // flag will be known only at the very end } - if (!rule.splitRegex && typeof rule.token != "string") - splitterRurles.push(rule); // flag will be known only at the very end - } - mapping[matchTotal] = i; - matchTotal += matchcount; + mapping[matchTotal] = i; + matchTotal += matchcount; - ruleRegExps.push(adjustedregex); + ruleRegExps.push(adjustedregex); - // makes property access faster - if (!rule.onMatch) - rule.onMatch = null; - } - - if (!ruleRegExps.length) { - mapping[0] = 0; - ruleRegExps.push("$"); - } - - splitterRurles.forEach(function(rule) { - rule.splitRegex = this.createSplitterRegexp(rule.regex, flag); - }, this); + // makes property access faster + if (!rule.onMatch) + rule.onMatch = null; + } + + if (!ruleRegExps.length) { + mapping[0] = 0; + ruleRegExps.push("$"); + } - this.regExps[key] = new RegExp("(" + ruleRegExps.join(")|(") + ")|($)", flag); - } -}; + splitterRurles.forEach(function(rule) { + rule.splitRegex = this.createSplitterRegexp(rule.regex, flag); + }, this); -(function() { - this.$setMaxTokenCount = function(m) { + this.regExps[key] = new RegExp("(" + ruleRegExps.join(")|(") + ")|($)", flag); + } + }; + + $setMaxTokenCount(m) { MAX_TOKEN_COUNT = m | 0; }; - this.$applyToken = function(str) { + $applyToken(str) { var values = this.splitRegex.exec(str).slice(1); var types = this.token.apply(this, values); @@ -127,7 +124,7 @@ var Tokenizer = function(rules) { return tokens; }; - this.$arrayTokens = function(str) { + $arrayTokens(str) { if (!str) return []; var values = this.splitRegex.exec(str); @@ -145,7 +142,7 @@ var Tokenizer = function(rules) { return tokens; }; - this.removeCapturingGroups = function(src) { + removeCapturingGroups(src) { var r = src.replace( /\\.|\[(?:\\.|[^\\\]])*|\(\?[:=!<]|(\()/g, function(x, y) {return y ? "(?:" : x;} @@ -153,7 +150,7 @@ var Tokenizer = function(rules) { return r; }; - this.createSplitterRegexp = function(src, flag) { + createSplitterRegexp(src, flag) { if (src.indexOf("(?=") != -1) { var stack = 0; var inChClass = false; @@ -196,7 +193,7 @@ var Tokenizer = function(rules) { * Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state. * @returns {Object} **/ - this.getLineTokens = function(line, startState) { + getLineTokens(line, startState) { if (startState && typeof startState != "string") { var stack = startState.slice(0); startState = stack[0]; @@ -332,8 +329,8 @@ var Tokenizer = function(rules) { }; }; - this.reportError = config.reportError; + reportError = config.reportError; -}).call(Tokenizer.prototype); +} exports.Tokenizer = Tokenizer; diff --git a/src/tokenizer_dev.js b/src/tokenizer_dev.js index c6ff3ff0acf..60cb5b9dc7b 100644 --- a/src/tokenizer_dev.js +++ b/src/tokenizer_dev.js @@ -8,14 +8,13 @@ var MAX_TOKEN_COUNT = 2000; * can be used for developing/testing new modes **/ -var Tokenizer = function(rules) { - BaseTokenizer.call(this, rules); - +class Tokenizer extends BaseTokenizer { + /** * Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state. * @returns {Object} **/ - this.getLineTokens = function(line, startState) { + getLineTokens(line, startState) { if (startState && typeof startState != "string") { var stack = startState.slice(0); startState = stack[0]; @@ -146,7 +145,7 @@ var Tokenizer = function(rules) { }; }; -}; +} Tokenizer.prototype = BaseTokenizer.prototype; diff --git a/src/tooltip.js b/src/tooltip.js index 64803f8d86d..e73abdf0e1d 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -1,27 +1,20 @@ "use strict"; -var oop = require("./lib/oop"); var dom = require("./lib/dom"); var CLASSNAME = "ace_tooltip"; -/** - * @class Tooltip - **/ - -/** - * @param {Element} parentNode - * - * @constructor - **/ -function Tooltip (parentNode) { - this.isOpen = false; - this.$element = null; - this.$parentNode = parentNode; -} - -(function() { - this.$init = function() { +class Tooltip { + /** + * @param {Element} parentNode + **/ + constructor(parentNode) { + this.isOpen = false; + this.$element = null; + this.$parentNode = parentNode; + } + + $init() { this.$element = dom.createElement("div"); this.$element.className = CLASSNAME; this.$element.style.display = "none"; @@ -32,21 +25,21 @@ function Tooltip (parentNode) { /** * @returns {Element} **/ - this.getElement = function() { + getElement() { return this.$element || this.$init(); }; /** * @param {String} text **/ - this.setText = function(text) { + setText(text) { this.getElement().textContent = text; }; /** * @param {String} html **/ - this.setHtml = function(html) { + setHtml(html) { this.getElement().innerHTML = html; }; @@ -54,7 +47,7 @@ function Tooltip (parentNode) { * @param {Number} x * @param {Number} y **/ - this.setPosition = function(x, y) { + setPosition(x, y) { this.getElement().style.left = x + "px"; this.getElement().style.top = y + "px"; }; @@ -62,7 +55,7 @@ function Tooltip (parentNode) { /** * @param {String} className **/ - this.setClassName = function(className) { + setClassName(className) { dom.addCssClass(this.getElement(), className); }; @@ -71,7 +64,7 @@ function Tooltip (parentNode) { * @param {Number} x * @param {Number} y **/ - this.show = function(text, x, y) { + show(text, x, y) { if (text != null) this.setText(text); if (x != null && y != null) @@ -82,7 +75,7 @@ function Tooltip (parentNode) { } }; - this.hide = function() { + hide() { if (this.isOpen) { this.getElement().style.display = "none"; this.getElement().className = CLASSNAME; @@ -93,24 +86,24 @@ function Tooltip (parentNode) { /** * @returns {Number} **/ - this.getHeight = function() { + getHeight() { return this.getElement().offsetHeight; }; /** * @returns {Number} **/ - this.getWidth = function() { + getWidth() { return this.getElement().offsetWidth; }; - this.destroy = function() { + destroy() { this.isOpen = false; if (this.$element && this.$element.parentNode) { this.$element.parentNode.removeChild(this.$element); } }; -}).call(Tooltip.prototype); +} exports.Tooltip = Tooltip; diff --git a/src/undomanager.js b/src/undomanager.js index a068acd76bc..43fd51ab13c 100644 --- a/src/undomanager.js +++ b/src/undomanager.js @@ -2,24 +2,20 @@ /** * This object maintains the undo stack for an [[EditSession `EditSession`]]. - * @class UndoManager **/ - -/** - * Resets the current undo state and creates a new `UndoManager`. - * - * @constructor - **/ -var UndoManager = function() { - this.$maxRev = 0; - this.$fromUndo = false; - this.$undoDepth = Infinity; - this.reset(); -}; - -(function() { +class UndoManager { + + /** + * Resets the current undo state and creates a new `UndoManager`. + **/ + constructor() { + this.$maxRev = 0; + this.$fromUndo = false; + this.$undoDepth = Infinity; + this.reset(); + }; - this.addSession = function(session) { + addSession(session) { this.$session = session; }; /** @@ -31,7 +27,7 @@ var UndoManager = function() { * @param {Object} options Contains additional properties * **/ - this.add = function(delta, allowMerge, session) { + add(delta, allowMerge, session) { if (this.$fromUndo) return; if (delta == this.$lastDelta) return; if (!this.$keepRedoStack) this.$redoStack.length = 0; @@ -49,19 +45,19 @@ var UndoManager = function() { this.lastDeltas.push(delta); }; - this.addSelection = function(selection, rev) { + addSelection(selection, rev) { this.selections.push({ value: selection, rev: rev || this.$rev }); }; - this.startNewGroup = function() { + startNewGroup() { this.lastDeltas = null; return this.$rev; }; - this.markIgnored = function(from, to) { + markIgnored(from, to) { if (to == null) to = this.$rev + 1; var stack = this.$undoStack; for (var i = stack.length; i--;) { @@ -74,7 +70,7 @@ var UndoManager = function() { this.lastDeltas = null; }; - this.getSelection = function(rev, after) { + getSelection(rev, after) { var stack = this.selections; for (var i = stack.length; i--;) { var selection = stack[i]; @@ -86,11 +82,11 @@ var UndoManager = function() { } }; - this.getRevision = function() { + getRevision() { return this.$rev; }; - this.getDeltas = function(from, to) { + getDeltas(from, to) { if (to == null) to = this.$rev + 1; var stack = this.$undoStack; var end = null, start = 0; @@ -106,23 +102,24 @@ var UndoManager = function() { return stack.slice(start, end); }; - this.getChangedRanges = function(from, to) { + getChangedRanges(from, to) { if (to == null) to = this.$rev + 1; }; - this.getChangedLines = function(from, to) { + getChangedLines(from, to) { if (to == null) to = this.$rev + 1; }; /** * [Perform an undo operation on the document, reverting the last change.]{: #UndoManager.undo} + * @param {EditSession} session * @param {Boolean} dontSelect {:dontSelect} * * @returns {Range} The range of the undo. **/ - this.undo = function(session, dontSelect) { + undo(session, dontSelect) { this.lastDeltas = null; var stack = this.$undoStack; @@ -155,7 +152,7 @@ var UndoManager = function() { * @param {Boolean} dontSelect {:dontSelect} * **/ - this.redo = function(session, dontSelect) { + redo(session, dontSelect) { this.lastDeltas = null; if (!session) @@ -183,7 +180,7 @@ var UndoManager = function() { return redoSelectionRange; }; - this.$syncRev = function() { + $syncRev() { var stack = this.$undoStack; var nextDelta = stack[stack.length - 1]; var id = nextDelta && nextDelta[0].id || 0; @@ -194,7 +191,7 @@ var UndoManager = function() { /** * Destroys the stack of undo and redo redo operations. **/ - this.reset = function() { + reset() { this.lastDeltas = null; this.$lastDelta = null; this.$undoStack = []; @@ -210,7 +207,7 @@ var UndoManager = function() { * Returns `true` if there are undo operations left to perform. * @returns {Boolean} **/ - this.canUndo = function() { + canUndo() { return this.$undoStack.length > 0; }; @@ -218,14 +215,14 @@ var UndoManager = function() { * Returns `true` if there are redo operations left to perform. * @returns {Boolean} **/ - this.canRedo = function() { + canRedo() { return this.$redoStack.length > 0; }; /** * Marks the current status clean **/ - this.bookmark = function(rev) { + bookmark(rev) { if (rev == undefined) rev = this.$rev; this.mark = rev; @@ -235,28 +232,28 @@ var UndoManager = function() { * Returns if the current status is clean * @returns {Boolean} **/ - this.isAtBookmark = function() { + isAtBookmark() { return this.$rev === this.mark; }; - this.toJSON = function() { + toJSON() { }; - this.fromJSON = function() { + fromJSON() { }; - this.hasUndo = this.canUndo; - this.hasRedo = this.canRedo; - this.isClean = this.isAtBookmark; - this.markClean = this.bookmark; + hasUndo = this.canUndo; + hasRedo = this.canRedo; + isClean = this.isAtBookmark; + markClean = this.bookmark; - this.$prettyPrint = function(delta) { + $prettyPrint(delta) { if (delta) return stringifyDelta(delta); return stringifyDelta(this.$undoStack) + "\n---\n" + stringifyDelta(this.$redoStack); }; -}).call(UndoManager.prototype); +} function rearrangeUndoStack(stack, pos) { for (var i = pos; i--; ) { @@ -317,8 +314,6 @@ function $updateMarkers(delta) { } } - - function clonePos(pos) { return {row: pos.row,column: pos.column}; } @@ -565,5 +560,4 @@ function rebaseRedoStack(redoStack, deltaSets) { } } } - exports.UndoManager = UndoManager; diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index f73f4271273..eebb81ff462 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -25,155 +25,149 @@ dom.importCssString(editorCss, "ace_editor.css", false); /** * The class that is responsible for drawing everything you see on the screen! * @related editor.renderer - * @class VirtualRenderer **/ +class VirtualRenderer { + /** + * Constructs a new `VirtualRenderer` within the `container` specified, applying the given `theme`. + * @param {Element} container The root element of the editor + * @param {String} [theme] The starting theme + **/ + constructor(container, theme) { + var _self = this; -/** - * Constructs a new `VirtualRenderer` within the `container` specified, applying the given `theme`. - * @param {Element} container The root element of the editor - * @param {String} theme The starting theme - * - * @constructor - **/ + this.container = container || dom.createElement("div"); -var VirtualRenderer = function(container, theme) { - var _self = this; + dom.addCssClass(this.container, "ace_editor"); + if (dom.HI_DPI) dom.addCssClass(this.container, "ace_hidpi"); - this.container = container || dom.createElement("div"); + this.setTheme(theme); + if (config.get("useStrictCSP") == null) + config.set("useStrictCSP", false); - dom.addCssClass(this.container, "ace_editor"); - if (dom.HI_DPI) dom.addCssClass(this.container, "ace_hidpi"); + this.$gutter = dom.createElement("div"); + this.$gutter.className = "ace_gutter"; + this.container.appendChild(this.$gutter); + this.$gutter.setAttribute("aria-hidden", true); - this.setTheme(theme); - if (config.get("useStrictCSP") == null) - config.set("useStrictCSP", false); + this.scroller = dom.createElement("div"); + this.scroller.className = "ace_scroller"; - this.$gutter = dom.createElement("div"); - this.$gutter.className = "ace_gutter"; - this.container.appendChild(this.$gutter); - this.$gutter.setAttribute("aria-hidden", true); + this.container.appendChild(this.scroller); - this.scroller = dom.createElement("div"); - this.scroller.className = "ace_scroller"; - - this.container.appendChild(this.scroller); - - this.content = dom.createElement("div"); - this.content.className = "ace_content"; - this.scroller.appendChild(this.content); - - this.$gutterLayer = new GutterLayer(this.$gutter); - this.$gutterLayer.on("changeGutterWidth", this.onGutterResize.bind(this)); - - this.$markerBack = new MarkerLayer(this.content); - - var textLayer = this.$textLayer = new TextLayer(this.content); - this.canvas = textLayer.element; - - this.$markerFront = new MarkerLayer(this.content); - - this.$cursorLayer = new CursorLayer(this.content); - - // Indicates whether the horizontal scrollbar is visible - this.$horizScroll = false; - this.$vScroll = false; - - this.scrollBar = - this.scrollBarV = new VScrollBar(this.container, this); - this.scrollBarH = new HScrollBar(this.container, this); - this.scrollBarV.on("scroll", function(e) { - if (!_self.$scrollAnimation) - _self.session.setScrollTop(e.data - _self.scrollMargin.top); - }); - this.scrollBarH.on("scroll", function(e) { - if (!_self.$scrollAnimation) - _self.session.setScrollLeft(e.data - _self.scrollMargin.left); - }); - - this.scrollTop = 0; - this.scrollLeft = 0; - - this.cursorPos = { - row : 0, - column : 0 - }; - - this.$fontMetrics = new FontMetrics(this.container); - this.$textLayer.$setFontMetrics(this.$fontMetrics); - this.$textLayer.on("changeCharacterSize", function(e) { - _self.updateCharacterSize(); - _self.onResize(true, _self.gutterWidth, _self.$size.width, _self.$size.height); - _self._signal("changeCharacterSize", e); - }); - - this.$size = { - width: 0, - height: 0, - scrollerHeight: 0, - scrollerWidth: 0, - $dirty: true - }; - - this.layerConfig = { - width : 1, - padding : 0, - firstRow : 0, - firstRowScreen: 0, - lastRow : 0, - lineHeight : 0, - characterWidth : 0, - minHeight : 1, - maxHeight : 1, - offset : 0, - height : 1, - gutterOffset: 1 - }; - - this.scrollMargin = { - left: 0, - right: 0, - top: 0, - bottom: 0, - v: 0, - h: 0 - }; - - this.margin = { - left: 0, - right: 0, - top: 0, - bottom: 0, - v: 0, - h: 0 + this.content = dom.createElement("div"); + this.content.className = "ace_content"; + this.scroller.appendChild(this.content); + + this.$gutterLayer = new GutterLayer(this.$gutter); + this.$gutterLayer.on("changeGutterWidth", this.onGutterResize.bind(this)); + + this.$markerBack = new MarkerLayer(this.content); + + var textLayer = this.$textLayer = new TextLayer(this.content); + this.canvas = textLayer.element; + + this.$markerFront = new MarkerLayer(this.content); + + this.$cursorLayer = new CursorLayer(this.content); + + // Indicates whether the horizontal scrollbar is visible + this.$horizScroll = false; + this.$vScroll = false; + + this.scrollBar = + this.scrollBarV = new VScrollBar(this.container, this); + this.scrollBarH = new HScrollBar(this.container, this); + this.scrollBarV.on("scroll", function(e) { + if (!_self.$scrollAnimation) + _self.session.setScrollTop(e.data - _self.scrollMargin.top); + }); + this.scrollBarH.on("scroll", function(e) { + if (!_self.$scrollAnimation) + _self.session.setScrollLeft(e.data - _self.scrollMargin.left); + }); + + this.scrollTop = 0; + this.scrollLeft = 0; + + this.cursorPos = { + row : 0, + column : 0 + }; + + this.$fontMetrics = new FontMetrics(this.container); + this.$textLayer.$setFontMetrics(this.$fontMetrics); + this.$textLayer.on("changeCharacterSize", function(e) { + _self.updateCharacterSize(); + _self.onResize(true, _self.gutterWidth, _self.$size.width, _self.$size.height); + _self._signal("changeCharacterSize", e); + }); + + this.$size = { + width: 0, + height: 0, + scrollerHeight: 0, + scrollerWidth: 0, + $dirty: true + }; + + this.layerConfig = { + width : 1, + padding : 0, + firstRow : 0, + firstRowScreen: 0, + lastRow : 0, + lineHeight : 0, + characterWidth : 0, + minHeight : 1, + maxHeight : 1, + offset : 0, + height : 1, + gutterOffset: 1 + }; + + this.scrollMargin = { + left: 0, + right: 0, + top: 0, + bottom: 0, + v: 0, + h: 0 + }; + + this.margin = { + left: 0, + right: 0, + top: 0, + bottom: 0, + v: 0, + h: 0 + }; + + this.$keepTextAreaAtCursor = !useragent.isIOS; + + this.$loop = new RenderLoop( + this.$renderChanges.bind(this), + this.container.ownerDocument.defaultView + ); + this.$loop.schedule(this.CHANGE_FULL); + + this.updateCharacterSize(); + this.setPadding(4); + config.resetOptions(this); + config._signal("renderer", this); }; - - this.$keepTextAreaAtCursor = !useragent.isIOS; - - this.$loop = new RenderLoop( - this.$renderChanges.bind(this), - this.container.ownerDocument.defaultView - ); - this.$loop.schedule(this.CHANGE_FULL); - - this.updateCharacterSize(); - this.setPadding(4); - config.resetOptions(this); - config._signal("renderer", this); -}; - -(function() { - - this.CHANGE_CURSOR = 1; - this.CHANGE_MARKER = 2; - this.CHANGE_GUTTER = 4; - this.CHANGE_SCROLL = 8; - this.CHANGE_LINES = 16; - this.CHANGE_TEXT = 32; - this.CHANGE_SIZE = 64; - this.CHANGE_MARKER_BACK = 128; - this.CHANGE_MARKER_FRONT = 256; - this.CHANGE_FULL = 512; - this.CHANGE_H_SCROLL = 1024; + + CHANGE_CURSOR = 1; + CHANGE_MARKER = 2; + CHANGE_GUTTER = 4; + CHANGE_SCROLL = 8; + CHANGE_LINES = 16; + CHANGE_TEXT = 32; + CHANGE_SIZE = 64; + CHANGE_MARKER_BACK = 128; + CHANGE_MARKER_FRONT = 256; + CHANGE_FULL = 512; + CHANGE_H_SCROLL = 1024; // this.$logChanges = function(changes) { // var a = "" @@ -191,9 +185,7 @@ var VirtualRenderer = function(container, theme) { // console.log(a.trim()) // }; - oop.implement(this, EventEmitter); - - this.updateCharacterSize = function() { + updateCharacterSize() { if (this.$textLayer.allowBoldFonts != this.$allowBoldFonts) { this.$allowBoldFonts = this.$textLayer.allowBoldFonts; this.setStyle("ace_nobold", !this.$allowBoldFonts); @@ -212,7 +204,7 @@ var VirtualRenderer = function(container, theme) { * * Associates the renderer with an [[EditSession `EditSession`]]. **/ - this.setSession = function(session) { + setSession(session) { if (this.session) this.session.doc.off("changeNewLineMode", this.onChangeNewLineMode); @@ -243,7 +235,7 @@ var VirtualRenderer = function(container, theme) { * @param {Number} lastRow The last row to update * **/ - this.updateLines = function(firstRow, lastRow, force) { + updateLines(firstRow, lastRow, force) { if (lastRow === undefined) lastRow = Infinity; @@ -276,13 +268,13 @@ var VirtualRenderer = function(container, theme) { this.$loop.schedule(this.CHANGE_LINES); }; - this.onChangeNewLineMode = function() { + onChangeNewLineMode() { this.$loop.schedule(this.CHANGE_TEXT); this.$textLayer.$updateEolChar(); this.session.$bidiHandler.setEolChar(this.$textLayer.EOL_CHAR); }; - this.onChangeTabSize = function() { + onChangeTabSize() { this.$loop.schedule(this.CHANGE_TEXT | this.CHANGE_MARKER); this.$textLayer.onChangeTabSize(); }; @@ -290,16 +282,15 @@ var VirtualRenderer = function(container, theme) { /** * Triggers a full update of the text, for all the rows. **/ - this.updateText = function() { + updateText() { this.$loop.schedule(this.CHANGE_TEXT); }; /** * Triggers a full update of all the layers, for all the rows. * @param {Boolean} force If `true`, forces the changes through - * **/ - this.updateFull = function(force) { + updateFull(force) { if (force) this.$renderChanges(this.CHANGE_FULL, true); else @@ -309,12 +300,12 @@ var VirtualRenderer = function(container, theme) { /** * Updates the font size. **/ - this.updateFontSize = function() { + updateFontSize() { this.$textLayer.checkForSizeChanges(); }; - this.$changes = 0; - this.$updateSizeAsync = function() { + $changes = 0; + $updateSizeAsync() { if (this.$loop.pending) this.$size.$dirty = true; else @@ -328,7 +319,7 @@ var VirtualRenderer = function(container, theme) { * @param {Number} height The hiehgt of the editor, in pixels * **/ - this.onResize = function(force, gutterWidth, width, height) { + onResize(force, gutterWidth, width, height) { if (this.resizing > 2) return; else if (this.resizing > 0) @@ -366,7 +357,7 @@ var VirtualRenderer = function(container, theme) { } }; - this.$updateCachedSize = function(force, gutterWidth, width, height) { + $updateCachedSize(force, gutterWidth, width, height) { height -= (this.$extraHeight || 0); var changes = 0; var size = this.$size; @@ -424,7 +415,7 @@ var VirtualRenderer = function(container, theme) { return changes; }; - this.onGutterResize = function(width) { + onGutterResize(width) { var gutterWidth = this.$showGutter ? width : 0; if (gutterWidth != this.gutterWidth) this.$changes |= this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height); @@ -441,7 +432,7 @@ var VirtualRenderer = function(container, theme) { /** * Adjusts the wrap limit, which is the number of characters that can fit within the width of the edit area on screen. **/ - this.adjustWrapLimit = function() { + adjustWrapLimit() { var availableWidth = this.$size.scrollerWidth - this.$padding * 2; var limit = Math.floor(availableWidth / this.characterWidth); return this.session.adjustWrapLimit(limit, this.$showPrintMargin && this.$printMarginColumn); @@ -452,7 +443,7 @@ var VirtualRenderer = function(container, theme) { * @param {Boolean} shouldAnimate Set to `true` to show animated scrolls * **/ - this.setAnimatedScroll = function(shouldAnimate){ + setAnimatedScroll(shouldAnimate){ this.setOption("animatedScroll", shouldAnimate); }; @@ -460,7 +451,7 @@ var VirtualRenderer = function(container, theme) { * Returns whether an animated scroll happens or not. * @returns {Boolean} **/ - this.getAnimatedScroll = function() { + getAnimatedScroll() { return this.$animatedScroll; }; @@ -469,7 +460,7 @@ var VirtualRenderer = function(container, theme) { * @param {Boolean} showInvisibles Set to `true` to show invisibles * **/ - this.setShowInvisibles = function(showInvisibles) { + setShowInvisibles(showInvisibles) { this.setOption("showInvisibles", showInvisibles); this.session.$bidiHandler.setShowInvisibles(showInvisibles); }; @@ -478,22 +469,22 @@ var VirtualRenderer = function(container, theme) { * Returns whether invisible characters are being shown or not. * @returns {Boolean} **/ - this.getShowInvisibles = function() { + getShowInvisibles() { return this.getOption("showInvisibles"); }; - this.getDisplayIndentGuides = function() { + getDisplayIndentGuide() { return this.getOption("displayIndentGuides"); }; - this.setDisplayIndentGuides = function(display) { + setDisplayIndentGuides(display) { this.setOption("displayIndentGuides", display); }; - this.getHighlightIndentGuides = function() { + getHighlightIndentGuides() { return this.getOption("highlightIndentGuides"); }; - this.setHighlightIndentGuides = function(highlight) { + setHighlightIndentGuides(highlight) { this.setOption("highlightIndentGuides", highlight); }; @@ -502,7 +493,7 @@ var VirtualRenderer = function(container, theme) { * @param {Boolean} showPrintMargin Set to `true` to show the print margin * **/ - this.setShowPrintMargin = function(showPrintMargin) { + setShowPrintMargin(showPrintMargin) { this.setOption("showPrintMargin", showPrintMargin); }; @@ -510,7 +501,7 @@ var VirtualRenderer = function(container, theme) { * Returns whether the print margin is being shown or not. * @returns {Boolean} **/ - this.getShowPrintMargin = function() { + getShowPrintMargin() { return this.getOption("showPrintMargin"); }; /** @@ -518,7 +509,7 @@ var VirtualRenderer = function(container, theme) { * @param {Boolean} showPrintMargin Set to `true` to show the print margin column * **/ - this.setPrintMarginColumn = function(showPrintMargin) { + setPrintMarginColumn(showPrintMargin) { this.setOption("printMarginColumn", showPrintMargin); }; @@ -526,7 +517,7 @@ var VirtualRenderer = function(container, theme) { * Returns whether the print margin column is being shown or not. * @returns {Boolean} **/ - this.getPrintMarginColumn = function() { + getPrintMarginColumn() { return this.getOption("printMarginColumn"); }; @@ -534,7 +525,7 @@ var VirtualRenderer = function(container, theme) { * Returns `true` if the gutter is being shown. * @returns {Boolean} **/ - this.getShowGutter = function(){ + getShowGutter(){ return this.getOption("showGutter"); }; @@ -543,27 +534,27 @@ var VirtualRenderer = function(container, theme) { * @param {Boolean} show Set to `true` to show the gutter * **/ - this.setShowGutter = function(show){ + setShowGutter(show){ return this.setOption("showGutter", show); }; - this.getFadeFoldWidgets = function(){ + getFadeFoldWidgets(){ return this.getOption("fadeFoldWidgets"); }; - this.setFadeFoldWidgets = function(show) { + setFadeFoldWidgets(show) { this.setOption("fadeFoldWidgets", show); }; - this.setHighlightGutterLine = function(shouldHighlight) { + setHighlightGutterLine(shouldHighlight) { this.setOption("highlightGutterLine", shouldHighlight); }; - this.getHighlightGutterLine = function() { + getHighlightGutterLine() { return this.getOption("highlightGutterLine"); }; - this.$updatePrintMargin = function() { + $updatePrintMargin() { if (!this.$showPrintMargin && !this.$printMarginEl) return; @@ -589,7 +580,7 @@ var VirtualRenderer = function(container, theme) { * Returns the root element containing this renderer. * @returns {Element} **/ - this.getContainerElement = function() { + getContainerElement() { return this.container; }; @@ -598,7 +589,7 @@ var VirtualRenderer = function(container, theme) { * Returns the element that the mouse events are attached to * @returns {Element} **/ - this.getMouseEventTarget = function() { + getMouseEventTarget() { return this.scroller; }; @@ -607,13 +598,13 @@ var VirtualRenderer = function(container, theme) { * Returns the element to which the hidden text area is added. * @returns {Element} **/ - this.getTextAreaContainer = function() { + getTextAreaContainer() { return this.container; }; // move text input over the cursor // this is required for IME - this.$moveTextAreaToCursor = function() { + $moveTextAreaToCursor() { if (this.$isMousePressed) return; var style = this.textarea.style; var composition = this.$composition; @@ -668,7 +659,7 @@ var VirtualRenderer = function(container, theme) { * [Returns the index of the first visible row.]{: #VirtualRenderer.getFirstVisibleRow} * @returns {Number} **/ - this.getFirstVisibleRow = function() { + getFirstVisibleRow() { return this.layerConfig.firstRow; }; @@ -677,7 +668,7 @@ var VirtualRenderer = function(container, theme) { * Returns the index of the first fully visible row. "Fully" here means that the characters in the row are not truncated; that the top and the bottom of the row are on the screen. * @returns {Number} **/ - this.getFirstFullyVisibleRow = function() { + getFirstFullyVisibleRow() { return this.layerConfig.firstRow + (this.layerConfig.offset === 0 ? 0 : 1); }; @@ -686,7 +677,7 @@ var VirtualRenderer = function(container, theme) { * Returns the index of the last fully visible row. "Fully" here means that the characters in the row are not truncated; that the top and the bottom of the row are on the screen. * @returns {Number} **/ - this.getLastFullyVisibleRow = function() { + getLastFullyVisibleRow() { var config = this.layerConfig; var lastRow = config.lastRow; var top = this.session.documentToScreenRow(lastRow, 0) * config.lineHeight; @@ -700,18 +691,18 @@ var VirtualRenderer = function(container, theme) { * [Returns the index of the last visible row.]{: #VirtualRenderer.getLastVisibleRow} * @returns {Number} **/ - this.getLastVisibleRow = function() { + getLastVisibleRow() { return this.layerConfig.lastRow; }; - this.$padding = null; + $padding = null; /** * Sets the padding for all the layers. * @param {Number} padding A new padding value (in pixels) * **/ - this.setPadding = function(padding) { + setPadding(padding) { this.$padding = padding; this.$textLayer.setPadding(padding); this.$cursorLayer.setPadding(padding); @@ -721,7 +712,7 @@ var VirtualRenderer = function(container, theme) { this.$updatePrintMargin(); }; - this.setScrollMargin = function(top, bottom, left, right) { + setScrollMargin(top, bottom, left, right) { var sm = this.scrollMargin; sm.top = top|0; sm.bottom = bottom|0; @@ -734,7 +725,7 @@ var VirtualRenderer = function(container, theme) { this.updateFull(); }; - this.setMargin = function(top, bottom, left, right) { + setMargin(top, bottom, left, right) { var sm = this.margin; sm.top = top|0; sm.bottom = bottom|0; @@ -750,7 +741,7 @@ var VirtualRenderer = function(container, theme) { * Returns whether the horizontal scrollbar is set to be always visible. * @returns {Boolean} **/ - this.getHScrollBarAlwaysVisible = function() { + getHScrollBarAlwaysVisible() { return this.$hScrollBarAlwaysVisible; }; @@ -758,14 +749,14 @@ var VirtualRenderer = function(container, theme) { * Identifies whether you want to show the horizontal scrollbar or not. * @param {Boolean} alwaysVisible Set to `true` to make the horizontal scroll bar visible **/ - this.setHScrollBarAlwaysVisible = function(alwaysVisible) { + setHScrollBarAlwaysVisible(alwaysVisible) { this.setOption("hScrollBarAlwaysVisible", alwaysVisible); }; /** * Returns whether the horizontal scrollbar is set to be always visible. * @returns {Boolean} **/ - this.getVScrollBarAlwaysVisible = function() { + getVScrollBarAlwaysVisible() { return this.$vScrollBarAlwaysVisible; }; @@ -773,11 +764,11 @@ var VirtualRenderer = function(container, theme) { * Identifies whether you want to show the horizontal scrollbar or not. * @param {Boolean} alwaysVisible Set to `true` to make the horizontal scroll bar visible **/ - this.setVScrollBarAlwaysVisible = function(alwaysVisible) { + setVScrollBarAlwaysVisible(alwaysVisible) { this.setOption("vScrollBarAlwaysVisible", alwaysVisible); }; - this.$updateScrollBarV = function() { + $updateScrollBarV() { var scrollHeight = this.layerConfig.maxHeight; var scrollerHeight = this.$size.scrollerHeight; if (!this.$maxLines && this.$scrollPastEnd) { @@ -790,21 +781,21 @@ var VirtualRenderer = function(container, theme) { this.scrollBarV.setScrollHeight(scrollHeight + this.scrollMargin.v); this.scrollBarV.setScrollTop(this.scrollTop + this.scrollMargin.top); }; - this.$updateScrollBarH = function() { + $updateScrollBarH() { this.scrollBarH.setScrollWidth(this.layerConfig.width + 2 * this.$padding + this.scrollMargin.h); this.scrollBarH.setScrollLeft(this.scrollLeft + this.scrollMargin.left); }; - this.$frozen = false; - this.freeze = function() { + $frozen = false; + freeze() { this.$frozen = true; }; - this.unfreeze = function() { + unfreeze() { this.$frozen = false; }; - this.$renderChanges = function(changes, force) { + $renderChanges(changes, force) { if (this.$changes) { changes |= this.$changes; this.$changes = 0; @@ -962,7 +953,7 @@ var VirtualRenderer = function(container, theme) { }; - this.$autosize = function() { + $autosize() { var height = this.session.getScreenLength() * this.lineHeight; var maxHeight = this.$maxLines * this.lineHeight; var desiredHeight = Math.min(maxHeight, @@ -993,7 +984,7 @@ var VirtualRenderer = function(container, theme) { } }; - this.$computeLayerConfig = function() { + $computeLayerConfig() { var session = this.session; var size = this.$size; @@ -1099,7 +1090,7 @@ var VirtualRenderer = function(container, theme) { return changes; }; - this.$updateLines = function() { + $updateLines() { if (!this.$changedLines) return; var firstRow = this.$changedLines.firstRow; var lastRow = this.$changedLines.lastRow; @@ -1123,7 +1114,7 @@ var VirtualRenderer = function(container, theme) { return true; }; - this.$getLongestLine = function() { + $getLongestLine() { var charCount = this.session.getScreenWidth(); if (this.showInvisibles && !this.session.$useWrapMode) charCount += 1; @@ -1137,7 +1128,7 @@ var VirtualRenderer = function(container, theme) { /** * Schedules an update to all the front markers in the document. **/ - this.updateFrontMarkers = function() { + updateFrontMarkers() { this.$markerFront.setMarkers(this.session.getMarkers(true)); this.$loop.schedule(this.CHANGE_MARKER_FRONT); }; @@ -1146,7 +1137,7 @@ var VirtualRenderer = function(container, theme) { * * Schedules an update to all the back markers in the document. **/ - this.updateBackMarkers = function() { + updateBackMarkers() { this.$markerBack.setMarkers(this.session.getMarkers()); this.$loop.schedule(this.CHANGE_MARKER_BACK); }; @@ -1156,7 +1147,7 @@ var VirtualRenderer = function(container, theme) { * Deprecated; (moved to [[EditSession]]) * @deprecated **/ - this.addGutterDecoration = function(row, className){ + addGutterDecoration(row, className){ this.$gutterLayer.addGutterDecoration(row, className); }; @@ -1164,7 +1155,7 @@ var VirtualRenderer = function(container, theme) { * Deprecated; (moved to [[EditSession]]) * @deprecated **/ - this.removeGutterDecoration = function(row, className){ + removeGutterDecoration(row, className){ this.$gutterLayer.removeGutterDecoration(row, className); }; @@ -1172,7 +1163,7 @@ var VirtualRenderer = function(container, theme) { * * Redraw breakpoints. **/ - this.updateBreakpoints = function(rows) { + updateBreakpoints(rows) { this.$loop.schedule(this.CHANGE_GUTTER); }; @@ -1181,7 +1172,7 @@ var VirtualRenderer = function(container, theme) { * @param {Annotation[]} annotations An array containing annotations * **/ - this.setAnnotations = function(annotations) { + setAnnotations(annotations) { this.$gutterLayer.setAnnotations(annotations); this.$loop.schedule(this.CHANGE_GUTTER); }; @@ -1190,7 +1181,7 @@ var VirtualRenderer = function(container, theme) { * * Updates the cursor icon. **/ - this.updateCursor = function() { + updateCursor() { this.$loop.schedule(this.CHANGE_CURSOR); }; @@ -1198,7 +1189,7 @@ var VirtualRenderer = function(container, theme) { * * Hides the cursor icon. **/ - this.hideCursor = function() { + hideCursor() { this.$cursorLayer.hideCursor(); }; @@ -1206,11 +1197,11 @@ var VirtualRenderer = function(container, theme) { * * Shows the cursor icon. **/ - this.showCursor = function() { + showCursor() { this.$cursorLayer.showCursor(); }; - this.scrollSelectionIntoView = function(anchor, lead, offset) { + scrollSelectionIntoView(anchor, lead, offset) { // first scroll anchor into view then scroll lead into view this.scrollCursorIntoView(anchor, offset); this.scrollCursorIntoView(lead, offset); @@ -1220,7 +1211,7 @@ var VirtualRenderer = function(container, theme) { * * Scrolls the cursor into the first visibile area of the editor **/ - this.scrollCursorIntoView = function(cursor, offset, $viewMargin) { + scrollCursorIntoView(cursor, offset, $viewMargin) { // the editor is not visible if (this.$size.scrollerHeight === 0) return; @@ -1276,7 +1267,7 @@ var VirtualRenderer = function(container, theme) { * @related EditSession.getScrollTop * @returns {Number} **/ - this.getScrollTop = function() { + getScrollTop() { return this.session.getScrollTop(); }; @@ -1285,7 +1276,7 @@ var VirtualRenderer = function(container, theme) { * @related EditSession.getScrollLeft * @returns {Number} **/ - this.getScrollLeft = function() { + getScrollLeft() { return this.session.getScrollLeft(); }; @@ -1293,7 +1284,7 @@ var VirtualRenderer = function(container, theme) { * Returns the first visible row, regardless of whether it's fully visible or not. * @returns {Number} **/ - this.getScrollTopRow = function() { + getScrollTopRow() { return this.scrollTop / this.lineHeight; }; @@ -1301,7 +1292,7 @@ var VirtualRenderer = function(container, theme) { * Returns the last visible row, regardless of whether it's fully visible or not. * @returns {Number} **/ - this.getScrollBottomRow = function() { + getScrollBottomRow() { return Math.max(0, Math.floor((this.scrollTop + this.$size.scrollerHeight) / this.lineHeight) - 1); }; @@ -1311,11 +1302,11 @@ var VirtualRenderer = function(container, theme) { * * @related EditSession.setScrollTop **/ - this.scrollToRow = function(row) { + scrollToRow(row) { this.session.setScrollTop(row * this.lineHeight); }; - this.alignCursor = function(cursor, alignment) { + alignCursor(cursor, alignment) { if (typeof cursor == "number") cursor = {row: cursor, column: 0}; @@ -1327,8 +1318,8 @@ var VirtualRenderer = function(container, theme) { return offset; }; - this.STEPS = 8; - this.$calcSteps = function(fromValue, toValue){ + STEPS = 8; + $calcSteps(fromValue, toValue){ var i = 0; var l = this.STEPS; var steps = []; @@ -1351,7 +1342,7 @@ var VirtualRenderer = function(container, theme) { * @param {Function} callback Function to be called after the animation has finished * **/ - this.scrollToLine = function(line, center, animate, callback) { + scrollToLine(line, center, animate, callback) { var pos = this.$cursorLayer.getPixelPosition({row: line, column: 0}); var offset = pos.top; if (center) @@ -1363,7 +1354,7 @@ var VirtualRenderer = function(container, theme) { this.animateScrolling(initialScroll, callback); }; - this.animateScrolling = function(fromValue, callback) { + animateScrolling(fromValue, callback) { var toValue = this.scrollTop; if (!this.$animatedScroll) return; @@ -1425,7 +1416,7 @@ var VirtualRenderer = function(container, theme) { * * @returns {Number} **/ - this.scrollToY = function(scrollTop) { + scrollToY(scrollTop) { // after calling scrollBar.setScrollTop // scrollbar sends us event with same scrollTop. ignore it if (this.scrollTop !== scrollTop) { @@ -1440,7 +1431,7 @@ var VirtualRenderer = function(container, theme) { * * @returns {Number} **/ - this.scrollToX = function(scrollLeft) { + scrollToX(scrollLeft) { if (this.scrollLeft !== scrollLeft) this.scrollLeft = scrollLeft; this.$loop.schedule(this.CHANGE_H_SCROLL); @@ -1451,7 +1442,7 @@ var VirtualRenderer = function(container, theme) { * @param {Number} x The x value to scroll to * @param {Number} y The y value to scroll to **/ - this.scrollTo = function(x, y) { + scrollTo(x, y) { this.session.setScrollTop(y); this.session.setScrollLeft(x); }; @@ -1461,7 +1452,7 @@ var VirtualRenderer = function(container, theme) { * @param {Number} deltaX The x value to scroll by * @param {Number} deltaY The y value to scroll by **/ - this.scrollBy = function(deltaX, deltaY) { + scrollBy(deltaX, deltaY) { deltaY && this.session.setScrollTop(this.session.getScrollTop() + deltaY); deltaX && this.session.setScrollLeft(this.session.getScrollLeft() + deltaX); }; @@ -1473,7 +1464,7 @@ var VirtualRenderer = function(container, theme) { * * @returns {Boolean} **/ - this.isScrollableBy = function(deltaX, deltaY) { + isScrollableBy(deltaX, deltaY) { if (deltaY < 0 && this.session.getScrollTop() >= 1 - this.scrollMargin.top) return true; if (deltaY > 0 && this.session.getScrollTop() + this.$size.scrollerHeight @@ -1486,7 +1477,7 @@ var VirtualRenderer = function(container, theme) { return true; }; - this.pixelToScreenCoordinates = function(x, y) { + pixelToScreenCoordinates(x, y) { var canvasPos; if (this.$hasCssTransforms) { canvasPos = {top:0, left: 0}; @@ -1505,7 +1496,7 @@ var VirtualRenderer = function(container, theme) { return {row: row, column: col, side: offset - col > 0 ? 1 : -1, offsetX: offsetX}; }; - this.screenToTextCoordinates = function(x, y) { + screenToTextCoordinates(x, y) { var canvasPos; if (this.$hasCssTransforms) { canvasPos = {top:0, left: 0}; @@ -1532,7 +1523,7 @@ var VirtualRenderer = function(container, theme) { * * @returns {Object} **/ - this.textToScreenCoordinates = function(row, column) { + textToScreenCoordinates(row, column) { var canvasPos = this.scroller.getBoundingClientRect(); var pos = this.session.documentToScreenPosition(row, column); @@ -1552,7 +1543,7 @@ var VirtualRenderer = function(container, theme) { * * Focuses the current container. **/ - this.visualizeFocus = function() { + visualizeFocus() { dom.addCssClass(this.container, "ace_focus"); }; @@ -1560,16 +1551,16 @@ var VirtualRenderer = function(container, theme) { * * Blurs the current container. **/ - this.visualizeBlur = function() { + visualizeBlur() { dom.removeCssClass(this.container, "ace_focus"); }; /** - * @param {Number} position + * @param {Object} composition * * @private **/ - this.showComposition = function(composition) { + showComposition(composition) { this.$composition = composition; if (!composition.cssText) { composition.cssText = this.textarea.style.cssText; @@ -1593,7 +1584,7 @@ var VirtualRenderer = function(container, theme) { * * Sets the inner text of the current composition to `text`. **/ - this.setCompositionText = function(text) { + setCompositionText(text) { var cursor = this.session.selection.cursor; this.addToken(text, "composition_placeholder", cursor.row, cursor.column); this.$moveTextAreaToCursor(); @@ -1603,7 +1594,7 @@ var VirtualRenderer = function(container, theme) { * * Hides the current composition. **/ - this.hideComposition = function() { + hideComposition() { if (!this.$composition) return; @@ -1618,7 +1609,7 @@ var VirtualRenderer = function(container, theme) { this.$cursorLayer.element.style.display = ""; }; - this.setGhostText = function(text, position) { + setGhostText(text, position) { var cursor = this.session.selection.cursor; var insertPosition = position || { row: cursor.row, column: cursor.column }; @@ -1645,7 +1636,7 @@ var VirtualRenderer = function(container, theme) { }; - this.removeGhostText = function() { + removeGhostText() { if (!this.$ghostText) return; var position = this.$ghostText.position; @@ -1657,7 +1648,7 @@ var VirtualRenderer = function(container, theme) { this.$ghostText = null; }; - this.addToken = function(text, type, row, column) { + addToken(text, type, row, column) { var session = this.session; session.bgTokenizer.lines[row] = null; var newToken = {type: type, value: text}; @@ -1682,18 +1673,18 @@ var VirtualRenderer = function(container, theme) { this.updateLines(row, row); }; - this.removeExtraToken = function(row, column) { + removeExtraToken(row, column) { this.session.bgTokenizer.lines[row] = null; this.updateLines(row, row); }; /** * [Sets a new theme for the editor. `theme` should exist, and be a directory path, like `ace/theme/textmate`.]{: #VirtualRenderer.setTheme} - * @param {String} theme The path to a theme - * @param {Function} cb optional callback + * @param {String} [theme] The path to a theme + * @param {Function} [cb] optional callback * **/ - this.setTheme = function(theme, cb) { + setTheme(theme, cb) { var _self = this; this.$themeId = theme; _self._dispatchEvent('themeChange',{theme:theme}); @@ -1748,7 +1739,7 @@ var VirtualRenderer = function(container, theme) { * [Returns the path of the current theme.]{: #VirtualRenderer.getTheme} * @returns {String} **/ - this.getTheme = function() { + getTheme() { return this.$themeId; }; @@ -1761,7 +1752,7 @@ var VirtualRenderer = function(container, theme) { * @param {String} style A class name * **/ - this.setStyle = function(style, include) { + setStyle(style, include) { dom.setCssClass(this.container, style, include !== false); }; @@ -1770,11 +1761,11 @@ var VirtualRenderer = function(container, theme) { * @param {String} style A class name * **/ - this.unsetStyle = function(style) { + unsetStyle(style) { dom.removeCssClass(this.container, style); }; - this.setCursorStyle = function(style) { + setCursorStyle(style) { dom.setStyle(this.scroller.style, "cursor", style); }; @@ -1782,18 +1773,18 @@ var VirtualRenderer = function(container, theme) { * @param {String} cursorStyle A css cursor style * **/ - this.setMouseCursor = function(cursorStyle) { + setMouseCursor(cursorStyle) { dom.setStyle(this.scroller.style, "cursor", cursorStyle); }; - this.attachToShadowRoot = function() { + attachToShadowRoot() { dom.importCssString(editorCss, "ace_editor.css", this.container); }; /** * Destroys the text and cursor layers for this renderer. **/ - this.destroy = function() { + destroy() { this.freeze(); this.$fontMetrics.destroy(); this.$cursorLayer.destroy(); @@ -1801,7 +1792,7 @@ var VirtualRenderer = function(container, theme) { this.container.textContent = ""; }; - this.$updateCustomScrollbar = function (val) { + $updateCustomScrollbar(val) { var _self = this; this.$horizScroll = this.$vScroll = null; this.scrollBarV.element.remove(); @@ -1836,8 +1827,8 @@ var VirtualRenderer = function(container, theme) { } }; -}).call(VirtualRenderer.prototype); - +} +oop.implement(VirtualRenderer.prototype, EventEmitter); config.defineOptions(VirtualRenderer.prototype, "renderer", { animatedScroll: {initialValue: false}, From eef0363579421238b685d00430304ce5472071be Mon Sep 17 00:00:00 2001 From: mkslanc Date: Thu, 23 Mar 2023 16:26:16 +0400 Subject: [PATCH 0754/1293] fix `SimpleTextLayer` relying on prototype properties --- src/edit_session.js | 6 ++--- src/ext/static_highlight.js | 10 +++---- src/layer/text.js | 54 +++++++++++++++++-------------------- 3 files changed, 32 insertions(+), 38 deletions(-) diff --git a/src/edit_session.js b/src/edit_session.js index eb9c93f9c58..2069d701a13 100644 --- a/src/edit_session.js +++ b/src/edit_session.js @@ -810,9 +810,7 @@ class EditSession { this.bgTokenizer.start(rows.first); this._signal("tokenizerUpdate", e); }; - - $modes = config.$modes; - + /** * * @type {TextMode|null} @@ -2358,6 +2356,8 @@ class EditSession { isFullWidth = isFullWidth; } +EditSession.prototype.$modes = config.$modes; + oop.implement(EditSession.prototype, EventEmitter); // "Tokens" diff --git a/src/ext/static_highlight.js b/src/ext/static_highlight.js index c6aa860e278..3538a34a544 100644 --- a/src/ext/static_highlight.js +++ b/src/ext/static_highlight.js @@ -63,12 +63,10 @@ var simpleDom = { }; -class SimpleTextLayer { - constructor() { - this.config = {}; - this.dom = simpleDom; - }; -} +var SimpleTextLayer = function() { + this.config = {}; + this.dom = simpleDom; +}; SimpleTextLayer.prototype = TextLayer.prototype; var highlight = function(el, opts, callback) { diff --git a/src/layer/text.js b/src/layer/text.js index 0b204ef813b..c3268dfdfb3 100644 --- a/src/layer/text.js +++ b/src/layer/text.js @@ -17,15 +17,6 @@ class Text { this.$lines = new Lines(this.element); }; - EOF_CHAR = "\xB6"; - EOL_CHAR_LF = "\xAC"; - EOL_CHAR_CRLF = "\xa4"; - EOL_CHAR = this.EOL_CHAR_LF; - TAB_CHAR = "\u2014"; //"\u21E5"; - SPACE_CHAR = "\xB7"; - $padding = 0; - MAX_LINE_LENGTH = 10000; - $updateEolChar() { var doc = this.session.doc; var unixMode = doc.getNewLineCharacter() == "\n" && doc.getNewLineMode() != "windows"; @@ -68,11 +59,7 @@ class Text { if (session) this.$computeTabString(); }; - - showInvisibles = false; - showSpaces = false; - showTabs = false; - showEOL = false; + setShowInvisibles(showInvisibles) { if (this.showInvisibles == showInvisibles) return false; @@ -88,8 +75,7 @@ class Text { this.$computeTabString(); return true; }; - - displayIndentGuides = true; + setDisplayIndentGuides(display) { if (this.displayIndentGuides == display) return false; @@ -98,17 +84,13 @@ class Text { this.$computeTabString(); return true; }; - - $highlightIndentGuides = true; + setHighlightIndentGuides(highlight) { if (this.$highlightIndentGuides === highlight) return false; this.$highlightIndentGuides = highlight; return highlight; }; - - $tabStrings = []; - $computeTabString() { var tabSize = this.session.getTabSize(); @@ -314,12 +296,6 @@ class Text { lines.push(this.$renderLinesFragment(config, firstRow, lastRow)); }; - $textToken = { - "text": true, - "rparen": true, - "lparen": true - }; - $renderToken(parent, screenColumn, token, value) { var self = this; var re = /(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC\u2066\u2067\u2068\u202A\u202B\u202D\u202E\u202C\u2069]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g; @@ -736,10 +712,30 @@ class Text { // with the class name ace_line_group). return this.session.getUseWrapMode(); }; - - destroy = {}; } +Text.prototype.$textToken = { + "text": true, + "rparen": true, + "lparen": true +}; +Text.prototype.EOF_CHAR = "\xB6"; +Text.prototype.EOL_CHAR_LF = "\xAC"; +Text.prototype.EOL_CHAR_CRLF = "\xa4"; +Text.prototype.EOL_CHAR = Text.prototype.EOL_CHAR_LF; +Text.prototype.TAB_CHAR = "\u2014"; //"\u21E5"; +Text.prototype.SPACE_CHAR = "\xB7"; +Text.prototype.$padding = 0; +Text.prototype.MAX_LINE_LENGTH = 10000; +Text.prototype.showInvisibles = false; +Text.prototype.showSpaces = false; +Text.prototype.showTabs = false; +Text.prototype.showEOL = false; +Text.prototype.displayIndentGuides = true; +Text.prototype.$highlightIndentGuides = true; +Text.prototype.$tabStrings = []; +Text.prototype.destroy = {}; + oop.implement(Text.prototype, EventEmitter); exports.Text = Text; From e05883012542ba2b78d01ca8b38e82b51db69071 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Thu, 23 Mar 2023 16:56:23 +0400 Subject: [PATCH 0755/1293] remove unnecessary semicolons; set prototype properties --- src/anchor.js | 27 +- src/autocomplete.js | 112 ++++---- src/autocomplete/inline.js | 10 +- src/autocomplete/popup.js | 2 +- src/background_tokenizer.js | 26 +- src/bidihandler.js | 38 +-- src/commands/command_manager.js | 10 +- src/config.js | 1 - src/document.js | 112 ++++---- src/edit_session.js | 323 +++++++++++----------- src/edit_session/fold.js | 12 +- src/edit_session/fold_line.js | 20 +- src/editor.js | 415 ++++++++++++++-------------- src/ext/elastic_tabstops_lite.js | 22 +- src/ext/inline_autocomplete.js | 146 +++++----- src/ext/modelist.js | 4 +- src/ext/options.js | 16 +- src/ext/searchbox.js | 56 ++-- src/ext/static_highlight.js | 6 +- src/ext/statusbar.js | 4 +- src/incremental_search.js | 31 +-- src/keyboard/keybinding.js | 20 +- src/layer/cursor.js | 47 ++-- src/layer/decorators.js | 6 +- src/layer/font_metrics.js | 29 +- src/layer/gutter.js | 54 ++-- src/layer/lines.js | 28 +- src/layer/marker.js | 32 +-- src/layer/text.js | 62 ++--- src/lib/app_config.js | 14 +- src/line_widgets.js | 30 +- src/mouse/default_gutter_handler.js | 3 +- src/mouse/default_handlers.js | 27 +- src/mouse/mouse_event.js | 26 +- src/mouse/mouse_handler.js | 19 +- src/occur.js | 17 +- src/placeholder.js | 20 +- src/range.js | 54 ++-- src/range_list.js | 30 +- src/renderloop.js | 6 +- src/scrollbar.js | 45 +-- src/scrollbar_custom.js | 40 +-- src/search.js | 18 +- src/search_highlight.js | 13 +- src/token_iterator.js | 16 +- src/tokenizer.js | 19 +- src/tokenizer_dev.js | 2 +- src/tooltip.js | 22 +- src/undomanager.js | 55 ++-- src/virtual_renderer.js | 245 ++++++++-------- 50 files changed, 1193 insertions(+), 1199 deletions(-) diff --git a/src/anchor.js b/src/anchor.js index d81f8bb9140..06884e56bd6 100644 --- a/src/anchor.js +++ b/src/anchor.js @@ -22,7 +22,7 @@ class Anchor { this.setPosition(row.row, row.column); else this.setPosition(row, column); - }; + } /** * Returns an object identifying the `row` and `column` position of the current anchor. @@ -30,7 +30,7 @@ class Anchor { **/ getPosition() { return this.$clipPositionToDocument(this.row, this.column); - }; + } /** * @@ -39,12 +39,8 @@ class Anchor { **/ getDocument() { return this.document; - }; - - /** - * experimental: allows anchor to stick to the next on the left - */ - $insertRight = false; + } + /** * Fires whenever the anchor position changes. * @@ -71,7 +67,7 @@ class Anchor { var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight); this.setPosition(point.row, point.column, true); - }; + } /** * Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not clipped. @@ -105,7 +101,7 @@ class Anchor { old: old, value: pos }); - }; + } /** * When called, the `"change"` event listener is removed. @@ -113,7 +109,7 @@ class Anchor { **/ detach() { this.document.off("change", this.$onChange); - }; + } /** * When called, the `"change"` event listener is appended. @@ -123,7 +119,7 @@ class Anchor { attach(doc) { this.document = doc || this.document; this.document.on("change", this.$onChange); - }; + } /** * Clips the anchor position to the specified row and column. @@ -152,9 +148,14 @@ class Anchor { pos.column = 0; return pos; - }; + } } +/** + * experimental: allows anchor to stick to the next on the left + */ +Anchor.prototype.$insertRight = false; + oop.implement(Anchor.prototype, EventEmitter); function $pointsInOrder(point1, point2, equalPointsInOrder) { diff --git a/src/autocomplete.js b/src/autocomplete.js index dfdc947237c..6389d6b2cb1 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -37,7 +37,7 @@ class Autocomplete { }.bind(this)); this.tooltipTimer = lang.delayedCall(this.updateDocTooltip.bind(this), 50); - }; + } $init() { this.popup = new AcePopup(document.body || document.documentElement); @@ -51,25 +51,25 @@ class Autocomplete { this.popup.on("select", this.$onPopupChange.bind(this)); this.popup.on("changeHoverMarker", this.tooltipTimer.bind(null, null)); return this.popup; - }; + } $initInline() { if (!this.inlineEnabled || this.inlineRenderer) return; this.inlineRenderer = new AceInline(); return this.inlineRenderer; - }; + } getPopup() { return this.popup || this.$init(); - }; + } $onHidePopup() { if (this.inlineRenderer) { this.inlineRenderer.hide(); } this.hideDocTooltip(); - }; + } $onPopupChange(hide) { if (this.inlineRenderer && this.inlineEnabled) { @@ -81,7 +81,7 @@ class Autocomplete { this.$updatePopupPosition(); } this.tooltipTimer.call(null, null); - }; + } $updatePopupPosition() { var editor = this.editor; @@ -117,7 +117,7 @@ class Autocomplete { } this.popup.show(pos, lineHeight); - }; + } openPopup(editor, prefix, keepPopupPosition) { if (!this.popup) @@ -151,7 +151,7 @@ class Autocomplete { this.detach(); } this.changeTimer.cancel(); - }; + } /** * Detaches all elements from the editor, and cleans up the data for the session @@ -178,7 +178,7 @@ class Autocomplete { this.base.detach(); this.activated = false; this.completionProvider = this.completions = this.base = null; - }; + } changeListener(e) { var cursor = this.editor.selection.lead; @@ -189,7 +189,7 @@ class Autocomplete { this.changeTimer.schedule(); else this.detach(); - }; + } blurListener(e) { // we have to check if activeElement is a child of popup because @@ -203,19 +203,19 @@ class Autocomplete { ) { this.detach(); } - }; + } mousedownListener(e) { this.detach(); - }; + } mousewheelListener(e) { this.detach(); - }; + } goTo(where) { this.popup.goTo(where); - }; + } insertMatch(data, options) { if (!data) @@ -228,29 +228,8 @@ class Autocomplete { if (this.completions == completions) this.detach(); return result; - }; - - commands = { - "Up": function(editor) { editor.completer.goTo("up"); }, - "Down": function(editor) { editor.completer.goTo("down"); }, - "Ctrl-Up|Ctrl-Home": function(editor) { editor.completer.goTo("start"); }, - "Ctrl-Down|Ctrl-End": function(editor) { editor.completer.goTo("end"); }, - - "Esc": function(editor) { editor.completer.detach(); }, - "Return": function(editor) { return editor.completer.insertMatch(); }, - "Shift-Return": function(editor) { editor.completer.insertMatch(null, {deleteSuffix: true}); }, - "Tab": function(editor) { - var result = editor.completer.insertMatch(); - if (!result && !editor.tabstopManager) - editor.completer.goTo("down"); - else - return result; - }, - - "PageUp": function(editor) { editor.completer.popup.gotoPageUp(); }, - "PageDown": function(editor) { editor.completer.popup.gotoPageDown(); } - }; - + } + /** * This is the entry point for the autocompletion class, triggers the actions which collect and display suggestions * @param {Editor} editor @@ -275,13 +254,13 @@ class Autocomplete { editor.on("mousewheel", this.mousewheelListener); this.updateCompletions(false, options); - }; + } getCompletionProvider() { if (!this.completionProvider) this.completionProvider = new CompletionProvider(); return this.completionProvider; - }; + } /** * This method is deprecated, it is only kept for backwards compatibility. @@ -290,7 +269,7 @@ class Autocomplete { */ gatherCompletions(editor, callback) { return this.getCompletionProvider().gatherCompletions(editor, callback); - }; + } updateCompletions(keepPopupPosition, options) { if (keepPopupPosition && this.base && this.completions) { @@ -343,11 +322,11 @@ class Autocomplete { this.completions = completions; this.openPopup(this.editor, prefix, keepPopupPosition); }.bind(this)); - }; + } cancelContextMenu() { this.editor.$mouseHandler.cancelContextMenu(); - }; + } updateDocTooltip() { var popup = this.popup; @@ -369,7 +348,7 @@ class Autocomplete { if (!doc || !(doc.docHTML || doc.docText)) return this.hideDocTooltip(); this.showDocTooltip(doc); - }; + } showDocTooltip(item) { if (!this.tooltipNode) { @@ -418,7 +397,7 @@ class Autocomplete { tooltipNode.style.left = (rect.right + 1) + "px"; tooltipNode.style.right = ""; } - }; + } hideDocTooltip() { this.tooltipTimer.cancel(); @@ -429,7 +408,7 @@ class Autocomplete { this.tooltipNode = null; if (el.parentNode) el.parentNode.removeChild(el); - }; + } onTooltipClick(e) { var a = e.target; @@ -441,7 +420,7 @@ class Autocomplete { } a = a.parentNode; } - }; + } destroy() { this.detach(); @@ -456,10 +435,31 @@ class Autocomplete { this.editor.completer = null; } this.inlineRenderer = this.popup = this.editor = null; - }; + } } +Autocomplete.prototype.commands = { + "Up": function(editor) { editor.completer.goTo("up"); }, + "Down": function(editor) { editor.completer.goTo("down"); }, + "Ctrl-Up|Ctrl-Home": function(editor) { editor.completer.goTo("start"); }, + "Ctrl-Down|Ctrl-End": function(editor) { editor.completer.goTo("end"); }, + + "Esc": function(editor) { editor.completer.detach(); }, + "Return": function(editor) { return editor.completer.insertMatch(); }, + "Shift-Return": function(editor) { editor.completer.insertMatch(null, {deleteSuffix: true}); }, + "Tab": function(editor) { + var result = editor.completer.insertMatch(); + if (!result && !editor.tabstopManager) + editor.completer.goTo("down"); + else + return result; + }, + + "PageUp": function(editor) { editor.completer.popup.gotoPageUp(); }, + "PageDown": function(editor) { editor.completer.popup.gotoPageDown(); } +}; + Autocomplete.for = function(editor) { if (editor.completer instanceof Autocomplete) { @@ -500,14 +500,14 @@ class CompletionProvider { constructor() { this.active = true; - }; + } insertByIndex(editor, index, options) { if (!this.completions || !this.completions.filtered) { return false; } return this.insertMatch(editor, this.completions.filtered[index], options); - }; + } insertMatch(editor, data, options) { if (!data) @@ -535,7 +535,7 @@ class CompletionProvider { } editor.endOperation(); return true; - }; + } gatherCompletions(editor, callback) { var session = editor.getSession(); @@ -558,7 +558,7 @@ class CompletionProvider { }); }); return true; - }; + } /** * This is the entry point to the class, it gathers, then provides the completions asynchronously via callback. @@ -616,11 +616,11 @@ class CompletionProvider { immediateResults = null; processResults(results); } - }; + } detach() { this.active = false; - }; + } } class FilteredList { @@ -630,7 +630,7 @@ class FilteredList { this.filterText = filterText || ""; this.exactMatch = false; this.ignoreCaption = false; - }; + } setFilter(str) { if (str.length > this.filterText && str.lastIndexOf(this.filterText, 0) === 0) @@ -655,7 +655,7 @@ class FilteredList { }); this.filtered = matches; - }; + } filterCompletions(items, needle) { var results = []; @@ -707,7 +707,7 @@ class FilteredList { results.push(item); } return results; - }; + } } exports.Autocomplete = Autocomplete; diff --git a/src/autocomplete/inline.js b/src/autocomplete/inline.js index b8853e14014..7239aee2c64 100644 --- a/src/autocomplete/inline.js +++ b/src/autocomplete/inline.js @@ -11,7 +11,7 @@ class AceInline { */ constructor() { this.editor = null; - }; + } /** * Renders the completion as ghost text to the current cursor position @@ -41,14 +41,14 @@ class AceInline { editor.setGhostText(displayText); } return true; - }; + } isOpen() { if (!this.editor) { return false; } return !!this.editor.renderer.$ghostText; - }; + } hide() { if (!this.editor) { @@ -56,12 +56,12 @@ class AceInline { } this.editor.removeGhostText(); return true; - }; + } destroy() { this.hide(); this.editor = null; - }; + } } diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js index f58e84a3aa8..397490c894a 100644 --- a/src/autocomplete/popup.js +++ b/src/autocomplete/popup.js @@ -382,7 +382,7 @@ class AcePopup { popup.$borderSize = 1; return popup; - }; + } } dom.importCssString(` diff --git a/src/background_tokenizer.js b/src/background_tokenizer.js index d31b3c289b1..2729e38d93e 100644 --- a/src/background_tokenizer.js +++ b/src/background_tokenizer.js @@ -62,7 +62,7 @@ class BackgroundTokenizer { if (startLine <= endLine) self.fireUpdateEvent(startLine, endLine); }; - }; + } /** * Sets a new tokenizer for this object. @@ -74,7 +74,7 @@ class BackgroundTokenizer { this.states = []; this.start(0); - }; + } /** * Sets a new document to associate with this object. @@ -86,7 +86,7 @@ class BackgroundTokenizer { this.states = []; this.stop(); - }; + } /** * Fires whenever the background tokeniziers between a range of rows are going to be updated. @@ -106,7 +106,7 @@ class BackgroundTokenizer { last: lastRow }; this._signal("update", {data: data}); - }; + } /** * Starts tokenizing at the row indicated. @@ -122,7 +122,7 @@ class BackgroundTokenizer { this.stop(); // pretty long delay to prevent the tokenizer from interfering with the user this.running = setTimeout(this.$worker, 700); - }; + } /** * Sets pretty long delay to prevent the tokenizer from interfering with the user @@ -130,7 +130,7 @@ class BackgroundTokenizer { scheduleStart() { if (!this.running) this.running = setTimeout(this.$worker, 700); - }; + } $updateOnChange(delta) { var startRow = delta.start.row; @@ -151,7 +151,7 @@ class BackgroundTokenizer { this.currentLine = Math.min(startRow, this.currentLine, this.doc.getLength()); this.stop(); - }; + } /** * Stops tokenizing. @@ -160,7 +160,7 @@ class BackgroundTokenizer { if (this.running) clearTimeout(this.running); this.running = false; - }; + } /** * Gives list of [[Token]]'s of the row. (tokens are cached) @@ -169,7 +169,7 @@ class BackgroundTokenizer { **/ getTokens(row) { return this.lines[row] || this.$tokenizeRow(row); - }; + } /** * Returns the state of tokenization at the end of a row. @@ -180,7 +180,7 @@ class BackgroundTokenizer { if (this.currentLine == row) this.$tokenizeRow(row); return this.states[row] || "start"; - }; + } $tokenizeRow(row) { var line = this.doc.getLine(row); @@ -198,15 +198,15 @@ class BackgroundTokenizer { } return this.lines[row] = data.tokens; - }; + } - cleanup = function() { + cleanup() { this.running = false; this.lines = []; this.states = []; this.currentLine = 0; this.removeAllListeners(); - }; + } } diff --git a/src/bidihandler.js b/src/bidihandler.js index 348d5fd0d28..8b065f83da6 100644 --- a/src/bidihandler.js +++ b/src/bidihandler.js @@ -35,7 +35,7 @@ class BidiHandler { this.wrapOffset = 0; this.isMoveLeftOperation = false; this.seenBidi = bidiRE.test(session.getValue()); - }; + } /** * Returns 'true' if row contains Bidi characters, in such case @@ -54,7 +54,7 @@ class BidiHandler { this.updateBidiMap(); } return this.bidiMap.bidiLevels; - }; + } onChange(delta) { if (!this.seenBidi) { @@ -66,7 +66,7 @@ class BidiHandler { else { this.currentRow = null; } - }; + } getDocumentRow() { var docRow = 0; @@ -78,7 +78,7 @@ class BidiHandler { } return docRow; - }; + } getSplitIndex() { var splitIndex = 0; @@ -98,7 +98,7 @@ class BidiHandler { } return splitIndex; - }; + } updateRowLine(docRow, splitIndex) { if (docRow === undefined) @@ -149,7 +149,7 @@ class BidiHandler { this.fontMetrics.$main.textContent = (this.line.charAt(this.line.length - 1) == bidiUtil.DOT) ? this.line.substr(0, this.line.length - 1) : this.line; this.rtlLineOffset = this.contentWidth - this.fontMetrics.$main.getBoundingClientRect().width; } - }; + } updateBidiMap() { var textCharTypes = []; @@ -158,14 +158,14 @@ class BidiHandler { } else { this.bidiMap = {}; } - }; + } /** * Resets stored info related to current screen row **/ markAsDirty() { this.currentRow = null; - }; + } /** * Updates array of character widths @@ -186,20 +186,20 @@ class BidiHandler { this.charWidths[bidiUtil.B] = this.charWidths[bidiUtil.RLE] = 0; this.currentRow = null; - }; + } setShowInvisibles(showInvisibles) { this.showInvisibles = showInvisibles; this.currentRow = null; - }; + } setEolChar(eolChar) { this.EOL = eolChar; - }; + } setContentWidth(width) { this.contentWidth = width; - }; + } isRtlLine(row) { if (this.$isRtl) return true; @@ -207,7 +207,7 @@ class BidiHandler { return (this.session.getLine(row).charAt(0) == this.RLE); else return this.isRtlDir; - }; + } setRtlDirection(editor, isRtlDir) { var cursor = editor.getCursorPosition(); @@ -217,7 +217,7 @@ class BidiHandler { else if (isRtlDir && editor.session.getLine(row).charAt(0) !== editor.session.$bidiHandler.RLE) editor.session.doc.insert({column: 0, row: row}, editor.session.$bidiHandler.RLE); } - }; + } /** @@ -226,7 +226,7 @@ class BidiHandler { * * @return {Number} horizontal pixel offset of given screen column **/ - getPosLeft = function(col) { + getPosLeft(col) { col -= this.wrapIndent; var leftBoundary = (this.line.charAt(0) === this.RLE) ? 1 : 0; var logicalIdx = (col > leftBoundary) ? (this.session.getOverwrite() ? col : col - 1) : leftBoundary; @@ -250,7 +250,7 @@ class BidiHandler { left += this.rtlLineOffset; return left; - }; + } /** * Returns 'selections' - array of objects defining set of selection rectangles @@ -259,7 +259,7 @@ class BidiHandler { * * @return {Object[]} Each object contains 'left' and 'width' values defining selection rectangle. **/ - getSelections = function(startCol, endCol) { + getSelections(startCol, endCol) { var map = this.bidiMap, levels = map.bidiLevels, level, selections = [], offset = 0, selColMin = Math.min(startCol, endCol) - this.wrapIndent, selColMax = Math.max(startCol, endCol) - this.wrapIndent, isSelected = false, isSelectedPrev = false, selectionStart = 0; @@ -290,7 +290,7 @@ class BidiHandler { } } return selections; - }; + } /** * Converts character coordinates on the screen to respective document column number @@ -348,7 +348,7 @@ class BidiHandler { logicalIdx++; return (logicalIdx + this.wrapIndent); - }; + } } diff --git a/src/commands/command_manager.js b/src/commands/command_manager.js index 2e20962f9b9..76d1ba9bee1 100644 --- a/src/commands/command_manager.js +++ b/src/commands/command_manager.js @@ -19,7 +19,7 @@ class CommandManager extends MultiHashHandler{ } return e.command.exec(e.editor, e.args, e.event, false); }); - }; + } exec(command, editor, args) { if (Array.isArray(command)) { @@ -46,7 +46,7 @@ class CommandManager extends MultiHashHandler{ this._signal("afterExec", e); return e.returnValue === false ? false : true; - }; + } toggleRecording(editor) { if (this.$inReplay) @@ -72,7 +72,7 @@ class CommandManager extends MultiHashHandler{ this.macro = []; this.on("exec", this.$addCommandToMacro); return this.recording = true; - }; + } replay(editor) { if (this.$inReplay || !this.macro) @@ -92,7 +92,7 @@ class CommandManager extends MultiHashHandler{ } finally { this.$inReplay = false; } - }; + } trimMacro(m) { return m.map(function(x){ @@ -102,7 +102,7 @@ class CommandManager extends MultiHashHandler{ x = x[0]; return x; }); - }; + } } oop.implement(CommandManager.prototype, EventEmitter); diff --git a/src/config.js b/src/config.js index 3b12f54bb61..42a30987b32 100644 --- a/src/config.js +++ b/src/config.js @@ -1,7 +1,6 @@ "no use strict"; var lang = require("./lib/lang"); -var oop = require("./lib/oop"); var net = require("./lib/net"); var dom = require("./lib/dom"); var AppConfig = require("./lib/app_config").AppConfig; diff --git a/src/document.js b/src/document.js index a3cac10f84f..171e5f80d6e 100644 --- a/src/document.js +++ b/src/document.js @@ -28,7 +28,7 @@ class Document { } else { this.insert({row: 0, column:0}, textOrLines); } - }; + } /** * Replaces all the lines in the current `Document` with the value of `text`. @@ -39,14 +39,14 @@ class Document { var len = this.getLength() - 1; this.remove(new Range(0, 0, len, this.getLine(len).length)); this.insert({row: 0, column: 0}, text || ""); - }; + } /** * Returns all the lines in the document as a single string, joined by the new line character. **/ getValue() { return this.getAllLines().join(this.getNewLineCharacter()); - }; + } /** * Creates a new `Anchor` to define a floating point in the document. @@ -56,28 +56,13 @@ class Document { **/ createAnchor(row, column) { return new Anchor(this, row, column); - }; - - /** - * Splits a string of text on any newline (`\n`) or carriage-return (`\r`) characters. - * - * @method $split - * @param {String} text The text to work with - * @returns {String} A String array, with each index containing a piece of the original `text` string. - * - **/ - // check for IE split bug - $split = ("aaa".split(/a/).length === 0) ? function (text) { - return text.replace(/\r\n|\r/g, "\n").split("\n"); - } : function (text) { - return text.split(/\r\n|\r|\n/); - }; + } $detectNewLine(text) { var match = text.match(/^.*?(\r\n|\r|\n)/m); this.$autoNewLine = match ? match[1] : "\n"; this._signal("changeNewLineMode"); - }; + } /** * Returns the newline character that's being used, depending on the value of `newLineMode`. @@ -95,10 +80,8 @@ class Document { default: return this.$autoNewLine || "\n"; } - }; + } - $autoNewLine = ""; - $newLineMode = "auto"; /** * [Sets the new line mode.]{: #Document.setNewLineMode.desc} * @param {String} newLineMode [The newline mode to use; can be either `windows`, `unix`, or `auto`]{: #Document.setNewLineMode.param} @@ -110,7 +93,7 @@ class Document { this.$newLineMode = newLineMode; this._signal("changeNewLineMode"); - }; + } /** * [Returns the type of newlines being used; either `windows`, `unix`, or `auto`]{: #Document.getNewLineMode} @@ -118,7 +101,7 @@ class Document { **/ getNewLineMode() { return this.$newLineMode; - }; + } /** * Returns `true` if `text` is a newline character (either `\r\n`, `\r`, or `\n`). @@ -127,7 +110,7 @@ class Document { **/ isNewLine(text) { return (text == "\r\n" || text == "\r" || text == "\n"); - }; + } /** * Returns a verbatim copy of the given line as it is in the document @@ -136,7 +119,7 @@ class Document { **/ getLine(row) { return this.$lines[row] || ""; - }; + } /** * Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`. @@ -146,21 +129,21 @@ class Document { **/ getLines(firstRow, lastRow) { return this.$lines.slice(firstRow, lastRow + 1); - }; + } /** * Returns all lines in the document as string array. **/ getAllLines() { return this.getLines(0, this.getLength()); - }; + } /** * Returns the number of rows in the document. **/ getLength() { return this.$lines.length; - }; + } /** * Returns all the text within `range` as a single string. @@ -170,7 +153,7 @@ class Document { **/ getTextRange(range) { return this.getLinesForRange(range).join(this.getNewLineCharacter()); - }; + } /** * Returns all the text within `range` as an array of lines. @@ -192,21 +175,21 @@ class Document { lines[l] = lines[l].substring(0, range.end.column); } return lines; - }; + } // Deprecated methods retained for backwards compatibility. insertLines(row, lines) { console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."); return this.insertFullLines(row, lines); - }; + } removeLines(firstRow, lastRow) { console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."); return this.removeFullLines(firstRow, lastRow); - }; + } insertNewLine(position) { console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."); return this.insertMergedLines(position, ["", ""]); - }; + } /** * Inserts a block of `text` at the indicated `position`. @@ -221,7 +204,7 @@ class Document { this.$detectNewLine(text); return this.insertMergedLines(position, this.$split(text)); - }; + } /** * Inserts `text` into the `position` at the current row. This method also triggers the `"change"` event. @@ -249,7 +232,7 @@ class Document { }, true); return this.clonePos(end); - }; + } clippedPos(row, column) { var length = this.getLength(); @@ -266,15 +249,15 @@ class Document { column = line.length; column = Math.min(Math.max(column, 0), line.length); return {row: row, column: column}; - }; + } clonePos(pos) { return {row: pos.row, column: pos.column}; - }; + } pos(row, column) { return {row: row, column: column}; - }; + } $clipPosition(position) { var length = this.getLength(); @@ -286,7 +269,7 @@ class Document { position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length); } return position; - }; + } /** * Fires whenever the document changes. @@ -339,7 +322,7 @@ class Document { // Insert. this.insertMergedLines({row: row, column: column}, lines); - }; + } /** * Inserts the elements in `lines` into the document, starting at the position index given by `row`. This method also triggers the `"change"` event. @@ -370,7 +353,7 @@ class Document { }); return this.clonePos(end); - }; + } /** * Removes the `range` from the document. @@ -388,7 +371,7 @@ class Document { lines: this.getLinesForRange({start: start, end: end}) }); return this.clonePos(start); - }; + } /** * Removes the specified columns from the `row`. This method also triggers a `"change"` event. @@ -410,7 +393,7 @@ class Document { }, true); return this.clonePos(start); - }; + } /** * Removes a range of full lines. This method also triggers the `"change"` event. @@ -447,7 +430,7 @@ class Document { // Return the deleted lines. return deletedLines; - }; + } /** * Removes the new line between `row` and the row immediately following it. This method also triggers the `"change"` event. @@ -463,7 +446,7 @@ class Document { lines: ["", ""] }); } - }; + } /** * Replaces a range in the document with the new `text`. @@ -496,7 +479,7 @@ class Document { } return end; - }; + } /** * Applies all changes in `deltas` to the document. @@ -506,7 +489,7 @@ class Document { for (var i=0; i=0; i--) { this.revertDelta(deltas[i]); } - }; + } /** * Applies `delta` to the document. @@ -538,7 +521,7 @@ class Document { applyDelta(this.$lines, delta, doNotValidate); this._signal("change", delta); } - }; + } $safeApplyDelta(delta) { var docLength = this.$lines.length; @@ -549,7 +532,7 @@ class Document { ) { this.applyDelta(delta); } - }; + } $splitAndapplyLargeDelta(delta, MAX) { // Split large insert deltas. This is necessary because: @@ -581,7 +564,7 @@ class Document { delta.start.row = row + from; delta.start.column = column; this.applyDelta(delta, true); - }; + } /** * Reverts `delta` from the document. @@ -594,7 +577,7 @@ class Document { action: (delta.action == "insert" ? "remove" : "insert"), lines: delta.lines.slice() }); - }; + } /** * Converts an index position in a document to a `{row, column}` object. @@ -621,7 +604,7 @@ class Document { return {row: i, column: index + lines[i].length + newlineLength}; } return {row: l-1, column: index + lines[l-1].length + newlineLength}; - }; + } /** * Converts the `{row, column}` position in a document to the character's index. @@ -648,10 +631,27 @@ class Document { index += lines[i].length + newlineLength; return index + pos.column; - }; + } } +/** + * Splits a string of text on any newline (`\n`) or carriage-return (`\r`) characters. + * + * @method $split + * @param {String} text The text to work with + * @returns {String} A String array, with each index containing a piece of the original `text` string. + * + **/ +// check for IE split bug +Document.prototype.$split = ("aaa".split(/a/).length === 0) ? function (text) { + return text.replace(/\r\n|\r/g, "\n").split("\n"); +} : function (text) { + return text.split(/\r\n|\r|\n/); +}; +Document.prototype.$autoNewLine = ""; +Document.prototype.$newLineMode = "auto"; + oop.implement(Document.prototype, EventEmitter); exports.Document = Document; diff --git a/src/edit_session.js b/src/edit_session.js index 2069d701a13..e6fd6f9587d 100644 --- a/src/edit_session.js +++ b/src/edit_session.js @@ -101,8 +101,6 @@ var SearchHighlight = require("./search_highlight").SearchHighlight; **/ class EditSession { - static $uid = 0; - /** * Sets up a new `EditSession` and associates it with the given `Document` and `Mode`. * @param {Document | String} text [If `text` is a `Document`, it associates the `EditSession` with it. Otherwise, a new `Document` is created, with the initial text]{: #textParam} @@ -145,7 +143,7 @@ class EditSession { config._signal("session", this); this.destroyed = false; - }; + } /** * Sets the `EditSession` to point to a new `Document`. If a `BackgroundTokenizer` exists, it also points to `doc`. @@ -163,7 +161,7 @@ class EditSession { this.bgTokenizer.setDocument(this.getDocument()); this.resetCaches(); - }; + } /** * Returns the `Document` associated with this session. @@ -171,7 +169,7 @@ class EditSession { **/ getDocument() { return this.doc; - }; + } /** * @param {Number} docRow The row to work with @@ -189,7 +187,7 @@ class EditSession { this.$docRowCache.splice(i, l); this.$screenRowCache.splice(i, l); } - }; + } $getRowCacheIndex(cacheArray, val) { var low = 0; @@ -208,7 +206,7 @@ class EditSession { } return low -1; - }; + } resetCaches() { this.$modified = true; @@ -217,12 +215,12 @@ class EditSession { this.$resetRowCache(0); if (!this.destroyed) this.bgTokenizer.start(0); - }; + } onChangeFold(e) { var fold = e.data; this.$resetRowCache(fold.start.row); - }; + } onChange(delta) { this.$modified = true; @@ -246,7 +244,7 @@ class EditSession { this.bgTokenizer.$updateOnChange(delta); this._signal("change", delta); - }; + } /** * Sets the session text. @@ -260,7 +258,7 @@ class EditSession { this.$resetRowCache(0); this.setUndoManager(this.$undoManager); this.getUndoManager().reset(); - }; + } /** * Returns the current [[Document `Document`]] as a string. @@ -269,24 +267,16 @@ class EditSession { * @alias EditSession.getValue * **/ - toString = function() { + toString() { return this.doc.getValue(); - }; - - /** - * Returns the current [[Document `Document`]] as a string. - * @method getValue - * @returns {String} - * @alias EditSession.toString - **/ - getValue = this.toString; + } /** * Returns selection object. **/ getSelection() { return this.selection; - }; + } /** * {:BackgroundTokenizer.getState} @@ -296,7 +286,7 @@ class EditSession { **/ getState(row) { return this.bgTokenizer.getState(row); - }; + } /** * Starts tokenizing at the row indicated. Returns a list of objects of the tokenized rows. @@ -305,7 +295,7 @@ class EditSession { **/ getTokens(row) { return this.bgTokenizer.getTokens(row); - }; + } /** * Returns an object indicating the token at the current row. The object has two properties: `index` and `start`. @@ -333,7 +323,7 @@ class EditSession { token.index = i; token.start = c - token.value.length; return token; - }; + } /** * Sets the undo manager. @@ -358,7 +348,7 @@ class EditSession { } else { this.$syncInformUndoManager = function() {}; } - }; + } /** * starts a new group in undo history @@ -366,26 +356,14 @@ class EditSession { markUndoGroup() { if (this.$syncInformUndoManager) this.$syncInformUndoManager(); - }; - - $defaultUndoManager = { - undo: function() {}, - redo: function() {}, - hasUndo: function() {}, - hasRedo: function() {}, - reset: function() {}, - add: function() {}, - addSelection: function() {}, - startNewGroup: function() {}, - addSession: function() {} - }; + } /** * Returns the current undo manager. **/ getUndoManager() { return this.$undoManager || this.$defaultUndoManager; - }; + } /** * Returns the current value for tabs. If the user is using soft tabs, this will be a series of spaces (defined by [[EditSession.getTabSize `getTabSize()`]]); otherwise it's simply `'\t'`. @@ -396,7 +374,7 @@ class EditSession { } else { return "\t"; } - }; + } /** * Pass `true` to enable the use of soft tabs. Soft tabs means you're using spaces instead of the tab character (`'\t'`). @@ -404,7 +382,7 @@ class EditSession { **/ setUseSoftTabs(val) { this.setOption("useSoftTabs", val); - }; + } /** * Returns `true` if soft tabs are being used, `false` otherwise. @@ -413,20 +391,20 @@ class EditSession { getUseSoftTabs() { // todo might need more general way for changing settings from mode, but this is ok for now return this.$useSoftTabs && !this.$mode.$indentWithTabs; - }; + } /** * Set the number of spaces that define a soft tab; for example, passing in `4` transforms the soft tabs to be equivalent to four spaces. This function also emits the `changeTabSize` event. * @param {Number} tabSize The new tab size **/ setTabSize(tabSize) { this.setOption("tabSize", tabSize); - }; + } /** * Returns the current tab size. **/ getTabSize() { return this.$tabSize; - }; + } /** * Returns `true` if the character at the position is a soft tab. @@ -435,7 +413,7 @@ class EditSession { **/ isTabStop(position) { return this.$useSoftTabs && (position.column % this.$tabSize === 0); - }; + } /** * Set whether keyboard navigation of soft tabs moves the cursor within the soft tab, rather than over @@ -443,16 +421,15 @@ class EditSession { **/ setNavigateWithinSoftTabs(navigateWithinSoftTabs) { this.setOption("navigateWithinSoftTabs", navigateWithinSoftTabs); - }; + } /** * Returns `true` if keyboard navigation moves the cursor within soft tabs, `false` if it moves the cursor over soft tabs. * @returns {Boolean} **/ getNavigateWithinSoftTabs() { return this.$navigateWithinSoftTabs; - }; + } - $overwrite = false; /** * Pass in `true` to enable overwrites in your session, or `false` to disable. * @@ -464,21 +441,21 @@ class EditSession { **/ setOverwrite(overwrite) { this.setOption("overwrite", overwrite); - }; + } /** * Returns `true` if overwrites are enabled; `false` otherwise. **/ getOverwrite() { return this.$overwrite; - }; + } /** * Sets the value of overwrite to the opposite of whatever it currently is. **/ toggleOverwrite() { this.setOverwrite(!this.$overwrite); - }; + } /** * Adds `className` to the `row`, to be used for CSS stylings and whatnot. @@ -491,7 +468,7 @@ class EditSession { this.$decorations[row] = ""; this.$decorations[row] += " " + className; this._signal("changeBreakpoint", {}); - }; + } /** * Removes `className` from the `row`. @@ -502,7 +479,7 @@ class EditSession { removeGutterDecoration(row, className) { this.$decorations[row] = (this.$decorations[row] || "").replace(" " + className, ""); this._signal("changeBreakpoint", {}); - }; + } /** * Returns an array of strings, indicating the breakpoint class (if any) applied to each row. @@ -510,7 +487,7 @@ class EditSession { **/ getBreakpoints() { return this.$breakpoints; - }; + } /** * Sets a breakpoint on every row number given by `rows`. This function also emites the `'changeBreakpoint'` event. @@ -523,7 +500,7 @@ class EditSession { this.$breakpoints[rows[i]] = "ace_breakpoint"; } this._signal("changeBreakpoint", {}); - }; + } /** * Removes all breakpoints on the rows. This function also emits the `'changeBreakpoint'` event. @@ -531,7 +508,7 @@ class EditSession { clearBreakpoints() { this.$breakpoints = []; this._signal("changeBreakpoint", {}); - }; + } /** * Sets a breakpoint on the row number given by `row`. This function also emits the `'changeBreakpoint'` event. @@ -547,7 +524,7 @@ class EditSession { else delete this.$breakpoints[row]; this._signal("changeBreakpoint", {}); - }; + } /** * Removes a breakpoint on the row number given by `row`. This function also emits the `'changeBreakpoint'` event. @@ -557,7 +534,7 @@ class EditSession { clearBreakpoint(row) { delete this.$breakpoints[row]; this._signal("changeBreakpoint", {}); - }; + } /** * Adds a new marker to the given `Range`. If `inFront` is `true`, a front marker is defined, and the `'changeFrontMarker'` event fires; otherwise, the `'changeBackMarker'` event fires. @@ -589,7 +566,7 @@ class EditSession { } return id; - }; + } /** * Adds a dynamic marker to the session. @@ -614,7 +591,7 @@ class EditSession { } return marker; - }; + } /** * Removes the marker with the specified ID. If this marker was in front, the `'changeFrontMarker'` event is emitted. If the marker was in the back, the `'changeBackMarker'` event is emitted. @@ -629,7 +606,7 @@ class EditSession { var markers = marker.inFront ? this.$frontMarkers : this.$backMarkers; delete (markers[markerId]); this._signal(marker.inFront ? "changeFrontMarker" : "changeBackMarker"); - }; + } /** * Returns an object containing all of the markers, either front or back. @@ -639,7 +616,7 @@ class EditSession { **/ getMarkers(inFront) { return inFront ? this.$frontMarkers : this.$backMarkers; - }; + } highlight(re) { if (!this.$searchHighlight) { @@ -647,7 +624,7 @@ class EditSession { this.$searchHighlight = this.addDynamicMarker(highlight); } this.$searchHighlight.setRegexp(re); - }; + } // experimental highlightLines(startRow, endRow, clazz, inFront) { @@ -661,7 +638,7 @@ class EditSession { var range = new Range(startRow, 0, endRow, Infinity); range.id = this.addMarker(range, clazz, "fullLine", inFront); return range; - }; + } /* * Error: @@ -680,7 +657,7 @@ class EditSession { setAnnotations(annotations) { this.$annotations = annotations; this._signal("changeAnnotation", {}); - }; + } /** * Returns the annotations for the `EditSession`. @@ -688,14 +665,14 @@ class EditSession { **/ getAnnotations() { return this.$annotations || []; - }; + } /** * Clears all the annotations for this session. This function also triggers the `'changeAnnotation'` event. **/ clearAnnotations() { this.setAnnotations([]); - }; + } /** * If `text` contains either the newline (`\n`) or carriage-return ('\r') characters, `$autoNewLine` stores that value. @@ -709,7 +686,7 @@ class EditSession { } else { this.$autoNewLine = "\n"; } - }; + } /** * Given a starting row and column, this method returns the `Range` of the first word boundary it finds. @@ -750,7 +727,7 @@ class EditSession { } return new Range(row, start, row, end); - }; + } /** * Gets the range of a word, including its right whitespace. @@ -767,7 +744,7 @@ class EditSession { wordRange.end.column += 1; } return wordRange; - }; + } /** * {:Document.setNewLineMode.desc} @@ -778,7 +755,7 @@ class EditSession { **/ setNewLineMode(newLineMode) { this.doc.setNewLineMode(newLineMode); - }; + } /** * @@ -788,19 +765,19 @@ class EditSession { **/ getNewLineMode() { return this.doc.getNewLineMode(); - }; + } /** * Identifies if you want to use a worker for the `EditSession`. * @param {Boolean} useWorker Set to `true` to use a worker * **/ - setUseWorker(useWorker) { this.setOption("useWorker", useWorker); }; + setUseWorker(useWorker) { this.setOption("useWorker", useWorker); } /** * Returns `true` if workers are being used. **/ - getUseWorker() { return this.$useWorker; }; + getUseWorker() { return this.$useWorker; } /** * Reloads all the tokens on the current session. This function calls [[BackgroundTokenizer.start `BackgroundTokenizer.start ()`]] to all the rows; it also emits the `'tokenizerUpdate'` event. @@ -809,14 +786,7 @@ class EditSession { var rows = e.data; this.bgTokenizer.start(rows.first); this._signal("tokenizerUpdate", e); - }; - - /** - * - * @type {TextMode|null} - */ - $mode = null; - $modeId = null; + } /** * Sets a new text mode for the `EditSession`. This method also emits the `'changeMode'` event. If a [[BackgroundTokenizer `BackgroundTokenizer`]] is set, the `'tokenizerUpdate'` event is also emitted. @@ -864,7 +834,7 @@ class EditSession { // set mode to text until loading is finished if (!this.$mode) this.$onChangeMode(this.$modes["ace/mode/text"], true); - }; + } $onChangeMode(mode, $isPlaceholder) { if (!$isPlaceholder) @@ -903,14 +873,14 @@ class EditSession { this.bgTokenizer.start(0); this._emit("changeMode", {oldMode: oldMode, mode: mode}); } - }; + } $stopWorker() { if (this.$worker) { this.$worker.terminate(); this.$worker = null; } - }; + } $startWorker() { try { @@ -919,7 +889,7 @@ class EditSession { config.warn("Could not load worker", e); this.$worker = null; } - }; + } /** * Returns the current text mode. @@ -927,9 +897,8 @@ class EditSession { **/ getMode() { return this.$mode; - }; + } - $scrollTop = 0; /** * This function sets the scroll top value. It also emits the `'changeScrollTop'` event. * @param {Number} scrollTop The new scroll top value @@ -942,7 +911,7 @@ class EditSession { this.$scrollTop = scrollTop; this._signal("changeScrollTop", scrollTop); - }; + } /** * [Returns the value of the distance between the top of the editor and the topmost part of the visible content.]{: #EditSession.getScrollTop} @@ -950,9 +919,8 @@ class EditSession { **/ getScrollTop() { return this.$scrollTop; - }; + } - $scrollLeft = 0; /** * [Sets the value of the distance between the left of the editor and the leftmost part of the visible content.]{: #EditSession.setScrollLeft} **/ @@ -963,7 +931,7 @@ class EditSession { this.$scrollLeft = scrollLeft; this._signal("changeScrollLeft", scrollLeft); - }; + } /** * [Returns the value of the distance between the left of the editor and the leftmost part of the visible content.]{: #EditSession.getScrollLeft} @@ -971,7 +939,7 @@ class EditSession { **/ getScrollLeft() { return this.$scrollLeft; - }; + } /** * Returns the width of the screen. @@ -982,7 +950,7 @@ class EditSession { if (this.lineWidgets) return Math.max(this.getLineWidgetMaxWidth(), this.screenWidth); return this.screenWidth; - }; + } getLineWidgetMaxWidth() { if (this.lineWidgetsWidth != null) return this.lineWidgetsWidth; @@ -992,7 +960,7 @@ class EditSession { width = w.screenWidth; }); return this.lineWidgetWidth = width; - }; + } $computeWidth(force) { if (this.$modified || force) { @@ -1026,7 +994,7 @@ class EditSession { } this.screenWidth = longestScreenLine; } - }; + } /** * Returns a verbatim copy of the given line as it is in the document @@ -1036,7 +1004,7 @@ class EditSession { **/ getLine(row) { return this.doc.getLine(row); - }; + } /** * Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`. @@ -1048,7 +1016,7 @@ class EditSession { **/ getLines(firstRow, lastRow) { return this.doc.getLines(firstRow, lastRow); - }; + } /** * Returns the number of rows in the document. @@ -1056,7 +1024,7 @@ class EditSession { **/ getLength() { return this.doc.getLength(); - }; + } /** * {:Document.getTextRange.desc} @@ -1066,7 +1034,7 @@ class EditSession { **/ getTextRange(range) { return this.doc.getTextRange(range || this.selection.getRange()); - }; + } /** * Inserts a block of `text` and the indicated `position`. @@ -1078,7 +1046,7 @@ class EditSession { **/ insert(position, text) { return this.doc.insert(position, text); - }; + } /** * Removes the `range` from the document. @@ -1090,7 +1058,7 @@ class EditSession { **/ remove(range) { return this.doc.remove(range); - }; + } /** * Removes a range of full lines. This method also triggers the `'change'` event. @@ -1103,7 +1071,7 @@ class EditSession { **/ removeFullLines(firstRow, lastRow){ return this.doc.removeFullLines(firstRow, lastRow); - }; + } /** * Reverts previous changes to your document. @@ -1130,7 +1098,7 @@ class EditSession { this.selection.setRange(this.$getUndoSelection(deltas, true)); } this.$fromUndo = false; - }; + } /** * Re-implements a previously undone change to your document. @@ -1156,7 +1124,7 @@ class EditSession { this.selection.setRange(this.$getUndoSelection(deltas, false)); } this.$fromUndo = false; - }; + } /** * Enables or disables highlighting of the range where an undo occurred. @@ -1165,7 +1133,7 @@ class EditSession { **/ setUndoSelect(enable) { this.$undoSelect = enable; - }; + } $getUndoSelection(deltas, isUndo) { function isInsert(delta) { @@ -1203,7 +1171,7 @@ class EditSession { } } return range; - }; + } /** * Replaces a range in the document with the new `text`. @@ -1221,7 +1189,7 @@ class EditSession { **/ replace(range, text) { return this.doc.replace(range, text); - }; + } /** * Moves a range of text from the given range to the given position. `toPosition` is an object that looks like this: @@ -1273,7 +1241,7 @@ class EditSession { } return toRange; - }; + } /** * Indents all the rows, from `startRow` to `endRow` (inclusive), by prefixing each row with the token in `indentString`. @@ -1287,7 +1255,7 @@ class EditSession { indentString = indentString.replace(/\t/g, this.getTabString()); for (var row=startRow; row<=endRow; row++) this.doc.insertInLine({row: row, column: 0}, indentString); - }; + } /** * Outdents all the rows defined by the `start` and `end` properties of `range`. @@ -1316,7 +1284,7 @@ class EditSession { } this.remove(deleteRange); } - }; + } $moveLines(firstRow, lastRow, dir) { firstRow = this.getRowFoldStart(firstRow); @@ -1349,7 +1317,7 @@ class EditSession { this.doc.insertFullLines(firstRow+diff, lines); folds.length && this.addFolds(folds); return diff; - }; + } /** * Shifts all the lines in the document up one, starting from `firstRow` and ending at `lastRow`. * @param {Number} firstRow The starting row to move up @@ -1359,7 +1327,7 @@ class EditSession { **/ moveLinesUp(firstRow, lastRow) { return this.$moveLines(firstRow, lastRow, -1); - }; + } /** * Shifts all the lines in the document down one, starting from `firstRow` and ending at `lastRow`. @@ -1369,7 +1337,7 @@ class EditSession { **/ moveLinesDown(firstRow, lastRow) { return this.$moveLines(firstRow, lastRow, 1); - }; + } /** * Duplicates all the text between `firstRow` and `lastRow`. @@ -1379,17 +1347,17 @@ class EditSession { **/ duplicateLines(firstRow, lastRow) { return this.$moveLines(firstRow, lastRow, 0); - }; + } $clipRowToDocument(row) { return Math.max(0, Math.min(row, this.doc.getLength()-1)); - }; + } $clipColumnToRow(row, column) { if (column < 0) return 0; return Math.min(this.doc.getLine(row).length, column); - }; + } $clipPositionToDocument(row, column) { column = Math.max(0, column); @@ -1411,7 +1379,7 @@ class EditSession { row: row, column: column }; - }; + } $clipRangeToDocument(range) { if (range.start.row < 0) { @@ -1435,16 +1403,8 @@ class EditSession { ); } return range; - }; - - // WRAPMODE - $wrapLimit = 80; - $useWrapMode = false; - $wrapLimitRange = { - min : null, - max : null - }; - + } + /** * Sets whether or not line wrapping is enabled. If `useWrapMode` is different than the current value, the `'changeWrapMode'` event is emitted. * @param {Boolean} useWrapMode Enable (or disable) wrap mode @@ -1465,7 +1425,7 @@ class EditSession { this._signal("changeWrapMode"); } - }; + } /** * Returns `true` if wrap mode is being used; `false` otherwise. @@ -1473,7 +1433,7 @@ class EditSession { **/ getUseWrapMode() { return this.$useWrapMode; - }; + } // Allow the wrap limit to move freely between min and max. Either // parameter can be null to allow the wrap limit to be unconstrained @@ -1495,7 +1455,7 @@ class EditSession { if (this.$useWrapMode) this._signal("changeWrapMode"); } - }; + } /** * This should generally only be called by the renderer when a resize is detected. @@ -1520,7 +1480,7 @@ class EditSession { return true; } return false; - }; + } $constrainWrapLimit(wrapLimit, min, max) { if (min) @@ -1530,7 +1490,7 @@ class EditSession { wrapLimit = Math.min(max, wrapLimit); return wrapLimit; - }; + } /** * Returns the value of wrap limit. @@ -1538,7 +1498,7 @@ class EditSession { **/ getWrapLimit() { return this.$wrapLimit; - }; + } /** * Sets the line length for soft wrap in the editor. Lines will break @@ -1548,7 +1508,7 @@ class EditSession { */ setWrapLimit(limit) { this.setWrapLimitRange(limit, limit); - }; + } /** * Returns an object that defines the minimum and maximum of the wrap limit; it looks something like this: @@ -1563,7 +1523,7 @@ class EditSession { min : this.$wrapLimitRange.min, max : this.$wrapLimitRange.max }; - }; + } $updateInternalDataOnChange(delta) { var useWrapMode = this.$useWrapMode; @@ -1671,12 +1631,12 @@ class EditSession { this.$updateRowLengthCache(firstRow, lastRow); return removedFolds; - }; + } $updateRowLengthCache(firstRow, lastRow, b) { this.$rowLengthCache[firstRow] = null; this.$rowLengthCache[lastRow] = null; - }; + } $updateWrapData(firstRow, lastRow) { var lines = this.doc.getAllLines(); @@ -1720,7 +1680,7 @@ class EditSession { row = foldLine.end.row + 1; } } - }; + } $computeWrapSplits(tokens, wrapLimit, tabSize) { if (tokens.length == 0) { @@ -1869,7 +1829,7 @@ class EditSession { addSplit(split - indent); } return splits; - }; + } /** * Given a string, returns an array of the display characters, including tabs and spaces. @@ -1905,7 +1865,7 @@ class EditSession { } } return arr; - }; + } /** * Calculates the width of the string `str` on the screen while assuming that the string starts at the first column on the screen. @@ -1942,9 +1902,8 @@ class EditSession { } return [screenColumn, column]; - }; + } - lineWidgets = null; /** * Returns number of screenrows in a wrapped line. * @param {Number} row The row number to check @@ -1960,14 +1919,14 @@ class EditSession { return h; else return this.$wrapData[row].length + h; - }; + } getRowLineCount(row) { if (!this.$useWrapMode || !this.$wrapData[row]) { return 1; } else { return this.$wrapData[row].length + 1; } - }; + } getRowWrapIndent(screenRow) { if (this.$useWrapMode) { @@ -1977,7 +1936,7 @@ class EditSession { } else { return 0; } - }; + } /** * Returns the position (on screen) for the last character in the provided screen row. @@ -1989,7 +1948,7 @@ class EditSession { getScreenLastRowColumn(screenRow) { var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE); return this.documentToScreenColumn(pos.row, pos.column); - }; + } /** * For the given document row and column, this returns the column position of the last screen row. @@ -2000,7 +1959,7 @@ class EditSession { getDocumentLastRowColumn(docRow, docColumn) { var screenRow = this.documentToScreenRow(docRow, docColumn); return this.getScreenLastRowColumn(screenRow); - }; + } /** * For the given document row and column, this returns the document position of the last row. @@ -2011,7 +1970,7 @@ class EditSession { getDocumentLastRowColumnPosition(docRow, docColumn) { var screenRow = this.documentToScreenRow(docRow, docColumn); return this.screenToDocumentPosition(screenRow, Number.MAX_VALUE / 10); - }; + } /** * For the given row, this returns the split data. @@ -2023,7 +1982,7 @@ class EditSession { } else { return this.$wrapData[row]; } - }; + } /** * The distance to the next tab stop at the specified screen column. @@ -2033,17 +1992,17 @@ class EditSession { **/ getScreenTabSize(screenColumn) { return this.$tabSize - (screenColumn % this.$tabSize | 0); - }; + } screenToDocumentRow(screenRow, screenColumn) { return this.screenToDocumentPosition(screenRow, screenColumn).row; - }; + } screenToDocumentColumn(screenRow, screenColumn) { return this.screenToDocumentPosition(screenRow, screenColumn).column; - }; + } /** * Converts characters coordinates on the screen to characters coordinates within the document. [This takes into account code folding, word wrap, tab size, and any other visual modifications.]{: #conversionConsiderations} @@ -2141,7 +2100,7 @@ class EditSession { return foldLine.idxToPosition(docColumn); return {row: docRow, column: docColumn}; - }; + } /** * Converts document coordinates to screen coordinates. {:conversionConsiderations} @@ -2244,7 +2203,7 @@ class EditSession { row: screenRow, column: wrapIndent + this.$getStringScreenWidth(textLine)[0] }; - }; + } /** * For the given document row and column, returns the screen column. @@ -2255,7 +2214,7 @@ class EditSession { **/ documentToScreenColumn(row, docColumn) { return this.documentToScreenPosition(row, docColumn).column; - }; + } /** * For the given document row and column, returns the screen row. @@ -2265,7 +2224,7 @@ class EditSession { **/ documentToScreenRow(docRow, docColumn) { return this.documentToScreenPosition(docRow, docColumn).row; - }; + } /** * Returns the length of the screen. @@ -2306,7 +2265,7 @@ class EditSession { screenRows += this.$getWidgetScreenLength(); return screenRows; - }; + } /** * @private @@ -2337,7 +2296,7 @@ class EditSession { return [screenColumn, column]; }; - }; + } destroy() { if (!this.destroyed) { @@ -2351,12 +2310,48 @@ class EditSession { this.doc.off("change", this.$onChange); } this.selection.detach(); - }; - - isFullWidth = isFullWidth; - + } } + +EditSession.$uid = 0; EditSession.prototype.$modes = config.$modes; +/** + * Returns the current [[Document `Document`]] as a string. + * @method getValue + * @returns {String} + * @alias EditSession.toString + **/ +EditSession.prototype.getValue = EditSession.prototype.toString; + +EditSession.prototype.$defaultUndoManager = { + undo: function() {}, + redo: function() {}, + hasUndo: function() {}, + hasRedo: function() {}, + reset: function() {}, + add: function() {}, + addSelection: function() {}, + startNewGroup: function() {}, + addSession: function() {} +}; +EditSession.prototype.$overwrite = false; +/** + * + * @type {TextMode|null} + */ +EditSession.prototype.$mode = null; +EditSession.prototype.$modeId = null; +EditSession.prototype.$scrollTop = 0; +EditSession.prototype.$scrollLeft = 0; +// WRAPMODE +EditSession.prototype.$wrapLimit = 80; +EditSession.prototype.$useWrapMode = false; +EditSession.prototype.$wrapLimitRange = { + min : null, + max : null +}; +EditSession.prototype.lineWidgets = null; +EditSession.prototype.isFullWidth = isFullWidth; oop.implement(EditSession.prototype, EventEmitter); diff --git a/src/edit_session/fold.js b/src/edit_session/fold.js index 690cad36b43..a3c752fd270 100644 --- a/src/edit_session/fold.js +++ b/src/edit_session/fold.js @@ -16,18 +16,18 @@ class Fold extends RangeList { this.sameRow = range.start.row == range.end.row; this.subFolds = this.ranges = []; - }; + } toString() { return '"' + this.placeholder + '" ' + this.range.toString(); - }; + } setFoldLine(foldLine) { this.foldLine = foldLine; this.subFolds.forEach(function(fold) { fold.setFoldLine(foldLine); }); - }; + } clone() { var range = this.range.clone(); @@ -37,7 +37,7 @@ class Fold extends RangeList { }); fold.collapseChildren = this.collapseChildren; return fold; - }; + } addSubFold(fold) { if (this.range.isEqual(fold)) @@ -78,11 +78,11 @@ class Fold extends RangeList { fold.setFoldLine(this.foldLine); return fold; - }; + } restoreRange(range) { return restoreRange(range, this.start); - }; + } } diff --git a/src/edit_session/fold_line.js b/src/edit_session/fold_line.js index 392eab38334..d8d7ce8e433 100644 --- a/src/edit_session/fold_line.js +++ b/src/edit_session/fold_line.js @@ -34,7 +34,7 @@ class FoldLine { fold.start.row += shift; fold.end.row += shift; }); - }; + } addFold(fold) { if (fold.sameRow) { @@ -64,11 +64,11 @@ class FoldLine { throw new Error("Trying to add fold to FoldRow that doesn't have a matching row"); } fold.foldLine = this; - }; + } containsRow(row) { return row >= this.start.row && row <= this.end.row; - }; + } walk(callback, endRow, endColumn) { var lastEnd = 0, @@ -106,7 +106,7 @@ class FoldLine { lastEnd = fold.end.column; } callback(null, endRow, endColumn, lastEnd, isNewRow); - }; + } getNextFoldTo(row, column) { var fold, cmp; @@ -126,7 +126,7 @@ class FoldLine { } } return null; - }; + } addRemoveChars(row, column, len) { var ret = this.getNextFoldTo(row, column), @@ -157,7 +157,7 @@ class FoldLine { this.end.column += len; } } - }; + } split(row, column) { var pos = this.getNextFoldTo(row, column); @@ -181,7 +181,7 @@ class FoldLine { var newFoldLine = new FoldLine(foldData, folds); foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine); return newFoldLine; - }; + } merge(foldLineNext) { var folds = foldLineNext.folds; @@ -192,7 +192,7 @@ class FoldLine { // it's merged now with foldLineNext. var foldData = this.foldData; foldData.splice(foldData.indexOf(foldLineNext), 1); - }; + } toString() { var ret = [this.range.toString() + ": [" ]; @@ -202,7 +202,7 @@ class FoldLine { }); ret.push("]"); return ret.join("\n"); - }; + } idxToPosition(idx) { var lastFoldEndColumn = 0; @@ -230,7 +230,7 @@ class FoldLine { row: this.end.row, column: this.end.column + idx }; - }; + } } exports.FoldLine = FoldLine; diff --git a/src/editor.js b/src/editor.js index 1ead5aae5f1..db3a648ac3f 100644 --- a/src/editor.js +++ b/src/editor.js @@ -28,8 +28,6 @@ var clipboard = require("./clipboard"); * Event sessions dealing with the mouse and keyboard are bubbled up from `Document` to the `Editor`, which decides what to do with them. **/ class Editor { - static $uid = 0; - /** * Creates a new `Editor` object. * @@ -78,7 +76,7 @@ class Editor { if (options) this.setOptions(options); config._signal("editor", this); - }; + } $initOperationListeners() { this.commands.on("exec", this.startOperation.bind(this), true); @@ -102,10 +100,8 @@ class Editor { } this.curOp.selectionChanged = true; }.bind(this), true); - }; + } - curOp = null; - prevOp = {}; startOperation(commandEvent) { if (this.curOp) { if (!commandEvent || this.curOp.command) @@ -124,7 +120,7 @@ class Editor { scrollTop: this.renderer.scrollTop }; this.curOp.selectionBefore = this.selection.toJSON(); - }; + } endOperation(e) { if (this.curOp && this.session) { @@ -170,10 +166,8 @@ class Editor { this.prevOp = this.curOp; this.curOp = null; } - }; - - // TODO use property on commands instead of this - $mergeableCommands = ["backspace", "del", "insertstring"]; + } + $historyTracker(e) { if (!this.$mergeUndoDeltas) return; @@ -208,7 +202,7 @@ class Editor { this.session.mergeUndoDeltas = true; else if (mergeableCommands.indexOf(e.command.name) !== -1) this.sequenceStartTime = Date.now(); - }; + } /** * Sets a new key handler, such as "vim" or "windows". @@ -229,7 +223,7 @@ class Editor { this.keyBinding.setKeyboardHandler(keyboardHandler); cb && cb(); } - }; + } /** * Returns the keyboard handler, such as "vim" or "windows". @@ -239,7 +233,7 @@ class Editor { **/ getKeyboardHandler() { return this.keyBinding.getKeyboardHandler(); - }; + } /** @@ -364,7 +358,7 @@ class Editor { if (session && !session.destroyed) session.bgTokenizer.scheduleStart(); - }; + } /** * Returns the current session being used. @@ -372,7 +366,7 @@ class Editor { **/ getSession() { return this.session; - }; + } /** * Sets the current document to `val`. @@ -393,7 +387,7 @@ class Editor { this.navigateFileStart(); return val; - }; + } /** * Returns the current session's content. @@ -403,7 +397,7 @@ class Editor { **/ getValue() { return this.session.getValue(); - }; + } /** * @@ -412,7 +406,7 @@ class Editor { **/ getSelection() { return this.selection; - }; + } /** * {:VirtualRenderer.onResize} @@ -423,7 +417,7 @@ class Editor { **/ resize(force) { this.renderer.onResize(force); - }; + } /** * {:VirtualRenderer.setTheme} @@ -432,7 +426,7 @@ class Editor { **/ setTheme(theme, cb) { this.renderer.setTheme(theme, cb); - }; + } /** * {:VirtualRenderer.getTheme} @@ -442,7 +436,7 @@ class Editor { **/ getTheme() { return this.renderer.getTheme(); - }; + } /** * {:VirtualRenderer.setStyle} @@ -453,7 +447,7 @@ class Editor { **/ setStyle(style) { this.renderer.setStyle(style); - }; + } /** * {:VirtualRenderer.unsetStyle} @@ -461,7 +455,7 @@ class Editor { **/ unsetStyle(style) { this.renderer.unsetStyle(style); - }; + } /** * Gets the current font size of the editor text. @@ -469,7 +463,7 @@ class Editor { getFontSize() { return this.getOption("fontSize") || dom.computedStyle(this.container).fontSize; - }; + } /** * Set a new font size (in pixels) for the editor text. @@ -479,7 +473,7 @@ class Editor { **/ setFontSize(size) { this.setOption("fontSize", size); - }; + } $highlightBrackets() { if (this.$highlightPending) { @@ -543,7 +537,7 @@ class Editor { }; if (self.getHighlightIndentGuides()) self.renderer.$textLayer.$highlightIndentGuide(); }, 50); - }; + } /** * @@ -551,7 +545,7 @@ class Editor { **/ focus() { this.textInput.focus(); - }; + } /** * Returns `true` if the current `textInput` is in focus. @@ -559,7 +553,7 @@ class Editor { **/ isFocused() { return this.textInput.isFocused(); - }; + } /** * @@ -567,7 +561,7 @@ class Editor { **/ blur() { this.textInput.blur(); - }; + } /** * Emitted once the editor comes into focus. @@ -582,7 +576,7 @@ class Editor { this.renderer.showCursor(); this.renderer.visualizeFocus(); this._emit("focus", e); - }; + } /** * Emitted once the editor has been blurred. @@ -597,13 +591,13 @@ class Editor { this.renderer.hideCursor(); this.renderer.visualizeBlur(); this._emit("blur", e); - }; + } $cursorChange() { this.renderer.updateCursor(); this.$highlightBrackets(); this.$updateHighlightActiveLine(); - }; + } /** * Emitted whenever the document is changed. @@ -623,21 +617,21 @@ class Editor { // Update cursor because tab characters can influence the cursor position. this.$cursorChange(); - }; + } onTokenizerUpdate(e) { var rows = e.data; this.renderer.updateLines(rows.first, rows.last); - }; + } onScrollTopChange() { this.renderer.scrollToY(this.session.getScrollTop()); - }; + } onScrollLeftChange() { this.renderer.scrollToX(this.session.getScrollLeft()); - }; + } /** * Emitted when the selection changes. @@ -646,7 +640,7 @@ class Editor { onCursorChange() { this.$cursorChange(); this._signal("changeSelection"); - }; + } $updateHighlightActiveLine() { var session = this.getSession(); @@ -674,7 +668,7 @@ class Editor { session.$highlightLineMarker.start.column = highlight.column; session._signal("changeBackMarker"); } - }; + } onSelectionChange(e) { var session = this.session; @@ -696,7 +690,7 @@ class Editor { this.session.highlight(re); this._signal("changeSelection"); - }; + } $getSelectionHighLightRegexp() { var session = this.session; @@ -726,40 +720,40 @@ class Editor { return; return re; - }; + } onChangeFrontMarker() { this.renderer.updateFrontMarkers(); - }; + } onChangeBackMarker() { this.renderer.updateBackMarkers(); - }; + } onChangeBreakpoint() { this.renderer.updateBreakpoints(); - }; + } onChangeAnnotation() { this.renderer.setAnnotations(this.session.getAnnotations()); - }; + } onChangeMode (e) { this.renderer.updateText(); this._emit("changeMode", e); - }; + } onChangeWrapLimit() { this.renderer.updateFull(); - }; + } onChangeWrapMode() { this.renderer.onResize(true); - }; + } onChangeFold() { @@ -768,7 +762,7 @@ class Editor { this.$updateHighlightActiveLine(); // TODO: This might be too much updating. Okay for now. this.renderer.updateFull(); - }; + } /** @@ -777,7 +771,7 @@ class Editor { **/ getSelectedText() { return this.session.getTextRange(this.getSelectionRange()); - }; + } /** * Emitted when text is copied. @@ -807,21 +801,21 @@ class Editor { this._signal("copy", e); clipboard.lineMode = copyLine ? e.text : false; return e.text; - }; + } /** * Called whenever a text "copy" happens. **/ onCopy() { this.commands.exec("copy", this); - }; + } /** * Called whenever a text "cut" happens. **/ onCut() { this.commands.exec("cut", this); - }; + } /** * Emitted when text is pasted. @@ -839,7 +833,7 @@ class Editor { onPaste(text, event) { var e = {text: text, event: event}; this.commands.exec("paste", this, e); - }; + } $handlePaste(e) { if (typeof e == "string") @@ -874,11 +868,11 @@ class Editor { session.insert(range.start, lines[i]); } } - }; + } execCommand(command, args) { return this.commands.exec(command, this, args); - }; + } /** * Inserts `text` into wherever the cursor is pointing. @@ -958,7 +952,7 @@ class Editor { if (shouldOutdent) mode.autoOutdent(lineState, session, cursor.row); } - }; + } autoIndent() { var session = this.session; @@ -1002,7 +996,7 @@ class Editor { mode.autoOutdent(prevLineState, session, row); } - }; + } onTextInput(text, composition) { @@ -1016,7 +1010,7 @@ class Editor { else applyComposition(); this.endOperation(); - }; + } applyComposition(text, composition) { if (composition.extendLeft || composition.extendRight) { @@ -1039,11 +1033,11 @@ class Editor { r.end.column -= composition.restoreEnd; this.selection.setRange(r); } - }; + } onCommandKey(e, hashId, keyCode) { return this.keyBinding.onCommandKey(e, hashId, keyCode); - }; + } /** * Pass in `true` to enable overwrites in your session, or `false` to disable. If overwrites is enabled, any text you enter will type over any text after it. If the value of `overwrite` changes, this function also emits the `changeOverwrite` event. @@ -1054,7 +1048,7 @@ class Editor { **/ setOverwrite(overwrite) { this.session.setOverwrite(overwrite); - }; + } /** * Returns `true` if overwrites are enabled; `false` otherwise. @@ -1063,7 +1057,7 @@ class Editor { **/ getOverwrite() { return this.session.getOverwrite(); - }; + } /** * Sets the value of overwrite to the opposite of whatever it currently is. @@ -1071,7 +1065,7 @@ class Editor { **/ toggleOverwrite() { this.session.toggleOverwrite(); - }; + } /** * Sets how fast the mouse scrolling should do. @@ -1079,7 +1073,7 @@ class Editor { **/ setScrollSpeed(speed) { this.setOption("scrollSpeed", speed); - }; + } /** * Returns the value indicating how fast the mouse scroll speed is (in milliseconds). @@ -1087,7 +1081,7 @@ class Editor { **/ getScrollSpeed() { return this.getOption("scrollSpeed"); - }; + } /** * Sets the delay (in milliseconds) of the mouse drag. @@ -1095,7 +1089,7 @@ class Editor { **/ setDragDelay(dragDelay) { this.setOption("dragDelay", dragDelay); - }; + } /** * Returns the current mouse drag delay. @@ -1103,7 +1097,7 @@ class Editor { **/ getDragDelay() { return this.getOption("dragDelay"); - }; + } /** * Emitted when the selection style changes, via [[Editor.setSelectionStyle]]. @@ -1117,7 +1111,7 @@ class Editor { **/ setSelectionStyle(val) { this.setOption("selectionStyle", val); - }; + } /** * Returns the current selection style. @@ -1125,7 +1119,7 @@ class Editor { **/ getSelectionStyle() { return this.getOption("selectionStyle"); - }; + } /** * Determines whether or not the current line should be highlighted. @@ -1133,21 +1127,21 @@ class Editor { **/ setHighlightActiveLine(shouldHighlight) { this.setOption("highlightActiveLine", shouldHighlight); - }; + } /** * Returns `true` if current lines are always highlighted. * @return {Boolean} **/ getHighlightActiveLine() { return this.getOption("highlightActiveLine"); - }; + } setHighlightGutterLine(shouldHighlight) { this.setOption("highlightGutterLine", shouldHighlight); - }; + } getHighlightGutterLine() { return this.getOption("highlightGutterLine"); - }; + } /** * Determines if the currently selected word should be highlighted. @@ -1156,7 +1150,7 @@ class Editor { **/ setHighlightSelectedWord(shouldHighlight) { this.setOption("highlightSelectedWord", shouldHighlight); - }; + } /** * Returns `true` if currently highlighted words are to be highlighted. @@ -1164,15 +1158,15 @@ class Editor { **/ getHighlightSelectedWord() { return this.$highlightSelectedWord; - }; + } setAnimatedScroll(shouldAnimate){ this.renderer.setAnimatedScroll(shouldAnimate); - }; + } getAnimatedScroll(){ return this.renderer.getAnimatedScroll(); - }; + } /** * If `showInvisibles` is set to `true`, invisible characters—like spaces or new lines—are show in the editor. @@ -1181,7 +1175,7 @@ class Editor { **/ setShowInvisibles(showInvisibles) { this.renderer.setShowInvisibles(showInvisibles); - }; + } /** * Returns `true` if invisible characters are being shown. @@ -1189,23 +1183,23 @@ class Editor { **/ getShowInvisibles() { return this.renderer.getShowInvisibles(); - }; + } setDisplayIndentGuides(display) { this.renderer.setDisplayIndentGuides(display); - }; + } getDisplayIndentGuides() { return this.renderer.getDisplayIndentGuides(); - }; + } setHighlightIndentGuides(highlight) { this.renderer.setHighlightIndentGuides(highlight); - }; + } getHighlightIndentGuides() { return this.renderer.getHighlightIndentGuides(); - }; + } /** * If `showPrintMargin` is set to `true`, the print margin is shown in the editor. @@ -1214,7 +1208,7 @@ class Editor { **/ setShowPrintMargin(showPrintMargin) { this.renderer.setShowPrintMargin(showPrintMargin); - }; + } /** * Returns `true` if the print margin is being shown. @@ -1222,7 +1216,7 @@ class Editor { **/ getShowPrintMargin() { return this.renderer.getShowPrintMargin(); - }; + } /** * Sets the column defining where the print margin should be. @@ -1231,7 +1225,7 @@ class Editor { **/ setPrintMarginColumn(showPrintMargin) { this.renderer.setPrintMarginColumn(showPrintMargin); - }; + } /** * Returns the column number of where the print margin is. @@ -1239,7 +1233,7 @@ class Editor { **/ getPrintMarginColumn() { return this.renderer.getPrintMarginColumn(); - }; + } /** * If `readOnly` is true, then the editor is set to read-only mode, and none of the content can change. @@ -1248,7 +1242,7 @@ class Editor { **/ setReadOnly(readOnly) { this.setOption("readOnly", readOnly); - }; + } /** * Returns `true` if the editor is set to read-only mode. @@ -1256,7 +1250,7 @@ class Editor { **/ getReadOnly() { return this.getOption("readOnly"); - }; + } /** * Specifies whether to use behaviors or not. ["Behaviors" in this case is the auto-pairing of special characters, like quotation marks, parenthesis, or brackets.]{: #BehaviorsDef} @@ -1265,7 +1259,7 @@ class Editor { **/ setBehavioursEnabled(enabled) { this.setOption("behavioursEnabled", enabled); - }; + } /** * Returns `true` if the behaviors are currently enabled. {:BehaviorsDef} @@ -1274,7 +1268,7 @@ class Editor { **/ getBehavioursEnabled() { return this.getOption("behavioursEnabled"); - }; + } /** * Specifies whether to use wrapping behaviors or not, i.e. automatically wrapping the selection with characters such as brackets @@ -1284,14 +1278,14 @@ class Editor { **/ setWrapBehavioursEnabled(enabled) { this.setOption("wrapBehavioursEnabled", enabled); - }; + } /** * Returns `true` if the wrapping behaviors are currently enabled. **/ getWrapBehavioursEnabled() { return this.getOption("wrapBehavioursEnabled"); - }; + } /** * Indicates whether the fold widgets should be shown or not. @@ -1300,22 +1294,22 @@ class Editor { setShowFoldWidgets(show) { this.setOption("showFoldWidgets", show); - }; + } /** * Returns `true` if the fold widgets are shown. * @return {Boolean} **/ getShowFoldWidgets() { return this.getOption("showFoldWidgets"); - }; + } setFadeFoldWidgets(fade) { this.setOption("fadeFoldWidgets", fade); - }; + } getFadeFoldWidgets() { return this.getOption("fadeFoldWidgets"); - }; + } /** * Removes the current selection or one character. @@ -1351,7 +1345,7 @@ class Editor { this.session.remove(range); this.clearSelection(); - }; + } /** * Removes the word directly to the right of the current selection. @@ -1362,7 +1356,7 @@ class Editor { this.session.remove(this.getSelectionRange()); this.clearSelection(); - }; + } /** * Removes the word directly to the left of the current selection. @@ -1373,7 +1367,7 @@ class Editor { this.session.remove(this.getSelectionRange()); this.clearSelection(); - }; + } /** * Removes all the words to the left of the current selection, until the start of the line. @@ -1385,7 +1379,7 @@ class Editor { this.selection.selectLeft(); this.session.remove(this.getSelectionRange()); this.clearSelection(); - }; + } /** * Removes all the words to the right of the current selection, until the end of the line. @@ -1402,7 +1396,7 @@ class Editor { this.session.remove(range); this.clearSelection(); - }; + } /** * Splits the line at the current selection (by inserting an `'\n'`). @@ -1416,7 +1410,7 @@ class Editor { var cursor = this.getCursorPosition(); this.insert("\n"); this.moveCursorToPosition(cursor); - }; + } /** * Set the "ghost" text in provided position. "Ghost" text is a kind of @@ -1432,7 +1426,7 @@ class Editor { this.session.widgetManager.attach(this); } this.renderer.setGhostText(text, position); - }; + } /** * Removes "ghost" text currently displayed in the editor. @@ -1441,7 +1435,7 @@ class Editor { if (!this.session.widgetManager) return; this.renderer.removeGhostText(); - }; + } /** * Transposes current line. @@ -1468,7 +1462,7 @@ class Editor { } this.session.replace(range, swap); this.session.selection.moveToPosition(range.end); - }; + } /** * Converts the current selection entirely into lowercase. @@ -1483,7 +1477,7 @@ class Editor { var text = this.session.getTextRange(range); this.session.replace(range, text.toLowerCase()); this.selection.setSelectionRange(originalRange); - }; + } /** * Converts the current selection entirely into uppercase. @@ -1498,7 +1492,7 @@ class Editor { var text = this.session.getTextRange(range); this.session.replace(range, text.toUpperCase()); this.selection.setSelectionRange(originalRange); - }; + } /** * Inserts an indentation into the current cursor position or indents the selected lines. @@ -1540,7 +1534,7 @@ class Editor { indentString = "\t"; } return this.insert(indentString); - }; + } /** * Indents the current line. @@ -1549,7 +1543,7 @@ class Editor { blockIndent() { var rows = this.$getSelectedRows(); this.session.indentRows(rows.first, rows.last, "\t"); - }; + } /** * Outdents the current line. @@ -1558,7 +1552,7 @@ class Editor { blockOutdent() { var selection = this.session.getSelection(); this.session.outdentRows(selection.getRange()); - }; + } // TODO: move out of core when we have good mechanism for managing extensions sortLines() { @@ -1583,7 +1577,7 @@ class Editor { deleteRange.end.column = line.length; session.replace(deleteRange, lines[i-rows.first]); } - }; + } /** * Given the currently selected range, this function either comments all the lines, or uncomments all of them. @@ -1592,14 +1586,14 @@ class Editor { var state = this.session.getState(this.getCursorPosition().row); var rows = this.$getSelectedRows(); this.session.getMode().toggleCommentLines(state, this.session, rows.first, rows.last); - }; + } toggleBlockComment() { var cursor = this.getCursorPosition(); var state = this.session.getState(cursor.row); var range = this.getSelectionRange(); this.session.getMode().toggleBlockComment(state, this.session, range, cursor); - }; + } /** * Works like [[EditSession.getTokenAt]], except it returns a number. @@ -1622,7 +1616,7 @@ class Editor { } } return null; - }; + } /** * If the character before the cursor is a number, this functions changes its value by `amount`. @@ -1671,34 +1665,8 @@ class Editor { } else { this.toggleWord(); } - }; - - $toggleWordPairs = [ - ["first", "last"], - ["true", "false"], - ["yes", "no"], - ["width", "height"], - ["top", "bottom"], - ["right", "left"], - ["on", "off"], - ["x", "y"], - ["get", "set"], - ["max", "min"], - ["horizontal", "vertical"], - ["show", "hide"], - ["add", "remove"], - ["up", "down"], - ["before", "after"], - ["even", "odd"], - ["in", "out"], - ["inside", "outside"], - ["next", "previous"], - ["increase", "decrease"], - ["attach", "detach"], - ["&&", "||"], - ["==", "!="] - ]; - + } + toggleWord() { var row = this.selection.getCursor().row; var column = this.selection.getCursor().column; @@ -1748,7 +1716,7 @@ class Editor { } } } - }; + } /** * Finds link at defined {row} and {column} @@ -1771,7 +1739,7 @@ class Editor { previousPosition = currentPosition; } return match; - }; + } /** * Open valid url under cursor in another tab @@ -1783,7 +1751,7 @@ class Editor { if (url) window.open(url, '_blank'); return url != null; - }; + } /** * Removes all the lines in the current selection @@ -1793,7 +1761,7 @@ class Editor { var rows = this.$getSelectedRows(); this.session.removeFullLines(rows.first, rows.last); this.clearSelection(); - }; + } duplicateSelection() { var sel = this.selection; @@ -1811,7 +1779,7 @@ class Editor { sel.setSelectionRange(range, reverse); } - }; + } /** * Shifts all the selected lines down one row. @@ -1821,7 +1789,7 @@ class Editor { **/ moveLinesDown() { this.$moveLines(1, false); - }; + } /** * Shifts all the selected lines up one row. @@ -1830,7 +1798,7 @@ class Editor { **/ moveLinesUp() { this.$moveLines(-1, false); - }; + } /** * Moves a range of text from the given range to the given position. `toPosition` is an object that looks like this: @@ -1845,7 +1813,7 @@ class Editor { **/ moveText(range, toPosition, copy) { return this.session.moveText(range, toPosition, copy); - }; + } /** * Copies all the selected lines up one row. @@ -1854,7 +1822,7 @@ class Editor { **/ copyLinesUp() { this.$moveLines(-1, true); - }; + } /** * Copies all the selected lines down one row. @@ -1864,7 +1832,7 @@ class Editor { **/ copyLinesDown() { this.$moveLines(1, true); - }; + } /** * for internal use @@ -1919,7 +1887,7 @@ class Editor { selection.rangeList.attach(this.session); this.inVirtualSelectionMode = false; } - }; + } /** * Returns an object indicating the currently selected rows. The object looks like this: @@ -1937,19 +1905,19 @@ class Editor { first: this.session.getRowFoldStart(range.start.row), last: this.session.getRowFoldEnd(range.end.row) }; - }; + } onCompositionStart(compositionState) { this.renderer.showComposition(compositionState); - }; + } onCompositionUpdate(text) { this.renderer.setCompositionText(text); - }; + } onCompositionEnd() { this.renderer.hideComposition(); - }; + } /** * {:VirtualRenderer.getFirstVisibleRow} @@ -1959,7 +1927,7 @@ class Editor { **/ getFirstVisibleRow() { return this.renderer.getFirstVisibleRow(); - }; + } /** * {:VirtualRenderer.getLastVisibleRow} @@ -1969,7 +1937,7 @@ class Editor { **/ getLastVisibleRow() { return this.renderer.getLastVisibleRow(); - }; + } /** * Indicates if the row is currently visible on the screen. @@ -1979,7 +1947,7 @@ class Editor { **/ isRowVisible(row) { return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow()); - }; + } /** * Indicates if the entire row is currently visible on the screen. @@ -1990,7 +1958,7 @@ class Editor { **/ isRowFullyVisible(row) { return (row >= this.renderer.getFirstFullyVisibleRow() && row <= this.renderer.getLastFullyVisibleRow()); - }; + } /** * Returns the number of currently visible rows. @@ -1998,7 +1966,7 @@ class Editor { **/ $getVisibleRowCount() { return this.renderer.getScrollBottomRow() - this.renderer.getScrollTopRow() + 1; - }; + } $moveByPage(dir, select) { var renderer = this.renderer; @@ -2021,49 +1989,49 @@ class Editor { renderer.scrollCursorIntoView(null, 0.5); renderer.animateScrolling(scrollTop); - }; + } /** * Selects the text from the current position of the document until where a "page down" finishes. **/ selectPageDown() { this.$moveByPage(1, true); - }; + } /** * Selects the text from the current position of the document until where a "page up" finishes. **/ selectPageUp() { this.$moveByPage(-1, true); - }; + } /** * Shifts the document to wherever "page down" is, as well as moving the cursor position. **/ gotoPageDown() { this.$moveByPage(1, false); - }; + } /** * Shifts the document to wherever "page up" is, as well as moving the cursor position. **/ gotoPageUp() { this.$moveByPage(-1, false); - }; + } /** * Scrolls the document to wherever "page down" is, without changing the cursor position. **/ scrollPageDown() { this.$moveByPage(1); - }; + } /** * Scrolls the document to wherever "page up" is, without changing the cursor position. **/ scrollPageUp() { this.$moveByPage(-1); - }; + } /** * Moves the editor to the specified row. @@ -2071,7 +2039,7 @@ class Editor { **/ scrollToRow(row) { this.renderer.scrollToRow(row); - }; + } /** * Scrolls to a line. If `center` is `true`, it puts the line in middle of screen (or attempts to). @@ -2085,7 +2053,7 @@ class Editor { **/ scrollToLine(line, center, animate, callback) { this.renderer.scrollToLine(line, center, animate, callback); - }; + } /** * Attempts to center the current selection on the screen. @@ -2097,7 +2065,7 @@ class Editor { column: Math.floor(range.start.column + (range.end.column - range.start.column) / 2) }; this.renderer.alignCursor(pos, 0.5); - }; + } /** * Gets the current position of the cursor. @@ -2111,7 +2079,7 @@ class Editor { **/ getCursorPosition() { return this.selection.getCursor(); - }; + } /** * Returns the screen position of the cursor. @@ -2120,7 +2088,7 @@ class Editor { **/ getCursorPositionScreen() { return this.session.documentToScreenPosition(this.getCursorPosition()); - }; + } /** * {:Selection.getRange} @@ -2129,7 +2097,7 @@ class Editor { **/ getSelectionRange() { return this.selection.getRange(); - }; + } /** * Selects all the text in editor. @@ -2137,7 +2105,7 @@ class Editor { **/ selectAll() { this.selection.selectAll(); - }; + } /** * {:Selection.clearSelection} @@ -2145,7 +2113,7 @@ class Editor { **/ clearSelection() { this.selection.clearSelection(); - }; + } /** * Moves the cursor to the specified row and column. Note that this does not de-select the current selection. @@ -2155,7 +2123,7 @@ class Editor { **/ moveCursorTo(row, column) { this.selection.moveCursorTo(row, column); - }; + } /** * Moves the cursor to the position indicated by `pos.row` and `pos.column`. @@ -2164,7 +2132,7 @@ class Editor { **/ moveCursorToPosition(pos) { this.selection.moveCursorToPosition(pos); - }; + } /** * Moves the cursor's row and column to the next matching bracket or HTML tag. @@ -2313,7 +2281,7 @@ class Editor { this.selection.moveTo(pos.row, pos.column); } } - }; + } /** * Moves the cursor to the specified line number, and also into the indicated column. @@ -2332,7 +2300,7 @@ class Editor { if (!this.isRowFullyVisible(lineNumber - 1)) this.scrollToLine(lineNumber - 1, true, animate); - }; + } /** * Moves the cursor to the specified row and column. Note that this does de-select the current selection. @@ -2344,7 +2312,7 @@ class Editor { **/ navigateTo(row, column) { this.selection.moveTo(row, column); - }; + } /** * Moves the cursor up in the document the specified number of times. Note that this does de-select the current selection. @@ -2359,7 +2327,7 @@ class Editor { } this.selection.clearSelection(); this.selection.moveCursorBy(-times || -1, 0); - }; + } /** * Moves the cursor down in the document the specified number of times. Note that this does de-select the current selection. @@ -2374,7 +2342,7 @@ class Editor { } this.selection.clearSelection(); this.selection.moveCursorBy(times || 1, 0); - }; + } /** * Moves the cursor left in the document the specified number of times. Note that this does de-select the current selection. @@ -2394,7 +2362,7 @@ class Editor { } } this.clearSelection(); - }; + } /** * Moves the cursor right in the document the specified number of times. Note that this does de-select the current selection. @@ -2414,7 +2382,7 @@ class Editor { } } this.clearSelection(); - }; + } /** * @@ -2423,7 +2391,7 @@ class Editor { navigateLineStart() { this.selection.moveCursorLineStart(); this.clearSelection(); - }; + } /** * @@ -2432,7 +2400,7 @@ class Editor { navigateLineEnd() { this.selection.moveCursorLineEnd(); this.clearSelection(); - }; + } /** * @@ -2441,7 +2409,7 @@ class Editor { navigateFileEnd() { this.selection.moveCursorFileEnd(); this.clearSelection(); - }; + } /** * @@ -2450,7 +2418,7 @@ class Editor { navigateFileStart() { this.selection.moveCursorFileStart(); this.clearSelection(); - }; + } /** * @@ -2459,7 +2427,7 @@ class Editor { navigateWordRight() { this.selection.moveCursorWordRight(); this.clearSelection(); - }; + } /** * @@ -2468,7 +2436,7 @@ class Editor { navigateWordLeft() { this.selection.moveCursorWordLeft(); this.clearSelection(); - }; + } /** * Replaces the first occurrence of `options.needle` with the value in `replacement`. @@ -2494,7 +2462,7 @@ class Editor { this.renderer.scrollSelectionIntoView(range.start, range.end); return replaced; - }; + } /** * Replaces all occurrences of `options.needle` with the value in `replacement`. @@ -2525,7 +2493,7 @@ class Editor { this.selection.setSelectionRange(selection); return replaced; - }; + } $tryReplace(range, replacement) { var input = this.session.getTextRange(range); @@ -2536,7 +2504,7 @@ class Editor { } else { return null; } - }; + } /** * {:Search.getOptions} For more information on `options`, see [[Search `Search`]]. @@ -2545,7 +2513,7 @@ class Editor { **/ getLastSearchOptions() { return this.$search.getOptions(); - }; + } /** * Attempts to find `needle` within the document. For more information on `options`, see [[Search `Search`]]. @@ -2591,7 +2559,7 @@ class Editor { else range.end = range.start; this.selection.setRange(range); - }; + } /** * Performs another search for `needle` in the document. For more information on `options`, see [[Search `Search`]]. @@ -2603,7 +2571,7 @@ class Editor { **/ findNext(options, animate) { this.find({skipCurrent: true, backwards: false}, options, animate); - }; + } /** * Performs a search for `needle` backwards. For more information on `options`, see [[Search `Search`]]. @@ -2615,7 +2583,7 @@ class Editor { **/ findPrevious(options, animate) { this.find(options, {skipCurrent: true, backwards: true}, animate); - }; + } revealRange(range, animate) { this.session.unfold(range); @@ -2625,7 +2593,7 @@ class Editor { this.renderer.scrollSelectionIntoView(range.start, range.end, 0.5); if (animate !== false) this.renderer.animateScrolling(scrollTop); - }; + } /** * {:UndoManager.undo} @@ -2634,7 +2602,7 @@ class Editor { undo() { this.session.getUndoManager().undo(this.session); this.renderer.scrollCursorIntoView(null, 0.5); - }; + } /** * {:UndoManager.redo} @@ -2643,7 +2611,7 @@ class Editor { redo() { this.session.getUndoManager().redo(this.session); this.renderer.scrollCursorIntoView(null, 0.5); - }; + } /** * @@ -2665,7 +2633,7 @@ class Editor { if (this._$emitInputEvent) this._$emitInputEvent.cancel(); this.removeAllListeners(); - }; + } /** * Enables automatic scrolling of the cursor into view when editor itself is inside scrollable element @@ -2723,7 +2691,7 @@ class Editor { this.renderer.off("afterRender", onAfterRender); this.renderer.off("beforeRender", onBeforeRender); }; - }; + } $resetCursorStyle() { @@ -2734,7 +2702,7 @@ class Editor { cursorLayer.setSmoothBlinking(/smooth/.test(style)); cursorLayer.isBlinking = !this.$readOnly && style != "wide"; dom.setCssClass(cursorLayer.element, "ace_slim-cursors", /slim/.test(style)); - }; + } /** * opens a prompt displaying message @@ -2744,10 +2712,41 @@ class Editor { config.loadModule("ace/ext/prompt", function (module) { module.prompt(editor, message, options, callback); }); - }; + } } +Editor.$uid = 0; +Editor.prototype.curOp = null; +Editor.prototype.prevOp = {}; +// TODO use property on commands instead of this +Editor.prototype.$mergeableCommands = ["backspace", "del", "insertstring"]; +Editor.prototype.$toggleWordPairs = [ + ["first", "last"], + ["true", "false"], + ["yes", "no"], + ["width", "height"], + ["top", "bottom"], + ["right", "left"], + ["on", "off"], + ["x", "y"], + ["get", "set"], + ["max", "min"], + ["horizontal", "vertical"], + ["show", "hide"], + ["add", "remove"], + ["up", "down"], + ["before", "after"], + ["even", "odd"], + ["in", "out"], + ["inside", "outside"], + ["next", "previous"], + ["increase", "decrease"], + ["attach", "detach"], + ["&&", "||"], + ["==", "!="] +]; + oop.implement(Editor.prototype, EventEmitter); diff --git a/src/ext/elastic_tabstops_lite.js b/src/ext/elastic_tabstops_lite.js index 16ee488fda1..f5726991789 100644 --- a/src/ext/elastic_tabstops_lite.js +++ b/src/ext/elastic_tabstops_lite.js @@ -22,7 +22,7 @@ class ElasticTabstopsLite { changedRows.push(delta.end.row); } }; - }; + } processRows(rows) { this.$inChange = true; @@ -46,7 +46,7 @@ class ElasticTabstopsLite { } } this.$inChange = false; - }; + } $findCellWidthsForBlock(row) { var cellWidths = [], widths; @@ -78,7 +78,7 @@ class ElasticTabstopsLite { } return { cellWidths: cellWidths, firstRow: firstRow }; - }; + } $cellWidthsForRow(row) { var selectionColumns = this.$selectionColumnsForRow(row); @@ -98,7 +98,7 @@ class ElasticTabstopsLite { } return widths; - }; + } $selectionColumnsForRow(row) { var selections = [], cursor = this.$editor.getCursorPosition(); @@ -109,7 +109,7 @@ class ElasticTabstopsLite { } return selections; - }; + } $setBlockCellWidthsToMax(cellWidths) { var startingNewBlock = true, blockStartRow, blockEndRow, maxWidth; @@ -147,7 +147,7 @@ class ElasticTabstopsLite { } return cellWidths; - }; + } $rightmostSelectionInCell(selectionColumns, cellRightEdge) { var rightmost = 0; @@ -164,7 +164,7 @@ class ElasticTabstopsLite { } return rightmost; - }; + } $tabsForRow(row) { var rowTabs = [], line = this.$editor.session.getLine(row), @@ -175,7 +175,7 @@ class ElasticTabstopsLite { } return rowTabs; - }; + } $adjustRow(row, widths) { var rowTabs = this.$tabsForRow(row); @@ -215,7 +215,7 @@ class ElasticTabstopsLite { bias += difference; } } - }; + } // the is a (naive) Python port--but works for these purposes $izip_longest(iterables) { @@ -246,7 +246,7 @@ class ElasticTabstopsLite { return expandedSet; - }; + } // an even more (naive) Python port $izip(widths, tabs) { @@ -259,7 +259,7 @@ class ElasticTabstopsLite { expandedSet.push(set); } return expandedSet; - }; + } } diff --git a/src/ext/inline_autocomplete.js b/src/ext/inline_autocomplete.js index 1a1c3885f66..7e10a8f0a14 100644 --- a/src/ext/inline_autocomplete.js +++ b/src/ext/inline_autocomplete.js @@ -46,13 +46,13 @@ class InlineAutocomplete { this.changeTimer = lang.delayedCall(function() { this.updateCompletions(); }.bind(this)); - }; + } getInlineRenderer() { if (!this.inlineRenderer) this.inlineRenderer = new AceInline(); return this.inlineRenderer; - }; + } getInlineTooltip() { if (!this.inlineTooltip) { @@ -60,7 +60,7 @@ class InlineAutocomplete { this.inlineTooltip.setCommands(this.commands); } return this.inlineTooltip; - }; + } /** @@ -81,7 +81,7 @@ class InlineAutocomplete { this.editor.on("mousewheel", this.mousewheelListener); this.updateCompletions(options); - }; + } $open() { if (this.editor.textInput.setAriaOptions) { @@ -102,58 +102,13 @@ class InlineAutocomplete { } this.changeTimer.cancel(); - }; + } insertMatch() { var result = this.getCompletionProvider().insertByIndex(this.editor, this.$index); this.detach(); return result; - }; - - commands = { - "Previous": { - bindKey: "Alt-[", - name: "Previous", - exec: function(editor) { - editor.completer.goTo("prev"); - }, - enabled: function(editor) { - return editor.completer.getIndex() > 0; - }, - position: 10 - }, - "Next": { - bindKey: "Alt-]", - name: "Next", - exec: function(editor) { - editor.completer.goTo("next"); - }, - enabled: function(editor) { - return editor.completer.getIndex() < editor.completer.getLength() - 1; - }, - position: 20 - }, - "Accept": { - bindKey: { win: "Tab|Ctrl-Right", mac: "Tab|Cmd-Right" }, - name: "Accept", - exec: function(editor) { - return editor.completer.insertMatch(); - }, - enabled: function(editor) { - return editor.completer.getIndex() >= 0; - }, - position: 30 - }, - "Close": { - bindKey: "Esc", - name: "Close", - exec: function(editor) { - editor.completer.detach(); - }, - enabled: true, - position: 40 - } - }; + } changeListener(e) { var cursor = this.editor.selection.lead; @@ -164,17 +119,17 @@ class InlineAutocomplete { this.changeTimer.schedule(); else this.detach(); - }; + } blurListener(e) { this.detach(); - }; + } mousewheelListener(e) { if (this.inlineTooltip && this.inlineTooltip.isShown()) { this.inlineTooltip.updatePosition(); } - }; + } goTo(where) { if (!this.completions || !this.completions.filtered) { @@ -194,14 +149,14 @@ class InlineAutocomplete { this.setIndex(this.completions.filtered.length - 1); break; } - }; + } getLength() { if (!this.completions || !this.completions.filtered) { return 0; } return this.completions.filtered.length; - }; + } getData(index) { if (index == undefined || index === null) { @@ -209,15 +164,15 @@ class InlineAutocomplete { } else { return this.completions.filtered[index]; } - }; + } getIndex() { return this.$index; - }; + } isOpen() { return this.$index >= 0; - }; + } setIndex(value) { if (!this.completions || !this.completions.filtered) { @@ -228,13 +183,13 @@ class InlineAutocomplete { this.$index = newIndex; this.$showCompletion(); } - }; + } getCompletionProvider() { if (!this.completionProvider) this.completionProvider = new CompletionProvider(); return this.completionProvider; - }; + } $showCompletion() { if (!this.getInlineRenderer().show(this.editor, this.completions.filtered[this.$index], this.completions.filterText)) { @@ -244,7 +199,7 @@ class InlineAutocomplete { if (this.inlineTooltip && this.inlineTooltip.isShown()) { this.inlineTooltip.updateButtons(); } - }; + } $updatePrefix() { var pos = this.editor.getCursorPosition(); @@ -258,7 +213,7 @@ class InlineAutocomplete { return this.detach(); this.$open(this.editor, prefix); return prefix; - }; + } updateCompletions(options) { var prefix = ""; @@ -300,7 +255,7 @@ class InlineAutocomplete { this.completions = completions; this.$open(this.editor, prefix); }.bind(this)); - }; + } detach() { if (this.editor) { @@ -328,7 +283,7 @@ class InlineAutocomplete { this.base.detach(); this.activated = false; this.completionProvider = this.completions = this.base = null; - }; + } destroy() { this.detach(); @@ -341,10 +296,55 @@ class InlineAutocomplete { this.editor.completer = null; } this.inlineTooltip = this.editor = this.inlineRenderer = null; - }; + } } +InlineAutocomplete.prototype.commands = { + "Previous": { + bindKey: "Alt-[", + name: "Previous", + exec: function(editor) { + editor.completer.goTo("prev"); + }, + enabled: function(editor) { + return editor.completer.getIndex() > 0; + }, + position: 10 + }, + "Next": { + bindKey: "Alt-]", + name: "Next", + exec: function(editor) { + editor.completer.goTo("next"); + }, + enabled: function(editor) { + return editor.completer.getIndex() < editor.completer.getLength() - 1; + }, + position: 20 + }, + "Accept": { + bindKey: { win: "Tab|Ctrl-Right", mac: "Tab|Cmd-Right" }, + name: "Accept", + exec: function(editor) { + return editor.completer.insertMatch(); + }, + enabled: function(editor) { + return editor.completer.getIndex() >= 0; + }, + position: 30 + }, + "Close": { + bindKey: "Esc", + name: "Close", + exec: function(editor) { + editor.completer.detach(); + }, + enabled: true, + position: 40 + } +}; + InlineAutocomplete.for = function(editor) { if (editor.completer instanceof InlineAutocomplete) { return editor.completer; @@ -451,7 +451,7 @@ class InlineTooltip { var buttonText = dom.createTextNode([command.name, "(", bindKey, ")"].join(" ")); this.buttons[key].appendChild(buttonText); }.bind(this)); - }; + } /** * Displays the clickable command bar tooltip @@ -464,11 +464,11 @@ class InlineTooltip { this.updatePosition(); this.updateButtons(true); - }; + } isShown() { return !!this.htmlElement && window.getComputedStyle(this.htmlElement).display !== "none"; - }; + } /** * Updates the position of the command bar tooltip. It aligns itself above the topmost selection in the editor. @@ -508,7 +508,7 @@ class InlineTooltip { el.style.top = top + "px"; el.style.bottom = ""; el.style.left = Math.min(screenWidth - el.offsetWidth, pos.left) + "px"; - }; + } /** * Updates the buttons in the command bar tooltip. Should be called every time when any of the buttons can become disabled or enabled. @@ -539,7 +539,7 @@ class InlineTooltip { delete this.eventListeners[key]; } }.bind(this)); - }; + } detach() { var listenerKeys = Object.keys(this.eventListeners); @@ -553,7 +553,7 @@ class InlineTooltip { this.htmlElement.removeEventListener('mousedown', captureMousedown.bind(this)); this.htmlElement.style.display = 'none'; } - }; + } destroy() { this.detach(); @@ -564,7 +564,7 @@ class InlineTooltip { this.buttons = null; this.htmlElement = null; this.controls = null; - }; + } } var captureMousedown = function(e) { diff --git a/src/ext/modelist.js b/src/ext/modelist.js index db942d1084a..cd98590a0c5 100644 --- a/src/ext/modelist.js +++ b/src/ext/modelist.js @@ -36,11 +36,11 @@ class Mode { } this.extRe = new RegExp(re, "gi"); - }; + } supportsFile(filename) { return filename.match(this.extRe); - }; + } } // todo firstlinematch diff --git a/src/ext/options.js b/src/ext/options.js index 99d13dc2153..a80010444af 100644 --- a/src/ext/options.js +++ b/src/ext/options.js @@ -204,14 +204,14 @@ class OptionPanel { this.container = element || document.createElement("div"); this.groups = []; this.options = {}; - }; + } add(config) { if (config.Main) oop.mixin(optionGroups.Main, config.Main); if (config.More) oop.mixin(optionGroups.More, config.More); - }; + } render() { this.container.innerHTML = ""; @@ -224,7 +224,7 @@ class OptionPanel { ]], ["tr", null, ["td", {colspan: 2}, "version " + config.version]] ], this.container); - }; + } renderOptionGroup(group) { return Object.keys(group).map(function(key, i) { @@ -239,7 +239,7 @@ class OptionPanel { }).map(function(item) { return this.renderOption(item.label, item); }, this); - }; + } renderOptionControl(key, option) { var self = this; @@ -325,7 +325,7 @@ class OptionPanel { } } return control; - }; + } renderOption(key, option) { if (option.path && !option.onchange && !this.editor.$options[option.path]) @@ -338,7 +338,7 @@ class OptionPanel { return ["tr", {class: "ace_optionsMenuEntry"}, ["td", ["label", {for: safeKey, id: safeId}, key] ], ["td", control]]; - }; + } setOption(option, value) { if (typeof option == "string") @@ -354,13 +354,13 @@ class OptionPanel { else if (option.path) this.editor.setOption(option.path, value); this._signal("setOption", {name: option.path, value: value}); - }; + } getOption(option) { if (option.getValue) return option.getValue(); return this.editor.getOption(option.path); - }; + } } oop.implement(OptionPanel.prototype, EventEmitter); diff --git a/src/ext/searchbox.js b/src/ext/searchbox.js index a11e10d05ac..4a731bfefcb 100644 --- a/src/ext/searchbox.js +++ b/src/ext/searchbox.js @@ -127,18 +127,27 @@ class SearchBox { sb.$syncOptions(); } }]); - }; + + //keybinding outside of the searchbox + this.$closeSearchBarKb = new HashHandler([{ + bindKey: "Esc", + name: "closeSearchBar", + exec: function(editor) { + editor.searchBox.hide(); + } + }]); + } setEditor(editor) { editor.searchBox = this; editor.renderer.scroller.appendChild(this.element); this.editor = editor; - }; + } setSession(e) { this.searchRange = null; this.$syncOptions(true); - }; + } $initElements(sb) { this.searchBox = sb.querySelector(".ace_search_form"); @@ -151,7 +160,7 @@ class SearchBox { this.searchInput = this.searchBox.querySelector(".ace_search_field"); this.replaceInput = this.replaceBox.querySelector(".ace_search_field"); this.searchCounter = sb.querySelector(".ace_search_counter"); - }; + } $init() { var sb = this.element; @@ -199,16 +208,7 @@ class SearchBox { _this.activeInput = _this.replaceInput; _this.searchInput.value && _this.highlight(); }); - }; - - //keybinding outside of the searchbox - $closeSearchBarKb = new HashHandler([{ - bindKey: "Esc", - name: "closeSearchBar", - exec: function(editor) { - editor.searchBox.hide(); - } - }]); + } setSearchRange(range) { this.searchRange = range; @@ -218,7 +218,7 @@ class SearchBox { this.editor.session.removeMarker(this.searchRangeMarker); this.searchRangeMarker = null; } - }; + } $syncOptions(preventScroll) { dom.setCssClass(this.replaceOption, "checked", this.searchRange); @@ -231,12 +231,12 @@ class SearchBox { this.replaceOption.style.display = readOnly ? "none" : ""; this.replaceBox.style.display = this.replaceOption.checked && !readOnly ? "" : "none"; this.find(false, false, preventScroll); - }; + } highlight(re) { this.editor.session.highlight(re || this.editor.$search.$options.re); this.editor.renderer.updateBackMarkers(); - }; + } find(skipCurrent, backwards, preventScroll) { var range = this.editor.find(this.searchInput.value, { @@ -254,7 +254,7 @@ class SearchBox { this.editor._emit("findSearchBox", { match: !noMatch }); this.highlight(); this.updateCounter(); - }; + } updateCounter() { var editor = this.editor; var regex = editor.$search.$options.re; @@ -286,13 +286,13 @@ class SearchBox { } } this.searchCounter.textContent = before + " of " + (all > MAX_COUNT ? MAX_COUNT + "+" : all); - }; + } findNext() { this.find(true, false); - }; + } findPrev() { this.find(true, true); - }; + } findAll(){ var range = this.editor.findAll(this.searchInput.value, { regExp: this.regExpOption.checked, @@ -304,21 +304,21 @@ class SearchBox { this.editor._emit("findSearchBox", { match: !noMatch }); this.highlight(); this.hide(); - }; + } replace() { if (!this.editor.getReadOnly()) this.editor.replace(this.replaceInput.value); - }; + } replaceAndFindNext() { if (!this.editor.getReadOnly()) { this.editor.replace(this.replaceInput.value); this.findNext(); } - }; + } replaceAll() { if (!this.editor.getReadOnly()) this.editor.replaceAll(this.replaceInput.value); - }; + } hide() { this.active = false; @@ -328,7 +328,7 @@ class SearchBox { this.element.style.display = "none"; this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb); this.editor.focus(); - }; + } show(value, isReplace) { this.active = true; this.editor.on("changeSession", this.setSession); @@ -344,12 +344,12 @@ class SearchBox { this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb); this.$syncOptions(true); - }; + } isFocused() { var el = document.activeElement; return el == this.searchInput || el == this.replaceInput; - }; + } } exports.SearchBox = SearchBox; diff --git a/src/ext/static_highlight.js b/src/ext/static_highlight.js index 3538a34a544..060c3bb684d 100644 --- a/src/ext/static_highlight.js +++ b/src/ext/static_highlight.js @@ -16,11 +16,11 @@ class Element { cloneNode() { return this; - }; + } appendChild(child) { this.textContent += child.toString(); - }; + } toString() { var stringBuilder = []; @@ -46,7 +46,7 @@ class Element { } return stringBuilder.join(""); - }; + } } diff --git a/src/ext/statusbar.js b/src/ext/statusbar.js index b0d60373caf..ece9d0fede2 100644 --- a/src/ext/statusbar.js +++ b/src/ext/statusbar.js @@ -18,7 +18,7 @@ class StatusBar{ editor.on("changeStatus", statusUpdate); editor.on("changeSelection", statusUpdate); editor.on("keyboardActivity", statusUpdate); - }; + } updateStatus(editor) { var status = []; @@ -42,7 +42,7 @@ class StatusBar{ add("[" + sel.rangeCount + "]", " "); status.pop(); this.element.textContent = status.join(""); - }; + } } exports.StatusBar = StatusBar; diff --git a/src/incremental_search.js b/src/incremental_search.js index 750c5bc3804..f9b5e428abb 100644 --- a/src/incremental_search.js +++ b/src/incremental_search.js @@ -1,6 +1,5 @@ "use strict"; -var oop = require("./lib/oop"); var Range = require("./range").Range; var Search = require("./search").Search; var SearchHighlight = require("./search_highlight").SearchHighlight; @@ -63,7 +62,7 @@ class IncrementalSearch extends Search { this.$mousedownHandler = editor.on('mousedown', this.onMouseDown.bind(this)); this.selectionFix(editor); this.statusMessage(true); - }; + } deactivate(reset) { this.cancelSearch(reset); @@ -75,7 +74,7 @@ class IncrementalSearch extends Search { } editor.onPaste = this.$originalEditorOnPaste; this.message(''); - }; + } selectionFix(editor) { // Fix selection bug: When clicked inside the editor @@ -86,7 +85,7 @@ class IncrementalSearch extends Search { if (editor.selection.isEmpty() && !editor.session.$emacsMark) { editor.clearSelection(); } - }; + } highlight(regexp) { var sess = this.$editor.session, @@ -94,7 +93,7 @@ class IncrementalSearch extends Search { new SearchHighlight(null, "ace_isearch-result", "text")); hl.setRegexp(regexp); sess._emit("changeBackMarker"); // force highlight layer redraw - }; + } cancelSearch(reset) { var e = this.$editor; @@ -108,7 +107,7 @@ class IncrementalSearch extends Search { } this.highlight(null); return Range.fromPoints(this.$currentPos, this.$currentPos); - }; + } highlightAndFindWithNeedle(moveToNext, needleUpdateFunc) { if (!this.$editor) return null; @@ -140,7 +139,7 @@ class IncrementalSearch extends Search { this.statusMessage(found); return found; - }; + } addString(s) { return this.highlightAndFindWithNeedle(false, function(needle) { @@ -150,7 +149,7 @@ class IncrementalSearch extends Search { reObj.expression += s; return objectToRegExp(reObj); }); - }; + } removeChar(c) { return this.highlightAndFindWithNeedle(false, function(needle) { @@ -160,7 +159,7 @@ class IncrementalSearch extends Search { reObj.expression = reObj.expression.substring(0, reObj.expression.length-1); return objectToRegExp(reObj); }); - }; + } next(options) { // try to find the next occurrence of whatever we have searched for @@ -173,29 +172,29 @@ class IncrementalSearch extends Search { return options.useCurrentOrPrevSearch && needle.length === 0 ? this.$prevNeedle || '' : needle; }); - }; + } onMouseDown(evt) { // when mouse interaction happens then we quit incremental search this.deactivate(); return true; - }; + } onPaste(text) { this.addString(text); - }; + } convertNeedleToRegExp() { return this.highlightAndFindWithNeedle(false, function(needle) { return isRegExp(needle) ? needle : stringToRegExp(needle, 'ig'); }); - }; + } convertNeedleToString() { return this.highlightAndFindWithNeedle(false, function(needle) { return isRegExp(needle) ? regExpToObject(needle).expression : needle; }); - }; + } statusMessage(found) { var options = this.$options, msg = ''; @@ -203,14 +202,14 @@ class IncrementalSearch extends Search { msg += 'isearch: ' + options.needle; msg += found ? '' : ' (not found)'; this.message(msg); - }; + } message(msg) { if (this.$editor.showCommandLine) { this.$editor.showCommandLine(msg); this.$editor.focus(); } - }; + } } diff --git a/src/keyboard/keybinding.js b/src/keyboard/keybinding.js index 4b375945354..70c2897f5cc 100644 --- a/src/keyboard/keybinding.js +++ b/src/keyboard/keybinding.js @@ -10,13 +10,13 @@ class KeyBinding { this.$data = {editor: editor}; this.$handlers = []; this.setDefaultHandler(editor.commands); - }; + } setDefaultHandler(kb) { this.removeKeyboardHandler(this.$defaultHandler); this.$defaultHandler = kb; this.addKeyboardHandler(kb, 0); - }; + } setKeyboardHandler(kb) { var h = this.$handlers; @@ -27,7 +27,7 @@ class KeyBinding { this.removeKeyboardHandler(h[h.length - 1]); this.addKeyboardHandler(kb, 1); - }; + } addKeyboardHandler(kb, pos) { if (!kb) @@ -45,7 +45,7 @@ class KeyBinding { if (i == -1 && kb.attach) kb.attach(this.$editor); - }; + } removeKeyboardHandler(kb) { var i = this.$handlers.indexOf(kb); @@ -54,11 +54,11 @@ class KeyBinding { this.$handlers.splice(i, 1); kb.detach && kb.detach(this.$editor); return true; - }; + } getKeyboardHandler() { return this.$handlers[this.$handlers.length - 1]; - }; + } getStatusText() { var data = this.$data; @@ -66,7 +66,7 @@ class KeyBinding { return this.$handlers.map(function(h) { return h.getStatusText && h.getStatusText(editor, data) || ""; }).filter(Boolean).join(" "); - }; + } $callKeyboardHandlers(hashId, keyString, keyCode, e) { var toExecute; @@ -105,16 +105,16 @@ class KeyBinding { this.$editor._signal("keyboardActivity", toExecute); return success; - }; + } onCommandKey(e, hashId, keyCode) { var keyString = keyUtil.keyCodeToString(keyCode); return this.$callKeyboardHandlers(hashId, keyString, keyCode, e); - }; + } onTextInput(text) { return this.$callKeyboardHandlers(-1, text); - }; + } } diff --git a/src/layer/cursor.js b/src/layer/cursor.js index 828e8988dfb..3b369cdce38 100644 --- a/src/layer/cursor.js +++ b/src/layer/cursor.js @@ -18,13 +18,13 @@ class Cursor { this.cursor = this.addCursor(); dom.addCssClass(this.element, "ace_hidden-cursors"); this.$updateCursors = this.$updateOpacity.bind(this); - }; + } $updateOpacity(val) { var cursors = this.cursors; for (var i = cursors.length; i--; ) dom.setStyle(cursors[i].style, "opacity", val ? "" : "0"); - }; + } $startCssAnimation() { var cursors = this.cursors; @@ -37,35 +37,34 @@ class Cursor { dom.addCssClass(this.element, "ace_animate-blinking"); } }.bind(this)); - }; + } $stopCssAnimation() { this.$isAnimating = false; dom.removeCssClass(this.element, "ace_animate-blinking"); - }; - - $padding = 0; + } + setPadding(padding) { this.$padding = padding; - }; + } setSession(session) { this.session = session; - }; + } setBlinking(blinking) { if (blinking != this.isBlinking) { this.isBlinking = blinking; this.restartTimer(); } - }; + } setBlinkInterval(blinkInterval) { if (blinkInterval != this.blinkInterval) { this.blinkInterval = blinkInterval; this.restartTimer(); } - }; + } setSmoothBlinking(smoothBlinking) { if (smoothBlinking != this.smoothBlinking) { @@ -74,7 +73,7 @@ class Cursor { this.$updateCursors(true); this.restartTimer(); } - }; + } addCursor() { var el = dom.createElement("div"); @@ -82,7 +81,7 @@ class Cursor { this.element.appendChild(el); this.cursors.push(el); return el; - }; + } removeCursor() { if (this.cursors.length > 1) { @@ -90,19 +89,19 @@ class Cursor { el.parentNode.removeChild(el); return el; } - }; + } hideCursor() { this.isVisible = false; dom.addCssClass(this.element, "ace_hidden-cursors"); this.restartTimer(); - }; + } showCursor() { this.isVisible = true; dom.removeCssClass(this.element, "ace_hidden-cursors"); this.restartTimer(); - }; + } restartTimer() { var update = this.$updateCursors; @@ -146,7 +145,7 @@ class Cursor { }, this.blinkInterval); blink(); } - }; + } getPixelPosition(position, onScreen) { if (!this.config || !this.session) @@ -163,11 +162,11 @@ class Cursor { this.config.lineHeight; return {left : cursorLeft, top : cursorTop}; - }; + } isCursorInView(pixelPos, config) { return pixelPos.top >= 0 && pixelPos.top < config.maxHeight; - }; + } update(config) { this.config = config; @@ -211,9 +210,7 @@ class Cursor { // cache for textarea and gutter highlight this.$pixelPos = pixelPos; this.restartTimer(); - }; - - drawCursor = null; + } $setOverwrite(overwrite) { if (overwrite != this.overwrite) { @@ -223,13 +220,17 @@ class Cursor { else dom.removeCssClass(this.element, "ace_overwrite-cursors"); } - }; + } destroy() { clearInterval(this.intervalId); clearTimeout(this.timeoutId); - }; + } } +Cursor.prototype.$padding = 0; +Cursor.prototype.drawCursor = null; + + exports.Cursor = Cursor; diff --git a/src/layer/decorators.js b/src/layer/decorators.js index 88d927ba425..c4a835bef87 100644 --- a/src/layer/decorators.js +++ b/src/layer/decorators.js @@ -37,7 +37,7 @@ class Decorator { parent.element.appendChild(this.canvas); - }; + } $updateDecorators(config) { var colors = (this.renderer.theme.isDark === true) ? this.colors.dark : this.colors.light; @@ -106,7 +106,7 @@ class Decorator { ctx.fillRect(0, currentY, this.canvasWidth, 2); } - }; + } compensateFoldRows(row, foldData) { let compensateFold = 0; @@ -121,7 +121,7 @@ class Decorator { } } return compensateFold; - }; + } } oop.implement(Decorator.prototype, EventEmitter); diff --git a/src/layer/font_metrics.js b/src/layer/font_metrics.js index 83c56d85d97..adb95c0480c 100644 --- a/src/layer/font_metrics.js +++ b/src/layer/font_metrics.js @@ -35,9 +35,7 @@ class FontMetrics { this.$addObserver(); else this.checkForSizeChanges(); - }; - - $characterSize = {width: 0, height: 0}; + } $setMeasureNodeStyles(style, isRoot) { style.width = style.height = "auto"; @@ -52,7 +50,7 @@ class FontMetrics { style.font = "inherit"; } style.overflow = isRoot ? "hidden" : "visible"; - }; + } checkForSizeChanges(size) { if (size === undefined) @@ -66,7 +64,7 @@ class FontMetrics { this.allowBoldFonts = boldSize && boldSize.width === size.width && boldSize.height === size.height; this._emit("changeCharacterSize", {data: size}); } - }; + } $addObserver() { var self = this; @@ -75,7 +73,7 @@ class FontMetrics { self.checkForSizeChanges(); }); this.$observer.observe(this.$measureNode); - }; + } $pollSizeChanges() { if (this.$pollSizeChangesTimer || this.$observer) @@ -86,7 +84,7 @@ class FontMetrics { self.checkForSizeChanges(); event.onIdle(cb, 500); }, 500); - }; + } setPolling(val) { if (val) { @@ -95,7 +93,7 @@ class FontMetrics { clearInterval(this.$pollSizeChangesTimer); this.$pollSizeChangesTimer = 0; } - }; + } $measureSizes(node) { var size = { @@ -108,13 +106,13 @@ class FontMetrics { if (size.width === 0 || size.height === 0) return null; return size; - }; + } $measureCharWidth(ch) { this.$main.textContent = lang.stringRepeat(ch, CHAR_COUNT); var rect = this.$main.getBoundingClientRect(); return rect.width / CHAR_COUNT; - }; + } getCharacterWidth(ch) { var w = this.charSizes[ch]; @@ -122,7 +120,7 @@ class FontMetrics { w = this.charSizes[ch] = this.$measureCharWidth(ch) / this.$characterSize.width; } return w; - }; + } destroy() { clearInterval(this.$pollSizeChangesTimer); @@ -130,13 +128,13 @@ class FontMetrics { this.$observer.disconnect(); if (this.el && this.el.parentNode) this.el.parentNode.removeChild(this.el); - }; + } $getZoom(element) { if (!element || !element.parentElement) return 1; return (window.getComputedStyle(element).zoom || 1) * this.$getZoom(element.parentElement); - }; + } $initTransformMeasureNodes() { var t = function(t, l) { @@ -145,7 +143,7 @@ class FontMetrics { }]; }; this.els = dom.buildDom([t(0, 0), t(L, 0), t(0, L), t(L, L)], this.el); - }; + } // general transforms from element coordinates x to screen coordinates u have the form // | m1[0] m2[0] t[0] | | x | | u | // | m1[1] m2[1] t[1] | . | y | == k | v | @@ -195,9 +193,10 @@ class FontMetrics { var u = sub(clientPos, a); var f = solve(sub(m1, mul(h[0], u)), sub(m2, mul(h[1], u)), u); return mul(L, f); - }; + } } +FontMetrics.prototype.$characterSize = {width: 0, height: 0}; oop.implement(FontMetrics.prototype, EventEmitter); diff --git a/src/layer/gutter.js b/src/layer/gutter.js index 7bb6a01fdae..5afccb24605 100644 --- a/src/layer/gutter.js +++ b/src/layer/gutter.js @@ -20,7 +20,7 @@ class Gutter{ this.$lines = new Lines(this.element); this.$lines.$offsetCoefficient = 1; - }; + } setSession(session) { if (this.session) @@ -28,19 +28,19 @@ class Gutter{ this.session = session; if (session) session.on("change", this.$updateAnnotations); - }; + } addGutterDecoration(row, className) { if (window.console) console.warn && console.warn("deprecated use session.addGutterDecoration"); this.session.addGutterDecoration(row, className); - }; + } removeGutterDecoration(row, className) { if (window.console) console.warn && console.warn("deprecated use session.removeGutterDecoration"); this.session.removeGutterDecoration(row, className); - }; + } setAnnotations(annotations) { // iterate over sparse array @@ -69,7 +69,7 @@ class Gutter{ else if (type == "info" && (!rowInfo.className)) rowInfo.className = " ace_info"; } - }; + } $updateAnnotations(delta) { if (!this.$annotations.length) @@ -85,7 +85,7 @@ class Gutter{ args.unshift(firstRow, 1); this.$annotations.splice.apply(this.$annotations, args); } - }; + } update(config) { this.config = config; @@ -135,7 +135,7 @@ class Gutter{ this._signal("afterRender"); this.$updateGutterWidth(config); - }; + } $updateGutterWidth(config) { var session = this.session; @@ -160,7 +160,7 @@ class Gutter{ this.element.style.width = Math.ceil(this.gutterWidth) + "px"; this._signal("changeGutterWidth", gutterWidth); } - }; + } $updateCursorRow() { if (!this.$highlightGutterLine) @@ -171,7 +171,7 @@ class Gutter{ return; this.$cursorRow = position.row; - }; + } updateLineHighlight() { if (!this.$highlightGutterLine) @@ -200,7 +200,7 @@ class Gutter{ break; } } - }; + } scrollLines(config) { var oldConfig = this.config; @@ -243,7 +243,7 @@ class Gutter{ this._signal("afterRender"); this.$updateGutterWidth(config); - }; + } $renderLines(config, firstRow, lastRow) { var fragment = []; @@ -267,7 +267,7 @@ class Gutter{ row++; } return fragment; - }; + } $renderCell(cell, config, fold, row) { var element = cell.element; @@ -344,30 +344,24 @@ class Gutter{ cell.text = text; return cell; - }; - - $fixedWidth = false; + } - $highlightGutterLine = true; - $renderer = ""; setHighlightGutterLine(highlightGutterLine) { this.$highlightGutterLine = highlightGutterLine; - }; + } - $showLineNumbers = true; - $renderer = ""; + setShowLineNumbers(show) { this.$renderer = !show && { getWidth: function() {return 0;}, getText: function() {return "";} }; - }; + } getShowLineNumbers() { return this.$showLineNumbers; - }; + } - $showFoldWidgets = true; setShowFoldWidgets(show) { if (show) dom.addCssClass(this.element, "ace_folding-enabled"); @@ -376,11 +370,11 @@ class Gutter{ this.$showFoldWidgets = show; this.$padding = null; - }; + } getShowFoldWidgets() { return this.$showFoldWidgets; - }; + } $computePadding() { if (!this.element.firstChild) @@ -392,7 +386,7 @@ class Gutter{ this.$padding.right = (parseInt(style.borderRightWidth) || 0) + (parseInt(style.paddingRight) || 0); return this.$padding; - }; + } getRegion(point) { var padding = this.$padding || this.$computePadding(); @@ -401,10 +395,16 @@ class Gutter{ return "markers"; if (this.$showFoldWidgets && point.x > rect.right - padding.right) return "foldWidgets"; - }; + } } +Gutter.prototype.$fixedWidth = false; +Gutter.prototype.$highlightGutterLine = true; +Gutter.prototype.$renderer = ""; +Gutter.prototype.$showLineNumbers = true; +Gutter.prototype.$showFoldWidgets = true; + oop.implement(Gutter.prototype, EventEmitter); function onCreateCell(element) { diff --git a/src/layer/lines.js b/src/layer/lines.js index 207d3a12c7b..e2f9a1e808d 100644 --- a/src/layer/lines.js +++ b/src/layer/lines.js @@ -11,45 +11,45 @@ class Lines { this.cells = []; this.cellCache = []; this.$offsetCoefficient = 0; - }; + } moveContainer(config) { dom.translate(this.element, 0, -((config.firstRowScreen * config.lineHeight) % this.canvasHeight) - config.offset * this.$offsetCoefficient); - }; + } pageChanged(oldConfig, newConfig) { return ( Math.floor((oldConfig.firstRowScreen * oldConfig.lineHeight) / this.canvasHeight) !== Math.floor((newConfig.firstRowScreen * newConfig.lineHeight) / this.canvasHeight) ); - }; + } computeLineTop(row, config, session) { var screenTop = config.firstRowScreen * config.lineHeight; var screenPage = Math.floor(screenTop / this.canvasHeight); var lineTop = session.documentToScreenRow(row, 0) * config.lineHeight; return lineTop - (screenPage * this.canvasHeight); - }; + } computeLineHeight(row, config, session) { return config.lineHeight * session.getRowLineCount(row); - }; + } getLength() { return this.cells.length; - }; + } get(index) { return this.cells[index]; - }; + } shift() { this.$cacheCell(this.cells.shift()); - }; + } pop() { this.$cacheCell(this.cells.pop()); - }; + } push(cell) { if (Array.isArray(cell)) { @@ -63,7 +63,7 @@ class Lines { this.cells.push(cell); this.element.appendChild(cell.element); } - }; + } unshift(cell) { if (Array.isArray(cell)) { @@ -80,14 +80,14 @@ class Lines { this.cells.unshift(cell); this.element.insertAdjacentElement("afterbegin", cell.element); } - }; + } last() { if (this.cells.length) return this.cells[this.cells.length-1]; else return null; - }; + } $cacheCell(cell) { if (!cell) @@ -95,7 +95,7 @@ class Lines { cell.element.remove(); this.cellCache.push(cell); - }; + } createCell(row, config, session, initElement) { var cell = this.cellCache.pop(); @@ -115,7 +115,7 @@ class Lines { cell.row = row; return cell; - }; + } } diff --git a/src/layer/marker.js b/src/layer/marker.js index 50ca4495b82..f7edb09e58a 100644 --- a/src/layer/marker.js +++ b/src/layer/marker.js @@ -9,20 +9,18 @@ class Marker { this.element = dom.createElement("div"); this.element.className = "ace_layer ace_marker-layer"; parentEl.appendChild(this.element); - }; - - $padding = 0; - + } + setPadding(padding) { this.$padding = padding; - }; + } setSession(session) { this.session = session; - }; + } setMarkers(markers) { this.markers = markers; - }; + } elt(className, css) { var x = this.i != -1 && this.element.childNodes[this.i]; @@ -35,7 +33,7 @@ class Marker { } x.style.cssText = css; x.className = className; - }; + } update(config) { if (!config) return; @@ -77,11 +75,11 @@ class Marker { while (this.i < this.element.childElementCount) this.element.removeChild(this.element.lastChild); } - }; + } $getTop(row, layerConfig) { return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight; - }; + } // Draws a marker, which spans a range of text on multiple lines @@ -106,7 +104,7 @@ class Marker { + getBorderClass(row == start || row == start + 1 && range.start.column, prev < curr, curr > next, row == end), layerConfig, row == end ? 0 : 1, extraStyle); } - }; + } // Draws a multi line marker, where lines span the full width drawMultiLineMarker(stringBuilder, range, clazz, config, extraStyle) { @@ -161,7 +159,7 @@ class Marker { "top:"+ top+ "px;"+ "left:"+ padding+ "px;"+ (extraStyle || "") ); - }; + } // Draws a marker which covers part or whole width of a single screen line drawSingleLineMarker(stringBuilder, range, clazz, config, extraLength, extraStyle) { @@ -180,7 +178,7 @@ class Marker { "top:"+ top+ "px;"+ "left:"+ left+ "px;"+ (extraStyle || "") ); - }; + } // Draws Bidi marker which covers part or whole width of a single screen line drawBidiSingleLineMarker(stringBuilder, range, clazz, config, extraLength, extraStyle) { @@ -196,7 +194,7 @@ class Marker { "left:" + (padding + selection.left) + "px;" + (extraStyle || "") ); }, this); - }; + } drawFullLineMarker(stringBuilder, range, clazz, config, extraStyle) { var top = this.$getTop(range.start.row, config); @@ -210,7 +208,7 @@ class Marker { "top:"+ top+ "px;"+ "left:0;right:0;"+ (extraStyle || "") ); - }; + } drawScreenLineMarker(stringBuilder, range, clazz, config, extraStyle) { var top = this.$getTop(range.start.row, config); @@ -222,10 +220,12 @@ class Marker { "top:"+ top+ "px;"+ "left:0;right:0;"+ (extraStyle || "") ); - }; + } } +Marker.prototype.$padding = 0; + function getBorderClass(tl, tr, br, bl) { return (tl ? 1 : 0) | (tr ? 2 : 0) | (br ? 4 : 0) | (bl ? 8 : 0); } diff --git a/src/layer/text.js b/src/layer/text.js index c3268dfdfb3..264fc55b29f 100644 --- a/src/layer/text.js +++ b/src/layer/text.js @@ -15,7 +15,7 @@ class Text { parentEl.appendChild(this.element); this.$updateEolChar = this.$updateEolChar.bind(this); this.$lines = new Lines(this.element); - }; + } $updateEolChar() { var doc = this.session.doc; @@ -25,20 +25,20 @@ class Text { this.EOL_CHAR = EOL_CHAR; return true; } - }; + } setPadding(padding) { this.$padding = padding; this.element.style.margin = "0 " + padding + "px"; - }; + } getLineHeight() { return this.$fontMetrics.$characterSize.height || 0; - }; + } getCharacterWidth() { return this.$fontMetrics.$characterSize.width || 0; - }; + } $setFontMetrics(measure) { this.$fontMetrics = measure; @@ -46,19 +46,19 @@ class Text { this._signal("changeCharacterSize", e); }.bind(this)); this.$pollSizeChanges(); - }; + } checkForSizeChanges() { this.$fontMetrics.checkForSizeChanges(); - }; + } $pollSizeChanges() { return this.$pollSizeChangesTimer = this.$fontMetrics.$pollSizeChanges(); - }; + } setSession(session) { this.session = session; if (session) this.$computeTabString(); - }; + } setShowInvisibles(showInvisibles) { if (this.showInvisibles == showInvisibles) @@ -74,7 +74,7 @@ class Text { } this.$computeTabString(); return true; - }; + } setDisplayIndentGuides(display) { if (this.displayIndentGuides == display) @@ -83,14 +83,14 @@ class Text { this.displayIndentGuides = display; this.$computeTabString(); return true; - }; + } setHighlightIndentGuides(highlight) { if (this.$highlightIndentGuides === highlight) return false; this.$highlightIndentGuides = highlight; return highlight; - }; + } $computeTabString() { var tabSize = this.session.getTabSize(); @@ -129,8 +129,7 @@ class Text { span.textContent = tabContent; this.$tabStrings["\t"] = span; } - }; - onChangeTabSize = this.$computeTabString; + } updateLines(config, firstRow, lastRow) { // Due to wrap line changes there can be new lines if e.g. @@ -199,7 +198,7 @@ class Text { cell.element.style.top = this.$lines.computeLineTop(cell.row, config, this.session) + "px"; } } - }; + } scrollLines(config) { var oldConfig = this.config; @@ -241,7 +240,7 @@ class Text { this.$lines.push(this.$renderLinesFragment(config, oldConfig.lastRow + 1, config.lastRow)); } this.$highlightIndentGuide(); - }; + } $renderLinesFragment(config, firstRow, lastRow) { var fragment = []; @@ -279,7 +278,7 @@ class Text { row++; } return fragment; - }; + } update(config) { this.$lines.moveContainer(config); @@ -294,7 +293,7 @@ class Text { lines.pop(); lines.push(this.$renderLinesFragment(config, firstRow, lastRow)); - }; + } $renderToken(parent, screenColumn, token, value) { var self = this; @@ -377,7 +376,7 @@ class Text { } return screenColumn + value.length; - }; + } renderIndentGuide(parent, value, max) { var cols = value.search(this.$indentGuideRe); @@ -400,7 +399,7 @@ class Text { } this.$highlightIndentGuide(); return value; - }; + } $highlightIndentGuide() { if (!this.$highlightIndentGuides || !this.displayIndentGuides) return; @@ -454,7 +453,7 @@ class Text { } this.$renderHighlightIndentGuide(); - }; + } $clearActiveIndentGuide() { var cells = this.$lines.cells; @@ -470,7 +469,7 @@ class Text { } } } - }; + } $setIndentGuideActive(cell, indentLevel) { var line = this.session.doc.getLine(cell.row); @@ -482,7 +481,7 @@ class Text { "ace_indent-guide-active"); } } - }; + } $renderHighlightIndentGuide() { if (!this.$lines) return; @@ -510,7 +509,7 @@ class Text { } } } - }; + } $createLineElement(parent) { var lineEl = this.dom.createElement("div"); @@ -518,7 +517,7 @@ class Text { lineEl.style.height = this.config.lineHeight + "px"; return lineEl; - }; + } $renderWrappedLine(parent, tokens, splits) { var chars = 0; @@ -572,7 +571,7 @@ class Text { if (splits[splits.length - 1] > this.MAX_LINE_LENGTH) this.$renderOverflowMessage(lineEl, screenColumn, null, "", true); - }; + } $renderSimpleLine(parent, tokens) { var screenColumn = 0; @@ -589,7 +588,7 @@ class Text { return this.$renderOverflowMessage(parent, screenColumn, token, value); screenColumn = this.$renderToken(parent, screenColumn, token, value); } - }; + } $renderOverflowMessage(parent, screenColumn, token, value, hide) { token && this.$renderToken(parent, screenColumn, token, @@ -600,7 +599,7 @@ class Text { overflowEl.textContent = hide ? "" : ""; parent.appendChild(overflowEl); - }; + } // row is either first row of foldline or not in fold $renderLine(parent, row, foldLine) { @@ -641,7 +640,7 @@ class Text { lastLineEl.appendChild(invisibleEl); } - }; + } $getFoldLineTokens(row, foldLine) { var session = this.session; @@ -702,7 +701,7 @@ class Text { }, foldLine.end.row, this.session.getLine(foldLine.end.row).length); return renderTokens; - }; + } $useLineGroups() { // For the updateLines function to work correctly, it's important that the @@ -711,7 +710,7 @@ class Text { // wrapped, this means we need to add a layer to the node hierarchy (tagged // with the class name ace_line_group). return this.session.getUseWrapMode(); - }; + } } Text.prototype.$textToken = { @@ -735,6 +734,7 @@ Text.prototype.displayIndentGuides = true; Text.prototype.$highlightIndentGuides = true; Text.prototype.$tabStrings = []; Text.prototype.destroy = {}; +Text.prototype.onChangeTabSize = Text.prototype.$computeTabString; oop.implement(Text.prototype, EventEmitter); diff --git a/src/lib/app_config.js b/src/lib/app_config.js index d29a4d66d03..31c82fc1f11 100644 --- a/src/lib/app_config.js +++ b/src/lib/app_config.js @@ -67,7 +67,7 @@ function reportError(msg, data) { class AppConfig { constructor() { this.$defaultOptions = {}; - }; + } /* * option {name, value, initialValue, setterName, set, get } @@ -91,7 +91,7 @@ class AppConfig { oop.implement(obj, optionsProvider); return this; - }; + } resetOptions(obj) { Object.keys(obj.$options).forEach(function(key) { @@ -99,7 +99,7 @@ class AppConfig { if ("value" in opt) obj.setOption(key, opt.value); }); - }; + } setDefaultValue(path, name, value) { if (!path) { @@ -116,17 +116,17 @@ class AppConfig { else opts[name].value = value; } - }; + } setDefaultValues(path, optionHash) { Object.keys(optionHash).forEach(function(key) { this.setDefaultValue(path, key, optionHash[key]); }, this); - }; + } - warn = warn; - reportError = reportError; } +AppConfig.prototype.warn = warn; +AppConfig.prototype.reportError = reportError; // module loading oop.implement(AppConfig.prototype, EventEmitter); diff --git a/src/line_widgets.js b/src/line_widgets.js index d6d9a88a5e2..ad19e2f5821 100644 --- a/src/line_widgets.js +++ b/src/line_widgets.js @@ -32,7 +32,7 @@ class LineWidgets { } else { return this.$wrapData[row].length + 1 + h; } - }; + } $getWidgetScreenLength() { var screenRows = 0; @@ -41,11 +41,11 @@ class LineWidgets { screenRows += w.rowCount; }); return screenRows; - }; + } $onChangeEditor(e) { this.attach(e.editor); - }; + } attach(editor) { if (editor && editor.widgetManager && editor.widgetManager != this) @@ -62,7 +62,7 @@ class LineWidgets { editor.renderer.on("beforeRender", this.measureWidgets); editor.renderer.on("afterRender", this.renderWidgets); } - }; + } detach(e) { var editor = this.editor; if (!editor) @@ -80,7 +80,7 @@ class LineWidgets { w.el.parentNode.removeChild(w.el); } }); - }; + } updateOnFold(e, session) { var lineWidgets = session.lineWidgets; @@ -106,7 +106,7 @@ class LineWidgets { lineWidgets[end].hidden = hide; } } - }; + } updateOnChange(delta) { var lineWidgets = this.session.lineWidgets; @@ -136,7 +136,7 @@ class LineWidgets { lineWidgets.splice.apply(lineWidgets, args); this.$updateRows(); } - }; + } $updateRows() { var lineWidgets = this.session.lineWidgets; @@ -154,7 +154,7 @@ class LineWidgets { }); if (noWidgets) this.session.lineWidgets = null; - }; + } $registerLineWidget(w) { if (!this.session.lineWidgets) @@ -171,7 +171,7 @@ class LineWidgets { this.session.lineWidgets[w.row] = w; return w; - }; + } addLineWidget(w) { this.$registerLineWidget(w); @@ -225,7 +225,7 @@ class LineWidgets { this.renderWidgets(null, renderer); this.onWidgetChanged(w); return w; - }; + } removeLineWidget(w) { w._inDocument = false; @@ -253,7 +253,7 @@ class LineWidgets { } this.session._emit("changeFold", {data:{start:{row: w.row}}}); this.$updateRows(); - }; + } getWidgetsAtRow(row) { var lineWidgets = this.session.lineWidgets; @@ -264,12 +264,12 @@ class LineWidgets { w = w.$oldWidget; } return list; - }; + } onWidgetChanged(w) { this.session._changedWidgets.push(w); this.editor && this.editor.renderer.updateFull(); - }; + } measureWidgets(e, renderer) { var changedWidgets = this.session._changedWidgets; @@ -312,7 +312,7 @@ class LineWidgets { this.session.lineWidgetWidth = null; } this.session._changedWidgets = []; - }; + } renderWidgets(e, renderer) { var config = renderer.layerConfig; @@ -360,7 +360,7 @@ class LineWidgets { w.el.style.right = ""; } } - }; + } } diff --git a/src/mouse/default_gutter_handler.js b/src/mouse/default_gutter_handler.js index c85ea94c9b5..f6944ff9b51 100644 --- a/src/mouse/default_gutter_handler.js +++ b/src/mouse/default_gutter_handler.js @@ -1,6 +1,5 @@ "use strict"; var dom = require("../lib/dom"); -var oop = require("../lib/oop"); var event = require("../lib/event"); var Tooltip = require("../tooltip").Tooltip; @@ -141,7 +140,7 @@ class GutterTooltip extends Tooltip { y -= 20 + height; } Tooltip.prototype.setPosition.call(this, x, y); - }; + } } diff --git a/src/mouse/default_handlers.js b/src/mouse/default_handlers.js index 2daaa002aee..de020471ee5 100644 --- a/src/mouse/default_handlers.js +++ b/src/mouse/default_handlers.js @@ -65,7 +65,7 @@ class DefaultHandlers { this.captureMouse(ev); this.startSelect(pos, ev.domEvent._clicks > 1); return ev.preventDefault(); - }; + } startSelect(pos, waitForClickSelection) { pos = pos || this.editor.renderer.screenToTextCoordinates(this.x, this.y); @@ -80,7 +80,7 @@ class DefaultHandlers { this.select(); editor.setStyle("ace_selecting"); this.setState("select"); - }; + } select() { var anchor, editor = this.editor; @@ -101,7 +101,7 @@ class DefaultHandlers { } editor.selection.selectToPosition(cursor); editor.renderer.scrollCursorIntoView(); - }; + } extendSelectionBy(unitName) { var anchor, editor = this.editor; @@ -131,16 +131,12 @@ class DefaultHandlers { } editor.selection.selectToPosition(cursor); editor.renderer.scrollCursorIntoView(); - }; + } selectByLinesEnd() { this.$clickSelection = null; this.editor.unsetStyle("ace_selecting"); - }; - - selectEnd = this.selectByLinesEnd; - selectAllEnd = this.selectByLinesEnd; - selectByWordsEnd = this.selectByLinesEnd; + } focusWait() { var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y); @@ -148,7 +144,7 @@ class DefaultHandlers { if (distance > DRAG_OFFSET || time - this.mousedownEvent.time > this.$focusTimeout) this.startSelect(this.mousedownEvent.getDocumentPosition()); - }; + } onDoubleClick(ev) { var pos = ev.getDocumentPosition(); @@ -168,7 +164,7 @@ class DefaultHandlers { } this.$clickSelection = range; this.select(); - }; + } onTripleClick(ev) { var pos = ev.getDocumentPosition(); @@ -183,7 +179,7 @@ class DefaultHandlers { this.$clickSelection = editor.selection.getLineRange(pos.row); } this.select(); - }; + } onQuadClick(ev) { var editor = this.editor; @@ -191,7 +187,7 @@ class DefaultHandlers { editor.selectAll(); this.$clickSelection = editor.getSelectionRange(); this.setState("selectAll"); - }; + } onMouseWheel(ev) { if (ev.getAccelKey()) @@ -251,9 +247,12 @@ class DefaultHandlers { editor.renderer.scrollBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed); return ev.stop(); } - }; + } } +DefaultHandlers.prototype.selectEnd = DefaultHandlers.prototype.selectByLinesEnd; +DefaultHandlers.prototype.selectAllEnd = DefaultHandlers.prototype.selectByLinesEnd; +DefaultHandlers.prototype.selectByWordsEnd = DefaultHandlers.prototype.selectByLinesEnd; exports.DefaultHandlers = DefaultHandlers; diff --git a/src/mouse/mouse_event.js b/src/mouse/mouse_event.js index 2c6ddf668e3..f7b9f063598 100644 --- a/src/mouse/mouse_event.js +++ b/src/mouse/mouse_event.js @@ -19,22 +19,28 @@ class MouseEvent { this.propagationStopped = false; this.defaultPrevented = false; - }; + + this.getAccelKey = useragent.isMac ? function () { + return this.domEvent.metaKey; + } : function () { + return this.domEvent.ctrlKey; + }; + } stopPropagation() { event.stopPropagation(this.domEvent); this.propagationStopped = true; - }; + } preventDefault() { event.preventDefault(this.domEvent); this.defaultPrevented = true; - }; + } stop() { this.stopPropagation(); this.preventDefault(); - }; + } /** * Get the document position below the mouse cursor @@ -47,7 +53,7 @@ class MouseEvent { this.$pos = this.editor.renderer.screenToTextCoordinates(this.clientX, this.clientY); return this.$pos; - }; + } /** * Check if the mouse cursor is inside of the text selection @@ -70,7 +76,7 @@ class MouseEvent { } return this.$inSelection; - }; + } /** * Get the clicked mouse button @@ -79,18 +85,14 @@ class MouseEvent { */ getButton() { return event.getButton(this.domEvent); - }; + } /** * @return {Boolean} whether the shift key was pressed when the event was emitted */ getShiftKey() { return this.domEvent.shiftKey; - }; - - getAccelKey = useragent.isMac - ? function() { return this.domEvent.metaKey; } - : function() { return this.domEvent.ctrlKey; }; + } } diff --git a/src/mouse/mouse_handler.js b/src/mouse/mouse_handler.js index 9601007fd38..35cca30d300 100644 --- a/src/mouse/mouse_handler.js +++ b/src/mouse/mouse_handler.js @@ -71,12 +71,12 @@ class MouseHandler { renderer.setCursorStyle(""); } }, editor); - }; + } onMouseEvent(name, e) { if (!this.editor.session) return; this.editor._emit(name, new MouseEvent(e, this.editor)); - }; + } onMouseMove(name, e) { // optimization, because mousemove doesn't have a default handler. @@ -85,7 +85,7 @@ class MouseHandler { return; this.editor._emit(name, new MouseEvent(e, this.editor)); - }; + } onMouseWheel(name, e) { var mouseEvent = new MouseEvent(e, this.editor); @@ -94,11 +94,11 @@ class MouseHandler { mouseEvent.wheelY = e.wheelY; this.editor._emit(name, mouseEvent); - }; + } setState(state) { this.state = state; - }; + } captureMouse(ev, mouseMoveHandler) { this.x = ev.x; @@ -166,8 +166,7 @@ class MouseHandler { self.$onCaptureMouseMove = onMouseMove; self.releaseMouse = event.capture(this.editor.container, onMouseMove, onCaptureEnd); var timerId = setInterval(onCaptureInterval, 20); - }; - releaseMouse = null; + } cancelContextMenu() { var stop = function(e) { if (e && e.domEvent && e.domEvent.type != "contextmenu") @@ -178,12 +177,14 @@ class MouseHandler { }.bind(this); setTimeout(stop, 10); this.editor.on("nativecontextmenu", stop); - }; + } destroy() { if (this.releaseMouse) this.releaseMouse(); - }; + } } +MouseHandler.prototype.releaseMouse = null; + config.defineOptions(MouseHandler.prototype, "mouseHandler", { scrollSpeed: {initialValue: 2}, dragDelay: {initialValue: (useragent.isMac ? 150 : 0)}, diff --git a/src/occur.js b/src/occur.js index f17bca2ec23..34c03f34fde 100644 --- a/src/occur.js +++ b/src/occur.js @@ -1,7 +1,6 @@ "use strict"; var oop = require("./lib/oop"); -var Range = require("./range").Range; var Search = require("./search").Search; var EditSession = require("./edit_session").EditSession; var SearchHighlight = require("./search_highlight").SearchHighlight; @@ -34,7 +33,7 @@ class Occur extends Search { var translatedPos = this.originalToOccurPosition(editor.session, pos); editor.moveCursorToPosition(translatedPos); return true; - }; + } /** * Disables occur mode. Resets the [[Sessions `EditSession`]] [[Document @@ -52,14 +51,14 @@ class Occur extends Search { if (translatedPos) editor.moveCursorToPosition(translatedPos); return true; - }; + } highlight(sess, regexp) { var hl = sess.$occurHighlight = sess.$occurHighlight || sess.addDynamicMarker( new SearchHighlight(null, "ace_occur-highlight", "text")); hl.setRegexp(regexp); sess._emit("changeBackMarker"); // force highlight layer redraw - }; + } displayOccurContent(editor, options) { // this.setSession(session || new EditSession("")) @@ -74,12 +73,12 @@ class Occur extends Search { occurSession.$useEmacsStyleLineStart = this.$useEmacsStyleLineStart; this.highlight(occurSession, options.re); occurSession._emit('changeBackMarker'); - }; + } displayOriginalContent(editor) { editor.setSession(this.$originalSession); this.$originalSession.$useEmacsStyleLineStart = this.$useEmacsStyleLineStart; - }; + } /** * Translates the position from the original document to the occur lines in @@ -98,7 +97,7 @@ class Occur extends Search { return {row: i, column: pos.column}; } return nullPos; - }; + } /** * Translates the position from the occur document to the original document @@ -112,7 +111,7 @@ class Occur extends Search { if (!lines || !lines[pos.row]) return pos; return {row: lines[pos.row].row, column: pos.column}; - }; + } matchingLines(session, options) { options = oop.mixin({}, options); @@ -126,7 +125,7 @@ class Occur extends Search { lines : lines.concat({row: row, content: session.getLine(row)}); }, []); - }; + } } diff --git a/src/placeholder.js b/src/placeholder.js index 024e999082b..a90ea2e5f95 100644 --- a/src/placeholder.js +++ b/src/placeholder.js @@ -37,7 +37,7 @@ class PlaceHolder { this.setup(); session.selection.on("changeCursor", this.$onCursorChange); - }; + } /** * PlaceHolder.setup() @@ -67,7 +67,7 @@ class PlaceHolder { _self.others.push(anchor); }); session.setUndoSelect(false); - }; + } /** * PlaceHolder.showOtherMarkers() @@ -83,7 +83,7 @@ class PlaceHolder { this.others.forEach(function(anchor) { anchor.markerId = session.addMarker(new Range(anchor.row, anchor.column, anchor.row, anchor.column+_self.length), _self.othersClass, null, false); }); - }; + } /** * PlaceHolder.hideOtherMarkers() @@ -97,7 +97,7 @@ class PlaceHolder { for (var i = 0; i < this.others.length; i++) { this.session.removeMarker(this.others[i].markerId); } - }; + } /** * PlaceHolder@onUpdate(e) @@ -140,14 +140,14 @@ class PlaceHolder { this.$updating = false; this.updateMarkers(); - }; + } updateAnchors(delta) { this.pos.onChange(delta); for (var i = this.others.length; i--;) this.others[i].onChange(delta); this.updateMarkers(); - }; + } updateMarkers() { if (this.$updating) @@ -161,7 +161,7 @@ class PlaceHolder { updateMarker(this.pos, this.mainClass); for (var i = this.others.length; i--;) updateMarker(this.others[i], this.othersClass); - }; + } /** * PlaceHolder@onCursorChange(e) @@ -180,7 +180,7 @@ class PlaceHolder { this.hideOtherMarkers(); this._emit("cursorLeave", event); } - }; + } /** * PlaceHolder.detach() @@ -195,7 +195,7 @@ class PlaceHolder { this.session.selection.off("changeCursor", this.$onCursorChange); this.session.setUndoSelect(true); this.session = null; - }; + } /** * PlaceHolder.cancel() @@ -213,7 +213,7 @@ class PlaceHolder { } if (this.selectionBefore) this.session.selection.fromJSON(this.selectionBefore); - }; + } } oop.implement(PlaceHolder.prototype, EventEmitter); diff --git a/src/range.js b/src/range.js index 8420a0e1579..63eef84e50f 100644 --- a/src/range.js +++ b/src/range.js @@ -26,7 +26,7 @@ class Range { row: endRow, column: endColumn }; - }; + } /** * Returns `true` if and only if the starting row and column, and ending row and column, are equivalent to those given by `range`. @@ -38,7 +38,7 @@ class Range { this.end.row === range.end.row && this.start.column === range.start.column && this.end.column === range.end.column; - }; + } /** * Returns a string containing the range's row and column information, given like this: @@ -50,7 +50,7 @@ class Range { toString() { return ("Range: [" + this.start.row + "/" + this.start.column + "] -> [" + this.end.row + "/" + this.end.column + "]"); - }; + } /** * Returns `true` if the `row` and `column` provided are within the given range. This can better be expressed as returning `true` if: @@ -66,7 +66,7 @@ class Range { contains(row, column) { return this.compare(row, column) == 0; - }; + } /** * Compares `this` range (A) with another range (B). @@ -107,7 +107,7 @@ class Range { return 0; } } - }; + } /** * Compares the row and column of `p` with the starting and ending [[Point]]'s of the calling range (by calling [[Range.compare]]). @@ -117,7 +117,7 @@ class Range { **/ comparePoint(p) { return this.compare(p.row, p.column); - }; + } /** * Checks the start and end [[Point]]'s of `range` and compares them to the calling range. Returns `true` if the `range` is contained within the caller's range. @@ -127,7 +127,7 @@ class Range { **/ containsRange(range) { return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; - }; + } /** * Returns `true` if passed in `range` intersects with the one calling this method. @@ -137,7 +137,7 @@ class Range { intersects(range) { var cmp = this.compareRange(range); return (cmp == -1 || cmp == 0 || cmp == 1); - }; + } /** * Returns `true` if the caller's ending row is the same as `row`, and if the caller's ending column is the same as `column`. @@ -147,7 +147,7 @@ class Range { **/ isEnd(row, column) { return this.end.row == row && this.end.column == column; - }; + } /** * Returns `true` if the caller's starting row is the same as `row`, and if the caller's starting column is the same as `column`. @@ -157,7 +157,7 @@ class Range { **/ isStart(row, column) { return this.start.row == row && this.start.column == column; - }; + } /** * Sets the starting row and column for the range. @@ -173,7 +173,7 @@ class Range { this.start.row = row; this.start.column = column; } - }; + } /** * Sets the starting row and column for the range. @@ -189,7 +189,7 @@ class Range { this.end.row = row; this.end.column = column; } - }; + } /** * Returns `true` if the `row` and `column` are within the given range. @@ -207,7 +207,7 @@ class Range { } } return false; - }; + } /** * Returns `true` if the `row` and `column` are within the given range's starting [[Point]]. @@ -225,7 +225,7 @@ class Range { } } return false; - }; + } /** * Returns `true` if the `row` and `column` are within the given range's ending [[Point]]. @@ -244,7 +244,7 @@ class Range { } } return false; - }; + } /** * Compares the `row` and `column` with the starting and ending [[Point]]'s of the calling range. @@ -283,7 +283,7 @@ class Range { return column <= this.end.column ? 0 : 1; return 0; - }; + } /** * Compares the `row` and `column` with the starting and ending [[Point]]'s of the calling range. @@ -299,7 +299,7 @@ class Range { } else { return this.compare(row, column); } - }; + } /** * Compares the `row` and `column` with the starting and ending [[Point]]'s of the calling range. @@ -315,7 +315,7 @@ class Range { } else { return this.compare(row, column); } - }; + } /** * Compares the `row` and `column` with the start and end [[Point]]'s of the calling range. @@ -334,7 +334,7 @@ class Range { } else { return this.compare(row, column); } - }; + } /** * Returns the part of the current `Range` that occurs within the boundaries of `firstRow` and `lastRow` as a new `Range` object. @@ -354,7 +354,7 @@ class Range { var start = {row: firstRow, column: 0}; return Range.fromPoints(start || this.start, end || this.end); - }; + } /** * Changes the `row` and `column` for the calling range for both the starting and ending [[Point]]'s. @@ -373,7 +373,7 @@ class Range { var end = {row: row, column: column}; return Range.fromPoints(start || this.start, end || this.end); - }; + } /** * Returns `true` if the calling range is empty (starting [[Point]] == ending [[Point]]). @@ -381,7 +381,7 @@ class Range { **/ isEmpty() { return (this.start.row === this.end.row && this.start.column === this.end.column); - }; + } /** * Returns `true` if the range spans across multiple lines. @@ -389,7 +389,7 @@ class Range { **/ isMultiLine() { return (this.start.row !== this.end.row); - }; + } /** * Returns a duplicate of the calling range. @@ -397,7 +397,7 @@ class Range { **/ clone() { return Range.fromPoints(this.start, this.end); - }; + } /** * Returns a range containing the starting and ending rows of the original range, but with a column value of `0`. @@ -408,7 +408,7 @@ class Range { return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0); else return new Range(this.start.row, 0, this.end.row, 0); - }; + } /** * Given the current `Range`, this function converts those starting and ending [[Point]]'s into screen positions, and then returns a new `Range` object. @@ -423,7 +423,7 @@ class Range { screenPosStart.row, screenPosStart.column, screenPosEnd.row, screenPosEnd.column ); - }; + } /** * Shift the calling range by `row` and `column` values. @@ -436,7 +436,7 @@ class Range { this.start.column += column; this.end.row += row; this.end.column += column; - }; + } } diff --git a/src/range_list.js b/src/range_list.js index f50e44cdebc..bc5322caaa5 100644 --- a/src/range_list.js +++ b/src/range_list.js @@ -8,8 +8,6 @@ class RangeList { this.ranges = []; this.$bias = 1; } - - comparePoints = comparePoints; pointIndex(pos, excludeEdges, startIndex) { var list = this.ranges; @@ -28,7 +26,7 @@ class RangeList { return -i-1; } return -i - 1; - }; + } add(range) { var excludeEdges = !range.isEmpty(); @@ -43,7 +41,7 @@ class RangeList { else endIndex++; return this.ranges.splice(startIndex, endIndex - startIndex, range); - }; + } addList(list) { var removed = []; @@ -51,14 +49,14 @@ class RangeList { removed.push.apply(removed, this.add(list[i])); } return removed; - }; + } substractPoint(pos) { var i = this.pointIndex(pos); if (i >= 0) return this.ranges.splice(i, 1); - }; + } // merge overlapping ranges merge() { @@ -94,21 +92,21 @@ class RangeList { this.ranges = list; return removed; - }; + } contains(row, column) { return this.pointIndex({row: row, column: column}) >= 0; - }; + } containsPoint(pos) { return this.pointIndex(pos) >= 0; - }; + } rangeAtPoint(pos) { var i = this.pointIndex(pos); if (i >= 0) return this.ranges[i]; - }; + } clipRows(startRow, endRow) { @@ -128,11 +126,11 @@ class RangeList { clipped.push(list[i]); } return clipped; - }; + } removeAll() { return this.ranges.splice(0, this.ranges.length); - }; + } attach(session) { if (this.session) @@ -142,14 +140,14 @@ class RangeList { this.onChange = this.$onChange.bind(this); this.session.on('change', this.onChange); - }; + } detach() { if (!this.session) return; this.session.removeListener('change', this.onChange); this.session = null; - }; + } $onChange(delta) { var start = delta.start; @@ -260,8 +258,10 @@ class RangeList { r.end.row += lineDif; } } - }; + } } +RangeList.prototype.comparePoints = comparePoints; + exports.RangeList = RangeList; diff --git a/src/renderloop.js b/src/renderloop.js index 864b84cdf64..f0b7f70ec14 100644 --- a/src/renderloop.js +++ b/src/renderloop.js @@ -32,7 +32,7 @@ class RenderLoop { _self.$recursionLimit = 2; } }; - }; + } schedule(change) { this.changes = this.changes | change; @@ -40,13 +40,13 @@ class RenderLoop { event.nextFrame(this._flush); this.pending = true; } - }; + } clear(change) { var changes = this.changes; this.changes = 0; return changes; - }; + } } diff --git a/src/scrollbar.js b/src/scrollbar.js index feb3d2dbc9b..1098aaa5b25 100644 --- a/src/scrollbar.js +++ b/src/scrollbar.js @@ -35,13 +35,13 @@ class Scrollbar { event.addListener(this.element, "scroll", this.onScroll.bind(this)); event.addListener(this.element, "mousedown", event.preventDefault); - }; + } setVisible(isVisible) { this.element.style.display = isVisible ? "" : "none"; this.isVisible = isVisible; this.coeff = 1; - }; + } } oop.implement(Scrollbar.prototype, EventEmitter); @@ -69,7 +69,7 @@ class VScrollBar extends Scrollbar { this.inner.style.width = this.element.style.width = (this.width || 15) + 5 + "px"; this.$minWidth = 0; - }; + } /** @@ -87,7 +87,7 @@ class VScrollBar extends Scrollbar { this._emit("scroll", {data: this.scrollTop}); } this.skipEvent = false; - }; + } /** * Returns the width of the scroll bar. @@ -95,7 +95,7 @@ class VScrollBar extends Scrollbar { **/ getWidth() { return Math.max(this.isVisible ? this.width : 0, this.$minWidth || 0); - }; + } /** * Sets the height of the scroll bar, in pixels. @@ -103,7 +103,7 @@ class VScrollBar extends Scrollbar { **/ setHeight(height) { this.element.style.height = height + "px"; - }; + } /** * Sets the scroll height of the scroll bar, in pixels. @@ -118,14 +118,8 @@ class VScrollBar extends Scrollbar { this.coeff = 1; } this.inner.style.height = height + "px"; - }; - - /** - * Sets the inner height of the scroll bar, in pixels. - * @param {Number} height The new inner height - * @deprecated Use setScrollHeight instead - **/ - setInnerHeight = this.setScrollHeight; + } + /** * Sets the scroll top of the scroll bar. @@ -139,10 +133,17 @@ class VScrollBar extends Scrollbar { this.scrollTop = scrollTop; this.element.scrollTop = scrollTop * this.coeff; } - }; + } } +/** + * Sets the inner height of the scroll bar, in pixels. + * @param {Number} height The new inner height + * @deprecated Use setScrollHeight instead + **/ +VScrollBar.prototype.setInnerHeight = VScrollBar.prototype.setScrollHeight; + /** * Represents a horisontal scroll bar. **/ @@ -164,7 +165,7 @@ class HScrollBar extends Scrollbar { this.height = renderer.$scrollbarWidth; this.inner.style.height = this.element.style.height = (this.height || 15) + 5 + "px"; - }; + } /** * Emitted when the scroll bar, well, scrolls. @@ -177,7 +178,7 @@ class HScrollBar extends Scrollbar { this._emit("scroll", {data: this.scrollLeft}); } this.skipEvent = false; - }; + } /** * Returns the height of the scroll bar. @@ -185,7 +186,7 @@ class HScrollBar extends Scrollbar { **/ getHeight() { return this.isVisible ? this.height : 0; - }; + } /** * Sets the width of the scroll bar, in pixels. @@ -193,7 +194,7 @@ class HScrollBar extends Scrollbar { **/ setWidth(width) { this.element.style.width = width + "px"; - }; + } /** * Sets the inner width of the scroll bar, in pixels. @@ -202,7 +203,7 @@ class HScrollBar extends Scrollbar { **/ setInnerWidth(width) { this.inner.style.width = width + "px"; - }; + } /** * Sets the scroll width of the scroll bar, in pixels. @@ -210,7 +211,7 @@ class HScrollBar extends Scrollbar { **/ setScrollWidth(width) { this.inner.style.width = width + "px"; - }; + } /** * Sets the scroll left of the scroll bar. @@ -223,7 +224,7 @@ class HScrollBar extends Scrollbar { this.skipEvent = true; this.scrollLeft = this.element.scrollLeft = scrollLeft; } - }; + } } diff --git a/src/scrollbar_custom.js b/src/scrollbar_custom.js index cb51213aed9..095d2038ba8 100644 --- a/src/scrollbar_custom.js +++ b/src/scrollbar_custom.js @@ -68,13 +68,13 @@ class ScrollBar { this.skipEvent = false; event.addMultiMouseDownListener(this.element, [500, 300, 300], this, "onMouseDown"); - }; + } setVisible(isVisible) { this.element.style.display = isVisible ? "" : "none"; this.isVisible = isVisible; this.coeff = 1; - }; + } } oop.implement(ScrollBar.prototype, EventEmitter); @@ -101,7 +101,7 @@ class VScrollBar extends ScrollBar { this.renderer = renderer; this.inner.style.width = this.element.style.width = (this.width || 15) + "px"; this.$minWidth = 0; - }; + } /** * Emitted when the scroll thumb dragged or scrollbar canvas clicked. @@ -141,11 +141,11 @@ class VScrollBar extends ScrollBar { var top = e.clientY - this.element.getBoundingClientRect().top - this.thumbHeight / 2; this._emit("scroll", {data: this.scrollTopFromThumbTop(top)}); return event.preventDefault(e); - }; + } getHeight() { return this.height; - }; + } /** * Returns new top for scroll thumb @@ -162,7 +162,7 @@ class VScrollBar extends ScrollBar { scrollTop = this.pageHeight - this.viewHeight; } return scrollTop; - }; + } /** * Returns the width of the scroll bar. @@ -170,7 +170,7 @@ class VScrollBar extends ScrollBar { **/ getWidth() { return Math.max(this.isVisible ? this.width : 0, this.$minWidth || 0); - }; + } /** * Sets the height of the scroll bar, in pixels. @@ -182,7 +182,7 @@ class VScrollBar extends ScrollBar { this.viewHeight = this.height; this.setScrollHeight(this.pageHeight, true); - }; + } /** * Sets the inner and scroll height of the scroll bar, in pixels. @@ -205,9 +205,7 @@ class VScrollBar extends ScrollBar { if (this.scrollTop < 0) this.scrollTop = 0; this._emit("scroll", {data: this.scrollTop}); } - }; - - setInnerHeight = this.setScrollHeight; + } /** * Sets the scroll top of the scroll bar. @@ -218,9 +216,10 @@ class VScrollBar extends ScrollBar { if (scrollTop < 0) scrollTop = 0; this.thumbTop = scrollTop * (this.slideHeight - this.thumbHeight) / (this.pageHeight - this.viewHeight); this.inner.style.top = this.thumbTop + "px"; - }; + } } +VScrollBar.prototype.setInnerHeight = VScrollBar.prototype.setScrollHeight; /** * Represents a horizontal scroll bar. @@ -238,7 +237,7 @@ class HScrollBar extends ScrollBar { this.height = this.HScrollHeight; this.inner.style.height = this.element.style.height = (this.height || 12) + "px"; this.renderer = renderer; - }; + } /** * Emitted when the scroll thumb dragged or scrollbar canvas clicked. @@ -280,7 +279,7 @@ class HScrollBar extends ScrollBar { var left = e.clientX - this.element.getBoundingClientRect().left - this.thumbWidth / 2; this._emit("scroll", {data: this.scrollLeftFromThumbLeft(left)}); return event.preventDefault(e); - }; + } /** * Returns the height of the scroll bar. @@ -288,7 +287,7 @@ class HScrollBar extends ScrollBar { **/ getHeight() { return this.isVisible ? this.height : 0; - }; + } /** * Returns new left for scroll thumb @@ -305,7 +304,7 @@ class HScrollBar extends ScrollBar { scrollLeft = this.pageWidth - this.viewWidth; } return scrollLeft; - }; + } /** * Sets the width of the scroll bar, in pixels. @@ -318,7 +317,7 @@ class HScrollBar extends ScrollBar { this.viewWidth = this.width; this.setScrollWidth(this.pageWidth, true); - }; + } /** * Sets the inner and scroll width of the scroll bar, in pixels. @@ -339,9 +338,8 @@ class HScrollBar extends ScrollBar { if (this.scrollLeft < 0) this.scrollLeft = 0; this._emit("scroll", {data: this.scrollLeft}); } - }; + } - setInnerWidth = this.setScrollWidth; /** * Sets the scroll left of the scroll bar. @@ -352,10 +350,12 @@ class HScrollBar extends ScrollBar { if (scrollLeft < 0) scrollLeft = 0; this.thumbLeft = scrollLeft * (this.slideWidth - this.thumbWidth) / (this.pageWidth - this.viewWidth); this.inner.style.left = (this.thumbLeft) + "px"; - }; + } } +HScrollBar.prototype.setInnerWidth = HScrollBar.prototype.setScrollWidth; + exports.ScrollBar = VScrollBar; // backward compatibility exports.ScrollBarV = VScrollBar; // backward compatibility exports.ScrollBarH = HScrollBar; // backward compatibility diff --git a/src/search.js b/src/search.js index dc82cfa5223..6b31b525b72 100644 --- a/src/search.js +++ b/src/search.js @@ -37,7 +37,7 @@ class Search { set(options) { oop.mixin(this.$options, options); return this; - }; + } /** * [Returns an object containing all the search options.]{: #Search.getOptions} @@ -45,7 +45,7 @@ class Search { **/ getOptions() { return lang.copyObject(this.$options); - }; + } /** * Sets the search options via the `options` parameter. @@ -54,7 +54,7 @@ class Search { **/ setOptions(options) { this.$options = options; - }; + } /** * Searches for `options.needle`. If found, this method returns the [[Range `Range`]] where the text first occurs. If `options.backwards` is `true`, the search goes backwards in the session. * @param {EditSession} session The session to search with @@ -82,7 +82,7 @@ class Search { }); return firstRange; - }; + } /** * Searches for all occurrances `options.needle`. If found, this method returns an array of [[Range `Range`s]] where the text first occurs. If `options.backwards` is `true`, the search goes backwards in the session. @@ -158,7 +158,7 @@ class Search { } return ranges; - }; + } /** * Searches for `options.needle` in `input`, and, if found, replaces it with `replacement`. @@ -198,7 +198,7 @@ class Search { } return replacement; - }; + } $assembleRegExp(options, $disableFakeMultiline) { if (options.needle instanceof RegExp) @@ -227,7 +227,7 @@ class Search { re = false; } return options.re = re; - }; + } $assembleMultilineRegExp(needle, modifier) { var parts = needle.replace(/\r\n|\r|\n/g, "$\n^").split("\n"); @@ -238,7 +238,7 @@ class Search { return false; } return re; - }; + } $matchIterator(session, options) { var re = this.$assembleRegExp(options); @@ -352,7 +352,7 @@ class Search { }; } return {forEach: forEach}; - }; + } } diff --git a/src/search_highlight.js b/src/search_highlight.js index 3258be72e86..68a3ce9bd6b 100644 --- a/src/search_highlight.js +++ b/src/search_highlight.js @@ -1,7 +1,6 @@ "use strict"; var lang = require("./lib/lang"); -var oop = require("./lib/oop"); var Range = require("./range").Range; var SearchHighlight = @@ -11,17 +10,14 @@ class SearchHighlight { this.setRegexp(regExp); this.clazz = clazz; this.type = type; - }; - - // needed to prevent long lines from freezing the browser - MAX_RANGES = 500; + } setRegexp(regExp) { if (this.regExp+"" == regExp+"") return; this.regExp = regExp; this.cache = []; - }; + } update(html, markerLayer, session, config) { if (!this.regExp) @@ -51,8 +47,11 @@ class SearchHighlight { html, rangeToAddMarkerTo, this.clazz, config); } } - }; + } }; +// needed to prevent long lines from freezing the browser +SearchHighlight.prototype.MAX_RANGES = 500; + exports.SearchHighlight = SearchHighlight; diff --git a/src/token_iterator.js b/src/token_iterator.js index da54baf8afe..ae1caa48a69 100644 --- a/src/token_iterator.js +++ b/src/token_iterator.js @@ -19,7 +19,7 @@ class TokenIterator { var token = session.getTokenAt(initialRow, initialColumn); this.$tokenIndex = token ? token.index : -1; - }; + } /** * Moves iterator position to the start of previous token. @@ -40,7 +40,7 @@ class TokenIterator { } return this.$rowTokens[this.$tokenIndex]; - }; + } /** * Moves iterator position to the start of next token. @@ -63,7 +63,7 @@ class TokenIterator { } return this.$rowTokens[this.$tokenIndex]; - }; + } /** * @@ -72,7 +72,7 @@ class TokenIterator { **/ getCurrentToken() { return this.$rowTokens[this.$tokenIndex]; - }; + } /** * @@ -81,7 +81,7 @@ class TokenIterator { **/ getCurrentTokenRow() { return this.$row; - }; + } /** * @@ -104,7 +104,7 @@ class TokenIterator { } return column; - }; + } /** * Return the current token position. @@ -112,7 +112,7 @@ class TokenIterator { */ getCurrentTokenPosition() { return {row: this.$row, column: this.getCurrentTokenColumn()}; - }; + } /** * Return the current token range. @@ -122,7 +122,7 @@ class TokenIterator { var token = this.$rowTokens[this.$tokenIndex]; var column = this.getCurrentTokenColumn(); return new Range(this.$row, column, this.$row, column + token.value.length); - }; + } } diff --git a/src/tokenizer.js b/src/tokenizer.js index 781dcd86f4c..353ab56ecd8 100644 --- a/src/tokenizer.js +++ b/src/tokenizer.js @@ -99,11 +99,11 @@ class Tokenizer { this.regExps[key] = new RegExp("(" + ruleRegExps.join(")|(") + ")|($)", flag); } - }; + } $setMaxTokenCount(m) { MAX_TOKEN_COUNT = m | 0; - }; + } $applyToken(str) { var values = this.splitRegex.exec(str).slice(1); @@ -122,7 +122,7 @@ class Tokenizer { }; } return tokens; - }; + } $arrayTokens(str) { if (!str) @@ -140,7 +140,7 @@ class Tokenizer { }; } return tokens; - }; + } removeCapturingGroups(src) { var r = src.replace( @@ -148,7 +148,7 @@ class Tokenizer { function(x, y) {return y ? "(?:" : x;} ); return r; - }; + } createSplitterRegexp(src, flag) { if (src.indexOf("(?=") != -1) { @@ -187,7 +187,7 @@ class Tokenizer { if (src.charAt(src.length - 1) != "$") src += "$"; return new RegExp(src, (flag||"").replace("g", "")); - }; + } /** * Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state. @@ -327,10 +327,9 @@ class Tokenizer { tokens : tokens, state : stack.length ? stack : currentState }; - }; - - reportError = config.reportError; - + } } +Tokenizer.prototype.reportError = config.reportError; + exports.Tokenizer = Tokenizer; diff --git a/src/tokenizer_dev.js b/src/tokenizer_dev.js index 60cb5b9dc7b..62f6bc62f97 100644 --- a/src/tokenizer_dev.js +++ b/src/tokenizer_dev.js @@ -143,7 +143,7 @@ class Tokenizer extends BaseTokenizer { tokens : tokens, state : stack.length ? stack : currentState }; - }; + } } diff --git a/src/tooltip.js b/src/tooltip.js index e73abdf0e1d..37a220df3ce 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -20,28 +20,28 @@ class Tooltip { this.$element.style.display = "none"; this.$parentNode.appendChild(this.$element); return this.$element; - }; + } /** * @returns {Element} **/ getElement() { return this.$element || this.$init(); - }; + } /** * @param {String} text **/ setText(text) { this.getElement().textContent = text; - }; + } /** * @param {String} html **/ setHtml(html) { this.getElement().innerHTML = html; - }; + } /** * @param {Number} x @@ -50,14 +50,14 @@ class Tooltip { setPosition(x, y) { this.getElement().style.left = x + "px"; this.getElement().style.top = y + "px"; - }; + } /** * @param {String} className **/ setClassName(className) { dom.addCssClass(this.getElement(), className); - }; + } /** * @param {String} text @@ -73,7 +73,7 @@ class Tooltip { this.getElement().style.display = "block"; this.isOpen = true; } - }; + } hide() { if (this.isOpen) { @@ -81,28 +81,28 @@ class Tooltip { this.getElement().className = CLASSNAME; this.isOpen = false; } - }; + } /** * @returns {Number} **/ getHeight() { return this.getElement().offsetHeight; - }; + } /** * @returns {Number} **/ getWidth() { return this.getElement().offsetWidth; - }; + } destroy() { this.isOpen = false; if (this.$element && this.$element.parentNode) { this.$element.parentNode.removeChild(this.$element); } - }; + } } diff --git a/src/undomanager.js b/src/undomanager.js index 43fd51ab13c..6128177c93e 100644 --- a/src/undomanager.js +++ b/src/undomanager.js @@ -13,11 +13,11 @@ class UndoManager { this.$fromUndo = false; this.$undoDepth = Infinity; this.reset(); - }; + } addSession(session) { this.$session = session; - }; + } /** * Provides a means for implementing your own undo manager. `options` has one property, `args`, an [[Array `Array`]], with two elements: * @@ -43,19 +43,19 @@ class UndoManager { if (delta.action == "remove" || delta.action == "insert") this.$lastDelta = delta; this.lastDeltas.push(delta); - }; + } addSelection(selection, rev) { this.selections.push({ value: selection, rev: rev || this.$rev }); - }; + } startNewGroup() { this.lastDeltas = null; return this.$rev; - }; + } markIgnored(from, to) { if (to == null) to = this.$rev + 1; @@ -68,7 +68,7 @@ class UndoManager { delta.ignore = true; } this.lastDeltas = null; - }; + } getSelection(rev, after) { var stack = this.selections; @@ -80,11 +80,11 @@ class UndoManager { return selection; } } - }; + } getRevision() { return this.$rev; - }; + } getDeltas(from, to) { if (to == null) to = this.$rev + 1; @@ -100,17 +100,17 @@ class UndoManager { } } return stack.slice(start, end); - }; + } getChangedRanges(from, to) { if (to == null) to = this.$rev + 1; - }; + } getChangedLines(from, to) { if (to == null) to = this.$rev + 1; - }; + } /** * [Perform an undo operation on the document, reverting the last change.]{: #UndoManager.undo} @@ -145,7 +145,7 @@ class UndoManager { this.$fromUndo = false; return undoSelectionRange; - }; + } /** * [Perform a redo operation on the document, reimplementing the last change.]{: #UndoManager.redo} @@ -178,7 +178,7 @@ class UndoManager { this.$fromUndo = false; return redoSelectionRange; - }; + } $syncRev() { var stack = this.$undoStack; @@ -186,7 +186,7 @@ class UndoManager { var id = nextDelta && nextDelta[0].id || 0; this.$redoStackBaseRev = id; this.$rev = id; - }; + } /** * Destroys the stack of undo and redo redo operations. @@ -200,7 +200,7 @@ class UndoManager { this.mark = 0; this.$redoStackBaseRev = this.$rev; this.selections = []; - }; + } /** @@ -209,7 +209,7 @@ class UndoManager { **/ canUndo() { return this.$undoStack.length > 0; - }; + } /** * Returns `true` if there are redo operations left to perform. @@ -217,7 +217,7 @@ class UndoManager { **/ canRedo() { return this.$redoStack.length > 0; - }; + } /** * Marks the current status clean @@ -226,7 +226,7 @@ class UndoManager { if (rev == undefined) rev = this.$rev; this.mark = rev; - }; + } /** * Returns if the current status is clean @@ -234,27 +234,28 @@ class UndoManager { **/ isAtBookmark() { return this.$rev === this.mark; - }; + } toJSON() { - }; + } fromJSON() { - }; - - hasUndo = this.canUndo; - hasRedo = this.canRedo; - isClean = this.isAtBookmark; - markClean = this.bookmark; + } + $prettyPrint(delta) { if (delta) return stringifyDelta(delta); return stringifyDelta(this.$undoStack) + "\n---\n" + stringifyDelta(this.$redoStack); - }; + } } +UndoManager.prototype.hasUndo = UndoManager.prototype.canUndo; +UndoManager.prototype.hasRedo = UndoManager.prototype.canRedo; +UndoManager.prototype.isClean = UndoManager.prototype.isAtBookmark; +UndoManager.prototype.markClean = UndoManager.prototype.bookmark; + function rearrangeUndoStack(stack, pos) { for (var i = pos; i--; ) { var deltaSet = stack[i]; diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 23d8c91ceb1..d8b76288043 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -156,19 +156,8 @@ class VirtualRenderer { this.$addResizeObserver(); config.resetOptions(this); config._signal("renderer", this); - }; - - CHANGE_CURSOR = 1; - CHANGE_MARKER = 2; - CHANGE_GUTTER = 4; - CHANGE_SCROLL = 8; - CHANGE_LINES = 16; - CHANGE_TEXT = 32; - CHANGE_SIZE = 64; - CHANGE_MARKER_BACK = 128; - CHANGE_MARKER_FRONT = 256; - CHANGE_FULL = 512; - CHANGE_H_SCROLL = 1024; + } + // this.$logChanges = function(changes) { // var a = "" @@ -199,7 +188,7 @@ class VirtualRenderer { this.$updatePrintMargin(); // set explicit line height to avoid normal resolving to different values based on text dom.setStyle(this.scroller.style, "line-height", this.lineHeight + "px"); - }; + } /** * @@ -228,7 +217,7 @@ class VirtualRenderer { this.onChangeNewLineMode = this.onChangeNewLineMode.bind(this); this.onChangeNewLineMode(); this.session.doc.on("changeNewLineMode", this.onChangeNewLineMode); - }; + } /** * Triggers a partial update of the text, from the range given by the two parameters. @@ -267,25 +256,25 @@ class VirtualRenderer { if (this.$changedLines.firstRow > this.layerConfig.lastRow) return; this.$loop.schedule(this.CHANGE_LINES); - }; + } onChangeNewLineMode() { this.$loop.schedule(this.CHANGE_TEXT); this.$textLayer.$updateEolChar(); this.session.$bidiHandler.setEolChar(this.$textLayer.EOL_CHAR); - }; + } onChangeTabSize() { this.$loop.schedule(this.CHANGE_TEXT | this.CHANGE_MARKER); this.$textLayer.onChangeTabSize(); - }; + } /** * Triggers a full update of the text, for all the rows. **/ updateText() { this.$loop.schedule(this.CHANGE_TEXT); - }; + } /** * Triggers a full update of all the layers, for all the rows. @@ -296,22 +285,21 @@ class VirtualRenderer { this.$renderChanges(this.CHANGE_FULL, true); else this.$loop.schedule(this.CHANGE_FULL); - }; + } /** * Updates the font size. **/ updateFontSize() { this.$textLayer.checkForSizeChanges(); - }; + } - $changes = 0; $updateSizeAsync() { if (this.$loop.pending) this.$size.$dirty = true; else this.onResize(); - }; + } /** * [Triggers a resize of the editor.]{: #VirtualRenderer.onResize} * @param {Boolean} force If `true`, recomputes the size, even if the height and width haven't changed @@ -357,7 +345,7 @@ class VirtualRenderer { if (this.$customScrollbar) { this.$updateCustomScrollbar(true); } - }; + } $updateCachedSize(force, gutterWidth, width, height) { height -= (this.$extraHeight || 0); @@ -415,7 +403,7 @@ class VirtualRenderer { this._signal("resize", oldSize); return changes; - }; + } onGutterResize(width) { var gutterWidth = this.$showGutter ? width : 0; @@ -429,7 +417,7 @@ class VirtualRenderer { } else { this.$computeLayerConfig(); } - }; + } /** * Adjusts the wrap limit, which is the number of characters that can fit within the width of the edit area on screen. @@ -438,7 +426,7 @@ class VirtualRenderer { var availableWidth = this.$size.scrollerWidth - this.$padding * 2; var limit = Math.floor(availableWidth / this.characterWidth); return this.session.adjustWrapLimit(limit, this.$showPrintMargin && this.$printMarginColumn); - }; + } /** * Identifies whether you want to have an animated scroll or not. @@ -447,7 +435,7 @@ class VirtualRenderer { **/ setAnimatedScroll(shouldAnimate){ this.setOption("animatedScroll", shouldAnimate); - }; + } /** * Returns whether an animated scroll happens or not. @@ -455,7 +443,7 @@ class VirtualRenderer { **/ getAnimatedScroll() { return this.$animatedScroll; - }; + } /** * Identifies whether you want to show invisible characters or not. @@ -465,7 +453,7 @@ class VirtualRenderer { setShowInvisibles(showInvisibles) { this.setOption("showInvisibles", showInvisibles); this.session.$bidiHandler.setShowInvisibles(showInvisibles); - }; + } /** * Returns whether invisible characters are being shown or not. @@ -473,22 +461,22 @@ class VirtualRenderer { **/ getShowInvisibles() { return this.getOption("showInvisibles"); - }; + } getDisplayIndentGuide() { return this.getOption("displayIndentGuides"); - }; + } setDisplayIndentGuides(display) { this.setOption("displayIndentGuides", display); - }; + } getHighlightIndentGuides() { return this.getOption("highlightIndentGuides"); - }; + } setHighlightIndentGuides(highlight) { this.setOption("highlightIndentGuides", highlight); - }; + } /** * Identifies whether you want to show the print margin or not. @@ -497,7 +485,7 @@ class VirtualRenderer { **/ setShowPrintMargin(showPrintMargin) { this.setOption("showPrintMargin", showPrintMargin); - }; + } /** * Returns whether the print margin is being shown or not. @@ -505,7 +493,7 @@ class VirtualRenderer { **/ getShowPrintMargin() { return this.getOption("showPrintMargin"); - }; + } /** * Identifies whether you want to show the print margin column or not. * @param {Boolean} showPrintMargin Set to `true` to show the print margin column @@ -513,7 +501,7 @@ class VirtualRenderer { **/ setPrintMarginColumn(showPrintMargin) { this.setOption("printMarginColumn", showPrintMargin); - }; + } /** * Returns whether the print margin column is being shown or not. @@ -521,7 +509,7 @@ class VirtualRenderer { **/ getPrintMarginColumn() { return this.getOption("printMarginColumn"); - }; + } /** * Returns `true` if the gutter is being shown. @@ -529,7 +517,7 @@ class VirtualRenderer { **/ getShowGutter(){ return this.getOption("showGutter"); - }; + } /** * Identifies whether you want to show the gutter or not. @@ -538,23 +526,23 @@ class VirtualRenderer { **/ setShowGutter(show){ return this.setOption("showGutter", show); - }; + } getFadeFoldWidgets(){ return this.getOption("fadeFoldWidgets"); - }; + } setFadeFoldWidgets(show) { this.setOption("fadeFoldWidgets", show); - }; + } setHighlightGutterLine(shouldHighlight) { this.setOption("highlightGutterLine", shouldHighlight); - }; + } getHighlightGutterLine() { return this.getOption("highlightGutterLine"); - }; + } $updatePrintMargin() { if (!this.$showPrintMargin && !this.$printMarginEl) @@ -575,7 +563,7 @@ class VirtualRenderer { if (this.session && this.session.$wrap == -1) this.adjustWrapLimit(); - }; + } /** * @@ -584,7 +572,7 @@ class VirtualRenderer { **/ getContainerElement() { return this.container; - }; + } /** * @@ -593,7 +581,7 @@ class VirtualRenderer { **/ getMouseEventTarget() { return this.scroller; - }; + } /** * @@ -602,7 +590,7 @@ class VirtualRenderer { **/ getTextAreaContainer() { return this.container; - }; + } // move text input over the cursor // this is required for IME @@ -655,7 +643,7 @@ class VirtualRenderer { dom.setStyle(style, "height", h + "px"); dom.setStyle(style, "width", w + "px"); dom.translate(this.textarea, Math.min(posLeft, this.$size.scrollerWidth - w), Math.min(posTop, maxTop)); - }; + } /** * [Returns the index of the first visible row.]{: #VirtualRenderer.getFirstVisibleRow} @@ -663,7 +651,7 @@ class VirtualRenderer { **/ getFirstVisibleRow() { return this.layerConfig.firstRow; - }; + } /** * @@ -672,7 +660,7 @@ class VirtualRenderer { **/ getFirstFullyVisibleRow() { return this.layerConfig.firstRow + (this.layerConfig.offset === 0 ? 0 : 1); - }; + } /** * @@ -686,7 +674,7 @@ class VirtualRenderer { if (top - this.session.getScrollTop() > config.height - config.lineHeight) return lastRow - 1; return lastRow; - }; + } /** * @@ -695,9 +683,7 @@ class VirtualRenderer { **/ getLastVisibleRow() { return this.layerConfig.lastRow; - }; - - $padding = null; + } /** * Sets the padding for all the layers. @@ -712,7 +698,7 @@ class VirtualRenderer { this.$markerBack.setPadding(padding); this.$loop.schedule(this.CHANGE_FULL); this.$updatePrintMargin(); - }; + } setScrollMargin(top, bottom, left, right) { var sm = this.scrollMargin; @@ -725,7 +711,7 @@ class VirtualRenderer { if (sm.top && this.scrollTop <= 0 && this.session) this.session.setScrollTop(-sm.top); this.updateFull(); - }; + } setMargin(top, bottom, left, right) { var sm = this.margin; @@ -737,7 +723,7 @@ class VirtualRenderer { sm.h = sm.left + sm.right; this.$updateCachedSize(true, this.gutterWidth, this.$size.width, this.$size.height); this.updateFull(); - }; + } /** * Returns whether the horizontal scrollbar is set to be always visible. @@ -745,7 +731,7 @@ class VirtualRenderer { **/ getHScrollBarAlwaysVisible() { return this.$hScrollBarAlwaysVisible; - }; + } /** * Identifies whether you want to show the horizontal scrollbar or not. @@ -753,14 +739,14 @@ class VirtualRenderer { **/ setHScrollBarAlwaysVisible(alwaysVisible) { this.setOption("hScrollBarAlwaysVisible", alwaysVisible); - }; + } /** * Returns whether the horizontal scrollbar is set to be always visible. * @returns {Boolean} **/ getVScrollBarAlwaysVisible() { return this.$vScrollBarAlwaysVisible; - }; + } /** * Identifies whether you want to show the horizontal scrollbar or not. @@ -768,7 +754,7 @@ class VirtualRenderer { **/ setVScrollBarAlwaysVisible(alwaysVisible) { this.setOption("vScrollBarAlwaysVisible", alwaysVisible); - }; + } $updateScrollBarV() { var scrollHeight = this.layerConfig.maxHeight; @@ -782,20 +768,19 @@ class VirtualRenderer { } this.scrollBarV.setScrollHeight(scrollHeight + this.scrollMargin.v); this.scrollBarV.setScrollTop(this.scrollTop + this.scrollMargin.top); - }; + } $updateScrollBarH() { this.scrollBarH.setScrollWidth(this.layerConfig.width + 2 * this.$padding + this.scrollMargin.h); this.scrollBarH.setScrollLeft(this.scrollLeft + this.scrollMargin.left); - }; - - $frozen = false; + } + freeze() { this.$frozen = true; - }; + } unfreeze() { this.$frozen = false; - }; + } $renderChanges(changes, force) { if (this.$changes) { @@ -952,7 +937,7 @@ class VirtualRenderer { } this._signal("afterRender", changes); - }; + } $autosize() { @@ -984,7 +969,7 @@ class VirtualRenderer { this._signal("autosize"); } - }; + } $computeLayerConfig() { var session = this.session; @@ -1090,7 +1075,7 @@ class VirtualRenderer { // console.log(JSON.stringify(this.layerConfig)); return changes; - }; + } $updateLines() { if (!this.$changedLines) return; @@ -1114,7 +1099,7 @@ class VirtualRenderer { // else update only the changed rows this.$textLayer.updateLines(layerConfig, firstRow, lastRow); return true; - }; + } $getLongestLine() { var charCount = this.session.getScreenWidth(); @@ -1125,7 +1110,7 @@ class VirtualRenderer { charCount = this.$textLayer.MAX_LINE_LENGTH + 30; return Math.max(this.$size.scrollerWidth - 2 * this.$padding, Math.round(charCount * this.characterWidth)); - }; + } /** * Schedules an update to all the front markers in the document. @@ -1133,7 +1118,7 @@ class VirtualRenderer { updateFrontMarkers() { this.$markerFront.setMarkers(this.session.getMarkers(true)); this.$loop.schedule(this.CHANGE_MARKER_FRONT); - }; + } /** * @@ -1142,7 +1127,7 @@ class VirtualRenderer { updateBackMarkers() { this.$markerBack.setMarkers(this.session.getMarkers()); this.$loop.schedule(this.CHANGE_MARKER_BACK); - }; + } /** * @@ -1151,7 +1136,7 @@ class VirtualRenderer { **/ addGutterDecoration(row, className){ this.$gutterLayer.addGutterDecoration(row, className); - }; + } /** * Deprecated; (moved to [[EditSession]]) @@ -1159,7 +1144,7 @@ class VirtualRenderer { **/ removeGutterDecoration(row, className){ this.$gutterLayer.removeGutterDecoration(row, className); - }; + } /** * @@ -1167,7 +1152,7 @@ class VirtualRenderer { **/ updateBreakpoints(rows) { this.$loop.schedule(this.CHANGE_GUTTER); - }; + } /** * Sets annotations for the gutter. @@ -1177,7 +1162,7 @@ class VirtualRenderer { setAnnotations(annotations) { this.$gutterLayer.setAnnotations(annotations); this.$loop.schedule(this.CHANGE_GUTTER); - }; + } /** * @@ -1185,7 +1170,7 @@ class VirtualRenderer { **/ updateCursor() { this.$loop.schedule(this.CHANGE_CURSOR); - }; + } /** * @@ -1193,7 +1178,7 @@ class VirtualRenderer { **/ hideCursor() { this.$cursorLayer.hideCursor(); - }; + } /** * @@ -1201,13 +1186,13 @@ class VirtualRenderer { **/ showCursor() { this.$cursorLayer.showCursor(); - }; + } scrollSelectionIntoView(anchor, lead, offset) { // first scroll anchor into view then scroll lead into view this.scrollCursorIntoView(anchor, offset); this.scrollCursorIntoView(lead, offset); - }; + } /** * @@ -1262,7 +1247,7 @@ class VirtualRenderer { this.session.setScrollLeft(0); } } - }; + } /** * {:EditSession.getScrollTop} @@ -1271,7 +1256,7 @@ class VirtualRenderer { **/ getScrollTop() { return this.session.getScrollTop(); - }; + } /** * {:EditSession.getScrollLeft} @@ -1280,7 +1265,7 @@ class VirtualRenderer { **/ getScrollLeft() { return this.session.getScrollLeft(); - }; + } /** * Returns the first visible row, regardless of whether it's fully visible or not. @@ -1288,7 +1273,7 @@ class VirtualRenderer { **/ getScrollTopRow() { return this.scrollTop / this.lineHeight; - }; + } /** * Returns the last visible row, regardless of whether it's fully visible or not. @@ -1296,7 +1281,7 @@ class VirtualRenderer { **/ getScrollBottomRow() { return Math.max(0, Math.floor((this.scrollTop + this.$size.scrollerHeight) / this.lineHeight) - 1); - }; + } /** * Gracefully scrolls from the top of the editor to the row indicated. @@ -1306,7 +1291,7 @@ class VirtualRenderer { **/ scrollToRow(row) { this.session.setScrollTop(row * this.lineHeight); - }; + } alignCursor(cursor, alignment) { if (typeof cursor == "number") @@ -1318,9 +1303,8 @@ class VirtualRenderer { this.session.setScrollTop(offset); return offset; - }; + } - STEPS = 8; $calcSteps(fromValue, toValue){ var i = 0; var l = this.STEPS; @@ -1334,7 +1318,7 @@ class VirtualRenderer { steps.push(func(i / this.STEPS, fromValue, toValue - fromValue)); return steps; - }; + } /** * Gracefully scrolls the editor to the row indicated. @@ -1354,7 +1338,7 @@ class VirtualRenderer { this.session.setScrollTop(offset); if (animate !== false) this.animateScrolling(initialScroll, callback); - }; + } animateScrolling(fromValue, callback) { var toValue = this.scrollTop; @@ -1410,7 +1394,7 @@ class VirtualRenderer { endAnimation(); } }, 10); - }; + } /** * Scrolls the editor to the y pixel indicated. @@ -1425,7 +1409,7 @@ class VirtualRenderer { this.$loop.schedule(this.CHANGE_SCROLL); this.scrollTop = scrollTop; } - }; + } /** * Scrolls the editor across the x-axis to the pixel indicated. @@ -1437,7 +1421,7 @@ class VirtualRenderer { if (this.scrollLeft !== scrollLeft) this.scrollLeft = scrollLeft; this.$loop.schedule(this.CHANGE_H_SCROLL); - }; + } /** * Scrolls the editor across both x- and y-axes. @@ -1447,7 +1431,7 @@ class VirtualRenderer { scrollTo(x, y) { this.session.setScrollTop(y); this.session.setScrollLeft(x); - }; + } /** * Scrolls the editor across both x- and y-axes. @@ -1457,7 +1441,7 @@ class VirtualRenderer { scrollBy(deltaX, deltaY) { deltaY && this.session.setScrollTop(this.session.getScrollTop() + deltaY); deltaX && this.session.setScrollLeft(this.session.getScrollLeft() + deltaX); - }; + } /** * Returns `true` if you can still scroll by either parameter; in other words, you haven't reached the end of the file or line. @@ -1477,7 +1461,7 @@ class VirtualRenderer { if (deltaX > 0 && this.session.getScrollLeft() + this.$size.scrollerWidth - this.layerConfig.width < -1 + this.scrollMargin.right) return true; - }; + } pixelToScreenCoordinates(x, y) { var canvasPos; @@ -1496,7 +1480,7 @@ class VirtualRenderer { var col = this.$blockCursor ? Math.floor(offset) : Math.round(offset); return {row: row, column: col, side: offset - col > 0 ? 1 : -1, offsetX: offsetX}; - }; + } screenToTextCoordinates(x, y) { var canvasPos; @@ -1516,7 +1500,7 @@ class VirtualRenderer { var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight); return this.session.screenToDocumentPosition(row, Math.max(col, 0), offsetX); - }; + } /** * Returns an object containing the `pageX` and `pageY` coordinates of the document position. @@ -1539,7 +1523,7 @@ class VirtualRenderer { pageX: canvasPos.left + x - this.scrollLeft, pageY: canvasPos.top + y - this.scrollTop }; - }; + } /** * @@ -1547,7 +1531,7 @@ class VirtualRenderer { **/ visualizeFocus() { dom.addCssClass(this.container, "ace_focus"); - }; + } /** * @@ -1555,7 +1539,7 @@ class VirtualRenderer { **/ visualizeBlur() { dom.removeCssClass(this.container, "ace_focus"); - }; + } /** * @param {Object} composition @@ -1579,7 +1563,7 @@ class VirtualRenderer { else { composition.markerId = this.session.addMarker(composition.markerRange, "ace_composition_marker", "text"); } - }; + } /** * @param {String} text A string of text to use @@ -1590,7 +1574,7 @@ class VirtualRenderer { var cursor = this.session.selection.cursor; this.addToken(text, "composition_placeholder", cursor.row, cursor.column); this.$moveTextAreaToCursor(); - }; + } /** * @@ -1609,7 +1593,7 @@ class VirtualRenderer { this.removeExtraToken(cursor.row, cursor.column); this.$composition = null; this.$cursorLayer.element.style.display = ""; - }; + } setGhostText(text, position) { var cursor = this.session.selection.cursor; @@ -1636,7 +1620,7 @@ class VirtualRenderer { this.session.widgetManager.addLineWidget(this.$ghostTextWidget); } - }; + } removeGhostText() { if (!this.$ghostText) return; @@ -1648,7 +1632,7 @@ class VirtualRenderer { this.$ghostTextWidget = null; } this.$ghostText = null; - }; + } addToken(text, type, row, column) { var session = this.session; @@ -1673,12 +1657,12 @@ class VirtualRenderer { } } this.updateLines(row, row); - }; + } removeExtraToken(row, column) { this.session.bgTokenizer.lines[row] = null; this.updateLines(row, row); - }; + } /** * [Sets a new theme for the editor. `theme` should exist, and be a directory path, like `ace/theme/textmate`.]{: #VirtualRenderer.setTheme} @@ -1735,7 +1719,7 @@ class VirtualRenderer { _self._dispatchEvent('themeLoaded', {theme:module}); cb && cb(); } - }; + } /** * [Returns the path of the current theme.]{: #VirtualRenderer.getTheme} @@ -1743,7 +1727,7 @@ class VirtualRenderer { **/ getTheme() { return this.$themeId; - }; + } // Methods allows to add / remove CSS classnames to the editor element. // This feature can be used by plug-ins to provide a visual indication of @@ -1756,7 +1740,7 @@ class VirtualRenderer { **/ setStyle(style, include) { dom.setCssClass(this.container, style, include !== false); - }; + } /** * [Removes the class `style` from the editor.]{: #VirtualRenderer.unsetStyle} @@ -1765,11 +1749,11 @@ class VirtualRenderer { **/ unsetStyle(style) { dom.removeCssClass(this.container, style); - }; + } setCursorStyle(style) { dom.setStyle(this.scroller.style, "cursor", style); - }; + } /** * @param {String} cursorStyle A css cursor style @@ -1777,11 +1761,11 @@ class VirtualRenderer { **/ setMouseCursor(cursorStyle) { dom.setStyle(this.scroller.style, "cursor", cursorStyle); - }; + } attachToShadowRoot() { dom.importCssString(editorCss, "ace_editor.css", this.container); - }; + } /** * Destroys the text and cursor layers for this renderer. @@ -1793,7 +1777,7 @@ class VirtualRenderer { this.removeAllListeners(); this.container.textContent = ""; this.setOption("useResizeObserver", false); - }; + } $updateCustomScrollbar(val) { var _self = this; @@ -1828,7 +1812,7 @@ class VirtualRenderer { if (!_self.$scrollAnimation) _self.session.setScrollLeft(e.data - _self.scrollMargin.left); }); } - }; + } $addResizeObserver() { if (!window.ResizeObserver || this.$resizeObserver) return; @@ -1849,9 +1833,26 @@ class VirtualRenderer { } }); this.$resizeObserver.observe(this.container); - }; + } } + +VirtualRenderer.prototype.CHANGE_CURSOR = 1; +VirtualRenderer.prototype.CHANGE_MARKER = 2; +VirtualRenderer.prototype.CHANGE_GUTTER = 4; +VirtualRenderer.prototype.CHANGE_SCROLL = 8; +VirtualRenderer.prototype.CHANGE_LINES = 16; +VirtualRenderer.prototype.CHANGE_TEXT = 32; +VirtualRenderer.prototype.CHANGE_SIZE = 64; +VirtualRenderer.prototype.CHANGE_MARKER_BACK = 128; +VirtualRenderer.prototype.CHANGE_MARKER_FRONT = 256; +VirtualRenderer.prototype.CHANGE_FULL = 512; +VirtualRenderer.prototype.CHANGE_H_SCROLL = 1024; +VirtualRenderer.prototype.$changes = 0; +VirtualRenderer.prototype.$padding = null; +VirtualRenderer.prototype.$frozen = false; +VirtualRenderer.prototype.STEPS = 8; + oop.implement(VirtualRenderer.prototype, EventEmitter); config.defineOptions(VirtualRenderer.prototype, "renderer", { From 3cd28b88a51176c791e045f405cdf842916697ab Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Fri, 24 Mar 2023 13:25:43 +0100 Subject: [PATCH 0756/1293] feat: Add annotation level information to gutter tooltip (#5101) * Add annotation level information to gutter tooltip Improves gutter tooltip by adding a header indicating the total number of annotations per level for that row and an icon in front of each message indicating the annotation level for that annotation. --- src/css/editor.css.js | 23 ++++- src/layer/gutter.js | 14 +-- src/mouse/default_gutter_handler.js | 42 ++++++-- src/mouse/default_gutter_handler_test.js | 125 +++++++++++++++++++++++ src/test/all_browser.js | 1 + 5 files changed, 186 insertions(+), 19 deletions(-) create mode 100644 src/mouse/default_gutter_handler_test.js diff --git a/src/css/editor.css.js b/src/css/editor.css.js index 66150be103a..052b9214af1 100644 --- a/src/css/editor.css.js +++ b/src/css/editor.css.js @@ -115,22 +115,24 @@ module.exports = ` background-repeat: no-repeat; } -.ace_gutter-cell.ace_error { +.ace_gutter-cell.ace_error, .ace_icon.ace_error { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg=="); background-repeat: no-repeat; background-position: 2px center; } -.ace_gutter-cell.ace_warning { +.ace_gutter-cell.ace_warning, .ace_icon.ace_warning { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg=="); + background-repeat: no-repeat; background-position: 2px center; } -.ace_gutter-cell.ace_info { +.ace_gutter-cell.ace_info, .ace_icon.ace_info { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII="); + background-repeat: no-repeat; background-position: 2px center; } -.ace_dark .ace_gutter-cell.ace_info { +.ace_dark .ace_gutter-cell.ace_info, .ace_dark .ace_icon.ace_info { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC"); } @@ -422,6 +424,19 @@ module.exports = ` outline: 1px solid black; } +.ace_gutter-tooltip_header { + font-weight: bold; +} + +.ace_gutter-tooltip_body { + padding-top: 5px; +} + +.ace_gutter-tooltip .ace_icon { + display: inline-block; + width: 18px; +} + .ace_folding-enabled > .ace_gutter-cell { padding-right: 13px; } diff --git a/src/layer/gutter.js b/src/layer/gutter.js index b352752be07..1bc13bd22c6 100644 --- a/src/layer/gutter.js +++ b/src/layer/gutter.js @@ -53,23 +53,25 @@ var Gutter = function(parentEl) { var row = annotation.row; var rowInfo = this.$annotations[row]; if (!rowInfo) - rowInfo = this.$annotations[row] = {text: []}; + rowInfo = this.$annotations[row] = {text: [], type: []}; var annoText = annotation.text; + var annoType = annotation.type; annoText = annoText ? lang.escapeHTML(annoText) : annotation.html || ""; - if (rowInfo.text.indexOf(annoText) === -1) + if (rowInfo.text.indexOf(annoText) === -1){ rowInfo.text.push(annoText); + rowInfo.type.push(annoType); + } - var type = annotation.type; var className = annotation.className; if (className) rowInfo.className = className; - else if (type == "error") + else if (annoType == "error") rowInfo.className = " ace_error"; - else if (type == "warning" && rowInfo.className != " ace_error") + else if (annoType == "warning" && rowInfo.className != " ace_error") rowInfo.className = " ace_warning"; - else if (type == "info" && (!rowInfo.className)) + else if (annoType == "info" && (!rowInfo.className)) rowInfo.className = " ace_info"; } }; diff --git a/src/mouse/default_gutter_handler.js b/src/mouse/default_gutter_handler.js index e86811c005f..80e0e6e1335 100644 --- a/src/mouse/default_gutter_handler.js +++ b/src/mouse/default_gutter_handler.js @@ -51,17 +51,41 @@ function GutterHandler(mouseHandler) { return hideTooltip(); } - if (tooltipAnnotation == annotation) - return; - tooltipAnnotation = annotation.text.join("
    "); - - tooltip.setHtml(tooltipAnnotation); - - var annotationClassName = annotation.className; - if (annotationClassName) { - tooltip.setClassName(annotationClassName.trim()); + var annotationMessages = {error: [], warning: [], info: []}; + var annotationLabels = { + error: {singular: "error", plural: "errors"}, + warning: {singular: "warning", plural: "warnings"}, + info: {singular: "information message", plural: "information messages"} + }; + + // Construct the body of the tooltip. + for (var i = 0; i < annotation.text.length; i++) { + var line = ` ${annotation.text[i]}`; + annotationMessages[annotation.type[i]].push(line); } + var tooltipBody = "
    "; + tooltipBody += [].concat(annotationMessages.error, annotationMessages.warning, annotationMessages.info).join("
    "); + tooltipBody += '
    '; + + // Construct the header of the tooltip. + var isMoreThanOneAnnotationType = false; + var tooltipHeader = "
    "; + for (var i = 0; i < 3; i++){ + var annotationType = ['error', 'warning', 'info'][i]; + if (annotationMessages[annotationType].length > 0){ + var label = annotationMessages[annotationType].length === 1 ? annotationLabels[annotationType].singular : annotationLabels[annotationType].plural; + tooltipHeader += `${isMoreThanOneAnnotationType ? ', ' : ''}${annotationMessages[annotationType].length} ${label}`; + isMoreThanOneAnnotationType = true; + } + } + tooltipHeader += "
    "; + + tooltipAnnotation = tooltipHeader + tooltipBody; + tooltip.setHtml(tooltipAnnotation); + tooltip.setClassName("ace_gutter-tooltip"); + tooltip.$element.setAttribute("aria-live", "polite"); + tooltip.show(); editor._signal("showGutterTooltip", tooltip); editor.on("mousewheel", hideTooltip); diff --git a/src/mouse/default_gutter_handler_test.js b/src/mouse/default_gutter_handler_test.js new file mode 100644 index 00000000000..d089c9024be --- /dev/null +++ b/src/mouse/default_gutter_handler_test.js @@ -0,0 +1,125 @@ +if (typeof process !== "undefined") { + require("amd-loader"); + require("../test/mockdom"); +} + +"use strict"; + +require("../multi_select"); +require("../theme/textmate"); +var Editor = require("../editor").Editor; +var Mode = require("../mode/java").Mode; +var VirtualRenderer = require("../virtual_renderer").VirtualRenderer; +var assert = require("../test/assertions"); +var MouseEvent = function(type, opts){ + var e = document.createEvent("MouseEvents"); + e.initMouseEvent(/click|wheel/.test(type) ? type : "mouse" + type, + true, true, window, + opts.detail, + opts.x, opts.y, opts.x, opts.y, + opts.ctrl, opts.alt, opts.shift, opts.meta, + opts.button || 0, opts.relatedTarget); + return e; +}; + +var editor; + +module.exports = { + setUp : function(next) { + this.editor = new Editor(new VirtualRenderer()); + this.editor.container.style.position = "absolute"; + this.editor.container.style.height = "500px"; + this.editor.container.style.width = "500px"; + this.editor.container.style.left = "50px"; + this.editor.container.style.top = "10px"; + document.body.appendChild(this.editor.container); + editor = this.editor; + next(); + }, + + "test: gutter error tooltip" : function() { + var editor = this.editor; + var value = ""; + + editor.session.setMode(new Mode()); + editor.setValue(value, -1); + editor.session.setAnnotations([{row: 0, column: 0, text: "error test", type: "error"}]); + editor.renderer.$loop._flush(); + + var lines = editor.renderer.$gutterLayer.$lines; + var annotation = lines.cells[0].element; + assert.ok(/ace_error/.test(annotation.className)); + + var rect = annotation.getBoundingClientRect(); + annotation.dispatchEvent(new MouseEvent("move", {clientX: rect.left, clientY: rect.top})); + + // Wait for the tooltip to appear after its timeout. + setTimeout(function() { + editor.renderer.$loop._flush(); + var tooltipHeader = editor.container.querySelector(".ace_gutter-tooltip_header"); + var tooltipBody = editor.container.querySelector(".ace_gutter-tooltip_body"); + assert.ok(/1 error/.test(tooltipHeader.textContent)); + assert.ok(/error test/.test(tooltipBody.textContent)); + }, 100); + }, + "test: gutter warning tooltip" : function() { + var editor = this.editor; + var value = ""; + + editor.session.setMode(new Mode()); + editor.setValue(value, -1); + editor.session.setAnnotations([{row: 0, column: 0, text: "warning test", type: "warning"}]); + editor.renderer.$loop._flush(); + + var lines = editor.renderer.$gutterLayer.$lines; + var annotation = lines.cells[0].element; + assert.ok(/ace_warning/.test(annotation.className)); + + var rect = annotation.getBoundingClientRect(); + annotation.dispatchEvent(new MouseEvent("move", {clientX: rect.left, clientY: rect.top})); + + // Wait for the tooltip to appear after its timeout. + setTimeout(function() { + editor.renderer.$loop._flush(); + var tooltipHeader = editor.container.querySelector(".ace_gutter-tooltip_header"); + var tooltipBody = editor.container.querySelector(".ace_gutter-tooltip_body"); + assert.ok(/1 warning/.test(tooltipHeader.textContent)); + assert.ok(/warning test/.test(tooltipBody.textContent)); + }, 100); + }, + "test: gutter info tooltip" : function() { + var editor = this.editor; + var value = ""; + + editor.session.setMode(new Mode()); + editor.setValue(value, -1); + editor.session.setAnnotations([{row: 0, column: 0, text: "info test", type: "info"}]); + editor.renderer.$loop._flush(); + + var lines = editor.renderer.$gutterLayer.$lines; + var annotation = lines.cells[0].element; + assert.ok(/ace_info/.test(annotation.className)); + + var rect = annotation.getBoundingClientRect(); + annotation.dispatchEvent(new MouseEvent("move", {clientX: rect.left, clientY: rect.top})); + + // Wait for the tooltip to appear after its timeout. + setTimeout(function() { + editor.renderer.$loop._flush(); + var tooltipHeader = editor.container.querySelector(".ace_gutter-tooltip_header"); + var tooltipBody = editor.container.querySelector(".ace_gutter-tooltip_body"); + assert.ok(/1 information message/.test(tooltipHeader.textContent)); + assert.ok(/info test/.test(tooltipBody.textContent)); + }, 100); + }, + + tearDown : function() { + this.editor.destroy(); + document.body.removeChild(this.editor.container); + } +}; + + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/src/test/all_browser.js b/src/test/all_browser.js index 944889212b2..1724945aa0b 100644 --- a/src/test/all_browser.js +++ b/src/test/all_browser.js @@ -62,6 +62,7 @@ var testNames = [ "ace/mode/behaviour/behaviour_test", "ace/multi_select_test", "ace/mouse/mouse_handler_test", + "ace/mouse/default_gutter_handler_test", "ace/occur_test", "ace/placeholder_test", "ace/range_test", From 0ae8dbb0fe017cfb8321307e5bfe5959eb121754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=9D=CE=99=CE=9A=CE=9F=CE=9B=CE=91=CE=A3?= Date: Tue, 28 Mar 2023 11:51:10 +0200 Subject: [PATCH 0757/1293] fix: Improves Liquid Support (#5098) * Improve liquid grammar support Brings support for Shopify Liquid Variation embedded code blocks which include: - {% schema %} - {% javascript %} - {% style %} - {% stylesheet %} In addition, line comment highlighting is now provided. * Include the additional modes * add additional context and syntax samples * purge the mode test file (not really relevant anymore) * align behaviour for delimiter matches * fix lookbehind expressions * restore test for liquid mode --------- Co-authored-by: nightwing --- demo/kitchen-sink/docs/liquid.liquid | 57 ++- src/mode/_test/highlight_rules_test.js | 2 +- src/mode/_test/tokens_liquid.json | 570 +++++++++++++++++-------- src/mode/behaviour/liquid.js | 24 +- src/mode/liquid.js | 39 +- src/mode/liquid_highlight_rules.js | 347 +++++++++++---- 6 files changed, 755 insertions(+), 284 deletions(-) diff --git a/demo/kitchen-sink/docs/liquid.liquid b/demo/kitchen-sink/docs/liquid.liquid index 29c0b016551..a06a7a7f4e2 100644 --- a/demo/kitchen-sink/docs/liquid.liquid +++ b/demo/kitchen-sink/docs/liquid.liquid @@ -1,4 +1,8 @@ -The following examples can be found in full at http://liquidmarkup.org/ +There are a couple of different Liquid variations in circulation. This grammars supports +both the Standard and Shopify Liquid variations. The following examples can be found in full at: + +Standard Variation: https://shopify.github.io/liquid +Shopify Variation: https://shopify.dev/docs/api/liquid Liquid is an extraction from the e-commerce system Shopify. Shopify powers many thousands of e-commerce stores which all call for unique designs. @@ -37,11 +41,18 @@ Some more features include:

    If

    - {% if user.name == 'tobi' or user.name == 'marc' %} + {% if user.name == 'tobi' or user.name == 'marc' %} hi marc or tobi {% endif %}

    +

    Comments

    + +{% # Line Comment %} + +{% comment %} + Block Comment +{% endcomment %}

    Case

    @@ -58,7 +69,7 @@ Some more features include:

    For Loops

    - {% for item in array %} + {% for item in array %} {{ item }} {% endfor %}

    @@ -74,3 +85,43 @@ Some more features include: {% endif %} {% endtablerow %}

    + +

    Embedded Code Blocks

    + +This support Shopify Liquid variation JSON schema code blocks + +{% schema %} + { + "string": "bar", + "boolean": true, + "number": 100, + "object": { + "array": [100, false, "string", {}, [] ] + } + } +{% endschema %} + +This support Shopify Liquid variation Stylesheet and Style code blocks + +{% style %} + .class { + font-size: 10px; /* comment */ + } +{% endstyle %} + +{% stylesheet %} + .class { + font-size: 10px; /* comment */ + } +{% endstylesheet %} + +This support Shopify Liquid variation JavaScript code blocks + +{% javascript %} + + function foo (param) { + + return 'something' // comment + } + +{% endjavascript %} diff --git a/src/mode/_test/highlight_rules_test.js b/src/mode/_test/highlight_rules_test.js index e8940f99189..ccb4faf6839 100644 --- a/src/mode/_test/highlight_rules_test.js +++ b/src/mode/_test/highlight_rules_test.js @@ -13,7 +13,7 @@ if (!fs.existsSync) require("amd-loader"); var cwd = __dirname + "/"; -var root = path.normalize(cwd + Array(5).join("../")); +var root = path.normalize(cwd + Array(4).join("../")); function jsFileList(path, filter) { if (!filter) filter = /_test/; diff --git a/src/mode/_test/tokens_liquid.json b/src/mode/_test/tokens_liquid.json index f745a156aa4..cb92f661549 100644 --- a/src/mode/_test/tokens_liquid.json +++ b/src/mode/_test/tokens_liquid.json @@ -1,6 +1,17 @@ [[ "start", - ["text.xml","The following examples can be found in full at http://liquidmarkup.org/"] + ["text.xml","There are a couple of different Liquid variations in circulation. This grammars supports"] +],[ + "start", + ["text.xml","both the Standard and Shopify Liquid variations. The following examples can be found in full at:"] +],[ + "start" +],[ + "start", + ["text.xml","Standard Variation: https://shopify.github.io/liquid"] +],[ + "start", + ["text.xml","Shopify Variation: https://shopify.dev/docs/api/liquid"] ],[ "start" ],[ @@ -51,17 +62,12 @@ ],[ "start", ["text.xml"," "], - ["variable","{%"], - ["text"," "], - ["keyword.block","for"], - ["text"," "], - ["identifier","product"], - ["text"," "], - ["keyword","in"], - ["text"," "], - ["identifier","products"], - ["text"," "], - ["variable","%}"] + ["meta.tag.punctuation.tag-open","{%"], + ["keyword.block"," for"], + ["text"," product"], + ["keyword.operator"," in "], + ["text","products "], + ["meta.tag.punctuation.tag-close","%}"] ],[ "start", ["text.xml"," "], @@ -74,28 +80,29 @@ ["meta.tag.punctuation.tag-open.xml","<"], ["meta.tag.tag-name.xml","h2"], ["meta.tag.punctuation.tag-close.xml",">"], - ["variable","{{"], + ["meta.tag.punctuation.ouput-open","{{"], ["text"," "], - ["identifier","product"], - ["text","."], - ["identifier","title"], + ["support.class","product"], + ["keyword.operator","."], + ["support.object","title"], ["text"," "], - ["variable","}}"], + ["meta.tag.punctuation.ouput-close","}}"], ["meta.tag.punctuation.end-tag-open.xml",""] ],[ "start", ["text.xml"," Only "], - ["variable","{{"], + ["meta.tag.punctuation.ouput-open","{{"], + ["text"," "], + ["support.class","product"], + ["keyword.operator","."], + ["support.object","price"], ["text"," "], - ["identifier","product"], - ["text","."], - ["identifier","price"], - ["text"," | "], - ["identifier","format_as_money"], + ["keyword.operator","| "], + ["support.function","format_as_money"], ["text"," "], - ["variable","}}"] + ["meta.tag.punctuation.ouput-close","}}"] ],[ "start" ],[ @@ -104,19 +111,21 @@ ["meta.tag.punctuation.tag-open.xml","<"], ["meta.tag.tag-name.xml","p"], ["meta.tag.punctuation.tag-close.xml",">"], - ["variable","{{"], - ["text"," "], - ["identifier","product"], - ["text","."], - ["identifier","description"], - ["text"," | "], - ["identifier","prettyprint"], - ["text"," | "], + ["meta.tag.punctuation.ouput-open","{{"], + ["text"," "], + ["support.class","product"], + ["keyword.operator","."], + ["support.object","description"], + ["text"," "], + ["keyword.operator","| "], + ["support.function","prettyprint"], + ["text"," "], + ["keyword.operator","| "], ["support.function","truncate"], ["text",": "], ["constant.numeric","200"], ["text"," "], - ["variable","}}"], + ["meta.tag.punctuation.ouput-close","}}"], ["meta.tag.punctuation.end-tag-open.xml",""] @@ -131,11 +140,10 @@ ],[ "start", ["text.xml"," "], - ["variable","{%"], - ["text"," "], - ["keyword","endfor"], + ["meta.tag.punctuation.tag-open","{%"], + ["keyword.block"," endfor"], ["text"," "], - ["variable","%}"] + ["meta.tag.punctuation.tag-close","%}"] ],[ "start", ["text.xml"," "], @@ -166,13 +174,14 @@ ["meta.tag.tag-name.xml","p"], ["meta.tag.punctuation.tag-close.xml",">"], ["text.xml"," The word \"tobi\" in uppercase: "], - ["variable","{{"], + ["meta.tag.punctuation.ouput-open","{{"], ["text"," "], ["string","'tobi'"], - ["text"," | "], + ["text"," "], + ["keyword.operator","| "], ["support.function","upcase"], ["text"," "], - ["variable","}}"], + ["meta.tag.punctuation.ouput-close","}}"], ["text.xml"," "], ["meta.tag.punctuation.end-tag-open.xml",""], ["text.xml","The word \"tobi\" has "], - ["variable","{{"], + ["meta.tag.punctuation.ouput-open","{{"], ["text"," "], ["string","'tobi'"], - ["text"," | "], + ["text"," "], + ["keyword.operator","| "], ["support.function","size"], ["text"," "], - ["variable","}}"], + ["meta.tag.punctuation.ouput-close","}}"], ["text.xml"," letters! "], ["meta.tag.punctuation.end-tag-open.xml",""], ["text.xml","Change \"Hello world\" to \"Hi world\": "], - ["variable","{{"], + ["meta.tag.punctuation.ouput-open","{{"], ["text"," "], ["string","'Hello world'"], - ["text"," | "], + ["text"," "], + ["keyword.operator","| "], ["support.function","replace"], ["text",": "], ["string","'Hello'"], ["text",", "], ["string","'Hi'"], ["text"," "], - ["variable","}}"], + ["meta.tag.punctuation.ouput-close","}}"], ["text.xml"," "], ["meta.tag.punctuation.end-tag-open.xml",""], ["text.xml","The date today is "], - ["variable","{{"], + ["meta.tag.punctuation.ouput-open","{{"], ["text"," "], ["string","'now'"], - ["text"," | "], + ["text"," "], + ["keyword.operator","| "], ["support.function","date"], ["text",": "], ["string","\"%Y %b %d\""], ["text"," "], - ["variable","}}"], + ["meta.tag.punctuation.ouput-close","}}"], ["text.xml"," "], ["meta.tag.punctuation.end-tag-open.xml",""] ],[ "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Comments"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start", + ["comment.line","{% #"], + ["comment"," Line Comment "], + ["comment.line","%}"] +],[ + "start" +],[ + "comment.block", + ["comment.block","{% comment %}"] +],[ + "comment.block", + ["comment"," Block Comment"] +],[ + "start", + ["comment.block","{% endcomment %}"] ],[ "start" ],[ @@ -316,80 +350,72 @@ ],[ "start", ["text.xml"," "], - ["variable","{%"], - ["text"," "], - ["keyword.block","case"], - ["text"," "], - ["identifier","template"], - ["text"," "], - ["variable","%}"] + ["meta.tag.punctuation.tag-open","{%"], + ["keyword.block"," case"], + ["text"," template "], + ["meta.tag.punctuation.tag-close","%}"] ],[ "start", ["text.xml"," "], - ["variable","{%"], - ["text"," "], - ["keyword","when"], + ["meta.tag.punctuation.tag-open","{%"], + ["keyword.block"," when"], ["text"," "], ["string","'index'"], ["text"," "], - ["variable","%}"] + ["meta.tag.punctuation.tag-close","%}"] ],[ "start", ["text.xml"," Welcome"] ],[ "start", ["text.xml"," "], - ["variable","{%"], - ["text"," "], - ["keyword","when"], + ["meta.tag.punctuation.tag-open","{%"], + ["keyword.block"," when"], ["text"," "], ["string","'product'"], ["text"," "], - ["variable","%}"] + ["meta.tag.punctuation.tag-close","%}"] ],[ "start", ["text.xml"," "], - ["variable","{{"], + ["meta.tag.punctuation.ouput-open","{{"], + ["text"," "], + ["support.class","product"], + ["keyword.operator","."], + ["support.object","vendor"], ["text"," "], - ["identifier","product"], - ["text","."], - ["identifier","vendor"], - ["text"," | "], - ["identifier","link_to_vendor"], + ["keyword.operator","| "], + ["support.function","link_to_vendor"], ["text"," "], - ["variable","}}"], + ["meta.tag.punctuation.ouput-close","}}"], ["text.xml"," / "], - ["variable","{{"], + ["meta.tag.punctuation.ouput-open","{{"], ["text"," "], - ["identifier","product"], - ["text","."], - ["identifier","title"], + ["support.class","product"], + ["keyword.operator","."], + ["support.object","title"], ["text"," "], - ["variable","}}"] + ["meta.tag.punctuation.ouput-close","}}"] ],[ "start", ["text.xml"," "], - ["variable","{%"], - ["text"," "], - ["keyword","else"], + ["meta.tag.punctuation.tag-open","{%"], + ["keyword.block"," else"], ["text"," "], - ["variable","%}"] + ["meta.tag.punctuation.tag-close","%}"] ],[ "start", ["text.xml"," "], - ["variable","{{"], - ["text"," "], - ["identifier","page_title"], - ["text"," "], - ["variable","}}"] + ["meta.tag.punctuation.ouput-open","{{"], + ["text"," page_title "], + ["meta.tag.punctuation.ouput-close","}}"] ],[ "start", ["text.xml"," "], - ["variable","{%"], - ["text"," "], - ["keyword","endcase"], + ["meta.tag.punctuation.tag-open","{%"], + ["keyword.block"," endcase"], ["text"," "], - ["variable","%}"] + ["meta.tag.punctuation.tag-close","%}"] ],[ "start", ["meta.tag.punctuation.end-tag-open.xml",""] ],[ "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Embedded Code Blocks"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start", + ["text.xml","This support Shopify Liquid variation JSON schema code blocks"] +],[ + "start" +],[ + "schema-start", + ["meta.tag.punctuation.tag-open","{%"], + ["text"," "], + ["keyword.tagschema.tag-name","schema"], + ["text"," "], + ["meta.tag.punctuation.tag-close","%}"] +],[ + "schema-start", + ["text"," "], + ["paren.lparen","{"] +],[ + "schema-start", + ["text"," "], + ["variable","\"string\""], + ["text",": "], + ["string","\"bar\""], + ["punctuation.operator",","] +],[ + "schema-start", + ["text"," "], + ["variable","\"boolean\""], + ["text",": "], + ["constant.language.boolean","true"], + ["punctuation.operator",","] +],[ + "schema-start", + ["text"," "], + ["variable","\"number\""], + ["text",": "], + ["constant.numeric","100"], + ["punctuation.operator",","] +],[ + "schema-start", + ["text"," "], + ["variable","\"object\""], + ["text",": "], + ["paren.lparen","{"] +],[ + "schema-start", + ["text"," "], + ["variable","\"array\""], + ["text",": "], + ["paren.lparen","["], + ["constant.numeric","100"], + ["punctuation.operator",","], + ["text"," "], + ["constant.language.boolean","false"], + ["punctuation.operator",","], + ["text"," "], + ["string","\"string\""], + ["punctuation.operator",","], + ["text"," "], + ["paren.lparen","{"], + ["paren.rparen","}"], + ["punctuation.operator",","], + ["text"," "], + ["paren.lparen","["], + ["paren.rparen","]"], + ["text"," "], + ["paren.rparen","]"] +],[ + "schema-start", + ["text"," "], + ["paren.rparen","}"] +],[ + "schema-start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["meta.tag.punctuation.tag-open","{%"], + ["text"," "], + ["keyword.tagendschema.tag-name","endschema"], + ["text"," "], + ["meta.tag.punctuation.tag-close","%}"] +],[ + "start" +],[ + "start", + ["text.xml","This support Shopify Liquid variation Stylesheet and Style code blocks"] +],[ + "start" +],[ + "style-start", + ["meta.tag.punctuation.tag-open","{%"], + ["text"," "], + ["keyword.tagstyle.tag-name","style"], + ["text"," "], + ["meta.tag.punctuation.tag-close","%}"] +],[ + "style-ruleset", + ["text"," "], + ["variable",".class"], + ["text"," "], + ["paren.lparen","{"] +],[ + "style-ruleset", + ["text"," "], + ["support.type","font-size"], + ["punctuation.operator",":"], + ["text"," "], + ["constant.numeric","10"], + ["keyword","px"], + ["punctuation.operator",";"], + ["text"," "], + ["comment","/* comment */"] +],[ + "style-start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["meta.tag.punctuation.tag-open","{%"], + ["text"," "], + ["keyword.tagendstyle.tag-name","endstyle"], + ["text"," "], + ["meta.tag.punctuation.tag-close","%}"] +],[ + "start" +],[ + "stylesheet-start", + ["meta.tag.punctuation.tag-open","{%"], + ["text"," "], + ["keyword.tagstylesheet.tag-name","stylesheet"], + ["text"," "], + ["meta.tag.punctuation.tag-close","%}"] +],[ + "stylesheet-ruleset", + ["text"," "], + ["variable",".class"], + ["text"," "], + ["paren.lparen","{"] +],[ + "stylesheet-ruleset", + ["text"," "], + ["support.type","font-size"], + ["punctuation.operator",":"], + ["text"," "], + ["constant.numeric","10"], + ["keyword","px"], + ["punctuation.operator",";"], + ["text"," "], + ["comment","/* comment */"] +],[ + "stylesheet-start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["meta.tag.punctuation.tag-open","{%"], + ["text"," "], + ["keyword.tagendstylesheet.tag-name","endstylesheet"], + ["text"," "], + ["meta.tag.punctuation.tag-close","%}"] +],[ + "start" +],[ + "start", + ["text.xml","This support Shopify Liquid variation JavaScript code blocks"] +],[ + "start" +],[ + "javascript-start", + ["meta.tag.punctuation.tag-open","{%"], + ["text"," "], + ["keyword.tagjavascript.tag-name","javascript"], + ["text"," "], + ["meta.tag.punctuation.tag-close","%}"] +],[ + "javascript-start" +],[ + "javascript-start", + ["text"," "], + ["storage.type","function"], + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","param"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "javascript-start" +],[ + "javascript-no_regex", + ["text"," "], + ["keyword","return"], + ["text"," "], + ["string","'something'"], + ["text"," "], + ["comment","// comment"] +],[ + "javascript-no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "javascript-no_regex" +],[ + "start", + ["meta.tag.punctuation.tag-open","{%"], + ["text"," "], + ["keyword.tagendjavascript.tag-name","endjavascript"], + ["text"," "], + ["meta.tag.punctuation.tag-close","%}"] +],[ + "start" ]] \ No newline at end of file diff --git a/src/mode/behaviour/liquid.js b/src/mode/behaviour/liquid.js index 60b59d2153b..750278235d0 100644 --- a/src/mode/behaviour/liquid.js +++ b/src/mode/behaviour/liquid.js @@ -1,15 +1,15 @@ "use strict"; - + var oop = require("../../lib/oop"); var Behaviour = require("../behaviour").Behaviour; var XmlBehaviour = require("./xml").XmlBehaviour; var TokenIterator = require("../../token_iterator").TokenIterator; var lang = require("../../lib/lang"); - + function is(token, type) { return token && token.type.lastIndexOf(type + ".xml") > -1; } - + var LiquidBehaviour = function () { XmlBehaviour.call(this); this.add("autoBraceTagClosing","insertion", function (state, action, editor, session, text) { @@ -21,7 +21,7 @@ // exit if we're not in a tag if (!token || !( token.value.trim() === '%' || is(token, "tag-name") || is(token, "tag-whitespace") || is(token, "attribute-name") || is(token, "attribute-equals") || is(token, "attribute-value"))) return; - + // exit if we're inside of a quoted attribute value if (is(token, "reference.attribute-value")) return; @@ -38,26 +38,26 @@ iterator.stepBackward(); } } - // exit if the tag is empty + // exit if the tag is empty if (/{%\s*%/.test(session.getLine(position.row))) return; if (/^\s*}/.test(session.getLine(position.row).slice(position.column))) return; // find tag name - while (!token.type != 'keyword.block') { + while (!token.type != 'meta.tag.punctuation.tag-open') { token = iterator.stepBackward(); if (token.value == '{%') { while(true) { token = iterator.stepForward(); - if (token.type === 'keyword.block') { + if (token.type === 'meta.tag.punctuation.tag-open') { break; } else if (token.value.trim() == '%') { token = null; break; } } - break; + break; } } if (!token ) return ; @@ -67,11 +67,11 @@ // exit if the tag is ending if (is(iterator.stepBackward(), "end-tag-open")) return; - + var element = token.value; if (tokenRow == position.row) element = element.substring(0, position.column - tokenColumn); - + if (this.voidElements.hasOwnProperty(element.toLowerCase())) return; return { @@ -80,9 +80,9 @@ }; } }); - + }; oop.inherits(LiquidBehaviour, Behaviour); - + exports.LiquidBehaviour = LiquidBehaviour; diff --git a/src/mode/liquid.js b/src/mode/liquid.js index fb512710844..c1fe5f69b9c 100644 --- a/src/mode/liquid.js +++ b/src/mode/liquid.js @@ -1,24 +1,40 @@ var oop = require("../lib/oop"); var TextMode = require("./text").Mode; var HtmlMode = require("./html").Mode; -var HtmlCompletions = require("./html_completions").HtmlCompletions; -var LiquidBehaviour = require("./behaviour/liquid").LiquidBehaviour; +var JavascriptMode = require("./javascript").Mode; +var JsonMode = require("./json").Mode; +var CssMode = require("./css").Mode; var LiquidHighlightRules = require("./liquid_highlight_rules").LiquidHighlightRules; var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; -var Mode = function() { - this.HighlightRules = LiquidHighlightRules; - this.$outdent = new MatchingBraceOutdent(); - this.$behaviour = new LiquidBehaviour(); - this.$completer = new HtmlCompletions(); +/* -------------------------------------------- */ +/* FOLDS */ +/* -------------------------------------------- */ + +var FoldMode = require("./folding/cstyle").FoldMode; + +/* -------------------------------------------- */ +/* MODE */ +/* -------------------------------------------- */ + +var Mode = function () { + + JsonMode.call(this); + HtmlMode.call(this); + CssMode.call(this); + JavascriptMode.call(this); + this.HighlightRules = LiquidHighlightRules; + this.foldingRules = new FoldMode(); + }; + oop.inherits(Mode, TextMode); -(function() { - // this.blockComment = {start: "{% comment %}", end: "{% endcomment %}"}; +(function () { + this.blockComment = {start: ""}; this.voidElements = new HtmlMode().voidElements; - + this.getNextLineIndent = function(state, line, tab) { var indent = this.$getIndent(line); @@ -50,6 +66,7 @@ oop.inherits(Mode, TextMode); this.$id = "ace/mode/liquid"; this.snippetFileId = "ace/snippets/liquid"; -}).call(Mode.prototype); + +}.call(Mode.prototype)); exports.Mode = Mode; diff --git a/src/mode/liquid_highlight_rules.js b/src/mode/liquid_highlight_rules.js index 4db550a62f7..c2fd4070539 100644 --- a/src/mode/liquid_highlight_rules.js +++ b/src/mode/liquid_highlight_rules.js @@ -1,103 +1,274 @@ "use strict"; var oop = require("../lib/oop"); + var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; +var CssHighlightRules = require("./css_highlight_rules").CssHighlightRules; var HtmlHighlightRules = require("./html_highlight_rules").HtmlHighlightRules; +var JsonHighlightRules = require("./json_highlight_rules").JsonHighlightRules; +var JavaScriptHighlightRules = require("./javascript_highlight_rules").JavaScriptHighlightRules; -var LiquidHighlightRules = function() { - HtmlHighlightRules.call(this); +var LiquidHighlightRules = function () { - // see: https://developer.mozilla.org/en/Liquid/Reference/Global_Objects - var functions = ( - // Standard Filters - "date|capitalize|downcase|upcase|first|last|join|sort|map|size|escape|" + - "escape_once|strip_html|strip_newlines|newline_to_br|replace|replace_first|" + - "truncate|truncatewords|prepend|append|minus|plus|times|divided_by|split" - ); + HtmlHighlightRules.call(this); - var keywords = ( - // Standard Tags - "capture|endcapture|case|endcase|when|comment|endcomment|" + - "cycle|for|endfor|in|reversed|if|endif|else|elsif|include|endinclude|unless|endunless|" + - // Commonly used tags - "style|text|image|widget|plugin|marker|endmarker|tablerow|endtablerow" - ); - - // common standard block tags that require to be closed with an end[block] token - var blocks = 'for|if|case|capture|unless|tablerow|marker|comment'; - - var builtinVariables = 'forloop|tablerowloop'; - // "forloop\\.(length|index|index0|rindex|rindex0|first|last)|limit|offset|range" + - // "tablerowloop\\.(length|index|index0|rindex|rindex0|first|last|col|col0|"+ - // "col_first|col_last)" - - var definitions = ("assign"); - - var keywordMapper = this.createKeywordMapper({ - "variable.language": builtinVariables, - "keyword": keywords, - "keyword.block": blocks, - "support.function": functions, - "keyword.definition": definitions - }, "identifier"); - - // add liquid start tags to the HTML start tags - for (var rule in this.$rules) { - this.$rules[rule].unshift({ - token : "variable", - regex : "{%", - push : "liquid-start" - }, { - token : "variable", - regex : "{{", - push : "liquid-start" - }); - } + /** + * Embedded Matches + * + * Handles `onMatch` tokens and correct parses the + * inner contents of the tag. + */ + function onMatchEmbedded(name) { + + const length = name.length; + + return function (value) { + + const idx = value.indexOf(name); + + const x = [ + { + type: "meta.tag.punctuation.tag-open", + value: "{%" + }, + { + type: "text", + value: value.slice(2, idx) + }, + { + type: "keyword.tag" + name + ".tag-name", + value: value.slice(idx, idx + length) + }, + { + type: "text", + value: value.slice(idx + length, value.indexOf("%}")) + }, + { + type: "meta.tag.punctuation.tag-close", + value: "%}" + } + ]; - this.addRules({ - "liquid-start" : [{ - token: "variable", - regex: "}}", + return x; + }; + } + + + for (var rule in this.$rules) { + + this.$rules[rule].unshift( + { + token: "comment.block", + regex: /{%-?\s*comment\s*-?%}/, + next: [ + { + token: "comment.block", + regex: /{%-?\s*endcomment\s*-?%}/, + next: "pop" + }, + { + defaultToken: "comment", + caseInsensitive: false + } + ] + }, + { + token: "comment.line", + regex: /{%-?\s*#/, + next: [ + { + token: "comment.line", + regex: /-?%}/, next: "pop" - }, { - token: "variable", - regex: "%}", + }, + { + defaultToken: "comment", + caseInsensitive: false + } + ] + }, + { + token: 'style.embedded.start', + regex: /({%-?\s*\bstyle\b\s*-?%})/, + next: "style-start", + onMatch: onMatchEmbedded("style") + }, + { + regex: /({%-?\s*\bstylesheet\b\s*-?%})/, + next: "stylesheet-start", + onMatch: onMatchEmbedded("stylesheet") + }, + { + regex: /({%-?\s*\bschema\b\s*-?%})/, + next: "schema-start", + onMatch: onMatchEmbedded("schema") + }, + { + regex: /({%-?\s*\bjavascript\b\s*-?%})/, + next: "javascript-start", + onMatch: onMatchEmbedded("javascript") + }, + { + token: "meta.tag.punctuation.tag-open", + regex: /({%)/, + next: [ + { + token: "keyword.block", + regex: /-?\s*[a-zA-Z_$][a-zA-Z0-9_$]+\b/, + next: 'liquid-start' + }, + { + token: "meta.tag.punctuation.tag-close", + regex: /(-?)(%})/, next: "pop" - }, { - token : "string", // single line - regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' - }, { - token : "string", // single line - regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" - }, { - token : "constant.numeric", // hex - regex : "0[xX][0-9a-fA-F]+\\b" - }, { - token : "constant.numeric", // float - regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" - }, { - token : "constant.language.boolean", - regex : "(?:true|false)\\b" - }, { - token : keywordMapper, - regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" - }, { - token : "keyword.operator", - regex : "/|\\*|\\-|\\+|=|!=|\\?\\:" - }, { - token : "paren.lparen", - regex : /[\[\({]/ - }, { - token : "paren.rparen", - regex : /[\])}]/ - }, { - token : "text", - regex : "\\s+" - }] - }); - - this.normalizeRules(); + } + ] + }, + { + token: "meta.tag.punctuation.ouput-open", + regex: /({{)/, + push: "liquid-start" + } + ); + } + + /* -------------------------------------------- */ + /* EMBEDDED REGIONS */ + /* -------------------------------------------- */ + + this.embedRules(JsonHighlightRules, "schema-", [ + { + token: "schema-start", + next: "pop", + regex: /({%-?\s*\bendschema\b\s*-?%})/, + onMatch: onMatchEmbedded("endschema") + } + ]); + + this.embedRules(JavaScriptHighlightRules, "javascript-", [ + { + token: "javascript-start", + next: "pop", + regex: /({%-?\s*\bendjavascript\b\s*-?%})/, + onMatch: onMatchEmbedded("endjavascript") + } + ]); + + + + this.embedRules(CssHighlightRules, "style-", [ + { + token: "style-start", + next: "pop", + regex: /({%-?\s*\bendstyle\b\s*-?%})/, + onMatch: onMatchEmbedded("endstyle") + } + ]); + + this.embedRules(CssHighlightRules, "stylesheet-", [ + { + token: "stylesheet-start", + next: "pop", + regex: /({%-?\s*\bendstylesheet\b\s*-?%})/, + onMatch: onMatchEmbedded("endstylesheet") + } + ]); + + /* -------------------------------------------- */ + /* LIQUID GRAMMARS */ + /* -------------------------------------------- */ + + this.addRules({ + "liquid-start": [ + { + token: "meta.tag.punctuation.ouput-close", + regex: /}}/, + next: "pop" + }, + { + token: "meta.tag.punctuation.tag-close", + regex: /%}/, + next: "pop" + }, + { + token: "string", + regex: /['](?:(?:\\.)|(?:[^'\\]))*?[']/ + }, + { + token: "string", + regex: /["](?:(?:\\.)|(?:[^'\\]))*?["]/ + }, + { + token: "constant.numeric", + regex: /0[xX][0-9a-fA-F]+\b/ + }, + { + token: "constant.numeric", + regex: /[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/ + }, + { + token: "keyword.operator", + regex: /\*|\-|\+|=|!=|\?\|\:/ + }, + { + token: "constant.language.boolean", + regex: /(?:true|false|nil|empty)\b/ + }, + { + token: "keyword.operator", + regex: /\s+(?:and|contains|in|with)\b\s+/ + }, + { + token: ["keyword.operator", "support.function"], + regex: /(\|\s*)([a-zA-Z_]+)/ + + }, + { + token: "support.function", + regex: /\s*([a-zA-Z_]+\b)(?=:)/ + }, + { + token: "keyword.operator", + regex: + /(:)\s*(?=[a-zA-Z_])/ + }, + { + token: [ + "support.class", + "keyword.operator", + "support.object", + "keyword.operator", + "variable.parameter" + ], + regex: /(\w+)(\.)(\w+)(\.)?(\w+)?/ + }, + { + token: "variable.parameter", + regex: /\.([a-zA-Z_$][a-zA-Z0-9_$]*\b)$/ + }, + { + token: "support.class", + regex: /(?:additional_checkout_buttons|content_for_additional_checkout_buttons)\b/ + }, + { + token: "paren.lparen", + regex: /[\[\({]/ + }, + { + token: "paren.rparen", + regex: /[\])}]/ + }, + { + token: "text", + regex: /\s+/ + } + ] + }); + + this.normalizeRules(); + }; + oop.inherits(LiquidHighlightRules, TextHighlightRules); exports.LiquidHighlightRules = LiquidHighlightRules; From 3c149a97acedd9c9ad52daebaf944aa26534d37f Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Wed, 29 Mar 2023 20:11:41 +0400 Subject: [PATCH 0758/1293] fix: Fix bracket highlighting for brackets in open/close tags (#5108) --- src/edit_session/bracket_match.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/edit_session/bracket_match.js b/src/edit_session/bracket_match.js index 3dfe05897cb..17d39b4390c 100644 --- a/src/edit_session/bracket_match.js +++ b/src/edit_session/bracket_match.js @@ -126,6 +126,7 @@ function BracketMatch() { "(\\.?" + token.type.replace(".", "\\.").replace("rparen", ".paren") .replace(/\b(?:end)\b/, "(?:start|begin|end)") + .replace(/-close\b/, "-(close|open)") + ")+" ); } @@ -183,6 +184,7 @@ function BracketMatch() { "(\\.?" + token.type.replace(".", "\\.").replace("lparen", ".paren") .replace(/\b(?:start|begin)\b/, "(?:start|begin|end)") + .replace(/-open\b/, "-(close|open)") + ")+" ); } From 30d66465d0c002d49177d3e8a8a204ae904bb14f Mon Sep 17 00:00:00 2001 From: mkslanc Date: Thu, 30 Mar 2023 20:06:05 +0400 Subject: [PATCH 0759/1293] fix merge conflicts --- src/autocomplete.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/autocomplete.js b/src/autocomplete.js index aa5690b6ab7..ca4baaeb9b2 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -553,7 +553,7 @@ class CompletionProvider { if (data.snippet) snippetManager.insertSnippet(editor, data.snippet, data.range); else { - this.$insertString(data); + this.$insertString(editor, data); } if (data.command && data.command === "startAutocomplete") { @@ -564,24 +564,24 @@ class CompletionProvider { return true; } - $insertString = function (data) { + $insertString(editor, data) { var text = data.value || data; if (data.range) { - if (this.editor.inVirtualSelectionMode) { - return this.editor.session.replace(data.range, text); + if (editor.inVirtualSelectionMode) { + return editor.session.replace(data.range, text); } - this.editor.forEachSelection(() => { - var range = this.editor.getSelectionRange(); + editor.forEachSelection(() => { + var range = editor.getSelectionRange(); if (data.range.compareRange(range) === 0) { - this.editor.session.replace(data.range, text); + editor.session.replace(data.range, text); } else { - this.editor.insert(text); + editor.insert(text); } }, null, {keepOrder: true}); } else { - this.editor.execCommand("insertstring", text); + editor.execCommand("insertstring", text); } } From 01f37fde973b653aa0f0a28e12bb23d692d12a0a Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 29 Mar 2023 03:21:04 +0400 Subject: [PATCH 0760/1293] add hover tooltip --- demo/kitchen-sink/demo.js | 52 +++++++++ src/test/all_browser.js | 1 + src/tooltip.js | 218 ++++++++++++++++++++++++++++++++++++++ src/tooltip_test.js | 118 +++++++++++++++++++++ 4 files changed, 389 insertions(+) create mode 100644 src/tooltip_test.js diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index fc616182e88..808a09ff730 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -61,9 +61,57 @@ require("ace/config").defineOptions(Editor.prototype, "editor", { return !!this.tokenTooltip; }, handlesSet: true + }, +}); + +require("ace/config").defineOptions(Editor.prototype, "editor", { + useAceLinters: { + set: function(val) { + if (val && !window.languageProvider) { + loadLanguageProvider(editor); + } + else if (val) { + window.languageProvider.registerEditor(this); + } else { + // todo unregister + } + } } }); +var {HoverTooltip} = require("ace/tooltip"); +var docTooltip = new HoverTooltip(); +function loadLanguageProvider(editor) { + require([ + "https://www.unpkg.com/ace-linters/build/ace-linters.js" + ], (m) => { + window.languageProvider = m.LanguageProvider.fromCdn("https://www.unpkg.com/ace-linters/build"); + window.languageProvider.registerEditor(editor); + if (languageProvider.$descriptionTooltip) + editor.off("mousemove", languageProvider.$descriptionTooltip.onMouseMove); + + + docTooltip.setDataProvider(function(e, editor) { + var renderer = editor.renderer; + + let session = editor.session; + let docPos = e.getDocumentPosition() ; + + languageProvider.doHover(session, docPos, function(hover) { + if (!hover) { + return; + } + // todo should ace itself handle markdown? + var domNode = dom.buildDom(["p", {}, hover.content.text]); + docTooltip.showForRange(editor, hover.range, domNode, e); + }); + }); + + docTooltip.addToEditor(editor) + }); +} + + var workerModule = require("ace/worker/worker_client"); if (location.href.indexOf("noworker") !== -1) { @@ -393,6 +441,10 @@ optionsPanel.add({ return !!originalAutocompleteCommand; } }, + "Use Ace Linters": { + position: 3000, + path: "useAceLinters" + }, "Show Textarea Position": devUtil.textPositionDebugger, "Text Input Debugger": devUtil.textInputDebugger, } diff --git a/src/test/all_browser.js b/src/test/all_browser.js index 1724945aa0b..00946198dd3 100644 --- a/src/test/all_browser.js +++ b/src/test/all_browser.js @@ -70,6 +70,7 @@ var testNames = [ "ace/search_test", "ace/selection_test", "ace/snippets_test", + "ace/tooltip_test", "ace/token_iterator_test", "ace/tokenizer_test", "ace/test/mockdom_test", diff --git a/src/tooltip.js b/src/tooltip.js index 37a220df3ce..c62b125d7ba 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -1,6 +1,7 @@ "use strict"; var dom = require("./lib/dom"); +var Range = require("./range").Range; var CLASSNAME = "ace_tooltip"; @@ -106,4 +107,221 @@ class Tooltip { } +class PopupManager { + constructor () { + this.popups = []; + } + + addPopup(popup) { + this.popups.push(popup); + this.updatePopups(); + } + + removePopup(popup) { + const index = this.popups.indexOf(popup); + if (index !== -1) { + this.popups.splice(index, 1); + this.updatePopups(); + } + } + + updatePopups() { + this.popups.sort((a, b) => b.priority - a.priority); + let visiblepopups = []; + + for (let popup of this.popups) { + let shouldDisplay = true; + for (let visiblePopup of visiblepopups) { + if (this.doPopupsOverlap(visiblePopup, popup)) { + shouldDisplay = false; + break; + } + } + + if (shouldDisplay) { + visiblepopups.push(popup); + } else { + popup.hide(); + } + } + } + + doPopupsOverlap (popupA, popupB) { + const rectA = popupA.getRect(); + const rectB = popupB.getRect(); + + return (rectA.left < rectB.right && rectA.right > rectB.left && rectA.top < rectB.bottom && rectA.bottom + > rectB.top); + } +} + +var popupManager = new PopupManager(); +exports.popupManager = popupManager; + exports.Tooltip = Tooltip; + + +class HoverTooltip extends Tooltip { + constructor() { + super(document.body); + + this.timeout = undefined; + this.lastT = 0; + this.idleTime = 350; + this.lastEvent = undefined; + + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseMove = this.onMouseMove.bind(this); + this.waitForHover = this.waitForHover.bind(this); + this.hide = this.hide.bind(this); + + var el = this.getElement(); + el.style.whiteSpace = "pre-wrap"; + el.style.pointerEvents = "auto"; + el.addEventListener("mouseout", this.onMouseOut); + el.classList.add("ace_doc-tooltip"); + el.tabIndex = -1; + + el.addEventListener("blur", function() { + if (document.activeElement != el) this.hide(); + }.bind(this)); + } + + addToEditor(editor, callback, cancel) { + editor.on("mousemove", this.onMouseMove); + } + + onMouseMove(e, editor) { + this.lastEvent = e; + this.lastT = Date.now(); + var isMousePressed = editor.$mouseHandler.isMousePressed; + if (this.isOpen) { + var pos = this.lastEvent.getDocumentPosition(); + if ( + !this.range + || !this.range.contains(pos.row, pos.column) + || isMousePressed + ) { + this.hide(); + } + } + if (this.timeout || isMousePressed) return; + this.timeout = setTimeout(this.waitForHover, this.idleTime); + } + waitForHover() { + clearTimeout(this.timeout); + var dt = Date.now() - this.lastT; + if (this.idleTime - dt > 10) { + this.timeout = setTimeout(this.waitForHover, this.idleTime - dt); + return; + } + + this.timeout = null; + this.$gatherData(this.lastEvent, this.lastEvent.editor); + } + + setDataProvider(value) { + this.$gatherData = value; + } + + showForRange(editor, range, domNode, startingEvent) { + if (startingEvent && startingEvent != this.lastEvent) return; + if (this.isOpen && document.activeElement == this.getElement()) return; + + if (!this.isOpen) { + popupManager.addPopup(this); + this.$registerCloseEvents(); + } + this.isOpen = true; + + this.addMarker(range, editor.session); + this.range = Range.fromPoints(range.start, range.end); + + var element = this.getElement(); + element.innerHTML = ""; + element.appendChild(domNode); + element.style.display = "block"; + + var renderer = editor.renderer; + var position = renderer.textToScreenCoordinates(range.start.row, range.start.column); + var cursorPos = editor.getCursorPosition(); + + var labelHeight = element.clientHeight; + var rect = renderer.scroller.getBoundingClientRect(); + + var isTopdown = true; + if (this.row > cursorPos.row) { + // don't obscure cursor + isTopdown = true; + } else if (this.row < cursorPos.row) { + // don't obscure cursor + isTopdown = false; + } + + if (position.pageY - labelHeight + renderer.lineHeight < rect.top) { + // not enough space above us + isTopdown = true; + } else if (position.pageY + labelHeight > rect.bottom) { + isTopdown = false; + } + + if (!isTopdown) { + position.pageY -= labelHeight; + } else { + position.pageY += renderer.lineHeight; + } + + element.style.maxWidth = rect.width - (position.pageX - rect.left) + "px"; + + this.setPosition(position.pageX, position.pageY); + } + + addMarker(range, session) { + if (this.marker) { + this.$markerSession.removeMarker(this.marker); + } + this.$markerSession = session; + this.marker = session && session.addMarker(range, "ace_highlight-marker", "text"); + } + + hide(e) { + if (!e && document.activeElement == this.getElement()) + return; + if (e && e.target && this.$element.contains(e.target)) + return; + clearTimeout(this.timeout); + this.timeout = null; + this.addMarker(null); + if (this.isOpen) { + this.$removeCloseEvents(); + this.getElement().style.display = "none"; + this.isOpen = false; + popupManager.removePopup(this); + } + } + + $registerCloseEvents() { + window.addEventListener("keydown", this.hide, true); + window.addEventListener("mousewheel", this.hide, true); + window.addEventListener("mousedown", this.hide, true); + } + + $removeCloseEvents() { + window.removeEventListener("keydown", this.hide, true); + window.removeEventListener("mousewheel", this.hide, true); + window.removeEventListener("mousedown", this.hide, true); + } + + onMouseOut(e) { + clearTimeout(this.timeout); + this.timeout = null; + if (!e.relatedTarget || e.relatedTarget == this.getElement()) return; + + if (e && e.currentTarget.contains(e.relatedTarget)) return; + if (!e.relatedTarget.classList.contains("ace_content")) this.hide(); + } + + +} + +exports.HoverTooltip = HoverTooltip; diff --git a/src/tooltip_test.js b/src/tooltip_test.js new file mode 100644 index 00000000000..0e196ca56b1 --- /dev/null +++ b/src/tooltip_test.js @@ -0,0 +1,118 @@ +/*global CustomEvent*/ +if (typeof process !== "undefined") { + require("./test/mockdom"); +} + +"use strict"; + +var ace = require("./ace"); +var assert = require("./test/assertions"); +var HoverTooltip = require("./tooltip").HoverTooltip; +var editor, docTooltip; +module.exports = { + setUp: function() { + docTooltip = new HoverTooltip(); + editor = ace.edit(null, { + value: "Hello empty world\n" + }); + document.body.appendChild(editor.container); + editor.container.style.height = "200px"; + editor.container.style.width = "300px"; + }, + tearDown: function() { + editor.destroy(); + docTooltip.destroy(); + editor = docTooltip = null; + }, + "test: show doc tooltip" : function(next) { + docTooltip.addToEditor(editor); + + docTooltip.setDataProvider(function(e, editor) { + let session = editor.session; + let docPos = e.getDocumentPosition(); + + var range = session.getWordRange(docPos.row, docPos.column); + + var domNode = document.createElement("span"); + domNode.textContent = "tooltip " + range; + domNode.className = "doc-tooltip"; + docTooltip.showForRange(editor, range, domNode, e); + }); + + + editor.resize(true); + docTooltip.idleTime = 3; + mouse("move", {row: 0, column: 1}); + setTimeout(function() { + var nodes = document.querySelectorAll(".doc-tooltip"); + assert.equal(nodes.length, 1); + assert.equal(nodes[0].textContent, "tooltip Range: [0/0] -> [0/5]"); + assert.equal(docTooltip.$element.style.display, "block"); + mouse("move", {row: 0, column: 9}); + assert.equal(docTooltip.$element.style.display, "none"); + setTimeout(function() { + assert.equal(docTooltip.$element.textContent, "tooltip Range: [0/6] -> [0/11]"); + assert.equal(docTooltip.$element.style.display, "block"); + mouse("down", docTooltip.$element, {button: 0}); + mouse("up", docTooltip.$element, {button: 0}); + assert.equal(docTooltip.$element.style.display, "block"); + mouse("down", {row: 0, column: 8}, {button: 0}); + assert.ok(editor.$mouseHandler.isMousePressed); + assert.equal(docTooltip.$element.style.display, "none"); + setTimeout(function() { + assert.equal(docTooltip.$element.style.display, "none"); + assert.ok(editor.$mouseHandler.isMousePressed); + mouse("move", {row: 0, column: 13}, {which: 1}); + assert.ok(editor.$mouseHandler.isMousePressed); + setTimeout(function() { + assert.equal(docTooltip.$element.style.display, "none"); + mouse("up", {row: 0, column: 13}); + assert.ok(!editor.$mouseHandler.isMousePressed); + + docTooltip.idleTime = 20; + assert.ok(!docTooltip.timeout); + mouse("move", {row: 0, column: 1}); + assert.ok(docTooltip.timeout); + docTooltip.lastT = Date.now(); + docTooltip.waitForHover(); + assert.equal(docTooltip.$element.style.display, "none"); + mouse("move", {row: 0, column: 13}); + docTooltip.lastT = Date.now() - docTooltip.idleTime; + docTooltip.waitForHover(); + assert.equal(docTooltip.$element.style.display, "block"); + + + assert.equal(docTooltip.$element.textContent, "tooltip Range: [0/12] -> [0/17]"); + mouse("out", docTooltip.$element, {relatedTarget: document.body}); + assert.equal(docTooltip.$element.style.display, "none"); + assert.ok(!docTooltip.timeout); + next(); + }, 6); + }, 6); + }, 6); + }, 6); + } +}; + +function mouse(type, pos, properties) { + var target = editor.renderer.getMouseEventTarget(); + var event = new CustomEvent("mouse" + type, {bubbles: true}); + + if ("row" in pos) { + var pagePos = editor.renderer.textToScreenCoordinates(pos.row, pos.column); + event.clientX = pagePos.pageX; + event.clientY = pagePos.pageY; + } else { + target = pos; + var rect = target.getBoundingClientRect(); + event.clientX = rect.left + rect.width / 2; + event.clientY = rect.top + rect.height / 2; + } + Object.assign(event, properties); + target.dispatchEvent(event); +} + + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} From 49ba187b9756e84869d7a38cb960d2a21f9975b1 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Tue, 4 Apr 2023 13:44:32 +0400 Subject: [PATCH 0761/1293] better types for `Completion` items --- ace.d.ts | 14 +++++++++++--- src/autocomplete.js | 30 ++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index 45b7811cbe2..a3641c6f80d 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -313,9 +313,7 @@ export namespace Ace { start?: number; } - export interface Completion { - value?: string; - snippet?: string; + interface BaseCompletion { score?: number; meta?: string; caption?: string; @@ -324,6 +322,16 @@ export namespace Ace { completerId?: string; } + export interface SnippetCompletion extends BaseCompletion { + snippet: string; + } + + export interface ValueCompletion extends BaseCompletion { + value: string; + } + + export type Completion = SnippetCompletion | ValueCompletion + export interface Tokenizer { removeCapturingGroups(src: string): string; createSplitterRegexp(src: string, flag?: string): RegExp; diff --git a/src/autocomplete.js b/src/autocomplete.js index ca4baaeb9b2..dc4cc651cec 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -11,11 +11,7 @@ var snippetManager = require("./snippets").snippetManager; var config = require("./config"); /** - * Completion represents a text snippet that is proposed to complete text - * @typedef Completion - * @property {string} [snippet] - a text snippet that would be inserted when the completion is selected - * @property {string} [value] - The text that would be inserted when selecting this completion. If a `snippet` is - * provided, it will be used instead of `value` + * @typedef BaseCompletion * @property {number} [score] - a numerical value that determines the order in which completions would be displayed. * A lower score means that the completion would be displayed further from the start * @property {string} [meta] - a short description of the completion @@ -25,8 +21,26 @@ var config = require("./config"); * @property {string} [docText] - a plain text that would be displayed as an additional popup. If `docHTML` exists, * it would be used instead of `docText`. * @property {string} [completerId] - the identifier of the completer - * @property {Ace.Range} [range] - an object that determines which range should be replaced in the text with new values (experimental) - * @property {string} [command] - A command that needs to be executed after the insertion of the completion (experimental) + * @property {Ace.Range} [range] - An object specifying the range of text to be replaced with the new completion value (experimental) + * @property {string} [command] - A command to be executed after the completion is inserted (experimental) + */ + +/** + * @typedef SnippetCompletion + * @extends BaseCompletion + * @property {string} snippet - a text snippet that would be inserted when the completion is selected + */ + +/** + * @typedef ValueCompletion + * @extends BaseCompletion + * @property {string} value - The text that would be inserted when selecting this completion. + */ + +/** + * Represents a suggested text snippet intended to complete a user's input + * @typedef Completion + * @type {SnippetCompletion|ValueCompletion} */ var destroyCompleter = function(e, editor) { @@ -704,7 +718,7 @@ class FilteredList { this.filtered = matches; } - + filterCompletions(items, needle) { var results = []; var upper = needle.toUpperCase(); From 82eb439709773a71515fbe97c4e89890ea77e752 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Wed, 5 Apr 2023 10:54:30 +0200 Subject: [PATCH 0762/1293] feat: Add option to use SVG gutter icons (#5107) * add option for using SVG icons Adds an option (useSvgGutterIcons) to use SVG gutter icons (only annotation icons for now) to the VirtualRendererOptions. --- Makefile.dryice.js | 6 ++++- ace.d.ts | 1 + src/css/editor.css.js | 31 ++++++++++++++++++++++-- src/editor.js | 1 + src/ext/options.js | 3 +++ src/layer/gutter.js | 29 +++++++++++++++++++--- src/mouse/default_gutter_handler.js | 4 ++- src/mouse/default_gutter_handler_test.js | 18 ++++++++++++++ src/mouse/mouse_handler_test.js | 2 +- src/virtual_renderer.js | 6 +++++ 10 files changed, 93 insertions(+), 8 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 7a060aea269..1b84f0c0b32 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -606,7 +606,11 @@ function extractCss(callback) { } var buffer = Buffer.from(data.slice(i + 1), "base64"); imageCounter++; - var imageName = name + "-" + imageCounter + ".png"; + var imageName; + if (/^image\/svg\+xml/.test(data)) + imageName = name + "-" + imageCounter + ".svg"; + else + imageName = name + "-" + imageCounter + ".png"; images[imageName] = buffer; console.log("url(http://github.com/%22%22%20+%20directory%20+%20%22/%22%20+%20imageName%20+%20%22/")"); return "url(http://github.com/%22%22%20+%20directory%20+%20%22/%22%20+%20imageName%20+%20%22/")"; diff --git a/ace.d.ts b/ace.d.ts index a3641c6f80d..e816e36e72b 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -194,6 +194,7 @@ export namespace Ace { theme: string; hasCssTransforms: boolean; maxPixelHeight: number; + useSvgGutterIcons: boolean; } export interface MouseHandlerOptions { diff --git a/src/css/editor.css.js b/src/css/editor.css.js index 052b9214af1..c62630005c2 100644 --- a/src/css/editor.css.js +++ b/src/css/editor.css.js @@ -105,7 +105,7 @@ module.exports = ` pointer-events: none; } -.ace_gutter-cell { +.ace_gutter-cell, .ace_gutter-cell_svg-icons { position: absolute; top: 0; left: 0; @@ -115,6 +115,11 @@ module.exports = ` background-repeat: no-repeat; } +.ace_gutter-cell_svg-icons .ace_icon_svg{ + margin-left: -14px; + float: left; +} + .ace_gutter-cell.ace_error, .ace_icon.ace_error { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg=="); background-repeat: no-repeat; @@ -136,6 +141,19 @@ module.exports = ` background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC"); } +.ace_icon_svg.ace_error { + -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJyZWQiIHNoYXBlLXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIj4KPGNpcmNsZSBmaWxsPSJub25lIiBjeD0iOCIgY3k9IjgiIHI9IjciIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPGxpbmUgeDE9IjExIiB5MT0iNSIgeDI9IjUiIHkyPSIxMSIvPgo8bGluZSB4MT0iMTEiIHkxPSIxMSIgeDI9IjUiIHkyPSI1Ii8+CjwvZz4KPC9zdmc+"); + background-color: crimson; +} +.ace_icon_svg.ace_warning { + -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJkYXJrb3JhbmdlIiBzaGFwZS1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiI+Cjxwb2x5Z29uIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGZpbGw9Im5vbmUiIHBvaW50cz0iOCAxIDE1IDE1IDEgMTUgOCAxIi8+CjxyZWN0IHg9IjgiIHk9IjEyIiB3aWR0aD0iMC4wMSIgaGVpZ2h0PSIwLjAxIi8+CjxsaW5lIHgxPSI4IiB5MT0iNiIgeDI9IjgiIHkyPSIxMCIvPgo8L2c+Cjwvc3ZnPg=="); + background-color: darkorange; +} +.ace_icon_svg.ace_info { + -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJibHVlIiBzaGFwZS1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiI+CjxjaXJjbGUgZmlsbD0ibm9uZSIgY3g9IjgiIGN5PSI4IiByPSI3IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjxwb2x5bGluZSBwb2ludHM9IjggMTEgOCA4Ii8+Cjxwb2x5bGluZSBwb2ludHM9IjkgOCA2IDgiLz4KPGxpbmUgeDE9IjEwIiB5MT0iMTEiIHgyPSI2IiB5Mj0iMTEiLz4KPHJlY3QgeD0iOCIgeT0iNSIgd2lkdGg9IjAuMDEiIGhlaWdodD0iMC4wMSIvPgo8L2c+Cjwvc3ZnPg=="); + background-color: royalblue; +} + .ace_scrollbar { contain: strict; position: absolute; @@ -437,7 +455,16 @@ module.exports = ` width: 18px; } -.ace_folding-enabled > .ace_gutter-cell { +.ace_icon_svg { + display: inline-block; + width: 12px; + vertical-align: top; + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: 12px; + -webkit-mask-position: center; +} + +.ace_folding-enabled > .ace_gutter-cell, .ace_folding-enabled > .ace_gutter-cell_svg-icons { padding-right: 13px; } diff --git a/src/editor.js b/src/editor.js index db3a648ac3f..b9f928f055c 100644 --- a/src/editor.js +++ b/src/editor.js @@ -2883,6 +2883,7 @@ config.defineOptions(Editor.prototype, "editor", { maxPixelHeight: "renderer", useTextareaForIME: "renderer", useResizeObserver: "renderer", + useSvgGutterIcons: "renderer", scrollSpeed: "$mouseHandler", dragDelay: "$mouseHandler", diff --git a/src/ext/options.js b/src/ext/options.js index a80010444af..00f86bd36ff 100644 --- a/src/ext/options.js +++ b/src/ext/options.js @@ -194,6 +194,9 @@ var optionGroups = { }, "Custom scrollbar": { path: "customScrollbar" + }, + "Use SVG gutter icons": { + path: "useSvgGutterIcons" } } }; diff --git a/src/layer/gutter.js b/src/layer/gutter.js index 579bb98b00e..2f1bdbc73ae 100644 --- a/src/layer/gutter.js +++ b/src/layer/gutter.js @@ -278,6 +278,7 @@ class Gutter{ var textNode = element.childNodes[0]; var foldWidget = element.childNodes[1]; + var annotationNode = element.childNodes[2]; var firstLineNumber = session.$firstLineNumber; @@ -287,7 +288,27 @@ class Gutter{ var foldWidgets = this.$showFoldWidgets && session.foldWidgets; var foldStart = fold ? fold.start.row : Number.MAX_VALUE; - var className = "ace_gutter-cell "; + var lineHeight = config.lineHeight + "px"; + + var className; + if (this.$useSvgGutterIcons){ + className = "ace_gutter-cell_svg-icons "; + + if (this.$annotations[row]){ + annotationNode.className = "ace_icon_svg" + this.$annotations[row].className; + + dom.setStyle(annotationNode.style, "height", lineHeight); + dom.setStyle(annotationNode.style, "display", "block"); + } + else { + dom.setStyle(annotationNode.style, "display", "none"); + } + } + else { + className = "ace_gutter-cell "; + dom.setStyle(annotationNode.style, "display", "none"); + } + if (this.$highlightGutterLine) { if (row == this.$cursorRow || (fold && row < this.$cursorRow && row >= foldStart && this.$cursorRow <= fold.end.row)) { className += "ace_gutter-active-line "; @@ -324,8 +345,7 @@ class Gutter{ if (foldWidget.className != className) foldWidget.className = className; - var foldHeight = config.lineHeight + "px"; - dom.setStyle(foldWidget.style, "height", foldHeight); + dom.setStyle(foldWidget.style, "height", lineHeight); dom.setStyle(foldWidget.style, "display", "inline-block"); } else { if (foldWidget) { @@ -415,6 +435,9 @@ function onCreateCell(element) { var foldWidget = dom.createElement("span"); element.appendChild(foldWidget); + + var annotationNode = dom.createElement("span"); + element.appendChild(annotationNode); return element; } diff --git a/src/mouse/default_gutter_handler.js b/src/mouse/default_gutter_handler.js index 28fddd78901..d53d5543aab 100644 --- a/src/mouse/default_gutter_handler.js +++ b/src/mouse/default_gutter_handler.js @@ -57,9 +57,11 @@ function GutterHandler(mouseHandler) { info: {singular: "information message", plural: "information messages"} }; + var iconClassName = gutter.$useSvgGutterIcons ? "ace_icon_svg" : "ace_icon"; + // Construct the body of the tooltip. for (var i = 0; i < annotation.text.length; i++) { - var line = ` ${annotation.text[i]}`; + var line = ` ${annotation.text[i]}`; annotationMessages[annotation.type[i]].push(line); } var tooltipBody = "
    "; diff --git a/src/mouse/default_gutter_handler_test.js b/src/mouse/default_gutter_handler_test.js index d089c9024be..59e2f823b90 100644 --- a/src/mouse/default_gutter_handler_test.js +++ b/src/mouse/default_gutter_handler_test.js @@ -112,6 +112,24 @@ module.exports = { assert.ok(/info test/.test(tooltipBody.textContent)); }, 100); }, + "test: gutter svg icons" : function() { + var editor = this.editor; + var value = ""; + + editor.session.setMode(new Mode()); + editor.setOption("useSvgGutterIcons", true); + editor.setValue(value, -1); + editor.session.setAnnotations([{row: 0, column: 0, type: "error", text: "error test"}]); + editor.renderer.$loop._flush(); + + var lines = editor.renderer.$gutterLayer.$lines; + var line = lines.cells[0].element; + assert.ok(/ace_gutter-cell_svg-icons/.test(line.className)); + + var annotation = line.children[2]; + assert.ok(/ace_icon_svg/.test(annotation.className)); + }, + tearDown : function() { this.editor.destroy(); diff --git a/src/mouse/mouse_handler_test.js b/src/mouse/mouse_handler_test.js index 64a4c105fd5..3d057312fd7 100644 --- a/src/mouse/mouse_handler_test.js +++ b/src/mouse/mouse_handler_test.js @@ -126,7 +126,7 @@ module.exports = { editor.setValue(value, -1); editor.renderer.$loop._flush(); var lines = editor.renderer.$gutterLayer.$lines; - var toggler = lines.cells[0].element.lastChild; + var toggler = lines.cells[0].element.children[1]; var rect = toggler.getBoundingClientRect(); if (!rect.left) rect.left = 100; // for mockdom toggler.dispatchEvent(MouseEvent("down", {x: rect.left, y: rect.top})); diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index d8b76288043..7dfa7cf47a9 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -1902,6 +1902,12 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { }, initialValue: true }, + useSvgGutterIcons: { + set: function(value){ + this.$gutterLayer.$useSvgGutterIcons = value; + }, + initialValue: false + }, fadeFoldWidgets: { set: function(show) { dom.setCssClass(this.$gutter, "ace_fade-fold-widgets", show); From 6a37a5f518434e7cf3fc0dd83fd6c087b2ff9d05 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Wed, 5 Apr 2023 15:15:36 +0400 Subject: [PATCH 0763/1293] fix wrong path for modes --- tool/esm_resolver_generator.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tool/esm_resolver_generator.js b/tool/esm_resolver_generator.js index dcaacd0303f..85c28f2a565 100644 --- a/tool/esm_resolver_generator.js +++ b/tool/esm_resolver_generator.js @@ -1,5 +1,5 @@ var fs = require("fs"); -const {modeList, jsFileList} = require("../Makefile.dryice"); +const {jsFileList} = require("../Makefile.dryice"); function buildResolver() { var moduleNames = getModuleNames(); @@ -13,7 +13,7 @@ function buildResolver() { function getModuleNames() { let paths = []; - var modeNames = modeList(); + var modeNames = jsFileList("src/mode", /_highlight_rules|_test|_worker|xml_util|_outdent|behaviour|completions/); // modes let modeNamePaths = modeNames.map(function (name) { return "ace/mode/" + name; From 26029ef90240eef76323c04f5bb1e2a4fd2af6a4 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Wed, 5 Apr 2023 15:52:09 +0400 Subject: [PATCH 0764/1293] modify `modeList` function to accept optional `path` --- Makefile.dryice.js | 5 +++-- tool/esm_resolver_generator.js | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 1b84f0c0b32..90a53451835 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -300,8 +300,9 @@ function workers(path) { }).filter(function(x) { return !!x; }); } -function modeList() { - return jsFileList("lib/ace/mode", /_highlight_rules|_test|_worker|xml_util|_outdent|behaviour|completions/); +function modeList(path) { + path = path || "lib/ace/mode"; + return jsFileList(path, /_highlight_rules|_test|_worker|xml_util|_outdent|behaviour|completions/); } function buildAceModule(opts, callback) { diff --git a/tool/esm_resolver_generator.js b/tool/esm_resolver_generator.js index 85c28f2a565..acd05ccac29 100644 --- a/tool/esm_resolver_generator.js +++ b/tool/esm_resolver_generator.js @@ -1,5 +1,5 @@ var fs = require("fs"); -const {jsFileList} = require("../Makefile.dryice"); +const {modeList, jsFileList} = require("../Makefile.dryice"); function buildResolver() { var moduleNames = getModuleNames(); @@ -13,7 +13,7 @@ function buildResolver() { function getModuleNames() { let paths = []; - var modeNames = jsFileList("src/mode", /_highlight_rules|_test|_worker|xml_util|_outdent|behaviour|completions/); + var modeNames = modeList("src/mode"); // modes let modeNamePaths = modeNames.map(function (name) { return "ace/mode/" + name; From 37ac29e7d9144d7ff563b233726a6b971991a938 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Fri, 7 Apr 2023 08:01:12 +0000 Subject: [PATCH 0765/1293] update ci --- .github/workflows/nodejs.yml | 4 ++-- src/mouse/mouse_handler_test.js | 2 +- src/test/mockdom.js | 21 ++++++++++++--------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index c9a33ea6d40..02642cc0f8c 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: - node-version: [12.x] + node-version: [16.x] steps: - uses: actions/checkout@v2 @@ -52,7 +52,7 @@ jobs: fi # - run: npm run lint - run: node_modules/.bin/tsc --noImplicitAny --strict --noUnusedLocals --noImplicitReturns --noUnusedParameters --noImplicitThis ace.d.ts - - uses: codecov/codecov-action@v1 + - uses: codecov/codecov-action@v3 with: file: ./coverage/coverage.json flags: unittests diff --git a/src/mouse/mouse_handler_test.js b/src/mouse/mouse_handler_test.js index 3d057312fd7..e6dfc657c74 100644 --- a/src/mouse/mouse_handler_test.js +++ b/src/mouse/mouse_handler_test.js @@ -33,7 +33,7 @@ var WheelEvent = function(opts) { }; function sendTouchEvent(type, opts, editor) { - var e = new window.Event("touch" + type, {bubbles: true, cancelable: true}); + var e = new window.CustomEvent("touch" + type, {bubbles: true, cancelable: true}); Object.defineProperties(e, Object.getOwnPropertyDescriptors(opts)); editor.container.dispatchEvent(e); } diff --git a/src/test/mockdom.js b/src/test/mockdom.js index f06370e390f..ff87d7d5a11 100644 --- a/src/test/mockdom.js +++ b/src/test/mockdom.js @@ -830,14 +830,14 @@ exports.load = function() { if (typeof global == "undefined") return; window.window = global; Object.keys(window).forEach(function(i) { - if (!global[i]) { - addedProperties.push(i); - global.__defineGetter__(i, function() { - return window[i]; - }); - global.__defineSetter__(i, function() { - }); - } + var desc = Object.getOwnPropertyDescriptor(global, i); + addedProperties.push({name: i, desc: desc}); + global.__defineGetter__(i, function() { + return window[i]; + }); + global.__defineSetter__(i, function() { + console.log("attempt to set " + i); + }); }); }; @@ -894,7 +894,10 @@ exports.unload = function() { var cache = req("module")._cache; delete cache[__filename]; addedProperties.forEach(function(i) { - delete global[i]; + delete global[i.name]; + if (i.desc) { + Object.defineProperty(global, i.name, i.desc); + } }); }; From 79b83c94729e0bbe377a73bbf689903b51cc1fff Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 7 Apr 2023 18:56:55 +0400 Subject: [PATCH 0766/1293] fix bugs with tooltip not closing --- src/tooltip.js | 38 +++++++++++++++++++++++++++++++++----- src/tooltip_test.js | 35 +++++++++++++++++++++++------------ 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/tooltip.js b/src/tooltip.js index c62b125d7ba..81832b00672 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -189,6 +189,7 @@ class HoverTooltip extends Tooltip { addToEditor(editor, callback, cancel) { editor.on("mousemove", this.onMouseMove); + editor.renderer.getMouseEventTarget().addEventListener("mouseout", this.onMouseOut, true); } onMouseMove(e, editor) { @@ -196,16 +197,18 @@ class HoverTooltip extends Tooltip { this.lastT = Date.now(); var isMousePressed = editor.$mouseHandler.isMousePressed; if (this.isOpen) { - var pos = this.lastEvent.getDocumentPosition(); + var pos = this.lastEvent && this.lastEvent.getDocumentPosition(); if ( !this.range - || !this.range.contains(pos.row, pos.column) + || !this.range.contains(pos.row, pos.column) || isMousePressed + || this.isOutsideOfText(this.lastEvent) ) { this.hide(); } } if (this.timeout || isMousePressed) return; + this.lastEvent = e; this.timeout = setTimeout(this.waitForHover, this.idleTime); } waitForHover() { @@ -217,7 +220,26 @@ class HoverTooltip extends Tooltip { } this.timeout = null; - this.$gatherData(this.lastEvent, this.lastEvent.editor); + if (this.lastEvent && !this.isOutsideOfText(this.lastEvent)) { + this.$gatherData(this.lastEvent, this.lastEvent.editor); + } + } + + isOutsideOfText(e) { + var editor = e.editor; + var docPos = e.getDocumentPosition(); + var line = editor.session.getLine(docPos.row); + if (docPos.column == line.length) { + var screenPos = editor.renderer.pixelToScreenCoordinates(e.clientX, e.clientY); + var clippedPos = editor.session.documentToScreenPosition(docPos.row, docPos.column); + if ( + clippedPos.column != screenPos.column + || clippedPos.row != screenPos.row + ) { + return true; + } + } + return false; } setDataProvider(value) { @@ -289,6 +311,7 @@ class HoverTooltip extends Tooltip { return; if (e && e.target && this.$element.contains(e.target)) return; + this.lastEvent = null; clearTimeout(this.timeout); this.timeout = null; this.addMarker(null); @@ -313,8 +336,13 @@ class HoverTooltip extends Tooltip { } onMouseOut(e) { - clearTimeout(this.timeout); - this.timeout = null; + if (this.timeout) { + clearTimeout(this.timeout); + this.timeout = null; + } + this.lastEvent = null; + if (!this.isOpen) return; + if (!e.relatedTarget || e.relatedTarget == this.getElement()) return; if (e && e.currentTarget.contains(e.relatedTarget)) return; diff --git a/src/tooltip_test.js b/src/tooltip_test.js index 0e196ca56b1..10b8202e702 100644 --- a/src/tooltip_test.js +++ b/src/tooltip_test.js @@ -13,19 +13,11 @@ module.exports = { setUp: function() { docTooltip = new HoverTooltip(); editor = ace.edit(null, { - value: "Hello empty world\n" + value: "Hello empty world" }); document.body.appendChild(editor.container); editor.container.style.height = "200px"; editor.container.style.width = "300px"; - }, - tearDown: function() { - editor.destroy(); - docTooltip.destroy(); - editor = docTooltip = null; - }, - "test: show doc tooltip" : function(next) { - docTooltip.addToEditor(editor); docTooltip.setDataProvider(function(e, editor) { let session = editor.session; @@ -38,7 +30,14 @@ module.exports = { domNode.className = "doc-tooltip"; docTooltip.showForRange(editor, range, domNode, e); }); - + }, + tearDown: function() { + editor.destroy(); + docTooltip.destroy(); + editor = docTooltip = null; + }, + "test: show doc tooltip" : function(next) { + docTooltip.addToEditor(editor); editor.resize(true); docTooltip.idleTime = 3; @@ -81,12 +80,24 @@ module.exports = { docTooltip.waitForHover(); assert.equal(docTooltip.$element.style.display, "block"); - assert.equal(docTooltip.$element.textContent, "tooltip Range: [0/12] -> [0/17]"); mouse("out", docTooltip.$element, {relatedTarget: document.body}); assert.equal(docTooltip.$element.style.display, "none"); assert.ok(!docTooltip.timeout); - next(); + + docTooltip.idleTime = 3; + mouse("move", editor.container); + setTimeout(function() { + mouse("move", {row: 0, column: 13}); + assert.equal(docTooltip.$element.style.display, "none"); + setTimeout(function() { + assert.equal(docTooltip.$element.style.display, "block"); + assert.equal(docTooltip.$element.textContent, "tooltip Range: [0/12] -> [0/17]"); + mouse("move", editor.renderer.scroller); + assert.equal(docTooltip.$element.style.display, "none"); + next(); + }, 6); + }, 6); }, 6); }, 6); }, 6); From 721204292907549fd4fd02d6672afd2b63d1e168 Mon Sep 17 00:00:00 2001 From: YasinKavuk Date: Sat, 8 Apr 2023 16:57:31 +0200 Subject: [PATCH 0767/1293] fix: adds missing 'on' method for 'guttermousedown' --- ace.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ace.d.ts b/ace.d.ts index e816e36e72b..58276a1e988 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -792,6 +792,7 @@ export namespace Ace { on(name: 'mouseup', callback: (e: any) => void): void; on(name: 'mousewheel', callback: (e: any) => void): void; on(name: 'click', callback: (e: any) => void): void; + on(name: 'guttermousedown', callback: (e: any) => void): void; onPaste(text: string, event: any): void; From 02900f69701142c5051f46919e19e67584065181 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 10 Apr 2023 15:37:52 +0400 Subject: [PATCH 0768/1293] fix autocomplete popup being shown without results --- src/autocomplete.js | 3 ++- src/autocomplete_test.js | 49 ++++++++++++++++++++++++++++++++++++++++ src/virtual_renderer.js | 2 +- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/autocomplete.js b/src/autocomplete.js index dc4cc651cec..d93a45ab909 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -644,7 +644,8 @@ class CompletionProvider { this.completions.setFilter(prefix); - callback(null, this.completions, results.finished); + if (results.finished || this.completions.filtered.length) + callback(null, this.completions, results.finished); }.bind(this); var isImmediate = true; diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index 69ea63b65c8..6a980d9e123 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -196,6 +196,55 @@ module.exports = { callback(); }, 70); } + }, + "test: slow and fast completers": function(done) { + var syncCompleter={ + getCompletions: function(editor, session, pos, prefix, callback) { + callback(null,[{ + value: "test" + }]); + }, + id: "asyncCompleter" + }; + + var asyncCompleter = { + getCompletions: function(editor, session, pos, prefix, callback) { + setTimeout(() => { + callback(null,[{ + value: "some" + }]); + }, 10); + }, + id: "asyncCompleter" + }; + var editor = initEditor(""); + editor.completers=[ + syncCompleter,asyncCompleter + ]; + editor.resize(true); + editor.execCommand("insertstring", "o"); + assert.notOk(!!editor.completer.popup); + setTimeout(function() { + assert.ok(editor.completer.popup.isOpen); + assert.equal(editor.completer.popup.renderer.scrollTop, 0); + editor.completer.popup.renderer.$loop._flush(); + assert.equal(editor.completer.popup.renderer.scrollTop, 0); + assert.equal(editor.completer.popup.renderer.scroller.textContent, "some"); + editor.onCommandKey(null, 0, 13); + assert.equal(editor.getValue(), "some"); + editor.execCommand("insertstring", " "); + assert.equal(editor.completer.popup.isOpen, false); + editor.execCommand("insertstring", "t"); + assert.equal(editor.completer.popup.isOpen, true); + editor.onCommandKey(null, 0, 13); + editor.execCommand("insertstring", " "); + editor.execCommand("insertstring", "q"); + assert.equal(editor.completer.popup.isOpen, false); + + editor.destroy(); + editor.container.remove(); + done(); + }, 10); } }; diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 7dfa7cf47a9..18d33bb1415 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -821,7 +821,7 @@ class VirtualRenderer { // scrollTop so that the cursor and onscreen content stays in the same place. // TODO: find a better way to handle this, that works non wrapped case and doesn't compute layerConfig twice if (config.firstRow != this.layerConfig.firstRow && config.firstRowScreen == this.layerConfig.firstRowScreen) { - var st = this.scrollTop + (config.firstRow - this.layerConfig.firstRow) * this.lineHeight; + var st = this.scrollTop + (config.firstRow - Math.max(this.layerConfig.firstRow, 0)) * this.lineHeight; if (st > 0) { // this check is needed as a workaround for the documentToScreenRow returning -1 if document.length == 0 this.scrollTop = st; From 8927df6dd3cfc57bb344e8cc40686aad830a366a Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 10 Apr 2023 18:22:28 +0400 Subject: [PATCH 0769/1293] use sendKey in autocomplete_test.js --- src/autocomplete_test.js | 45 ++++++++++++++++++++-------------------- src/test/mockdom.js | 2 +- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index 6a980d9e123..57a68d8b832 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -1,10 +1,10 @@ if (typeof process !== "undefined") { - require("amd-loader"); require("./test/mockdom"); } "use strict"; +var sendKey = require("./test/user").type; var ace = require("./ace"); var assert = require("./test/assertions"); var Range = require("./range").Range; @@ -18,6 +18,7 @@ function initEditor(value) { enableLiveAutocompletion: true }); document.body.appendChild(editor.container); + editor.focus(); // workaround for autocomplete using non-relative path editor.renderer.$themeId = "./theme/textmate"; @@ -32,18 +33,18 @@ module.exports = { assert.ok(!editor.container.querySelector("style")); - editor.execCommand("insertstring", "a"); - checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { - editor.execCommand("insertstring", "rr"); - checkInnerHTML('arraysortlocal', function() { - editor.execCommand("insertstring", "r"); - checkInnerHTML('arraysortlocal', function() { + sendKey("a"); + checkInnerHTML('arraysortlocalalooooooooooooooooooooooooooooong_wordlocal', function() { + sendKey("rr"); + checkInnerHTML('arraysortlocal', function() { + sendKey("r"); + checkInnerHTML('arraysortlocal', function() { - editor.onCommandKey(null, 0, 13); + sendKey("Return"); assert.equal(editor.getValue(), "arraysort\narraysort alooooooooooooooooooooooooooooong_word"); editor.execCommand("insertstring", " looooooooooooooooooooooooooooong_"); - checkInnerHTML('alooooooooooooooooooooooooooooong_wordlocal', function() { - editor.onCommandKey(null, 0, 13); + checkInnerHTML('alooooooooooooooooooooooooooooong_wordlocal', function() { + sendKey("Return"); editor.destroy(); editor.container.remove(); done(); @@ -93,7 +94,7 @@ module.exports = { ]; editor.moveCursorTo(0, 6); - editor.execCommand("insertstring", "w"); + sendKey("w"); var popup = editor.completer.popup; check(function () { assert.equal(popup.data.length, 1); @@ -169,18 +170,18 @@ module.exports = { } ]; - editor.execCommand("insertstring", "c"); + sendKey("c"); var popup = editor.completer.popup; check(function () { assert.equal(popup.data.length, 4); assert.equal(document.body.lastChild.innerHTML, firstDoc); - editor.onCommandKey(null, 0, 40); + sendKey("Down"); check(function () { assert.equal(document.body.lastChild.innerHTML, secondDoc); - editor.onCommandKey(null, 0, 40); + sendKey("Down"); check(function () { assert.equal(document.body.lastChild.innerHTML, firstDoc); - editor.onCommandKey(null, 0, 40); + sendKey("Down"); check(function () { assert.equal(document.body.lastChild.innerHTML, secondDoc); editor.destroy(); @@ -194,7 +195,7 @@ module.exports = { function check(callback) { setTimeout(function wait() { callback(); - }, 70); + }, 10); } }, "test: slow and fast completers": function(done) { @@ -230,15 +231,15 @@ module.exports = { editor.completer.popup.renderer.$loop._flush(); assert.equal(editor.completer.popup.renderer.scrollTop, 0); assert.equal(editor.completer.popup.renderer.scroller.textContent, "some"); - editor.onCommandKey(null, 0, 13); + sendKey("Return"); assert.equal(editor.getValue(), "some"); - editor.execCommand("insertstring", " "); + sendKey(" "); assert.equal(editor.completer.popup.isOpen, false); - editor.execCommand("insertstring", "t"); + sendKey("t"); assert.equal(editor.completer.popup.isOpen, true); - editor.onCommandKey(null, 0, 13); - editor.execCommand("insertstring", " "); - editor.execCommand("insertstring", "q"); + sendKey("Return"); + sendKey(" "); + sendKey("q"); assert.equal(editor.completer.popup.isOpen, false); editor.destroy(); diff --git a/src/test/mockdom.js b/src/test/mockdom.js index ff87d7d5a11..2c29469b209 100644 --- a/src/test/mockdom.js +++ b/src/test/mockdom.js @@ -307,7 +307,7 @@ function Node(name) { }); this.__defineGetter__("outerHTML", function() { var attributes = this.attributes.map(function(attr) { - return attr.name + "=" + JSON.stringify(attr.value); + return attr.name + "=" + JSON.stringify(attr.value + ""); }, this).join(" "); return "<" + this.localName + (attributes ? " " + attributes : "") + ">" + this.innerHTML + ""; }); From fe5d1bfbf0a3432b78a5e503d1db680181ef48b8 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Wed, 12 Apr 2023 10:38:01 +0200 Subject: [PATCH 0770/1293] feat: Add option to prevent keyboard focus trapping (#5114) * adds an option `enableKeyboardAccessibility` to `EditorOptions`, after setting this to `true` the editor will not trap focus. Press enter to enter the editor and escape to exit it. --- ace.d.ts | 1 + src/css/editor.css.js | 5 ++++ src/editor.js | 48 +++++++++++++++++++++++++++++++++++ src/editor_navigation_test.js | 38 +++++++++++++++++++++++++++ src/ext/options.js | 3 +++ 5 files changed, 95 insertions(+) diff --git a/ace.d.ts b/ace.d.ts index 58276a1e988..7ed46b6f7b6 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -227,6 +227,7 @@ export namespace Ace { value: string; session: EditSession; relativeLineNumbers: boolean; + enableKeyboardAccessibility: boolean; } export interface SearchOptions { diff --git a/src/css/editor.css.js b/src/css/editor.css.js index c62630005c2..a4e012ada7d 100644 --- a/src/css/editor.css.js +++ b/src/css/editor.css.js @@ -58,6 +58,11 @@ module.exports = ` font-variant-ligatures: no-common-ligatures; } +.ace_keyboard-focus:focus { + box-shadow: inset 0 0 0 2px #5E9ED6; + outline: none; +} + .ace_dragging .ace_scroller:before{ position: absolute; top: 0; diff --git a/src/editor.js b/src/editor.js index b9f928f055c..474e8448b24 100644 --- a/src/editor.js +++ b/src/editor.js @@ -19,6 +19,7 @@ var TokenIterator = require("./token_iterator").TokenIterator; var LineWidgets = require("./line_widgets").LineWidgets; var clipboard = require("./clipboard"); +var keys = require('./lib/keys'); /** * The main entry point into the Ace functionality. @@ -2858,6 +2859,53 @@ config.defineOptions(Editor.prototype, "editor", { this.$updatePlaceholder(); } }, + enableKeyboardAccessibility: { + set: function(value) { + var blurCommand = { + name: "blurTextInput", + description: "Set focus to the editor content div to allow tabbing through the page", + bindKey: "Esc", + exec: function(editor) { + editor.blur(); + editor.renderer.content.focus(); + }, + readOnly: true + }; + + var focusOnEnterKeyup = function (e) { + if (e.target == this.renderer.content && e.keyCode === keys['enter']){ + e.stopPropagation(); + e.preventDefault(); + this.focus(); + } + }; + + var keyboardFocusClassName = "ace_keyboard-focus"; + + // Prevent focus to be captured when tabbing through the page. When focus is set to the content div, + // press Enter key to give focus to Ace and press Esc to again allow to tab through the page. + if (value){ + this.textInput.getElement().setAttribute("tabindex", -1); + this.renderer.content.setAttribute("tabindex", 0); + this.renderer.content.classList.add(keyboardFocusClassName); + this.renderer.content.setAttribute("aria-label", + "Editor, press Enter key to start editing, press Escape key to exit" + ); + + this.renderer.content.addEventListener("keyup", focusOnEnterKeyup.bind(this)); + this.commands.addCommand(blurCommand); + } else { + this.textInput.getElement().setAttribute("tabindex", 0); + this.renderer.content.setAttribute("tabindex", -1); + this.renderer.content.classList.remove(keyboardFocusClassName); + this.renderer.content.setAttribute("aria-label", ""); + + this.renderer.content.removeEventListener("keyup", focusOnEnterKeyup.bind(this)); + this.commands.removeCommand(blurCommand); + } + }, + initialValue: false + }, customScrollbar: "renderer", hScrollBarAlwaysVisible: "renderer", vScrollBarAlwaysVisible: "renderer", diff --git a/src/editor_navigation_test.js b/src/editor_navigation_test.js index 9d16b52af95..102609a7447 100644 --- a/src/editor_navigation_test.js +++ b/src/editor_navigation_test.js @@ -8,7 +8,9 @@ if (typeof process !== "undefined") { var EditSession = require("./edit_session").EditSession; var Editor = require("./editor").Editor; var MockRenderer = require("./test/mockrenderer").MockRenderer; +var VirtualRenderer = require("./virtual_renderer").VirtualRenderer; var assert = require("./test/assertions"); +var keys = require('./lib/keys'); module.exports = { createEditSession : function(rows, cols) { @@ -154,6 +156,42 @@ module.exports = { editor.navigateDown(); assert.position(editor.getCursorPosition(), 1, 7); + }, + + "test: should allow to toggle between keyboard trapping modes": function() { + var editor = new Editor(new VirtualRenderer(), new EditSession(["1234", "1234567890"])); + + // Should not trap focus + editor.setOption('enableKeyboardAccessibility', true); + + // Focus on editor + editor.focus(); + + // Focus should be on textInput + assert.equal(document.activeElement, editor.textInput.getElement()); + assert.notEqual(document.activeElement, editor.renderer.content); + + editor.onCommandKey({}, 0, keys["escape"]); + + // Focus should be on the content div after pressing Esc + assert.equal(document.activeElement, editor.renderer.content); + assert.notEqual(document.activeElement, editor.textInput.getElement()); + + // Should trap focus + editor.setOption('enableKeyboardAccessibility', false); + + // Focus on editor + editor.focus(); + + // Focus should be on textInput + assert.equal(document.activeElement, editor.textInput.getElement()); + assert.notEqual(document.activeElement, editor.renderer.content); + + editor.onCommandKey({}, 0, keys["escape"]); + + // Focus should still be on the textInput + assert.equal(document.activeElement, editor.textInput.getElement()); + assert.notEqual(document.activeElement, editor.renderer.content); } }; diff --git a/src/ext/options.js b/src/ext/options.js index 00f86bd36ff..471635fe182 100644 --- a/src/ext/options.js +++ b/src/ext/options.js @@ -197,6 +197,9 @@ var optionGroups = { }, "Use SVG gutter icons": { path: "useSvgGutterIcons" + }, + "Keyboard Accessibility Mode": { + path: "enableKeyboardAccessibility" } } }; From e5dd49b0cc1fc253ce60cc5ff76e7c0675903369 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Thu, 6 Apr 2023 14:08:01 +0000 Subject: [PATCH 0771/1293] add playground and fix documentation --- index.html | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/index.html b/index.html index 30dbdbeba23..28f80e842c6 100644 --- a/index.html +++ b/index.html @@ -53,7 +53,7 @@

    The high performance code ed
                             <a href=Real World Users

  • - Support + Try
  • @@ -137,6 +137,11 @@

    Related Projects

  • Ace wrapper for ExtJS
  • Ace wrapper for GWT
  • +

    Getting Help

    +

    Embedding Ace in Your Site

    @@ -220,7 +225,9 @@

    Changing the size of the editor

    Setting Themes

    Themes are loaded on demand; all you have to do is pass the string name:

    editor.setTheme("ace/theme/twilight");
    -

    > See all themes

    +

    > See all themes. + Or use themelist extension to get the list of available themes at runtime. +

    Setting the Programming Language Mode

    By default, the editor supports plain text mode. All other language modes are available as separate modules, loaded on demand like this:

    editor.session.setMode("ace/mode/javascript");
    @@ -362,8 +369,10 @@

    Configure dynamic loading of modes and themes

    ace.config.set("basePath", "https://url.to.a/folder/that/contains-ace-modes");

    Path for one module alone can be configured with:

    ace.config.setModuleUrl("ace/theme/textmate", "url for textmate.js");
    -

    When using ace with webpack, it is possible to configure paths for all submodules using

    -
    require("ace-builds/webpack-resolver");
    +

    When using ace with webpack, it is possible to configure paths for all submodules using

    +
    require("ace-builds/esm-resolver"); // for new bundlers: webpack 5, rollup, vite
    + For webpack 4 use +
    require("ace-builds/webpack-resolver"); 

    which depends on file-loader

    @@ -1143,15 +1152,6 @@

    Projects Using Ace

    -
    -

    Support and User Resources

    -

    Aside from our GitHub page, here's a list of places you can find help for Ace:

    - -
    From f85076b1e5ad0259b4036a3b45198e34ccc04108 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 12 Apr 2023 20:40:12 +0400 Subject: [PATCH 0772/1293] release v1.17.0 --- CHANGELOG.md | 17 +++++++++++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cfa7c982c0..ad227fb03f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.17.0](https://github.com/ajaxorg/ace/compare/v1.16.0...v1.17.0) (2023-04-12) + + +### Features + +* Add annotation level information to gutter tooltip ([#5101](https://github.com/ajaxorg/ace/issues/5101)) ([3cd28b8](https://github.com/ajaxorg/ace/commit/3cd28b88a51176c791e045f405cdf842916697ab)) +* Add option to prevent keyboard focus trapping ([#5114](https://github.com/ajaxorg/ace/issues/5114)) ([fe5d1bf](https://github.com/ajaxorg/ace/commit/fe5d1bfbf0a3432b78a5e503d1db680181ef48b8)) +* Add option to use SVG gutter icons ([#5107](https://github.com/ajaxorg/ace/issues/5107)) ([82eb439](https://github.com/ajaxorg/ace/commit/82eb439709773a71515fbe97c4e89890ea77e752)) +* add ResizeObserver to make calling editor.resize optional ([51d5e4d](https://github.com/ajaxorg/ace/commit/51d5e4d4308ba98921b1d6ea8cf946d0e17d0a7a)) + + +### Bug Fixes + +* adds missing 'on' method for 'guttermousedown' ([7212042](https://github.com/ajaxorg/ace/commit/721204292907549fd4fd02d6672afd2b63d1e168)) +* Fix bracket highlighting for brackets in open/close tags ([#5108](https://github.com/ajaxorg/ace/issues/5108)) ([3c149a9](https://github.com/ajaxorg/ace/commit/3c149a97acedd9c9ad52daebaf944aa26534d37f)) +* Improves Liquid Support ([#5098](https://github.com/ajaxorg/ace/issues/5098)) ([0ae8dbb](https://github.com/ajaxorg/ace/commit/0ae8dbb0fe017cfb8321307e5bfe5959eb121754)) + ## [1.16.0](https://github.com/ajaxorg/ace/compare/v1.14.0...v1.16.0) (2023-03-17) diff --git a/build b/build index 10aa96811ed..0a07fb082b4 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 10aa96811ed49898e9e677545471da73260b98aa +Subproject commit 0a07fb082b48d26cd561ad96e1c76941a4d55c39 diff --git a/package.json b/package.json index 8c09db4c9ce..0054cc95b55 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.16.0", + "version": "1.17.0", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 42a30987b32..c63d06ab985 100644 --- a/src/config.js +++ b/src/config.js @@ -156,6 +156,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.16.0"; +exports.version = "1.17.0"; From c9b52d2af967fa269242b168c62fe656a1ba58c0 Mon Sep 17 00:00:00 2001 From: Nanne <184182+whazor@users.noreply.github.com> Date: Fri, 14 Apr 2023 14:08:46 +0200 Subject: [PATCH 0773/1293] Make vim copy/paste more robust (#5073) Add fallback and checks for whether browser has vim paste/copy --- src/keyboard/vim.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/keyboard/vim.js b/src/keyboard/vim.js index df760a6e9f8..956cfaf7316 100644 --- a/src/keyboard/vim.js +++ b/src/keyboard/vim.js @@ -2062,7 +2062,9 @@ domLib.importCssString(`.normal-mode .ace_cursor{ } else { register.setText(text, linewise, blockwise); } - if (registerName === '+') { + if (registerName === '+' && typeof navigator !== 'undefined' && + typeof navigator.clipboard !== 'undefined' && + typeof navigator.clipboard.readText === 'function') { navigator.clipboard.writeText(text); } // The unnamed register always has the same value as the last used @@ -3597,14 +3599,20 @@ domLib.importCssString(`.normal-mode .ace_cursor{ }, paste: function(cm, actionArgs, vim) { var register = vimGlobalState.registerController.getRegister( - actionArgs.registerName); - if (actionArgs.registerName === '+') { + actionArgs.registerName); + var fallback = () => { + var text = register.toString(); + this.continuePaste(cm, actionArgs, vim, text, register); + } + if (actionArgs.registerName === '+' && + typeof navigator !== 'undefined' && + typeof navigator.clipboard !== 'undefined' && + typeof navigator.clipboard.readText === 'function') { navigator.clipboard.readText().then((value) => { this.continuePaste(cm, actionArgs, vim, value, register); - }) + }, () => { fallback() }) } else { - var text = register.toString(); - this.continuePaste(cm, actionArgs, vim, text, register); + fallback() } }, continuePaste: function(cm, actionArgs, vim, text, register) { From 23d4df6a260a504f4523be6176c5e8bcc6ab132e Mon Sep 17 00:00:00 2001 From: Slava Rozhnev Date: Fri, 14 Apr 2023 17:51:06 +0300 Subject: [PATCH 0774/1293] Date and Time Functions added to MySQL highlight mode (#5126) added list of Date and Time Functions according MySQL documentation https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html Co-authored-by: SlavaRozhnev --- src/mode/mysql_highlight_rules.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mode/mysql_highlight_rules.js b/src/mode/mysql_highlight_rules.js index 5ccf55308e5..2f88e5c2b00 100644 --- a/src/mode/mysql_highlight_rules.js +++ b/src/mode/mysql_highlight_rules.js @@ -5,10 +5,13 @@ var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var MysqlHighlightRules = function() { var mySqlKeywords = /*sql*/ "alter|and|as|asc|between|count|create|delete|desc|distinct|drop|from|lateral|having|in|insert|into|is|join|like|not|on|or|order|select|set|table|union|update|values|where" - /*mysql*/ + "|accessible|action|add|after|algorithm|all|analyze|asensitive|at|authors|auto_increment|autocommit|avg|avg_row_length|before|binary|binlog|both|btree|cache|call|cascade|cascaded|case|catalog_name|chain|change|changed|character|check|checkpoint|checksum|class_origin|client_statistics|close|coalesce|code|collate|collation|collations|column|columns|comment|commit|committed|completion|concurrent|condition|connection|consistent|constraint|contains|continue|contributors|convert|cross|current_date|current_time|current_timestamp|current_user|cursor|data|database|databases|day_hour|day_microsecond|day_minute|day_second|deallocate|dec|declare|default|delay_key_write|delayed|delimiter|des_key_file|describe|deterministic|dev_pop|dev_samp|deviance|directory|disable|discard|distinctrow|div|dual|dumpfile|each|elseif|enable|enclosed|end|ends|engine|engines|enum|errors|escape|escaped|even|event|events|every|execute|exists|exit|explain|extended|fast|fetch|field|fields|first|flush|for|force|foreign|found_rows|full|fulltext|function|general|global|grant|grants|group|by|groupby_concat|handler|hash|help|high_priority|hosts|hour_microsecond|hour_minute|hour_second|if|ignore|ignore_server_ids|import|index|index_statistics|infile|inner|innodb|inout|insensitive|insert_method|install|interval|invoker|isolation|iterate|key|keys|kill|language|last|leading|leave|left|level|limit|linear|lines|list|load|local|localtime|localtimestamp|lock|logs|low_priority|master|master_heartbeat_period|master_ssl_verify_server_cert|masters|match|max|max_rows|maxvalue|message_text|middleint|migrate|min|min_rows|minute_microsecond|minute_second|mod|mode|modifies|modify|mutex|mysql_errno|natural|next|no|no_write_to_binlog|offline|offset|one|online|open|optimize|option|optionally|out|outer|outfile|pack_keys|parser|partition|partitions|password|phase|plugin|plugins|prepare|preserve|prev|primary|privileges|procedure|processlist|profile|profiles|purge|query|quick|range|read|read_write|reads|real|rebuild|recover|references|regexp|relaylog|release|remove|rename|reorganize|repair|repeatable|replace|require|resignal|restrict|resume|return|returns|revoke|right|rlike|rollback|rollup|row|row_format|rtree|savepoint|schedule|schema|schema_name|schemas|second_microsecond|security|sensitive|separator|serializable|server|session|share|show|signal|slave|slow|smallint|snapshot|soname|spatial|specific|sql|sql_big_result|sql_buffer_result|sql_cache|sql_calc_found_rows|sql_no_cache|sql_small_result|sqlexception|sqlstate|sqlwarning|ssl|start|starting|starts|status|std|stddev|stddev_pop|stddev_samp|storage|straight_join|subclass_origin|sum|suspend|table_name|table_statistics|tables|tablespace|temporary|terminated|to|trailing|transaction|trigger|triggers|truncate|uncommitted|undo|uninstall|unique|unlock|upgrade|usage|use|use_frm|user|user_resources|user_statistics|using|utc_date|utc_time|utc_timestamp|value|variables|varying|view|views|warnings|when|while|with|work|write|xa|xor|year_month|zerofill|begin|do|then|else|loop|repeat"; - var builtins = "ucase|lcase|mid|len|round|rank|now|format|coalesce|ifnull|isnull|nvl|date|time|timestamp"; + /*mysql*/ + "|accessible|action|add|after|algorithm|all|analyze|asensitive|at|authors|auto_increment|autocommit|avg|avg_row_length|before|binary|binlog|both|btree|cache|call|cascade|cascaded|case|catalog_name|chain|change|changed|character|check|checkpoint|checksum|class_origin|client_statistics|close|code|collate|collation|collations|column|columns|comment|commit|committed|completion|concurrent|condition|connection|consistent|constraint|contains|continue|contributors|convert|cross|current_date|current_time|current_timestamp|current_user|cursor|data|database|databases|day_hour|day_microsecond|day_minute|day_second|deallocate|dec|declare|default|delay_key_write|delayed|delimiter|des_key_file|describe|deterministic|dev_pop|dev_samp|deviance|directory|disable|discard|distinctrow|div|dual|dumpfile|each|elseif|enable|enclosed|end|ends|engine|engines|enum|errors|escape|escaped|even|event|events|every|execute|exists|exit|explain|extended|fast|fetch|field|fields|first|flush|for|force|foreign|found_rows|full|fulltext|function|general|global|grant|grants|group|by|groupby_concat|handler|hash|help|high_priority|hosts|hour_microsecond|hour_minute|hour_second|if|ignore|ignore_server_ids|import|index|index_statistics|infile|inner|innodb|inout|insensitive|insert_method|install|interval|invoker|isolation|iterate|key|keys|kill|language|last|leading|leave|left|level|limit|linear|lines|list|load|local|localtime|localtimestamp|lock|logs|low_priority|master|master_heartbeat_period|master_ssl_verify_server_cert|masters|match|max|max_rows|maxvalue|message_text|middleint|migrate|min|min_rows|minute_microsecond|minute_second|mod|mode|modifies|modify|mutex|mysql_errno|natural|next|no|no_write_to_binlog|offline|offset|one|online|open|optimize|option|optionally|out|outer|outfile|pack_keys|parser|partition|partitions|password|phase|plugin|plugins|prepare|preserve|prev|primary|privileges|procedure|processlist|profile|profiles|purge|query|quick|range|read|read_write|reads|real|rebuild|recover|references|regexp|relaylog|release|remove|rename|reorganize|repair|repeatable|replace|require|resignal|restrict|resume|return|returns|revoke|right|rlike|rollback|rollup|row|row_format|rtree|savepoint|schedule|schema|schema_name|schemas|second_microsecond|security|sensitive|separator|serializable|server|session|share|show|signal|slave|slow|smallint|snapshot|soname|spatial|specific|sql|sql_big_result|sql_buffer_result|sql_cache|sql_calc_found_rows|sql_no_cache|sql_small_result|sqlexception|sqlstate|sqlwarning|ssl|start|starting|starts|status|std|stddev|stddev_pop|stddev_samp|storage|straight_join|subclass_origin|sum|suspend|table_name|table_statistics|tables|tablespace|temporary|terminated|to|trailing|transaction|trigger|triggers|truncate|uncommitted|undo|uninstall|unique|unlock|upgrade|usage|use|use_frm|user|user_resources|user_statistics|using|utc_date|utc_time|utc_timestamp|value|variables|varying|view|views|warnings|when|while|with|work|write|xa|xor|year_month|zerofill|begin|do|then|else|loop|repeat"; + var builtins = "rank|coalesce|ifnull|isnull|nvl"; var variable = "charset|clear|connect|edit|ego|exit|go|help|nopager|notee|nowarning|pager|print|prompt|quit|rehash|source|status|system|tee"; - + var datetimeFunctions = 'adddate|addtime|convert_tz|curdate|current_date|current_time|current_timestamp|curtime|date|date_add|date_format|date_sub|datediff|day|dayname|dayofmonth|dayofweek|dayofyear|extract|from_days|from_unixtime|get_format|hour|last_day|localtime|localtimestamp|makedate|maketime|microsecond|minute|month|monthname|now|period_add|period_diff|quarter|sec_to_time|second|str_to_date|subdate|subtime|sysdate|time|time_format|time_to_sec|timediff|timestamp|timestampadd|timestampdiff|to_days|to_seconds|unix_timestamp|utc_date|utc_time|utc_timestamp|week|weekday|weekofyear|year|yearweek'; + var encryptionFunctions = 'aes_decrypt|aes_encrypt|compress|md|random_bytes|sha|sha|statement_digest|statement_digest_text|uncompress|uncompressed_length|validate_password_strength'; + var mathFunctions = 'abs|acos|asin|atan|atan|ceil|ceiling|conv|cos|cot|crc|degrees|div|exp|floor|ln|log|log10|log2|mod|pi|pow|power|radians|rand|round|sign|sin|sqrt|tan|truncate'; + var stringFunctions = 'ascii|bin|bit_length|char|char_length|character_length|concat|concat_ws|elt|export_set|field|find_in_set|format|from_base|hex|insert|instr|lcase|left|length|like|load_file|locate|lower|lpad|ltrim|make_set|match|mid|not|not|oct|octet_length|ord|position|quote|regexp|regexp_instr|regexp_like|regexp_replace|regexp_substr|repeat|replace|reverse|right|rlike|rpad|rtrim|soundex|sounds|space|strcmp|substr|substring|substring_index|to_base|trim|ucase|unhex|upper|weight_string'; //operatorChars: /^[*+\-%<>!=&|^]/, var dataTypes = ( "bool|boolean|bit|blob|decimal|double|enum|float|long|longblob|longtext|medium|mediumblob|mediumint|mediumtext|time|timestamp|tinyblob|tinyint|tinytext|text|" + @@ -16,7 +19,7 @@ var MysqlHighlightRules = function() { ); var keywordMapper = this.createKeywordMapper({ - "support.function": builtins, + "support.function": [builtins, datetimeFunctions, encryptionFunctions, mathFunctions, stringFunctions].join('|'), "keyword": mySqlKeywords, "storage.type": dataTypes, "constant": "false|true|null|unknown|ODBCdotTable|zerolessFloat", From 3b94227f8f92efb7ddcb4b93b81fdf2a76b23e98 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 17 Apr 2023 15:49:22 +0400 Subject: [PATCH 0775/1293] tooltips should follow editor theme --- demo/kitchen-sink/token_tooltip.js | 3 +++ src/autocomplete.js | 4 +++- src/css/editor.css.js | 7 ++++++- src/mouse/default_gutter_handler.js | 3 +++ src/tooltip.js | 17 ++++++++++------- 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/demo/kitchen-sink/token_tooltip.js b/demo/kitchen-sink/token_tooltip.js index c2bbccdbbbf..f352463aecb 100644 --- a/demo/kitchen-sink/token_tooltip.js +++ b/demo/kitchen-sink/token_tooltip.js @@ -72,6 +72,9 @@ class TokenTooltip extends Tooltip { this.height = this.getHeight(); this.tokenText = tokenText; } + if (!this.isOpen) { + this.setTheme(r.theme); + } this.show(null, this.x, this.y); diff --git a/src/autocomplete.js b/src/autocomplete.js index d93a45ab909..d665e37aa3f 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -390,13 +390,15 @@ class Autocomplete { showDocTooltip(item) { if (!this.tooltipNode) { this.tooltipNode = dom.createElement("div"); - this.tooltipNode.className = "ace_tooltip ace_doc-tooltip"; this.tooltipNode.style.margin = 0; this.tooltipNode.style.pointerEvents = "auto"; this.tooltipNode.tabIndex = -1; this.tooltipNode.onblur = this.blurListener.bind(this); this.tooltipNode.onclick = this.onTooltipClick.bind(this); } + var theme = this.editor.renderer.theme; + this.tooltipNode.className = "ace_tooltip ace_doc-tooltip " + + (theme.isDark? "ace_dark " : "") + (theme.cssClass || ""); var tooltipNode = this.tooltipNode; if (item.docHTML) { diff --git a/src/css/editor.css.js b/src/css/editor.css.js index a4e012ada7d..372c83ba806 100644 --- a/src/css/editor.css.js +++ b/src/css/editor.css.js @@ -443,8 +443,13 @@ module.exports = ` pointer-events: none; } +.ace_tooltip.ace_dark { + background-color: #636363; + color: #fff; +} + .ace_tooltip:focus { - outline: 1px solid black; + outline: 1px solid #5E9ED6; } .ace_gutter-tooltip_header { diff --git a/src/mouse/default_gutter_handler.js b/src/mouse/default_gutter_handler.js index d53d5543aab..d7c6cdea92f 100644 --- a/src/mouse/default_gutter_handler.js +++ b/src/mouse/default_gutter_handler.js @@ -87,6 +87,9 @@ function GutterHandler(mouseHandler) { tooltip.setClassName("ace_gutter-tooltip"); tooltip.$element.setAttribute("aria-live", "polite"); + if (!tooltip.isOpen) { + tooltip.setTheme(editor.renderer.theme); + } tooltip.show(); editor._signal("showGutterTooltip", tooltip); editor.on("mousewheel", hideTooltip); diff --git a/src/tooltip.js b/src/tooltip.js index 81832b00672..a7f3194a583 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -24,7 +24,7 @@ class Tooltip { } /** - * @returns {Element} + * @returns {HTMLElement} **/ getElement() { return this.$element || this.$init(); @@ -60,6 +60,11 @@ class Tooltip { dom.addCssClass(this.getElement(), className); } + setTheme(theme) { + this.$element.className = CLASSNAME + " " + + (theme.isDark? "ace_dark " : "") + (theme.cssClass || ""); + } + /** * @param {String} text * @param {Number} x @@ -179,7 +184,6 @@ class HoverTooltip extends Tooltip { el.style.whiteSpace = "pre-wrap"; el.style.pointerEvents = "auto"; el.addEventListener("mouseout", this.onMouseOut); - el.classList.add("ace_doc-tooltip"); el.tabIndex = -1; el.addEventListener("blur", function() { @@ -212,7 +216,7 @@ class HoverTooltip extends Tooltip { this.timeout = setTimeout(this.waitForHover, this.idleTime); } waitForHover() { - clearTimeout(this.timeout); + if (this.timeout) clearTimeout(this.timeout); var dt = Date.now() - this.lastT; if (this.idleTime - dt > 10) { this.timeout = setTimeout(this.waitForHover, this.idleTime - dt); @@ -250,9 +254,11 @@ class HoverTooltip extends Tooltip { if (startingEvent && startingEvent != this.lastEvent) return; if (this.isOpen && document.activeElement == this.getElement()) return; + var renderer = editor.renderer; if (!this.isOpen) { popupManager.addPopup(this); this.$registerCloseEvents(); + this.setTheme(renderer.theme); } this.isOpen = true; @@ -264,7 +270,6 @@ class HoverTooltip extends Tooltip { element.appendChild(domNode); element.style.display = "block"; - var renderer = editor.renderer; var position = renderer.textToScreenCoordinates(range.start.row, range.start.column); var cursorPos = editor.getCursorPosition(); @@ -312,7 +317,7 @@ class HoverTooltip extends Tooltip { if (e && e.target && this.$element.contains(e.target)) return; this.lastEvent = null; - clearTimeout(this.timeout); + if (this.timeout) clearTimeout(this.timeout); this.timeout = null; this.addMarker(null); if (this.isOpen) { @@ -348,8 +353,6 @@ class HoverTooltip extends Tooltip { if (e && e.currentTarget.contains(e.relatedTarget)) return; if (!e.relatedTarget.classList.contains("ace_content")) this.hide(); } - - } exports.HoverTooltip = HoverTooltip; From b48a59f47058277de0968251274d19d1d2449cf7 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 19 Apr 2023 10:25:56 +0400 Subject: [PATCH 0776/1293] fix regression in searchbar keyboard handler --- src/ext/searchbox.js | 186 ++++++++++++++++++++++--------------------- 1 file changed, 94 insertions(+), 92 deletions(-) diff --git a/src/ext/searchbox.js b/src/ext/searchbox.js index 4a731bfefcb..5d034817173 100644 --- a/src/ext/searchbox.js +++ b/src/ext/searchbox.js @@ -44,98 +44,6 @@ class SearchBox { this.$init(); this.setEditor(editor); dom.importCssString(searchboxCss, "ace_searchbox", editor.container); - - - //keybinding outside of the searchbox - this.$searchBarKb = new HashHandler(); - this.$searchBarKb.bindKeys({ - "Ctrl-f|Command-f": function(sb) { - var isReplace = sb.isReplace = !sb.isReplace; - sb.replaceBox.style.display = isReplace ? "" : "none"; - sb.replaceOption.checked = false; - sb.$syncOptions(); - sb.searchInput.focus(); - }, - "Ctrl-H|Command-Option-F": function(sb) { - if (sb.editor.getReadOnly()) - return; - sb.replaceOption.checked = true; - sb.$syncOptions(); - sb.replaceInput.focus(); - }, - "Ctrl-G|Command-G": function(sb) { - sb.findNext(); - }, - "Ctrl-Shift-G|Command-Shift-G": function(sb) { - sb.findPrev(); - }, - "esc": function(sb) { - setTimeout(function() { sb.hide();}); - }, - "Return": function(sb) { - if (sb.activeInput == sb.replaceInput) - sb.replace(); - sb.findNext(); - }, - "Shift-Return": function(sb) { - if (sb.activeInput == sb.replaceInput) - sb.replace(); - sb.findPrev(); - }, - "Alt-Return": function(sb) { - if (sb.activeInput == sb.replaceInput) - sb.replaceAll(); - sb.findAll(); - }, - "Tab": function(sb) { - (sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus(); - } - }); - - this.$searchBarKb.addCommands([{ - name: "toggleRegexpMode", - bindKey: {win: "Alt-R|Alt-/", mac: "Ctrl-Alt-R|Ctrl-Alt-/"}, - exec: function(sb) { - sb.regExpOption.checked = !sb.regExpOption.checked; - sb.$syncOptions(); - } - }, { - name: "toggleCaseSensitive", - bindKey: {win: "Alt-C|Alt-I", mac: "Ctrl-Alt-R|Ctrl-Alt-I"}, - exec: function(sb) { - sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked; - sb.$syncOptions(); - } - }, { - name: "toggleWholeWords", - bindKey: {win: "Alt-B|Alt-W", mac: "Ctrl-Alt-B|Ctrl-Alt-W"}, - exec: function(sb) { - sb.wholeWordOption.checked = !sb.wholeWordOption.checked; - sb.$syncOptions(); - } - }, { - name: "toggleReplace", - exec: function(sb) { - sb.replaceOption.checked = !sb.replaceOption.checked; - sb.$syncOptions(); - } - }, { - name: "searchInSelection", - exec: function(sb) { - sb.searchOption.checked = !sb.searchRange; - sb.setSearchRange(sb.searchOption.checked && sb.editor.getSelectionRange()); - sb.$syncOptions(); - } - }]); - - //keybinding outside of the searchbox - this.$closeSearchBarKb = new HashHandler([{ - bindKey: "Esc", - name: "closeSearchBar", - exec: function(editor) { - editor.searchBox.hide(); - } - }]); } setEditor(editor) { @@ -352,6 +260,100 @@ class SearchBox { } } +//keybinding outside of the searchbox +var $searchBarKb = new HashHandler(); +$searchBarKb.bindKeys({ + "Ctrl-f|Command-f": function(sb) { + var isReplace = sb.isReplace = !sb.isReplace; + sb.replaceBox.style.display = isReplace ? "" : "none"; + sb.replaceOption.checked = false; + sb.$syncOptions(); + sb.searchInput.focus(); + }, + "Ctrl-H|Command-Option-F": function(sb) { + if (sb.editor.getReadOnly()) + return; + sb.replaceOption.checked = true; + sb.$syncOptions(); + sb.replaceInput.focus(); + }, + "Ctrl-G|Command-G": function(sb) { + sb.findNext(); + }, + "Ctrl-Shift-G|Command-Shift-G": function(sb) { + sb.findPrev(); + }, + "esc": function(sb) { + setTimeout(function() { sb.hide();}); + }, + "Return": function(sb) { + if (sb.activeInput == sb.replaceInput) + sb.replace(); + sb.findNext(); + }, + "Shift-Return": function(sb) { + if (sb.activeInput == sb.replaceInput) + sb.replace(); + sb.findPrev(); + }, + "Alt-Return": function(sb) { + if (sb.activeInput == sb.replaceInput) + sb.replaceAll(); + sb.findAll(); + }, + "Tab": function(sb) { + (sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus(); + } +}); + +$searchBarKb.addCommands([{ + name: "toggleRegexpMode", + bindKey: {win: "Alt-R|Alt-/", mac: "Ctrl-Alt-R|Ctrl-Alt-/"}, + exec: function(sb) { + sb.regExpOption.checked = !sb.regExpOption.checked; + sb.$syncOptions(); + } +}, { + name: "toggleCaseSensitive", + bindKey: {win: "Alt-C|Alt-I", mac: "Ctrl-Alt-R|Ctrl-Alt-I"}, + exec: function(sb) { + sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked; + sb.$syncOptions(); + } +}, { + name: "toggleWholeWords", + bindKey: {win: "Alt-B|Alt-W", mac: "Ctrl-Alt-B|Ctrl-Alt-W"}, + exec: function(sb) { + sb.wholeWordOption.checked = !sb.wholeWordOption.checked; + sb.$syncOptions(); + } +}, { + name: "toggleReplace", + exec: function(sb) { + sb.replaceOption.checked = !sb.replaceOption.checked; + sb.$syncOptions(); + } +}, { + name: "searchInSelection", + exec: function(sb) { + sb.searchOption.checked = !sb.searchRange; + sb.setSearchRange(sb.searchOption.checked && sb.editor.getSelectionRange()); + sb.$syncOptions(); + } +}]); + +//keybinding outside of the searchbox +var $closeSearchBarKb = new HashHandler([{ + bindKey: "Esc", + name: "closeSearchBar", + exec: function(editor) { + editor.searchBox.hide(); + } +}]); + +SearchBox.prototype.$searchBarKb = $searchBarKb; +SearchBox.prototype.$closeSearchBarKb = $closeSearchBarKb; + exports.SearchBox = SearchBox; exports.Search = function(editor, isReplace) { From 01d4605c0dcf7bcbb4f1a09a243f7ef6d16d7d43 Mon Sep 17 00:00:00 2001 From: Zakhar Kozlov Date: Wed, 19 Apr 2023 10:38:59 +0200 Subject: [PATCH 0777/1293] feat: marker groups (#5113) * feat: markers with tooltips * refactor: rename TooltipMarkerGroup to MarkerGroup * unify diagnostic and occurrence markers * cleanup --------- Co-authored-by: Zakhar Kozlov Co-authored-by: nightwing --- ace.d.ts | 13 +++++ demo/kitchen-sink/demo.js | 110 ++++++++++++++++++++++++++++++----- demo/kitchen-sink/styles.css | 32 ++++++++++ src/marker_group.js | 102 ++++++++++++++++++++++++++++++++ src/marker_group_test.js | 75 ++++++++++++++++++++++++ src/search_highlight.js | 4 +- src/test/all_browser.js | 1 + src/tooltip.js | 21 +++++-- src/tooltip_test.js | 11 ++++ 9 files changed, 346 insertions(+), 23 deletions(-) create mode 100644 src/marker_group.js create mode 100644 src/marker_group_test.js diff --git a/ace.d.ts b/ace.d.ts index 7ed46b6f7b6..b7d483857c7 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -227,6 +227,7 @@ export namespace Ace { value: string; session: EditSession; relativeLineNumbers: boolean; + enableMultiselect: boolean; enableKeyboardAccessibility: boolean; } @@ -275,6 +276,18 @@ export namespace Ace { type: string; } + export interface MarkerGroupItem { + range: Range; + className: string; + } + + export class MarkerGroup { + constructor(session: EditSession); + setMarkers: (markers: MarkerGroupItem[]) => void; + getMarkerAtPosition: (pos: Position) => MarkerGroupItem; + } + + export interface Command { name?: string; bindKey?: string | { mac?: string, win?: string }; diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 808a09ff730..ed48cf8e7c6 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -29,6 +29,7 @@ var HashHandler = require("ace/keyboard/hash_handler").HashHandler; var Renderer = require("ace/virtual_renderer").VirtualRenderer; var Editor = require("ace/editor").Editor; +var Range = require("ace/range").Range; var whitespace = require("ace/ext/whitespace"); @@ -44,7 +45,6 @@ var ElasticTabstopsLite = require("ace/ext/elastic_tabstops_lite").ElasticTabsto var IncrementalSearch = require("ace/incremental_search").IncrementalSearch; - var TokenTooltip = require("./token_tooltip").TokenTooltip; require("ace/config").defineOptions(Editor.prototype, "editor", { showTokenInfo: { @@ -61,7 +61,7 @@ require("ace/config").defineOptions(Editor.prototype, "editor", { return !!this.tokenTooltip; }, handlesSet: true - }, + } }); require("ace/config").defineOptions(Editor.prototype, "editor", { @@ -80,30 +80,110 @@ require("ace/config").defineOptions(Editor.prototype, "editor", { }); var {HoverTooltip} = require("ace/tooltip"); +var MarkerGroup = require("ace/marker_group").MarkerGroup; var docTooltip = new HoverTooltip(); function loadLanguageProvider(editor) { require([ "https://www.unpkg.com/ace-linters/build/ace-linters.js" - ], (m) => { - window.languageProvider = m.LanguageProvider.fromCdn("https://www.unpkg.com/ace-linters/build"); - window.languageProvider.registerEditor(editor); + ], function(m) { + var languageProvider = m.LanguageProvider.fromCdn("https://www.unpkg.com/ace-linters/build", { + functionality: { + hover: true, + completion: { + overwriteCompleters: true + }, + completionResolve: true, + format: true, + documentHighlights: true, + signatureHelp: false + } + }); + window.languageProvider = languageProvider; + languageProvider.registerEditor(editor); + // hack to replace tooltip implementation from ace-linters with hover tooltip + // can be removed when ace-linters is updated to use MarkerGroup and HoverTooltip if (languageProvider.$descriptionTooltip) editor.off("mousemove", languageProvider.$descriptionTooltip.onMouseMove); - + languageProvider.$messageController.$worker.addEventListener("message", function(e) { + var id = e.data.sessionId.split(".")[0]; + var session = languageProvider.$getSessionLanguageProvider({id: id})?.session; + if (e.data.type == 6) { + // annotation message + e.stopPropagation(); + if (session) { + showAnnotations(session, e.data.value); + } + } else if (e.data.type == 13) { + // highlights message + if (session) showOccurrenceMarkers(session, e.data.value); + } + }, true); + function showOccurrenceMarkers(session, positions) { + if (!session.state.occurrenceMarkers) { + session.state.occurrenceMarkers = new MarkerGroup(session); + } + session.state.occurrenceMarkers.setMarkers(positions.map(function(el) { + var r = el.range; + return { + range: new Range(r.start.line, r.start.character, r.end.line, r.end.character), + // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#documentHighlightKind + className: el.kind == 2 + ? "language_highlight_read" + : el.kind == 3 + ? "language_highlight_write" + : "language_highlight_text" + }; + })); + } + function showAnnotations(session, diagnostics) { + session.clearAnnotations(); + let annotations = diagnostics.map((el) => { + console.log(el.severity, el) + return { + row: el.range.start.line, + column: el.range.start.character, + text: el.message, + type: el.severity === 1 ? "error" : el.severity === 2 ? "warning" : "info" + }; + }); + if (annotations && annotations.length > 0) { + session.setAnnotations(annotations); + } + + if (!session.state) session.state = {} + if (!session.state.diagnosticMarkers) { + session.state.diagnosticMarkers = new MarkerGroup(session); + } + session.state.diagnosticMarkers.setMarkers(diagnostics.map(function(el) { + var r = el.range; + return { + range: new Range(r.start.line, r.start.character, r.end.line, r.end.character), + tooltipText: el.message, + className: "language_highlight_error" + }; + })); + }; docTooltip.setDataProvider(function(e, editor) { - var renderer = editor.renderer; - let session = editor.session; - let docPos = e.getDocumentPosition() ; + let docPos = e.getDocumentPosition(); languageProvider.doHover(session, docPos, function(hover) { - if (!hover) { - return; - } - // todo should ace itself handle markdown? - var domNode = dom.buildDom(["p", {}, hover.content.text]); - docTooltip.showForRange(editor, hover.range, domNode, e); + var errorMarker = session.state?.diagnosticMarkers.getMarkerAtPosition(docPos); + var range = hover?.range || errorMarker?.range; + if (!range) return; + var hoverNode = hover && dom.buildDom(["div", {}]) + if (hoverNode) { + hover.content.text = hover.content.text.replace(/(?!^)`{3}/gm, "\n$&"); + // todo render markdown using ace markdown mode + hoverNode.innerHTML = languageProvider.getTooltipText(hover); + }; + + var domNode = dom.buildDom(["div", {}, + errorMarker && ["div", {}, errorMarker.tooltipText.trim()], + hoverNode + ]); + docTooltip.showForRange(editor, range, domNode, e); }); }); diff --git a/demo/kitchen-sink/styles.css b/demo/kitchen-sink/styles.css index a0ad03869ca..d669a716c4a 100644 --- a/demo/kitchen-sink/styles.css +++ b/demo/kitchen-sink/styles.css @@ -92,4 +92,36 @@ body { z-index: 1000!important; opacity: 1!important; font-size: 1em!important; +} + + +.language_highlight_error { + position: absolute; + border-bottom: dotted 1px #e00404; + z-index: 2000; + border-radius: 0; +} +.language_highlight_warning { + position: absolute; + border-bottom: solid 1px #DDC50F; + z-index: 2000; + border-radius: 0; +} +.language_highlight_info { + position: absolute; + border-bottom: dotted 1px #999; + z-index: 2000; + border-radius: 0; +} +.language_highlight_text, .language_highlight_read, .language_highlight_write { + position: absolute; + box-sizing: border-box; + border: solid 1px #888; + z-index: 2000; +} +.language_highlight_write { + border: solid 1px #F88; +} +.ace_tooltip pre { + margin: 0; } \ No newline at end of file diff --git a/src/marker_group.js b/src/marker_group.js new file mode 100644 index 00000000000..0e559c66cc5 --- /dev/null +++ b/src/marker_group.js @@ -0,0 +1,102 @@ +"use strict"; + +/* +Potential improvements: +- use binary search when looking for hover match +*/ + +class MarkerGroup { + constructor(session) { + this.markers = []; + this.session = session; + session.addDynamicMarker(this); + } + + /** + * Finds the first marker containing pos + * @param {Position} pos + * @returns Ace.MarkerGroupItem + */ + getMarkerAtPosition(pos) { + return this.markers.find(function(marker) { + return marker.range.contains(pos.row, pos.column); + }); + } + + /** + * Comparator for Array.sort function, which sorts marker definitions by their positions + * + * @param {Ace.MarkerGroupItem} a first marker. + * @param {Ace.MarkerGroupItem} b second marker. + * @returns {number} negative number if a should be before b, positive number if b should be before a, 0 otherwise. + */ + markersComparator(a, b) { + return a.range.start.row - b.range.start.row; + } + + /** + * Sets marker definitions to be rendered. Limits the number of markers at MAX_MARKERS. + * @param {Ace.MarkerGroupItem[]} markers an array of marker definitions. + */ + setMarkers(markers) { + this.markers = markers.sort(this.markersComparator).slice(0, this.MAX_MARKERS); + this.session._signal("changeBackMarker"); + } + + update(html, markerLayer, session, config) { + if (!this.markers || !this.markers.length) + return; + var visibleRangeStartRow = config.firstRow, visibleRangeEndRow = config.lastRow; + var foldLine; + var markersOnOneLine = 0; + var lastRow = 0; + + for (var i = 0; i < this.markers.length; i++) { + var marker = this.markers[i]; + + if (marker.range.end.row < visibleRangeStartRow) continue; + if (marker.range.start.row > visibleRangeEndRow) continue; + + if (marker.range.start.row === lastRow) { + markersOnOneLine++; + } else { + lastRow = marker.range.start.row; + markersOnOneLine = 0; + } + // do not render too many markers on one line + // because we do not have virtual scroll for horizontal direction + if (markersOnOneLine > 200) { + continue; + } + + var markerVisibleRange = marker.range.clipRows(visibleRangeStartRow, visibleRangeEndRow); + if (markerVisibleRange.start.row === markerVisibleRange.end.row + && markerVisibleRange.start.column === markerVisibleRange.end.column) { + continue; // visible range is empty + } + + var screenRange = markerVisibleRange.toScreenRange(session); + if (screenRange.isEmpty()) { + // we are inside a fold + foldLine = session.getNextFoldLine(markerVisibleRange.end.row, foldLine); + if (foldLine && foldLine.end.row > markerVisibleRange.end.row) { + visibleRangeStartRow = foldLine.end.row; + } + continue; + } + + if (screenRange.isMultiLine()) { + markerLayer.drawTextMarker(html, screenRange, marker.className, config); + } else { + markerLayer.drawSingleLineMarker(html, screenRange, marker.className, config); + } + } + } + +} + +// this caps total amount of markers at 10K +MarkerGroup.prototype.MAX_MARKERS = 10000; + +exports.MarkerGroup = MarkerGroup; + diff --git a/src/marker_group_test.js b/src/marker_group_test.js new file mode 100644 index 00000000000..df88feea7d2 --- /dev/null +++ b/src/marker_group_test.js @@ -0,0 +1,75 @@ +if (typeof process !== "undefined") { + require("./test/mockdom"); +} + +"use strict"; + +var ace = require("./ace"); +var dom = require("./lib/dom"); +var assert = require("./test/assertions"); +var EditSession = require("./edit_session").EditSession; +var Range = require("./range").Range; +var MarkerGroup = require("./marker_group").MarkerGroup; +var editor; +var session1, session2; + +module.exports = { + setUp: function(next) { + var value = "Hello empty world\n" + + "This is a second line" + + "\n".repeat(100) + + "line number 100"; + session1 = new EditSession(value); + session2 = new EditSession("2 " + value); + editor = ace.edit(null, { + session: session1 + }); + document.body.appendChild(editor.container); + editor.container.style.height = "200px"; + editor.container.style.width = "300px"; + dom.importCssString('.ace_tooltip-marker_test { position: absolute; }'); + + next(); + }, + "test: show markers": function() { + editor.resize(true); + editor.renderer.$loop._flush(); + var markerGroup = new MarkerGroup(session1); + + markerGroup.setMarkers([{ + range: new Range(0, 0, 0, 5), + className: "ace_tooltip-marker_test m2" + }, { + range: new Range(0, 12, 1, 4), + className: "ace_tooltip-marker_test m1", + isSecond: true + }]); + assert.ok(markerGroup.getMarkerAtPosition({row: 1, column: 1}).isSecond); + assert.ok(!markerGroup.getMarkerAtPosition({row: 3, column: 1})); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 2); + assert.equal(editor.container.querySelectorAll(".m2").length, 1); + editor.setSession(session2); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 0); + editor.setSession(session1); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 2); + editor.execCommand("gotoend"); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 0); + editor.execCommand("gotostart"); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 2); + markerGroup.setMarkers([]); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 0); + }, + tearDown: function() { + editor.destroy(); + } +}; + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/src/search_highlight.js b/src/search_highlight.js index 68a3ce9bd6b..8c941e82a51 100644 --- a/src/search_highlight.js +++ b/src/search_highlight.js @@ -3,8 +3,6 @@ var lang = require("./lib/lang"); var Range = require("./range").Range; -var SearchHighlight = - class SearchHighlight { constructor(regExp, clazz, type = "text") { this.setRegexp(regExp); @@ -49,7 +47,7 @@ class SearchHighlight { } } -}; +} // needed to prevent long lines from freezing the browser SearchHighlight.prototype.MAX_RANGES = 500; diff --git a/src/test/all_browser.js b/src/test/all_browser.js index 00946198dd3..c6143d6ade2 100644 --- a/src/test/all_browser.js +++ b/src/test/all_browser.js @@ -70,6 +70,7 @@ var testNames = [ "ace/search_test", "ace/selection_test", "ace/snippets_test", + "ace/marker_group_test", "ace/tooltip_test", "ace/token_iterator_test", "ace/tokenizer_test", diff --git a/src/tooltip.js b/src/tooltip.js index 81832b00672..39ac84baa5f 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -147,8 +147,8 @@ class PopupManager { } doPopupsOverlap (popupA, popupB) { - const rectA = popupA.getRect(); - const rectB = popupB.getRect(); + const rectA = popupA.getElement().getBoundingClientRect(); + const rectB = popupB.getElement().getBoundingClientRect(); return (rectA.left < rectB.right && rectA.right > rectB.left && rectA.top < rectB.bottom && rectA.bottom > rectB.top); @@ -187,11 +187,22 @@ class HoverTooltip extends Tooltip { }.bind(this)); } - addToEditor(editor, callback, cancel) { + addToEditor(editor) { editor.on("mousemove", this.onMouseMove); + editor.on("mousedown", this.hide); editor.renderer.getMouseEventTarget().addEventListener("mouseout", this.onMouseOut, true); } - + + removeFromEditor(editor) { + editor.off("mousemove", this.onMouseMove); + editor.off("mousedown", this.hide); + editor.renderer.getMouseEventTarget().removeEventListener("mouseout", this.onMouseOut, true); + if (this.timeout) { + clearTimeout(this.timeout); + this.timeout = null; + } + } + onMouseMove(e, editor) { this.lastEvent = e; this.lastT = Date.now(); @@ -309,7 +320,7 @@ class HoverTooltip extends Tooltip { hide(e) { if (!e && document.activeElement == this.getElement()) return; - if (e && e.target && this.$element.contains(e.target)) + if (e && e.target && e.type != "keydown" && this.$element.contains(e.target)) return; this.lastEvent = null; clearTimeout(this.timeout); diff --git a/src/tooltip_test.js b/src/tooltip_test.js index 10b8202e702..09bcc4979de 100644 --- a/src/tooltip_test.js +++ b/src/tooltip_test.js @@ -102,6 +102,17 @@ module.exports = { }, 6); }, 6); }, 6); + }, + "test: remove listeners": function() { + var l = editor._eventRegistry.mousemove.length; + docTooltip.addToEditor(editor); + assert.ok(!docTooltip.timeout); + assert.equal(editor._eventRegistry.mousemove.length, l + 1); + mouse("move", {row: 0, column: 1}); + assert.ok(docTooltip.timeout); + docTooltip.removeFromEditor(editor); + assert.ok(!docTooltip.timeout); + assert.equal(editor._eventRegistry.mousemove.length, l); } }; From dc63ba900d3641284d7d11cbb5ccad7c3039f3a4 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Fri, 21 Apr 2023 10:01:38 +0200 Subject: [PATCH 0778/1293] feat: summary of annotations in folded lines (#5117) Currently, when there are gutter annotations for lines which are folded away, the gutter annotations are invisible. This change adds a (optional) one-line summary of the annotations in the folded code. --- ace.d.ts | 1 + src/css/editor.css.js | 39 ++++--- src/editor.js | 1 + src/ext/options.js | 3 + src/layer/gutter.js | 70 +++++++++---- src/mouse/default_gutter_handler.js | 110 +++++++++++++------- src/mouse/default_gutter_handler_test.js | 125 +++++++++++++++++++---- src/virtual_renderer.js | 6 ++ 8 files changed, 261 insertions(+), 94 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index b7d483857c7..5619e8d9c73 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -195,6 +195,7 @@ export namespace Ace { hasCssTransforms: boolean; maxPixelHeight: number; useSvgGutterIcons: boolean; + showFoldedAnnotations: boolean; } export interface MouseHandlerOptions { diff --git a/src/css/editor.css.js b/src/css/editor.css.js index 372c83ba806..d44ff16e049 100644 --- a/src/css/editor.css.js +++ b/src/css/editor.css.js @@ -110,7 +110,7 @@ module.exports = ` pointer-events: none; } -.ace_gutter-cell, .ace_gutter-cell_svg-icons { +.ace_gutter-cell, .ace_gutter-cell_svg-icons { position: absolute; top: 0; left: 0; @@ -120,18 +120,23 @@ module.exports = ` background-repeat: no-repeat; } -.ace_gutter-cell_svg-icons .ace_icon_svg{ +.ace_gutter-cell_svg-icons .ace_icon_svg { margin-left: -14px; float: left; } -.ace_gutter-cell.ace_error, .ace_icon.ace_error { +.ace_gutter-cell .ace_icon { + margin-left: -18px; + float: left; +} + +.ace_gutter-cell.ace_error, .ace_icon.ace_error, .ace_icon.ace_error_fold { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg=="); background-repeat: no-repeat; background-position: 2px center; } -.ace_gutter-cell.ace_warning, .ace_icon.ace_warning { +.ace_gutter-cell.ace_warning, .ace_icon.ace_warning, .ace_icon.ace_warning_fold { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg=="); background-repeat: no-repeat; background-position: 2px center; @@ -147,18 +152,27 @@ module.exports = ` } .ace_icon_svg.ace_error { - -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJyZWQiIHNoYXBlLXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIj4KPGNpcmNsZSBmaWxsPSJub25lIiBjeD0iOCIgY3k9IjgiIHI9IjciIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPGxpbmUgeDE9IjExIiB5MT0iNSIgeDI9IjUiIHkyPSIxMSIvPgo8bGluZSB4MT0iMTEiIHkxPSIxMSIgeDI9IjUiIHkyPSI1Ii8+CjwvZz4KPC9zdmc+"); + -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJyZWQiIHNoYXBlLXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIj4KPGNpcmNsZSBmaWxsPSJub25lIiBjeD0iOCIgY3k9IjgiIHI9IjciIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPGxpbmUgeDE9IjExIiB5MT0iNSIgeDI9IjUiIHkyPSIxMSIvPgo8bGluZSB4MT0iMTEiIHkxPSIxMSIgeDI9IjUiIHkyPSI1Ii8+CjwvZz4KPC9zdmc+"); background-color: crimson; } .ace_icon_svg.ace_warning { - -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJkYXJrb3JhbmdlIiBzaGFwZS1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiI+Cjxwb2x5Z29uIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGZpbGw9Im5vbmUiIHBvaW50cz0iOCAxIDE1IDE1IDEgMTUgOCAxIi8+CjxyZWN0IHg9IjgiIHk9IjEyIiB3aWR0aD0iMC4wMSIgaGVpZ2h0PSIwLjAxIi8+CjxsaW5lIHgxPSI4IiB5MT0iNiIgeDI9IjgiIHkyPSIxMCIvPgo8L2c+Cjwvc3ZnPg=="); + -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJkYXJrb3JhbmdlIiBzaGFwZS1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiI+Cjxwb2x5Z29uIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGZpbGw9Im5vbmUiIHBvaW50cz0iOCAxIDE1IDE1IDEgMTUgOCAxIi8+CjxyZWN0IHg9IjgiIHk9IjEyIiB3aWR0aD0iMC4wMSIgaGVpZ2h0PSIwLjAxIi8+CjxsaW5lIHgxPSI4IiB5MT0iNiIgeDI9IjgiIHkyPSIxMCIvPgo8L2c+Cjwvc3ZnPg=="); background-color: darkorange; } .ace_icon_svg.ace_info { - -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJibHVlIiBzaGFwZS1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiI+CjxjaXJjbGUgZmlsbD0ibm9uZSIgY3g9IjgiIGN5PSI4IiByPSI3IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjxwb2x5bGluZSBwb2ludHM9IjggMTEgOCA4Ii8+Cjxwb2x5bGluZSBwb2ludHM9IjkgOCA2IDgiLz4KPGxpbmUgeDE9IjEwIiB5MT0iMTEiIHgyPSI2IiB5Mj0iMTEiLz4KPHJlY3QgeD0iOCIgeT0iNSIgd2lkdGg9IjAuMDEiIGhlaWdodD0iMC4wMSIvPgo8L2c+Cjwvc3ZnPg=="); + -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJibHVlIiBzaGFwZS1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiI+CjxjaXJjbGUgZmlsbD0ibm9uZSIgY3g9IjgiIGN5PSI4IiByPSI3IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjxwb2x5bGluZSBwb2ludHM9IjggMTEgOCA4Ii8+Cjxwb2x5bGluZSBwb2ludHM9IjkgOCA2IDgiLz4KPGxpbmUgeDE9IjEwIiB5MT0iMTEiIHgyPSI2IiB5Mj0iMTEiLz4KPHJlY3QgeD0iOCIgeT0iNSIgd2lkdGg9IjAuMDEiIGhlaWdodD0iMC4wMSIvPgo8L2c+Cjwvc3ZnPg=="); background-color: royalblue; } +.ace_icon_svg.ace_error_fold { + -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAxNiIgZmlsbD0ibm9uZSI+CiAgPHBhdGggZD0ibSAxOC45Mjk4NTEsNy44Mjk4MDc2IGMgMC4xNDYzNTMsNi4zMzc0NjA0IC02LjMyMzE0Nyw3Ljc3Nzg0NDQgLTcuNDc3OTEyLDcuNzc3ODQ0NCAtMi4xMDcyNzI2LC0wLjEyODc1IDUuMTE3Njc4LDAuMzU2MjQ5IDUuMDUxNjk4LC03Ljg3MDA2MTggLTAuNjA0NjcyLC04LjAwMzk3MzQ5IC03LjA3NzI3MDYsLTcuNTYzMTE4OSAtNC44NTczLC03LjQzMDM5NTU2IDEuNjA2LC0wLjExNTE0MjI1IDYuODk3NDg1LDEuMjYyNTQ1OTYgNy4yODM1MTQsNy41MjI2MTI5NiB6IiBmaWxsPSJjcmltc29uIiBzdHJva2Utd2lkdGg9IjIiLz4KICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0ibSA4LjExNDc1NjIsMi4wNTI5ODI4IGMgMy4zNDkxNjk4LDAgNi4wNjQxMzI4LDIuNjc2ODYyNyA2LjA2NDEzMjgsNS45Nzg5NTMgMCwzLjMwMjExMjIgLTIuNzE0OTYzLDUuOTc4OTIwMiAtNi4wNjQxMzI4LDUuOTc4OTIwMiAtMy4zNDkxNDczLDAgLTYuMDY0MTc3MiwtMi42NzY4MDggLTYuMDY0MTc3MiwtNS45Nzg5MjAyIDAuMDA1MzksLTMuMjk5ODg2MSAyLjcxNzI2NTYsLTUuOTczNjQwOCA2LjA2NDE3NzIsLTUuOTc4OTUzIHogbSAwLC0xLjczNTgyNzE5IGMgLTQuMzIxNDgzNiwwIC03LjgyNDc0MDM4LDMuNDU0MDE4NDkgLTcuODI0NzQwMzgsNy43MTQ3ODAxOSAwLDQuMjYwNzI4MiAzLjUwMzI1Njc4LDcuNzE0NzQ1MiA3LjgyNDc0MDM4LDcuNzE0NzQ1MiA0LjMyMTQ0OTgsMCA3LjgyNDY5OTgsLTMuNDU0MDE3IDcuODI0Njk5OCwtNy43MTQ3NDUyIDAsLTIuMDQ2MDkxNCAtMC44MjQzOTIsLTQuMDA4MzY3MiAtMi4yOTE3NTYsLTUuNDU1MTc0NiBDIDEyLjE4MDIyNSwxLjEyOTk2NDggMTAuMTkwMDEzLDAuMzE3MTU1NjEgOC4xMTQ3NTYyLDAuMzE3MTU1NjEgWiBNIDYuOTM3NDU2Myw4LjI0MDU5ODUgNC42NzE4Njg1LDEwLjQ4NTg1MiA2LjAwODY4MTQsMTEuODc2NzI4IDguMzE3MDAzNSw5LjYwMDc5MTEgMTAuNjI1MzM3LDExLjg3NjcyOCAxMS45NjIxMzgsMTAuNDg1ODUyIDkuNjk2NTUwOCw4LjI0MDU5ODUgMTEuOTYyMTM4LDYuMDA2ODA2NiAxMC41NzMyNDYsNC42Mzc0MzM1IDguMzE3MDAzNSw2Ljg3MzQyOTcgNi4wNjA3NjA3LDQuNjM3NDMzNSA0LjY3MTg2ODUsNi4wMDY4MDY2IFoiIGZpbGw9ImNyaW1zb24iIHN0cm9rZS13aWR0aD0iMiIvPgo8L3N2Zz4="); + background-color: crimson; +} +.ace_icon_svg.ace_warning_fold { + -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAyMCAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNC43NzY5IDE0LjczMzdMOC42NTE5MiAyLjQ4MzY5QzguMzI5NDYgMS44Mzg3NyA3LjQwOTEzIDEuODM4NzcgNy4wODY2NyAyLjQ4MzY5TDAuOTYxNjY5IDE0LjczMzdDMC42NzA3NzUgMTUuMzE1NSAxLjA5MzgzIDE2IDEuNzQ0MjkgMTZIMTMuOTk0M0MxNC42NDQ4IDE2IDE1LjA2NzggMTUuMzE1NSAxNC43NzY5IDE0LjczMzdaTTMuMTYwMDcgMTQuMjVMNy44NjkyOSA0LjgzMTU2TDEyLjU3ODUgMTQuMjVIMy4xNjAwN1pNOC43NDQyOSAxMS42MjVWMTMuMzc1SDYuOTk0MjlWMTEuNjI1SDguNzQ0MjlaTTYuOTk0MjkgMTAuNzVWNy4yNUg4Ljc0NDI5VjEwLjc1SDYuOTk0MjlaIiBmaWxsPSIjRUM3MjExIi8+CjxwYXRoIGQ9Ik0xMS4xOTkxIDIuOTUyMzhDMTAuODgwOSAyLjMxNDY3IDEwLjM1MzcgMS44MDUyNiA5LjcwNTUgMS41MDlMMTEuMDQxIDEuMDY5NzhDMTEuNjg4MyAwLjk0OTgxNCAxMi4zMzcgMS4yNzI2MyAxMi42MzE3IDEuODYxNDFMMTcuNjEzNiAxMS44MTYxQzE4LjM1MjcgMTMuMjkyOSAxNy41OTM4IDE1LjA4MDQgMTYuMDE4IDE1LjU3NDVDMTYuNDA0NCAxNC40NTA3IDE2LjMyMzEgMTMuMjE4OCAxNS43OTI0IDEyLjE1NTVMMTEuMTk5MSAyLjk1MjM4WiIgZmlsbD0iI0VDNzIxMSIvPgo8L3N2Zz4="); + background-color: darkorange; +} + .ace_scrollbar { contain: strict; position: absolute; @@ -452,17 +466,10 @@ module.exports = ` outline: 1px solid #5E9ED6; } -.ace_gutter-tooltip_header { - font-weight: bold; -} - -.ace_gutter-tooltip_body { - padding-top: 5px; -} - -.ace_gutter-tooltip .ace_icon { +.ace_icon { display: inline-block; width: 18px; + vertical-align: top; } .ace_icon_svg { diff --git a/src/editor.js b/src/editor.js index 474e8448b24..80f89a3870d 100644 --- a/src/editor.js +++ b/src/editor.js @@ -2932,6 +2932,7 @@ config.defineOptions(Editor.prototype, "editor", { useTextareaForIME: "renderer", useResizeObserver: "renderer", useSvgGutterIcons: "renderer", + showFoldedAnnotations: "renderer", scrollSpeed: "$mouseHandler", dragDelay: "$mouseHandler", diff --git a/src/ext/options.js b/src/ext/options.js index 471635fe182..2e2beb36f0d 100644 --- a/src/ext/options.js +++ b/src/ext/options.js @@ -198,6 +198,9 @@ var optionGroups = { "Use SVG gutter icons": { path: "useSvgGutterIcons" }, + "Annotations for folded lines": { + path: "showFoldedAnnotations" + }, "Keyboard Accessibility Mode": { path: "enableKeyboardAccessibility" } diff --git a/src/layer/gutter.js b/src/layer/gutter.js index 2f1bdbc73ae..44a153b939d 100644 --- a/src/layer/gutter.js +++ b/src/layer/gutter.js @@ -290,25 +290,9 @@ class Gutter{ var lineHeight = config.lineHeight + "px"; - var className; - if (this.$useSvgGutterIcons){ - className = "ace_gutter-cell_svg-icons "; - - if (this.$annotations[row]){ - annotationNode.className = "ace_icon_svg" + this.$annotations[row].className; - - dom.setStyle(annotationNode.style, "height", lineHeight); - dom.setStyle(annotationNode.style, "display", "block"); - } - else { - dom.setStyle(annotationNode.style, "display", "none"); - } - } - else { - className = "ace_gutter-cell "; - dom.setStyle(annotationNode.style, "display", "none"); - } - + var className = this.$useSvgGutterIcons ? "ace_gutter-cell_svg-icons " : "ace_gutter-cell "; + var iconClassName = this.$useSvgGutterIcons ? "ace_icon_svg" : "ace_icon"; + if (this.$highlightGutterLine) { if (row == this.$cursorRow || (fold && row < this.$cursorRow && row >= foldStart && this.$cursorRow <= fold.end.row)) { className += "ace_gutter-active-line "; @@ -324,7 +308,7 @@ class Gutter{ className += breakpoints[row]; if (decorations[row]) className += decorations[row]; - if (this.$annotations[row]) + if (this.$annotations[row] && row !== foldStart) className += this.$annotations[row].className; if (element.className != className) element.className = className; @@ -338,8 +322,29 @@ class Gutter{ if (c) { var className = "ace_fold-widget ace_" + c; - if (c == "start" && row == foldStart && row < fold.end.row) + if (c == "start" && row == foldStart && row < fold.end.row){ className += " ace_closed"; + var foldAnnotationClass; + var annotationInFold = false; + + for (var i = row + 1; i <= fold.end.row; i++){ + if (!this.$annotations[i]) + continue; + + if (this.$annotations[i].className === " ace_error"){ + annotationInFold = true; + foldAnnotationClass = " ace_error_fold"; + break; + } + if (this.$annotations[i].className === " ace_warning"){ + annotationInFold = true; + foldAnnotationClass = " ace_warning_fold"; + continue; + } + } + + element.className += foldAnnotationClass; + } else className += " ace_open"; if (foldWidget.className != className) @@ -352,6 +357,28 @@ class Gutter{ dom.setStyle(foldWidget.style, "display", "none"); } } + + if (annotationInFold && this.$showFoldedAnnotations){ + annotationNode.className = iconClassName; + annotationNode.className += foldAnnotationClass; + + dom.setStyle(annotationNode.style, "height", lineHeight); + dom.setStyle(annotationNode.style, "display", "block"); + } + else if (this.$annotations[row]){ + annotationNode.className = iconClassName; + + if (this.$useSvgGutterIcons) + annotationNode.className += this.$annotations[row].className; + else + element.classList.add(this.$annotations[row].className.replace(" ", "")); + + dom.setStyle(annotationNode.style, "height", lineHeight); + dom.setStyle(annotationNode.style, "display", "block"); + } + else { + dom.setStyle(annotationNode.style, "display", "none"); + } var text = (gutterRenderer ? gutterRenderer.getText(session, row) @@ -372,7 +399,6 @@ class Gutter{ this.$highlightGutterLine = highlightGutterLine; } - setShowLineNumbers(show) { this.$renderer = !show && { getWidth: function() {return 0;}, diff --git a/src/mouse/default_gutter_handler.js b/src/mouse/default_gutter_handler.js index d7c6cdea92f..d8b1324f7a9 100644 --- a/src/mouse/default_gutter_handler.js +++ b/src/mouse/default_gutter_handler.js @@ -34,12 +34,60 @@ function GutterHandler(mouseHandler) { }); - var tooltipTimeout, mouseEvent, tooltipAnnotation; + var tooltipTimeout, mouseEvent, tooltipContent; + + var annotationLabels = { + error: {singular: "error", plural: "errors"}, + warning: {singular: "warning", plural: "warnings"}, + info: {singular: "information message", plural: "information messages"} + }; function showTooltip() { var row = mouseEvent.getDocumentPosition().row; - var annotation = gutter.$annotations[row]; - if (!annotation) + var annotationsInRow = gutter.$annotations[row]; + var annotation; + + if (annotationsInRow) + annotation = {text: Array.from(annotationsInRow.text), type: Array.from(annotationsInRow.type)}; + else + annotation = {text: [], type: []}; + + // If the tooltip is for a row which has a closed fold, check whether there are + // annotations in the folded lines. If so, add a summary to the list of annotations. + var fold = gutter.session.getFoldLine(row); + if (fold && gutter.$showFoldedAnnotations){ + var annotationsInFold = {error: [], warning: [], info: []}; + var mostSevereAnnotationInFoldType; + + for (var i = row + 1; i <= fold.end.row; i++){ + if (!gutter.$annotations[i]) + continue; + + for (var j = 0; j < gutter.$annotations[i].text.length; j++) { + var annotationType = gutter.$annotations[i].type[j]; + annotationsInFold[annotationType].push(gutter.$annotations[i].text[j]); + + if (annotationType === "error"){ + mostSevereAnnotationInFoldType = "error_fold"; + continue; + } + + if (annotationType === "warning"){ + mostSevereAnnotationInFoldType = "warning_fold"; + continue; + } + } + } + + if (mostSevereAnnotationInFoldType === "error_fold" || mostSevereAnnotationInFoldType === "warning_fold"){ + var summaryFoldedAnnotations = `${annotationsToSummaryString(annotationsInFold)} in folded code.`; + + annotation.text.push(summaryFoldedAnnotations); + annotation.type.push(mostSevereAnnotationInFoldType); + } + } + + if (annotation.text.length === 0) return hideTooltip(); var maxRow = editor.session.getLength(); @@ -51,39 +99,16 @@ function GutterHandler(mouseHandler) { } var annotationMessages = {error: [], warning: [], info: []}; - var annotationLabels = { - error: {singular: "error", plural: "errors"}, - warning: {singular: "warning", plural: "warnings"}, - info: {singular: "information message", plural: "information messages"} - }; - var iconClassName = gutter.$useSvgGutterIcons ? "ace_icon_svg" : "ace_icon"; - // Construct the body of the tooltip. + // Construct the contents of the tooltip. for (var i = 0; i < annotation.text.length; i++) { - var line = ` ${annotation.text[i]}`; - annotationMessages[annotation.type[i]].push(line); + var line = ` ${annotation.text[i]}`; + annotationMessages[annotation.type[i].replace("_fold","")].push(line); } - var tooltipBody = "
    "; - tooltipBody += [].concat(annotationMessages.error, annotationMessages.warning, annotationMessages.info).join("
    "); - tooltipBody += '
    '; - - // Construct the header of the tooltip. - var isMoreThanOneAnnotationType = false; - var tooltipHeader = "
    "; - for (var i = 0; i < 3; i++){ - var annotationType = ['error', 'warning', 'info'][i]; - if (annotationMessages[annotationType].length > 0){ - var label = annotationMessages[annotationType].length === 1 ? annotationLabels[annotationType].singular : annotationLabels[annotationType].plural; - tooltipHeader += `${isMoreThanOneAnnotationType ? ', ' : ''}${annotationMessages[annotationType].length} ${label}`; - isMoreThanOneAnnotationType = true; - } - } - tooltipHeader += "
    "; - - tooltipAnnotation = tooltipHeader + tooltipBody; - - tooltip.setHtml(tooltipAnnotation); + tooltipContent = [].concat(annotationMessages.error, annotationMessages.warning, annotationMessages.info).join("
    "); + + tooltip.setHtml(tooltipContent); tooltip.setClassName("ace_gutter-tooltip"); tooltip.$element.setAttribute("aria-live", "polite"); @@ -97,7 +122,7 @@ function GutterHandler(mouseHandler) { if (mouseHandler.$tooltipFollowsMouse) { moveTooltip(mouseEvent); } else { - var gutterElement = mouseEvent.domEvent.target; + var gutterElement = gutter.$lines.cells[row].element.querySelector("[class*=ace_icon]"); var rect = gutterElement.getBoundingClientRect(); var style = tooltip.getElement().style; style.left = rect.right + "px"; @@ -108,14 +133,25 @@ function GutterHandler(mouseHandler) { function hideTooltip() { if (tooltipTimeout) tooltipTimeout = clearTimeout(tooltipTimeout); - if (tooltipAnnotation) { + if (tooltipContent) { tooltip.hide(); - tooltipAnnotation = null; + tooltipContent = null; editor._signal("hideGutterTooltip", tooltip); editor.off("mousewheel", hideTooltip); } } + function annotationsToSummaryString(annotations) { + const summary = []; + const annotationTypes = ['error', 'warning', 'info']; + for (const annotationType of annotationTypes) { + if (!annotations[annotationType].length) continue; + const label = annotations[annotationType].length === 1 ? annotationLabels[annotationType].singular : annotationLabels[annotationType].plural; + summary.push(`${annotations[annotationType].length} ${label}`); + } + return summary.join(", "); + } + function moveTooltip(e) { tooltip.setPosition(e.x, e.y); } @@ -125,7 +161,7 @@ function GutterHandler(mouseHandler) { if (dom.hasCssClass(target, "ace_fold-widget")) return hideTooltip(); - if (tooltipAnnotation && mouseHandler.$tooltipFollowsMouse) + if (tooltipContent && mouseHandler.$tooltipFollowsMouse) moveTooltip(e); mouseEvent = e; @@ -142,7 +178,7 @@ function GutterHandler(mouseHandler) { event.addListener(editor.renderer.$gutter, "mouseout", function(e) { mouseEvent = null; - if (!tooltipAnnotation || tooltipTimeout) + if (!tooltipContent || tooltipTimeout) return; tooltipTimeout = setTimeout(function() { diff --git a/src/mouse/default_gutter_handler_test.js b/src/mouse/default_gutter_handler_test.js index 59e2f823b90..f170b1e25de 100644 --- a/src/mouse/default_gutter_handler_test.js +++ b/src/mouse/default_gutter_handler_test.js @@ -36,7 +36,7 @@ module.exports = { editor = this.editor; next(); }, - + "test: gutter error tooltip" : function() { var editor = this.editor; var value = ""; @@ -51,15 +51,13 @@ module.exports = { assert.ok(/ace_error/.test(annotation.className)); var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {clientX: rect.left, clientY: rect.top})); + annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltipHeader = editor.container.querySelector(".ace_gutter-tooltip_header"); - var tooltipBody = editor.container.querySelector(".ace_gutter-tooltip_body"); - assert.ok(/1 error/.test(tooltipHeader.textContent)); - assert.ok(/error test/.test(tooltipBody.textContent)); + var tooltip = editor.container.querySelector(".ace_tooltip"); + assert.ok(/error test/.test(tooltip.textContent)); }, 100); }, "test: gutter warning tooltip" : function() { @@ -76,15 +74,13 @@ module.exports = { assert.ok(/ace_warning/.test(annotation.className)); var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {clientX: rect.left, clientY: rect.top})); + annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltipHeader = editor.container.querySelector(".ace_gutter-tooltip_header"); - var tooltipBody = editor.container.querySelector(".ace_gutter-tooltip_body"); - assert.ok(/1 warning/.test(tooltipHeader.textContent)); - assert.ok(/warning test/.test(tooltipBody.textContent)); + var tooltip = editor.container.querySelector(".ace_tooltip"); + assert.ok(/warning test/.test(tooltip.textContent)); }, 100); }, "test: gutter info tooltip" : function() { @@ -101,15 +97,13 @@ module.exports = { assert.ok(/ace_info/.test(annotation.className)); var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {clientX: rect.left, clientY: rect.top})); + annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltipHeader = editor.container.querySelector(".ace_gutter-tooltip_header"); - var tooltipBody = editor.container.querySelector(".ace_gutter-tooltip_body"); - assert.ok(/1 information message/.test(tooltipHeader.textContent)); - assert.ok(/info test/.test(tooltipBody.textContent)); + var tooltip = editor.container.querySelector(".ace_tooltip"); + assert.ok(/info test/.test(tooltip.textContent)); }, 100); }, "test: gutter svg icons" : function() { @@ -129,15 +123,108 @@ module.exports = { var annotation = line.children[2]; assert.ok(/ace_icon_svg/.test(annotation.className)); }, - - + "test: error show up in fold" : function() { + var editor = this.editor; + var value = "x {" + "\n".repeat(50) + "}"; + value = value.repeat(50); + editor.session.setMode(new Mode()); + editor.setOption("showFoldedAnnotations", true); + editor.setValue(value, -1); + editor.session.setAnnotations([{row: 1, column: 0, type: "error", text: "error test"}]); + editor.renderer.$loop._flush(); + + // Fold the line containing the annotation. + var lines = editor.renderer.$gutterLayer.$lines; + assert.equal(lines.cells[1].element.textContent, "2"); + var toggler = lines.cells[0].element.children[1]; + var rect = toggler.getBoundingClientRect(); + if (!rect.left) rect.left = 100; // for mockdom + toggler.dispatchEvent(MouseEvent("click", {x: rect.left, y: rect.top})); + editor.renderer.$loop._flush(); + assert.ok(/ace_closed/.test(toggler.className)); + assert.equal(lines.cells[1].element.textContent, "51"); + + // Annotation node should have fold class. + var annotation = lines.cells[0].element.children[2]; + assert.ok(/ace_error_fold/.test(annotation.className)); + + var rect = annotation.getBoundingClientRect(); + annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + + // Wait for the tooltip to appear after its timeout. + setTimeout(function() { + editor.renderer.$loop._flush(); + var tooltip = editor.container.querySelector(".ace_tooltip"); + assert.ok(/error in folded/.test(tooltip.textContent)); + }, 100); + }, + "test: warning show up in fold" : function() { + var editor = this.editor; + var value = "x {" + "\n".repeat(50) + "}"; + value = value.repeat(50); + editor.session.setMode(new Mode()); + editor.setOption("showFoldedAnnotations", true); + editor.setValue(value, -1); + editor.session.setAnnotations([{row: 1, column: 0, type: "warning", text: "warning test"}]); + editor.renderer.$loop._flush(); + + // Fold the line containing the annotation. + var lines = editor.renderer.$gutterLayer.$lines; + assert.equal(lines.cells[1].element.textContent, "2"); + var toggler = lines.cells[0].element.children[1]; + var rect = toggler.getBoundingClientRect(); + if (!rect.left) rect.left = 100; // for mockdom + toggler.dispatchEvent(MouseEvent("click", {x: rect.left, y: rect.top})); + editor.renderer.$loop._flush(); + assert.ok(/ace_closed/.test(toggler.className)); + assert.equal(lines.cells[1].element.textContent, "51"); + + // Annotation node should have fold class. + var annotation = lines.cells[0].element.children[2]; + assert.ok(/ace_warning_fold/.test(annotation.className)); + + var rect = annotation.getBoundingClientRect(); + annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + + // Wait for the tooltip to appear after its timeout. + setTimeout(function() { + editor.renderer.$loop._flush(); + var tooltip = editor.container.querySelector(".ace_tooltip"); + assert.ok(/warning in folded/.test(tooltip.textContent)); + }, 100); + }, + "test: info not show up in fold" : function() { + var editor = this.editor; + var value = "x {" + "\n".repeat(50) + "}"; + value = value.repeat(50); + editor.session.setMode(new Mode()); + editor.setOption("showFoldedAnnotations", true); + editor.setValue(value, -1); + editor.session.setAnnotations([{row: 1, column: 0, type: "info", text: "info test"}]); + editor.renderer.$loop._flush(); + + // Fold the line containing the annotation. + var lines = editor.renderer.$gutterLayer.$lines; + assert.equal(lines.cells[1].element.textContent, "2"); + var toggler = lines.cells[0].element.children[1]; + var rect = toggler.getBoundingClientRect(); + if (!rect.left) rect.left = 100; // for mockdom + toggler.dispatchEvent(MouseEvent("click", {x: rect.left, y: rect.top})); + editor.renderer.$loop._flush(); + assert.ok(/ace_closed/.test(toggler.className)); + assert.equal(lines.cells[1].element.textContent, "51"); + + // Annotation node should NOT have fold class. + var annotation = lines.cells[0].element.children[2]; + assert.notOk(/fold/.test(annotation.className)); + }, + tearDown : function() { this.editor.destroy(); document.body.removeChild(this.editor.container); } }; - if (typeof module !== "undefined" && module === require.main) { require("asyncjs").test.testcase(module.exports).exec(); } diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 18d33bb1415..d86c4000777 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -1908,6 +1908,12 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { }, initialValue: false }, + showFoldedAnnotations: { + set: function(value){ + this.$gutterLayer.$showFoldedAnnotations = value; + }, + initialValue: false + }, fadeFoldWidgets: { set: function(show) { dom.setCssClass(this.$gutter, "ace_fade-fold-widgets", show); From 990745aba36d61409d51a9a2bc8836a450600e18 Mon Sep 17 00:00:00 2001 From: Zakhar Kozlov Date: Fri, 21 Apr 2023 13:49:15 +0200 Subject: [PATCH 0779/1293] release v1.18.0 --- CHANGELOG.md | 8 ++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad227fb03f6..a2abcaebacc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.18.0](https://github.com/ajaxorg/ace/compare/v1.17.0...v1.18.0) (2023-04-21) + + +### Features + +* marker groups ([#5113](https://github.com/ajaxorg/ace/issues/5113)) ([01d4605](https://github.com/ajaxorg/ace/commit/01d4605c0dcf7bcbb4f1a09a243f7ef6d16d7d43)) +* summary of annotations in folded lines ([#5117](https://github.com/ajaxorg/ace/issues/5117)) ([dc63ba9](https://github.com/ajaxorg/ace/commit/dc63ba900d3641284d7d11cbb5ccad7c3039f3a4)) + ## [1.17.0](https://github.com/ajaxorg/ace/compare/v1.16.0...v1.17.0) (2023-04-12) diff --git a/build b/build index 0a07fb082b4..d37df561f01 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 0a07fb082b48d26cd561ad96e1c76941a4d55c39 +Subproject commit d37df561f010a90a740300e593f8536d3435393c diff --git a/package.json b/package.json index 0054cc95b55..4fd6ba66422 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.17.0", + "version": "1.18.0", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index c63d06ab985..9f07f67f41b 100644 --- a/src/config.js +++ b/src/config.js @@ -156,6 +156,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.17.0"; +exports.version = "1.18.0"; From b72956d563961ed4519699693cdcbc731ed55333 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 24 Apr 2023 15:28:38 +0400 Subject: [PATCH 0780/1293] do not create getAccelKey method in event constructor --- src/document.js | 25 +++++++++++-------------- src/mouse/mouse_event.js | 11 ++++------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/document.js b/src/document.js index 171e5f80d6e..10ddbc5ca0d 100644 --- a/src/document.js +++ b/src/document.js @@ -633,22 +633,19 @@ class Document { return index + pos.column; } + /** + * Splits a string of text on any newline (`\n`) or carriage-return (`\r`) characters. + * + * @method $split + * @param {String} text The text to work with + * @returns {String} A String array, with each index containing a piece of the original `text` string. + * + **/ + $split(text) { + return text.split(/\r\n|\r|\n/); + } } -/** - * Splits a string of text on any newline (`\n`) or carriage-return (`\r`) characters. - * - * @method $split - * @param {String} text The text to work with - * @returns {String} A String array, with each index containing a piece of the original `text` string. - * - **/ -// check for IE split bug -Document.prototype.$split = ("aaa".split(/a/).length === 0) ? function (text) { - return text.replace(/\r\n|\r/g, "\n").split("\n"); -} : function (text) { - return text.split(/\r\n|\r|\n/); -}; Document.prototype.$autoNewLine = ""; Document.prototype.$newLineMode = "auto"; diff --git a/src/mouse/mouse_event.js b/src/mouse/mouse_event.js index f7b9f063598..c0f242fa4d2 100644 --- a/src/mouse/mouse_event.js +++ b/src/mouse/mouse_event.js @@ -19,12 +19,6 @@ class MouseEvent { this.propagationStopped = false; this.defaultPrevented = false; - - this.getAccelKey = useragent.isMac ? function () { - return this.domEvent.metaKey; - } : function () { - return this.domEvent.ctrlKey; - }; } stopPropagation() { @@ -93,7 +87,10 @@ class MouseEvent { getShiftKey() { return this.domEvent.shiftKey; } - + + getAccelKey() { + return useragent.isMac ? this.domEvent.metaKey : this.domEvent.ctrlKey; + } } exports.MouseEvent = MouseEvent; From c5ed7092f0151d4aa00c7060ecf0111fc37bfebb Mon Sep 17 00:00:00 2001 From: mkslanc Date: Tue, 25 Apr 2023 13:27:28 +0400 Subject: [PATCH 0781/1293] fix: wrong next state in regex state --- src/mode/_test/text_lucene.txt | 1 + src/mode/_test/tokens_lucene.json | 6 ++++++ src/mode/lucene_highlight_rules.js | 8 ++++---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/mode/_test/text_lucene.txt b/src/mode/_test/text_lucene.txt index 66669423109..4a308edb615 100644 --- a/src/mode/_test/text_lucene.txt +++ b/src/mode/_test/text_lucene.txt @@ -55,3 +55,4 @@ esc\:aped esc\\aped esc\ aped:foo "foo\"bar" +foo:/bar/ diff --git a/src/mode/_test/tokens_lucene.json b/src/mode/_test/tokens_lucene.json index d5d13aa6805..c50d47ff9ce 100644 --- a/src/mode/_test/tokens_lucene.json +++ b/src/mode/_test/tokens_lucene.json @@ -327,6 +327,12 @@ ],[ "start", ["string","\"foo\\\"bar\""] +],[ + "start", + ["keyword","foo:"], + ["string.regexp.start","/"], + ["string.regexp","bar"], + ["string.regexp.end","/"] ],[ "start" ]] \ No newline at end of file diff --git a/src/mode/lucene_highlight_rules.js b/src/mode/lucene_highlight_rules.js index 3b4afddff68..d8197a147d1 100644 --- a/src/mode/lucene_highlight_rules.js +++ b/src/mode/lucene_highlight_rules.js @@ -73,7 +73,7 @@ var LuceneHighlightRules = function() { // flag token: "string.regexp.end", regex: "/[sxngimy]*", - next: "no_regex" + next: "start" }, { // invalid operators token : "invalid", @@ -96,7 +96,7 @@ var LuceneHighlightRules = function() { }, { token: "empty", regex: "$", - next: "no_regex" + next: "start" }, { defaultToken: "string.regexp" } @@ -115,9 +115,9 @@ var LuceneHighlightRules = function() { }, { token: "empty", regex: "$", - next: "no_regex" + next: "start" }, { - defaultToken: "string.regexp.charachterclass" + defaultToken: "string.regexp.characterclass" } ] }; From c49ba525e27b74cb5cf9215ee95e5d31ffeedea4 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 25 Apr 2023 13:45:28 +0400 Subject: [PATCH 0782/1293] add codecov token to avoid upload rate-limiting error --- .github/workflows/nodejs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 02642cc0f8c..c83654e177e 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -54,6 +54,7 @@ jobs: - run: node_modules/.bin/tsc --noImplicitAny --strict --noUnusedLocals --noImplicitReturns --noUnusedParameters --noImplicitThis ace.d.ts - uses: codecov/codecov-action@v3 with: + token: d8edca4b-8e97-41e5-b54e-34c7cf3b2d47 file: ./coverage/coverage.json flags: unittests name: codecov-umbrella From 810e49fe5d94714003750611c990ef37ae55da23 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Tue, 25 Apr 2023 16:11:16 +0400 Subject: [PATCH 0783/1293] update link for ace documentation --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 0a5efe64031..70e5e0984c2 100644 --- a/Readme.md +++ b/Readme.md @@ -99,7 +99,7 @@ Documentation Additional usage information, including events to listen to and extending syntax highlighters, can be found [on the main Ace website](http://ace.c9.io). -You can also find API documentation at [http://ace.c9.io/#nav=api](http://ace.c9.io/#nav=api). +You can also find API documentation at [https://ajaxorg.github.io/ace-api-docs/](https://ajaxorg.github.io/ace-api-docs/). Also check out the sample code for the kitchen sink [demo app](https://github.com/ajaxorg/ace/blob/master/demo/kitchen-sink/demo.js). From e73323d01b10113a102b6c517473597801bd9b4e Mon Sep 17 00:00:00 2001 From: mkslanc Date: Tue, 25 Apr 2023 16:13:34 +0400 Subject: [PATCH 0784/1293] replace property declaration with method signature for `setMarkers` and `getMarkerAtPosition` --- ace.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index 5619e8d9c73..f449c470597 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -284,8 +284,8 @@ export namespace Ace { export class MarkerGroup { constructor(session: EditSession); - setMarkers: (markers: MarkerGroupItem[]) => void; - getMarkerAtPosition: (pos: Position) => MarkerGroupItem; + setMarkers(markers: MarkerGroupItem[]): void; + getMarkerAtPosition(pos: Position): MarkerGroupItem; } From e22bd5c860451c000187941991c0047db4e701a2 Mon Sep 17 00:00:00 2001 From: Ilia Babanov Date: Tue, 25 Apr 2023 12:18:58 +0000 Subject: [PATCH 0785/1293] fix: add mode types, improve type definitions This change adds a new ace-modes.d.ts file (references in the main ace.d.ts), which declares types for everything in the `ace/src/mode` folder. It's been done semi-automatically, and every mode or highlight rules have the same base type, even though technically different modes can have different sub-types (so currently we are omitting some information). Type definitions are excluded in the ace-builds package. Also included small fixes for existing types, like EditSession or Config. --- Makefile.dryice.js | 10 +- ace-modes.d.ts | 1152 ++++++++++++++++++++++++++++++++++++++++++++ ace.d.ts | 80 ++- 3 files changed, 1229 insertions(+), 13 deletions(-) create mode 100644 ace-modes.d.ts diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 90a53451835..4e06d745419 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -171,7 +171,10 @@ function ace() { } function buildTypes() { - var definitions = fs.readFileSync(ACE_HOME + '/ace.d.ts', 'utf8'); + var aceCodeModeDefinitions = '/// '; + // ace-builds package has different structure and can't use mode types defined for the ace-code. + // ace-builds modes are declared along with other modules in the ace-modules.d.ts file below. + var definitions = fs.readFileSync(ACE_HOME + '/ace.d.ts', 'utf8').replace(aceCodeModeDefinitions, ''); var paths = fs.readdirSync(BUILD_DIR + '/src-noconflict'); var moduleRef = '/// '; @@ -193,21 +196,20 @@ function buildTypes() { fs.writeFileSync(BUILD_DIR + '/ace.d.ts', moduleRef + '\n' + definitions); fs.writeFileSync(BUILD_DIR + '/ace-modules.d.ts', pathModules); - var esmUrls = []; + var loader = paths.map(function(path) { if (/\.js$/.test(path) && !/^ace\.js$/.test(path)) { var moduleName = path.split('.')[0].replace(/-/, "/"); if (/^worker/.test(moduleName)) moduleName = "mode" + moduleName.slice(6) + "_worker"; moduleName = moduleName.replace(/keybinding/, "keyboard"); - esmUrls.push("ace.config.setModuleLoader('ace/" + moduleName + "', () => import('./src-noconflict/" + path + "'));"); return "ace.config.setModuleUrl('ace/" + moduleName + "', require('file-loader?esModule=false!./src-noconflict/" + path + "'));"; } }).join('\n'); var esmLoader = esmUrls.join('\n'); - + fs.writeFileSync(BUILD_DIR + '/webpack-resolver.js', loader, "utf8"); fs.writeFileSync(BUILD_DIR + '/esm-resolver.js', esmLoader, "utf8"); } diff --git a/ace-modes.d.ts b/ace-modes.d.ts new file mode 100644 index 00000000000..b0d816c1f6c --- /dev/null +++ b/ace-modes.d.ts @@ -0,0 +1,1152 @@ +declare module "ace-code/src/mode/matching_brace_outdent" { + export const MatchingBraceOutdent: new () => import(".").Ace.Outdent; +} +declare module "ace-code/src/mode/matching_highlight_rules" { + export const MatchingHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/matching_parens_outdent" { + export const MatchingParensOutdent: new () => import(".").Ace.Outdent; +} +declare module "ace-code/src/mode/matching_highlight_rules" { + export const MatchingHighlightRules: new () => import(".").Ace.HighlightRules; +} + + +declare module "ace-code/src/mode/behaviour" { + export const Behaviour: new () => import(".").Ace.Behaviour; +} +declare module "ace-code/src/mode/behaviour/css" { + export const CssBehaviour: new () => import(".").Ace.Behaviour; +} +declare module "ace-code/src/mode/behaviour/cstyle" { + export const CstyleBehaviour: new () => import(".").Ace.Behaviour; +} +declare module "ace-code/src/mode/behaviour/html" { + export const HtmlBehaviour: new () => import(".").Ace.Behaviour; +} +declare module "ace-code/src/mode/behaviour/liquid" { + export const LiquidBehaviour: new () => import(".").Ace.Behaviour; +} +declare module "ace-code/src/mode/behaviour/xml" { + export const XmlBehaviour: new () => import(".").Ace.Behaviour; +} +declare module "ace-code/src/mode/behaviour/xquery" { + export const XQueryBehaviour: new () => import(".").Ace.Behaviour; +} + + +declare module "ace-code/src/mode/folding/fold_mode" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/asciidoc" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/c9search" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/coffee" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/csharp" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/cstyle" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/diff" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/drools" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/haskell_cabal" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/html" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/ini" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/java" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/latex" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/lua" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/markdown" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/mixed" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/pythonic" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/ruby" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/sql" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/sqlserver" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/vbscript" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/velocity" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} +declare module "ace-code/src/mode/folding/xml" { + export const FoldMode: new () => import(".").Ace.FoldMode; +} + + +declare module "ace-code/src/mode/abap" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/abap_highlight_rules" { + export const AbapHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/abc" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/abc_highlight_rules" { + export const ABCHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/actionscript" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/actionscript_highlight_rules" { + export const ActionScriptHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/ada" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/ada_highlight_rules" { + export const AdaHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/alda" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/alda_highlight_rules" { + export const AldaHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/apache_conf" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/apache_conf_highlight_rules" { + export const ApacheConfHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/apex" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/apex_highlight_rules" { + export const ApexHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/aql" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/aql_highlight_rules" { + export const AqlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/asciidoc" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/asciidoc_highlight_rules" { + export const AsciidocHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/asl" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/asl_highlight_rules" { + export const ASLHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/assembly_x86" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/assembly_x86_highlight_rules" { + export const AssemblyX86HighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/autohotkey" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/autohotkey_highlight_rules" { + export const AutoHotKeyHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/batchfile" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/batchfile_highlight_rules" { + export const BatchFileHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/bibtex" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/bibtex_highlight_rules" { + export const BibTeXHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/c_cpp" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/c_cpp_highlight_rules" { + export const c_cppHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/c9search" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/c9search_highlight_rules" { + export const C9SearchHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/cirru" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/cirru_highlight_rules" { + export const CirruHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/clojure" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/clojure_highlight_rules" { + export const ClojureHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/cobol" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/cobol_highlight_rules" { + export const CobolHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/coffee" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/coffee_highlight_rules" { + export const CoffeeHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/coldfusion" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/coldfusion_highlight_rules" { + export const ColdfusionHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/crystal" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/crystal_highlight_rules" { + export const CrystalHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/csharp" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/csharp_highlight_rules" { + export const CSharpHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/csound_document" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/csound_document_highlight_rules" { + export const CsoundDocumentHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/csound_orchestra" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/csound_orchestra_highlight_rules" { + export const CsoundOrchestraHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/csound_score" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/csound_score_highlight_rules" { + export const CsoundScoreHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/css" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/css_highlight_rules" { + export const CssHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/curly" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/curly_highlight_rules" { + export const CurlyHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/d" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/d_highlight_rules" { + export const DHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/dart" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/dart_highlight_rules" { + export const DartHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/diff" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/diff_highlight_rules" { + export const DiffHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/dockerfile" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/dockerfile_highlight_rules" { + export const DockerfileHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/dot" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/dot_highlight_rules" { + export const DotHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/drools" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/drools_highlight_rules" { + export const DroolsHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/edifact" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/edifact_highlight_rules" { + export const EdifactHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/eiffel" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/eiffel_highlight_rules" { + export const EiffelHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/ejs" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/ejs_highlight_rules" { + export const EjsHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/elixir" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/elixir_highlight_rules" { + export const ElixirHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/elm" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/elm_highlight_rules" { + export const ElmHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/erlang" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/erlang_highlight_rules" { + export const ErlangHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/forth" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/forth_highlight_rules" { + export const ForthHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/fortran" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/fortran_highlight_rules" { + export const FortranHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/fsharp" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/fsharp_highlight_rules" { + export const FSharpHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/fsl" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/fsl_highlight_rules" { + export const FSLHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/ftl" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/ftl_highlight_rules" { + export const FtlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/gcode" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/gcode_highlight_rules" { + export const GcodeHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/gherkin" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/gherkin_highlight_rules" { + export const GherkinHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/gitignore" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/gitignore_highlight_rules" { + export const GitignoreHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/glsl" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/glsl_highlight_rules" { + export const glslHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/gobstones" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/gobstones_highlight_rules" { + export const GobstonesHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/golang" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/golang_highlight_rules" { + export const GolangHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/graphqlschema" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/graphqlschema_highlight_rules" { + export const GraphQLSchemaHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/groovy" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/groovy_highlight_rules" { + export const GroovyHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/haml" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/haml_highlight_rules" { + export const HamlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/handlebars" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/handlebars_highlight_rules" { + export const HandlebarsHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/haskell" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/haskell_highlight_rules" { + export const HaskellHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/haskell_cabal" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/haskell_highlight_rules" { + export const HaskellHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/haxe" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/haxe_highlight_rules" { + export const HaxeHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/hjson" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/hjson_highlight_rules" { + export const HjsonHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/html" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/html_highlight_rules" { + export const HtmlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/html_elixir" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/html_elixir_highlight_rules" { + export const HtmlElixirHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/html_ruby" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/html_ruby_highlight_rules" { + export const HtmlRubyHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/ini" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/ini_highlight_rules" { + export const IniHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/io" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/io_highlight_rules" { + export const IoHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/ion" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/ion_highlight_rules" { + export const IonHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/jack" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/jack_highlight_rules" { + export const JackHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/jade" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/jade_highlight_rules" { + export const JadeHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/java" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/java_highlight_rules" { + export const JavaHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/javascript" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/javascript_highlight_rules" { + export const JavaScriptHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/jexl" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/jexl_highlight_rules" { + export const JexlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/json" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/json_highlight_rules" { + export const JsonHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/json5" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/json5_highlight_rules" { + export const Json5HighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/jsp" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/jsp_highlight_rules" { + export const JspHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/jssm" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/jssm_highlight_rules" { + export const JSSMHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/jsx" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/jsx_highlight_rules" { + export const JsxHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/julia" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/julia_highlight_rules" { + export const JuliaHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/kotlin" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/kotlin_highlight_rules" { + export const KotlinHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/latex" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/latex_highlight_rules" { + export const LatexHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/latte" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/latte_highlight_rules" { + export const LatteHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/less" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/less_highlight_rules" { + export const LessHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/liquid" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/liquid_highlight_rules" { + export const LiquidHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/lisp" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/lisp_highlight_rules" { + export const LispHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/livescript" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/logiql" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/logiql_highlight_rules" { + export const LogiQLHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/logtalk" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/logtalk_highlight_rules" { + export const LogtalkHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/lsl" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/lsl_highlight_rules" { + export const LSLHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/lua" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/lua_highlight_rules" { + export const LuaHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/luapage" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/luapage_highlight_rules" { + export const LuaPageHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/lucene" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/lucene_highlight_rules" { + export const LuceneHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/makefile" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/makefile_highlight_rules" { + export const MakefileHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/markdown" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/markdown_highlight_rules" { + export const MarkdownHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/mask" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/mask_highlight_rules" { + export const MaskHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/matlab" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/matlab_highlight_rules" { + export const MatlabHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/maze" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/maze_highlight_rules" { + export const MazeHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/mediawiki" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/mediawiki_highlight_rules" { + export const MediaWikiHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/mel" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/mel_highlight_rules" { + export const MELHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/mips" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/mips_highlight_rules" { + export const MIPSHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/mixal" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/mixal_highlight_rules" { + export const MixalHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/mushcode" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/mushcode_highlight_rules" { + export const MushCodeRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/mysql" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/mysql_highlight_rules" { + export const MysqlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/nginx" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/nginx_highlight_rules" { + export const NginxHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/nim" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/nim_highlight_rules" { + export const NimHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/nix" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/nix_highlight_rules" { + export const NixHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/nsis" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/nsis_highlight_rules" { + export const NSISHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/nunjucks" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/nunjucks_highlight_rules" { + export const NunjucksHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/objectivec" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/objectivec_highlight_rules" { + export const ObjectiveCHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/ocaml" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/ocaml_highlight_rules" { + export const OcamlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/partiql" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/partiql_highlight_rules" { + export const PartiqlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/pascal" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/pascal_highlight_rules" { + export const PascalHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/perl" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/perl_highlight_rules" { + export const PerlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/pgsql" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/pgsql_highlight_rules" { + export const PgsqlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/php" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/php_highlight_rules" { + export const PhpHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/php_laravel_blade" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/php_highlight_rules" { + export const PhpHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/pig" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/pig_highlight_rules" { + export const PigHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/plsql" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/plsql_highlight_rules" { + export const plsqlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/powershell" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/powershell_highlight_rules" { + export const PowershellHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/praat" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/praat_highlight_rules" { + export const PraatHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/prisma" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/prisma_highlight_rules" { + export const PrismaHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/prolog" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/prolog_highlight_rules" { + export const PrologHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/properties" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/properties_highlight_rules" { + export const PropertiesHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/protobuf" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/protobuf_highlight_rules" { + export const ProtobufHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/puppet" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/puppet_highlight_rules" { + export const PuppetHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/python" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/python_highlight_rules" { + export const PythonHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/qml" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/qml_highlight_rules" { + export const QmlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/r" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/r_highlight_rules" { + export const RHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/raku" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/raku_highlight_rules" { + export const RakuHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/razor" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/razor_highlight_rules" { + export const RazorHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/rdoc" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/rdoc_highlight_rules" { + export const RDocHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/red" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/red_highlight_rules" { + export const RedHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/rhtml" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/rhtml_highlight_rules" { + export const RHtmlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/robot" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/robot_highlight_rules" { + export const RobotHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/rst" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/rst_highlight_rules" { + export const RSTHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/ruby" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/ruby_highlight_rules" { + export const RubyHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/rust" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/rust_highlight_rules" { + export const RustHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/sac" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/sac_highlight_rules" { + export const sacHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/sass" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/sass_highlight_rules" { + export const SassHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/scad" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/scad_highlight_rules" { + export const scadHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/scala" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/scala_highlight_rules" { + export const ScalaHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/scheme" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/scheme_highlight_rules" { + export const SchemeHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/scrypt" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/scrypt_highlight_rules" { + export const scryptHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/scss" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/scss_highlight_rules" { + export const ScssHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/sh" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/sh_highlight_rules" { + export const ShHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/sjs" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/sjs_highlight_rules" { + export const SJSHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/slim" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/slim_highlight_rules" { + export const SlimHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/smarty" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/smarty_highlight_rules" { + export const SmartyHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/smithy" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/smithy_highlight_rules" { + export const SmithyHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/snippets" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/soy_template" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/soy_template_highlight_rules" { + export const SoyTemplateHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/space" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/space_highlight_rules" { + export const SpaceHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/sparql" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/sparql_highlight_rules" { + export const SPARQLHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/sql" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/sql_highlight_rules" { + export const SqlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/sqlserver" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/sqlserver_highlight_rules" { + export const SqlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/stylus" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/stylus_highlight_rules" { + export const StylusHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/svg" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/svg_highlight_rules" { + export const SvgHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/swift" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/swift_highlight_rules" { + export const SwiftHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/tcl" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/tcl_highlight_rules" { + export const TclHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/terraform" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/terraform_highlight_rules" { + export const TerraformHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/tex" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/tex_highlight_rules" { + export const TexHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/text" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/text_highlight_rules" { + export const TextHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/textile" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/textile_highlight_rules" { + export const TextileHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/toml" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/toml_highlight_rules" { + export const TomlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/tsx" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/turtle" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/turtle_highlight_rules" { + export const TurtleHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/twig" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/twig_highlight_rules" { + export const TwigHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/typescript" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/typescript_highlight_rules" { + export const TypeScriptHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/vala" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/vala_highlight_rules" { + export const ValaHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/vbscript" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/vbscript_highlight_rules" { + export const VBScriptHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/velocity" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/velocity_highlight_rules" { + export const VelocityHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/verilog" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/verilog_highlight_rules" { + export const VerilogHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/vhdl" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/vhdl_highlight_rules" { + export const VHDLHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/visualforce" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/visualforce_highlight_rules" { + export const VisualforceHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/wollok" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/wollok_highlight_rules" { + export const WollokHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/xml" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/xml_highlight_rules" { + export const XmlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/yaml" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/yaml_highlight_rules" { + export const YamlHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/zeek" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} +declare module "ace-code/src/mode/zeek_highlight_rules" { + export const ZeekHighlightRules: new () => import(".").Ace.HighlightRules; +} +declare module "ace-code/src/mode/django" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} diff --git a/ace.d.ts b/ace.d.ts index 5619e8d9c73..5a56b810a8b 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1,3 +1,5 @@ +/// + export namespace Ace { export type NewLineMode = 'auto' | 'unix' | 'windows'; @@ -364,7 +366,66 @@ export namespace Ace { stepForward(): Token; } + export type HighlightRule = {defaultToken: string} | {include: string} | {todo: string} | { + token: string | string[] | ((value: string) => string); + regex: string | RegExp; + next?: string; + push?: string; + comment?: string; + caseInsensitive?: boolean; + } + + export type HighlightRulesMap = Record; + + export type KeywordMapper = (keyword: string) => string; + + export interface HighlightRules { + $rules: HighlightRulesMap; + $embeds?: string[]; + $keywordList?: string[]; + $keywords?: KeywordMapper; + addRules(rules: HighlightRulesMap, prefix?: string): void; + getRules(): HighlightRulesMap; + embedRules(rules: (new () => HighlightRules) | HighlightRulesMap, prefix: string, escapeRules?: boolean, append?: boolean): void; + getEmbeds(): string[]; + normalizeRules(): void; + createKeywordMapper(map: Record, defaultToken?: string, ignoreCase?: boolean, splitChar?: string): KeywordMapper; + } + + export interface FoldMode { + foldingStartMarker: RegExp; + foldingStopMarker?: RegExp; + getFoldWidget(session: EditSession, foldStyle: string, row: number): string; + getFoldWidgetRange(session: EditSession, foldStyle: string, row: number, forceMultiline?: boolean): Range | undefined; + indentationBlock(session: EditSession, row: number, column?: number): Range | undefined; + openingBracketBlock(session: EditSession, bracket: string, row: number, column: number, typeRe?: RegExp): Range | undefined; + closingBracketBlock(session: EditSession, bracket: string, row: number, column: number, typeRe?: RegExp): Range | undefined; + } + + type BehaviorAction = (state: string, action: string, editor: Editor, session: EditSession, text: string) => {text: string, selection: number[]} | Range | undefined; + type BehaviorMap = Record>; + + export interface Behaviour { + $behaviours: BehaviorMap; + add(name: string, action: string, callback: BehaviorAction): void; + addBehaviours(behaviours: BehaviorMap): void; + remove(name: string): void; + inherit(mode: SyntaxMode | (new () => SyntaxMode), filter: string[]): void; + getBehaviours(filter: string[]): BehaviorMap; + } + + export interface Outdent { + checkOutdent(line: string, input: string): boolean; + autoOutdent(doc: Document, row: number): number | undefined; + $getIndent(line: string): string; + } + export interface SyntaxMode { + HighlightRules: new () => HighlightRules; + foldingRules?: FoldMode; + $behaviour?: Behaviour; + $defaultBehaviour?: Behaviour; + lineCommentStart?: string; getTokenizer(): Tokenizer; toggleCommentLines(state: any, session: EditSession, @@ -377,14 +438,11 @@ export namespace Ace { getNextLineIndent(state: any, line: string, tab: string): string; checkOutdent(state: any, line: string, input: string): boolean; autoOutdent(state: any, doc: Document, row: number): void; + $getIndent(line: string): string; // TODO implement WorkerClient types createWorker(session: EditSession): any; createModeDelegates(mapping: { [key: string]: string }): void; - transformAction(state: string, - action: string, - editor: Editor, - session: EditSession, - text: string): any; + transformAction: BehaviorAction; getKeywords(append?: boolean): Array; getCompletions(state: string, session: EditSession, @@ -392,13 +450,16 @@ export namespace Ace { prefix: string): Completion[]; } + type AfterLoadCallback = (err: Error | null, module: unknown) => void; + type LoaderFunction = (moduleName: string, afterLoad: AfterLoadCallback) => void; + export interface Config { get(key: string): any; set(key: string, value: any): void; all(): { [key: string]: any }; moduleUrl(name: string, component?: string): string; setModuleUrl(name: string, subst: string): string; - setLoader(cb: Function): void; + setLoader(cb: LoaderFunction): void; setModuleLoader(name: string, onLoad: Function): void; loadModule(moduleName: string | [string, string], onLoad?: (module: any) => void): void; @@ -455,11 +516,12 @@ export namespace Ace { on(name: 'tokenizerUpdate', callback: (obj: { data: { first: number, last: number } }) => void): Function; on(name: 'change', callback: () => void): Function; + on(name: 'changeTabSize', callback: () => void): Function; setOption(name: T, value: EditSessionOptions[T]): void; getOption(name: T): EditSessionOptions[T]; - + readonly doc: Document; setDocument(doc: Document): void; @@ -817,7 +879,7 @@ export namespace Ace { setKeyboardHandler(keyboardHandler: string, callback?: () => void): void; setKeyboardHandler(keyboardHandler: KeyboardHandler|null): void; getKeyboardHandler(): string; - setSession(session: EditSession): void; + setSession(session: EditSession | undefined): void; getSession(): EditSession; setValue(val: string, cursorPos?: number): string; getValue(): string; @@ -1032,7 +1094,7 @@ export const VirtualRenderer: { new(container: HTMLElement, theme?: string): Ace.VirtualRenderer; }; export const EditSession: { - new(text: string | Document, mode?: Ace.SyntaxMode): Ace.EditSession; + new(text: string | Ace.Document, mode?: Ace.SyntaxMode): Ace.EditSession; }; export const UndoManager: { new(): Ace.UndoManager; From 1e7b022908cdf6fef0a28419c464874ce6433e6e Mon Sep 17 00:00:00 2001 From: Ilia Babanov Date: Tue, 25 Apr 2023 12:54:01 +0000 Subject: [PATCH 0786/1293] fix: remove or update badly formatted declarations --- ace-modes.d.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/ace-modes.d.ts b/ace-modes.d.ts index b0d816c1f6c..20a0c61c512 100644 --- a/ace-modes.d.ts +++ b/ace-modes.d.ts @@ -1,15 +1,9 @@ declare module "ace-code/src/mode/matching_brace_outdent" { export const MatchingBraceOutdent: new () => import(".").Ace.Outdent; } -declare module "ace-code/src/mode/matching_highlight_rules" { - export const MatchingHighlightRules: new () => import(".").Ace.HighlightRules; -} declare module "ace-code/src/mode/matching_parens_outdent" { export const MatchingParensOutdent: new () => import(".").Ace.Outdent; } -declare module "ace-code/src/mode/matching_highlight_rules" { - export const MatchingHighlightRules: new () => import(".").Ace.HighlightRules; -} declare module "ace-code/src/mode/behaviour" { @@ -445,8 +439,8 @@ declare module "ace-code/src/mode/haskell_highlight_rules" { declare module "ace-code/src/mode/haskell_cabal" { export const Mode: new () => import(".").Ace.SyntaxMode; } -declare module "ace-code/src/mode/haskell_highlight_rules" { - export const HaskellHighlightRules: new () => import(".").Ace.HighlightRules; +declare module "ace-code/src/mode/haskell_cabal_highlight_rules" { + export const CabalHighlightRules: new () => import(".").Ace.HighlightRules; } declare module "ace-code/src/mode/haxe" { export const Mode: new () => import(".").Ace.SyntaxMode; @@ -778,8 +772,8 @@ declare module "ace-code/src/mode/php_highlight_rules" { declare module "ace-code/src/mode/php_laravel_blade" { export const Mode: new () => import(".").Ace.SyntaxMode; } -declare module "ace-code/src/mode/php_highlight_rules" { - export const PhpHighlightRules: new () => import(".").Ace.HighlightRules; +declare module "ace-code/src/mode/php_laravel_blade_highlight_rules" { + export const PHPLaravelBladeHighlightRules: new () => import(".").Ace.HighlightRules; } declare module "ace-code/src/mode/pig" { export const Mode: new () => import(".").Ace.SyntaxMode; From 2db9d4e88441f2932ce6c6f91e7f5ed36c590d2f Mon Sep 17 00:00:00 2001 From: Ilia Babanov Date: Tue, 25 Apr 2023 14:27:57 +0000 Subject: [PATCH 0787/1293] fix: remove '$' fields for types that don't require exposing them --- ace.d.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index 5a56b810a8b..d0b950e4e4c 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -380,10 +380,6 @@ export namespace Ace { export type KeywordMapper = (keyword: string) => string; export interface HighlightRules { - $rules: HighlightRulesMap; - $embeds?: string[]; - $keywordList?: string[]; - $keywords?: KeywordMapper; addRules(rules: HighlightRulesMap, prefix?: string): void; getRules(): HighlightRulesMap; embedRules(rules: (new () => HighlightRules) | HighlightRulesMap, prefix: string, escapeRules?: boolean, append?: boolean): void; @@ -406,7 +402,6 @@ export namespace Ace { type BehaviorMap = Record>; export interface Behaviour { - $behaviours: BehaviorMap; add(name: string, action: string, callback: BehaviorAction): void; addBehaviours(behaviours: BehaviorMap): void; remove(name: string): void; @@ -417,7 +412,6 @@ export namespace Ace { export interface Outdent { checkOutdent(line: string, input: string): boolean; autoOutdent(doc: Document, row: number): number | undefined; - $getIndent(line: string): string; } export interface SyntaxMode { From 2b1c65bceb290db74f26a5c59158f93830bc6111 Mon Sep 17 00:00:00 2001 From: Ilia Babanov Date: Tue, 25 Apr 2023 14:30:50 +0000 Subject: [PATCH 0788/1293] fix: hide `$getindent` from the SyntaxMode Technically derived modes use it a lot, but any new custom mode can use the super.getNextLineindent() instead --- ace.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ace.d.ts b/ace.d.ts index d0b950e4e4c..f06e217510d 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -432,7 +432,6 @@ export namespace Ace { getNextLineIndent(state: any, line: string, tab: string): string; checkOutdent(state: any, line: string, input: string): boolean; autoOutdent(state: any, doc: Document, row: number): void; - $getIndent(line: string): string; // TODO implement WorkerClient types createWorker(session: EditSession): any; createModeDelegates(mapping: { [key: string]: string }): void; From aac99ad953672b931fd8cb275531d8d880e19e80 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Wed, 26 Apr 2023 19:21:18 +0400 Subject: [PATCH 0789/1293] fix wrong next state for sqlserver mode; function to check, if any mode has wrong next state --- src/mode/_test/highlight_rules_test.js | 23 ++++++++++++++++++++++- src/mode/sqlserver_highlight_rules.js | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/mode/_test/highlight_rules_test.js b/src/mode/_test/highlight_rules_test.js index ccb4faf6839..192c6a6f0fa 100644 --- a/src/mode/_test/highlight_rules_test.js +++ b/src/mode/_test/highlight_rules_test.js @@ -45,7 +45,8 @@ function checkModes() { if (!m.$behaviour) console.warn("missing behavior in " + modeName); var tokenizer = m.getTokenizer(); - + + testNextState(tokenizer, modeName); testComments(m.lineCommentStart, testLineComment, tokenizer, modeName); testComments(m.blockComment, testBlockComment, tokenizer, modeName); testBrackets(m, modeName); @@ -65,6 +66,26 @@ function checkModes() { throw new Error("Snippet files missing"); } + function testNextState(tokenizer, modeName) { + let keys = Object.keys(tokenizer.states); + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + let tokens = tokenizer.states[key]; + for (let j = 0; j < tokens.length; j++) { + let token = tokens[j]; + checkState(keys, token, "nextState", modeName); + checkState(keys, token, "next", modeName); + } + } + } + + function checkState(stateNames, token, property, modeName) { + if (token.hasOwnProperty(property) && typeof token[property] === "string" && !stateNames.includes( + token[property])) { + console.warn("non-existent next state '" + token[property] + "' in " + modeName); + } + } + function testComments(desc, fn, tokenizer, modeName) { if (desc) { if (Array.isArray(desc)) { diff --git a/src/mode/sqlserver_highlight_rules.js b/src/mode/sqlserver_highlight_rules.js index 521a3c7a980..ffdb10ea98d 100644 --- a/src/mode/sqlserver_highlight_rules.js +++ b/src/mode/sqlserver_highlight_rules.js @@ -160,7 +160,7 @@ var SqlServerHighlightRules = function() { DocCommentHighlightRules.getTagRule(), { token: "comment", regex: "\\*\\/", - next: "no_regex" + next: "start" }, { defaultToken: "comment", caseInsensitive: true From e1bdcccb4ed3179734aa534b37a9dade2e207f07 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Wed, 26 Apr 2023 21:10:23 +0400 Subject: [PATCH 0790/1293] fix: replaceRange could now be implemented as an instance of the Range interface, rather than being an instance of the Range class --- src/snippets.js | 2 +- src/snippets_test.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/snippets.js b/src/snippets.js index f8d966a3b0e..0c5c35be866 100644 --- a/src/snippets.js +++ b/src/snippets.js @@ -483,7 +483,7 @@ var SnippetManager = function() { var processedSnippet = processSnippetText.call(this, editor, snippetText); var range = editor.getSelectionRange(); - if (replaceRange && replaceRange.compareRange(range) === 0) { + if (replaceRange && range.compareRange(replaceRange) === 0) { range = replaceRange; } var end = editor.session.replace(range, processedSnippet.text); diff --git a/src/snippets_test.js b/src/snippets_test.js index e540c2d7c60..edecbefd2d6 100644 --- a/src/snippets_test.js +++ b/src/snippets_test.js @@ -328,6 +328,14 @@ module.exports = { this.editor.tabstopManager.tabNext(); editor.execCommand("insertstring", "."); assert.equal(editor.getValue(), "qt qt qt."); + }, + "test: should work as expected with object of Range interface": function () { + var content = "test"; + this.editor.setValue("replace1"); + snippetManager.insertSnippet(this.editor, content, { + start: {row: 0, column: 0}, end: {row: 0, column: 7} + }); + assert.equal(this.editor.getValue(), "test1"); } }; From 3a8f9416492c9eb449ecdd66e0f45c7517a74d4d Mon Sep 17 00:00:00 2001 From: mkslanc Date: Sun, 30 Apr 2023 19:43:32 +0400 Subject: [PATCH 0791/1293] make Range object from object with `start` and end` --- src/snippets.js | 5 ++++- src/snippets_test.js | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/snippets.js b/src/snippets.js index 0c5c35be866..fcde92163fe 100644 --- a/src/snippets.js +++ b/src/snippets.js @@ -483,7 +483,7 @@ var SnippetManager = function() { var processedSnippet = processSnippetText.call(this, editor, snippetText); var range = editor.getSelectionRange(); - if (replaceRange && range.compareRange(replaceRange) === 0) { + if (replaceRange && replaceRange.compareRange(range) === 0) { range = replaceRange; } var end = editor.session.replace(range, processedSnippet.text); @@ -495,6 +495,9 @@ var SnippetManager = function() { this.insertSnippet = function(editor, snippetText, replaceRange) { var self = this; + if (replaceRange && !(replaceRange instanceof Range)) + replaceRange = Range.fromPoints(replaceRange.start, replaceRange.end); + if (editor.inVirtualSelectionMode) return self.insertSnippetForSelection(editor, snippetText, replaceRange); diff --git a/src/snippets_test.js b/src/snippets_test.js index edecbefd2d6..02aeb6604d7 100644 --- a/src/snippets_test.js +++ b/src/snippets_test.js @@ -333,9 +333,9 @@ module.exports = { var content = "test"; this.editor.setValue("replace1"); snippetManager.insertSnippet(this.editor, content, { - start: {row: 0, column: 0}, end: {row: 0, column: 7} + start: {row: 0, column: 0}, end: {row: 0, column: 8} }); - assert.equal(this.editor.getValue(), "test1"); + assert.equal(this.editor.getValue(), "test"); } }; From 6b2a3a79db8b102711569c92d67a4d9570d09b45 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Sun, 30 Apr 2023 19:50:26 +0400 Subject: [PATCH 0792/1293] correct description of `compareRange` method --- src/range.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/range.js b/src/range.js index 63eef84e50f..afa70a6c410 100644 --- a/src/range.js +++ b/src/range.js @@ -75,7 +75,7 @@ class Range { * @returns {Number} This method returns one of the following numbers: * * `-2`: (B) is in front of (A), and doesn't intersect with (A) * * `-1`: (B) begins before (A) but ends inside of (A) - * * `0`: (B) is completely inside of (A) OR (A) is completely inside of (B) + * * `0`: (B) is completely inside of (A) * * `+1`: (B) begins inside of (A) but ends outside of (A) * * `+2`: (B) is after (A) and doesn't intersect with (A) * * `42`: FTW state: (B) ends in (A) but starts outside of (A) From fe324f487b8fddef1317c41522ff4c18cd00e463 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 28 Apr 2023 16:18:01 +0400 Subject: [PATCH 0793/1293] fix mockdom issues --- src/test/mockdom.js | 97 +++++++++++++++++++++------------------- src/test/mockdom_test.js | 22 ++++++++- 2 files changed, 73 insertions(+), 46 deletions(-) diff --git a/src/test/mockdom.js b/src/test/mockdom.js index 2c29469b209..aeb4c02eba7 100644 --- a/src/test/mockdom.js +++ b/src/test/mockdom.js @@ -89,6 +89,14 @@ var initializers = { insertRule: function() {}, cssRules: [] }; + }, + a: function() { + this.__defineGetter__("href", function() { + return this.getAttribute("href"); + }); + this.__defineSetter__("href", function(v) { + return this.setAttribute("href", v); + }); } }; @@ -173,31 +181,30 @@ function Node(name) { this.__defineGetter__("childElementCount", function() { return this.childNodes.length; }); + this.hasAttribute = function(x) { + return this.$attributes.hasOwnProperty(x); + }; this.hasAttributes = function() { return Object.keys(this.$attributes).length > 0; }; this.querySelectorAll = function(selector) { + return querySelector(this, selector, true); + }; + this.querySelector = function(selector) { + return querySelector(this, selector, false)[0]; + }; + function querySelector(node, selector, all) { var parts = parseSelector(selector); var nodes = []; - function search(root, parts) { - var operator = parts[0]; - var tests = parts[1]; - var iterator = operator == ">" ? walkShallow : walk; - iterator(root, function(node) { - var isAMatch = tests.every(function(t) {return t(node);}); - if (isAMatch) { - if (parts.length > 3) search(node, parts.slice(2)); - else nodes.push(node); - } - }); - } - search(this, parts); + walk(node, function(node) { + if (node.matches && node.matches(parts)) { + nodes.push(node); + if (!all) return true; + } + }); return nodes; - }; - this.querySelector = function(s) { - return this.querySelectorAll(s)[0]; - }; + } this.getElementsByTagName = function(s) { var nodes = []; walk(this, function(node) { @@ -206,28 +213,24 @@ function Node(name) { }); return nodes; }; - this.getElementById = function(s) { - return walk(this, function(node) { - // console.log(node.getAttribute && node.getAttribute("id")) - if (node.getAttribute && node.getAttribute("id") == s) - return node; - }); - }; this.matches = function(selector) { var parts = parseSelector(selector); var node = this; - var operator, tests, skip; - while (parts.length && node) { - if (!skip) { - tests = parts.pop(); - operator = parts.pop(); - skip = operator != ">"; - } + var operator = parts.pop(); + var tests = parts.pop(); + while (node && node.nodeType != 9) { if (!tests) return true; var isAMatch = tests.every(function(t) {return t(node);}); - if (!isAMatch && !skip) return false; + if (!isAMatch) { + if (!operator || operator === ">") + return false; + } else { + operator = parts.pop(); + tests = parts.pop(); + } node = node.parentNode; } + return !tests; }; this.closest = function(s) { var el = this; @@ -531,6 +534,7 @@ function Node(name) { }).call(Node.prototype); function parseSelector(selector) { + if (Array.isArray(selector)) return selector.slice(); var parts = selector.split(/((?:[^\s>"[]|"[^"]+"?|\[[^\]]*\]?)+)/); for (var i = 1; i < parts.length; i += 2) { parts[i] = parseSimpleSelector(parts[i]); @@ -541,7 +545,7 @@ function parseSelector(selector) { function parseSimpleSelector(selector) { var tests = []; selector.replace( - /([#.])?([\w-]+)|\[\s*([\w-]+)\s*(?:=\s*"?([\w-]+)"?\s*)?\]|\*|./g, + /([#.])?([\w-]+)|\[\s*([\w-]+)\s*(?:=\s*["']?([\w-]+)["']?\s*)?\]|\*|./g, function(_, hash, name, attr, attrValue) { if (hash == "#") { tests.push(function(node) { return node.id == name; }); @@ -554,8 +558,10 @@ function parseSimpleSelector(selector) { tests.push(function(node) { return node.localName == name; }); } else if (attr) { - tests.push(function(node) { - return node.getAttribute(attr) == attrValue; + tests.push(attrValue != undefined ? function(node) { + return node.getAttribute && node.getAttribute(attr) == attrValue; + } : function(node) { + return node.hasAttribute && node.hasAttribute(attr); }); } else if (_ == "*") { @@ -614,7 +620,7 @@ function setInnerHTML(markup, parent, strict) { } else { root = root.appendChild(document.createElement(tagName)); } - attributes && attributes.replace(/([\w:-]+)\s*=\s*(?:"([^"]*)"|'([^"]*)'|(\w+))/g, function(_, key, v1,v2,v3) { + attributes && attributes.replace(/([\w:-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|(\w+))/g, function(_, key, v1,v2,v3) { root.setAttribute(key, v1 || v2 || v3 || key); }); } @@ -708,14 +714,6 @@ function walk(node, fn) { return result; } } -function walkShallow(node, fn) { - var children = node.children || []; - for (var i = 0; i < children.length; i++) { - var result = fn(children[i]); - if (result) - return result; - } -} function TextNode(value) { this.data = value || ""; @@ -745,6 +743,7 @@ window.HTMLDocument = window.XMLDocument = window.Document = function() { var document = this; if (!window.document) window.document = document; Node.call(this, "#document"); + this.nodeType = 9; document.navigator = window.navigator; document.styleSheets = []; document.createElementNS = function(ns, t) { @@ -772,7 +771,15 @@ window.HTMLDocument = window.XMLDocument = window.Document = function() { document.documentElement.appendChild(document.body); return document; }; -window.Document.prototype = Node.prototype; +window.Document.prototype = Object.create(Node.prototype); +(function() { + this.getElementById = function(s) { + return walk(this, function(node) { + if (node.getAttribute && node.getAttribute("id") == s) + return node; + }); + }; +}.call(window.Document.prototype)); window.DOMParser = function() { this.parseFromString = function(str, mode) { diff --git a/src/test/mockdom_test.js b/src/test/mockdom_test.js index b6f03012608..a1c44070046 100644 --- a/src/test/mockdom_test.js +++ b/src/test/mockdom_test.js @@ -10,7 +10,27 @@ if (typeof process !== "undefined") { var assert = require("./assertions"); module.exports = { - "test: getBoundingClientRect" : function() { + "test: selectors": function() { + document.body.innerHTML = `
    + span1 + xxx + some text + +
    `; + var spans = document.querySelectorAll("span"); + assert.equal(spans[0].matches("[z=dd]"), true); + assert.equal(spans[0].matches("[z=dde]"), false); + assert.equal(spans[1].matches("div>[class=x]"), true); + assert.equal(spans[1].matches("body>[class=x]"), false); + assert.equal(spans[0].matches("body [z=dd]"), true); + + assert.equal(document.querySelectorAll("body [x]").length, 2); + assert.equal(document.querySelectorAll("html *> [x]").length, 2); + assert.equal(document.querySelectorAll("html * * [x]").length, 1); + assert.equal(document.querySelectorAll(" * * * * [x]").length, 0); + + }, + "test: getBoundingClientRect" : function() { var span = document.createElement("span"); span.textContent = "x"; From b640e3d310beaf13dd4f0f58d622b62b2f552b02 Mon Sep 17 00:00:00 2001 From: Nanne <184182+whazor@users.noreply.github.com> Date: Tue, 2 May 2023 15:45:11 +0200 Subject: [PATCH 0794/1293] Allow copy pasting from hover tooltips. (#5150) While the hover tooltips are focusable and selectable, keydown closes the tooltip. Now we allow ctrl+cmd key bindings to be pressed and we keep the popup open. --- src/tooltip.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tooltip.js b/src/tooltip.js index ddf2a799aef..34958d771ac 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -325,7 +325,7 @@ class HoverTooltip extends Tooltip { hide(e) { if (!e && document.activeElement == this.getElement()) return; - if (e && e.target && e.type != "keydown" && this.$element.contains(e.target)) + if (e && e.target && (e.type != "keydown" || e.ctrlKey || e.metaKey) && this.$element.contains(e.target)) return; this.lastEvent = null; if (this.timeout) clearTimeout(this.timeout); From 3c4a81d1b9986ca3264f040eaeef2baac98c04b0 Mon Sep 17 00:00:00 2001 From: Oyku Yilmaz Date: Wed, 3 May 2023 09:19:05 +0000 Subject: [PATCH 0795/1293] release v1.18.1 --- CHANGELOG.md | 12 ++++++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2abcaebacc..4bc9c5b7693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.18.1](https://github.com/ajaxorg/ace/compare/v1.18.0...v1.18.1) (2023-05-03) + + +### Bug Fixes + +* add mode types, improve type definitions ([e22bd5c](https://github.com/ajaxorg/ace/commit/e22bd5c860451c000187941991c0047db4e701a2)) +* hide `$getindent` from the SyntaxMode ([2b1c65b](https://github.com/ajaxorg/ace/commit/2b1c65bceb290db74f26a5c59158f93830bc6111)) +* remove '$' fields for types that don't require exposing them ([2db9d4e](https://github.com/ajaxorg/ace/commit/2db9d4e88441f2932ce6c6f91e7f5ed36c590d2f)) +* remove or update badly formatted declarations ([1e7b022](https://github.com/ajaxorg/ace/commit/1e7b022908cdf6fef0a28419c464874ce6433e6e)) +* replaceRange could now be implemented as an instance of the Range interface, rather than being an instance of the Range class ([e1bdccc](https://github.com/ajaxorg/ace/commit/e1bdcccb4ed3179734aa534b37a9dade2e207f07)) +* wrong next state in regex state ([c5ed709](https://github.com/ajaxorg/ace/commit/c5ed7092f0151d4aa00c7060ecf0111fc37bfebb)) + ## [1.18.0](https://github.com/ajaxorg/ace/compare/v1.17.0...v1.18.0) (2023-04-21) diff --git a/build b/build index d37df561f01..e67b0ba7ceb 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit d37df561f010a90a740300e593f8536d3435393c +Subproject commit e67b0ba7cebf8aaee8970dd15da6e3d3ffa1af3c diff --git a/package.json b/package.json index 4fd6ba66422..03b1eab884e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.18.0", + "version": "1.18.1", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 9f07f67f41b..e8477813a40 100644 --- a/src/config.js +++ b/src/config.js @@ -156,6 +156,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.18.0"; +exports.version = "1.18.1"; From 1fa223e4ca0df16c9a0e0a6df2996fa010189666 Mon Sep 17 00:00:00 2001 From: Marin Sokol Date: Wed, 3 May 2023 09:30:07 +0000 Subject: [PATCH 0796/1293] feat: publishing generated styling files to ace-code package --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 03b1eab884e..fbe4e4e3240 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "license": "BSD-3-Clause", "files": [ "src", + "styles", "ace.d.ts", "esm-resolver.js", "!**/*_test.js", @@ -41,7 +42,7 @@ "lint": "eslint \"src/**/*.js\"", "fix": "eslint --fix \"src/**/*.js\"", "changelog": "standard-version", - "prepack": "node tool/esm_resolver_generator.js" + "prepack": "node tool/esm_resolver_generator.js && node Makefile.dryice.js css --target build-styles && mv build-styles/css styles" }, "standard-version": { "skip": { From b6799c1953eaf5661aab392e459a63521f5d6fff Mon Sep 17 00:00:00 2001 From: Marin Sokol Date: Wed, 3 May 2023 09:50:15 +0000 Subject: [PATCH 0797/1293] release v1.19.0 --- CHANGELOG.md | 7 +++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bc9c5b7693..17e99ab6579 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.19.0](https://github.com/ajaxorg/ace/compare/v1.18.1...v1.19.0) (2023-05-03) + + +### Features + +* publishing generated styling files to ace-code package ([1fa223e](https://github.com/ajaxorg/ace/commit/1fa223e4ca0df16c9a0e0a6df2996fa010189666)) + ### [1.18.1](https://github.com/ajaxorg/ace/compare/v1.18.0...v1.18.1) (2023-05-03) diff --git a/build b/build index e67b0ba7ceb..4769dead0e1 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit e67b0ba7cebf8aaee8970dd15da6e3d3ffa1af3c +Subproject commit 4769dead0e1f119a70341f32994055cb60d73922 diff --git a/package.json b/package.json index fbe4e4e3240..c41b8cb8c6d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.18.1", + "version": "1.19.0", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index e8477813a40..29d9e4c3a34 100644 --- a/src/config.js +++ b/src/config.js @@ -156,6 +156,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.18.1"; +exports.version = "1.19.0"; From 5f2face8febe7c260a42bc30c67195f6a5a46085 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Fri, 5 May 2023 15:41:13 +0200 Subject: [PATCH 0798/1293] feat: Add gutter controls to keyboard accessibility mode (#5146) Adds operating the fold controls and annotations in the gutter to the keyboard accessibility mode. When tabbing through the page, you can focus on the gutter div. When pressing enter, you enter the gutter and can use the arrow keys to navigate through the controls in the gutter. Press enter to interact with the controls. Press escape to set focus back to the gutter div and be able to TAB through the page again. --- .eslintrc | 1 + src/css/editor.css.js | 6 +- src/edit_session/folding.js | 5 +- src/editor.js | 47 ++- src/keyboard/gutter_handler.js | 426 +++++++++++++++++++++++ src/keyboard/gutter_handler_test.js | 270 ++++++++++++++ src/keyboard/textinput.js | 17 +- src/layer/gutter.js | 61 +++- src/layer/text.js | 4 +- src/mouse/default_gutter_handler.js | 189 +++++----- src/mouse/default_gutter_handler_test.js | 6 +- src/test/all_browser.js | 1 + 12 files changed, 914 insertions(+), 119 deletions(-) create mode 100644 src/keyboard/gutter_handler.js create mode 100644 src/keyboard/gutter_handler_test.js diff --git a/.eslintrc b/.eslintrc index d785fa3d830..d02dfb1dd72 100644 --- a/.eslintrc +++ b/.eslintrc @@ -29,6 +29,7 @@ prompt: true, XMLHttpRequest: true, localStorage: true, + KeyboardEvent: true, }, "rules": { curly: 0, diff --git a/src/css/editor.css.js b/src/css/editor.css.js index d44ff16e049..0dd118867ca 100644 --- a/src/css/editor.css.js +++ b/src/css/editor.css.js @@ -120,13 +120,13 @@ module.exports = ` background-repeat: no-repeat; } -.ace_gutter-cell_svg-icons .ace_icon_svg { +.ace_gutter-cell_svg-icons .ace_gutter_annotation { margin-left: -14px; float: left; } -.ace_gutter-cell .ace_icon { - margin-left: -18px; +.ace_gutter-cell .ace_gutter_annotation { + margin-left: -19px; float: left; } diff --git a/src/edit_session/folding.js b/src/edit_session/folding.js index 6d4d74aee13..308eb298614 100644 --- a/src/edit_session/folding.js +++ b/src/edit_session/folding.js @@ -4,6 +4,7 @@ var Range = require("../range").Range; var FoldLine = require("./fold_line").FoldLine; var Fold = require("./fold").Fold; var TokenIterator = require("../token_iterator").TokenIterator; +var MouseEvent = require("../mouse/mouse_event").MouseEvent; function Folding() { /* @@ -755,7 +756,9 @@ function Folding() { }; this.onFoldWidgetClick = function(row, e) { - e = e.domEvent; + if (e instanceof MouseEvent) + e = e.domEvent; + var options = { children: e.shiftKey, all: e.ctrlKey || e.metaKey, diff --git a/src/editor.js b/src/editor.js index 80f89a3870d..0406d86dc41 100644 --- a/src/editor.js +++ b/src/editor.js @@ -17,6 +17,7 @@ var defaultCommands = require("./commands/default_commands").commands; var config = require("./config"); var TokenIterator = require("./token_iterator").TokenIterator; var LineWidgets = require("./line_widgets").LineWidgets; +var GutterKeyboardHandler = require("./keyboard/gutter_handler").GutterKeyboardHandler; var clipboard = require("./clipboard"); var keys = require('./lib/keys'); @@ -2874,34 +2875,68 @@ config.defineOptions(Editor.prototype, "editor", { var focusOnEnterKeyup = function (e) { if (e.target == this.renderer.content && e.keyCode === keys['enter']){ - e.stopPropagation(); e.preventDefault(); + var row = this.getCursorPosition().row; + + if (!this.isRowVisible(row)) + this.scrollToLine(row, true, true); + this.focus(); } }; - var keyboardFocusClassName = "ace_keyboard-focus"; + var gutterKeyboardHandler; // Prevent focus to be captured when tabbing through the page. When focus is set to the content div, // press Enter key to give focus to Ace and press Esc to again allow to tab through the page. if (value){ + this.keyboardFocusClassName = "ace_keyboard-focus"; + this.textInput.getElement().setAttribute("tabindex", -1); this.renderer.content.setAttribute("tabindex", 0); - this.renderer.content.classList.add(keyboardFocusClassName); + this.renderer.content.setAttribute("role", "group"); + this.renderer.content.setAttribute("aria-roledescription", "editor"); + this.renderer.content.classList.add(this.keyboardFocusClassName); this.renderer.content.setAttribute("aria-label", - "Editor, press Enter key to start editing, press Escape key to exit" + "Editor content, press Enter to start editing, press Escape to exit" ); this.renderer.content.addEventListener("keyup", focusOnEnterKeyup.bind(this)); this.commands.addCommand(blurCommand); + + this.renderer.$gutter.setAttribute("tabindex", 0); + this.renderer.$gutter.setAttribute("aria-hidden", false); + this.renderer.$gutter.setAttribute("role", "group"); + this.renderer.$gutter.setAttribute("aria-roledescription", "editor"); + this.renderer.$gutter.setAttribute("aria-label", + "Editor gutter, press Enter to interact with controls using arrow keys, press Escape to exit" + ); + this.renderer.$gutter.classList.add(this.keyboardFocusClassName); + + if (!gutterKeyboardHandler) + gutterKeyboardHandler = new GutterKeyboardHandler(this); + + gutterKeyboardHandler.addListener(); } else { this.textInput.getElement().setAttribute("tabindex", 0); this.renderer.content.setAttribute("tabindex", -1); - this.renderer.content.classList.remove(keyboardFocusClassName); - this.renderer.content.setAttribute("aria-label", ""); + this.renderer.content.removeAttribute("role"); + this.renderer.content.removeAttribute("aria-roledescription"); + this.renderer.content.classList.remove(this.keyboardFocusClassName); + this.renderer.content.removeAttribute("aria-label"); this.renderer.content.removeEventListener("keyup", focusOnEnterKeyup.bind(this)); this.commands.removeCommand(blurCommand); + + this.renderer.$gutter.setAttribute("tabindex", -1); + this.renderer.$gutter.setAttribute("aria-hidden", true); + this.renderer.$gutter.removeAttribute("role"); + this.renderer.$gutter.removeAttribute("aria-roledescription"); + this.renderer.$gutter.removeAttribute("aria-label"); + this.renderer.$gutter.classList.remove(this.keyboardFocusClassName); + + if (gutterKeyboardHandler) + gutterKeyboardHandler.removeListener(); } }, initialValue: false diff --git a/src/keyboard/gutter_handler.js b/src/keyboard/gutter_handler.js new file mode 100644 index 00000000000..d0c48acaa17 --- /dev/null +++ b/src/keyboard/gutter_handler.js @@ -0,0 +1,426 @@ +"use strict"; + +var keys = require('../lib/keys'); +var GutterTooltip = require("../mouse/default_gutter_handler").GutterTooltip; + +class GutterKeyboardHandler { + constructor(editor) { + this.editor = editor; + this.gutterLayer = editor.renderer.$gutterLayer; + this.element = editor.renderer.$gutter; + this.lines = editor.renderer.$gutterLayer.$lines; + + this.activeRowIndex = null; + this.activeLane = null; + + this.annotationTooltip = new GutterTooltip(this.editor); + } + + addListener() { + this.element.addEventListener("keydown", this.$onGutterKeyDown.bind(this)); + this.element.addEventListener("focusout", this.$blurGutter.bind(this)); + this.editor.on("mousewheel", this.$blurGutter.bind(this)); + } + + removeListener() { + this.element.removeEventListener("keydown", this.$onGutterKeyDown.bind(this)); + this.element.removeEventListener("focusout", this.$blurGutter.bind(this)); + this.editor.off("mousewheel", this.$blurGutter.bind(this)); + } + + $onGutterKeyDown(e) { + // if the tooltip is open, we only want to respond to commands to close it (like a modal) + if (this.annotationTooltip.isOpen) { + e.preventDefault(); + + if (e.keyCode === keys["escape"]) + this.annotationTooltip.hide(); + + return; + } + + // If focus is on the gutter element, set focus to nearest gutter icon on enter press. + if (e.target === this.element) { + if (e.keyCode != keys["enter"]) {return;} + e.preventDefault(); + + // Scroll if the cursor is not currently within the viewport. + var row = this.editor.getCursorPosition().row; + if (!this.editor.isRowVisible(row)) + this.editor.scrollToLine(row, true, true); + + // After scrolling is completed, find the nearest gutter icon and set focus to it. + setTimeout(function() { + var index = this.$rowToRowIndex(this.gutterLayer.$cursorCell.row); + var nearestFoldIndex = this.$findNearestFoldWidget(index); + var nearestAnnotationIndex = this.$findNearestAnnotation(index); + + if (nearestFoldIndex === null && nearestAnnotationIndex === null) + return; + + if (nearestFoldIndex === null && nearestAnnotationIndex !== null){ + this.activeRowIndex = nearestAnnotationIndex; + this.activeLane = "annotation"; + this.$focusAnnotation(this.activeRowIndex); + return; + } + + if (nearestFoldIndex !== null && nearestAnnotationIndex === null){ + this.activeRowIndex = nearestFoldIndex; + this.activeLane = "fold"; + this.$focusFoldWidget(this.activeRowIndex); + return; + } + + if (Math.abs(nearestAnnotationIndex - index) < Math.abs(nearestFoldIndex - index)){ + this.activeRowIndex = nearestAnnotationIndex; + this.activeLane = "annotation"; + this.$focusAnnotation(this.activeRowIndex); + return; + } else { + this.activeRowIndex = nearestFoldIndex; + this.activeLane = "fold"; + this.$focusFoldWidget(this.activeRowIndex); + return; + } + }.bind(this), 10); + return; + } + + // After here, foucs is on a gutter icon and we want to interact with them. + // Prevent tabbing when interacting with the gutter icons. + if (e.keyCode === keys["tab"]){ + e.preventDefault(); + return; + } + + // If focus is on a gutter icon, set focus to gutter on escape press. + if (e.keyCode === keys["escape"]) { + e.preventDefault(); + this.$blurGutter(); + this.element.focus(); + this.lane = null; + return; + } + + if (e.keyCode === keys["up"]) { + e.preventDefault(); + + switch (this.activeLane){ + case "fold": + this.$moveFoldWidgetUp(); + break; + + case "annotation": + this.$moveAnnotationUp(); + break; + } + return; + } + + if (e.keyCode === keys["down"]) { + e.preventDefault(); + + switch (this.activeLane){ + case "fold": + this.$moveFoldWidgetDown(); + break; + + case "annotation": + this.$moveAnnotationDown(); + break; + } + return; + } + + // Try to switch from fold widgets to annotations. + if (e.keyCode === keys["left"]){ + e.preventDefault(); + this.$switchLane("annotation"); + } + + // Try to switch from annotations to fold widgets. + if (e.keyCode === keys["right"]){ + e.preventDefault(); + this.$switchLane("fold"); + } + + if (e.keyCode === keys["enter"] || e.keyCode === keys["space"]){ + e.preventDefault(); + + switch (this.activeLane) { + case "fold": + if (this.gutterLayer.session.foldWidgets[this.$rowIndexToRow(this.activeRowIndex)] === 'start') { + var rowFoldingWidget = this.$rowIndexToRow(this.activeRowIndex); + this.editor.session.onFoldWidgetClick(this.$rowIndexToRow(this.activeRowIndex), e); + + // After folding, check that the right fold widget is still in focus. + // If not (e.g. folding close to bottom of doc), put right widget in focus. + setTimeout(function() { + if (this.$rowIndexToRow(this.activeRowIndex) !== rowFoldingWidget){ + this.$blurFoldWidget(this.activeRowIndex); + this.activeRowIndex = this.$rowToRowIndex(rowFoldingWidget); + this.$focusFoldWidget(this.activeRowIndex); + } + }.bind(this), 10); + + break; + } else if (this.gutterLayer.session.foldWidgets[this.$rowIndexToRow(this.activeRowIndex)] === 'end') { + /* TO DO: deal with 'end' fold widgets */ + break; + } + return; + + case "annotation": + var gutterElement = this.lines.cells[this.activeRowIndex].element.childNodes[2]; + var rect = gutterElement.getBoundingClientRect(); + var style = this.annotationTooltip.getElement().style; + style.left = rect.right + "px"; + style.top = rect.bottom + "px"; + this.annotationTooltip.showTooltip(this.$rowIndexToRow(this.activeRowIndex)); + break; + } + return; + } + } + + $blurGutter() { + if (this.activeRowIndex !== null){ + switch (this.activeLane){ + case "fold": + this.$blurFoldWidget(this.activeRowIndex); + break; + + case "annotation": + this.$blurAnnotation(this.activeRowIndex); + break; + } + } + + if (this.annotationTooltip.isOpen) + this.annotationTooltip.hide(); + + return; + } + + $isFoldWidgetVisible(index) { + var isRowFullyVisible = this.editor.isRowFullyVisible(this.$rowIndexToRow(index)); + var isIconVisible = this.$getFoldWidget(index).style.display !== "none"; + return isRowFullyVisible && isIconVisible; + } + + $isAnnotationVisible(index) { + var isRowFullyVisible = this.editor.isRowFullyVisible(this.$rowIndexToRow(index)); + var isIconVisible = this.$getAnnotation(index).style.display !== "none"; + return isRowFullyVisible && isIconVisible; + } + + $getFoldWidget(index) { + var cell = this.lines.get(index); + var element = cell.element; + return element.childNodes[1]; + } + + $getAnnotation(index) { + var cell = this.lines.get(index); + var element = cell.element; + return element.childNodes[2]; + } + + // Given an index, find the nearest index with a foldwidget + $findNearestFoldWidget(index) { + // If fold widget exists at index, return index. + if (this.$isFoldWidgetVisible(index)) + return index; + + // else, find the nearest index with fold widget within viewport. + var i = 0; + while (index - i > 0 || index + i < this.lines.getLength() - 1){ + i++; + + if (index - i >= 0 && this.$isFoldWidgetVisible(index - i)) + return index - i; + + if (index + i <= this.lines.getLength() - 1 && this.$isFoldWidgetVisible(index + i)) + return index + i; + } + + // If there are no fold widgets within the viewport, return null. + return null; + } + + // Given an index, find the nearest index with an annotation. + $findNearestAnnotation(index) { + // If annotation exists at index, return index. + if (this.$isAnnotationVisible(index)) + return index; + + // else, find the nearest index with annotation within viewport. + var i = 0; + while (index - i > 0 || index + i < this.lines.getLength() - 1){ + i++; + + if (index - i >= 0 && this.$isAnnotationVisible(index - i)) + return index - i; + + if (index + i <= this.lines.getLength() - 1 && this.$isAnnotationVisible(index + i)) + return index + i; + } + + // If there are no annotations within the viewport, return null. + return null; + } + + $focusFoldWidget(index) { + if (index == null) + return; + + var foldWidget = this.$getFoldWidget(index); + + foldWidget.classList.add(this.editor.keyboardFocusClassName); + foldWidget.focus(); + } + + $focusAnnotation(index) { + if (index == null) + return; + + var annotation = this.$getAnnotation(index); + + annotation.classList.add(this.editor.keyboardFocusClassName); + annotation.setAttribute("role", "button"); + annotation.focus(); + } + + $blurFoldWidget(index) { + var foldWidget = this.$getFoldWidget(index); + + foldWidget.classList.remove(this.editor.keyboardFocusClassName); + foldWidget.blur(); + } + + $blurAnnotation(index) { + var annotation = this.$getAnnotation(index); + + annotation.classList.remove(this.editor.keyboardFocusClassName); + annotation.removeAttribute("role"); + annotation.blur(); + } + + $moveFoldWidgetUp() { + var index = this.activeRowIndex; + + while (index > 0){ + index--; + + if (this.$isFoldWidgetVisible(index)){ + this.$blurFoldWidget(this.activeRowIndex); + this.activeRowIndex = index; + this.$focusFoldWidget(this.activeRowIndex); + return; + } + } + return; + } + + $moveFoldWidgetDown() { + var index = this.activeRowIndex; + + while (index < this.lines.getLength() - 1){ + index++; + + if (this.$isFoldWidgetVisible(index)){ + this.$blurFoldWidget(this.activeRowIndex); + this.activeRowIndex = index; + this.$focusFoldWidget(this.activeRowIndex); + return; + } + } + return; + } + + $moveAnnotationUp() { + var index = this.activeRowIndex; + + while (index > 0){ + index--; + + if (this.$isAnnotationVisible(index)){ + this.$blurAnnotation(this.activeRowIndex); + this.activeRowIndex = index; + this.$focusAnnotation(this.activeRowIndex); + return; + } + } + return; + } + + $moveAnnotationDown() { + var index = this.activeRowIndex; + + while (index < this.lines.getLength() - 1){ + index++; + + if (this.$isAnnotationVisible(index)){ + this.$blurAnnotation(this.activeRowIndex); + this.activeRowIndex = index; + this.$focusAnnotation(this.activeRowIndex); + return; + } + } + return; + } + + $switchLane(desinationLane){ + switch (desinationLane) { + case "annotation": + if (this.activeLane === "annotation") {break;} + var annotationIndex = this.$findNearestAnnotation(this.activeRowIndex); + if (annotationIndex == null) {break;} + + this.activeLane = "annotation"; + + this.$blurFoldWidget(this.activeRowIndex); + this.activeRowIndex = annotationIndex; + this.$focusAnnotation(this.activeRowIndex); + + break; + + case "fold": + if (this.activeLane === "fold") {break;} + var foldWidgetIndex = this.$findNearestFoldWidget(this.activeRowIndex); + if (foldWidgetIndex == null) {break;} + + this.activeLane = "fold"; + + this.$blurAnnotation(this.activeRowIndex); + this.activeRowIndex = foldWidgetIndex; + this.$focusFoldWidget(this.activeRowIndex); + + break; + } + return; + } + + // Convert row index (viewport space) to row (document space). + $rowIndexToRow(index) { + var cell = this.lines.get(index); + if (cell) + return cell.row; + + return null; + } + + // Convert row (document space) to row index (viewport space). + $rowToRowIndex(row) { + for (var i = 0; i < this.lines.getLength(); i++){ + var cell = this.lines.get(i); + if (cell.row == row) + return i; + } + + return null; + } +} + +exports.GutterKeyboardHandler = GutterKeyboardHandler; \ No newline at end of file diff --git a/src/keyboard/gutter_handler_test.js b/src/keyboard/gutter_handler_test.js new file mode 100644 index 00000000000..c0312405e25 --- /dev/null +++ b/src/keyboard/gutter_handler_test.js @@ -0,0 +1,270 @@ +if (typeof process !== "undefined") { + require("amd-loader"); + require("../test/mockdom"); +} + +var keys = require('../lib/keys'); + +"use strict"; + +require("../multi_select"); +require("../theme/textmate"); +var Editor = require("../editor").Editor; +var Mode = require("../mode/java").Mode; +var VirtualRenderer = require("../virtual_renderer").VirtualRenderer; +var assert = require("../test/assertions"); + +function emit(keyCode) { + var data = {bubbles: true, keyCode}; + var event = new KeyboardEvent("keydown", data); + + var el = document.activeElement; + el.dispatchEvent(event); +} + +module.exports = { + setUp : function(done) { + this.editor = new Editor(new VirtualRenderer()); + this.editor.container.style.position = "absolute"; + this.editor.container.style.height = "500px"; + this.editor.container.style.width = "500px"; + this.editor.container.style.left = "50px"; + this.editor.container.style.top = "10px"; + document.body.appendChild(this.editor.container); + done(); + }, + "test: keyboard code folding: basic functionality" : function(done) { + var editor = this.editor; + var value = "x {" + "\n".repeat(50) + "}\n"; + value = value.repeat(50); + editor.session.setMode(new Mode()); + editor.setValue(value, -1); + editor.setOption("enableKeyboardAccessibility", true); + editor.renderer.$loop._flush(); + + var lines = editor.renderer.$gutterLayer.$lines; + var toggler = lines.cells[0].element.children[1]; + + // Set focus to the gutter div. + editor.renderer.$gutter.focus(); + assert.equal(document.activeElement, editor.renderer.$gutter); + + // Focus on the fold widget. + emit(keys["enter"]); + + setTimeout(function() { + assert.equal(document.activeElement, lines.cells[0].element.childNodes[1]); + + // Click the fold widget. + emit(keys["enter"]); + + setTimeout(function() { + // Check that code is folded. + editor.renderer.$loop._flush(); + assert.ok(/ace_closed/.test(toggler.className)); + assert.equal(lines.cells[1].element.textContent, "52"); + + // After escape focus should be back to the gutter. + emit(keys["escape"]); + assert.equal(document.activeElement, editor.renderer.$gutter); + + done(); + }, 20); + }, 20); + }, + "test: keyboard code folding: multiple folds" : function(done) { + var editor = this.editor; + var value = "\n x {" + "\n".repeat(5) + "}\n"; + value = value.repeat(50); + editor.session.setMode(new Mode()); + editor.setValue(value, -1); + editor.setOption("enableKeyboardAccessibility", true); + editor.renderer.$loop._flush(); + + var lines = editor.renderer.$gutterLayer.$lines; + + // Set focus to the gutter div. + editor.renderer.$gutter.focus(); + assert.equal(document.activeElement, editor.renderer.$gutter); + + assert.equal(lines.cells[2].element.textContent, "3"); + + // Focus on the fold widgets. + emit(keys["enter"]); + + setTimeout(function() { + assert.equal(document.activeElement, lines.cells[1].element.childNodes[1]); + + // Click the first fold widget. + emit(keys["enter"]); + + setTimeout(function() { + // Check that code is folded. + editor.renderer.$loop._flush(); + assert.equal(lines.cells[2].element.textContent, "8"); + + // Move to the next fold widget. + emit(keys["down"]); + assert.equal(document.activeElement, lines.cells[3].element.childNodes[1]); + assert.equal(lines.cells[4].element.textContent, "10"); + + // Click the fold widget. + emit(keys["enter"]); + + setTimeout(function() { + // Check that code is folded. + assert.equal(lines.cells[4].element.textContent, "15"); + + // Move back up one fold widget. + emit(keys["up"]); + assert.equal(document.activeElement, lines.cells[1].element.childNodes[1]); + + done(); + }, 20); + }, 20); + }, 20); + }, + "test: keyboard annotation: basic functionality" : function(done) { + var editor = this.editor; + var value = "x {" + "\n".repeat(50) + "}\n"; + value = value.repeat(50); + editor.session.setMode(new Mode()); + editor.setOption("enableKeyboardAccessibility", true); + editor.setValue(value, -1); + editor.session.setAnnotations([{row: 0, column: 0, text: "error test", type: "error"}]); + editor.renderer.$loop._flush(); + + var lines = editor.renderer.$gutterLayer.$lines; + + // Set focus to the gutter div. + editor.renderer.$gutter.focus(); + assert.equal(document.activeElement, editor.renderer.$gutter); + + // Focus on the annotation. + emit(keys["enter"]); + + setTimeout(function() { + emit(keys["left"]); + assert.equal(document.activeElement, lines.cells[0].element.childNodes[2]); + + // Click annotation. + emit(keys["enter"]); + + setTimeout(function() { + // Check annotation is rendered. + editor.renderer.$loop._flush(); + var tooltip = editor.container.querySelector(".ace_tooltip"); + assert.ok(/error test/.test(tooltip.textContent)); + + // Press escape to dismiss the tooltip. + emit(keys["escape"]); + + // After escape again focus should be back to the gutter. + emit(keys["escape"]); + assert.equal(document.activeElement, editor.renderer.$gutter); + + done(); + }, 20); + }, 20); + },"test: keyboard annotation: multiple annotations" : function(done) { + var editor = this.editor; + var value = "x {" + "\n".repeat(50) + "}\n"; + value = value.repeat(50); + editor.session.setMode(new Mode()); + editor.setOption("enableKeyboardAccessibility", true); + editor.setValue(value, -1); + editor.session.setAnnotations([ + {row: 1, column: 0, text: "error test", type: "error"}, + {row: 2, column: 0, text: "warning test", type: "warning"} + ]); + editor.renderer.$loop._flush(); + + var lines = editor.renderer.$gutterLayer.$lines; + + // Set focus to the gutter div. + editor.renderer.$gutter.focus(); + assert.equal(document.activeElement, editor.renderer.$gutter); + + // Focus on the annotation. + emit(keys["enter"]); + + setTimeout(function() { + emit(keys["left"]); + assert.equal(document.activeElement, lines.cells[1].element.childNodes[2]); + + // Click annotation. + emit(keys["enter"]); + + setTimeout(function() { + // Check annotation is rendered. + editor.renderer.$loop._flush(); + var tooltip = editor.container.querySelector(".ace_tooltip"); + assert.ok(/error test/.test(tooltip.textContent)); + + // Press escape to dismiss the tooltip. + emit(keys["escape"]); + + // Press down to move to next annotation. + emit(keys["down"]); + assert.equal(document.activeElement, lines.cells[2].element.childNodes[2]); + + // Click annotation. + emit(keys["enter"]); + + setTimeout(function() { + // Check annotation is rendered. + editor.renderer.$loop._flush(); + var tooltip = editor.container.querySelector(".ace_tooltip"); + assert.ok(/warning test/.test(tooltip.textContent)); + + // Press escape to dismiss the tooltip. + emit(keys["escape"]); + + // Move back up one annotation. + emit(keys["up"]); + assert.equal(document.activeElement, lines.cells[1].element.childNodes[2]); + + // Move back to the folds, focus should be on the fold on line 1. + emit(keys["right"]); + assert.equal(document.activeElement, lines.cells[0].element.childNodes[1]); + + done(); + }, 20); + }, 20); + }, 20); + },"test: keyboard annotation: no folds" : function(done) { + var editor = this.editor; + var value = "x\n"; + value = value.repeat(50); + editor.session.setMode(new Mode()); + editor.setOption("enableKeyboardAccessibility", true); + editor.setValue(value, -1); + editor.session.setAnnotations([{row: 1, column: 0, text: "error test", type: "error"}]); + editor.renderer.$loop._flush(); + + var lines = editor.renderer.$gutterLayer.$lines; + + // Set focus to the gutter div. + editor.renderer.$gutter.focus(); + assert.equal(document.activeElement, editor.renderer.$gutter); + + // Focus on gutter interaction. + emit(keys["enter"]); + + setTimeout(function() { + // Focus should be on the annotation directly. + assert.equal(document.activeElement, lines.cells[1].element.childNodes[2]); + done(); + }, 20); + }, + + tearDown : function() { + this.editor.destroy(); + document.body.removeChild(this.editor.container); + } + +}; + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/src/keyboard/textinput.js b/src/keyboard/textinput.js index d8fd222566f..1f06fb344dc 100644 --- a/src/keyboard/textinput.js +++ b/src/keyboard/textinput.js @@ -61,9 +61,21 @@ var TextInput = function(parentNode, host) { } if (options.role) { text.setAttribute("role", options.role); - } + } + }; + this.setAriaLabel = function() { + var row; + if (!host.session) + row = 0; + else + row = host.session.selection.cursor.row; + + text.setAttribute("aria-roledescription", "editor"); + text.setAttribute("aria-label", `Cursor at row ${row + 1}`); }; + this.setAriaOptions({role: "textbox"}); + this.setAriaLabel(); event.addListener(text, "blur", function(e) { if (ignoreFocusEvents) return; @@ -92,6 +104,9 @@ var TextInput = function(parentNode, host) { }, host); this.$focusScroll = false; this.focus = function() { + // On focusing on the textarea, read active row to assistive tech. + this.setAriaLabel(); + if (tempStyle || HAS_FOCUS_ARGS || this.$focusScroll == "browser") return text.focus({ preventScroll: true }); diff --git a/src/layer/gutter.js b/src/layer/gutter.js index 44a153b939d..e45ecad9857 100644 --- a/src/layer/gutter.js +++ b/src/layer/gutter.js @@ -279,6 +279,7 @@ class Gutter{ var textNode = element.childNodes[0]; var foldWidget = element.childNodes[1]; var annotationNode = element.childNodes[2]; + var annotationIconNode = annotationNode.firstChild; var firstLineNumber = session.$firstLineNumber; @@ -293,6 +294,10 @@ class Gutter{ var className = this.$useSvgGutterIcons ? "ace_gutter-cell_svg-icons " : "ace_gutter-cell "; var iconClassName = this.$useSvgGutterIcons ? "ace_icon_svg" : "ace_icon"; + var rowText = (gutterRenderer + ? gutterRenderer.getText(session, row) + : row + firstLineNumber).toString(); + if (this.$highlightGutterLine) { if (row == this.$cursorRow || (fold && row < this.$cursorRow && row >= foldStart && this.$cursorRow <= fold.end.row)) { className += "ace_gutter-active-line "; @@ -352,46 +357,67 @@ class Gutter{ dom.setStyle(foldWidget.style, "height", lineHeight); dom.setStyle(foldWidget.style, "display", "inline-block"); + + // Set a11y properties. + foldWidget.setAttribute("role", "button"); + foldWidget.setAttribute("tabindex", "-1"); + var fold = session.getFoldLine(rowText - 1); + if (fold) { + foldWidget.setAttribute("aria-label", `Unfold rows ${rowText} to ${fold.end.row + 1}`); + foldWidget.setAttribute("title", "Unfold code"); + } + else { + foldWidget.setAttribute("aria-label", `Fold at row ${rowText}`); + foldWidget.setAttribute("title", "Fold code"); + } } else { if (foldWidget) { dom.setStyle(foldWidget.style, "display", "none"); + foldWidget.setAttribute("tabindex", "0"); + foldWidget.removeAttribute("role"); + foldWidget.removeAttribute("aria-label"); } } if (annotationInFold && this.$showFoldedAnnotations){ - annotationNode.className = iconClassName; - annotationNode.className += foldAnnotationClass; + annotationNode.className = "ace_gutter_annotation"; + annotationIconNode.className = iconClassName; + annotationIconNode.className += foldAnnotationClass; - dom.setStyle(annotationNode.style, "height", lineHeight); + dom.setStyle(annotationIconNode.style, "height", lineHeight); dom.setStyle(annotationNode.style, "display", "block"); + dom.setStyle(annotationNode.style, "height", lineHeight); + annotationNode.setAttribute("aria-label", `Read annotations row ${rowText}`); + annotationNode.setAttribute("tabindex", "-1"); } else if (this.$annotations[row]){ - annotationNode.className = iconClassName; + annotationNode.className = "ace_gutter_annotation"; + annotationIconNode.className = iconClassName; if (this.$useSvgGutterIcons) - annotationNode.className += this.$annotations[row].className; + annotationIconNode.className += this.$annotations[row].className; else element.classList.add(this.$annotations[row].className.replace(" ", "")); - dom.setStyle(annotationNode.style, "height", lineHeight); + dom.setStyle(annotationIconNode.style, "height", lineHeight); dom.setStyle(annotationNode.style, "display", "block"); + dom.setStyle(annotationNode.style, "height", lineHeight); + annotationNode.setAttribute("aria-label", `Read annotations row ${rowText}`); + annotationNode.setAttribute("tabindex", "-1"); } else { dom.setStyle(annotationNode.style, "display", "none"); + annotationNode.removeAttribute("aria-label"); + annotationNode.setAttribute("tabindex", "0"); } - - var text = (gutterRenderer - ? gutterRenderer.getText(session, row) - : row + firstLineNumber).toString(); - - if (text !== textNode.data) { - textNode.data = text; - } - + if (rowText !== textNode.data) { + textNode.data = rowText; + } + dom.setStyle(cell.element.style, "height", this.$lines.computeLineHeight(row, config, session) + "px"); dom.setStyle(cell.element.style, "top", this.$lines.computeLineTop(row, config, session) + "px"); - cell.text = text; + cell.text = rowText; return cell; } @@ -464,6 +490,9 @@ function onCreateCell(element) { var annotationNode = dom.createElement("span"); element.appendChild(annotationNode); + + var annotationIconNode = dom.createElement("span"); + annotationNode.appendChild(annotationIconNode); return element; } diff --git a/src/layer/text.js b/src/layer/text.js index 264fc55b29f..9d225c376c4 100644 --- a/src/layer/text.js +++ b/src/layer/text.js @@ -363,8 +363,10 @@ class Text { if (!this.$textToken[token.type]) { var classes = "ace_" + token.type.replace(/\./g, " ace_"); var span = this.dom.createElement("span"); - if (token.type == "fold") + if (token.type == "fold"){ span.style.width = (token.value.length * this.config.characterWidth) + "px"; + span.setAttribute("title", "Unfold code"); + } span.className = classes; span.appendChild(valueFragment); diff --git a/src/mouse/default_gutter_handler.js b/src/mouse/default_gutter_handler.js index d8b1324f7a9..316edbe91de 100644 --- a/src/mouse/default_gutter_handler.js +++ b/src/mouse/default_gutter_handler.js @@ -6,7 +6,7 @@ var Tooltip = require("../tooltip").Tooltip; function GutterHandler(mouseHandler) { var editor = mouseHandler.editor; var gutter = editor.renderer.$gutterLayer; - var tooltip = new GutterTooltip(editor.container); + var tooltip = new GutterTooltip(editor); mouseHandler.editor.setDefaultHandler("guttermousedown", function(e) { if (!editor.isFocused() || e.getButton() != 0) @@ -33,62 +33,10 @@ function GutterHandler(mouseHandler) { return e.preventDefault(); }); - - var tooltipTimeout, mouseEvent, tooltipContent; - - var annotationLabels = { - error: {singular: "error", plural: "errors"}, - warning: {singular: "warning", plural: "warnings"}, - info: {singular: "information message", plural: "information messages"} - }; + var tooltipTimeout, mouseEvent; function showTooltip() { var row = mouseEvent.getDocumentPosition().row; - var annotationsInRow = gutter.$annotations[row]; - var annotation; - - if (annotationsInRow) - annotation = {text: Array.from(annotationsInRow.text), type: Array.from(annotationsInRow.type)}; - else - annotation = {text: [], type: []}; - - // If the tooltip is for a row which has a closed fold, check whether there are - // annotations in the folded lines. If so, add a summary to the list of annotations. - var fold = gutter.session.getFoldLine(row); - if (fold && gutter.$showFoldedAnnotations){ - var annotationsInFold = {error: [], warning: [], info: []}; - var mostSevereAnnotationInFoldType; - - for (var i = row + 1; i <= fold.end.row; i++){ - if (!gutter.$annotations[i]) - continue; - - for (var j = 0; j < gutter.$annotations[i].text.length; j++) { - var annotationType = gutter.$annotations[i].type[j]; - annotationsInFold[annotationType].push(gutter.$annotations[i].text[j]); - - if (annotationType === "error"){ - mostSevereAnnotationInFoldType = "error_fold"; - continue; - } - - if (annotationType === "warning"){ - mostSevereAnnotationInFoldType = "warning_fold"; - continue; - } - } - } - - if (mostSevereAnnotationInFoldType === "error_fold" || mostSevereAnnotationInFoldType === "warning_fold"){ - var summaryFoldedAnnotations = `${annotationsToSummaryString(annotationsInFold)} in folded code.`; - - annotation.text.push(summaryFoldedAnnotations); - annotation.type.push(mostSevereAnnotationInFoldType); - } - } - - if (annotation.text.length === 0) - return hideTooltip(); var maxRow = editor.session.getLength(); if (row == maxRow) { @@ -98,25 +46,8 @@ function GutterHandler(mouseHandler) { return hideTooltip(); } - var annotationMessages = {error: [], warning: [], info: []}; - var iconClassName = gutter.$useSvgGutterIcons ? "ace_icon_svg" : "ace_icon"; + tooltip.showTooltip(row); - // Construct the contents of the tooltip. - for (var i = 0; i < annotation.text.length; i++) { - var line = ` ${annotation.text[i]}`; - annotationMessages[annotation.type[i].replace("_fold","")].push(line); - } - tooltipContent = [].concat(annotationMessages.error, annotationMessages.warning, annotationMessages.info).join("
    "); - - tooltip.setHtml(tooltipContent); - tooltip.setClassName("ace_gutter-tooltip"); - tooltip.$element.setAttribute("aria-live", "polite"); - - if (!tooltip.isOpen) { - tooltip.setTheme(editor.renderer.theme); - } - tooltip.show(); - editor._signal("showGutterTooltip", tooltip); editor.on("mousewheel", hideTooltip); if (mouseHandler.$tooltipFollowsMouse) { @@ -133,25 +64,13 @@ function GutterHandler(mouseHandler) { function hideTooltip() { if (tooltipTimeout) tooltipTimeout = clearTimeout(tooltipTimeout); - if (tooltipContent) { + if (tooltip.isOpen) { tooltip.hide(); - tooltipContent = null; editor._signal("hideGutterTooltip", tooltip); editor.off("mousewheel", hideTooltip); } } - function annotationsToSummaryString(annotations) { - const summary = []; - const annotationTypes = ['error', 'warning', 'info']; - for (const annotationType of annotationTypes) { - if (!annotations[annotationType].length) continue; - const label = annotations[annotationType].length === 1 ? annotationLabels[annotationType].singular : annotationLabels[annotationType].plural; - summary.push(`${annotations[annotationType].length} ${label}`); - } - return summary.join(", "); - } - function moveTooltip(e) { tooltip.setPosition(e.x, e.y); } @@ -161,7 +80,7 @@ function GutterHandler(mouseHandler) { if (dom.hasCssClass(target, "ace_fold-widget")) return hideTooltip(); - if (tooltipContent && mouseHandler.$tooltipFollowsMouse) + if (tooltip.isOpen && mouseHandler.$tooltipFollowsMouse) moveTooltip(e); mouseEvent = e; @@ -178,7 +97,7 @@ function GutterHandler(mouseHandler) { event.addListener(editor.renderer.$gutter, "mouseout", function(e) { mouseEvent = null; - if (!tooltipContent || tooltipTimeout) + if (!tooltip.isOpen || tooltipTimeout) return; tooltipTimeout = setTimeout(function() { @@ -190,7 +109,14 @@ function GutterHandler(mouseHandler) { editor.on("changeSession", hideTooltip); } +exports.GutterHandler = GutterHandler; + class GutterTooltip extends Tooltip { + constructor(editor) { + super(editor.container); + this.editor = editor; + } + setPosition(x, y) { var windowWidth = window.innerWidth || document.documentElement.clientWidth; var windowHeight = window.innerHeight || document.documentElement.clientHeight; @@ -206,7 +132,94 @@ class GutterTooltip extends Tooltip { } Tooltip.prototype.setPosition.call(this, x, y); } + + static get annotationLabels() { return { + error: {singular: "error", plural: "errors"}, + warning: {singular: "warning", plural: "warnings"}, + info: {singular: "information message", plural: "information messages"} + }; + } + + showTooltip(row) { + var gutter = this.editor.renderer.$gutterLayer; + var annotationsInRow = gutter.$annotations[row]; + var annotation; + + if (annotationsInRow) + annotation = {text: Array.from(annotationsInRow.text), type: Array.from(annotationsInRow.type)}; + else + annotation = {text: [], type: []}; + + // If the tooltip is for a row which has a closed fold, check whether there are + // annotations in the folded lines. If so, add a summary to the list of annotations. + var fold = gutter.session.getFoldLine(row); + if (fold && gutter.$showFoldedAnnotations){ + var annotationsInFold = {error: [], warning: [], info: []}; + var mostSevereAnnotationInFoldType; + + for (var i = row + 1; i <= fold.end.row; i++){ + if (!gutter.$annotations[i]) + continue; + + for (var j = 0; j < gutter.$annotations[i].text.length; j++) { + var annotationType = gutter.$annotations[i].type[j]; + annotationsInFold[annotationType].push(gutter.$annotations[i].text[j]); + + if (annotationType === "error"){ + mostSevereAnnotationInFoldType = "error_fold"; + continue; + } + + if (annotationType === "warning"){ + mostSevereAnnotationInFoldType = "warning_fold"; + continue; + } + } + } + + if (mostSevereAnnotationInFoldType === "error_fold" || mostSevereAnnotationInFoldType === "warning_fold"){ + var summaryFoldedAnnotations = `${GutterTooltip.annotationsToSummaryString(annotationsInFold)} in folded code.`; + + annotation.text.push(summaryFoldedAnnotations); + annotation.type.push(mostSevereAnnotationInFoldType); + } + } + + if (annotation.text.length === 0) + return this.hide(); + + var annotationMessages = {error: [], warning: [], info: []}; + var iconClassName = gutter.$useSvgGutterIcons ? "ace_icon_svg" : "ace_icon"; + + // Construct the contents of the tooltip. + for (var i = 0; i < annotation.text.length; i++) { + var line = ` ${annotation.text[i]}`; + annotationMessages[annotation.type[i].replace("_fold","")].push(line); + } + var tooltipContent = [].concat(annotationMessages.error, annotationMessages.warning, annotationMessages.info).join("
    "); + + this.setHtml(tooltipContent); + this.setClassName("ace_gutter-tooltip"); + this.$element.setAttribute("aria-live", "polite"); + + if (!this.isOpen) { + this.setTheme(this.editor.renderer.theme); + } + + this.editor._signal("showGutterTooltip", this); + this.show(); + } + static annotationsToSummaryString(annotations) { + const summary = []; + const annotationTypes = ['error', 'warning', 'info']; + for (const annotationType of annotationTypes) { + if (!annotations[annotationType].length) continue; + const label = annotations[annotationType].length === 1 ? GutterTooltip.annotationLabels[annotationType].singular : GutterTooltip.annotationLabels[annotationType].plural; + summary.push(`${annotations[annotationType].length} ${label}`); + } + return summary.join(", "); + } } -exports.GutterHandler = GutterHandler; +exports.GutterTooltip = GutterTooltip; diff --git a/src/mouse/default_gutter_handler_test.js b/src/mouse/default_gutter_handler_test.js index f170b1e25de..03a23d4989f 100644 --- a/src/mouse/default_gutter_handler_test.js +++ b/src/mouse/default_gutter_handler_test.js @@ -120,7 +120,7 @@ module.exports = { var line = lines.cells[0].element; assert.ok(/ace_gutter-cell_svg-icons/.test(line.className)); - var annotation = line.children[2]; + var annotation = line.children[2].firstChild; assert.ok(/ace_icon_svg/.test(annotation.className)); }, "test: error show up in fold" : function() { @@ -145,7 +145,7 @@ module.exports = { assert.equal(lines.cells[1].element.textContent, "51"); // Annotation node should have fold class. - var annotation = lines.cells[0].element.children[2]; + var annotation = lines.cells[0].element.children[2].firstChild; assert.ok(/ace_error_fold/.test(annotation.className)); var rect = annotation.getBoundingClientRect(); @@ -180,7 +180,7 @@ module.exports = { assert.equal(lines.cells[1].element.textContent, "51"); // Annotation node should have fold class. - var annotation = lines.cells[0].element.children[2]; + var annotation = lines.cells[0].element.children[2].firstChild; assert.ok(/ace_warning_fold/.test(annotation.className)); var rect = annotation.getBoundingClientRect(); diff --git a/src/test/all_browser.js b/src/test/all_browser.js index c6143d6ade2..6108b025644 100644 --- a/src/test/all_browser.js +++ b/src/test/all_browser.js @@ -40,6 +40,7 @@ var testNames = [ "ace/keyboard/vim_test", "ace/keyboard/vim_ace_test", "ace/keyboard/sublime_test", + "ace/keyboard/gutter_handler_test", "ace/layer/text_test", "ace/lib/event_emitter_test", "ace/mode/coffee/parser_test", From 9ccc5ddcc9f7e18b827f86c6adafcf7c21f6025c Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Mon, 8 May 2023 11:32:44 +0200 Subject: [PATCH 0799/1293] change support link to GH discussions --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 70e5e0984c2..e77ff5a70eb 100644 --- a/Readme.md +++ b/Readme.md @@ -103,7 +103,7 @@ You can also find API documentation at [https://ajaxorg.github.io/ace-api-docs/] Also check out the sample code for the kitchen sink [demo app](https://github.com/ajaxorg/ace/blob/master/demo/kitchen-sink/demo.js). -If you still need help, feel free to drop a mail on the [ace mailing list](http://groups.google.com/group/ace-discuss), or at `irc.freenode.net#ace`. +If you still need help, feel free to ask a question on our [discussions page](https://github.com/ajaxorg/ace/discussions). Running Ace ----------- From 3d99f13e8a9f3484b3061d2f5fa5c361add48d38 Mon Sep 17 00:00:00 2001 From: Slava Rozhnev Date: Mon, 8 May 2023 16:29:28 +0300 Subject: [PATCH 0800/1293] MySql INTERSECT & EXCEPT keywords highlight (#5136) INTERSECT & EXCEPT keywords added to mySqlKeywords ------ Co-authored-by: SlavaRozhnev --- src/mode/mysql_highlight_rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mode/mysql_highlight_rules.js b/src/mode/mysql_highlight_rules.js index 2f88e5c2b00..591aa8c79be 100644 --- a/src/mode/mysql_highlight_rules.js +++ b/src/mode/mysql_highlight_rules.js @@ -4,7 +4,7 @@ var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocComme var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var MysqlHighlightRules = function() { - var mySqlKeywords = /*sql*/ "alter|and|as|asc|between|count|create|delete|desc|distinct|drop|from|lateral|having|in|insert|into|is|join|like|not|on|or|order|select|set|table|union|update|values|where" + var mySqlKeywords = /*sql*/ "alter|and|as|asc|between|count|create|delete|desc|distinct|drop|from|lateral|having|in|insert|into|is|join|like|not|on|or|order|select|set|table|union|intersect|except|update|values|where" /*mysql*/ + "|accessible|action|add|after|algorithm|all|analyze|asensitive|at|authors|auto_increment|autocommit|avg|avg_row_length|before|binary|binlog|both|btree|cache|call|cascade|cascaded|case|catalog_name|chain|change|changed|character|check|checkpoint|checksum|class_origin|client_statistics|close|code|collate|collation|collations|column|columns|comment|commit|committed|completion|concurrent|condition|connection|consistent|constraint|contains|continue|contributors|convert|cross|current_date|current_time|current_timestamp|current_user|cursor|data|database|databases|day_hour|day_microsecond|day_minute|day_second|deallocate|dec|declare|default|delay_key_write|delayed|delimiter|des_key_file|describe|deterministic|dev_pop|dev_samp|deviance|directory|disable|discard|distinctrow|div|dual|dumpfile|each|elseif|enable|enclosed|end|ends|engine|engines|enum|errors|escape|escaped|even|event|events|every|execute|exists|exit|explain|extended|fast|fetch|field|fields|first|flush|for|force|foreign|found_rows|full|fulltext|function|general|global|grant|grants|group|by|groupby_concat|handler|hash|help|high_priority|hosts|hour_microsecond|hour_minute|hour_second|if|ignore|ignore_server_ids|import|index|index_statistics|infile|inner|innodb|inout|insensitive|insert_method|install|interval|invoker|isolation|iterate|key|keys|kill|language|last|leading|leave|left|level|limit|linear|lines|list|load|local|localtime|localtimestamp|lock|logs|low_priority|master|master_heartbeat_period|master_ssl_verify_server_cert|masters|match|max|max_rows|maxvalue|message_text|middleint|migrate|min|min_rows|minute_microsecond|minute_second|mod|mode|modifies|modify|mutex|mysql_errno|natural|next|no|no_write_to_binlog|offline|offset|one|online|open|optimize|option|optionally|out|outer|outfile|pack_keys|parser|partition|partitions|password|phase|plugin|plugins|prepare|preserve|prev|primary|privileges|procedure|processlist|profile|profiles|purge|query|quick|range|read|read_write|reads|real|rebuild|recover|references|regexp|relaylog|release|remove|rename|reorganize|repair|repeatable|replace|require|resignal|restrict|resume|return|returns|revoke|right|rlike|rollback|rollup|row|row_format|rtree|savepoint|schedule|schema|schema_name|schemas|second_microsecond|security|sensitive|separator|serializable|server|session|share|show|signal|slave|slow|smallint|snapshot|soname|spatial|specific|sql|sql_big_result|sql_buffer_result|sql_cache|sql_calc_found_rows|sql_no_cache|sql_small_result|sqlexception|sqlstate|sqlwarning|ssl|start|starting|starts|status|std|stddev|stddev_pop|stddev_samp|storage|straight_join|subclass_origin|sum|suspend|table_name|table_statistics|tables|tablespace|temporary|terminated|to|trailing|transaction|trigger|triggers|truncate|uncommitted|undo|uninstall|unique|unlock|upgrade|usage|use|use_frm|user|user_resources|user_statistics|using|utc_date|utc_time|utc_timestamp|value|variables|varying|view|views|warnings|when|while|with|work|write|xa|xor|year_month|zerofill|begin|do|then|else|loop|repeat"; var builtins = "rank|coalesce|ifnull|isnull|nvl"; var variable = "charset|clear|connect|edit|ego|exit|go|help|nopager|notee|nowarning|pager|print|prompt|quit|rehash|source|status|system|tee"; From 948d9a58635e3eb168a5cb06f0f9e36e9778199f Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 28 Apr 2023 01:29:12 +0400 Subject: [PATCH 0801/1293] fix instances of exponential backtracking found by recheck --- demo/kitchen-sink/docs/clojure.clj | 6 ++- src/mode/_test/highlight_rules_test.js | 59 +++++++++----------------- src/mode/_test/tokens_clojure.json | 27 ++++++++++++ src/mode/clojure_highlight_rules.js | 52 ++++++++++++++++++++--- src/mode/ion_highlight_rules.js | 2 +- src/mode/raku_highlight_rules.js | 12 +----- 6 files changed, 99 insertions(+), 59 deletions(-) diff --git a/demo/kitchen-sink/docs/clojure.clj b/demo/kitchen-sink/docs/clojure.clj index 42acfcc7b7c..2f7a1208504 100644 --- a/demo/kitchen-sink/docs/clojure.clj +++ b/demo/kitchen-sink/docs/clojure.clj @@ -16,4 +16,8 @@ (println (parting)) ; -> Goodbye, World (println (parting "Mark")) ; -> Goodbye, Mark (println (parting "Mark" "es")) ; -> Adios, Mark -(println (parting "Mark", "xy")) ; -> java.lang.IllegalArgumentException: unsupported language xy \ No newline at end of file +(println (parting "Mark", "xy")) ; -> java.lang.IllegalArgumentException: unsupported language xy + +(print (re-matches #"abc(.*) + (r)" "abcxyz + r") ) \ No newline at end of file diff --git a/src/mode/_test/highlight_rules_test.js b/src/mode/_test/highlight_rules_test.js index 192c6a6f0fa..9bbab769557 100644 --- a/src/mode/_test/highlight_rules_test.js +++ b/src/mode/_test/highlight_rules_test.js @@ -259,7 +259,8 @@ function testMode(modeName, i) { var Mode = require("../" + modeName).Mode; var tokenizer = new Mode().getTokenizer(); - checkBacktracking(tokenizer); + // TODO this is too slow to run in regular tests + if (RECHECK) checkBacktracking(tokenizer); var state = "start"; data.forEach(function(lineData) { @@ -323,51 +324,29 @@ function padNumber(num, digits) { return (" " + num).slice(-digits); } -function maybeCatastrophicBacktracking(regex) { - var tokens = regexpTokenizer.tokenize(regex.source); - var quantifiedGroups = []; - var groups = []; - var groupIndex = 0; - for (var i = 0; i < tokens.length; i++) { - var token = tokens[i]; - if (token.type == "group.start") { - var endIndex = tokens.indexOf(token.end, i); - var next = tokens[endIndex + 1]; - if (next && next.type == "quantifier" && next.value != "?") { - quantifiedGroups.push(token.end); - } - groups.push(token.end); - } - if (token.type == "group.end") { - if (quantifiedGroups[quantifiedGroups.length - 1] == token) - quantifiedGroups.pop(); - if (groups[groups.length - 1] == token) - groups.pop(); - if (groups.length == 0) - groupIndex++; - } - if (token.type == "quantifier" && quantifiedGroups.length >= 1 && token.value != "?") { - return groupIndex; - } - } - return null; -} function checkBacktracking(tokenizer) { - var regExps = tokenizer.regExps; - Object.keys(regExps || {}).forEach(function(state) { - var i = maybeCatastrophicBacktracking(regExps[state]); - if (i != null) { - i = tokenizer.matchMappings[state][i]; - var rule = tokenizer.states[state][i]; - console.log("\tPossible error in", state, rule && rule.token, i); - } + var states = tokenizer.states; + Object.keys(states || {}).forEach(function(state) { + states[state].forEach(function(rule) { + var regex = rule.regex; + if (regex && typeof regex != "string") regex = regex.source; + if (!regex) return; + var result = require("recheck").checkSync(regex, "gmi", { + checker: "automaton", + timeout: 100000 + }); + if (result.status != "safe") { + if (result.attack && result.attack.string) delete result.attack.string; + + console.log("\tPossible error in", state, rule, result); + } + }); }); } - - // cli var arg = process.argv[2]; +var RECHECK = process.argv.indexOf("--recheck") !== -1; if (!arg) { test(); checkModes(); diff --git a/src/mode/_test/tokens_clojure.json b/src/mode/_test/tokens_clojure.json index 824cba5934f..ab3d2cea0df 100644 --- a/src/mode/_test/tokens_clojure.json +++ b/src/mode/_test/tokens_clojure.json @@ -159,4 +159,31 @@ ["keyword","))"], ["text"," "], ["comment","; -> java.lang.IllegalArgumentException: unsupported language xy"] +],[ + "start" +],[ + "regex", + ["keyword","("], + ["support.function","print"], + ["text"," "], + ["keyword","("], + ["support.function","re-matches"], + ["text"," "], + ["string.regexp","#\"abc"], + ["constant.language.escape","(.*)"] +],[ + "string", + ["string.regexp"," "], + ["constant.language.escape","("], + ["string.regexp","r"], + ["constant.language.escape",")"], + ["string.regexp","\""], + ["text"," "], + ["string","\"abcxyz"] +],[ + "start", + ["string"," r\""], + ["keyword",")"], + ["text"," "], + ["keyword",")"] ]] \ No newline at end of file diff --git a/src/mode/clojure_highlight_rules.js b/src/mode/clojure_highlight_rules.js index 4b0a1f2b83e..6e95a5d29c6 100644 --- a/src/mode/clojure_highlight_rules.js +++ b/src/mode/clojure_highlight_rules.js @@ -107,6 +107,10 @@ var ClojureHighlightRules = function() { }, { token : "keyword", //vectors regex : "[\\[|\\]]" + }, { + token : "string.regexp", //Regular Expressions + regex : '#"', + next: "regex" }, { token : "keyword", //sets and maps regex : "[\\{|\\}|\\#\\{|\\#\\}]" @@ -141,9 +145,6 @@ var ClojureHighlightRules = function() { }, { token : "constant", // symbol regex : /:[^()\[\]{}'"\^%`,;\s]+/ - }, { - token : "string.regexp", //Regular Expressions - regex : '/#"(?:\\.|(?:\\")|[^""\n])*"/g' } ], @@ -151,13 +152,52 @@ var ClojureHighlightRules = function() { { token : "constant.language.escape", regex : "\\\\.|\\\\$" - }, { - token : "string", - regex : '[^"\\\\]+' }, { token : "string", regex : '"', next : "start" + }, { + defaultToken: "string" + } + ], + "regex": [ + { + // escapes + token: "regexp.keyword.operator", + regex: "\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)" + }, { + // flag + token: "string.regexp", + regex: '"', + next: "start" + }, { + // operators + token : "constant.language.escape", + regex: /\(\?[:=!]|\)|\{\d+\b,?\d*\}|[+*]\?|[()$^+*?.]/ + }, { + token : "constant.language.delimiter", + regex: /\|/ + }, { + token: "constant.language.escape", + regex: /\[\^?/, + next: "regex_character_class" + }, { + defaultToken: "string.regexp" + } + ], + "regex_character_class": [ + { + token: "regexp.charclass.keyword.operator", + regex: "\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)" + }, { + token: "constant.language.escape", + regex: "]", + next: "regex" + }, { + token: "constant.language.escape", + regex: "-" + }, { + defaultToken: "string.regexp.charachterclass" } ] }; diff --git a/src/mode/ion_highlight_rules.js b/src/mode/ion_highlight_rules.js index fbcc8ba5543..ed9026805a9 100644 --- a/src/mode/ion_highlight_rules.js +++ b/src/mode/ion_highlight_rules.js @@ -268,7 +268,7 @@ "variable.language.annotation.ion", "punctuation.definition.annotation.ion" ], - "regex": "('(?:[^']|\\\\\\\\|\\\\')*')\\s*(::)" + "regex": /('(?:[^'\\]|\\.)*')\s*(::)/ }, { "token": [ diff --git a/src/mode/raku_highlight_rules.js b/src/mode/raku_highlight_rules.js index 45341ce41ab..138739a7055 100644 --- a/src/mode/raku_highlight_rules.js +++ b/src/mode/raku_highlight_rules.js @@ -173,11 +173,7 @@ var RakuHighlightRules = function() { // Numbers - Hexadecimal var hex = { token : "constant.numeric", regex : "0x[0-9a-fA-F]+\\b" }; // Numbers - Num & Rat - var num_rat = { token : "constant.numeric", regex : "[+-.]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" }; - // Numbers - With _ - var num_with_ = { token : "constant.numeric", regex : "(?:\\d+_?\\d+)+\\b" }; - // Numbers - Complex - var complex_numbers = { token : "constant.numeric", regex : "\\+?\\d+i\\b" }; + var num_rat = { token : "constant.numeric", regex : "[+-.]?\\d[\\d_]*(?:(?:\\.\\d[\\d_]*)?(?:[eE][+-]?\\d[\\d_]*)?)?i?\\b" }; // Booleans var booleans = { token : "constant.language.boolean", regex : "(?:True|False)\\b" }; // Versions @@ -238,8 +234,6 @@ var RakuHighlightRules = function() { }, hex, num_rat, - num_with_, - complex_numbers, booleans, versions, lang_keywords, @@ -283,8 +277,6 @@ var RakuHighlightRules = function() { "qqinterpolation" : [ hex, num_rat, - num_with_, - complex_numbers, booleans, versions, lang_keywords, @@ -338,8 +330,6 @@ var RakuHighlightRules = function() { "qqheredocinterpolation" : [ hex, num_rat, - num_with_, - complex_numbers, booleans, versions, lang_keywords, From 5190ac83de2f5a7a585f52387a5ca4b55c77915f Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 3 May 2023 18:38:39 +0400 Subject: [PATCH 0802/1293] basic i18n support --- Makefile.dryice.js | 49 ++++++++++ demo/i18n.html | 144 ++++++++++++++++++++++++++++ demo/show_own_source.js | 10 +- package.json | 1 + src/autocomplete/popup.js | 3 +- src/config_test.js | 11 +++ src/editor.js | 9 +- src/ext/error_marker.js | 3 +- src/ext/prompt.js | 9 +- src/ext/searchbox.js | 23 ++--- src/keyboard/textinput.js | 5 +- src/layer/gutter.js | 15 +-- src/lib/app_config.js | 16 ++++ src/mouse/default_gutter_handler.js | 7 +- translations/am.json | 33 +++++++ translations/ru.json | 33 +++++++ 16 files changed, 336 insertions(+), 35 deletions(-) create mode 100644 demo/i18n.html create mode 100644 translations/am.json create mode 100644 translations/ru.json diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 4e06d745419..aa9fb3521d6 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -111,6 +111,9 @@ function main(args) { if (type == "css") { return extractCss(); } + if (type == "nls") { + return extractNls(); + } if (args.indexOf("--reuse") === -1) { console.log("updating files in lib/ace"); @@ -145,6 +148,7 @@ function showHelp(type) { console.log(" full all of above"); console.log(" highlighter "); console.log(" css extract css files"); + console.log(" nls extract nls messages"); console.log("args:"); console.log(" --target ./path path to build folder"); console.log("flags:"); @@ -295,6 +299,24 @@ function jsFileList(path, filter) { }).filter(Boolean); } +function searchFiles(dir, fn) { + var files = fs.readdirSync(dir); + files.forEach(function(name) { + var path = dir + "/" + name; + try { + var stat = fs.statSync(path); + } catch (e) { + return; + } + if (stat.isFile() && /\.js$/.test(path)) { + fn(path); + } else if (stat.isDirectory()) { + if (/node_modules|[#\s]/.test(name)) return; + searchFiles(path, fn); + } + }); +} + function workers(path) { return jsFileList(path).map(function(x) { if (x.slice(-7) == "_worker") @@ -627,6 +649,33 @@ function extractCss(callback) { } } +function extractNls() { + var allMessages = {}; + searchFiles(__dirname + "/src", function(path) { + if (/_test/.test(path)) return; + var text = fs.readFileSync(path, "utf8"); + var matches = text.match(/nls\s*\(\s*("([^"\\]|\\.)+"|'([^'\\]|\\.)+')/g); + matches && matches.forEach(function(m) { + var eng = m.replace(/^nls\s*\(\s*["']|["']$/g, ""); + allMessages[eng] = ""; + }); + }); + + fs.readdirSync(__dirname + "/translations").forEach(function(x) { + if (!/\.json$/.test(x)) return; + var path = __dirname + "/translations/" + x; + var existingStr = fs.readFileSync(path, "utf8"); + var existing = JSON.parse(existingStr); + + var newData = {$id: existing.$id}; + for (var i in allMessages) { + newData[i] = existing[i] || ""; + } + fs.writeFileSync(path, JSON.stringify(newData, null, 4), "utf8"); + console.log("Saved " + x); + }); +} + function getLoadedFileList(options, callback, result) { if (!result) { return buildCore({}, {}, function(e, result) { diff --git a/demo/i18n.html b/demo/i18n.html new file mode 100644 index 00000000000..1d5d44e6ef8 --- /dev/null +++ b/demo/i18n.html @@ -0,0 +1,144 @@ + + + + + + ACE Editor StatusBar Demo + + + +Russian   +Armenian  +English  +
    
    +    
    +
    +
    +
    +
    +
    +
    diff --git a/demo/show_own_source.js b/demo/show_own_source.js
    index 23d79c2be51..7537d84a7fd 100644
    --- a/demo/show_own_source.js
    +++ b/demo/show_own_source.js
    @@ -2,7 +2,15 @@ if (typeof ace == "undefined" && typeof require == "undefined") {
         document.body.innerHTML = "

    couldn't find ace.js file,
    " + "to build it run node Makefile.dryice.js full" } else if (typeof ace == "undefined" && typeof require != "undefined") { - require(["ace/ace"], setValue) + require(["ace/ace"], function() { + setValue(); + var config = require("ace/config"); + config.setLoader(function(moduleName, cb) { + require([moduleName], function(module) { + cb(null, module); + }); + }); + }) } else { require = ace.require; setValue() diff --git a/package.json b/package.json index c41b8cb8c6d..f6f96139078 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "styles", "ace.d.ts", "esm-resolver.js", + "translations", "!**/*_test.js", "!_test" ], diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js index 397490c894a..bdca6b606cb 100644 --- a/src/autocomplete/popup.js +++ b/src/autocomplete/popup.js @@ -6,6 +6,7 @@ var Range = require("../range").Range; var event = require("../lib/event"); var lang = require("../lib/lang"); var dom = require("../lib/dom"); +var nls = require("../config").nls; var getAriaId = function(index) { return `suggest-aria-id:${index}`; @@ -49,7 +50,7 @@ class AcePopup { // Set aria attributes for the popup popup.renderer.container.setAttribute("role", "listbox"); - popup.renderer.container.setAttribute("aria-label", "Autocomplete suggestions"); + popup.renderer.container.setAttribute("aria-label", nls("Autocomplete suggestions")); popup.setOption("displayIndentGuides", false); popup.setOption("dragDelay", 150); diff --git a/src/config_test.js b/src/config_test.js index faadab6cce5..34e89f7b0a1 100644 --- a/src/config_test.js +++ b/src/config_test.js @@ -49,6 +49,17 @@ module.exports = { done(); }); }, + "test: nls": function() { + var nls = config.nls; + config.setMessages({ + foo: "hello world of $1" + }); + assert.equal(nls("bar $1"), "bar $1"); + assert.equal(nls("bar"), "bar"); + assert.equal(nls("foo"), "hello world of $1"); + assert.equal(nls("foo", {1: "goo"}), "hello world of goo"); + assert.equal(nls("$0B is $1$$", [0.11, 22]), "0.11B is 22$"); + }, "test: define options" : function() { var o = {}; config.defineOptions(o, "test_object", { diff --git a/src/editor.js b/src/editor.js index 0406d86dc41..bed38846f3c 100644 --- a/src/editor.js +++ b/src/editor.js @@ -18,6 +18,7 @@ var config = require("./config"); var TokenIterator = require("./token_iterator").TokenIterator; var LineWidgets = require("./line_widgets").LineWidgets; var GutterKeyboardHandler = require("./keyboard/gutter_handler").GutterKeyboardHandler; +var nls = require("./config").nls; var clipboard = require("./clipboard"); var keys = require('./lib/keys'); @@ -2895,10 +2896,10 @@ config.defineOptions(Editor.prototype, "editor", { this.textInput.getElement().setAttribute("tabindex", -1); this.renderer.content.setAttribute("tabindex", 0); this.renderer.content.setAttribute("role", "group"); - this.renderer.content.setAttribute("aria-roledescription", "editor"); + this.renderer.content.setAttribute("aria-roledescription", nls("editor")); this.renderer.content.classList.add(this.keyboardFocusClassName); this.renderer.content.setAttribute("aria-label", - "Editor content, press Enter to start editing, press Escape to exit" + nls("Editor content, press Enter to start editing, press Escape to exit") ); this.renderer.content.addEventListener("keyup", focusOnEnterKeyup.bind(this)); @@ -2907,9 +2908,9 @@ config.defineOptions(Editor.prototype, "editor", { this.renderer.$gutter.setAttribute("tabindex", 0); this.renderer.$gutter.setAttribute("aria-hidden", false); this.renderer.$gutter.setAttribute("role", "group"); - this.renderer.$gutter.setAttribute("aria-roledescription", "editor"); + this.renderer.$gutter.setAttribute("aria-roledescription", nls("editor")); this.renderer.$gutter.setAttribute("aria-label", - "Editor gutter, press Enter to interact with controls using arrow keys, press Escape to exit" + nls("Editor gutter, press Enter to interact with controls using arrow keys, press Escape to exit") ); this.renderer.$gutter.classList.add(this.keyboardFocusClassName); diff --git a/src/ext/error_marker.js b/src/ext/error_marker.js index 318e650e969..afdae823878 100644 --- a/src/ext/error_marker.js +++ b/src/ext/error_marker.js @@ -2,6 +2,7 @@ var LineWidgets = require("../line_widgets").LineWidgets; var dom = require("../lib/dom"); var Range = require("../range").Range; +var nls = require("../config").nls; function binarySearch(array, needle, comparator) { var first = 0; @@ -88,7 +89,7 @@ exports.showErrorMarker = function(editor, dir) { return; } else { gutterAnno = { - text: ["Looks good!"], + text: [nls("Looks good!")], className: "ace_ok" }; } diff --git a/src/ext/prompt.js b/src/ext/prompt.js index 57f7aa48b3f..6db2baf3612 100644 --- a/src/ext/prompt.js +++ b/src/ext/prompt.js @@ -22,9 +22,9 @@ "use strict"; +var nls = require("../config").nls; var Range = require("../range").Range; var dom = require("../lib/dom"); -var shortcuts = require("../ext/menu_tools/get_editor_keyboard_shortcuts"); var FilteredList= require("../autocomplete").FilteredList; var AcePopup = require('../autocomplete/popup').AcePopup; var $singleLineEditor = require('../autocomplete/popup').$singleLineEditor; @@ -276,7 +276,6 @@ prompt.gotoLine = function(editor, callback) { editor.renderer.animateScrolling(scrollTop); }, history: function() { - var undoManager = editor.session.getUndoManager(); if (!prompt.gotoLine._history) return []; return prompt.gotoLine._history; @@ -419,13 +418,13 @@ prompt.commands = function(editor, callback) { otherCommands = getFilteredCompletions(otherCommands, prefix); if (recentlyUsedCommands.length && otherCommands.length) { - recentlyUsedCommands[0]["message"] = " Recently used"; - otherCommands[0]["message"] = " Other commands"; + recentlyUsedCommands[0].message = nls("Recently used"); + otherCommands[0].message = nls("Other commands"); } var completions = recentlyUsedCommands.concat(otherCommands); return completions.length > 0 ? completions : [{ - value: "No matching commands", + value: nls("No matching commands"), error: 1 }]; } diff --git a/src/ext/searchbox.js b/src/ext/searchbox.js index 5d034817173..625faa508e9 100644 --- a/src/ext/searchbox.js +++ b/src/ext/searchbox.js @@ -6,6 +6,7 @@ var event = require("../lib/event"); var searchboxCss = require("./searchbox.css"); var HashHandler = require("../keyboard/hash_handler").HashHandler; var keyUtil = require("../lib/keys"); +var nls = require("../config").nls; var MAX_COUNT = 999; @@ -17,24 +18,24 @@ class SearchBox { dom.buildDom(["div", {class:"ace_search right"}, ["span", {action: "hide", class: "ace_searchbtn_close"}], ["div", {class: "ace_search_form"}, - ["input", {class: "ace_search_field", placeholder: "Search for", spellcheck: "false"}], + ["input", {class: "ace_search_field", placeholder: nls("Search for"), spellcheck: "false"}], ["span", {action: "findPrev", class: "ace_searchbtn prev"}, "\u200b"], ["span", {action: "findNext", class: "ace_searchbtn next"}, "\u200b"], - ["span", {action: "findAll", class: "ace_searchbtn", title: "Alt-Enter"}, "All"] + ["span", {action: "findAll", class: "ace_searchbtn", title: "Alt-Enter"}, nls("All")] ], ["div", {class: "ace_replace_form"}, - ["input", {class: "ace_search_field", placeholder: "Replace with", spellcheck: "false"}], - ["span", {action: "replaceAndFindNext", class: "ace_searchbtn"}, "Replace"], - ["span", {action: "replaceAll", class: "ace_searchbtn"}, "All"] + ["input", {class: "ace_search_field", placeholder: nls("Replace with"), spellcheck: "false"}], + ["span", {action: "replaceAndFindNext", class: "ace_searchbtn"}, nls("Replace")], + ["span", {action: "replaceAll", class: "ace_searchbtn"}, nls("All")] ], ["div", {class: "ace_search_options"}, - ["span", {action: "toggleReplace", class: "ace_button", title: "Toggle Replace mode", + ["span", {action: "toggleReplace", class: "ace_button", title: nls("Toggle Replace mode"), style: "float:left;margin-top:-2px;padding:0 5px;"}, "+"], ["span", {class: "ace_search_counter"}], - ["span", {action: "toggleRegexpMode", class: "ace_button", title: "RegExp Search"}, ".*"], - ["span", {action: "toggleCaseSensitive", class: "ace_button", title: "CaseSensitive Search"}, "Aa"], - ["span", {action: "toggleWholeWords", class: "ace_button", title: "Whole Word Search"}, "\\b"], - ["span", {action: "searchInSelection", class: "ace_button", title: "Search In Selection"}, "S"] + ["span", {action: "toggleRegexpMode", class: "ace_button", title: nls("RegExp Search")}, ".*"], + ["span", {action: "toggleCaseSensitive", class: "ace_button", title: nls("CaseSensitive Search")}, "Aa"], + ["span", {action: "toggleWholeWords", class: "ace_button", title: nls("Whole Word Search")}, "\\b"], + ["span", {action: "searchInSelection", class: "ace_button", title: nls("Search In Selection")}, "S"] ] ], div); this.element = div.firstChild; @@ -193,7 +194,7 @@ class SearchBox { } } } - this.searchCounter.textContent = before + " of " + (all > MAX_COUNT ? MAX_COUNT + "+" : all); + this.searchCounter.textContent = nls("$0 of $1", [before , (all > MAX_COUNT ? MAX_COUNT + "+" : all)]); } findNext() { this.find(true, false); diff --git a/src/keyboard/textinput.js b/src/keyboard/textinput.js index 1f06fb344dc..2765eb4ccfe 100644 --- a/src/keyboard/textinput.js +++ b/src/keyboard/textinput.js @@ -1,6 +1,7 @@ "use strict"; var event = require("../lib/event"); +var nls = require("../config").nls; var useragent = require("../lib/useragent"); var dom = require("../lib/dom"); var lang = require("../lib/lang"); @@ -70,8 +71,8 @@ var TextInput = function(parentNode, host) { else row = host.session.selection.cursor.row; - text.setAttribute("aria-roledescription", "editor"); - text.setAttribute("aria-label", `Cursor at row ${row + 1}`); + text.setAttribute("aria-roledescription", nls("editor")); + text.setAttribute("aria-label", nls("Cursor at row $0", [row + 1])); }; this.setAriaOptions({role: "textbox"}); diff --git a/src/layer/gutter.js b/src/layer/gutter.js index e45ecad9857..61e05b5b75e 100644 --- a/src/layer/gutter.js +++ b/src/layer/gutter.js @@ -5,6 +5,7 @@ var oop = require("../lib/oop"); var lang = require("../lib/lang"); var EventEmitter = require("../lib/event_emitter").EventEmitter; var Lines = require("./lines").Lines; +var nls = require("../config").nls; class Gutter{ constructor(parentEl) { @@ -363,13 +364,13 @@ class Gutter{ foldWidget.setAttribute("tabindex", "-1"); var fold = session.getFoldLine(rowText - 1); if (fold) { - foldWidget.setAttribute("aria-label", `Unfold rows ${rowText} to ${fold.end.row + 1}`); - foldWidget.setAttribute("title", "Unfold code"); + foldWidget.setAttribute("aria-label", nls("Unfold rows $0 to $1", [rowText, fold.end.row + 1])); + foldWidget.setAttribute("title", nls("Unfold code")); } else { - foldWidget.setAttribute("aria-label", `Fold at row ${rowText}`); - foldWidget.setAttribute("title", "Fold code"); - } + foldWidget.setAttribute("aria-label", nls("Fold at row $0", [rowText])); + foldWidget.setAttribute("title", nls("Fold code")); + } } else { if (foldWidget) { dom.setStyle(foldWidget.style, "display", "none"); @@ -387,7 +388,7 @@ class Gutter{ dom.setStyle(annotationIconNode.style, "height", lineHeight); dom.setStyle(annotationNode.style, "display", "block"); dom.setStyle(annotationNode.style, "height", lineHeight); - annotationNode.setAttribute("aria-label", `Read annotations row ${rowText}`); + annotationNode.setAttribute("aria-label", nls("Read annotations row $0", [rowText])); annotationNode.setAttribute("tabindex", "-1"); } else if (this.$annotations[row]){ @@ -402,7 +403,7 @@ class Gutter{ dom.setStyle(annotationIconNode.style, "height", lineHeight); dom.setStyle(annotationNode.style, "display", "block"); dom.setStyle(annotationNode.style, "height", lineHeight); - annotationNode.setAttribute("aria-label", `Read annotations row ${rowText}`); + annotationNode.setAttribute("aria-label", nls("Read annotations row $0", [rowText])); annotationNode.setAttribute("tabindex", "-1"); } else { diff --git a/src/lib/app_config.js b/src/lib/app_config.js index 31c82fc1f11..a06a3ceac5d 100644 --- a/src/lib/app_config.js +++ b/src/lib/app_config.js @@ -64,6 +64,8 @@ function reportError(msg, data) { setTimeout(function() { throw e; }); } +var messages; + class AppConfig { constructor() { this.$defaultOptions = {}; @@ -124,6 +126,20 @@ class AppConfig { }, this); } + setMessages(value) { + messages = value; + } + + nls(string, params) { + var translated = messages && messages[string] || string; + if (params) { + translated = translated.replace(/\$(\$|[\d]+)/g, function(_, name) { + if (name == "$") return "$"; + return params[name]; + }); + } + return translated; + } } AppConfig.prototype.warn = warn; AppConfig.prototype.reportError = reportError; diff --git a/src/mouse/default_gutter_handler.js b/src/mouse/default_gutter_handler.js index 316edbe91de..42cbc5efb04 100644 --- a/src/mouse/default_gutter_handler.js +++ b/src/mouse/default_gutter_handler.js @@ -2,6 +2,7 @@ var dom = require("../lib/dom"); var event = require("../lib/event"); var Tooltip = require("../tooltip").Tooltip; +var nls = require("../config").nls; function GutterHandler(mouseHandler) { var editor = mouseHandler.editor; @@ -134,9 +135,9 @@ class GutterTooltip extends Tooltip { } static get annotationLabels() { return { - error: {singular: "error", plural: "errors"}, - warning: {singular: "warning", plural: "warnings"}, - info: {singular: "information message", plural: "information messages"} + error: {singular: nls("error"), plural: nls("errors")}, + warning: {singular: nls("warning"), plural: nls("warnings")}, + info: {singular: nls("information message"), plural: nls("information messages")} }; } diff --git a/translations/am.json b/translations/am.json new file mode 100644 index 00000000000..2cecb0e1868 --- /dev/null +++ b/translations/am.json @@ -0,0 +1,33 @@ +{ + "$id": "am", + "Autocomplete suggestions": "Ավտոմատ լրացման առաջարկներ", + "editor": "", + "Editor content, press Enter to start editing, press Escape to exit": "", + "Editor gutter, press Enter to interact with controls using arrow keys, press Escape to exit": "", + "Looks good!": "Սխալ չկա", + "Recently used": "Վերջերս օգտագործված", + "Other commands": "Այլ հրամաններ", + "No matching commands": "Չկան համապատասխան հրամաններ", + "Search for": "Փնտրել", + "All": "Բոլորը", + "Replace with": "Փոխարինել", + "Replace": "Փոխարինել", + "Toggle Replace mode": "", + "RegExp Search": "Փնտրել ռեգեքսպով", + "CaseSensitive Search": "", + "Whole Word Search": "Ամբողջ բառեր", + "Search In Selection": "Փնտրել նշվածում", + "$0 of $1": "$1-ից $0", + "Cursor at row $0": "", + "Unfold rows $0 to $1": "", + "Unfold code": "", + "Fold at row $0": "", + "Fold code": "", + "Read annotations row $0": "", + "error": "սխալ", + "errors": "սխալներ", + "warning": "նախազգուշացում", + "warnings": "նախազգուշացումներ", + "information message": "տեղեկատվություն", + "information messages": "տեղեկատվություններ" +} \ No newline at end of file diff --git a/translations/ru.json b/translations/ru.json new file mode 100644 index 00000000000..0135d054b67 --- /dev/null +++ b/translations/ru.json @@ -0,0 +1,33 @@ +{ + "$id": "ru", + "Autocomplete suggestions": "Предложения автозаполнения", + "editor": "", + "Editor content, press Enter to start editing, press Escape to exit": "", + "Editor gutter, press Enter to interact with controls using arrow keys, press Escape to exit": "", + "Looks good!": "Нет ошибок", + "Recently used": "Недавно использованные", + "Other commands": "Другие команды", + "No matching commands": "Нет подходящих команд", + "Search for": "Найти", + "All": "Все", + "Replace with": "Заменить", + "Replace": "Заменить", + "Toggle Replace mode": "Перейти в режим поиска", + "RegExp Search": "Поиск по регулярному выражению", + "CaseSensitive Search": "", + "Whole Word Search": "", + "Search In Selection": "Искать в выделенном", + "$0 of $1": "$0 из $1", + "Cursor at row $0": "", + "Unfold rows $0 to $1": "", + "Unfold code": "", + "Fold at row $0": "", + "Fold code": "", + "Read annotations row $0": "", + "error": "ошибка", + "errors": "ошибки", + "warning": "предупреждение", + "warnings": "предупреждения", + "information message": "информационное сообщение", + "information messages": "информационные сообщения" +} \ No newline at end of file From f428ec39563fd923021691b4df006ee59053b38b Mon Sep 17 00:00:00 2001 From: "Rahmania Astrid (Aci) Mochtar" Date: Wed, 10 May 2023 10:00:04 +0200 Subject: [PATCH 0803/1293] New insert snippet option to exclude extra indentation (#5155) By default, when item is inserted, ace will modify snippet and add indentation to match previous code line. However some tooling may already include the proper indent format, thus creating improperly indented code when inserted. This change adds the option to exclude those extra indentations. --------- Co-authored-by: Rahmania Astrid Mochtar --- src/autocomplete.js | 2 +- src/snippets.js | 22 +++++++++++----------- src/snippets_test.js | 22 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/autocomplete.js b/src/autocomplete.js index d665e37aa3f..6367630a7b4 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -567,7 +567,7 @@ class CompletionProvider { } } if (data.snippet) - snippetManager.insertSnippet(editor, data.snippet, data.range); + snippetManager.insertSnippet(editor, data.snippet, {range: data.range}); else { this.$insertString(editor, data); } diff --git a/src/snippets.js b/src/snippets.js index fcde92163fe..6a5f74e4c65 100644 --- a/src/snippets.js +++ b/src/snippets.js @@ -349,7 +349,7 @@ var SnippetManager = function() { return result; }; - var processSnippetText = function(editor, snippetText, replaceRange) { + var processSnippetText = function(editor, snippetText, options={}) { var cursor = editor.getCursorPosition(); var line = editor.session.getLine(cursor.row); var tabString = editor.session.getTabString(); @@ -363,7 +363,7 @@ var SnippetManager = function() { tokens = this.resolveVariables(tokens, editor); // indent tokens = tokens.map(function(x) { - if (x == "\n") + if (x == "\n" && !options.excludeExtraIndent) return x + indentString; if (typeof x == "string") return x.replace(/\t/g, tabString); @@ -479,12 +479,12 @@ var SnippetManager = function() { return processedSnippet.text; }; - this.insertSnippetForSelection = function(editor, snippetText, replaceRange) { - var processedSnippet = processSnippetText.call(this, editor, snippetText); + this.insertSnippetForSelection = function(editor, snippetText, options={}) { + var processedSnippet = processSnippetText.call(this, editor, snippetText, options); var range = editor.getSelectionRange(); - if (replaceRange && replaceRange.compareRange(range) === 0) { - range = replaceRange; + if (options.range && options.range.compareRange(range) === 0) { + range = options.range; } var end = editor.session.replace(range, processedSnippet.text); @@ -493,16 +493,16 @@ var SnippetManager = function() { tabstopManager.addTabstops(processedSnippet.tabstops, range.start, end, selectionId); }; - this.insertSnippet = function(editor, snippetText, replaceRange) { + this.insertSnippet = function(editor, snippetText, options={}) { var self = this; - if (replaceRange && !(replaceRange instanceof Range)) - replaceRange = Range.fromPoints(replaceRange.start, replaceRange.end); + if (options.range && !(options.range instanceof Range)) + options.range = Range.fromPoints(options.range.start, options.range.end); if (editor.inVirtualSelectionMode) - return self.insertSnippetForSelection(editor, snippetText, replaceRange); + return self.insertSnippetForSelection(editor, snippetText, options); editor.forEachSelection(function() { - self.insertSnippetForSelection(editor, snippetText, replaceRange); + self.insertSnippetForSelection(editor, snippetText, options); }, null, {keepOrder: true}); if (editor.tabstopManager) diff --git a/src/snippets_test.js b/src/snippets_test.js index 02aeb6604d7..8cf64058705 100644 --- a/src/snippets_test.js +++ b/src/snippets_test.js @@ -336,6 +336,28 @@ module.exports = { start: {row: 0, column: 0}, end: {row: 0, column: 8} }); assert.equal(this.editor.getValue(), "test"); + }, + "test: insert snippet without extra indentation": function() { + var editor = this.editor; + const options = { + excludeExtraIndent: true + }; + const correctlyFormattedCode = [ + "def multiply_with_random(array):", + " for i in range(len(array)):", + " array[i] *= random.randint(1, 10)", + " return array" + ].join("\n"); + + editor.setValue(""); + snippetManager.insertSnippet(this.editor, "def multiply_with_random(array):\n\t"); + snippetManager.insertSnippet(this.editor, "for i in range(len(array)):\n\t\tarray[i] *= random.randint(1, 10)\n\treturn array"); + assert.notEqual(editor.getValue(), correctlyFormattedCode); + + editor.setValue(""); + snippetManager.insertSnippet(this.editor, "def multiply_with_random(array):\n\t", options); + snippetManager.insertSnippet(this.editor, "for i in range(len(array)):\n\t\tarray[i] *= random.randint(1, 10)\n\treturn array", options); + assert.equal(editor.getValue(), correctlyFormattedCode); } }; From 5f2e7d1b4dd42bb504c459d4638dd35d2a1b3013 Mon Sep 17 00:00:00 2001 From: Nanne <184182+whazor@users.noreply.github.com> Date: Wed, 10 May 2023 10:40:56 +0200 Subject: [PATCH 0804/1293] Allow custom parentNode for hover tooltips (#5156) --- src/tooltip.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tooltip.js b/src/tooltip.js index 34958d771ac..4372e55ce93 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -167,8 +167,8 @@ exports.Tooltip = Tooltip; class HoverTooltip extends Tooltip { - constructor() { - super(document.body); + constructor(parentNode=document.body) { + super(parentNode); this.timeout = undefined; this.lastT = 0; @@ -187,7 +187,7 @@ class HoverTooltip extends Tooltip { el.tabIndex = -1; el.addEventListener("blur", function() { - if (document.activeElement != el) this.hide(); + if (!el.contains(document.activeElement)) this.hide(); }.bind(this)); } @@ -366,4 +366,4 @@ class HoverTooltip extends Tooltip { } } -exports.HoverTooltip = HoverTooltip; +exports.HoverTooltip = HoverTooltip; \ No newline at end of file From 8d56c841ef980527a1ebe4cf73442766f5f97208 Mon Sep 17 00:00:00 2001 From: azmkercso <126491695+azmkercso@users.noreply.github.com> Date: Wed, 10 May 2023 11:32:03 +0200 Subject: [PATCH 0805/1293] feat: Inline autocomplete tooltip UX redesign (#5149) Changed UX of the inline tooltip for inline autocomplete. --- ace.d.ts | 23 +- src/autocomplete.js | 7 +- src/ext/command_bar.js | 635 ++++++++++++++++++ src/ext/command_bar_test.js | 694 ++++++++++++++++++++ src/ext/inline_autocomplete.js | 325 ++------- src/ext/inline_autocomplete_test.js | 223 ++++++- src/ext/inline_autocomplete_tooltip_test.js | 174 ----- src/test/all_browser.js | 2 +- src/test/mockdom.js | 4 + 9 files changed, 1632 insertions(+), 455 deletions(-) create mode 100644 src/ext/command_bar.js create mode 100644 src/ext/command_bar_test.js delete mode 100644 src/ext/inline_autocomplete_tooltip_test.js diff --git a/ace.d.ts b/ace.d.ts index 5ffa18ebd43..d0a90be7580 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1101,17 +1101,20 @@ export const Range: { type InlineAutocompleteAction = "prev" | "next" | "first" | "last"; -type TooltipCommandEnabledFunction = (editor: Ace.Editor) => boolean; +type TooltipCommandFunction = (editor: Ace.Editor) => T; interface TooltipCommand extends Ace.Command { - enabled: TooltipCommandEnabledFunction | boolean, - position?: number; + enabled: TooltipCommandFunction | boolean, + getValue?: TooltipCommandFunction, + type: "button" | "text" | "checkbox" + iconCssClass: string, + cssClass: string } export class InlineAutocomplete { constructor(); getInlineRenderer(): Ace.AceInline; - getInlineTooltip(): InlineTooltip; + getInlineTooltip(): CommandBarTooltip; getCompletionProvider(): Ace.CompletionProvider; show(editor: Ace.Editor): void; isOpen(): boolean; @@ -1119,7 +1122,7 @@ export class InlineAutocomplete { destroy(): void; goTo(action: InlineAutocompleteAction): void; tooltipEnabled: boolean; - commands: Record + commands: Record getIndex(): number; setIndex(value: number): void; getLength(): number; @@ -1127,13 +1130,15 @@ export class InlineAutocomplete { updateCompletions(options: Ace.CompletionOptions): void; } -export class InlineTooltip { +export class CommandBarTooltip { constructor(parentElement: HTMLElement); - setCommands(commands: Record): void; - show(editor: Ace.Editor): void; + registerCommand(id: string, command: TooltipCommand): void; + attach(editor: Ace.Editor): void; updatePosition(): void; - updateButtons(force?: boolean): void; + update(): void; isShown(): boolean; + getAlwaysShow(): boolean; + setAlwaysShow(alwaysShow: boolean): void; detach(): void; destroy(): void; } diff --git a/src/autocomplete.js b/src/autocomplete.js index 6367630a7b4..b3944c4f56e 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -560,7 +560,12 @@ class CompletionProvider { if (!this.completions) return false; if (this.completions.filterText) { - var ranges = editor.selection.getAllRanges(); + var ranges; + if (editor.selection.getAllRanges) { + ranges = editor.selection.getAllRanges(); + } else { + ranges = [editor.getSelectionRange()]; + } for (var i = 0, range; range = ranges[i]; i++) { range.start.column -= this.completions.filterText.length; editor.session.remove(range); diff --git a/src/ext/command_bar.js b/src/ext/command_bar.js new file mode 100644 index 00000000000..b3f99d571e6 --- /dev/null +++ b/src/ext/command_bar.js @@ -0,0 +1,635 @@ +var Tooltip = require("../tooltip").Tooltip; +var EventEmitter = require("../lib/event_emitter").EventEmitter; +var lang = require("../lib/lang"); +var dom = require("../lib/dom"); +var oop = require("../lib/oop"); +var useragent = require("../lib/useragent"); + +var BUTTON_CLASS_NAME = 'command_bar_tooltip_button'; +var VALUE_CLASS_NAME = 'command_bar_button_value'; +var CAPTION_CLASS_NAME = 'command_bar_button_caption'; +var KEYBINDING_CLASS_NAME = 'command_bar_keybinding'; +var TOOLTIP_CLASS_NAME = 'command_bar_tooltip'; +var MORE_OPTIONS_BUTTON_ID = 'MoreOptionsButton'; + +var defaultDelay = 100; +var defaultMaxElements = 4; + +var minPosition = function (posA, posB) { + if (posB.row > posA.row) { + return posA; + } else if (posB.row === posA.row && posB.column > posA.column) { + return posA; + } + return posB; +}; + +var keyDisplayMap = { + "Ctrl": { mac: "^"}, + "Option": { mac: "⌥"}, + "Command": { mac: "⌘"}, + "Cmd": { mac: "⌘"}, + "Shift": "⇧", + "Left": "←", + "Right": "→", + "Up": "↑", + "Down": "↓" +}; + + +/** + * Displays a command tooltip above the currently active line selection, with clickable elements. + * + * Internally it is a composite of two tooltips, one for the main tooltip and one for the + * overflowing commands. + * The commands are added sequentially in registration order. + * When attached to an editor, it is either always shown or only when the active line is hovered + * with mouse, depending on the alwaysShow property. + */ +class CommandBarTooltip { + constructor(parentNode, options) { + options = options || {}; + this.parentNode = parentNode; + this.tooltip = new Tooltip(this.parentNode); + this.moreOptions = new Tooltip(this.parentNode); + this.maxElementsOnTooltip = options.maxElementsOnTooltip || defaultMaxElements; + this.$alwaysShow = options.alwaysShow || false; + this.eventListeners = {}; + this.elements = {}; + this.commands = {}; + + this.tooltipEl = dom.buildDom(['div', { class: TOOLTIP_CLASS_NAME }], this.tooltip.getElement()); + this.moreOptionsEl = dom.buildDom(['div', { class: TOOLTIP_CLASS_NAME + " tooltip_more_options" }], this.moreOptions.getElement()); + + this.$showTooltipTimer = lang.delayedCall(this.$showTooltip.bind(this), options.showDelay || defaultDelay); + this.$hideTooltipTimer = lang.delayedCall(this.$hideTooltip.bind(this), options.hideDelay || defaultDelay); + this.$tooltipEnter = this.$tooltipEnter.bind(this); + this.$onMouseMove = this.$onMouseMove.bind(this); + this.$onChangeScroll = this.$onChangeScroll.bind(this); + this.$onEditorChangeSession = this.$onEditorChangeSession.bind(this); + this.$scheduleTooltipForHide = this.$scheduleTooltipForHide.bind(this); + this.$preventMouseEvent = this.$preventMouseEvent.bind(this); + + for (var event of ["mousedown", "mouseup", "click"]) { + this.tooltip.getElement().addEventListener(event, this.$preventMouseEvent); + this.moreOptions.getElement().addEventListener(event, this.$preventMouseEvent); + } + } + + /** + * Registers a command on the command bar tooltip. + * + * The commands are added in sequential order. If there is not enough space on the main + * toolbar, the remaining elements are added to the overflow menu. + * + * @param {string} id + * @param {CommandBarCommand} command + */ + registerCommand(id, command) { + var registerForMainTooltip = Object.keys(this.commands).length < this.maxElementsOnTooltip; + if (!registerForMainTooltip && !this.elements[MORE_OPTIONS_BUTTON_ID]) { + this.$createCommand(MORE_OPTIONS_BUTTON_ID, { + name: "···", + exec: function() { + this.$shouldHideMoreOptions = false; + this.$setMoreOptionsVisibility(!this.isMoreOptionsShown()); + }.bind(this), + type: "checkbox", + getValue: function() { + return this.isMoreOptionsShown(); + }.bind(this), + enabled: true + }, true); + } + this.$createCommand(id, command, registerForMainTooltip); + if (this.isShown()) { + this.updatePosition(); + } + } + + isShown() { + return !!this.tooltip && this.tooltip.isOpen; + } + + isMoreOptionsShown() { + return !!this.moreOptions && this.moreOptions.isOpen; + } + + getAlwaysShow() { + return this.$alwaysShow; + } + + /** + * Sets the display mode of the tooltip + * + * When true, the tooltip is always displayed while it is attached to an editor. + * When false, the tooltip is displayed only when the mouse hovers over the active editor line. + * + * @param {Editor} editor + */ + setAlwaysShow(alwaysShow) { + this.$alwaysShow = alwaysShow; + this.$updateOnHoverHandlers(!this.$alwaysShow); + this._signal("alwaysShow", this.$alwaysShow); + } + + /** + * Attaches the clickable command bar tooltip to an editor + * + * Depending on the alwaysShow parameter it either displays the tooltip immediately, + * or subscribes to the necessary events to display the tooltip on hover. + * + * @param {Editor} editor + */ + attach(editor) { + if (!editor || (this.isShown() && this.editor === editor)) { + return; + } + + this.detach(); + + this.editor = editor; + this.editor.on("changeSession", this.$onEditorChangeSession); + if (this.editor.session) { + this.editor.session.on("changeScrollLeft", this.$onChangeScroll); + this.editor.session.on("changeScrollTop", this.$onChangeScroll); + } + + if (this.getAlwaysShow()) { + this.$showTooltip(); + } else { + this.$updateOnHoverHandlers(true); + } + } + + /** + * Updates the position of the command bar tooltip. It aligns itself above the active line in the editor. + */ + updatePosition() { + if (!this.editor) { + return; + } + var renderer = this.editor.renderer; + + var ranges; + if (this.editor.selection.getAllRanges) { + ranges = this.editor.selection.getAllRanges(); + } else { + ranges = [this.editor.getSelectionRange()]; + } + if (!ranges.length) { + return; + } + var minPos = minPosition(ranges[0].start, ranges[0].end); + for (var i = 0, range; range = ranges[i]; i++) { + minPos = minPosition(minPos, minPosition(range.start, range.end)); + } + + var pos = renderer.$cursorLayer.getPixelPosition(minPos, true); + + var tooltipEl = this.tooltip.getElement(); + var screenWidth = window.innerWidth; + var screenHeight = window.innerHeight; + var rect = this.editor.container.getBoundingClientRect(); + + pos.top += rect.top - renderer.layerConfig.offset; + pos.left += rect.left + renderer.gutterWidth - renderer.scrollLeft; + + var cursorVisible = pos.top >= rect.top && pos.top <= rect.bottom && + pos.left >= rect.left + renderer.gutterWidth && pos.left <= rect.right; + + if (!cursorVisible && this.isShown()) { + this.$hideTooltip(); + return; + } else if (cursorVisible && !this.isShown() && this.getAlwaysShow()) { + this.$showTooltip(); + return; + } + + var top = pos.top - tooltipEl.offsetHeight; + var left = Math.min(screenWidth - tooltipEl.offsetWidth, pos.left); + + var tooltipFits = top >= 0 && top + tooltipEl.offsetHeight <= screenHeight && + left >= 0 && left + tooltipEl.offsetWidth <= screenWidth; + + if (!tooltipFits) { + this.$hideTooltip(); + return; + } + + this.tooltip.setPosition(left, top); + + if (this.isMoreOptionsShown()) { + top = top + tooltipEl.offsetHeight; + left = this.elements[MORE_OPTIONS_BUTTON_ID].getBoundingClientRect().left; + + var moreOptionsEl = this.moreOptions.getElement(); + var screenHeight = window.innerHeight; + if (top + moreOptionsEl.offsetHeight > screenHeight) { + top -= tooltipEl.offsetHeight + moreOptionsEl.offsetHeight; + } + if (left + moreOptionsEl.offsetWidth > screenWidth) { + left = screenWidth - moreOptionsEl.offsetWidth; + } + + this.moreOptions.setPosition(left, top); + } + } + + /** + * Updates each command element in the tooltip. + * + * This is automatically called on certain events, but can be called manually as well. + */ + update() { + Object.keys(this.elements).forEach(this.$updateElement.bind(this)); + } + + /** + * Detaches the tooltip from the editor. + */ + detach() { + this.tooltip.hide(); + this.moreOptions.hide(); + this.$updateOnHoverHandlers(false); + if (this.editor) { + this.editor.off("changeSession", this.$onEditorChangeSession); + if (this.editor.session) { + this.editor.session.off("changeScrollLeft", this.$onChangeScroll); + this.editor.session.off("changeScrollTop", this.$onChangeScroll); + } + } + this.$mouseInTooltip = false; + this.editor = null; + } + + destroy() { + if (this.tooltip && this.moreOptions) { + this.detach(); + this.tooltip.destroy(); + this.moreOptions.destroy(); + } + this.eventListeners = {}; + this.commands = {}; + this.elements = {}; + this.tooltip = this.moreOptions = this.parentNode = null; + } + + $createCommand(id, command, forMainTooltip) { + var parentEl = forMainTooltip ? this.tooltipEl : this.moreOptionsEl; + var keyParts = []; + var bindKey = command.bindKey; + if (bindKey) { + if (typeof bindKey === 'object') { + bindKey = useragent.isMac ? bindKey.mac : bindKey.win; + } + bindKey = bindKey.split("|")[0]; + keyParts = bindKey.split("-"); + + keyParts = keyParts.map(function(key) { + if (keyDisplayMap[key]) { + if (typeof keyDisplayMap[key] === 'string') { + return keyDisplayMap[key]; + } else if (useragent.isMac && keyDisplayMap[key].mac) { + return keyDisplayMap[key].mac; + } + } + return key; + }); + } + + var buttonNode; + if (forMainTooltip && command.iconCssClass) { + //Only support icon button for main tooltip, otherwise fall back to text button + buttonNode = [ + 'div', + { + class: ["ace_icon_svg", command.iconCssClass].join(" "), + "aria-label": command.name + " (" + command.bindKey + ")" + } + ]; + } else { + buttonNode = [ + ['div', { class: VALUE_CLASS_NAME }], + ['div', { class: CAPTION_CLASS_NAME }, command.name] + ]; + if (keyParts.length) { + buttonNode.push( + [ + 'div', + { class: KEYBINDING_CLASS_NAME }, + keyParts.map(function(keyPart) { + return ['div', keyPart]; + }) + ] + ); + } + } + + dom.buildDom(['div', { class: [BUTTON_CLASS_NAME, command.cssClass || ""].join(" "), ref: id }, buttonNode], parentEl, this.elements); + this.commands[id] = command; + + var eventListener = function(e) { + if (this.editor) { + this.editor.focus(); + } + // Internal variable to properly handle when the more options button is clicked + this.$shouldHideMoreOptions = this.isMoreOptionsShown(); + if (!this.elements[id].disabled && command.exec) { + command.exec(this.editor); + } + if (this.$shouldHideMoreOptions) { + this.$setMoreOptionsVisibility(false); + } + this.update(); + e.preventDefault(); + }.bind(this); + this.eventListeners[id] = eventListener; + this.elements[id].addEventListener('click', eventListener.bind(this)); + this.$updateElement(id); + } + + $setMoreOptionsVisibility(visible) { + if (visible) { + this.moreOptions.setTheme(this.editor.renderer.theme); + this.moreOptions.setClassName(TOOLTIP_CLASS_NAME + "_wrapper"); + this.moreOptions.show(); + this.update(); + this.updatePosition(); + } else { + this.moreOptions.hide(); + } + } + + $onEditorChangeSession(e) { + if (e.oldSession) { + e.oldSession.off("changeScrollTop", this.$onChangeScroll); + e.oldSession.off("changeScrollLeft", this.$onChangeScroll); + } + this.detach(); + } + + $onChangeScroll() { + if (this.editor.renderer && (this.isShown() || this.getAlwaysShow())) { + this.editor.renderer.once("afterRender", this.updatePosition.bind(this)); + } + } + + $onMouseMove(e) { + if (this.$mouseInTooltip) { + return; + } + var cursorPosition = this.editor.getCursorPosition(); + var cursorScreenPosition = this.editor.renderer.textToScreenCoordinates(cursorPosition.row, cursorPosition.column); + var lineHeight = this.editor.renderer.lineHeight; + + var isInCurrentLine = e.clientY >= cursorScreenPosition.pageY && e.clientY < cursorScreenPosition.pageY + lineHeight; + + if (isInCurrentLine) { + if (!this.isShown() && !this.$showTooltipTimer.isPending()) { + this.$showTooltipTimer.delay(); + } + if (this.$hideTooltipTimer.isPending()) { + this.$hideTooltipTimer.cancel(); + } + } else { + if (this.isShown() && !this.$hideTooltipTimer.isPending()) { + this.$hideTooltipTimer.delay(); + } + if (this.$showTooltipTimer.isPending()) { + this.$showTooltipTimer.cancel(); + } + } + } + + $preventMouseEvent(e) { + if (this.editor) { + this.editor.focus(); + } + e.preventDefault(); + } + + $scheduleTooltipForHide() { + this.$mouseInTooltip = false; + this.$showTooltipTimer.cancel(); + this.$hideTooltipTimer.delay(); + } + + $tooltipEnter() { + this.$mouseInTooltip = true; + if (this.$showTooltipTimer.isPending()) { + this.$showTooltipTimer.cancel(); + } + if (this.$hideTooltipTimer.isPending()) { + this.$hideTooltipTimer.cancel(); + } + } + + $updateOnHoverHandlers(enableHover) { + var tooltipEl = this.tooltip.getElement(); + var moreOptionsEl = this.moreOptions.getElement(); + if (enableHover) { + if (this.editor) { + this.editor.on("mousemove", this.$onMouseMove); + this.editor.renderer.getMouseEventTarget().addEventListener("mouseout", this.$scheduleTooltipForHide, true); + } + tooltipEl.addEventListener('mouseenter', this.$tooltipEnter); + tooltipEl.addEventListener('mouseleave', this.$scheduleTooltipForHide); + moreOptionsEl.addEventListener('mouseenter', this.$tooltipEnter); + moreOptionsEl.addEventListener('mouseleave', this.$scheduleTooltipForHide); + } else { + if (this.editor) { + this.editor.off("mousemove", this.$onMouseMove); + this.editor.renderer.getMouseEventTarget().removeEventListener("mouseout", this.$scheduleTooltipForHide, true); + } + tooltipEl.removeEventListener('mouseenter', this.$tooltipEnter); + tooltipEl.removeEventListener('mouseleave', this.$scheduleTooltipForHide); + moreOptionsEl.removeEventListener('mouseenter', this.$tooltipEnter); + moreOptionsEl.removeEventListener('mouseleave', this.$scheduleTooltipForHide); + } + } + + $showTooltip() { + if (this.isShown()) { + return; + } + this.tooltip.setTheme(this.editor.renderer.theme); + this.tooltip.setClassName(TOOLTIP_CLASS_NAME + "_wrapper"); + this.tooltip.show(); + this.update(); + this.updatePosition(); + this._signal("show"); + } + + $hideTooltip() { + this.$mouseInTooltip = false; + if (!this.isShown()) { + return; + } + this.moreOptions.hide(); + this.tooltip.hide(); + this._signal("hide"); + } + + $updateElement(id) { + var command = this.commands[id]; + if (!command) { + return; + } + var el = this.elements[id]; + var commandEnabled = command.enabled; + + if (typeof commandEnabled === 'function') { + commandEnabled = commandEnabled(this.editor); + } + + if (typeof command.getValue === 'function') { + var value = command.getValue(this.editor); + if (command.type === 'text') { + el.textContent = value; + } else if (command.type === 'checkbox') { + var domCssFn = value ? dom.addCssClass : dom.removeCssClass; + var isOnTooltip = el.parentElement === this.tooltipEl; + el.ariaChecked = value; + if (isOnTooltip) { + domCssFn(el, "ace_selected"); + } else { + el = el.querySelector("." + VALUE_CLASS_NAME); + domCssFn(el, "ace_checkmark"); + } + } + } + + if (commandEnabled && el.disabled) { + dom.removeCssClass(el, "ace_disabled"); + el.ariaDisabled = el.disabled = false; + el.removeAttribute("disabled"); + } else if (!commandEnabled && !el.disabled) { + dom.addCssClass(el, "ace_disabled"); + el.ariaDisabled = el.disabled = true; + el.setAttribute("disabled", ""); + } + } +} + +oop.implement(CommandBarTooltip.prototype, EventEmitter); + +dom.importCssString(` +.ace_tooltip.${TOOLTIP_CLASS_NAME}_wrapper { + padding: 0; +} + +.ace_tooltip .${TOOLTIP_CLASS_NAME} { + padding: 1px 5px; + display: flex; + pointer-events: auto; +} + +.ace_tooltip .${TOOLTIP_CLASS_NAME}.tooltip_more_options { + padding: 1px; + flex-direction: column; +} + +div.${BUTTON_CLASS_NAME} { + display: inline-flex; + cursor: pointer; + margin: 1px; + border-radius: 2px; + padding: 2px 5px; + align-items: center; +} + +div.${BUTTON_CLASS_NAME}.ace_selected, +div.${BUTTON_CLASS_NAME}:hover:not(.ace_disabled) { + background-color: rgba(0, 0, 0, 0.1); +} + +div.${BUTTON_CLASS_NAME}.ace_disabled { + color: #777; + pointer-events: none; +} + +div.${BUTTON_CLASS_NAME} .ace_icon_svg { + height: 12px; + background-color: #000; +} + +div.${BUTTON_CLASS_NAME}.ace_disabled .ace_icon_svg { + background-color: #777; +} + +.${TOOLTIP_CLASS_NAME}.tooltip_more_options .${BUTTON_CLASS_NAME} { + display: flex; +} + +.${TOOLTIP_CLASS_NAME}.${VALUE_CLASS_NAME} { + display: none; +} + +.${TOOLTIP_CLASS_NAME}.tooltip_more_options .${VALUE_CLASS_NAME} { + display: inline-block; + width: 12px; +} + +.${CAPTION_CLASS_NAME} { + display: inline-block; +} + +.${KEYBINDING_CLASS_NAME} { + margin: 0 2px; + display: inline-block; + font-size: 8px; +} + +.${TOOLTIP_CLASS_NAME}.tooltip_more_options .${KEYBINDING_CLASS_NAME} { + margin-left: auto; +} + +.${KEYBINDING_CLASS_NAME} div { + display: inline-block; + min-width: 8px; + padding: 2px; + margin: 0 1px; + border-radius: 2px; + background-color: #ccc; + text-align: center; +} + +.ace_dark.ace_tooltip .${TOOLTIP_CLASS_NAME} { + background-color: #373737; + color: #eee; +} + +.ace_dark div.${BUTTON_CLASS_NAME}.ace_disabled { + color: #979797; +} + +.ace_dark div.${BUTTON_CLASS_NAME}.ace_selected, +.ace_dark div.${BUTTON_CLASS_NAME}:hover:not(.ace_disabled) { + background-color: rgba(255, 255, 255, 0.1); +} + +.ace_dark div.${BUTTON_CLASS_NAME} .ace_icon_svg { + background-color: #eee; +} + +.ace_dark div.${BUTTON_CLASS_NAME}.ace_disabled .ace_icon_svg { + background-color: #979797; +} + +.ace_dark .${BUTTON_CLASS_NAME}.ace_disabled { + color: #979797; +} + +.ace_dark .${KEYBINDING_CLASS_NAME} div { + background-color: #575757; +} + +.ace_checkmark::before { + content: '✓'; +} +`, "commandbar.css", false); + +exports.CommandBarTooltip = CommandBarTooltip; +exports.TOOLTIP_CLASS_NAME = TOOLTIP_CLASS_NAME; +exports.BUTTON_CLASS_NAME = BUTTON_CLASS_NAME; diff --git a/src/ext/command_bar_test.js b/src/ext/command_bar_test.js new file mode 100644 index 00000000000..5538fc4dc02 --- /dev/null +++ b/src/ext/command_bar_test.js @@ -0,0 +1,694 @@ +/* global Promise */ +if (typeof process !== "undefined") { + require("amd-loader"); + require("../test/mockdom"); +} + +"use strict"; + +var TOOLTIP_CLASS_NAME = require("./command_bar").TOOLTIP_CLASS_NAME; +var BUTTON_CLASS_NAME = require("./command_bar").BUTTON_CLASS_NAME; +var CommandBarTooltip = require("./command_bar").CommandBarTooltip; +var Editor = require("../ace").Editor; +var EditSession = require("../ace").EditSession; +var VirtualRenderer = require("../ace").VirtualRenderer; +var assert = require("../test/assertions"); +var useragent = require("../lib/useragent"); + +function simulateClick(node) { + node.dispatchEvent(new window.CustomEvent("click", { bubbles: true })); +} + +function simulateMouseEvent(type, opts, node) { + var target = node || editor.renderer.getMouseEventTarget(); + var e = new window.CustomEvent("mouse" + type, {bubbles: true, cancelable: true}); + Object.defineProperties(e, Object.getOwnPropertyDescriptors(opts)); + target.dispatchEvent(e); +} + + +var editor; +var counters = {}; +var commandBarTooltip; +var testValues = {}; +var wrapperEl; +var editorPx = 500; + +function getActiveLinePosition() { + var cursorPosition = editor.getCursorPosition(); + return editor.renderer.textToScreenCoordinates(cursorPosition.row, cursorPosition.column); +} + + +var testFunction = function(name, defaultValue) { + return function(editor) { + if (!editor) { + return; + } + if (!counters[name]) { + counters[name] = 0; + } + counters[name]++; + return testValues[name] === undefined ? defaultValue : testValues[name]; + }; +}; + +var commands = { + "testCommand1": { + name: "testCommand1", + bindKey: { win: "Alt-K", mac: "Cmd-K" }, + exec: testFunction("testCommand1"), + enabled: testFunction("testEnabled1", true), + type: "button" + }, + "testCommand2": { + name: "testCommand2", + bindKey: "Ctrl-L", + exec: testFunction("testCommand2"), + enabled: testFunction("testEnabled2", true), + type: "button" + } +}; + +var createTooltip = function(options, additionalCommands) { + commandBarTooltip = new CommandBarTooltip(document.body, options); + Object.keys(commands).forEach(function(key) { + commandBarTooltip.registerCommand(key, commands[key]); + }); + (additionalCommands || []).forEach(function(commandEntry) { + commandBarTooltip.registerCommand(commandEntry[0], commandEntry[1]); + }); + commandBarTooltip.setAlwaysShow(true); + // Workaround: non-standard width and height hints for mock dom (which does not work well with flex elements) + // When running in the browser, these are ignored + commandBarTooltip.tooltip.getElement().style.widthHint = 150; + commandBarTooltip.tooltip.getElement().style.heightHint = editor.renderer.lineHeight * 2; + commandBarTooltip.moreOptions.getElement().style.widthHint = 150; + commandBarTooltip.moreOptions.getElement().style.heightHint = editor.renderer.lineHeight * 2;commandBarTooltip.moreOptions.getElement().style.heightHint = editor.renderer.lineHeight * 2;commandBarTooltip.moreOptions.getElement().style.heightHint = editor.renderer.lineHeight * 2;commandBarTooltip.moreOptions.getElement().style.heightHint = editor.renderer.lineHeight * 2;commandBarTooltip.moreOptions.getElement().style.heightHint = editor.renderer.lineHeight * 2; +}; + +var isElementVisible = function(elem) { + return !((elem.position !== "fixed" && elem.offsetParent === null) || + window.getComputedStyle(elem).display === 'none' || elem.clientHeight === 0); +}; + +var tooltipVisibilityCheck = function(tooltipVisible = false, moreOptionsVisible = false) { + moreOptionsVisible = tooltipVisible && moreOptionsVisible; + assert.strictEqual(commandBarTooltip.isShown(), tooltipVisible); + assert.strictEqual(commandBarTooltip.isMoreOptionsShown(), moreOptionsVisible); + var tooltipDomElements = document.querySelectorAll("." + TOOLTIP_CLASS_NAME); + assert.strictEqual(tooltipDomElements.length, 2); + assert.strictEqual(isElementVisible(tooltipDomElements[0]), tooltipVisible); + assert.strictEqual(isElementVisible(tooltipDomElements[1]), moreOptionsVisible); +}; + +module.exports = { + setUp: function() { + wrapperEl = document.createElement("div"); + wrapperEl.style.position = "fixed"; + wrapperEl.style.left = "400px"; + wrapperEl.style.top = "100px"; + wrapperEl.style.width = editorPx + "px"; + wrapperEl.style.height = editorPx + "px"; + document.body.appendChild(wrapperEl); + var renderer = new VirtualRenderer(wrapperEl); + var session = new EditSession("abc123\n\nfunc"); + editor = new Editor(renderer, session); + counters = {}; + testValues = {}; + editor.getSelection().moveCursorFileEnd(); + editor.renderer.$loop._flush(); + }, + "test: displays command bar tooltip above cursor with commands immediately in 'always show' mode": function(done) { + createTooltip(); + tooltipVisibilityCheck(false, false); + + commandBarTooltip.attach(editor); + tooltipVisibilityCheck(true, false); + done(); + }, + "test: commands are disabled when enable check is falsy": function(done) { + createTooltip(); + commandBarTooltip.attach(editor); + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + var disabledButtonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME + ".ace_disabled")); + assert.strictEqual(buttonElements.length, 2); + assert.strictEqual(disabledButtonElements.length, 0); + assert.strictEqual(buttonElements.filter(function (button) { return !button.disabled; }).length, 2); + assert.strictEqual(counters["testEnabled1"], 1); + assert.strictEqual(counters["testEnabled2"], 1); + + testValues.testEnabled2 = false; + commandBarTooltip.update(); + buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + disabledButtonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME + ".ace_disabled")); + assert.strictEqual(buttonElements.length, 2); + assert.strictEqual(disabledButtonElements.length, 1); + assert.strictEqual(disabledButtonElements.filter(function (button) { return button.disabled; }).length, 1); + assert.strictEqual(buttonElements.filter(function (button) { return !button.disabled; }).length, 1); + assert.strictEqual(counters["testEnabled1"], 2); + assert.strictEqual(counters["testEnabled2"], 2); + done(); + }, + "test: enabled commands are clickable": function(done) { + createTooltip(); + commandBarTooltip.attach(editor); + assert.strictEqual(commandBarTooltip.isShown(), true); + assert.strictEqual(counters["testCommand1"], undefined); + assert.strictEqual(counters["testCommand2"], undefined); + testValues.testEnabled2 = false; + commandBarTooltip.update(); + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 2); + var disabledButtonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME + ".ace_disabled")); + assert.strictEqual(disabledButtonElements.length, 1); + simulateClick(buttonElements[0]); + simulateClick(buttonElements[1]); + simulateClick(disabledButtonElements[0]); + assert.strictEqual(counters["testCommand1"], 1); + assert.strictEqual(counters["testCommand2"], undefined); + done(); + }, + "test: tooltip is displayed on hover with the tooltip delay": function(done) { + var delay = 10; + var waitFor = function(ms) { + return new Promise(function(resolve) { setTimeout(resolve, ms); }); + }; + var waitForDelay = function() { return waitFor(delay); }; + var waitForHalfDelay = function() { return waitFor(delay / 2); }; + createTooltip({ showDelay: delay, hideDelay: delay, maxElementsOnTooltip: 1 }); + commandBarTooltip.setAlwaysShow(false); + editor.getSelection().moveCursorTo(1, 1); + editor.renderer.$loop._flush(); + var activeLinePos = getActiveLinePosition(); + var mainTooltipEl = commandBarTooltip.tooltip.getElement(); + var moreOptionsEl = commandBarTooltip.moreOptions.getElement(); + var moveToActiveLineCursor = { clientX: activeLinePos.pageX + 1, clientY: activeLinePos.pageY + 1 }; + var moveAway = { clientX: activeLinePos.pageX + 1, clientY: activeLinePos.pageY + 100 }; + new Promise(function(resolve) { + commandBarTooltip.attach(editor); + simulateMouseEvent("move", moveToActiveLineCursor); + tooltipVisibilityCheck(false); + resolve(); + }).then(waitForDelay).then(function() { + tooltipVisibilityCheck(true, false); + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 3); + + var moreOptionsButton = buttonElements[1]; + + var moveToMoreOptionsButton = { clientX: moreOptionsButton.left + 1, clientY: moreOptionsButton.right + 1 }; + + simulateMouseEvent("move", moveToMoreOptionsButton); + simulateMouseEvent("enter", moveToMoreOptionsButton, mainTooltipEl); + + simulateClick(moreOptionsButton); + + tooltipVisibilityCheck(true, true); + + var leaveMainTooltip = { clientX: mainTooltipEl.right + 10, clientY: mainTooltipEl.top - 10 }; + simulateMouseEvent("move", leaveMainTooltip); + simulateMouseEvent("leave", leaveMainTooltip, mainTooltipEl); + }).then(waitForHalfDelay).then(function() { + var moreOptionsRect = moreOptionsEl.getBoundingClientRect(); + var enterMoreOptions = { clientX: moreOptionsRect.left + 1, clientY: moreOptionsRect.top + 1 }; + simulateMouseEvent("move", enterMoreOptions); + simulateMouseEvent("enter", enterMoreOptions, moreOptionsEl); + }).then(waitForDelay).then(function() { + tooltipVisibilityCheck(true, true); + var moreOptionsRect = moreOptionsEl.getBoundingClientRect(); + var leaveWholeTooltip = { clientX: moreOptionsRect.right + 10, clientY: moreOptionsRect.top - 10 }; + simulateMouseEvent("move", leaveWholeTooltip); + simulateMouseEvent("leave", leaveWholeTooltip, mainTooltipEl); + }).then(waitForHalfDelay).then(function() { + simulateMouseEvent("move", moveToActiveLineCursor); + }).then(waitForDelay).then(function() { + tooltipVisibilityCheck(true, true); + simulateMouseEvent("move", moveAway); + }).then(waitForDelay).then(function() { + tooltipVisibilityCheck(false); + simulateMouseEvent("move", moveToActiveLineCursor); + }).then(waitForDelay).then(function() { + tooltipVisibilityCheck(true); + done(); + }).catch(function(err) { + assert.strictEqual(err, undefined); + done(err); + }); + }, + "test: tooltip supports checkbox buttons": function(done) { + createTooltip(); + testValues.testCheckboxValue1 = true; + commandBarTooltip.registerCommand("testCheckbox1", { + name: "testCheckbox1", + bindKey: "Alt-C", + exec: function() { + testValues.testCheckboxValue1 = !testValues.testCheckboxValue1; + }, + enabled: testFunction("testCheckboxEnabled1", true), + getValue: testFunction("testCheckboxValue1"), + type: "checkbox" + }); + + commandBarTooltip.attach(editor); + assert.strictEqual(commandBarTooltip.isShown(), true); + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 3); + var checkboxElement = buttonElements[2]; + assert.strictEqual(checkboxElement.classList.contains("ace_selected"), true); + assert.strictEqual(checkboxElement.ariaChecked.toString(), "true"); + + testValues.testCheckboxValue1 = false; + commandBarTooltip.update(); + assert.strictEqual(checkboxElement.classList.contains("ace_selected"), false); + assert.strictEqual(checkboxElement.ariaChecked.toString(), "false"); + + simulateClick(checkboxElement); + assert.strictEqual(checkboxElement.classList.contains("ace_selected"), true); + assert.strictEqual(checkboxElement.ariaChecked.toString(), "true"); + + done(); + }, + "test: tooltip supports checkbox menu items": function(done) { + createTooltip({ maxElementsOnTooltip: 2 }); + testValues.testCheckboxValue1 = true; + commandBarTooltip.registerCommand("testCheckbox1", { + name: "testCheckbox1", + bindKey: "Alt-C", + exec: function() { + testValues.testCheckboxValue1 = !testValues.testCheckboxValue1; + }, + enabled: testFunction("testCheckboxEnabled1", true), + getValue: testFunction("testCheckboxValue1"), + type: "checkbox" + }); + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + commandBarTooltip.attach(editor); + assert.strictEqual(commandBarTooltip.isShown(), true); + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 4); + var moreOptionsElement = buttonElements[2]; + var checkboxElement = buttonElements[3]; + assert.strictEqual(checkboxElement.parentElement, commandBarTooltip.moreOptionsEl); + assert.strictEqual(checkboxElement.firstChild.classList.contains("ace_checkmark"), true); + assert.strictEqual(checkboxElement.ariaChecked.toString(), "true"); + + testValues.testCheckboxValue1 = false; + commandBarTooltip.update(); + assert.strictEqual(checkboxElement.firstChild.classList.contains("ace_checkmark"), false); + assert.strictEqual(checkboxElement.ariaChecked.toString(), "false"); + + assert.strictEqual(commandBarTooltip.isMoreOptionsShown(), false); + simulateClick(moreOptionsElement); + assert.strictEqual(commandBarTooltip.isMoreOptionsShown(), true); + simulateClick(checkboxElement); + assert.strictEqual(commandBarTooltip.isMoreOptionsShown(), false); + + assert.strictEqual(checkboxElement.firstChild.classList.contains("ace_checkmark"), true); + assert.strictEqual(checkboxElement.ariaChecked.toString(), "true"); + done(); + }, + "test: tooltip supports icon buttons": function(done) { + createTooltip(); + commandBarTooltip.registerCommand("testIcon1", { + name: "testIcon1", + bindKey: "Alt-I", + exec: testFunction("testIcon1"), + enabled: testFunction("testIconEnabled1", true), + iconCssClass: "ace_info", + type: "button" + }); + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + commandBarTooltip.attach(editor); + assert.strictEqual(commandBarTooltip.isShown(), true); + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 3); + var iconButtonElement = buttonElements[2]; + assert.strictEqual(iconButtonElement.firstChild.classList.contains("ace_info"), true); + assert.strictEqual(iconButtonElement.firstChild.classList.contains("ace_icon_svg"), true); + assert.strictEqual(counters["testIcon1"], undefined); + + simulateClick(iconButtonElement); + + assert.strictEqual(counters["testIcon1"], 1); + done(); + }, + "test: tooltip supports text elements": function(done) { + createTooltip(); + testValues.testTextValue1 = "test"; + commandBarTooltip.registerCommand("testText1", { + name: "testText1", + bindKey: "Alt-I", + enabled: testFunction("testTextEnabled1", true), + getValue: testFunction("testTextValue1"), + type: "text" + }); + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + commandBarTooltip.attach(editor); + assert.strictEqual(commandBarTooltip.isShown(), true); + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 3); + var textButtonElement = buttonElements[2]; + assert.strictEqual(textButtonElement.textContent, "test"); + assert.strictEqual(counters["testText1"], undefined); + + simulateClick(textButtonElement); + assert.strictEqual(textButtonElement.textContent, "test"); + assert.strictEqual(counters["testText1"], undefined); + + testValues.testTextValue1 = "updatedTest"; + commandBarTooltip.update(); + assert.strictEqual(textButtonElement.textContent, "updatedTest"); + assert.strictEqual(counters["testText1"], undefined); + done(); + }, + "test: tooltip creates more options menu for overflow options": function(done) { + createTooltip({ maxElementsOnTooltip: 2 }); + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 2); + assert.strictEqual(buttonElements[0].parentElement, commandBarTooltip.tooltipEl); + assert.strictEqual(buttonElements[1].parentElement, commandBarTooltip.tooltipEl); + + commandBarTooltip.attach(editor); + + commandBarTooltip.registerCommand("testText1", { + name: "testText1", + enabled: testFunction("testTextEnabled1", true), + getValue: testFunction("testTextValue1"), + type: "text" + }); + + buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 4); + assert.strictEqual(buttonElements[2].parentElement, commandBarTooltip.tooltipEl); + assert.strictEqual(buttonElements[3].parentElement, commandBarTooltip.moreOptionsEl); + + var moreOptionsButton = buttonElements[2]; + + assert.strictEqual(commandBarTooltip.isMoreOptionsShown(), false); + simulateClick(moreOptionsButton); + assert.strictEqual(commandBarTooltip.isMoreOptionsShown(), true); + simulateClick(moreOptionsButton); + assert.strictEqual(commandBarTooltip.isMoreOptionsShown(), false); + simulateClick(moreOptionsButton); + assert.strictEqual(commandBarTooltip.isMoreOptionsShown(), true); + simulateClick(buttonElements[3]); + assert.strictEqual(commandBarTooltip.isMoreOptionsShown(), false); + done(); + }, + "test: more options opens below main tooltip, above only if there is no space below": function(done) { + createTooltip({ maxElementsOnTooltip: 1 }); + + wrapperEl.style.top = (window.innerHeight - editorPx) + "px"; + wrapperEl.style.left = (window.innerWidth - editorPx) + "px"; + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 3); + + var moreOptionsButton = buttonElements[1]; + var tooltipEl = commandBarTooltip.tooltip.getElement(); + var moreOptionsEl = commandBarTooltip.moreOptions.getElement(); + var charWidth = editor.renderer.$textLayer.getCharacterWidth(); + var testString = "\n".repeat(editorPx / editor.renderer.lineHeight + 3) + + "b".repeat(editorPx / charWidth); + + + editor.execCommand("insertstring", testString); + editor.getSelection().moveCursorFileStart(); + editor.renderer.scrollTo(0,0); + editor.renderer.$loop._flush(); + + commandBarTooltip.attach(editor); + + tooltipVisibilityCheck(true); + simulateClick(moreOptionsButton); + tooltipVisibilityCheck(true, true); + + assert.ok(tooltipEl.getBoundingClientRect().top < moreOptionsEl.getBoundingClientRect().top); + + commandBarTooltip.detach(); + + editor.getSelection().moveCursorFileEnd(); + editor.renderer.scrollCursorIntoView(editor.getCursorPosition()); + editor.renderer.$loop._flush(); + + commandBarTooltip.attach(editor); + + tooltipVisibilityCheck(true); + simulateClick(moreOptionsButton); + tooltipVisibilityCheck(true, true); + + assert.ok(tooltipEl.getBoundingClientRect().top > moreOptionsEl.getBoundingClientRect().top); + done(); + }, + "test: keeps the editor in focus after the tooltip is clicked": function(done) { + createTooltip({ maxElementsOnTooltip: 1 }); + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 3); + + var moreOptionsButton = buttonElements[1]; + var tooltipEl = commandBarTooltip.tooltip.getElement(); + var moreOptionsEl = commandBarTooltip.moreOptions.getElement(); + + commandBarTooltip.attach(editor); + + tooltipVisibilityCheck(true); + simulateClick(tooltipEl); + assert.strictEqual(editor.isFocused(), true); + simulateClick(moreOptionsButton); + assert.strictEqual(editor.isFocused(), true); + tooltipVisibilityCheck(true, true); + simulateClick(moreOptionsEl); + assert.strictEqual(editor.isFocused(), true); + simulateClick(buttonElements[2]); + assert.strictEqual(editor.isFocused(), true); + + commandBarTooltip.detach(); + + assert.strictEqual(editor.isFocused(), true); + + done(); + }, + "test: shows windows keybindings when available": function(done) { + var origIsWin = useragent.isWin; + var origIsMac = useragent.isMac; + try { + useragent.isWin = true; + useragent.isMac = false; + createTooltip({ maxElementsOnTooltip: 1 }); + + commandBarTooltip.registerCommand("testButton3", { + name: "testButton", + bindKey: { win: "Shift-Right", mac: "Option-Right" }, + exec: testFunction("testButton3"), + enabled: testFunction("testButtonEnabled3", true), + type: "button" + }); + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 4); + + var extractTextContent = function(el) { + return el.textContent; + }; + + var keyBindings1 = Array.from(buttonElements[0].lastChild.childNodes).map(extractTextContent); + var keyBindings2 = Array.from(buttonElements[2].lastChild.childNodes).map(extractTextContent); + var keyBindings3 = Array.from(buttonElements[3].lastChild.childNodes).map(extractTextContent); + assert.deepEqual(keyBindings1, ["Alt", "K"]); + assert.deepEqual(keyBindings2, ["Ctrl", "L"]); + assert.deepEqual(keyBindings3, ["⇧", "→"]); + + done(); + } finally { + useragent.isWin = origIsWin; + useragent.isMac = origIsMac; + } + }, + "test: shows mac keybindings when available": function(done) { + var origIsWin = useragent.isWin; + var origIsMac = useragent.isMac; + try { + useragent.isWin = false; + useragent.isMac = true; + createTooltip({ maxElementsOnTooltip: 1 }); + + commandBarTooltip.registerCommand("testButton3", { + name: "testButton", + bindKey: { win: "Shift-Right", mac: "Option-Right" }, + exec: testFunction("testButton3"), + enabled: testFunction("testButtonEnabled3", true), + type: "button" + }); + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + assert.strictEqual(buttonElements.length, 4); + + var extractTextContent = function(el) { + return el.textContent; + }; + + var keyBindings1 = Array.from(buttonElements[0].lastChild.childNodes).map(extractTextContent); + var keyBindings2 = Array.from(buttonElements[2].lastChild.childNodes).map(extractTextContent); + var keyBindings3 = Array.from(buttonElements[3].lastChild.childNodes).map(extractTextContent); + assert.deepEqual(keyBindings1, ["⌘", "K"]); + assert.deepEqual(keyBindings2, ["^", "L"]); + assert.deepEqual(keyBindings3, ["⌥", "→"]); + + done(); + } finally { + useragent.isWin = origIsWin; + useragent.isMac = origIsMac; + } + }, + "test: does not display if the editor cursor is not visible": function(done) { + createTooltip(); + + var charWidth = editor.renderer.$textLayer.getCharacterWidth(); + + var testString = "a".repeat(100) + + "\n".repeat(editorPx / editor.renderer.lineHeight + 3) + + "b".repeat(100); + + editor.execCommand("insertstring", testString); + editor.renderer.$loop._flush(); + + editor.getSelection().moveCursorFileStart(); + editor.renderer.scrollTo(0,0); + editor.renderer.$loop._flush(); + + commandBarTooltip.attach(editor); + tooltipVisibilityCheck(true); + + editor.renderer.scrollToLine(1); + editor.renderer.$loop._flush(); + tooltipVisibilityCheck(false); + + editor.renderer.scrollToLine(0); + editor.renderer.$loop._flush(); + tooltipVisibilityCheck(true); + + editor.renderer.scrollBy(charWidth * 2); + editor.renderer.$loop._flush(); + tooltipVisibilityCheck(false); + + editor.renderer.scrollBy(-charWidth * 2); + editor.renderer.$loop._flush(); + tooltipVisibilityCheck(true); + commandBarTooltip.detach(); + + editor.getSelection().moveCursorFileEnd(); + editor.renderer.scrollCursorIntoView(editor.getCursorPosition()); + editor.renderer.$loop._flush(); + commandBarTooltip.attach(editor); + tooltipVisibilityCheck(true); + + editor.renderer.scrollToLine(editor.renderer.getScrollTopRow() - 2); + editor.renderer.$loop._flush(); + tooltipVisibilityCheck(false); + + editor.renderer.scrollToLine(editor.renderer.getScrollTopRow() + 2); + editor.renderer.$loop._flush(); + tooltipVisibilityCheck(true); + + editor.renderer.scrollBy(-charWidth * 10); + editor.renderer.$loop._flush(); + tooltipVisibilityCheck(false); + + editor.renderer.scrollBy(charWidth * 10); + editor.renderer.$loop._flush(); + tooltipVisibilityCheck(true); + commandBarTooltip.detach(); + done(); + }, + "test: does not display if the tooltip does not fit into the screen": function(done) { + createTooltip(); + + var testString = "a".repeat(100) + + "\n".repeat(editorPx / editor.renderer.lineHeight + 3) + + "b".repeat(100); + + editor.execCommand("insertstring", testString); + editor.renderer.$loop._flush(); + + wrapperEl.style.top = "10px"; + + commandBarTooltip.attach(editor); + tooltipVisibilityCheck(true); + + commandBarTooltip.detach(); + + tooltipVisibilityCheck(false); + + editor.getSelection().moveCursorFileStart(); + editor.renderer.scrollCursorIntoView(editor.getCursorPosition()); + editor.renderer.$loop._flush(); + + commandBarTooltip.attach(editor); + tooltipVisibilityCheck(false); + + done(); + }, + "test: detaches when session changes": function(done) { + createTooltip(); + commandBarTooltip.attach(editor); + tooltipVisibilityCheck(true); + + var currentSession = editor.getSession(); + editor.setSession(null); + tooltipVisibilityCheck(false); + + editor.setSession(currentSession); + tooltipVisibilityCheck(false); + + commandBarTooltip.attach(editor); + tooltipVisibilityCheck(true); + done(); + }, + "test: verify detach": function(done) { + createTooltip(); + commandBarTooltip.attach(editor); + tooltipVisibilityCheck(true); + + commandBarTooltip.detach(); + tooltipVisibilityCheck(false); + + commandBarTooltip.detach(); + tooltipVisibilityCheck(false); + done(); + }, + "test: verify destroy": function(done) { + createTooltip(); + commandBarTooltip.attach(editor); + tooltipVisibilityCheck(true); + + commandBarTooltip.destroy(); + assert.strictEqual(commandBarTooltip.isShown(), false); + assert.strictEqual(commandBarTooltip.isMoreOptionsShown(), false); + var tooltipDomElements = document.querySelectorAll("." + TOOLTIP_CLASS_NAME); + assert.strictEqual(tooltipDomElements.length, 0); + + // Intentionally called twice + commandBarTooltip.destroy(); + assert.strictEqual(commandBarTooltip.isShown(), false); + assert.strictEqual(commandBarTooltip.isMoreOptionsShown(), false); + tooltipDomElements = document.querySelectorAll("." + TOOLTIP_CLASS_NAME); + assert.strictEqual(tooltipDomElements.length, 0); + done(); + }, + tearDown: function() { + commandBarTooltip.destroy(); + editor.destroy(); + wrapperEl.parentElement.removeChild(wrapperEl); + } +}; + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/src/ext/inline_autocomplete.js b/src/ext/inline_autocomplete.js index 7e10a8f0a14..3b4f021a060 100644 --- a/src/ext/inline_autocomplete.js +++ b/src/ext/inline_autocomplete.js @@ -6,9 +6,11 @@ var FilteredList = require("../autocomplete").FilteredList; var CompletionProvider = require("../autocomplete").CompletionProvider; var Editor = require("../editor").Editor; var util = require("../autocomplete/util"); -var lang = require("../lib/lang"); var dom = require("../lib/dom"); -var useragent = require("../lib/useragent"); +var lang = require("../lib/lang"); +var CommandBarTooltip = require("./command_bar").CommandBarTooltip; +var BUTTON_CLASS_NAME = require("./command_bar").BUTTON_CLASS_NAME; + var snippetCompleter = require("./language_tools").snippetCompleter; var textCompleter = require("./language_tools").textCompleter; var keyWordCompleter = require("./language_tools").keyWordCompleter; @@ -17,16 +19,6 @@ var destroyCompleter = function(e, editor) { editor.completer && editor.completer.destroy(); }; -var minPosition = function (posA, posB) { - if (posB.row > posA.row) { - return posA; - } else if (posB.row === posA.row && posB.column > posA.column) { - return posA; - } - return posB; -}; - - /** * This class controls the inline-only autocompletion components and their lifecycle. * This is more lightweight than the popup-based autocompletion, as it can only work with exact prefix matches. @@ -35,13 +27,12 @@ var minPosition = function (posA, posB) { class InlineAutocomplete { constructor(editor) { this.editor = editor; - this.tooltipEnabled = true; this.keyboardHandler = new HashHandler(this.commands); this.$index = -1; this.blurListener = this.blurListener.bind(this); this.changeListener = this.changeListener.bind(this); - this.mousewheelListener = this.mousewheelListener.bind(this); + this.changeTimer = lang.delayedCall(function() { this.updateCompletions(); @@ -56,8 +47,7 @@ class InlineAutocomplete { getInlineTooltip() { if (!this.inlineTooltip) { - this.inlineTooltip = new InlineTooltip(this.editor, document.body || document.documentElement); - this.inlineTooltip.setCommands(this.commands); + this.inlineTooltip = InlineAutocomplete.createInlineTooltip(document.body || document.documentElement); } return this.inlineTooltip; } @@ -78,7 +68,6 @@ class InlineAutocomplete { this.editor.on("changeSelection", this.changeListener); this.editor.on("blur", this.blurListener); - this.editor.on("mousewheel", this.mousewheelListener); this.updateCompletions(options); } @@ -88,12 +77,8 @@ class InlineAutocomplete { this.editor.textInput.setAriaOptions({}); } - if (this.tooltipEnabled) { - this.getInlineTooltip().show(this.editor); - } else if (this.tooltipEnabled === "hover") { - } - this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); + this.getInlineTooltip().attach(this.editor); if (this.$index === -1) { this.setIndex(0); @@ -125,22 +110,17 @@ class InlineAutocomplete { this.detach(); } - mousewheelListener(e) { - if (this.inlineTooltip && this.inlineTooltip.isShown()) { - this.inlineTooltip.updatePosition(); - } - } - goTo(where) { if (!this.completions || !this.completions.filtered) { return; } + var completionLength = this.completions.filtered.length; switch(where.toLowerCase()) { case "prev": - this.setIndex(Math.max(0, this.$index - 1)); + this.setIndex((this.$index - 1 + completionLength) % completionLength); break; case "next": - this.setIndex(this.$index + 1); + this.setIndex((this.$index + 1 + completionLength) % completionLength); break; case "first": this.setIndex(0); @@ -197,7 +177,7 @@ class InlineAutocomplete { this.getInlineRenderer().hide(); } if (this.inlineTooltip && this.inlineTooltip.isShown()) { - this.inlineTooltip.updateButtons(); + this.inlineTooltip.update(); } } @@ -262,7 +242,6 @@ class InlineAutocomplete { this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler); this.editor.off("changeSelection", this.changeListener); this.editor.off("blur", this.blurListener); - this.editor.off("mousewheel", this.mousewheelListener); } this.changeTimer.cancel(); if (this.inlineTooltip) { @@ -306,42 +285,28 @@ InlineAutocomplete.prototype.commands = { name: "Previous", exec: function(editor) { editor.completer.goTo("prev"); - }, - enabled: function(editor) { - return editor.completer.getIndex() > 0; - }, - position: 10 + } }, "Next": { bindKey: "Alt-]", name: "Next", exec: function(editor) { editor.completer.goTo("next"); - }, - enabled: function(editor) { - return editor.completer.getIndex() < editor.completer.getLength() - 1; - }, - position: 20 + } }, "Accept": { bindKey: { win: "Tab|Ctrl-Right", mac: "Tab|Cmd-Right" }, name: "Accept", exec: function(editor) { return editor.completer.insertMatch(); - }, - enabled: function(editor) { - return editor.completer.getIndex() >= 0; - }, - position: 30 + } }, "Close": { bindKey: "Esc", name: "Close", exec: function(editor) { editor.completer.detach(); - }, - enabled: true, - position: 40 + } } }; @@ -386,218 +351,72 @@ require("../config").defineOptions(Editor.prototype, "editor", { } }); - -var ENTRY_CLASS_NAME = 'inline_autocomplete_tooltip_entry'; -var BUTTON_CLASS_NAME = 'inline_autocomplete_tooltip_button'; -var TOOLTIP_CLASS_NAME = 'ace_tooltip ace_inline_autocomplete_tooltip'; -var TOOLTIP_ID = 'inline_autocomplete_tooltip'; - /** - * Displays a command tooltip above the selection, with clickable elements. + * Factory method to create a command bar tooltip for inline autocomplete. + * + * @param {HTMLElement} parentEl The parent element where the tooltip HTML elements will be added. + * @returns {CommandBarTooltip} The command bar tooltip for inline autocomplete */ -class InlineTooltip { - /** - * Creates the inline command tooltip helper which displays the available keyboard commands for the user. - * @param {Editor} editor - * @param {HTMLElement} parentElement - */ - constructor(editor, parentElement) { - this.editor = editor; - this.htmlElement = document.createElement('div'); - var el = this.htmlElement; - el.style.display = 'none'; - if (parentElement) { - parentElement.appendChild(el); - } - el.id = TOOLTIP_ID; - el.style['pointer-events'] = 'auto'; - el.className = TOOLTIP_CLASS_NAME; - this.commands = {}; - this.buttons = {}; - this.eventListeners = {}; - } - - /** - * This function sets the commands. Note that it is advised to call this before calling show, otherwise there are no buttons to render - * @param {Record} commands - */ - setCommands(commands) { - if (!commands || !this.htmlElement) { - return; - } - this.detach(); - var el = this.htmlElement; - while (el.hasChildNodes()) { - el.removeChild(el.firstChild); - } - - this.commands = commands; - this.buttons = {}; - this.eventListeners = {}; - - Object.keys(commands) - .map(function(key) { return [key, commands[key]]; }) - .filter(function (entry) { return entry[1].position > 0; }) - .sort(function (a, b) { return a[1].position - b[1].position; }) - .forEach(function (entry) { - var key = entry[0]; - var command = entry[1]; - dom.buildDom(["div", { class: ENTRY_CLASS_NAME }, [['div', { class: BUTTON_CLASS_NAME, ref: key }, this.buttons]]], el, this.buttons); - var bindKey = command.bindKey; - if (typeof bindKey === 'object') { - bindKey = useragent.isMac ? bindKey.mac : bindKey.win; - } - bindKey = bindKey.replace("|", " / "); - var buttonText = dom.createTextNode([command.name, "(", bindKey, ")"].join(" ")); - this.buttons[key].appendChild(buttonText); - }.bind(this)); - } - - /** - * Displays the clickable command bar tooltip - */ - show() { - this.detach(); - - this.htmlElement.style.display = ''; - this.htmlElement.addEventListener('mousedown', captureMousedown.bind(this)); - - this.updatePosition(); - this.updateButtons(true); - } - - isShown() { - return !!this.htmlElement && window.getComputedStyle(this.htmlElement).display !== "none"; - } - - /** - * Updates the position of the command bar tooltip. It aligns itself above the topmost selection in the editor. - */ - updatePosition() { - if (!this.editor) { - return; - } - var renderer = this.editor.renderer; - - var ranges; - if (this.editor.selection.getAllRanges) { - ranges = this.editor.selection.getAllRanges(); - } else { - ranges = [this.editor.getSelection()]; - } - if (!ranges.length) { - return; - } - var minPos = minPosition(ranges[0].start, ranges[0].end); - for (var i = 0, range; range = ranges[i]; i++) { - minPos = minPosition(minPos, minPosition(range.start, range.end)); - } - - var pos = renderer.$cursorLayer.getPixelPosition(minPos, true); - - var el = this.htmlElement; - var screenWidth = window.innerWidth; - var rect = this.editor.container.getBoundingClientRect(); - - pos.top += rect.top - renderer.layerConfig.offset; - pos.left += rect.left - this.editor.renderer.scrollLeft; - pos.left += renderer.gutterWidth; - - var top = pos.top - el.offsetHeight; - - el.style.top = top + "px"; - el.style.bottom = ""; - el.style.left = Math.min(screenWidth - el.offsetWidth, pos.left) + "px"; - } - - /** - * Updates the buttons in the command bar tooltip. Should be called every time when any of the buttons can become disabled or enabled. - */ - updateButtons(force) { - Object.keys(this.buttons).forEach(function(key) { - var commandEnabled = this.commands[key].enabled; - if (typeof commandEnabled === 'function') { - commandEnabled = commandEnabled(this.editor); - } - - if (commandEnabled && (force || !this.eventListeners[key])) { - this.buttons[key].className = BUTTON_CLASS_NAME; - this.buttons[key].ariaDisabled = this.buttons[key].disabled = false; - this.buttons[key].removeAttribute("disabled"); - var eventListener = function(e) { - this.commands[key].exec(this.editor); - e.preventDefault(); - }.bind(this); - this.eventListeners[key] = eventListener; - this.buttons[key].addEventListener('mousedown', eventListener); - } - if (!commandEnabled && (force || this.eventListeners[key])) { - this.buttons[key].className = BUTTON_CLASS_NAME + "_disabled"; - this.buttons[key].ariaDisabled = this.buttons[key].disabled = true; - this.buttons[key].setAttribute("disabled", ""); - this.buttons[key].removeEventListener('mousedown', this.eventListeners[key]); - delete this.eventListeners[key]; - } - }.bind(this)); - } - - detach() { - var listenerKeys = Object.keys(this.eventListeners); - if (this.eventListeners && listenerKeys.length) { - listenerKeys.forEach(function(key) { - this.buttons[key].removeEventListener('mousedown', this.eventListeners[key]); - delete this.eventListeners[key]; - }.bind(this)); - } - if (this.htmlElement) { - this.htmlElement.removeEventListener('mousedown', captureMousedown.bind(this)); - this.htmlElement.style.display = 'none'; - } - } - - destroy() { - this.detach(); - if (this.htmlElement) { - this.htmlElement.parentNode.removeChild(this.htmlElement); - } - this.editor = null; - this.buttons = null; - this.htmlElement = null; - this.controls = null; - } -} - -var captureMousedown = function(e) { - e.preventDefault(); +InlineAutocomplete.createInlineTooltip = function(parentEl) { + var inlineTooltip = new CommandBarTooltip(parentEl); + inlineTooltip.registerCommand("Previous", + Object.assign({}, InlineAutocomplete.prototype.commands["Previous"], { + enabled: true, + type: "button", + iconCssClass: "ace_arrow_rotated" + }) + ); + inlineTooltip.registerCommand("Position", { + enabled: false, + getValue: function(editor) { + return editor ? [editor.completer.getIndex() + 1, editor.completer.getLength()].join("/") : ""; + }, + type: "text", + cssClass: "completion_position" + }); + inlineTooltip.registerCommand("Next", + Object.assign({}, InlineAutocomplete.prototype.commands["Next"], { + enabled: true, + type: "button", + iconCssClass: "ace_arrow" + }) + ); + inlineTooltip.registerCommand("Accept", + Object.assign({}, InlineAutocomplete.prototype.commands["Accept"], { + enabled: function(editor) { + return !!editor && editor.completer.getIndex() >= 0; + }, + type: "button" + }) + ); + inlineTooltip.registerCommand("ShowTooltip", { + name: "Always Show Tooltip", + exec: function() { + inlineTooltip.setAlwaysShow(!inlineTooltip.getAlwaysShow()); + }, + enabled: true, + getValue: function() { + return inlineTooltip.getAlwaysShow(); + }, + type: "checkbox" + }); + return inlineTooltip; }; dom.importCssString(` -.ace_inline_autocomplete_tooltip { - display: inline-block; -} -.${ENTRY_CLASS_NAME} { - display: inline-block; - padding: 0 5px; -} -.${BUTTON_CLASS_NAME} { - display: inline-block; - cursor: pointer; - padding: 5px; +.ace_icon_svg.ace_arrow, +.ace_icon_svg.ace_arrow_rotated { + -webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTUuODM3MDEgMTVMNC41ODc1MSAxMy43MTU1TDEwLjE0NjggOEw0LjU4NzUxIDIuMjg0NDZMNS44MzcwMSAxTDEyLjY0NjUgOEw1LjgzNzAxIDE1WiIgZmlsbD0iYmxhY2siLz48L3N2Zz4="); } -.${BUTTON_CLASS_NAME}:hover { - background-color: rgba(0, 0, 0, 0.1); +.ace_icon_svg.ace_arrow_rotated { + transform: rotate(180deg); } -div.${BUTTON_CLASS_NAME}_disabled { - display: inline-block; - padding: 5px; - cursor: default; - color: #777; -}`, "inlinetooltip.css", false); +div.${BUTTON_CLASS_NAME}.completion_position { + padding: 0; +} +`, "inlineautocomplete.css", false); exports.InlineAutocomplete = InlineAutocomplete; -exports.InlineTooltip = InlineTooltip; -exports.TOOLTIP_ID = TOOLTIP_ID; -exports.BUTTON_CLASS_NAME = BUTTON_CLASS_NAME; diff --git a/src/ext/inline_autocomplete_test.js b/src/ext/inline_autocomplete_test.js index 3bdcea986e1..ae97bad367c 100644 --- a/src/ext/inline_autocomplete_test.js +++ b/src/ext/inline_autocomplete_test.js @@ -9,12 +9,21 @@ if (typeof process !== "undefined") { var Editor = require("../editor").Editor; var EditSession = require("../edit_session").EditSession; var InlineAutocomplete = require("./inline_autocomplete").InlineAutocomplete; +const { Autocomplete } = require("../autocomplete"); var assert = require("../test/assertions"); +var BUTTON_CLASS_NAME = require("./command_bar").BUTTON_CLASS_NAME; var type = require("../test/user").type; var VirtualRenderer = require("../virtual_renderer").VirtualRenderer; var editor; var autocomplete; +var inlineTooltip; +var wrapperEl; + +function simulateClick(node) { + node.dispatchEvent(new window.CustomEvent("click", { bubbles: true })); +} + var getAllLines = function() { var text = Array.from(editor.renderer.$textLayer.element.childNodes).map(function (node) { @@ -61,22 +70,36 @@ var mockCompleter = { } }; +var setupInlineTooltip = function() { + inlineTooltip = autocomplete.getInlineTooltip(); + inlineTooltip.setAlwaysShow(true); + // Workaround: non-standard width and height hints for mock dom (mock dom does not work well with flex elements) + // When running in the browser, these are ignored + inlineTooltip.tooltip.getElement().style.widthHint = 150; + inlineTooltip.tooltip.getElement().style.heightHint = editor.renderer.lineHeight * 2; + inlineTooltip.moreOptions.getElement().style.widthHint = 150; + inlineTooltip.moreOptions.getElement().style.heightHint = editor.renderer.lineHeight * 2; +}; + module.exports = { setUp: function(done) { - var el = document.createElement("div"); - el.style.left = "20px"; - el.style.top = "30px"; - el.style.width = "500px"; - el.style.height = "500px"; - document.body.appendChild(el); - var renderer = new VirtualRenderer(el); + wrapperEl = document.createElement("div"); + wrapperEl.style.position = "fixed"; + wrapperEl.style.left = "400px"; + wrapperEl.style.top = "30px"; + wrapperEl.style.width = "500px"; + wrapperEl.style.height = "500px"; + document.body.appendChild(wrapperEl); + var renderer = new VirtualRenderer(wrapperEl); var session = new EditSession(""); editor = new Editor(renderer, session); + editor.setOption("enableInlineAutocompletion", true); editor.execCommand("insertstring", "f"); editor.getSelection().moveCursorFileEnd(); editor.renderer.$loop._flush(); editor.completers = [mockCompleter]; autocomplete = InlineAutocomplete.for(editor); + setupInlineTooltip(); editor.focus(); done(); }, @@ -88,17 +111,48 @@ module.exports = { assert.strictEqual(getAllLines(), "foo"); done(); }, - "test: autocomplete tooltip is shown according to the selected option": function(done) { - assert.equal(autocomplete.inlineTooltip, null); + "test: autocomplete start keybinding works": function(done) { + type("Alt-C"); + assert.strictEqual(autocomplete.isOpen(), true); + assert.strictEqual(autocomplete.getIndex(), 0); + assert.strictEqual(autocomplete.getData().value, "foo"); + editor.renderer.$loop._flush(); + assert.strictEqual(getAllLines(), "foo"); + autocomplete.detach(); + editor.setOption("enableInlineAutocompletion", false); + + type("Alt-C"); + assert.strictEqual(autocomplete.isOpen(), false); + assert.strictEqual(autocomplete.getIndex(), -1); + editor.renderer.$loop._flush(); + assert.strictEqual(getAllLines(), "f"); + + done(); + }, + "test: replaces different autocomplete implementation for the editor when opened": function(done) { + var completer = Autocomplete.for(editor); + completer.showPopup(editor, {}); + assert.strictEqual(editor.completer, completer); + assert.strictEqual(autocomplete.isOpen(), false); + + autocomplete = InlineAutocomplete.for(editor); + autocomplete.show(editor); + assert.strictEqual(editor.completer.isOpen(), true); + editor.renderer.$loop._flush(); + assert.strictEqual(getAllLines(), "foo"); + + done(); + }, + "test: autocomplete tooltip is shown according to the selected option": function(done) { autocomplete.show(editor); - assert.strictEqual(autocomplete.inlineTooltip.isShown(), true); + assert.strictEqual(inlineTooltip.isShown(), true); autocomplete.detach(); - assert.strictEqual(autocomplete.inlineTooltip.isShown(), false); + assert.strictEqual(inlineTooltip.isShown(), false); done(); }, - "test: autocomplete navigation works": function(done) { + "test: autocomplete keyboard navigation works": function(done) { autocomplete.show(editor); editor.renderer.$loop._flush(); assert.strictEqual(autocomplete.getIndex(), 0); @@ -118,6 +172,69 @@ module.exports = { assert.equal(getAllLines(), "foo"); done(); }, + "test: autocomplete tooltip navigation works": function(done) { + autocomplete.show(editor); + assert.strictEqual(autocomplete.getInlineTooltip().isShown(), true); + + editor.renderer.$loop._flush(); + assert.strictEqual(autocomplete.getIndex(), 0); + assert.strictEqual(autocomplete.getData().value, "foo"); + assert.strictEqual(getAllLines(), "foo"); + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + + var prevButton = buttonElements[0]; + var nextButton = buttonElements[2]; + + simulateClick(prevButton); + + editor.renderer.$loop._flush(); + assert.strictEqual(autocomplete.getIndex(), 5); + assert.strictEqual(autocomplete.getData().value, "fundraiser"); + assert.strictEqual(getAllLines(), "fundraiser"); + + simulateClick(nextButton); + + editor.renderer.$loop._flush(); + assert.strictEqual(autocomplete.getIndex(), 0); + assert.strictEqual(autocomplete.getData().value, "foo"); + assert.strictEqual(getAllLines(), "foo"); + + simulateClick(nextButton); + + editor.renderer.$loop._flush(); + assert.strictEqual(autocomplete.getIndex(), 1); + assert.strictEqual(autocomplete.getData().value, "foobar"); + assert.strictEqual(getAllLines(), "foobar"); + + autocomplete.setIndex(5); + editor.renderer.$loop._flush(); + assert.strictEqual(autocomplete.getData().value, "fundraiser"); + assert.equal(getAllLines(), "fundraiser"); + + simulateClick(nextButton); + + editor.renderer.$loop._flush(); + assert.strictEqual(autocomplete.getIndex(), 0); + assert.strictEqual(autocomplete.getData().value, "foo"); + assert.strictEqual(getAllLines(), "foo"); + + simulateClick(prevButton); + + editor.renderer.$loop._flush(); + assert.strictEqual(autocomplete.getIndex(), 5); + assert.strictEqual(autocomplete.getData().value, "fundraiser"); + assert.strictEqual(getAllLines(), "fundraiser"); + + simulateClick(prevButton); + + editor.renderer.$loop._flush(); + assert.strictEqual(autocomplete.getIndex(), 4); + assert.strictEqual(autocomplete.getData().value, "function"); + assert.strictEqual(getAllLines(), "function"); + + done(); + }, "test: verify goTo commands": function(done) { autocomplete.show(editor); autocomplete.setIndex(1); @@ -145,9 +262,14 @@ module.exports = { autocomplete.goTo("next"); editor.renderer.$loop._flush(); - assert.strictEqual(autocomplete.getIndex(), 5); + assert.strictEqual(autocomplete.getIndex(), 0); + assert.strictEqual(autocomplete.getData().value, "foo"); + assert.strictEqual(getAllLines(), "foo"); + + autocomplete.setIndex(5); + editor.renderer.$loop._flush(); assert.strictEqual(autocomplete.getData().value, "fundraiser"); - assert.strictEqual(getAllLines(), "fundraiser"); + assert.equal(getAllLines(), "fundraiser"); autocomplete.goTo("first"); editor.renderer.$loop._flush(); @@ -157,9 +279,9 @@ module.exports = { autocomplete.goTo("prev"); editor.renderer.$loop._flush(); - assert.strictEqual(autocomplete.getIndex(), 0); - assert.strictEqual(autocomplete.getData().value, "foo"); - assert.strictEqual(getAllLines(), "foo"); + assert.strictEqual(autocomplete.getIndex(), 5); + assert.strictEqual(autocomplete.getData().value, "fundraiser"); + assert.strictEqual(getAllLines(), "fundraiser"); done(); }, "test: set index to negative value hides suggestions": function(done) { @@ -204,6 +326,29 @@ module.exports = { assert.strictEqual(getAllLines(), "foo"); done(); }, + "test: autocomplete can be accepted via tooltip": function(done) { + autocomplete.show(editor); + editor.renderer.$loop._flush(); + assert.strictEqual(autocomplete.isOpen(), true); + assert.equal(autocomplete.inlineTooltip.isShown(), true); + assert.ok(document.querySelectorAll(".ace_ghost_text").length > 0); + assert.strictEqual(getAllLines(), "foo"); + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + var acceptButton = buttonElements[3]; + + simulateClick(acceptButton); + + editor.renderer.$loop._flush(); + assert.equal(autocomplete.inlineCompleter, null); + assert.equal(autocomplete.inlineTooltip.isShown(), false); + assert.strictEqual(autocomplete.isOpen(), false); + assert.equal(editor.renderer.$ghostText, null); + assert.equal(editor.renderer.$ghostTextWidget, null); + assert.strictEqual(document.querySelectorAll(".ace_ghost_text").length, 0); + assert.strictEqual(getAllLines(), "foo"); + done(); + }, "test: incremental typing filters results": function(done) { autocomplete.show(editor); editor.renderer.$loop._flush(); @@ -232,6 +377,48 @@ module.exports = { done(); }, + "test: tooltip stays open on incremental typing": function(done) { + autocomplete.show(editor); + assert.strictEqual(inlineTooltip.isShown(), true); + editor.renderer.$loop._flush(); + assert.strictEqual(autocomplete.isOpen(), true); + assert.equal(getAllLines(), "foo"); + typeAndChange("u", "n"); + editor.renderer.$loop._flush(); + assert.strictEqual(autocomplete.isOpen(), true); + assert.strictEqual(inlineTooltip.isShown(), true); + done(); + }, + "test: can toggle tooltip display mode via tooltip button": function(done) { + autocomplete.show(editor); + assert.strictEqual(inlineTooltip.isShown(), true); + + var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); + var moreOptionsButton = buttonElements[4]; + var showTooltipToggle = buttonElements[5]; + var showTooltipToggleCheckMark = showTooltipToggle.firstChild; + + assert.strictEqual(showTooltipToggle.ariaChecked.toString(), "true"); + assert.strictEqual(showTooltipToggleCheckMark.classList.contains("ace_checkmark"), true); + assert.strictEqual(inlineTooltip.getAlwaysShow(), true); + assert.strictEqual(inlineTooltip.isMoreOptionsShown(), false); + + simulateClick(moreOptionsButton); + + assert.strictEqual(inlineTooltip.isShown(), true); + assert.strictEqual(showTooltipToggle.ariaChecked.toString(), "true"); + assert.strictEqual(showTooltipToggleCheckMark.classList.contains("ace_checkmark"), true); + assert.strictEqual(inlineTooltip.getAlwaysShow(), true); + assert.strictEqual(inlineTooltip.isMoreOptionsShown(), true); + + simulateClick(showTooltipToggle); + + assert.strictEqual(showTooltipToggle.ariaChecked.toString(), "false"); + assert.strictEqual(showTooltipToggleCheckMark.classList.contains("ace_checkmark"), false); + assert.strictEqual(inlineTooltip.getAlwaysShow(), false); + assert.strictEqual(inlineTooltip.isMoreOptionsShown(), false); + done(); + }, "test: verify detach": function(done) { autocomplete.show(editor); editor.renderer.$loop._flush(); @@ -274,9 +461,11 @@ module.exports = { editor.renderer.$loop._flush(); done(); }, + tearDown: function() { autocomplete.destroy(); editor.destroy(); + wrapperEl.parentElement.removeChild(wrapperEl); } }; diff --git a/src/ext/inline_autocomplete_tooltip_test.js b/src/ext/inline_autocomplete_tooltip_test.js deleted file mode 100644 index bee40330e0c..00000000000 --- a/src/ext/inline_autocomplete_tooltip_test.js +++ /dev/null @@ -1,174 +0,0 @@ -if (typeof process !== "undefined") { - require("amd-loader"); - require("../test/mockdom"); -} - -"use strict"; - -var TOOLTIP_ID = require("./inline_autocomplete").TOOLTIP_ID; -var BUTTON_CLASS_NAME = require("./inline_autocomplete").BUTTON_CLASS_NAME; -var InlineTooltip = require("./inline_autocomplete").InlineTooltip; -var Editor = require("../ace").Editor; -var EditSession = require("../ace").EditSession; -var VirtualRenderer = require("../ace").VirtualRenderer; -var assert = require("../test/assertions"); - -function mousedown(node) { - node.dispatchEvent(new window.CustomEvent("mousedown", { bubbles: true })); -} - -var editor; -var counters = {}; -var inlineTooltip; -var testCommand2Enabled = true; -var commands = { - "testCommand1": { - name: "testCommand1", - bindKey: "Alt-K", - exec: function(editor) { - if (!editor) { - return; - } - if (!counters["testCommand1"]) { - counters["testCommand1"] = 0; - } - counters["testCommand1"]++; - }, - enabled: function(editor) { - if (!editor) { - return; - } - if (!counters["testEnabled1"]) { - counters["testEnabled1"] = 0; - } - counters["testEnabled1"]++; - return true; - }, - position: 10 - }, - "testCommand2": { - name: "testCommand2", - bindKey: "Alt-L", - exec: function(editor) { - if (!editor) { - return; - } - if (!counters["testCommand2"]) { - counters["testCommand2"] = 0; - } - counters["testCommand2"]++; - }, - enabled: function(editor) { - if (!editor) { - return; - } - if (!counters["testEnabled2"]) { - counters["testEnabled2"] = 0; - } - counters["testEnabled2"]++; - return testCommand2Enabled; - }, - position: 20 - } -}; - -module.exports = { - setUp: function() { - var el = document.createElement("div"); - el.style.left = "20px"; - el.style.top = "30px"; - el.style.width = "500px"; - el.style.height = "500px"; - document.body.appendChild(el); - var renderer = new VirtualRenderer(el); - var session = new EditSession("abc123\n\nfunc"); - editor = new Editor(renderer, session); - counters = {}; - inlineTooltip = new InlineTooltip(editor, document.body); - inlineTooltip.setCommands(commands); - testCommand2Enabled = true; - editor.getSelection().moveCursorFileEnd(); - editor.renderer.$loop._flush(); - }, - "test: displays inline tooltip above cursor with commands": function(done) { - var tooltipDomElement = document.getElementById(TOOLTIP_ID); - assert.strictEqual(inlineTooltip.isShown(), false); - assert.strictEqual(window.getComputedStyle(tooltipDomElement).display, "none"); - - inlineTooltip.show(editor); - tooltipDomElement = document.getElementById(TOOLTIP_ID); - assert.strictEqual(window.getComputedStyle(tooltipDomElement).display, ""); - assert.strictEqual(inlineTooltip.isShown(), true); - done(); - }, - "test: commands are clickable": function(done) { - inlineTooltip.show(editor); - assert.strictEqual(inlineTooltip.isShown(), true); - assert.strictEqual(counters["testCommand1"], undefined); - var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); - assert.strictEqual(buttonElements.length, 2); - mousedown(buttonElements[0]); - mousedown(buttonElements[1]); - assert.strictEqual(counters["testCommand1"], 1); - done(); - }, - "test: commands are disabled when enable check is falsy": function(done) { - inlineTooltip.show(editor); - var buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); - var disabledButtonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME + "_disabled")); - assert.strictEqual(buttonElements.length, 2); - assert.strictEqual(disabledButtonElements.length, 0); - assert.strictEqual(buttonElements.filter(function (button) { return !button.disabled; }).length, 2); - assert.strictEqual(counters["testEnabled1"], 1); - assert.strictEqual(counters["testEnabled2"], 1); - - testCommand2Enabled = false; - inlineTooltip.updateButtons(); - buttonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME)); - disabledButtonElements = Array.from(document.querySelectorAll("." + BUTTON_CLASS_NAME + "_disabled")); - assert.strictEqual(buttonElements.length, 1); - assert.strictEqual(disabledButtonElements.length, 1); - assert.strictEqual(disabledButtonElements.filter(function (button) { return button.disabled; }).length, 1); - assert.strictEqual(buttonElements.filter(function (button) { return !button.disabled; }).length, 1); - assert.strictEqual(counters["testEnabled1"], 2); - assert.strictEqual(counters["testEnabled2"], 2); - done(); - }, - "test: verify detach": function(done) { - inlineTooltip.show(editor); - var tooltipDomElement = document.getElementById(TOOLTIP_ID); - assert.strictEqual(inlineTooltip.isShown(), true); - - inlineTooltip.detach(); - assert.strictEqual(inlineTooltip.isShown(), false); - var tooltipDomElement = document.getElementById(TOOLTIP_ID); - assert.strictEqual(window.getComputedStyle(tooltipDomElement).display, "none"); - done(); - }, - "test: verify destroy": function(done) { - inlineTooltip.show(editor); - var tooltipDomElement = document.getElementById(TOOLTIP_ID); - assert.strictEqual(inlineTooltip.isShown(), true); - assert.ok(tooltipDomElement); - - inlineTooltip.destroy(); - assert.strictEqual(inlineTooltip.isShown(), false); - tooltipDomElement = document.getElementById(TOOLTIP_ID); - assert.equal(tooltipDomElement, null); - - // Intentionally called twice - inlineTooltip.destroy(); - assert.strictEqual(inlineTooltip.isShown(), false); - tooltipDomElement = document.getElementById(TOOLTIP_ID); - assert.equal(tooltipDomElement, null); - done(); - }, - tearDown: function() { - inlineTooltip.destroy(); - editor.destroy(); - } -}; - -if (typeof module !== "undefined" && module === require.main) { - require("asyncjs").test.testcase(module.exports).exec(); -} diff --git a/src/test/all_browser.js b/src/test/all_browser.js index 6108b025644..989e76ce48f 100644 --- a/src/test/all_browser.js +++ b/src/test/all_browser.js @@ -25,9 +25,9 @@ var testNames = [ "ace/editor_navigation_test", "ace/editor_text_edit_test", "ace/editor_commands_test", + "ace/ext/command_bar_test", "ace/ext/hardwrap_test", "ace/ext/inline_autocomplete_test", - "ace/ext/inline_autocomplete_tooltip_test", "ace/ext/static_highlight_test", "ace/ext/whitespace_test", "ace/ext/error_marker_test", diff --git a/src/test/mockdom.js b/src/test/mockdom.js index aeb4c02eba7..c36b9892b05 100644 --- a/src/test/mockdom.js +++ b/src/test/mockdom.js @@ -375,11 +375,15 @@ function Node(name) { if (this.style.width) width = parseCssLength(this.style.width || "100%", rect.width); + else if (this.style.widthHint) + width = this.style.widthHint; else width = rect.width - right - left; if (this.style.height) height = parseCssLength(this.style.height || "100%", rect.height); + else if (this.style.heightHint) + height = this.style.heightHint; else height = rect.height - top - bottom; From 2c8f232c4b96d72de1cf5463f14f3cd2f47254b5 Mon Sep 17 00:00:00 2001 From: Sergey Kazantsev Date: Wed, 10 May 2023 14:41:07 +0200 Subject: [PATCH 0806/1293] Updated jquery and fixed the fork me ribbon on the ace website (#5161) * Updated jquery on the ace website * fixed the fork me ribbon on the ace website --------- Co-authored-by: Sergey Kazantsev --- doc/template/resources/javascripts/bbq.js | 4 ++-- index.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/template/resources/javascripts/bbq.js b/doc/template/resources/javascripts/bbq.js index bcbf24834ac..52785b47767 100644 --- a/doc/template/resources/javascripts/bbq.js +++ b/doc/template/resources/javascripts/bbq.js @@ -8,11 +8,11 @@ */ (function($,p){var i,m=Array.prototype.slice,r=decodeURIComponent,a=$.param,c,l,v,b=$.bbq=$.bbq||{},q,u,j,e=$.event.special,d="hashchange",A="querystring",D="fragment",y="elemUrlAttr",g="location",k="href",t="src",x=/^.*\?|#.*$/g,w=/^.*\#/,h,C={};function E(F){return typeof F==="string"}function B(G){var F=m.call(arguments,1);return function(){return G.apply(this,F.concat(m.call(arguments)))}}function n(F){return F.replace(/^[^#]*#?(.*)$/,"$1")}function o(F){return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(H,M,F,I,G){var O,L,K,N,J;if(I!==i){K=F.match(H?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);J=K[3]||"";if(G===2&&E(I)){L=I.replace(H?w:x,"")}else{N=l(K[2]);I=E(I)?l[H?D:A](I):I;L=G===2?I:G===1?$.extend({},I,N):$.extend({},N,I);L=a(L);if(H){L=L.replace(h,r)}}O=K[1]+(H?"#":L||!K[1]?"?":"")+L+J}else{O=M(F!==i?F:p[g][k])}return O}a[A]=B(f,0,o);a[D]=c=B(f,1,n);c.noEscape=function(G){G=G||"";var F=$.map(G.split(""),encodeURIComponent);h=new RegExp(F.join("|"),"g")};c.noEscape(",/");$.deparam=l=function(I,F){var H={},G={"true":!0,"false":!1,"null":null};$.each(I.replace(/\+/g," ").split("&"),function(L,Q){var K=Q.split("="),P=r(K[0]),J,O=H,M=0,R=P.split("]["),N=R.length-1;if(/\[/.test(R[0])&&/\]$/.test(R[N])){R[N]=R[N].replace(/\]$/,"");R=R.shift().split("[").concat(R);N=R.length-1}else{N=0}if(K.length===2){J=r(K[1]);if(F){J=J&&!isNaN(J)?+J:J==="undefined"?i:G[J]!==i?G[J]:J}if(N){for(;M<=N;M++){P=R[M]===""?O.length:R[M];O=O[P]=M').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this); \ No newline at end of file +(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}/msie/.test(navigator.userAgent.toLowerCase())&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$(' - + +

    From 78a28b91f5c48d510e9f31704e000adcfaf47826 Mon Sep 17 00:00:00 2001 From: nlujjawal <164378643+nlujjawal@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:25:43 +0200 Subject: [PATCH 1162/1293] Moving open source scripts and css loaded for doc website using external sources to github repo static files. --- doc/site/css/bootstrap.no-icons.min.css | 724 +++++++++++ doc/site/css/font-awesome.css | 1479 +++++++++++++++++++++++ doc/site/js/bootstrap.min.js | 7 + doc/site/js/jquery.min.js | 2 + index.html | 8 +- 5 files changed, 2216 insertions(+), 4 deletions(-) create mode 100644 doc/site/css/bootstrap.no-icons.min.css create mode 100644 doc/site/css/font-awesome.css create mode 100644 doc/site/js/bootstrap.min.js create mode 100644 doc/site/js/jquery.min.js diff --git a/doc/site/css/bootstrap.no-icons.min.css b/doc/site/css/bootstrap.no-icons.min.css new file mode 100644 index 00000000000..a0f5e16ca27 --- /dev/null +++ b/doc/site/css/bootstrap.no-icons.min.css @@ -0,0 +1,724 @@ +/*! + * Bootstrap v2.3.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + .clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;} + .clearfix:after{clear:both;} + .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;} + .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} + article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} + audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} + audio:not([controls]){display:none;} + html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} + a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} + a:hover,a:active{outline:0;} + sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;} + sup{top:-0.5em;} + sub{bottom:-0.25em;} + img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;} + #map_canvas img,.google-maps img{max-width:none;} + button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;} + button,input{*overflow:visible;line-height:normal;} + button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;} + button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;} + label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer;} + input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;} + input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;} + textarea{overflow:auto;vertical-align:top;} + @media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important;} a,a:visited{text-decoration:underline;} a[href]:after{content:" (" attr(href) ")";} abbr[title]:after{content:" (" attr(title) ")";} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:"";} pre,blockquote{border:1px solid #999;page-break-inside:avoid;} thead{display:table-header-group;} tr,img{page-break-inside:avoid;} img{max-width:100% !important;} @page {margin:0.5cm;}p,h2,h3{orphans:3;widows:3;} h2,h3{page-break-after:avoid;}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333333;background-color:#ffffff;} + a{color:#0088cc;text-decoration:none;} + a:hover,a:focus{color:#005580;text-decoration:underline;} + .img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} + .img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);} + .img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px;} + .row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} + .row:after{clear:both;} + [class*="span"]{float:left;min-height:1px;margin-left:20px;} + .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} + .span12{width:940px;} + .span11{width:860px;} + .span10{width:780px;} + .span9{width:700px;} + .span8{width:620px;} + .span7{width:540px;} + .span6{width:460px;} + .span5{width:380px;} + .span4{width:300px;} + .span3{width:220px;} + .span2{width:140px;} + .span1{width:60px;} + .offset12{margin-left:980px;} + .offset11{margin-left:900px;} + .offset10{margin-left:820px;} + .offset9{margin-left:740px;} + .offset8{margin-left:660px;} + .offset7{margin-left:580px;} + .offset6{margin-left:500px;} + .offset5{margin-left:420px;} + .offset4{margin-left:340px;} + .offset3{margin-left:260px;} + .offset2{margin-left:180px;} + .offset1{margin-left:100px;} + .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} + .row-fluid:after{clear:both;} + .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;} + .row-fluid [class*="span"]:first-child{margin-left:0;} + .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%;} + .row-fluid .span12{width:100%;*width:99.94680851063829%;} + .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%;} + .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%;} + .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%;} + .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%;} + .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%;} + .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%;} + .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%;} + .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%;} + .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%;} + .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%;} + .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%;} + .row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%;} + .row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%;} + .row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%;} + .row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%;} + .row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%;} + .row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%;} + .row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%;} + .row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%;} + .row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%;} + .row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%;} + .row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%;} + .row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%;} + .row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%;} + .row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%;} + .row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%;} + .row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%;} + .row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%;} + .row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%;} + .row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%;} + .row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%;} + .row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%;} + .row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%;} + .row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%;} + .row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%;} + [class*="span"].hide,.row-fluid [class*="span"].hide{display:none;} + [class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right;} + .container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";line-height:0;} + .container:after{clear:both;} + .container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0;} + .container-fluid:after{clear:both;} + p{margin:0 0 10px;} + .lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px;} + small{font-size:85%;} + strong{font-weight:bold;} + em{font-style:italic;} + cite{font-style:normal;} + .muted{color:#999999;} + a.muted:hover,a.muted:focus{color:#808080;} + .text-warning{color:#c09853;} + a.text-warning:hover,a.text-warning:focus{color:#a47e3c;} + .text-error{color:#b94a48;} + a.text-error:hover,a.text-error:focus{color:#953b39;} + .text-info{color:#3a87ad;} + a.text-info:hover,a.text-info:focus{color:#2d6987;} + .text-success{color:#468847;} + a.text-success:hover,a.text-success:focus{color:#356635;} + .text-left{text-align:left;} + .text-right{text-align:right;} + .text-center{text-align:center;} + h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999999;} + h1,h2,h3{line-height:40px;} + h1{font-size:38.5px;} + h2{font-size:31.5px;} + h3{font-size:24.5px;} + h4{font-size:17.5px;} + h5{font-size:14px;} + h6{font-size:11.9px;} + h1 small{font-size:24.5px;} + h2 small{font-size:17.5px;} + h3 small{font-size:14px;} + h4 small{font-size:14px;} + .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eeeeee;} + ul,ol{padding:0;margin:0 0 10px 25px;} + ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} + li{line-height:20px;} + ul.unstyled,ol.unstyled{margin-left:0;list-style:none;} + ul.inline,ol.inline{margin-left:0;list-style:none;}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;*zoom:1;padding-left:5px;padding-right:5px;} + dl{margin-bottom:20px;} + dt,dd{line-height:20px;} + dt{font-weight:bold;} + dd{margin-left:10px;} + .dl-horizontal{*zoom:1;}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0;} + .dl-horizontal:after{clear:both;} + .dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;} + .dl-horizontal dd{margin-left:180px;} + hr{margin:20px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;} + abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999;} + abbr.initialism{font-size:90%;text-transform:uppercase;} + blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25;} + blockquote small{display:block;line-height:20px;color:#999999;}blockquote small:before{content:'\2014 \00A0';} + blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;} + blockquote.pull-right small:before{content:'';} + blockquote.pull-right small:after{content:'\00A0 \2014';} + q:before,q:after,blockquote:before,blockquote:after{content:"";} + address{display:block;margin-bottom:20px;font-style:normal;line-height:20px;} + code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} + code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap;} + pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{margin-bottom:20px;} + pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0;} + .pre-scrollable{max-height:340px;overflow-y:scroll;} + .label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#ffffff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;} + .label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} + .badge{padding-left:9px;padding-right:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;} + .label:empty,.badge:empty{display:none;} + a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#ffffff;text-decoration:none;cursor:pointer;} + .label-important,.badge-important{background-color:#b94a48;} + .label-important[href],.badge-important[href]{background-color:#953b39;} + .label-warning,.badge-warning{background-color:#f89406;} + .label-warning[href],.badge-warning[href]{background-color:#c67605;} + .label-success,.badge-success{background-color:#468847;} + .label-success[href],.badge-success[href]{background-color:#356635;} + .label-info,.badge-info{background-color:#3a87ad;} + .label-info[href],.badge-info[href]{background-color:#2d6987;} + .label-inverse,.badge-inverse{background-color:#333333;} + .label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;} + .btn .label,.btn .badge{position:relative;top:-1px;} + .btn-mini .label,.btn-mini .badge{top:0;} + table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;} + .table{width:100%;margin-bottom:20px;}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;} + .table th{font-weight:bold;} + .table thead th{vertical-align:bottom;} + .table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;} + .table tbody+tbody{border-top:2px solid #dddddd;} + .table .table{background-color:#ffffff;} + .table-condensed th,.table-condensed td{padding:4px 5px;} + .table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;} + .table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;} + .table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} + .table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;} + .table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} + .table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} + .table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0;} + .table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomright:0;border-bottom-right-radius:0;} + .table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} + .table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;} + .table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9;} + .table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5;} + table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0;} + .table td.span1,.table th.span1{float:none;width:44px;margin-left:0;} + .table td.span2,.table th.span2{float:none;width:124px;margin-left:0;} + .table td.span3,.table th.span3{float:none;width:204px;margin-left:0;} + .table td.span4,.table th.span4{float:none;width:284px;margin-left:0;} + .table td.span5,.table th.span5{float:none;width:364px;margin-left:0;} + .table td.span6,.table th.span6{float:none;width:444px;margin-left:0;} + .table td.span7,.table th.span7{float:none;width:524px;margin-left:0;} + .table td.span8,.table th.span8{float:none;width:604px;margin-left:0;} + .table td.span9,.table th.span9{float:none;width:684px;margin-left:0;} + .table td.span10,.table th.span10{float:none;width:764px;margin-left:0;} + .table td.span11,.table th.span11{float:none;width:844px;margin-left:0;} + .table td.span12,.table th.span12{float:none;width:924px;margin-left:0;} + .table tbody tr.success>td{background-color:#dff0d8;} + .table tbody tr.error>td{background-color:#f2dede;} + .table tbody tr.warning>td{background-color:#fcf8e3;} + .table tbody tr.info>td{background-color:#d9edf7;} + .table-hover tbody tr.success:hover>td{background-color:#d0e9c6;} + .table-hover tbody tr.error:hover>td{background-color:#ebcccc;} + .table-hover tbody tr.warning:hover>td{background-color:#faf2cc;} + .table-hover tbody tr.info:hover>td{background-color:#c4e3f3;} + form{margin:0 0 20px;} + fieldset{padding:0;margin:0;border:0;} + legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333333;border:0;border-bottom:1px solid #e5e5e5;}legend small{font-size:15px;color:#999999;} + label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px;} + input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;} + label{display:block;margin-bottom:5px;} + select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle;} + input,textarea,.uneditable-input{width:206px;} + textarea{height:auto;} + textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#ffffff;border:1px solid #cccccc;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);} + input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal;} + input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto;} + select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px;} + select{width:220px;border:1px solid #cccccc;background-color:#ffffff;} + select[multiple],select[size]{height:auto;} + select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} + .uneditable-input,.uneditable-textarea{color:#999999;background-color:#fcfcfc;border-color:#cccccc;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} + .uneditable-input{overflow:hidden;white-space:nowrap;} + .uneditable-textarea{width:auto;height:auto;} + input:-moz-placeholder,textarea:-moz-placeholder{color:#999999;} + input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999999;} + input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999999;} + .radio,.checkbox{min-height:20px;padding-left:20px;} + .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px;} + .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} + .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;} + .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} + .input-mini{width:60px;} + .input-small{width:90px;} + .input-medium{width:150px;} + .input-large{width:210px;} + .input-xlarge{width:270px;} + .input-xxlarge{width:530px;} + input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0;} + .input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block;} + input,textarea,.uneditable-input{margin-left:0;} + .controls-row [class*="span"]+[class*="span"]{margin-left:20px;} + input.span12,textarea.span12,.uneditable-input.span12{width:926px;} + input.span11,textarea.span11,.uneditable-input.span11{width:846px;} + input.span10,textarea.span10,.uneditable-input.span10{width:766px;} + input.span9,textarea.span9,.uneditable-input.span9{width:686px;} + input.span8,textarea.span8,.uneditable-input.span8{width:606px;} + input.span7,textarea.span7,.uneditable-input.span7{width:526px;} + input.span6,textarea.span6,.uneditable-input.span6{width:446px;} + input.span5,textarea.span5,.uneditable-input.span5{width:366px;} + input.span4,textarea.span4,.uneditable-input.span4{width:286px;} + input.span3,textarea.span3,.uneditable-input.span3{width:206px;} + input.span2,textarea.span2,.uneditable-input.span2{width:126px;} + input.span1,textarea.span1,.uneditable-input.span1{width:46px;} + .controls-row{*zoom:1;}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0;} + .controls-row:after{clear:both;} + .controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left;} + .controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px;} + input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;} + input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent;} + .control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} + .control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;} + .control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;} + .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} + .control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} + .control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;} + .control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;} + .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} + .control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} + .control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;} + .control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;} + .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} + .control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad;} + .control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad;} + .control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;} + .control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad;} + input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} + .form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0;} + .form-actions:after{clear:both;} + .help-block,.help-inline{color:#595959;} + .help-block{display:block;margin-bottom:10px;} + .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;} + .input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap;}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px;} + .input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2;} + .input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#eeeeee;border:1px solid #ccc;} + .input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} + .input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546;} + .input-prepend .add-on,.input-prepend .btn{margin-right:-1px;} + .input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} + .input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} + .input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px;} + .input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} + .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} + .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} + .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} + .input-prepend.input-append .btn-group:first-child{margin-left:0;} + input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} + .form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} + .form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;} + .form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;} + .form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;} + .form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;} + .form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle;} + .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;} + .form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block;} + .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;} + .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;} + .form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0;} + .control-group{margin-bottom:10px;} + legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate;} + .form-horizontal .control-group{margin-bottom:20px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0;} + .form-horizontal .control-group:after{clear:both;} + .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right;} + .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:180px;} + .form-horizontal .help-block{margin-bottom:0;} + .form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px;} + .form-horizontal .form-actions{padding-left:180px;} + .btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333333;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #cccccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9;} + .btn:active,.btn.active{background-color:#cccccc \9;} + .btn:first-child{*margin-left:0;} + .btn:hover,.btn:focus{color:#333333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} + .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} + .btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);} + .btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} + .btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} + .btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px;} + .btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} + .btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0;} + .btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px;} + .btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} + .btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} + .btn-block+.btn-block{margin-top:5px;} + input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%;} + .btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);} + .btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0044cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;} + .btn-primary:active,.btn-primary.active{background-color:#003399 \9;} + .btn-warning{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505;} + .btn-warning:active,.btn-warning.active{background-color:#c67605 \9;} + .btn-danger{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a;} + .btn-danger:active,.btn-danger.active{background-color:#942a25 \9;} + .btn-success{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249;} + .btn-success:active,.btn-success.active{background-color:#408140 \9;} + .btn-info{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0;} + .btn-info:active,.btn-info.active{background-color:#24748c \9;} + .btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515;} + .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;} + button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;} + button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;} + button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;} + button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;} + .btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} + .btn-link{border-color:transparent;cursor:pointer;color:#0088cc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} + .btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent;} + .btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333333;text-decoration:none;} + .btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em;}.btn-group:first-child{*margin-left:0;} + .btn-group+.btn-group{margin-left:5px;} + .btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px;}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px;} + .btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} + .btn-group>.btn+.btn{margin-left:-1px;} + .btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px;} + .btn-group>.btn-mini{font-size:10.5px;} + .btn-group>.btn-small{font-size:11.9px;} + .btn-group>.btn-large{font-size:17.5px;} + .btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} + .btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} + .btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} + .btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} + .btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;} + .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;} + .btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px;} + .btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px;} + .btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px;} + .btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px;} + .btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);} + .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;} + .btn-group.open .btn-primary.dropdown-toggle{background-color:#0044cc;} + .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;} + .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;} + .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;} + .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;} + .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;} + .btn .caret{margin-top:8px;margin-left:0;} + .btn-large .caret{margin-top:6px;} + .btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px;} + .btn-mini .caret,.btn-small .caret{margin-top:8px;} + .dropup .btn-large .caret{border-bottom-width:5px;} + .btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} + .btn-group-vertical{display:inline-block;*display:inline;*zoom:1;} + .btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} + .btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px;} + .btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;} + .btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;} + .btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0;} + .btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;} + .nav{margin-left:0;margin-bottom:20px;list-style:none;} + .nav>li>a{display:block;} + .nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eeeeee;} + .nav>li>a>img{max-width:none;} + .nav>.pull-right{float:right;} + .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;} + .nav li+.nav-header{margin-top:9px;} + .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;} + .nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} + .nav-list>li>a{padding:3px 15px;} + .nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;} + .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px;} + .nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;} + .nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0;} + .nav-tabs:after,.nav-pills:after{clear:both;} + .nav-tabs>li,.nav-pills>li{float:left;} + .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;} + .nav-tabs{border-bottom:1px solid #ddd;} + .nav-tabs>li{margin-bottom:-1px;} + .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eeeeee #eeeeee #dddddd;} + .nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} + .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} + .nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#ffffff;background-color:#0088cc;} + .nav-stacked>li{float:none;} + .nav-stacked>li>a{margin-right:0;} + .nav-tabs.nav-stacked{border-bottom:0;} + .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} + .nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} + .nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} + .nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2;} + .nav-pills.nav-stacked>li>a{margin-bottom:3px;} + .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;} + .nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;} + .nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} + .nav .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;} + .nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580;} + .nav-tabs .dropdown-toggle .caret{margin-top:8px;} + .nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff;} + .nav-tabs .active .dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;} + .nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer;} + .nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#ffffff;background-color:#999999;border-color:#999999;} + .nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);} + .tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999999;} + .tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0;} + .tabbable:after{clear:both;} + .tab-content{overflow:auto;} + .tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0;} + .tab-content>.tab-pane,.pill-content>.pill-pane{display:none;} + .tab-content>.active,.pill-content>.active{display:block;} + .tabs-below>.nav-tabs{border-top:1px solid #ddd;} + .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0;} + .tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-bottom-color:transparent;border-top-color:#ddd;} + .tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd;} + .tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none;} + .tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;} + .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;} + .tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} + .tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eeeeee #dddddd #eeeeee #eeeeee;} + .tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;} + .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;} + .tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} + .tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eeeeee #eeeeee #eeeeee #dddddd;} + .tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;} + .nav>.disabled>a{color:#999999;} + .nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default;} + .navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2;} + .navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #ffffff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #ffffff, #f2f2f2);background-image:-o-linear-gradient(top, #ffffff, #f2f2f2);background-image:linear-gradient(to bottom, #ffffff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);-moz-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);*zoom:1;}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0;} + .navbar-inner:after{clear:both;} + .navbar .container{width:auto;} + .nav-collapse.collapse{height:auto;overflow:visible;} + .navbar .brand{float:left;display:block;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777777;text-shadow:0 1px 0 #ffffff;}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none;} + .navbar-text{margin-bottom:0;line-height:40px;color:#777777;} + .navbar-link{color:#777777;}.navbar-link:hover,.navbar-link:focus{color:#333333;} + .navbar .divider-vertical{height:40px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #ffffff;} + .navbar .btn,.navbar .btn-group{margin-top:5px;} + .navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0;} + .navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0;} + .navbar-form:after{clear:both;} + .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;} + .navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0;} + .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;} + .navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;} + .navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0;}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} + .navbar-static-top{position:static;margin-bottom:0;}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} + .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;} + .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px;} + .navbar-fixed-bottom .navbar-inner{border-width:1px 0 0;} + .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} + .navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} + .navbar-fixed-top{top:0;} + .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1);} + .navbar-fixed-bottom{bottom:0;}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1);} + .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;} + .navbar .nav.pull-right{float:right;margin-right:0;} + .navbar .nav>li{float:left;} + .navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777777;text-decoration:none;text-shadow:0 1px 0 #ffffff;} + .navbar .nav .dropdown-toggle .caret{margin-top:8px;} + .navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333333;text-decoration:none;} + .navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);-moz-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);} + .navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#ffffff;background-color:#e5e5e5;*background-color:#d9d9d9;} + .navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#cccccc \9;} + .navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);} + .btn-navbar .icon-bar+.icon-bar{margin-top:3px;} + .navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;} + .navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;} + .navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;} + .navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;} + .navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333333;border-bottom-color:#333333;} + .navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555555;} + .navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777777;border-bottom-color:#777777;} + .navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;} + .navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0;}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px;} + .navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px;} + .navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;} + .navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222222, #111111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));background-image:-webkit-linear-gradient(top, #222222, #111111);background-image:-o-linear-gradient(top, #222222, #111111);background-image:linear-gradient(to bottom, #222222, #111111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525;} + .navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999999;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#ffffff;} + .navbar-inverse .brand{color:#999999;} + .navbar-inverse .navbar-text{color:#999999;} + .navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#ffffff;} + .navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#ffffff;background-color:#111111;} + .navbar-inverse .navbar-link{color:#999999;}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#ffffff;} + .navbar-inverse .divider-vertical{border-left-color:#111111;border-right-color:#222222;} + .navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111111;color:#ffffff;} + .navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} + .navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999999;border-bottom-color:#999999;} + .navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} + .navbar-inverse .navbar-search .search-query{color:#ffffff;background-color:#515151;border-color:#111111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none;}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#cccccc;} + .navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#cccccc;} + .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;} + .navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;} + .navbar-inverse .btn-navbar{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#ffffff;background-color:#040404;*background-color:#000000;} + .navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000000 \9;} + .breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.breadcrumb>li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;}.breadcrumb>li>.divider{padding:0 5px;color:#ccc;} + .breadcrumb>.active{color:#999999;} + .pagination{margin:20px 0;} + .pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} + .pagination ul>li{display:inline;} + .pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#ffffff;border:1px solid #dddddd;border-left-width:0;} + .pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5;} + .pagination ul>.active>a,.pagination ul>.active>span{color:#999999;cursor:default;} + .pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999999;background-color:transparent;cursor:default;} + .pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} + .pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} + .pagination-centered{text-align:center;} + .pagination-right{text-align:right;} + .pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px;} + .pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} + .pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} + .pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px;} + .pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px;} + .pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px;} + .pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px;} + .pager{margin:20px 0;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";line-height:0;} + .pager:after{clear:both;} + .pager li{display:inline;} + .pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} + .pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5;} + .pager .next>a,.pager .next>span{float:right;} + .pager .previous>a,.pager .previous>span{float:left;} + .pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999999;background-color:#fff;cursor:default;} + .thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0;} + .thumbnails:after{clear:both;} + .row-fluid .thumbnails{margin-left:0;} + .thumbnails>li{float:left;margin-bottom:20px;margin-left:20px;} + .thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;} + a.thumbnail:hover,a.thumbnail:focus{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} + .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;} + .thumbnail .caption{padding:9px;color:#555555;} + .alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} + .alert,.alert h4{color:#c09853;} + .alert h4{margin:0;} + .alert .close{position:relative;top:-2px;right:-21px;line-height:20px;} + .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;} + .alert-success h4{color:#468847;} + .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;} + .alert-danger h4,.alert-error h4{color:#b94a48;} + .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;} + .alert-info h4{color:#3a87ad;} + .alert-block{padding-top:14px;padding-bottom:14px;} + .alert-block>p,.alert-block>ul{margin-bottom:0;} + .alert-block p+p{margin-top:5px;} + @-webkit-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-o-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} + .progress .bar{width:0%;height:100%;color:#ffffff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;} + .progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);} + .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;} + .progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;} + .progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);} + .progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} + .progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);} + .progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} + .progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);} + .progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} + .progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);} + .progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} + .hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;} + .hero-unit li{line-height:30px;} + .media,.media-body{overflow:hidden;*overflow:visible;zoom:1;} + .media,.media .media{margin-top:15px;} + .media:first-child{margin-top:0;} + .media-object{display:block;} + .media-heading{margin:0 0 5px;} + .media>.pull-left{margin-right:10px;} + .media>.pull-right{margin-left:10px;} + .media-list{margin-left:0;list-style:none;} + .tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);} + .tooltip.top{margin-top:-3px;padding:5px 0;} + .tooltip.right{margin-left:3px;padding:0 5px;} + .tooltip.bottom{margin-top:3px;padding:5px 0;} + .tooltip.left{margin-left:-3px;padding:0 5px;} + .tooltip-inner{max-width:200px;padding:8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} + .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;} + .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000;} + .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000;} + .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000;} + .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000;} + .popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#ffffff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);white-space:normal;}.popover.top{margin-top:-10px;} + .popover.right{margin-left:10px;} + .popover.bottom{margin-top:10px;} + .popover.left{margin-left:-10px;} + .popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}.popover-title:empty{display:none;} + .popover-content{padding:9px 14px;} + .popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid;} + .popover .arrow{border-width:11px;} + .popover .arrow:after{border-width:10px;content:"";} + .popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0, 0, 0, 0.25);bottom:-11px;}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#ffffff;} + .popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0, 0, 0, 0.25);}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#ffffff;} + .popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0, 0, 0, 0.25);top:-11px;}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#ffffff;} + .popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0, 0, 0, 0.25);}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#ffffff;bottom:-10px;} + .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;} + .modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);} + .modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} + .modal.fade.in{top:10%;} + .modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;} + .modal-header h3{margin:0;line-height:30px;} + .modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px;} + .modal-form{margin-bottom:0;} + .modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0;} + .modal-footer:after{clear:both;} + .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;} + .modal-footer .btn-group .btn+.btn{margin-left:-1px;} + .modal-footer .btn-block+.btn-block{margin-left:0;} + .dropup,.dropdown{position:relative;} + .dropdown-toggle{*margin-bottom:-3px;} + .dropdown-toggle:active,.open .dropdown-toggle{outline:0;} + .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";} + .dropdown .caret{margin-top:8px;margin-left:2px;} + .dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#ffffff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;}.dropdown-menu.pull-right{right:0;left:auto;} + .dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;} + .dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333333;white-space:nowrap;} + .dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{text-decoration:none;color:#ffffff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);} + .dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#ffffff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);} + .dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999999;} + .dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default;} + .open{*z-index:1000;}.open>.dropdown-menu{display:block;} + .pull-right>.dropdown-menu{right:0;left:auto;} + .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"";} + .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;} + .dropdown-submenu{position:relative;} + .dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;} + .dropdown-submenu:hover>.dropdown-menu{display:block;} + .dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0;} + .dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#cccccc;margin-top:5px;margin-right:-10px;} + .dropdown-submenu:hover>a:after{border-left-color:#ffffff;} + .dropdown-submenu.pull-left{float:none;}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;} + .dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px;} + .typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} + .accordion{margin-bottom:20px;} + .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} + .accordion-heading{border-bottom:0;} + .accordion-heading .accordion-toggle{display:block;padding:8px 15px;} + .accordion-toggle{cursor:pointer;} + .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;} + .carousel{position:relative;margin-bottom:20px;line-height:1;} + .carousel-inner{overflow:hidden;width:100%;position:relative;} + .carousel-inner>.item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1;} + .carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block;} + .carousel-inner>.active{left:0;} + .carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%;} + .carousel-inner>.next{left:100%;} + .carousel-inner>.prev{left:-100%;} + .carousel-inner>.next.left,.carousel-inner>.prev.right{left:0;} + .carousel-inner>.active.left{left:-100%;} + .carousel-inner>.active.right{left:100%;} + .carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;} + .carousel-control:hover,.carousel-control:focus{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);} + .carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none;}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255, 255, 255, 0.25);border-radius:5px;} + .carousel-indicators .active{background-color:#fff;} + .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333333;background:rgba(0, 0, 0, 0.75);} + .carousel-caption h4,.carousel-caption p{color:#ffffff;line-height:20px;} + .carousel-caption h4{margin:0 0 5px;} + .carousel-caption p{margin-bottom:0;} + .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} + .well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} + .well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} + .close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);} + button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;} + .pull-right{float:right;} + .pull-left{float:left;} + .hide{display:none;} + .show{display:block;} + .invisible{visibility:hidden;} + .affix{position:fixed;} + .fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;}.fade.in{opacity:1;} + .collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;}.collapse.in{height:auto;} \ No newline at end of file diff --git a/doc/site/css/font-awesome.css b/doc/site/css/font-awesome.css new file mode 100644 index 00000000000..89a4b239f27 --- /dev/null +++ b/doc/site/css/font-awesome.css @@ -0,0 +1,1479 @@ +/*! + * Font Awesome 3.2.1 + * the iconic font designed for Bootstrap + * ------------------------------------------------------------------------------ + * The full suite of pictographic icons, examples, and documentation can be + * found at http://fontawesome.io. Stay up to date on Twitter at + * http://twitter.com/fontawesome. + * + * License + * ------------------------------------------------------------------------------ + * - The Font Awesome font is licensed under SIL OFL 1.1 - + * http://scripts.sil.org/OFL + * - Font Awesome CSS, LESS, and SASS files are licensed under MIT License - + * http://opensource.org/licenses/mit-license.html + * - Font Awesome documentation licensed under CC BY 3.0 - + * http://creativecommons.org/licenses/by/3.0/ + * - Attribution is no longer required in Font Awesome 3.0, but much appreciated: + * "Font Awesome by Dave Gandy - http://fontawesome.io" + * + * Author - Dave Gandy + * ------------------------------------------------------------------------------ + * Email: dave@fontawesome.io + * Twitter: http://twitter.com/byscuits + * Work: Lead Product Designer @ Kyruus - http://kyruus.com + */ +/* FONT PATH + * -------------------------- */ + @font-face { + font-family: 'FontAwesome'; + src: url('http://github.com/font/fontawesome-webfont.eot?v=3.2.1'); + src: url('http://github.com/font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('http://github.com/font/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('http://github.com/font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('http://github.com/font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg'); + font-weight: normal; + font-style: normal; +} +/* FONT AWESOME CORE + * -------------------------- */ +[class^="icon-"], +[class*=" icon-"] { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; +} +[class^="icon-"]:before, +[class*=" icon-"]:before { + text-decoration: inherit; + display: inline-block; + speak: none; +} +/* makes the font 33% larger relative to the icon container */ +.icon-large:before { + vertical-align: -10%; + font-size: 1.3333333333333333em; +} +/* makes sure icons active on rollover in links */ +a [class^="icon-"], +a [class*=" icon-"] { + display: inline; +} +/* increased font size for icon-large */ +[class^="icon-"].icon-fixed-width, +[class*=" icon-"].icon-fixed-width { + display: inline-block; + width: 1.1428571428571428em; + text-align: right; + padding-right: 0.2857142857142857em; +} +[class^="icon-"].icon-fixed-width.icon-large, +[class*=" icon-"].icon-fixed-width.icon-large { + width: 1.4285714285714286em; +} +.icons-ul { + margin-left: 2.142857142857143em; + list-style-type: none; +} +.icons-ul > li { + position: relative; +} +.icons-ul .icon-li { + position: absolute; + left: -2.142857142857143em; + width: 2.142857142857143em; + text-align: center; + line-height: inherit; +} +[class^="icon-"].hide, +[class*=" icon-"].hide { + display: none; +} +.icon-muted { + color: #eeeeee; +} +.icon-light { + color: #ffffff; +} +.icon-dark { + color: #333333; +} +.icon-border { + border: solid 1px #eeeeee; + padding: .2em .25em .15em; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.icon-2x { + font-size: 2em; +} +.icon-2x.icon-border { + border-width: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.icon-3x { + font-size: 3em; +} +.icon-3x.icon-border { + border-width: 3px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.icon-4x { + font-size: 4em; +} +.icon-4x.icon-border { + border-width: 4px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.icon-5x { + font-size: 5em; +} +.icon-5x.icon-border { + border-width: 5px; + -webkit-border-radius: 7px; + -moz-border-radius: 7px; + border-radius: 7px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +[class^="icon-"].pull-left, +[class*=" icon-"].pull-left { + margin-right: .3em; +} +[class^="icon-"].pull-right, +[class*=" icon-"].pull-right { + margin-left: .3em; +} +/* BOOTSTRAP SPECIFIC CLASSES + * -------------------------- */ +/* Bootstrap 2.0 sprites.less reset */ +[class^="icon-"], +[class*=" icon-"] { + display: inline; + width: auto; + height: auto; + line-height: normal; + vertical-align: baseline; + background-image: none; + background-position: 0% 0%; + background-repeat: repeat; + margin-top: 0; +} +/* more sprites.less reset */ +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"] { + background-image: none; +} +/* keeps Bootstrap styles with and without icons the same */ +.btn [class^="icon-"].icon-large, +.nav [class^="icon-"].icon-large, +.btn [class*=" icon-"].icon-large, +.nav [class*=" icon-"].icon-large { + line-height: .9em; +} +.btn [class^="icon-"].icon-spin, +.nav [class^="icon-"].icon-spin, +.btn [class*=" icon-"].icon-spin, +.nav [class*=" icon-"].icon-spin { + display: inline-block; +} +.nav-tabs [class^="icon-"], +.nav-pills [class^="icon-"], +.nav-tabs [class*=" icon-"], +.nav-pills [class*=" icon-"], +.nav-tabs [class^="icon-"].icon-large, +.nav-pills [class^="icon-"].icon-large, +.nav-tabs [class*=" icon-"].icon-large, +.nav-pills [class*=" icon-"].icon-large { + line-height: .9em; +} +.btn [class^="icon-"].pull-left.icon-2x, +.btn [class*=" icon-"].pull-left.icon-2x, +.btn [class^="icon-"].pull-right.icon-2x, +.btn [class*=" icon-"].pull-right.icon-2x { + margin-top: .18em; +} +.btn [class^="icon-"].icon-spin.icon-large, +.btn [class*=" icon-"].icon-spin.icon-large { + line-height: .8em; +} +.btn.btn-small [class^="icon-"].pull-left.icon-2x, +.btn.btn-small [class*=" icon-"].pull-left.icon-2x, +.btn.btn-small [class^="icon-"].pull-right.icon-2x, +.btn.btn-small [class*=" icon-"].pull-right.icon-2x { + margin-top: .25em; +} +.btn.btn-large [class^="icon-"], +.btn.btn-large [class*=" icon-"] { + margin-top: 0; +} +.btn.btn-large [class^="icon-"].pull-left.icon-2x, +.btn.btn-large [class*=" icon-"].pull-left.icon-2x, +.btn.btn-large [class^="icon-"].pull-right.icon-2x, +.btn.btn-large [class*=" icon-"].pull-right.icon-2x { + margin-top: .05em; +} +.btn.btn-large [class^="icon-"].pull-left.icon-2x, +.btn.btn-large [class*=" icon-"].pull-left.icon-2x { + margin-right: .2em; +} +.btn.btn-large [class^="icon-"].pull-right.icon-2x, +.btn.btn-large [class*=" icon-"].pull-right.icon-2x { + margin-left: .2em; +} +/* Fixes alignment in nav lists */ +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + line-height: inherit; +} +/* EXTRAS + * -------------------------- */ +/* Stacked and layered icon */ +.icon-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: -35%; +} +.icon-stack [class^="icon-"], +.icon-stack [class*=" icon-"] { + display: block; + text-align: center; + position: absolute; + width: 100%; + height: 100%; + font-size: 1em; + line-height: inherit; + *line-height: 2em; +} +.icon-stack .icon-stack-base { + font-size: 2em; + *line-height: 1em; +} +/* Animated rotating icon */ +.icon-spin { + display: inline-block; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + -webkit-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +/* Prevent stack and spinners from being taken inline when inside a link */ +a .icon-stack, +a .icon-spin { + display: inline-block; + text-decoration: none; +} +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(359deg); + } +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + } +} +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); + } + 100% { + -o-transform: rotate(359deg); + } +} +@-ms-keyframes spin { + 0% { + -ms-transform: rotate(0deg); + } + 100% { + -ms-transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} +/* Icon rotations and mirroring */ +.icon-rotate-90:before { + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + -o-transform: rotate(90deg); + transform: rotate(90deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); +} +.icon-rotate-180:before { + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); +} +.icon-rotate-270:before { + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -o-transform: rotate(270deg); + transform: rotate(270deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); +} +.icon-flip-horizontal:before { + -webkit-transform: scale(-1, 1); + -moz-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + -o-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.icon-flip-vertical:before { + -webkit-transform: scale(1, -1); + -moz-transform: scale(1, -1); + -ms-transform: scale(1, -1); + -o-transform: scale(1, -1); + transform: scale(1, -1); +} +/* ensure rotation occurs inside anchor tags */ +a .icon-rotate-90:before, +a .icon-rotate-180:before, +a .icon-rotate-270:before, +a .icon-flip-horizontal:before, +a .icon-flip-vertical:before { + display: inline-block; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.icon-glass:before { + content: "\f000"; +} +.icon-music:before { + content: "\f001"; +} +.icon-search:before { + content: "\f002"; +} +.icon-envelope-alt:before { + content: "\f003"; +} +.icon-heart:before { + content: "\f004"; +} +.icon-star:before { + content: "\f005"; +} +.icon-star-empty:before { + content: "\f006"; +} +.icon-user:before { + content: "\f007"; +} +.icon-film:before { + content: "\f008"; +} +.icon-th-large:before { + content: "\f009"; +} +.icon-th:before { + content: "\f00a"; +} +.icon-th-list:before { + content: "\f00b"; +} +.icon-ok:before { + content: "\f00c"; +} +.icon-remove:before { + content: "\f00d"; +} +.icon-zoom-in:before { + content: "\f00e"; +} +.icon-zoom-out:before { + content: "\f010"; +} +.icon-power-off:before, +.icon-off:before { + content: "\f011"; +} +.icon-signal:before { + content: "\f012"; +} +.icon-gear:before, +.icon-cog:before { + content: "\f013"; +} +.icon-trash:before { + content: "\f014"; +} +.icon-home:before { + content: "\f015"; +} +.icon-file-alt:before { + content: "\f016"; +} +.icon-time:before { + content: "\f017"; +} +.icon-road:before { + content: "\f018"; +} +.icon-download-alt:before { + content: "\f019"; +} +.icon-download:before { + content: "\f01a"; +} +.icon-upload:before { + content: "\f01b"; +} +.icon-inbox:before { + content: "\f01c"; +} +.icon-play-circle:before { + content: "\f01d"; +} +.icon-rotate-right:before, +.icon-repeat:before { + content: "\f01e"; +} +.icon-refresh:before { + content: "\f021"; +} +.icon-list-alt:before { + content: "\f022"; +} +.icon-lock:before { + content: "\f023"; +} +.icon-flag:before { + content: "\f024"; +} +.icon-headphones:before { + content: "\f025"; +} +.icon-volume-off:before { + content: "\f026"; +} +.icon-volume-down:before { + content: "\f027"; +} +.icon-volume-up:before { + content: "\f028"; +} +.icon-qrcode:before { + content: "\f029"; +} +.icon-barcode:before { + content: "\f02a"; +} +.icon-tag:before { + content: "\f02b"; +} +.icon-tags:before { + content: "\f02c"; +} +.icon-book:before { + content: "\f02d"; +} +.icon-bookmark:before { + content: "\f02e"; +} +.icon-print:before { + content: "\f02f"; +} +.icon-camera:before { + content: "\f030"; +} +.icon-font:before { + content: "\f031"; +} +.icon-bold:before { + content: "\f032"; +} +.icon-italic:before { + content: "\f033"; +} +.icon-text-height:before { + content: "\f034"; +} +.icon-text-width:before { + content: "\f035"; +} +.icon-align-left:before { + content: "\f036"; +} +.icon-align-center:before { + content: "\f037"; +} +.icon-align-right:before { + content: "\f038"; +} +.icon-align-justify:before { + content: "\f039"; +} +.icon-list:before { + content: "\f03a"; +} +.icon-indent-left:before { + content: "\f03b"; +} +.icon-indent-right:before { + content: "\f03c"; +} +.icon-facetime-video:before { + content: "\f03d"; +} +.icon-picture:before { + content: "\f03e"; +} +.icon-pencil:before { + content: "\f040"; +} +.icon-map-marker:before { + content: "\f041"; +} +.icon-adjust:before { + content: "\f042"; +} +.icon-tint:before { + content: "\f043"; +} +.icon-edit:before { + content: "\f044"; +} +.icon-share:before { + content: "\f045"; +} +.icon-check:before { + content: "\f046"; +} +.icon-move:before { + content: "\f047"; +} +.icon-step-backward:before { + content: "\f048"; +} +.icon-fast-backward:before { + content: "\f049"; +} +.icon-backward:before { + content: "\f04a"; +} +.icon-play:before { + content: "\f04b"; +} +.icon-pause:before { + content: "\f04c"; +} +.icon-stop:before { + content: "\f04d"; +} +.icon-forward:before { + content: "\f04e"; +} +.icon-fast-forward:before { + content: "\f050"; +} +.icon-step-forward:before { + content: "\f051"; +} +.icon-eject:before { + content: "\f052"; +} +.icon-chevron-left:before { + content: "\f053"; +} +.icon-chevron-right:before { + content: "\f054"; +} +.icon-plus-sign:before { + content: "\f055"; +} +.icon-minus-sign:before { + content: "\f056"; +} +.icon-remove-sign:before { + content: "\f057"; +} +.icon-ok-sign:before { + content: "\f058"; +} +.icon-question-sign:before { + content: "\f059"; +} +.icon-info-sign:before { + content: "\f05a"; +} +.icon-screenshot:before { + content: "\f05b"; +} +.icon-remove-circle:before { + content: "\f05c"; +} +.icon-ok-circle:before { + content: "\f05d"; +} +.icon-ban-circle:before { + content: "\f05e"; +} +.icon-arrow-left:before { + content: "\f060"; +} +.icon-arrow-right:before { + content: "\f061"; +} +.icon-arrow-up:before { + content: "\f062"; +} +.icon-arrow-down:before { + content: "\f063"; +} +.icon-mail-forward:before, +.icon-share-alt:before { + content: "\f064"; +} +.icon-resize-full:before { + content: "\f065"; +} +.icon-resize-small:before { + content: "\f066"; +} +.icon-plus:before { + content: "\f067"; +} +.icon-minus:before { + content: "\f068"; +} +.icon-asterisk:before { + content: "\f069"; +} +.icon-exclamation-sign:before { + content: "\f06a"; +} +.icon-gift:before { + content: "\f06b"; +} +.icon-leaf:before { + content: "\f06c"; +} +.icon-fire:before { + content: "\f06d"; +} +.icon-eye-open:before { + content: "\f06e"; +} +.icon-eye-close:before { + content: "\f070"; +} +.icon-warning-sign:before { + content: "\f071"; +} +.icon-plane:before { + content: "\f072"; +} +.icon-calendar:before { + content: "\f073"; +} +.icon-random:before { + content: "\f074"; +} +.icon-comment:before { + content: "\f075"; +} +.icon-magnet:before { + content: "\f076"; +} +.icon-chevron-up:before { + content: "\f077"; +} +.icon-chevron-down:before { + content: "\f078"; +} +.icon-retweet:before { + content: "\f079"; +} +.icon-shopping-cart:before { + content: "\f07a"; +} +.icon-folder-close:before { + content: "\f07b"; +} +.icon-folder-open:before { + content: "\f07c"; +} +.icon-resize-vertical:before { + content: "\f07d"; +} +.icon-resize-horizontal:before { + content: "\f07e"; +} +.icon-bar-chart:before { + content: "\f080"; +} +.icon-twitter-sign:before { + content: "\f081"; +} +.icon-facebook-sign:before { + content: "\f082"; +} +.icon-camera-retro:before { + content: "\f083"; +} +.icon-key:before { + content: "\f084"; +} +.icon-gears:before, +.icon-cogs:before { + content: "\f085"; +} +.icon-comments:before { + content: "\f086"; +} +.icon-thumbs-up-alt:before { + content: "\f087"; +} +.icon-thumbs-down-alt:before { + content: "\f088"; +} +.icon-star-half:before { + content: "\f089"; +} +.icon-heart-empty:before { + content: "\f08a"; +} +.icon-signout:before { + content: "\f08b"; +} +.icon-linkedin-sign:before { + content: "\f08c"; +} +.icon-pushpin:before { + content: "\f08d"; +} +.icon-external-link:before { + content: "\f08e"; +} +.icon-signin:before { + content: "\f090"; +} +.icon-trophy:before { + content: "\f091"; +} +.icon-github-sign:before { + content: "\f092"; +} +.icon-upload-alt:before { + content: "\f093"; +} +.icon-lemon:before { + content: "\f094"; +} +.icon-phone:before { + content: "\f095"; +} +.icon-unchecked:before, +.icon-check-empty:before { + content: "\f096"; +} +.icon-bookmark-empty:before { + content: "\f097"; +} +.icon-phone-sign:before { + content: "\f098"; +} +.icon-twitter:before { + content: "\f099"; +} +.icon-facebook:before { + content: "\f09a"; +} +.icon-github:before { + content: "\f09b"; +} +.icon-unlock:before { + content: "\f09c"; +} +.icon-credit-card:before { + content: "\f09d"; +} +.icon-rss:before { + content: "\f09e"; +} +.icon-hdd:before { + content: "\f0a0"; +} +.icon-bullhorn:before { + content: "\f0a1"; +} +.icon-bell:before { + content: "\f0a2"; +} +.icon-certificate:before { + content: "\f0a3"; +} +.icon-hand-right:before { + content: "\f0a4"; +} +.icon-hand-left:before { + content: "\f0a5"; +} +.icon-hand-up:before { + content: "\f0a6"; +} +.icon-hand-down:before { + content: "\f0a7"; +} +.icon-circle-arrow-left:before { + content: "\f0a8"; +} +.icon-circle-arrow-right:before { + content: "\f0a9"; +} +.icon-circle-arrow-up:before { + content: "\f0aa"; +} +.icon-circle-arrow-down:before { + content: "\f0ab"; +} +.icon-globe:before { + content: "\f0ac"; +} +.icon-wrench:before { + content: "\f0ad"; +} +.icon-tasks:before { + content: "\f0ae"; +} +.icon-filter:before { + content: "\f0b0"; +} +.icon-briefcase:before { + content: "\f0b1"; +} +.icon-fullscreen:before { + content: "\f0b2"; +} +.icon-group:before { + content: "\f0c0"; +} +.icon-link:before { + content: "\f0c1"; +} +.icon-cloud:before { + content: "\f0c2"; +} +.icon-beaker:before { + content: "\f0c3"; +} +.icon-cut:before { + content: "\f0c4"; +} +.icon-copy:before { + content: "\f0c5"; +} +.icon-paperclip:before, +.icon-paper-clip:before { + content: "\f0c6"; +} +.icon-save:before { + content: "\f0c7"; +} +.icon-sign-blank:before { + content: "\f0c8"; +} +.icon-reorder:before { + content: "\f0c9"; +} +.icon-list-ul:before { + content: "\f0ca"; +} +.icon-list-ol:before { + content: "\f0cb"; +} +.icon-strikethrough:before { + content: "\f0cc"; +} +.icon-underline:before { + content: "\f0cd"; +} +.icon-table:before { + content: "\f0ce"; +} +.icon-magic:before { + content: "\f0d0"; +} +.icon-truck:before { + content: "\f0d1"; +} +.icon-pinterest:before { + content: "\f0d2"; +} +.icon-pinterest-sign:before { + content: "\f0d3"; +} +.icon-google-plus-sign:before { + content: "\f0d4"; +} +.icon-google-plus:before { + content: "\f0d5"; +} +.icon-money:before { + content: "\f0d6"; +} +.icon-caret-down:before { + content: "\f0d7"; +} +.icon-caret-up:before { + content: "\f0d8"; +} +.icon-caret-left:before { + content: "\f0d9"; +} +.icon-caret-right:before { + content: "\f0da"; +} +.icon-columns:before { + content: "\f0db"; +} +.icon-sort:before { + content: "\f0dc"; +} +.icon-sort-down:before { + content: "\f0dd"; +} +.icon-sort-up:before { + content: "\f0de"; +} +.icon-envelope:before { + content: "\f0e0"; +} +.icon-linkedin:before { + content: "\f0e1"; +} +.icon-rotate-left:before, +.icon-undo:before { + content: "\f0e2"; +} +.icon-legal:before { + content: "\f0e3"; +} +.icon-dashboard:before { + content: "\f0e4"; +} +.icon-comment-alt:before { + content: "\f0e5"; +} +.icon-comments-alt:before { + content: "\f0e6"; +} +.icon-bolt:before { + content: "\f0e7"; +} +.icon-sitemap:before { + content: "\f0e8"; +} +.icon-umbrella:before { + content: "\f0e9"; +} +.icon-paste:before { + content: "\f0ea"; +} +.icon-lightbulb:before { + content: "\f0eb"; +} +.icon-exchange:before { + content: "\f0ec"; +} +.icon-cloud-download:before { + content: "\f0ed"; +} +.icon-cloud-upload:before { + content: "\f0ee"; +} +.icon-user-md:before { + content: "\f0f0"; +} +.icon-stethoscope:before { + content: "\f0f1"; +} +.icon-suitcase:before { + content: "\f0f2"; +} +.icon-bell-alt:before { + content: "\f0f3"; +} +.icon-coffee:before { + content: "\f0f4"; +} +.icon-food:before { + content: "\f0f5"; +} +.icon-file-text-alt:before { + content: "\f0f6"; +} +.icon-building:before { + content: "\f0f7"; +} +.icon-hospital:before { + content: "\f0f8"; +} +.icon-ambulance:before { + content: "\f0f9"; +} +.icon-medkit:before { + content: "\f0fa"; +} +.icon-fighter-jet:before { + content: "\f0fb"; +} +.icon-beer:before { + content: "\f0fc"; +} +.icon-h-sign:before { + content: "\f0fd"; +} +.icon-plus-sign-alt:before { + content: "\f0fe"; +} +.icon-double-angle-left:before { + content: "\f100"; +} +.icon-double-angle-right:before { + content: "\f101"; +} +.icon-double-angle-up:before { + content: "\f102"; +} +.icon-double-angle-down:before { + content: "\f103"; +} +.icon-angle-left:before { + content: "\f104"; +} +.icon-angle-right:before { + content: "\f105"; +} +.icon-angle-up:before { + content: "\f106"; +} +.icon-angle-down:before { + content: "\f107"; +} +.icon-desktop:before { + content: "\f108"; +} +.icon-laptop:before { + content: "\f109"; +} +.icon-tablet:before { + content: "\f10a"; +} +.icon-mobile-phone:before { + content: "\f10b"; +} +.icon-circle-blank:before { + content: "\f10c"; +} +.icon-quote-left:before { + content: "\f10d"; +} +.icon-quote-right:before { + content: "\f10e"; +} +.icon-spinner:before { + content: "\f110"; +} +.icon-circle:before { + content: "\f111"; +} +.icon-mail-reply:before, +.icon-reply:before { + content: "\f112"; +} +.icon-github-alt:before { + content: "\f113"; +} +.icon-folder-close-alt:before { + content: "\f114"; +} +.icon-folder-open-alt:before { + content: "\f115"; +} +.icon-expand-alt:before { + content: "\f116"; +} +.icon-collapse-alt:before { + content: "\f117"; +} +.icon-smile:before { + content: "\f118"; +} +.icon-frown:before { + content: "\f119"; +} +.icon-meh:before { + content: "\f11a"; +} +.icon-gamepad:before { + content: "\f11b"; +} +.icon-keyboard:before { + content: "\f11c"; +} +.icon-flag-alt:before { + content: "\f11d"; +} +.icon-flag-checkered:before { + content: "\f11e"; +} +.icon-terminal:before { + content: "\f120"; +} +.icon-code:before { + content: "\f121"; +} +.icon-reply-all:before { + content: "\f122"; +} +.icon-mail-reply-all:before { + content: "\f122"; +} +.icon-star-half-full:before, +.icon-star-half-empty:before { + content: "\f123"; +} +.icon-location-arrow:before { + content: "\f124"; +} +.icon-crop:before { + content: "\f125"; +} +.icon-code-fork:before { + content: "\f126"; +} +.icon-unlink:before { + content: "\f127"; +} +.icon-question:before { + content: "\f128"; +} +.icon-info:before { + content: "\f129"; +} +.icon-exclamation:before { + content: "\f12a"; +} +.icon-superscript:before { + content: "\f12b"; +} +.icon-subscript:before { + content: "\f12c"; +} +.icon-eraser:before { + content: "\f12d"; +} +.icon-puzzle-piece:before { + content: "\f12e"; +} +.icon-microphone:before { + content: "\f130"; +} +.icon-microphone-off:before { + content: "\f131"; +} +.icon-shield:before { + content: "\f132"; +} +.icon-calendar-empty:before { + content: "\f133"; +} +.icon-fire-extinguisher:before { + content: "\f134"; +} +.icon-rocket:before { + content: "\f135"; +} +.icon-maxcdn:before { + content: "\f136"; +} +.icon-chevron-sign-left:before { + content: "\f137"; +} +.icon-chevron-sign-right:before { + content: "\f138"; +} +.icon-chevron-sign-up:before { + content: "\f139"; +} +.icon-chevron-sign-down:before { + content: "\f13a"; +} +.icon-html5:before { + content: "\f13b"; +} +.icon-css3:before { + content: "\f13c"; +} +.icon-anchor:before { + content: "\f13d"; +} +.icon-unlock-alt:before { + content: "\f13e"; +} +.icon-bullseye:before { + content: "\f140"; +} +.icon-ellipsis-horizontal:before { + content: "\f141"; +} +.icon-ellipsis-vertical:before { + content: "\f142"; +} +.icon-rss-sign:before { + content: "\f143"; +} +.icon-play-sign:before { + content: "\f144"; +} +.icon-ticket:before { + content: "\f145"; +} +.icon-minus-sign-alt:before { + content: "\f146"; +} +.icon-check-minus:before { + content: "\f147"; +} +.icon-level-up:before { + content: "\f148"; +} +.icon-level-down:before { + content: "\f149"; +} +.icon-check-sign:before { + content: "\f14a"; +} +.icon-edit-sign:before { + content: "\f14b"; +} +.icon-external-link-sign:before { + content: "\f14c"; +} +.icon-share-sign:before { + content: "\f14d"; +} +.icon-compass:before { + content: "\f14e"; +} +.icon-collapse:before { + content: "\f150"; +} +.icon-collapse-top:before { + content: "\f151"; +} +.icon-expand:before { + content: "\f152"; +} +.icon-euro:before, +.icon-eur:before { + content: "\f153"; +} +.icon-gbp:before { + content: "\f154"; +} +.icon-dollar:before, +.icon-usd:before { + content: "\f155"; +} +.icon-rupee:before, +.icon-inr:before { + content: "\f156"; +} +.icon-yen:before, +.icon-jpy:before { + content: "\f157"; +} +.icon-renminbi:before, +.icon-cny:before { + content: "\f158"; +} +.icon-won:before, +.icon-krw:before { + content: "\f159"; +} +.icon-bitcoin:before, +.icon-btc:before { + content: "\f15a"; +} +.icon-file:before { + content: "\f15b"; +} +.icon-file-text:before { + content: "\f15c"; +} +.icon-sort-by-alphabet:before { + content: "\f15d"; +} +.icon-sort-by-alphabet-alt:before { + content: "\f15e"; +} +.icon-sort-by-attributes:before { + content: "\f160"; +} +.icon-sort-by-attributes-alt:before { + content: "\f161"; +} +.icon-sort-by-order:before { + content: "\f162"; +} +.icon-sort-by-order-alt:before { + content: "\f163"; +} +.icon-thumbs-up:before { + content: "\f164"; +} +.icon-thumbs-down:before { + content: "\f165"; +} +.icon-youtube-sign:before { + content: "\f166"; +} +.icon-youtube:before { + content: "\f167"; +} +.icon-xing:before { + content: "\f168"; +} +.icon-xing-sign:before { + content: "\f169"; +} +.icon-youtube-play:before { + content: "\f16a"; +} +.icon-dropbox:before { + content: "\f16b"; +} +.icon-stackexchange:before { + content: "\f16c"; +} +.icon-instagram:before { + content: "\f16d"; +} +.icon-flickr:before { + content: "\f16e"; +} +.icon-adn:before { + content: "\f170"; +} +.icon-bitbucket:before { + content: "\f171"; +} +.icon-bitbucket-sign:before { + content: "\f172"; +} +.icon-tumblr:before { + content: "\f173"; +} +.icon-tumblr-sign:before { + content: "\f174"; +} +.icon-long-arrow-down:before { + content: "\f175"; +} +.icon-long-arrow-up:before { + content: "\f176"; +} +.icon-long-arrow-left:before { + content: "\f177"; +} +.icon-long-arrow-right:before { + content: "\f178"; +} +.icon-apple:before { + content: "\f179"; +} +.icon-windows:before { + content: "\f17a"; +} +.icon-android:before { + content: "\f17b"; +} +.icon-linux:before { + content: "\f17c"; +} +.icon-dribbble:before { + content: "\f17d"; +} +.icon-skype:before { + content: "\f17e"; +} +.icon-foursquare:before { + content: "\f180"; +} +.icon-trello:before { + content: "\f181"; +} +.icon-female:before { + content: "\f182"; +} +.icon-male:before { + content: "\f183"; +} +.icon-gittip:before { + content: "\f184"; +} +.icon-sun:before { + content: "\f185"; +} +.icon-moon:before { + content: "\f186"; +} +.icon-archive:before { + content: "\f187"; +} +.icon-bug:before { + content: "\f188"; +} +.icon-vk:before { + content: "\f189"; +} +.icon-weibo:before { + content: "\f18a"; +} +.icon-renren:before { + content: "\f18b"; +} \ No newline at end of file diff --git a/doc/site/js/bootstrap.min.js b/doc/site/js/bootstrap.min.js new file mode 100644 index 00000000000..43d69790efd --- /dev/null +++ b/doc/site/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/** +* Bootstrap.js version 2.3.2 by @fat & @mdo +* plugins: bootstrap-transition.js, bootstrap-modal.js, bootstrap-dropdown.js, bootstrap-scrollspy.js, bootstrap-tab.js, bootstrap-tooltip.js, bootstrap-popover.js, bootstrap-affix.js, bootstrap-alert.js, bootstrap-button.js, bootstrap-collapse.js, bootstrap-carousel.js, bootstrap-typeahead.js +* Copyright 2012 Twitter, Inc. +* http://www.apache.org/licenses/LICENSE-2.0.txt +*/ +!function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.focus().trigger("shown")}):b.$element.focus().trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a(' - - + + From a6ead2fcf2860c8b890f6adbd2e56f2ddc7f6d62 Mon Sep 17 00:00:00 2001 From: nlujjawal Date: Thu, 29 Aug 2024 17:15:52 +0200 Subject: [PATCH 1163/1293] release v1.36.1 --- CHANGELOG.md | 8 ++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09a05c5b5c9..e83d986eb10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.36.1](https://github.com/ajaxorg/ace/compare/v1.36.0...v1.36.1) (2024-08-29) + + +### Bug Fixes + +* improve type getMarkerAtPosition markergroup ([#5631](https://github.com/ajaxorg/ace/issues/5631)) ([89bd40a](https://github.com/ajaxorg/ace/commit/89bd40a66a2f06fb8806f174e5559021540a5b1e)) +* update cloudeditor light colours ([#5633](https://github.com/ajaxorg/ace/issues/5633)) ([0e2813e](https://github.com/ajaxorg/ace/commit/0e2813ed9e858d9359c2a79f2a9255d675308ad1)) + ## [1.36.0](https://github.com/ajaxorg/ace/compare/v1.35.5...v1.36.0) (2024-08-21) diff --git a/build b/build index 3945babc14c..68e4d6e6a9b 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 3945babc14cf72919658c9ca37349d6411e2a94c +Subproject commit 68e4d6e6a9b867c20927bcc31e39330e3f94bc7d diff --git a/package.json b/package.json index c8b5856fb92..f32a55c0a95 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.36.0", + "version": "1.36.1", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 7777216d3a0..848e7763b7e 100644 --- a/src/config.js +++ b/src/config.js @@ -194,6 +194,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.36.0"; +exports.version = "1.36.1"; From c7549aa5d53fb62f134b31a44d09029ceee3c800 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Fri, 30 Aug 2024 16:59:10 +0200 Subject: [PATCH 1164/1293] fix: apply padding to right side multi-line markers (#5636) --- src/layer/marker.js | 4 ++-- src/marker_group_test.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/layer/marker.js b/src/layer/marker.js index 935e1b8a4c4..3307c7b89b9 100644 --- a/src/layer/marker.js +++ b/src/layer/marker.js @@ -165,7 +165,7 @@ class Marker { } else { this.elt( clazz + " ace_br1 ace_start", - "height:"+ height+ "px;"+ "right:0;"+ "top:"+top+ "px;left:"+ left+ "px;" + (extraStyle || "") + "height:"+ height+ "px;"+ "right:" + padding + "px;"+ "top:"+top+ "px;left:"+ left+ "px;" + (extraStyle || "") ); } // from start of the last line to the selection end @@ -197,7 +197,7 @@ class Marker { this.elt( clazz + (radiusClass ? " ace_br" + radiusClass : ""), "height:"+ height+ "px;"+ - "right:0;"+ + "right:" + padding + "px;"+ "top:"+ top+ "px;"+ "left:"+ padding+ "px;"+ (extraStyle || "") ); diff --git a/src/marker_group_test.js b/src/marker_group_test.js index 6e65fd3d50d..f8006daab88 100644 --- a/src/marker_group_test.js +++ b/src/marker_group_test.js @@ -114,8 +114,8 @@ module.exports = { assert.equal(markerSize.height, lineHeight); // Should start at the 13th character (including 4px offset) assert.equal(markerSize.left, 12 * characterWidth + 4); - // Shoud be as wide as the marker layer - 12 characters and the offset. - assert.equal(markerSize.width, editor.renderer.$markerBack.element.getBoundingClientRect().width - 12 * characterWidth - 4); + // Shoud be as wide as the marker layer - 12 characters and the offset on both sides. + assert.equal(markerSize.width, editor.renderer.$markerBack.element.getBoundingClientRect().width - 12 * characterWidth - 4 - 4); }, "test: should default to markers of text type": function() { editor.resize(true); From be9e7d4b3ab54342f3b72d4ba6c132cd4bb15b76 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Fri, 30 Aug 2024 17:01:21 +0200 Subject: [PATCH 1165/1293] release v1.36.2 --- CHANGELOG.md | 7 +++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e83d986eb10..984bdb0f07e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.36.2](https://github.com/ajaxorg/ace/compare/v1.36.1...v1.36.2) (2024-08-30) + + +### Bug Fixes + +* apply padding to right side multi-line markers ([#5636](https://github.com/ajaxorg/ace/issues/5636)) ([c7549aa](https://github.com/ajaxorg/ace/commit/c7549aa5d53fb62f134b31a44d09029ceee3c800)) + ### [1.36.1](https://github.com/ajaxorg/ace/compare/v1.36.0...v1.36.1) (2024-08-29) diff --git a/build b/build index 68e4d6e6a9b..cb4c7c3d105 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 68e4d6e6a9b867c20927bcc31e39330e3f94bc7d +Subproject commit cb4c7c3d105c92b04f45d78d329f5509b7098906 diff --git a/package.json b/package.json index f32a55c0a95..c742e5f530e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.36.1", + "version": "1.36.2", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 848e7763b7e..0aea51463ca 100644 --- a/src/config.js +++ b/src/config.js @@ -194,6 +194,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.36.1"; +exports.version = "1.36.2"; From 560f5d318e811280e0f8a969baf9906bc4811bbf Mon Sep 17 00:00:00 2001 From: OppyDev <145087376+OppyDevAI@users.noreply.github.com> Date: Mon, 16 Sep 2024 02:02:35 -0700 Subject: [PATCH 1166/1293] Adding OppyDev to list of projects using Ace (#5642) Co-authored-by: Alex --- index.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.html b/index.html index b6e263508a9..35bdb114897 100644 --- a/index.html +++ b/index.html @@ -1203,6 +1203,10 @@

    Projects Using Ace

    Opensolr +
  • + + OppyDev +
  • +

    Your Site Here From 23b0b8b4dd64f956d6354493a003452600c0f467 Mon Sep 17 00:00:00 2001 From: Leo Feyer <1192057+leofeyer@users.noreply.github.com> Date: Mon, 14 Oct 2024 10:57:42 +0200 Subject: [PATCH 1167/1293] Add Contao Open Source CMS (#5653) --- index.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.html b/index.html index 35bdb114897..b08366aea11 100644 --- a/index.html +++ b/index.html @@ -1207,6 +1207,10 @@

    Projects Using Ace

    OppyDev
  • +
  • + + Contao +
  • +

    Your Site Here From 2953f72877a90691432373cfe9182e60ea9b2d8f Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Sun, 20 Oct 2024 14:06:11 +0200 Subject: [PATCH 1168/1293] fix: `readdirSync` options `recursive: true` was added only in NodeJs v20.1.0 (#5645) --- ace-modes.d.ts | 132 ++++++++++++++++++++++++++++ tool/modes-declaration-generator.js | 23 ++++- 2 files changed, 153 insertions(+), 2 deletions(-) diff --git a/ace-modes.d.ts b/ace-modes.d.ts index f852d5fe0ff..8a7f1899075 100644 --- a/ace-modes.d.ts +++ b/ace-modes.d.ts @@ -130,6 +130,34 @@ declare module "ace-code/src/mode/behaviour" { export const Behaviour: new () => import(".").Ace.Behaviour; } +declare module "ace-code/src/mode/behaviour/css" { + export const CssBehaviour: new () => import(".").Ace.Behaviour; +} + +declare module "ace-code/src/mode/behaviour/cstyle" { + export const CstyleBehaviour: new () => import(".").Ace.Behaviour; +} + +declare module "ace-code/src/mode/behaviour/html" { + export const HtmlBehaviour: new () => import(".").Ace.Behaviour; +} + +declare module "ace-code/src/mode/behaviour/javascript" { + export const JavaScriptBehaviour: new () => import(".").Ace.Behaviour; +} + +declare module "ace-code/src/mode/behaviour/liquid" { + export const LiquidBehaviour: new () => import(".").Ace.Behaviour; +} + +declare module "ace-code/src/mode/behaviour/xml" { + export const XmlBehaviour: new () => import(".").Ace.Behaviour; +} + +declare module "ace-code/src/mode/behaviour/xquery" { + export const XQueryBehaviour: new () => import(".").Ace.Behaviour; +} + declare module "ace-code/src/mode/bibtex_highlight_rules" { export const BibTeXHighlightRules: new () => import(".").Ace.HighlightRules; } @@ -392,6 +420,110 @@ declare module "ace-code/src/mode/flix" { export const Mode: new () => import(".").Ace.SyntaxMode; } +declare module "ace-code/src/mode/folding/asciidoc" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/c9search" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/coffee" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/csharp" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/cstyle" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/diff" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/drools" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/fold_mode" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/haskell_cabal" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/html" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/ini" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/java" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/javascript" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/latex" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/lua" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/markdown" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/mixed" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/php" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/pythonic" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/ruby" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/sql" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/sqlserver" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/vbscript" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/velocity" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/xml" { + export const FoldMode: new () => import(".").Ace.Folding; +} + +declare module "ace-code/src/mode/folding/yaml" { + export const FoldMode: new () => import(".").Ace.Folding; +} + declare module "ace-code/src/mode/forth_highlight_rules" { export const ForthHighlightRules: new () => import(".").Ace.HighlightRules; } diff --git a/tool/modes-declaration-generator.js b/tool/modes-declaration-generator.js index 1aad62dd8c6..372a5f818e1 100644 --- a/tool/modes-declaration-generator.js +++ b/tool/modes-declaration-generator.js @@ -124,9 +124,28 @@ function generateModuleDeclarations(dirPath) { }); } +function getAllFiles(dirPath) { + let files = []; + + const entries = fs.readdirSync(dirPath); + + entries.sort().forEach(entry => { + const fullPath = path.join(dirPath, entry); + const stat = fs.statSync(fullPath); + + if (stat.isDirectory()) { + files = files.concat(getAllFiles(fullPath)); + } + else if (stat.isFile()) { + files.push(fullPath); + } + }); + + return files; +} + function createProgram(dirPath) { - const fileNames = fs.readdirSync(dirPath, {recursive: true}).map(file => path.join(dirPath, file)).filter( - file => /\.js$/.test(file) && !/test\.js$/.test(file)); + const fileNames = getAllFiles(dirPath).filter(file => /\.js$/.test(file) && !/test\.js$/.test(file)); const program = ts.createProgram(fileNames, { target: ts.ScriptTarget.ES5, From 37c5f7602b33dd05bba5c2521abbfe7bb2cc651a Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:01:28 +0200 Subject: [PATCH 1169/1293] chore: disable Unexpected trailing comma comma-dangle rule (#5660) --- .eslintrc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.eslintrc b/.eslintrc index a4ac3f0748d..e2728a18a1d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -38,7 +38,7 @@ "rules": { curly: 0, eqeqeq: 0, - comma-dangle: 2, + //comma-dangle: 2, no-dupe-args: 2, no-dupe-keys: 2, no-duplicate-case: 2, @@ -56,7 +56,7 @@ no-unexpected-multiline: 2, use-isnan: 2, valid-typeof: 2, - + accessor-pairs: 2, complexity: 0, dot-location: [2, "property"], @@ -80,11 +80,11 @@ no-sequences: 2, no-useless-call: 2, yoda: 2, - + no-undef: 2, no-redeclare: 0, no-unused-vars: [1, {"args": "none", "vars": "all"}], - + no-debugger: 2, ////////////////////////////////////////////////////////////////// @@ -108,17 +108,17 @@ // no-else-return: 2, // no-unused-expressions: 2, // no-use-before-define: [2, { "functions": false, "classes": false, "variables": false }], - + // array-bracket-spacing: 2, // enforce spacing inside array brackets (fixable) // block-spacing: 2, // disallow or enforce spaces inside of single line blocks (fixable) - // brace-style: 2, // enforce one true brace style + // brace-style: 2, // enforce one true brace style // camelcase: 2, // require camel case names // comma-spacing: 2, // enforce spacing before and after comma (fixable) // comma-style: 2, // enforce one true comma style computed-property-spacing: 2, // require or disallow padding inside computed properties (fixable) - // consistent-this: 2, // enforce consistent naming when capturing the current execution context + // consistent-this: 2, // enforce consistent naming when capturing the current execution context linebreak-style: 2, // disallow mixed 'LF' and 'CRLF' as linebreaks - // indent: ["error", 4, { "outerIIFEBody": 0 }], // specify tab or space width for your code (fixable) + // indent: ["error", 4, { "outerIIFEBody": 0 }], // specify tab or space width for your code (fixable) // key-spacing: 2, // enforce spacing between keys and values in object literal properties // new-cap: 2, // require a capital letter for constructors // new-parens: 2, // disallow the omission of parentheses when invoking a constructor with no arguments @@ -151,6 +151,6 @@ // space-infix-ops: 2, // require spaces around operators (fixable) // space-unary-ops: 2, // require or disallow spaces before/after unary operators (fixable) // spaced-comment: [2, "always", { markers: ["-", "*", "/", "{", "}", "#"], exceptions: ["}"] }] - + } } From aba05756bf77229a033ef783647e3cd17d57aeb9 Mon Sep 17 00:00:00 2001 From: Marin Sokol Date: Mon, 21 Oct 2024 14:07:45 +0200 Subject: [PATCH 1170/1293] Edit session operation (#5657) * feat(edit-session): adding operation handling --------- Co-authored-by: Marin Sokol --- ace-internal.d.ts | 14 +++++ ace.d.ts | 11 +++- src/edit_session.js | 92 +++++++++++++++++++++++++++++++ src/edit_session_test.js | 113 +++++++++++++++++++++++++++++++++++++++ src/editor.js | 78 +++++++++++---------------- 5 files changed, 260 insertions(+), 48 deletions(-) diff --git a/ace-internal.d.ts b/ace-internal.d.ts index 12165e80b0b..7a345ea0828 100644 --- a/ace-internal.d.ts +++ b/ace-internal.d.ts @@ -427,6 +427,10 @@ export namespace Ace { * @param delta */ "change": (delta: Delta) => void; + /** + * Emitted when the selection changes. + */ + "changeSelection": () => void; /** * Emitted when the tab size changes, via [[EditSession.setTabSize]]. * @param tabSize @@ -492,6 +496,16 @@ export namespace Ace { **/ "changeScrollLeft": (scrollLeft: number) => void; "changeEditor": (e: { editor: Editor }) => void; + /** + * Emitted after operation starts. + * @param commandEvent event causing the operation + */ + "startOperation": (commandEvent) => void; + /** + * Emitted after operation finishes. + * @param e event causing the finish + */ + "endOperation": (e) => void; } interface EditorEvents { diff --git a/ace.d.ts b/ace.d.ts index 6fbcbbd1366..88560068eb7 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -506,6 +506,13 @@ export namespace Ace { export interface EditSession extends EventEmitter, OptionsProvider, Folding { selection: Selection; + curOp?: { + docChanged?: boolean; + selectionChanged?: boolean; + command?: { + name?: string; + }; + }; // TODO: define BackgroundTokenizer @@ -517,7 +524,7 @@ export namespace Ace { callback: (obj: { data: { first: number, last: number } }) => void): Function; on(name: 'change', callback: () => void): Function; on(name: 'changeTabSize', callback: () => void): Function; - + on(name: "beforeEndOperation", callback: () => void): Function; setOption(name: T, value: EditSessionOptions[T]): void; getOption(name: T): EditSessionOptions[T]; @@ -625,6 +632,8 @@ export namespace Ace { documentToScreenRow(docRow: number, docColumn: number): number; getScreenLength(): number; getPrecedingCharacter(): string; + startOperation(commandEvent: {command: {name: string}}): void; + endOperation(): void; toJSON(): Object; destroy(): void; } diff --git a/src/edit_session.js b/src/edit_session.js index 9cb28439f8b..0546545c505 100644 --- a/src/edit_session.js +++ b/src/edit_session.js @@ -45,6 +45,7 @@ class EditSession { this.$backMarkers = {}; this.$markerId = 1; this.$undoSelect = true; + this.prevOp = {}; /** @type {FoldLine[]} */ this.$foldData = []; @@ -69,7 +70,12 @@ class EditSession { text = new Document(/**@type{string}*/(text)); this.setDocument(text); + this.selection = new Selection(this); + this.$onSelectionChange = this.onSelectionChange.bind(this); + this.selection.on("changeSelection", this.$onSelectionChange); + this.selection.on("changeCursor", this.$onSelectionChange); + this.$bidiHandler = new BidiHandler(this); config.resetOptions(this); @@ -77,6 +83,83 @@ class EditSession { config._signal("session", this); this.destroyed = false; + this.$initOperationListeners(); + } + + $initOperationListeners() { + this.curOp = null; + this.on("change", () => { + if (!this.curOp) { + this.startOperation(); + this.curOp.selectionBefore = this.$lastSel; + } + this.curOp.docChanged = true; + }, true); + this.on("changeSelection", () => { + if (!this.curOp) { + this.startOperation(); + this.curOp.selectionBefore = this.$lastSel; + } + this.curOp.selectionChanged = true; + }, true); + + // Fallback mechanism in case current operation doesn't finish more explicitly. + // Triggered, for example, when a consumer makes programmatic changes without invoking endOperation afterwards. + this.$operationResetTimer = lang.delayedCall(this.endOperation.bind(this, true)); + } + + /** + * Start an Ace operation, which will then batch all the subsequent changes (to either content or selection) under a single atomic operation. + * @param {{command?: {name?: string}, args?: any}|undefined} [commandEvent] Optional name for the operation + */ + startOperation(commandEvent) { + if (this.curOp) { + if (!commandEvent || this.curOp.command) { + return; + } + this.prevOp = this.curOp; + } + if (!commandEvent) { + commandEvent = {}; + } + + this.$operationResetTimer.schedule(); + this.curOp = { + command: commandEvent.command || {}, + args: commandEvent.args + }; + this.curOp.selectionBefore = this.selection.toJSON(); + this._signal("startOperation", commandEvent); + } + + /** + * End current Ace operation. + * Emits "beforeEndOperation" event just before clearing everything, where the current operation can be accessed through `curOp` property. + * @param {any} e + */ + endOperation(e) { + if (this.curOp) { + if (e && e.returnValue === false) { + this.curOp = null; + this._signal("endOperation", e); + return; + } + if (e == true && this.curOp.command && this.curOp.command.name == "mouse") { + // When current operation is mousedown, we wait for the mouseup to end the operation. + // So during a user selection, we would only end the operation when the final selection is known. + return; + } + + const currentSelection = this.selection.toJSON(); + this.curOp.selectionAfter = currentSelection; + this.$lastSel = this.selection.toJSON(); + this.getUndoManager().addSelection(currentSelection); + + this._signal("beforeEndOperation"); + this.prevOp = this.curOp; + this.curOp = null; + this._signal("endOperation", e); + } } /** @@ -186,6 +269,10 @@ class EditSession { this._signal("change", delta); } + onSelectionChange() { + this._signal("changeSelection"); + } + /** * Sets the session text. * @param {String} text The new text to place @@ -2386,11 +2473,16 @@ class EditSession { this.bgTokenizer.cleanup(); this.destroyed = true; } + this.endOperation(); this.$stopWorker(); this.removeAllListeners(); if (this.doc) { this.doc.off("change", this.$onChange); } + if (this.selection) { + this.selection.off("changeCursor", this.$onSelectionChange); + this.selection.off("changeSelection", this.$onSelectionChange); + } this.selection.detach(); } } diff --git a/src/edit_session_test.js b/src/edit_session_test.js index 915912d2a1a..ca65b12bde2 100644 --- a/src/edit_session_test.js +++ b/src/edit_session_test.js @@ -1150,6 +1150,119 @@ module.exports = { assert.equal(session.getScrollLeft(), 0); assert.equal(session.getScrollTop(), 0); assert.equal(session.getValue(), "Hello world!"); + }, + + "test: operation handling : when session it not attached to an editor": function(done) { + const session = new EditSession("Hello world!"); + const beforeEndOperationSpy = []; + session.on("beforeEndOperation", () => { + beforeEndOperationSpy.push(session.curOp); + }); + + // When both start and end operation are invoked by the consumer + session.startOperation({command: {name: "inserting-both"}}); + session.insert({row: 0, column : 0}, "both"); + session.endOperation(); + assert.equal(beforeEndOperationSpy.length, 1); + assert.equal(beforeEndOperationSpy[0].command.name, "inserting-both"); + assert.equal(beforeEndOperationSpy[0].docChanged, true); + assert.equal(beforeEndOperationSpy[0].selectionChanged, true); + + // When only start operation is invoked + session.startOperation({command: {name: "inserting-start"}}); + session.insert({row: 0, column : 0}, "start"); + setTimeout(() => { + assert.equal(beforeEndOperationSpy.length, 2); + assert.equal(beforeEndOperationSpy[1].command.name, "inserting-start"); + assert.equal(beforeEndOperationSpy[1].docChanged, true); + assert.equal(beforeEndOperationSpy[1].selectionChanged, true); + + // When only end operation is invoked + session.insert({row: 0, column : 0}, "end"); + session.endOperation(); + assert.equal(beforeEndOperationSpy.length, 3); + assert.deepEqual(beforeEndOperationSpy[2].command, {}); + assert.equal(beforeEndOperationSpy[2].docChanged, true); + assert.equal(beforeEndOperationSpy[2].selectionChanged, true); + + // When nothing is invoked + session.insert({row: 0, column : 0}, "none"); + setTimeout(() => { + assert.equal(beforeEndOperationSpy.length, 4); + assert.deepEqual(beforeEndOperationSpy[3].command, {}); + assert.equal(beforeEndOperationSpy[3].docChanged, true); + assert.equal(beforeEndOperationSpy[3].selectionChanged, true); + + done(); + }, 10); + }, 10); + }, + + "test: operation handling : when session is attached to an editor": function(done) { + const session = new EditSession("Hello world!"); + const editor = new Editor(new MockRenderer(), session); + const beforeEndOperationSpySession = []; + session.on("beforeEndOperation", () => { + beforeEndOperationSpySession.push(session.curOp); + }); + const beforeEndOperationSpyEditor = []; + editor.on("beforeEndOperation", () => { + beforeEndOperationSpyEditor.push(editor.curOp); + }); + + // Imperative update from editor + editor.startOperation({command: {name: "imperative-update"}}); + editor.insert("update"); + editor.endOperation(); + for (const beforeEndOperationSpy of [beforeEndOperationSpySession, beforeEndOperationSpyEditor ]) { + assert.equal(beforeEndOperationSpy.length, 1); + assert.equal(beforeEndOperationSpy[0].command.name, "imperative-update"); + assert.equal(beforeEndOperationSpy[0].docChanged, true); + assert.equal(beforeEndOperationSpy[0].selectionChanged, true); + assert.equal(!!beforeEndOperationSpy[0].selectionBefore, true); + } + + // Imperative update from session + session.startOperation({command: {name: "session-update"}}); + session.insert({row: 0, column : 0},"update"); + session.endOperation(); + for (const beforeEndOperationSpy of [beforeEndOperationSpySession, beforeEndOperationSpyEditor ]) { + assert.equal(beforeEndOperationSpy.length, 2); + assert.equal(beforeEndOperationSpy[1].command.name, "session-update"); + assert.equal(beforeEndOperationSpy[1].docChanged, true); + assert.equal(beforeEndOperationSpy[1].selectionChanged, true); + assert.equal(!!beforeEndOperationSpy[1].selectionBefore, true); + } + + // Command update + editor.execCommand(editor.commands.byName.indent); + for (const beforeEndOperationSpy of [beforeEndOperationSpySession, beforeEndOperationSpyEditor ]) { + assert.equal(beforeEndOperationSpy.length, 3); + assert.equal(beforeEndOperationSpy[2].command.name, "indent"); + assert.equal(beforeEndOperationSpy[2].docChanged, true); + assert.equal(beforeEndOperationSpy[2].selectionChanged, true); + assert.equal(!!beforeEndOperationSpy[2].selectionBefore, true); + } + + // Session cleanup logic + const newSession = new EditSession("Hello again!"); + editor.setSession(newSession); + const beforeEndOperationSpyNewSession = []; + newSession.on("beforeEndOperation", () => { + beforeEndOperationSpyNewSession.push(newSession.curOp); + }); + editor.execCommand(editor.commands.byName.indent); + assert.equal(beforeEndOperationSpyEditor.length, 4); + assert.equal(beforeEndOperationSpyNewSession.length, 1); + assert.equal(beforeEndOperationSpySession.length, 3); + + // Imperative implicit update from editor + editor.insert("update"); + setTimeout(() => { + assert.equal(beforeEndOperationSpyEditor.length, 5); + assert.equal(beforeEndOperationSpyNewSession.length, 2); + done(); + }, 10); } }; diff --git a/src/editor.js b/src/editor.js index 01ef6461c68..62e1d613910 100644 --- a/src/editor.js +++ b/src/editor.js @@ -48,7 +48,6 @@ class Editor { **/ constructor(renderer, session, options) { /**@type{EditSession}*/this.session; - this.$toDestroy = []; var container = renderer.getContainerElement(); @@ -99,61 +98,42 @@ class Editor { $initOperationListeners() { this.commands.on("exec", this.startOperation.bind(this), true); this.commands.on("afterExec", this.endOperation.bind(this), true); - - this.$opResetTimer = lang.delayedCall(this.endOperation.bind(this, true)); - - // todo: add before change events? - this.on("change", function() { - if (!this.curOp) { - this.startOperation(); - this.curOp.selectionBefore = this.$lastSel; - } - this.curOp.docChanged = true; - }.bind(this), true); - - this.on("changeSelection", function() { - if (!this.curOp) { - this.startOperation(); - this.curOp.selectionBefore = this.$lastSel; - } - this.curOp.selectionChanged = true; - }.bind(this), true); } startOperation(commandEvent) { - if (this.curOp) { - if (!commandEvent || this.curOp.command) - return; - this.prevOp = this.curOp; - } + this.session.startOperation(commandEvent); + } + + /** + * @arg e + */ + endOperation(e) { + this.session.endOperation(e); + } + + onStartOperation(commandEvent) { + this.curOp = this.session.curOp; + this.curOp.scrollTop = this.renderer.scrollTop; + this.prevOp = this.session.prevOp; + if (!commandEvent) { this.previousCommand = null; - commandEvent = {}; } - - this.$opResetTimer.schedule(); - /** - * @type {{[key: string]: any;}} - */ - this.curOp = this.session.curOp = { - command: commandEvent.command || {}, - args: commandEvent.args, - scrollTop: this.renderer.scrollTop - }; - this.curOp.selectionBefore = this.selection.toJSON(); } /** * @arg e */ - endOperation(e) { + onEndOperation(e) { if (this.curOp && this.session) { - if (e && e.returnValue === false || !this.session) - return (this.curOp = null); - if (e == true && this.curOp.command && this.curOp.command.name == "mouse") + if (e && e.returnValue === false) { + this.curOp = null; return; + } + this._signal("beforeEndOperation"); if (!this.curOp) return; + var command = this.curOp.command; var scrollIntoView = command && command.scrollIntoView; if (scrollIntoView) { @@ -181,12 +161,8 @@ class Editor { if (scrollIntoView == "animate") this.renderer.animateScrolling(this.curOp.scrollTop); } - var sel = this.selection.toJSON(); - this.curOp.selectionAfter = sel; - this.$lastSel = this.selection.toJSON(); - - // console.log(this.$lastSel+" endOP") - this.session.getUndoManager().addSelection(sel); + + this.$lastSel = this.session.selection.toJSON(); this.prevOp = this.curOp; this.curOp = null; } @@ -291,6 +267,8 @@ class Editor { this.session.off("changeOverwrite", this.$onCursorChange); this.session.off("changeScrollTop", this.$onScrollTopChange); this.session.off("changeScrollLeft", this.$onScrollLeftChange); + this.session.off("startOperation", this.$onStartOperation); + this.session.off("endOperation", this.$onEndOperation); var selection = this.session.getSelection(); selection.off("changeCursor", this.$onCursorChange); @@ -347,6 +325,11 @@ class Editor { this.$onSelectionChange = this.onSelectionChange.bind(this); this.selection.on("changeSelection", this.$onSelectionChange); + + this.$onStartOperation = this.onStartOperation.bind(this); + this.session.on("startOperation", this.$onStartOperation); + this.$onEndOperation = this.onEndOperation.bind(this); + this.session.on("endOperation", this.$onEndOperation); this.onChangeMode(); @@ -2679,6 +2662,7 @@ class Editor { if (this._$emitInputEvent) this._$emitInputEvent.cancel(); this.removeAllListeners(); + } /** From b168a9737615d67f9797134153bc1e0dba8f2772 Mon Sep 17 00:00:00 2001 From: Marin Sokol Date: Mon, 21 Oct 2024 14:14:10 +0200 Subject: [PATCH 1171/1293] release v1.36.3 --- CHANGELOG.md | 7 +++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 984bdb0f07e..3be87ca7eb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.36.3](https://github.com/ajaxorg/ace/compare/v1.36.2...v1.36.3) (2024-10-21) + + +### Bug Fixes + +* `readdirSync` options `recursive: true` was added only in NodeJs v20.1.0 ([#5645](https://github.com/ajaxorg/ace/issues/5645)) ([2953f72](https://github.com/ajaxorg/ace/commit/2953f72877a90691432373cfe9182e60ea9b2d8f)) + ### [1.36.2](https://github.com/ajaxorg/ace/compare/v1.36.1...v1.36.2) (2024-08-30) diff --git a/build b/build index cb4c7c3d105..a10728b1a3e 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit cb4c7c3d105c92b04f45d78d329f5509b7098906 +Subproject commit a10728b1a3ed6f87e4c0cf308523f002daa7ffef diff --git a/package.json b/package.json index c742e5f530e..e89bbd1bbff 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.36.2", + "version": "1.36.3", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 0aea51463ca..0a76b117f4b 100644 --- a/src/config.js +++ b/src/config.js @@ -194,6 +194,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.36.2"; +exports.version = "1.36.3"; From 31cb7b54c1c12e1b9e4666248f20ed393bf01651 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:28:31 +0200 Subject: [PATCH 1172/1293] Add basic(ms-basic) highlight mode (#5649) * add basic(ms-basic) highlight mode * fix: Unexpected trailing comma * add basic mode --- ace-modes.d.ts | 12 + demo/kitchen-sink/docs/basic.bas | 43 +++ src/ext/modelist.js | 1 + src/mode/_test/tokens_basic.json | 531 ++++++++++++++++++++++++++++++ src/mode/basic.js | 40 +++ src/mode/basic_highlight_rules.js | 67 ++++ src/mode/folding/basic.js | 116 +++++++ src/mode/folding/basic_test.js | 97 ++++++ 8 files changed, 907 insertions(+) create mode 100644 demo/kitchen-sink/docs/basic.bas create mode 100644 src/mode/_test/tokens_basic.json create mode 100644 src/mode/basic.js create mode 100644 src/mode/basic_highlight_rules.js create mode 100644 src/mode/folding/basic.js create mode 100644 src/mode/folding/basic_test.js diff --git a/ace-modes.d.ts b/ace-modes.d.ts index 8a7f1899075..f2da9f47c56 100644 --- a/ace-modes.d.ts +++ b/ace-modes.d.ts @@ -118,6 +118,14 @@ declare module "ace-code/src/mode/autohotkey" { export const Mode: new () => import(".").Ace.SyntaxMode; } +declare module "ace-code/src/mode/basic_highlight_rules" { + export const BasicHighlightRules: new () => import(".").Ace.HighlightRules; +} + +declare module "ace-code/src/mode/basic" { + export const Mode: new () => import(".").Ace.SyntaxMode; +} + declare module "ace-code/src/mode/batchfile_highlight_rules" { export const BatchFileHighlightRules: new () => import(".").Ace.HighlightRules; } @@ -424,6 +432,10 @@ declare module "ace-code/src/mode/folding/asciidoc" { export const FoldMode: new () => import(".").Ace.Folding; } +declare module "ace-code/src/mode/folding/basic" { + export const FoldMode: new () => import(".").Ace.Folding; +} + declare module "ace-code/src/mode/folding/c9search" { export const FoldMode: new () => import(".").Ace.Folding; } diff --git a/demo/kitchen-sink/docs/basic.bas b/demo/kitchen-sink/docs/basic.bas new file mode 100644 index 00000000000..830fc5ea74c --- /dev/null +++ b/demo/kitchen-sink/docs/basic.bas @@ -0,0 +1,43 @@ +120 OPEN"R" #1 "INVEN.DAT",39 +125 FIELD#1,1 AS F$,30 AS D$, 2 AS Q$,2 AS R$,4 AS PH +130 PRINT:PRINT "FUNCTIONS:":PRINT +135 PRINT 1,"INITIALIZE FILE" +140 PRINT 2 "CREATE A NEW ENTRY" +150 PRINT 3,"DISPLAY INVENTORY FOR ONE PART" +160 PRINT 4 "ADD TO STOCK" +170 PRINT 5,"SUBTRACT FROM STOCK" +180 PRINT 6,"DISPLAY ALL ITEMS BELOW REORDER LEVEL" +220 PRINT:PRINT:INPUT"FUNCTION";FUNCTION +225 IF (FUNCTION<1)OR(FUNCTION>6) THEN PRINT "BAD FUNCTION NUMBER":GOTO 130 +230 ON FUNCTION GOSUB 900,250,390,480,560,680 +240 GOTO 220 +560 REM REMOVE FROM STOCK +570 GOSUB 840 +580 IF ASC(F$)=255 THEN PRINT "NULL ENTRY":RETURN +590 PRINT DH +600 INPUT "QUANTITY TO SUBTRACT";S% +610 Q%=CVI(Q$) +620 IF (Q%-S%)<0 THEN PRINT "ONIY";Q%; "IN STOCK":GOTO 600 +630 Q%=Q%-S% +640 IF Q%=100) THEN PRINT "BAD PART NUMBER": GOTO 840 ELSE GET#1 J>ART%:RETURN +END +REM INITIALIZE FILE +INPUT "ARE YOU SURE";B$:IF B$<="Y" THEN RETURN +LSET F$=CHR$(255) +FOR O=1 TO 100 +PUT#1J +NEXT I +RETURN diff --git a/src/ext/modelist.js b/src/ext/modelist.js index 791174fe07d..6a1f0a474f6 100644 --- a/src/ext/modelist.js +++ b/src/ext/modelist.js @@ -68,6 +68,7 @@ var supportedModes = { Astro: ["astro"], AutoHotKey: ["ahk"], BatchFile: ["bat|cmd"], + Basic: ["bas|bak"], BibTeX: ["bib"], C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp|ino"], C9Search: ["c9search_results"], diff --git a/src/mode/_test/tokens_basic.json b/src/mode/_test/tokens_basic.json new file mode 100644 index 00000000000..8cbe53e6f47 --- /dev/null +++ b/src/mode/_test/tokens_basic.json @@ -0,0 +1,531 @@ +[[ + "start", + ["constant.numeric","120"], + ["text"," "], + ["entity.name","OPEN"], + ["string","\"R\""], + ["text"," #"], + ["constant.numeric","1"], + ["text"," "], + ["string","\"INVEN.DAT\""], + ["punctiation",","], + ["constant.numeric","39"] +],[ + "start", + ["constant.numeric","125"], + ["text"," "], + ["entity.name","FIELD"], + ["text","#"], + ["constant.numeric","1"], + ["punctiation",","], + ["constant.numeric","1"], + ["text"," "], + ["identifier","AS"], + ["text"," "], + ["identifier","F"], + ["text","$"], + ["punctiation",","], + ["constant.numeric","30"], + ["text"," "], + ["identifier","AS"], + ["text"," "], + ["identifier","D"], + ["text","$"], + ["punctiation",","], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["identifier","AS"], + ["text"," "], + ["identifier","Q"], + ["text","$"], + ["punctiation",","], + ["constant.numeric","2"], + ["text"," "], + ["identifier","AS"], + ["text"," "], + ["identifier","R"], + ["text","$"], + ["punctiation",","], + ["constant.numeric","4"], + ["text"," "], + ["identifier","AS"], + ["text"," "], + ["identifier","PH"] +],[ + "start", + ["constant.numeric","130"], + ["text"," "], + ["entity.name","PRINT"], + ["text",":"], + ["entity.name","PRINT"], + ["text"," "], + ["string","\"FUNCTIONS:\""], + ["text",":"], + ["entity.name","PRINT"] +],[ + "start", + ["constant.numeric","135"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["constant.numeric","1"], + ["punctiation",","], + ["string","\"INITIALIZE FILE\""] +],[ + "start", + ["constant.numeric","140"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["string","\"CREATE A NEW ENTRY\""] +],[ + "start", + ["constant.numeric","150"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["constant.numeric","3"], + ["punctiation",","], + ["string","\"DISPLAY INVENTORY FOR ONE PART\""] +],[ + "start", + ["constant.numeric","160"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["constant.numeric","4"], + ["text"," "], + ["string","\"ADD TO STOCK\""] +],[ + "start", + ["constant.numeric","170"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["constant.numeric","5"], + ["punctiation",","], + ["string","\"SUBTRACT FROM STOCK\""] +],[ + "start", + ["constant.numeric","180"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["constant.numeric","6"], + ["punctiation",","], + ["string","\"DISPLAY ALL ITEMS BELOW REORDER LEVEL\""] +],[ + "start", + ["constant.numeric","220"], + ["text"," "], + ["entity.name","PRINT"], + ["text",":"], + ["entity.name","PRINT"], + ["text",":"], + ["entity.name","INPUT"], + ["string","\"FUNCTION\""], + ["punctiation",";"], + ["identifier","FUNCTION"] +],[ + "start", + ["constant.numeric","225"], + ["text"," "], + ["keyword.control","IF"], + ["text"," "], + ["paren.lparen","("], + ["identifier","FUNCTION"], + ["keyword.operator","<"], + ["constant.numeric","1"], + ["paren.rparen",")"], + ["keyword.operator","OR"], + ["paren.lparen","("], + ["identifier","FUNCTION"], + ["keyword.operator",">"], + ["constant.numeric","6"], + ["paren.rparen",")"], + ["text"," "], + ["keyword.control","THEN"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["string","\"BAD FUNCTION NUMBER\""], + ["text",":"], + ["keyword.control","GOTO"], + ["text"," "], + ["constant.numeric","130"] +],[ + "start", + ["constant.numeric","230"], + ["text"," "], + ["keyword.control","ON"], + ["text"," "], + ["identifier","FUNCTION"], + ["text"," "], + ["keyword.control","GOSUB"], + ["text"," "], + ["constant.numeric","900"], + ["punctiation",","], + ["constant.numeric","250"], + ["punctiation",","], + ["constant.numeric","390"], + ["punctiation",","], + ["constant.numeric","480"], + ["punctiation",","], + ["constant.numeric","560"], + ["punctiation",","], + ["constant.numeric","680"] +],[ + "start", + ["constant.numeric","240"], + ["text"," "], + ["keyword.control","GOTO"], + ["text"," "], + ["constant.numeric","220"] +],[ + "start", + ["constant.numeric","560"], + ["text"," "], + ["comment","REM REMOVE FROM STOCK"] +],[ + "start", + ["constant.numeric","570"], + ["text"," "], + ["keyword.control","GOSUB"], + ["text"," "], + ["constant.numeric","840"] +],[ + "start", + ["constant.numeric","580"], + ["text"," "], + ["keyword.control","IF"], + ["text"," "], + ["support.function","ASC"], + ["paren.lparen","("], + ["identifier","F"], + ["text","$"], + ["paren.rparen",")"], + ["keyword.operator","="], + ["constant.numeric","255"], + ["text"," "], + ["keyword.control","THEN"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["string","\"NULL ENTRY\""], + ["text",":"], + ["keyword.control","RETURN"] +],[ + "start", + ["constant.numeric","590"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["identifier","DH"] +],[ + "start", + ["constant.numeric","600"], + ["text"," "], + ["entity.name","INPUT"], + ["text"," "], + ["string","\"QUANTITY TO SUBTRACT\""], + ["punctiation",";"], + ["identifier","S"], + ["text","%"] +],[ + "start", + ["constant.numeric","610"], + ["text"," "], + ["variable","Q%"], + ["keyword.operator","="], + ["support.function","CVI"], + ["paren.lparen","("], + ["identifier","Q"], + ["text","$"], + ["paren.rparen",")"] +],[ + "start", + ["constant.numeric","620"], + ["text"," "], + ["keyword.control","IF"], + ["text"," "], + ["paren.lparen","("], + ["identifier","Q"], + ["text","%"], + ["keyword.operator","-"], + ["identifier","S"], + ["text","%"], + ["paren.rparen",")"], + ["keyword.operator","<"], + ["constant.numeric","0"], + ["text"," "], + ["keyword.control","THEN"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["string","\"ONIY\""], + ["punctiation",";"], + ["identifier","Q"], + ["text","%"], + ["punctiation",";"], + ["text"," "], + ["string","\"IN STOCK\""], + ["text",":"], + ["keyword.control","GOTO"], + ["text"," "], + ["constant.numeric","600"] +],[ + "start", + ["constant.numeric","630"], + ["text"," "], + ["variable","Q%"], + ["keyword.operator","="], + ["identifier","Q"], + ["text","%"], + ["keyword.operator","-"], + ["identifier","S"], + ["text","%"] +],[ + "start", + ["constant.numeric","640"], + ["text"," "], + ["keyword.control","IF"], + ["text"," "], + ["variable","Q%"], + ["keyword.operator","=<"], + ["identifier","CVT"], + ["paren.lparen","("], + ["identifier","R"], + ["text","$"], + ["paren.rparen",")"], + ["text"," "], + ["keyword.control","THEN"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["string","\"QUANTITY NOW\""], + ["punctiation",";"], + ["identifier","Q"], + ["text","%"], + ["punctiation",";"] +],[ + "start", + ["constant.numeric","44"], + ["text"," "], + ["identifier","REORDER"], + ["text"," "], + ["identifier","LEVEL"], + ["text","\""], + ["punctiation",";"], + ["support.function","CVI"], + ["paren.lparen","("], + ["identifier","RH"], + ["paren.rparen",")"] +],[ + "start", + ["entity.name","LSET"], + ["text"," "], + ["variable","Q$"], + ["keyword.operator","="], + ["identifier","MKU"], + ["paren.lparen","("], + ["identifier","Q"], + ["text","%"], + ["paren.rparen",")"] +],[ + "start", + ["entity.name","PUT"], + ["text","#"], + ["constant.numeric","1"], + ["punctiation",","], + ["identifier","PART"], + ["text","%"] +],[ + "start", + ["keyword.control","RETURN"] +],[ + "start", + ["identifier","DISPLAY"], + ["text"," "], + ["identifier","ITEMS"], + ["text"," "], + ["identifier","BELOW"], + ["text"," "], + ["identifier","REORDER"], + ["text"," "], + ["identifier","LEVEL"] +],[ + "start", + ["keyword.control","FOR"], + ["text"," "], + ["constant.numeric","1"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["text"," "], + ["keyword.control","TO"], + ["text"," "], + ["constant.numeric","100"] +],[ + "start", + ["entity.name","GET"], + ["text","#"], + ["constant.numeric","1"], + ["identifier","J"] +],[ + "start", + ["keyword.control","IF"], + ["text"," "], + ["identifier","OVI"], + ["paren.lparen","("], + ["identifier","tzH"], + ["paren.rparen",")"], + ["identifier","OVI"], + ["paren.lparen","("], + ["identifier","RH"], + ["paren.rparen",")"], + ["text"," "], + ["keyword.control","THEN"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["identifier","Dtz"], + ["punctiation",";"], + ["string","\" QUANTITY\""], + ["punctiation",";"] +],[ + "start", + ["identifier","OVI"], + ["paren.lparen","("], + ["identifier","Qtz"], + ["paren.rparen",")"], + ["text"," "], + ["support.function","TAB"], + ["paren.lparen","("], + ["constant.numeric","50"], + ["paren.rparen",")"], + ["text"," "], + ["string","\"REORDER LEVEL\""], + ["punctiation",";"], + ["support.function","CVI"], + ["paren.lparen","("], + ["identifier","R"], + ["text","$"], + ["paren.rparen",")"] +],[ + "start", + ["keyword.control","NEXT"], + ["text"," "], + ["identifier","I"] +],[ + "start", + ["keyword.control","RETURN"] +],[ + "start", + ["entity.name","INPUT"], + ["text"," "], + ["string","\"PART NUMBER\""], + ["punctiation",";"], + ["identifier","PART"], + ["text","%"] +],[ + "start", + ["keyword.control","IF"], + ["paren.lparen","("], + ["identifier","PART"], + ["text","%"], + ["keyword.operator","<"], + ["constant.numeric","1"], + ["paren.rparen",")"], + ["keyword.operator","OR"], + ["paren.lparen","("], + ["identifier","PART"], + ["text","%"], + ["keyword.operator",">"], + ["constant.numeric","100"], + ["paren.rparen",")"], + ["text"," "], + ["keyword.control","THEN"], + ["text"," "], + ["entity.name","PRINT"], + ["text"," "], + ["string","\"BAD PART NUMBER\""], + ["text",": "], + ["keyword.control","GOTO"], + ["text"," "], + ["constant.numeric","840"], + ["text"," "], + ["keyword.control","ELSE"], + ["text"," "], + ["entity.name","GET"], + ["text","#"], + ["constant.numeric","1"], + ["text"," "], + ["identifier","J"], + ["keyword.operator",">"], + ["identifier","ART"], + ["text","%:"], + ["keyword.control","RETURN"] +],[ + "start", + ["entity.name","END"] +],[ + "start", + ["comment","REM INITIALIZE FILE"] +],[ + "start", + ["entity.name","INPUT"], + ["text"," "], + ["string","\"ARE YOU SURE\""], + ["punctiation",";"], + ["identifier","B"], + ["text","$:"], + ["keyword.control","IF"], + ["text"," "], + ["identifier","B"], + ["text","$"], + ["keyword.operator","<="], + ["string","\"Y\""], + ["text"," "], + ["keyword.control","THEN"], + ["text"," "], + ["keyword.control","RETURN"] +],[ + "start", + ["entity.name","LSET"], + ["text"," "], + ["variable","F$"], + ["keyword.operator","="], + ["support.function","CHR$"], + ["paren.lparen","("], + ["constant.numeric","255"], + ["paren.rparen",")"] +],[ + "start", + ["keyword.control","FOR"], + ["text"," "], + ["variable","O"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["text"," "], + ["keyword.control","TO"], + ["text"," "], + ["constant.numeric","100"] +],[ + "start", + ["entity.name","PUT"], + ["text","#"], + ["constant.numeric","1"], + ["identifier","J"] +],[ + "start", + ["keyword.control","NEXT"], + ["text"," "], + ["identifier","I"] +],[ + "start", + ["keyword.control","RETURN"] +],[ + "start" +]] \ No newline at end of file diff --git a/src/mode/basic.js b/src/mode/basic.js new file mode 100644 index 00000000000..e3c26e9c9c0 --- /dev/null +++ b/src/mode/basic.js @@ -0,0 +1,40 @@ +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var BasicHighlightRules = require("./basic_highlight_rules").BasicHighlightRules; +var FoldMode = require("./folding/basic").FoldMode; + +var Mode = function() { + this.HighlightRules = BasicHighlightRules; + this.foldingRules = new FoldMode(); + this.$behaviour = this.$defaultBehaviour; + this.indentKeywords = this.foldingRules.indentKeywords; +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.lineCommentStart = ["REM"]; + + this.getMatching = function(session, row, column, tokenRange) { + if (row == undefined) { + var pos = session.selection.lead; + column = pos.column; + row = pos.row; + } + if (tokenRange == undefined) + tokenRange = true; + + var startToken = session.getTokenAt(row, column); + if (startToken) { + var val = startToken.value.toLowerCase(); + if (val in this.indentKeywords) + return this.foldingRules.basicBlock(session, row, column, tokenRange); + } + }; + + this.$id = "ace/mode/basic"; +}).call(Mode.prototype); + +exports.Mode = Mode; diff --git a/src/mode/basic_highlight_rules.js b/src/mode/basic_highlight_rules.js new file mode 100644 index 00000000000..6bc0477cd0a --- /dev/null +++ b/src/mode/basic_highlight_rules.js @@ -0,0 +1,67 @@ +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var BasicHighlightRules = function () { + + var keywordMapper = this.createKeywordMapper({ + "keyword.control": "FOR|TO|NEXT|GOSUB|RETURN|IF|THEN|ELSE|GOTO|ON|WHILE|WEND|TRON|TROFF", + "entity.name": "Auto|Call|Chain|Clear|Close|Common|Cont|Data|MERGE|ALL|Delete|DIM|EDIT|END|ERASE|ERROR|FIELD|" + + "GET|INPUT|KILL|LET|LIST|LLIST|LOAD|LSET|RSET|MERGE|NEW|NULL|OPEN|OUT|POKE|PRINT|PUT|RANDOMIZE|READ|" + + "RENUM|RESTORE|RESUME|RUN|SAVE|STOP|SWAP|WAIT|WIDTH", + "keyword.operator": "Mod|And|Not|Or|Xor|Eqv|Imp", + "support.function": "ABS|ASC|ATN|CDBL|CINT|COS|CSNG|CVI|CVS|CVD|EOF|EXP|FIX|FRE|INP|INSTR|INT|LEN|LOC|LOG|LPOS|" + + "PEEK|POS|RND|SGN|SIN|SPC|SQR|TAB|TAN|USR|VAL|VARPTR" + }, "identifier", true); + + this.$rules = { + "start": [ + { + token: "string", + regex: /"(?:\\.|[^"\\])*"/ + }, + { + token: "support.function", + regex: /(HEX|CHR|INPUT|LEFT|MID|MKI|MKS|MKD|OCT|RIGHT|SPACE|STR|STRING)\$/ + }, { + token: "entity.name", + regex: /(?:DEF\s(?:SEG|USR|FN[a-zA-Z]+)|LINE\sINPUT|L?PRINT#?(?:\sUSING)?|MID\$|ON\sERROR\sGOTO|OPTION\sBASE|WRITE#?|DATE\$|INKEY\$|TIME\$)/ + }, { + token: "variable", + regex: /[a-zA-Z][a-zA-Z0-9_]{0,38}[$%!#]?(?=\s*=)/ + }, { + token: "keyword.operator", + regex: /\\|=|\^|\*|\/|\+|\-|<|>|-/ + }, { + token: "paren.lparen", + regex: /[([]/ + }, { + token: "paren.rparen", + regex: /[\)\]]/ + }, { + token: "constant.numeric", + regex: /[+-]?\d+(\.\d+)?([ED][+-]?\d+)?(?:[!#])?/ + }, { + token: "constant.numeric", //hexal, octal + regex: /&[HO]?[0-9A-F]+/ + }, { + token: "comment", + regex: /REM\s+.*$/ + }, { + regex: "\\w+", + token: keywordMapper + },{ + token: "punctiation", + regex: /[,;]/ + + } + ] + + }; + this.normalizeRules(); +}; + +oop.inherits(BasicHighlightRules, TextHighlightRules); + +exports.BasicHighlightRules = BasicHighlightRules; diff --git a/src/mode/folding/basic.js b/src/mode/folding/basic.js new file mode 100644 index 00000000000..62efe5215fe --- /dev/null +++ b/src/mode/folding/basic.js @@ -0,0 +1,116 @@ +"use strict"; + +var oop = require("../../lib/oop"); +var BaseFoldMode = require("./fold_mode").FoldMode; +var Range = require("../../range").Range; +var TokenIterator = require("../../token_iterator").TokenIterator; + + +var FoldMode = exports.FoldMode = function() {}; + +oop.inherits(FoldMode, BaseFoldMode); + +(function() { + this.indentKeywords = { + "tron": 1, + "while": 1, + "for": 1, + "troff": -1, + "wend": -1, + "next": -1 + }; + + this.foldingStartMarker = /(?:\s|^)(tron|while|for)\b/i; + this.foldingStopMarker = /(?:\b)(troff|next|wend)\b/i; + + this.getFoldWidgetRange = function (session, foldStyle, row) { + var line = session.getLine(row); + var isStart = this.foldingStartMarker.test(line); + var isEnd = this.foldingStopMarker.test(line); + if (isStart || isEnd) { + var match = (isEnd) ? this.foldingStopMarker.exec(line) : this.foldingStartMarker.exec(line); + var keyword = match && match[1].toLowerCase(); + if (keyword) { + var type = session.getTokenAt(row, match.index + 2).type; + if (type === "keyword.control") + return this.basicBlock(session, row, match.index + 2); + } + } + }; + + + this.getFoldWidget = function(session, foldStyle, row) { + var line = session.getLine(row); + var isStart = this.foldingStartMarker.test(line); + var isEnd = this.foldingStopMarker.test(line); + if (isStart && !isEnd) { + var match = this.foldingStartMarker.exec(line); + var keyword = match && match[1].toLowerCase(); + if (keyword) { + var type = session.getTokenAt(row, match.index + 2).type; + if (type == "keyword.control") { + return "start"; + } + } + } + if (foldStyle != "markbeginend" || !isEnd || isStart && isEnd) + return ""; + + var match = line.match(this.foldingStopMarker); + var keyword = match && match[1].toLowerCase(); + if (this.indentKeywords[keyword]) { + if (session.getTokenAt(row, match.index + 2).type === "keyword.control") + return "end"; + } + + return ""; + }; + + this.basicBlock = function(session, row, column, tokenRange) { + var stream = new TokenIterator(session, row, column); + + var token = stream.getCurrentToken(); + if (!token || token.type != "keyword.control") + return; + + var val = token.value.toLowerCase(); + var stack = [val]; + var dir = this.indentKeywords[val]; + + if (!dir) + return; + + var startColumn = dir === -1 ? stream.getCurrentTokenColumn() : session.getLine(row).length; + var startRow = row; + + stream.step = dir === -1 ? stream.stepBackward : stream.stepForward; + while(token = stream.step()) { + val = token.value.toLowerCase(); + if (token.type !== "keyword.control" || !this.indentKeywords[val]) + continue; + var level = dir * this.indentKeywords[val]; + + if (level > 0) { + stack.unshift(val); + } else if (level <= 0) { + stack.shift(); + } + if (stack.length === 0) { + break; + } + } + + if (!token) + return null; + + if (tokenRange) + return stream.getCurrentTokenRange(); + + var row = stream.getCurrentTokenRow(); + if (dir === -1) + return new Range(row, session.getLine(row).length, startRow, startColumn); + else + return new Range(startRow, startColumn, row, stream.getCurrentTokenColumn()); + }; + +}).call(FoldMode.prototype); diff --git a/src/mode/folding/basic_test.js b/src/mode/folding/basic_test.js new file mode 100644 index 00000000000..a1fd2475c7f --- /dev/null +++ b/src/mode/folding/basic_test.js @@ -0,0 +1,97 @@ +if (typeof process !== "undefined") + require("amd-loader"); + +"use strict"; + +var BasicMode = require("../basic").Mode; +var EditSession = require("../../edit_session").EditSession; +var assert = require("../../test/assertions"); + +module.exports = { + setUp: function() { + this.mode = new BasicMode(); + }, + + "test: ms-basic mode folding with markbeginend": function() { + var session = new EditSession([ + '10 INPUT"HOW MANY DIGITS";N', + '20 T=TIME', + '30 L=INT(10*N/3)+1:DIM A(L)', + '40 Z$="000000":T$="999999"', + '50 FOR I=1TOL:A(I)=2:NEXT', + '60 M=0:P=0', + '70 FOR J=1TON:Q=0:K=2*L+1', + '80 FOR I=L TO 1 STEP -1', + 'WHILE FLIPS', + 'FLIPS=0', + 'FOR I=1 TO J-1', + 'IF A$(I)>A$(I+1) THEN', + 'SWAP A$(I),', + 'A$(I+1):FLIPS=1', + 'NEXT I', + 'WEND', + '90 K=K-2:X=10*A(I)+Q*I', + '100 Q=INT(X/K):A(I)=X-Q*K', + '110 NEXT', + '120 Y=INT(Q/10):A(1)=Q-10*Y:Q=Y', + '130 IF Q=9 THEN M=M+1:GOTO170', + '140 IF Q>9 THEN PRINT CHR$(49+P);LEFT$(Z$,M);:GOTO170', + '150 PRINT CHR$(48+P);LEFT$(T$,M);', + '160 P=Q:M=0', + '170 NEXT', + '180 PRINT CHR$(48+P):PRINT (TIME-T)/59.98' + ]); + + session.setFoldStyle("markbeginend"); + session.setMode(this.mode); + + // Assert fold widgets at the start of foldable regions + assert.equal(session.getFoldWidget(6), "start"); // Line 6: FOR J=1TON + assert.equal(session.getFoldWidget(7), "start"); // Line 7: FOR I=L TO 1 STEP -1 + assert.equal(session.getFoldWidget(8), "start"); // Line 8: WHILE FLIPS + assert.equal(session.getFoldWidget(10), "start"); // Line10: FOR I=1 TO J-1 + + // Assert fold widgets at the end of foldable regions + assert.equal(session.getFoldWidget(14), "end"); // Line14: NEXT I + assert.equal(session.getFoldWidget(15), "end"); // Line15: WEND + assert.equal(session.getFoldWidget(18), "end"); // Line18: 110 NEXT + assert.equal(session.getFoldWidget(24), "end"); // Line24: 170 NEXT + + // Lines without fold widgets + for (var i = 0; i < session.getLength(); i++) { + if ([0, 1, 2, 3, 4, 6, 7, 8, 10, 14, 15, 18, 24].indexOf(i) === -1) { + assert.equal(session.getFoldWidget(i), ""); + } + } + + // Check folding ranges from start lines + var range; + range = session.getFoldWidgetRange(6); + assert.range(range, 6, 25, 24, 4); + + range = session.getFoldWidgetRange(7); + assert.range(range, 7, 23, 18, 4); + + range = session.getFoldWidgetRange(8); + assert.range(range, 8, 11, 15, 0); + + range = session.getFoldWidgetRange(10); + assert.range(range, 10, 14, 14, 0); + + // Check folding ranges from end lines + range = session.getFoldWidgetRange(14); + assert.range(range, 10, 14, 14, 0); + + range = session.getFoldWidgetRange(15); + assert.range(range, 8, 11, 15, 0); + + range = session.getFoldWidgetRange(18); + assert.range(range, 7, 23, 18, 4); + + range = session.getFoldWidgetRange(24); + assert.range(range, 6, 25, 24, 4); + } +}; + +if (typeof module !== "undefined" && module === require.main) + require("asyncjs").test.testcase(module.exports).exec(); From e486e567197824bba8d4c1efcd8a94cf7eca58c4 Mon Sep 17 00:00:00 2001 From: Danil Reznichenko <61934489+reznichenkodev@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:21:20 +0300 Subject: [PATCH 1173/1293] add hidden symbols (#5663) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Резниченко Данил Витальевич --- src/layer/text.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layer/text.js b/src/layer/text.js index 20cc1194316..3f0c992a786 100644 --- a/src/layer/text.js +++ b/src/layer/text.js @@ -350,7 +350,7 @@ class Text { $renderToken(parent, screenColumn, token, value) { var self = this; - var re = /(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC\u2066\u2067\u2068\u202A\u202B\u202D\u202E\u202C\u2069]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g; + var re = /(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC\u2066\u2067\u2068\u202A\u202B\u202D\u202E\u202C\u2069\u2060\u2061\u2062\u2063\u2064\u206A\u206B\u206B\u206C\u206D\u206E\u206F]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g; var valueFragment = this.dom.createFragment(this.element); From 25d3feec91746a2a5b0cb995d9c72768889b75f2 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Tue, 29 Oct 2024 18:37:56 +0400 Subject: [PATCH 1174/1293] improve types for internal development (#5662) --- ace-internal.d.ts | 262 +++++++++++++++++++--------------- src/ace.js | 5 +- src/anchor.js | 7 +- src/autocomplete.js | 71 ++++++---- src/bidihandler.js | 28 ++-- src/config.js | 16 +-- src/edit_session.js | 80 ++++++----- src/editor.js | 179 ++++++++++++++--------- src/ext/code_lens.js | 10 +- src/ext/searchbox.js | 30 ++-- src/ext/static_highlight.js | 33 +++-- src/incremental_search.js | 6 +- src/keyboard/keybinding.js | 14 +- src/lib/app_config.js | 6 +- src/lib/lang.js | 13 +- src/line_widgets.js | 65 ++++----- src/marker_group.js | 8 +- src/mode/behaviour.js | 6 +- src/mode/behaviour/css.js | 1 + src/mode/behaviour/cstyle.js | 19 ++- src/mode/behaviour/html.js | 1 + src/mode/behaviour/liquid.js | 1 + src/mode/behaviour/xml.js | 3 +- src/mode/behaviour/xquery.js | 7 +- src/mode/text.js | 34 +++-- src/mouse/mouse_handler.js | 8 +- src/multi_select.js | 52 +++---- src/placeholder.js | 34 ++--- src/scrollbar.js | 14 +- src/scrollbar_custom.js | 8 +- src/search.js | 66 ++++----- src/snippets.js | 69 +++++---- src/tooltip.js | 46 +++--- src/virtual_renderer.js | 268 ++++++++++++++++++----------------- 34 files changed, 808 insertions(+), 662 deletions(-) diff --git a/ace-internal.d.ts b/ace-internal.d.ts index 7a345ea0828..96d51a66eb3 100644 --- a/ace-internal.d.ts +++ b/ace-internal.d.ts @@ -26,38 +26,22 @@ export namespace Ace { type GutterHandler = import("./src/mouse/default_gutter_handler").GutterHandler; type DragdropHandler = import("./src/mouse/dragdrop_handler").DragdropHandler; type AppConfig = import("./src/lib/app_config").AppConfig; - + type Config = typeof import("./src/config"); type AfterLoadCallback = (err: Error | null, module: unknown) => void; type LoaderFunction = (moduleName: string, afterLoad: AfterLoadCallback) => void; - export interface Config { - get(key: string): any; - - set(key: string, value: any): void; - - all(): { [key: string]: any }; - - moduleUrl(name: string, component?: string): string; - - setModuleUrl(name: string, subst: string): string; - - setLoader(cb: LoaderFunction): void; - - setModuleLoader(name: string, onLoad: Function): void; - - loadModule(moduleName: string | [string, string], - onLoad?: (module: any) => void): void; - - init(packaged: any): any; - - defineOptions(obj: any, path: string, options: { [key: string]: any }): Config; - - resetOptions(obj: any): void; - - setDefaultValue(path: string, name: string, value: any): void; - - setDefaultValues(path: string, optionHash: { [key: string]: any }): void; + export interface ConfigOptions { + packaged: boolean, + workerPath: string | null, + modePath: string | null, + themePath: string | null, + basePath: string, + suffix: string, + $moduleUrls: { [url: string]: string }, + loadWorkerFromBlob: boolean, + sharedPopups: boolean, + useStrictCSP: boolean | null } interface Theme { @@ -364,7 +348,7 @@ export namespace Ace { highlightGutterLine: boolean; hScrollBarAlwaysVisible: boolean; vScrollBarAlwaysVisible: boolean; - fontSize: string; + fontSize: string | number; fontFamily: string; maxLines: number; minLines: number; @@ -414,6 +398,7 @@ export namespace Ace { enableMultiselect: boolean; enableKeyboardAccessibility: boolean; enableCodeLens: boolean; + textInputAriaLabel: string; enableMobileMenu: boolean; } @@ -427,15 +412,10 @@ export namespace Ace { * @param delta */ "change": (delta: Delta) => void; - /** - * Emitted when the selection changes. - */ - "changeSelection": () => void; /** * Emitted when the tab size changes, via [[EditSession.setTabSize]]. - * @param tabSize */ - "changeTabSize": (tabSize: number) => void; + "changeTabSize": () => void; /** * Emitted when the ability to overwrite text changes, via [[EditSession.setOverwrite]]. * @param overwrite @@ -445,46 +425,43 @@ export namespace Ace { * Emitted when the gutter changes, either by setting or removing breakpoints, or when the gutter decorations change. * @param e */ - "changeBreakpoint": (e: { row: number, breakpoint: boolean }) => void; + "changeBreakpoint": (e?: { row?: number, breakpoint?: boolean }) => void; /** * Emitted when a front marker changes. - * @param e */ - "changeFrontMarker": (e: { row: number, marker: boolean }) => void; + "changeFrontMarker": () => void; /** * Emitted when a back marker changes. - * @param e */ - "changeBackMarker": (e: { row: number, marker: boolean }) => void; + "changeBackMarker": () => void; /** * Emitted when an annotation changes, like through [[EditSession.setAnnotations]]. - * @param e */ - "changeAnnotation": (e: { row: number, lines: string[] }) => void; + "changeAnnotation": (e: {}) => void; /** * Emitted when a background tokenizer asynchronously processes new rows. */ - "tokenizerUpdate": (e: { data: { first: string, last: string } }) => void; + "tokenizerUpdate": (e: { data: { first: number, last: number } }) => void; /** * Emitted when the current mode changes. * @param e */ - "changeMode": (e) => void; + "changeMode": (e: any) => void; /** * Emitted when the wrap mode changes. * @param e */ - "changeWrapMode": (e) => void; + "changeWrapMode": (e: any) => void; /** * Emitted when the wrapping limit changes. * @param e */ - "changeWrapLimit": (e) => void; + "changeWrapLimit": (e: any) => void; /** * Emitted when a code fold is added or removed. * @param e */ - "changeFold": (e, session: EditSession) => void; + "changeFold": (e: any, session?: EditSession) => void; /** * Emitted when the scroll top changes. * @param scrollTop The new scroll top value @@ -495,17 +472,11 @@ export namespace Ace { * @param scrollLeft The new scroll left value **/ "changeScrollLeft": (scrollLeft: number) => void; - "changeEditor": (e: { editor: Editor }) => void; - /** - * Emitted after operation starts. - * @param commandEvent event causing the operation - */ - "startOperation": (commandEvent) => void; - /** - * Emitted after operation finishes. - * @param e event causing the finish - */ - "endOperation": (e) => void; + "changeEditor": (e: { editor?: Editor, oldEditor?: Editor }) => void; + "changeSelection": () => void; + "startOperation": (op?: { command?: { name?: string }, args?: any }) => void; + "endOperation": (op?: any) => void; + "beforeEndOperation": () => void; } interface EditorEvents { @@ -517,31 +488,40 @@ export namespace Ace { * @param e An object with two properties, `oldSession` and `session`, that represent the old and new [[EditSession]]s. **/ "changeSession": (e: { oldSession: EditSession, session: EditSession }) => void; - "blur": (e) => void; + "blur": (e: any) => void; "mousedown": (e: MouseEvent) => void; - "mousemove": (e: MouseEvent & { scrollTop? }, editor?: Editor) => void; - "changeStatus": () => void; - "keyboardActivity": () => void; + "mousemove": (e: MouseEvent & { scrollTop?: any }, editor?: Editor) => void; + "changeStatus": (e: any) => void; + "keyboardActivity": (e: any) => void; "mousewheel": (e: MouseEvent) => void; "mouseup": (e: MouseEvent) => void; - "beforeEndOperation": (e) => void; - "nativecontextmenu": (e) => void; - "destroy": () => void; - "focus": () => void; + "beforeEndOperation": (e: any) => void; + "nativecontextmenu": (e: any) => void; + "destroy": (e: any) => void; + "focus": (e?: any) => void; /** * Emitted when text is copied. * @param text The copied text **/ - "copy": (text: string) => void; + "copy": (e: { text: string }) => void; /** * Emitted when text is pasted. **/ - "paste": (text: string, event) => void; + "paste": (text: string, event: any) => void; /** * Emitted when the selection style changes, via [[Editor.setSelectionStyle]]. * @param data Contains one property, `data`, which indicates the new selection style **/ "changeSelectionStyle": (data: "fullLine" | "screenLine" | "text" | "line") => void; + "changeMode": (e: { mode?: Ace.SyntaxMode, oldMode?: Ace.SyntaxMode }) => void; + + //from searchbox extension + "findSearchBox": (e: { match: boolean }) => void; + + //from code_lens extension + "codeLensClick": (e: any) => void; + + "select": () => void; } interface AcePopupEvents { @@ -552,7 +532,7 @@ export namespace Ace { "show": () => void; "hide": () => void; "select": (hide: boolean) => void; - "changeHoverMarker": (e) => void; + "changeHoverMarker": (e: any) => void; } interface DocumentEvents { @@ -586,9 +566,11 @@ export namespace Ace { interface BackgroundTokenizerEvents { /** * Fires whenever the background tokeniziers between a range of rows are going to be updated. - * @param {Object} e An object containing two properties, `first` and `last`, which indicate the rows of the region being updated. + * @param e An object containing two properties, `first` and `last`, which indicate the rows of the region being updated. **/ - "update": (e: { first: number, last: number }) => void; + "update": (e: { + data: { first: number, last: number } + }) => void; } interface SelectionEvents { @@ -602,21 +584,36 @@ export namespace Ace { "changeSelection": () => void; } - interface PlaceHolderEvents { + interface MultiSelectionEvents extends SelectionEvents { + "multiSelect": () => void; + "addRange": (e: { range: Range }) => void; + "removeRange": (e: { ranges: Range[] }) => void; + "singleSelect": () => void; + } + interface PlaceHolderEvents { + "cursorEnter": (e: any) => void; + "cursorLeave": (e: any) => void; } interface GutterEvents { "changeGutterWidth": (width: number) => void; + "afterRender": () => void; } interface TextEvents { - "changeCharacterSize": (e) => void; + "changeCharacterSize": (e: any) => void; } interface VirtualRendererEvents { - "afterRender": (e, renderer: VirtualRenderer) => void; - "beforeRender": (e, renderer: VirtualRenderer) => void; + "afterRender": (e?: any, renderer?: VirtualRenderer) => void; + "beforeRender": (e: any, renderer?: VirtualRenderer) => void; + "themeLoaded": (e: { theme: string | Theme }) => void; + "themeChange": (e: { theme: string | Theme }) => void; + "scrollbarVisibilityChanged": () => void; + "changeCharacterSize": (e: any) => void; + "resize": (e?: any) => void; + "autosize": () => void; } class EventEmitter { @@ -638,26 +635,42 @@ export namespace Ace { removeAllListeners(name?: string): void; - _signal(eventName: string, e: any): void; + _signal(eventName: K, ...args: Parameters): void; - _emit(eventName: string, e: any): void; + _emit(eventName: K, ...args: Parameters): void; - _dispatchEvent(eventName: string, e: any): void; + _dispatchEvent(eventName: K, ...args: Parameters): void; } interface SearchOptions { + /**The string or regular expression you're looking for*/ needle: string | RegExp; preventScroll: boolean; + /**Whether to search backwards from where cursor currently is*/ backwards: boolean; + /**The starting [[Range]] or cursor position to begin the search*/ start: Range; + /**Whether or not to include the current line in the search*/ skipCurrent: boolean; - range: Range; + /**The [[Range]] to search within. Set this to `null` for the whole document*/ + range: Range | null; preserveCase: boolean; + /**Whether the search is a regular expression or not*/ regExp: boolean; + /**Whether the search matches only on whole words*/ wholeWord: boolean; + /**Whether the search ought to be case-sensitive*/ caseSensitive: boolean; + /**Whether to wrap the search back to the beginning when it hits the end*/ wrap: boolean; - re: RegExp; + re: any; + /**true, if needle has \n or \r\n*/ + $isMultiLine: boolean; + /** + * internal property, determine if browser supports unicode flag + * @private + * */ + $supportsUnicodeFlag: boolean; } interface Point { @@ -711,7 +724,7 @@ export namespace Ace { type KeyboardHandler = Partial & { attach?: (editor: Editor) => void; detach?: (editor: Editor) => void; - getStatusText?: (editor?: any, data?) => string; + getStatusText?: (editor?: any, data?: any) => string; } export interface MarkerLike { @@ -805,6 +818,8 @@ export namespace Ace { type BehaviorMap = Record>; interface Behaviour { + $behaviours: { [behaviour: string]: any } + add(name: string, action: string, callback: BehaviorAction): void; addBehaviours(behaviours: BehaviorMap): void; @@ -891,7 +906,7 @@ export namespace Ace { $createKeywordList(): string[]; - $delegator(method: string, args: IArguments, defaultHandler): any; + $delegator(method: string, args: IArguments, defaultHandler: any): any; } @@ -943,7 +958,7 @@ export namespace Ace { interface TextInput { resetSelection(): void; - setAriaOption(options?: { activeDescendant: string, role: string, setLabel }): void; + setAriaOption(options?: { activeDescendant: string, role: string, setLabel: any }): void; } type CompleterCallback = (error: any, completions: Completion[]) => void; @@ -958,13 +973,16 @@ export namespace Ace { callback: CompleterCallback): void; getDocTooltip?(item: Completion): void | string | Completion; + onSeen?: (editor: Ace.Editor, completion: Completion) => void; onInsert?: (editor: Ace.Editor, completion: Completion) => void; + cancel?(): void; id?: string; triggerCharacters?: string[]; hideInlinePreview?: boolean; + insertMatch?: (editor: Editor, data: Completion) => void; } interface CompletionOptions { @@ -997,18 +1015,18 @@ export namespace Ace { * Adds the selection and cursor. * @param orientedRange A range containing a cursor **/ - addSelectionMarker: (orientedRange: Ace.Range & { marker? }) => Ace.Range & { marker? }, + addSelectionMarker: (orientedRange: Ace.Range & { marker?: any }) => Ace.Range & { marker?: any }, /** * Removes the selection marker. * @param range The selection range added with [[Editor.addSelectionMarker `addSelectionMarker()`]]. **/ - removeSelectionMarker: (range: Ace.Range & { marker? }) => void, - removeSelectionMarkers: (ranges: (Ace.Range & { marker? })[]) => void, - $onAddRange: (e) => void, - $onRemoveRange: (e) => void, - $onMultiSelect: (e) => void, - $onSingleSelect: (e) => void, - $onMultiSelectExec: (e) => void, + removeSelectionMarker: (range: Ace.Range & { marker?: any }) => void, + removeSelectionMarkers: (ranges: (Ace.Range & { marker?: any })[]) => void, + $onAddRange: (e: any) => void, + $onRemoveRange: (e: any) => void, + $onMultiSelect: (e: any) => void, + $onSingleSelect: (e: any) => void, + $onMultiSelectExec: (e: any) => void, /** * Executes a command for each selection range. * @param cmd The command to execute @@ -1020,7 +1038,7 @@ export namespace Ace { **/ exitMultiSelectMode: () => void, getSelectedText: () => string, - $checkMultiselectChange: (e, anchor: Ace.Anchor) => void, + $checkMultiselectChange: (e: any, anchor: Ace.Anchor) => void, /** * Finds and selects all the occurrences of `needle`. * @param needle The text to find @@ -1057,8 +1075,17 @@ export namespace Ace { $blockSelectEnabled?: boolean, } + interface CodeLenseProvider { + provideCodeLenses: (session: EditSession, callback: (err: any, payload: CodeLense[]) => void) => void; + } + + interface CodeLense { + start: Point, + command: any + } + interface CodeLenseEditorExtension { - codeLensProviders?: any[]; + codeLensProviders?: CodeLenseProvider[]; $codeLensClickHandler?: any; $updateLenses?: () => void; $updateLensesOnInput?: () => void; @@ -1168,7 +1195,7 @@ export namespace Ace { type TooltipCommandFunction = (editor: Ace.Editor) => T; export interface TooltipCommand extends Ace.Command { - enabled: TooltipCommandFunction | boolean, + enabled?: TooltipCommandFunction | boolean, getValue?: TooltipCommandFunction, type: "button" | "text" | "checkbox" iconCssClass?: string, @@ -1181,6 +1208,14 @@ export namespace Ace { className?: string, value: string, }>> + + export interface StaticHighlightOptions { + mode?: string | SyntaxMode, + theme?: string | Theme, + trim?: boolean, + firstLineNumber?: number, + showGutter?: boolean + } } @@ -1189,10 +1224,10 @@ export const config: Ace.Config; export function require(name: string): any; -export function edit(el: string | (Element & { - env?; - value?; -}), options?: Partial): Ace.Editor; +export function edit(el?: string | (Element & { + env?: any; + value?: any; +}) | null, options?: Partial): Ace.Editor; export function createEditSession(text: Ace.Document | string, mode: Ace.SyntaxMode): Ace.EditSession; @@ -1220,6 +1255,7 @@ export type CommandBarTooltip = Ace.CommandBarTooltip; declare global { interface Element { setAttribute(name: string, value: boolean): void; + setAttribute(name: string, value: number): void; } } @@ -1252,7 +1288,6 @@ declare module "./src/background_tokenizer" { declare module "./src/document" { export interface Document extends Ace.EventEmitter { - } } @@ -1301,12 +1336,6 @@ declare module "./src/edit_session" { widgetManager?: any, $bracketHighlight?: any, $selectionMarker?: number, - curOp?: { - command: {}, - args: string, - scrollTop: number, - [key: string]: any; - }, lineWidgetsWidth?: number, $getWidgetScreenLength?: () => number, _changedWidgets?: any, @@ -1315,9 +1344,6 @@ declare module "./src/edit_session" { $enableVarChar?: any, $wrap?: any, $navigateWithinSoftTabs?: boolean, - - getSelectionMarkers(): any[], - $selectionMarkers?: any[], gutterRenderer?: any, $firstLineNumber?: number, @@ -1329,6 +1355,14 @@ declare module "./src/edit_session" { $occurMatchingLines?: any, $useEmacsStyleLineStart?: boolean, $selectLongWords?: boolean, + curOp?: { + command: {}, + args: string, + scrollTop: number, + [key: string]: any; + }, + + getSelectionMarkers(): any[], } } @@ -1369,9 +1403,8 @@ declare module "./src/line_widgets" { } declare module "./src/selection" { - export interface Selection extends Ace.EventEmitter, Ace.MultiSelectProperties { + export interface Selection extends Ace.EventEmitter, Ace.MultiSelectProperties { } - } declare module "./src/range" { @@ -1397,7 +1430,6 @@ declare module "./src/virtual_renderer" { $maxLines?: number, $scrollPastEnd?: number, enableKeyboardAccessibility?: boolean, - keyboardFocusClassName?: string, $highlightGutterLine?: boolean, $minLines?: number, $maxPixelHeight?: number, @@ -1410,12 +1442,13 @@ declare module "./src/virtual_renderer" { $theme?: any, destroyed?: boolean, session: Ace.EditSession, + keyboardFocusClassName?: string, } } declare module "./src/snippets" { - export interface SnippetManager extends Ace.EventEmitter { + interface SnippetManager extends Ace.EventEmitter { } } @@ -1526,3 +1559,8 @@ declare module "./src/mouse/default_gutter_handler" { export interface GutterHandler { } } + +declare module "./src/lib/keys" { + export function keyCodeToString(keyCode: number): string; +} + diff --git a/src/ace.js b/src/ace.js index 86ea484a156..2e2180fdd5a 100644 --- a/src/ace.js +++ b/src/ace.js @@ -28,7 +28,7 @@ exports.config = require("./config"); /** * Embeds the Ace editor into the DOM, at the element provided by `el`. - * @param {String | HTMLElement & {env?, value?}} el Either the id of an element, or the element itself + * @param {String | HTMLElement & {env?: any, value?: any} | null} [el] Either the id of an element, or the element itself * @param {Object } [options] Options for the editor * @returns {Editor} **/ @@ -86,4 +86,5 @@ exports.Editor = Editor; exports.EditSession = EditSession; exports.UndoManager = UndoManager; exports.VirtualRenderer = Renderer; -exports.version = exports.config.version; +var version = exports.config.version; +exports.version = version; diff --git a/src/anchor.js b/src/anchor.js index b5d112c9a6d..4959ec1fa0e 100644 --- a/src/anchor.js +++ b/src/anchor.js @@ -25,7 +25,7 @@ class Anchor { else this.setPosition(row, column); } - + /** * Returns an object identifying the `row` and `column` position of the current anchor. * @returns {import("../ace-internal").Ace.Point} @@ -42,10 +42,11 @@ class Anchor { getDocument() { return this.document; } - + /** * Internal function called when `"change"` event fired. * @param {import("../ace-internal").Ace.Delta} delta + * @internal */ onChange(delta) { if (delta.start.row == delta.end.row && delta.start.row != this.row) @@ -53,7 +54,7 @@ class Anchor { if (delta.start.row > this.row) return; - + var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight); this.setPosition(point.row, point.column, true); } diff --git a/src/autocomplete.js b/src/autocomplete.js index 520c74ec070..a46dfc3704b 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -3,6 +3,7 @@ * @typedef {import("./editor").Editor} Editor * @typedef {import("../ace-internal").Ace.CompletionProviderOptions} CompletionProviderOptions * @typedef {import("../ace-internal").Ace.CompletionOptions} CompletionOptions + * @typedef {import("../ace-internal").Ace.Position} Position */ var HashHandler = require("./keyboard/hash_handler").HashHandler; var AcePopup = require("./autocomplete/popup").AcePopup; @@ -31,7 +32,7 @@ var preventParentScroll = require("./lib/scroll").preventParentScroll; * @property {string} [command] - A command to be executed after the completion is inserted (experimental) * @property {string} [snippet] - a text snippet that would be inserted when the completion is selected * @property {string} [value] - The text that would be inserted when selecting this completion. - * @property {import("../ace-internal").Ace.Completer & {insertMatch:(editor: Editor, data: Completion) => void}} [completer] + * @property {import("../ace-internal").Ace.Completer} [completer] * @property {boolean} [hideInlinePreview] * @export */ @@ -76,10 +77,11 @@ class Autocomplete { this.keyboardHandler.bindKeys(this.commands); this.parentNode = null; this.setSelectOnHover = false; + /**@private*/ this.hasSeen = new Set(); /** - * @property {Boolean} showLoadingState - A boolean indicating whether the loading states of the Autocompletion should be shown to the end-user. If enabled + * @property {Boolean} showLoadingState - A boolean indicating whether the loading states of the Autocompletion should be shown to the end-user. If enabled * it shows a loading indicator on the popup while autocomplete is loading. * * Experimental: This visualisation is not yet considered stable and might change in the future. @@ -255,6 +257,10 @@ class Autocomplete { }); this.$elements = null; } + + /** + * @internal + */ onLayoutChange() { if (!this.popup.isOpen) return this.unObserveLayoutChanges(); this.$updatePopupPosition(); @@ -470,7 +476,7 @@ class Autocomplete { /** * This is the entry point for the autocompletion class, triggers the actions which collect and display suggestions * @param {Editor} editor - * @param {CompletionOptions} options + * @param {CompletionOptions} [options] */ showPopup(editor, options) { if (this.editor) @@ -493,6 +499,11 @@ class Autocomplete { this.updateCompletions(false, options); } + /** + * + * @param {{pos: Position, prefix: string}} [initialPosition] + * @return {CompletionProvider} + */ getCompletionProvider(initialPosition) { if (!this.completionProvider) this.completionProvider = new CompletionProvider(initialPosition); @@ -510,7 +521,7 @@ class Autocomplete { /** * @param {boolean} keepPopupPosition - * @param {CompletionOptions} options + * @param {CompletionOptions} [options] */ updateCompletions(keepPopupPosition, options) { if (keepPopupPosition && this.base && this.completions) { @@ -705,7 +716,11 @@ class Autocomplete { if (el.parentNode) el.parentNode.removeChild(el); } - + + /** + * @param e + * @internal + */ onTooltipClick(e) { var a = e.target; while (a && a != this.tooltipNode) { @@ -733,6 +748,30 @@ class Autocomplete { this.inlineRenderer = this.popup = this.editor = null; } + /** + * @param {Editor} editor + * @return {Autocomplete} + */ + static for(editor) { + if (editor.completer instanceof Autocomplete) { + return editor.completer; + } + if (editor.completer) { + editor.completer.destroy(); + editor.completer = null; + } + if (config.get("sharedPopups")) { + if (!Autocomplete["$sharedInstance"]) + Autocomplete["$sharedInstance"] = new Autocomplete(); + editor.completer = Autocomplete["$sharedInstance"]; + } else { + editor.completer = new Autocomplete(); + editor.once("destroy", destroyCompleter); + } + // @ts-expect-error + return editor.completer; + } + } Autocomplete.prototype.commands = { @@ -762,26 +801,6 @@ Autocomplete.prototype.commands = { "PageDown": function(editor) { editor.completer.popup.gotoPageDown(); } }; - -Autocomplete.for = function(editor) { - if (editor.completer instanceof Autocomplete) { - return editor.completer; - } - if (editor.completer) { - editor.completer.destroy(); - editor.completer = null; - } - if (config.get("sharedPopups")) { - if (!Autocomplete["$sharedInstance"]) - Autocomplete["$sharedInstance"] = new Autocomplete(); - editor.completer = Autocomplete["$sharedInstance"]; - } else { - editor.completer = new Autocomplete(); - editor.once("destroy", destroyCompleter); - } - return editor.completer; -}; - Autocomplete.startCommand = { name: "startAutocomplete", exec: function(editor, options) { @@ -803,7 +822,7 @@ class CompletionProvider { /** - * @param {{pos: import("../ace-internal").Ace.Position, prefix: string}} initialPosition + * @param {{pos: Position, prefix: string}} [initialPosition] */ constructor(initialPosition) { this.initialPosition = initialPosition; diff --git a/src/bidihandler.js b/src/bidihandler.js index 003822fcafd..20f023613e2 100644 --- a/src/bidihandler.js +++ b/src/bidihandler.js @@ -39,7 +39,7 @@ class BidiHandler { this.isMoveLeftOperation = false; this.seenBidi = bidiRE.test(session.getValue()); } - + /** * Returns 'true' if row contains Bidi characters, in such case * creates Bidi map to be used in operations related to selection @@ -59,13 +59,17 @@ class BidiHandler { return this.bidiMap.bidiLevels; } + /** + * @param {import("../ace-internal").Ace.Delta} delta + * @internal + */ onChange(delta) { if (!this.seenBidi) { if (delta.action == "insert" && bidiRE.test(delta.lines.join("\n"))) { this.seenBidi = true; this.currentRow = null; } - } + } else { this.currentRow = null; } @@ -106,7 +110,7 @@ class BidiHandler { updateRowLine(docRow, splitIndex) { if (docRow === undefined) docRow = this.getDocumentRow(); - + var isLastRow = (docRow === this.session.getLength() - 1), endOfLine = isLastRow ? this.EOF : this.EOL; @@ -136,7 +140,7 @@ class BidiHandler { } else { this.line += this.showInvisibles ? endOfLine : bidiUtil.DOT; } - + /* replace tab and wide characters by commensurate spaces */ var session = this.session, shift = 0, size; this.line = this.line.replace(/\t|[\u1100-\u2029, \u202F-\uFFE6]/g, function(ch, i){ @@ -153,7 +157,7 @@ class BidiHandler { this.rtlLineOffset = this.contentWidth - this.fontMetrics.$main.getBoundingClientRect().width; } } - + updateBidiMap() { var textCharTypes = []; if (bidiUtil.hasBidiCharacters(this.line, textCharTypes) || this.isRtlDir) { @@ -197,7 +201,7 @@ class BidiHandler { } setEolChar(eolChar) { - this.EOL = eolChar; + this.EOL = eolChar; } setContentWidth(width) { @@ -209,11 +213,11 @@ class BidiHandler { if (row != undefined) return (this.session.getLine(row).charAt(0) == this.RLE); else - return this.isRtlDir; + return this.isRtlDir; } setRtlDirection(editor, isRtlDir) { - var cursor = editor.getCursorPosition(); + var cursor = editor.getCursorPosition(); for (var row = editor.selection.getSelectionAnchor().row; row <= cursor.row; row++) { if (!isRtlDir && editor.session.getLine(row).charAt(0) === editor.session.$bidiHandler.RLE) editor.session.doc.removeInLine(row, 0, 1); @@ -238,7 +242,7 @@ class BidiHandler { if (!this.session.getOverwrite() && col <= leftBoundary && levels[visualIdx] % 2 !== 0) visualIdx++; - + for (var i = 0; i < visualIdx; i++) { left += this.charWidths[levels[i]]; } @@ -266,7 +270,7 @@ class BidiHandler { var map = this.bidiMap, levels = map.bidiLevels, level, selections = [], offset = 0, selColMin = Math.min(startCol, endCol) - this.wrapIndent, selColMax = Math.max(startCol, endCol) - this.wrapIndent, isSelected = false, isSelectedPrev = false, selectionStart = 0; - + if (this.wrapIndent) offset += this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset; @@ -311,7 +315,7 @@ class BidiHandler { if (this.wrapIndent) posX -= this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset; - + while(posX > offset + charWidth/2) { offset += charWidth; if(visualIdx === levels.length - 1) { @@ -321,7 +325,7 @@ class BidiHandler { } charWidth = this.charWidths[levels[++visualIdx]]; } - + if (visualIdx > 0 && (levels[visualIdx - 1] % 2 !== 0) && (levels[visualIdx] % 2 === 0)){ /* Bidi character on the left and None Bidi character on the right */ if(posX < offset) diff --git a/src/config.js b/src/config.js index 0a76b117f4b..d4662231f17 100644 --- a/src/config.js +++ b/src/config.js @@ -6,6 +6,7 @@ var AppConfig = require("./lib/app_config").AppConfig; module.exports = exports = new AppConfig(); +/** @type {import("../ace-internal").Ace.ConfigOptions} */ var options = { packaged: false, workerPath: null, @@ -20,8 +21,9 @@ var options = { }; /** - * @param {string} key - * @return {*} + * @template {keyof import("../ace-internal").Ace.ConfigOptions} K + * @param {K} key - The key of the config option to retrieve. + * @returns {import("../ace-internal").Ace.ConfigOptions[K]} - The value of the config option. */ exports.get = function(key) { if (!options.hasOwnProperty(key)) @@ -30,8 +32,9 @@ exports.get = function(key) { }; /** - * @param {string} key - * @param value + * @template {keyof import("../ace-internal").Ace.ConfigOptions} K + * @param {K} key + * @param {import("../ace-internal").Ace.ConfigOptions[K]} value */ exports.set = function(key, value) { if (options.hasOwnProperty(key)) @@ -42,7 +45,7 @@ exports.set = function(key, value) { dom.useStrictCSP(value); }; /** - * @return {{[key: string]: any}} + * @return {import("../ace-internal").Ace.ConfigOptions} */ exports.all = function() { return lang.copyObject(options); @@ -100,9 +103,6 @@ var loader = function(moduleName, cb) { console.error("loader is not configured"); }; var customLoader; -/** - * @param {(moduleName: string, afterLoad: (err: Error | null, module: unknown) => void) => void}cb - */ exports.setLoader = function(cb) { customLoader = cb; }; diff --git a/src/edit_session.js b/src/edit_session.js index 0546545c505..7fef86d933d 100644 --- a/src/edit_session.js +++ b/src/edit_session.js @@ -54,10 +54,10 @@ class EditSession { return this.join("\n"); }; - // Set default background tokenizer with Text mode until editor session mode is set + // Set default background tokenizer with Text mode until editor session mode is set this.bgTokenizer = new BackgroundTokenizer((new TextMode()).getTokenizer(), this); - + var _self = this; this.bgTokenizer.on("update", function(e) { _self._signal("tokenizerUpdate", e); @@ -135,7 +135,7 @@ class EditSession { /** * End current Ace operation. * Emits "beforeEndOperation" event just before clearing everything, where the current operation can be accessed through `curOp` property. - * @param {any} e + * @param {any} e */ endOperation(e) { if (this.curOp) { @@ -235,14 +235,19 @@ class EditSession { this.bgTokenizer.start(0); } + /** + * @param e + * @internal + */ onChangeFold(e) { var fold = e.data; this.$resetRowCache(fold.start.row); } /** - * + * * @param {Delta} delta + * @internal */ onChange(delta) { this.$modified = true; @@ -261,7 +266,7 @@ class EditSession { } this.$undoManager.add(delta, this.mergeUndoDeltas); this.mergeUndoDeltas = true; - + this.$informUndoManager.schedule(); } @@ -300,7 +305,7 @@ class EditSession { undoManager.$redoStack = session.history.redo; undoManager.mark = session.history.mark; undoManager.$rev = session.history.rev; - + const editSession = new EditSession(session.value); session.folds.forEach(function(fold) { editSession.addFold("...", Range.fromPoints(fold.start, fold.end)); @@ -312,10 +317,10 @@ class EditSession { editSession.setScrollTop(session.scrollTop); editSession.setUndoManager(undoManager); editSession.selection.fromJSON(session.selection); - + return editSession; } - + /** * Returns the current edit session. * @method toJSON @@ -336,7 +341,7 @@ class EditSession { value: this.doc.getValue() }; } - + /** * Returns the current [[Document `Document`]] as a string. * @method toString @@ -409,10 +414,10 @@ class EditSession { **/ setUndoManager(undoManager) { this.$undoManager = undoManager; - + if (this.$informUndoManager) this.$informUndoManager.cancel(); - + if (undoManager) { var self = this; undoManager.addSession(this); @@ -462,7 +467,7 @@ class EditSession { setUseSoftTabs(val) { this.setOption("useSoftTabs", val); } - + /** * Returns `true` if soft tabs are being used, `false` otherwise. * @returns {Boolean} @@ -861,13 +866,14 @@ class EditSession { /** * Reloads all the tokens on the current session. This function calls [[BackgroundTokenizer.start `BackgroundTokenizer.start ()`]] to all the rows; it also emits the `'tokenizerUpdate'` event. + * @internal **/ onReloadTokenizer(e) { var rows = e.data; this.bgTokenizer.start(rows.first); this._signal("tokenizerUpdate", e); } - + /** * Sets a new text mode for the `EditSession`. This method also emits the `'changeMode'` event. If a [[BackgroundTokenizer `BackgroundTokenizer`]] is set, the `'tokenizerUpdate'` event is also emitted. * @param {SyntaxMode | string} mode Set a new text mode @@ -922,9 +928,9 @@ class EditSession { $onChangeMode(mode, $isPlaceholder) { if (!$isPlaceholder) this.$modeId = mode.$id; - if (this.$mode === mode) + if (this.$mode === mode) return; - + var oldMode = this.$mode; this.$mode = mode; @@ -948,7 +954,7 @@ class EditSession { /**@type {RegExp}*/ this.nonTokenRe = mode.nonTokenRe; - + if (!$isPlaceholder) { // experimental method, used by c9 findiniles if (mode.attachToSession) @@ -989,7 +995,7 @@ class EditSession { * @param {Number} scrollTop The new scroll top value **/ setScrollTop(scrollTop) { - // TODO: should we force integer lineheight instead? scrollTop = Math.round(scrollTop); + // TODO: should we force integer lineheight instead? scrollTop = Math.round(scrollTop); if (this.$scrollTop === scrollTop || isNaN(scrollTop)) return; @@ -1032,7 +1038,7 @@ class EditSession { **/ getScreenWidth() { this.$computeWidth(); - if (this.lineWidgets) + if (this.lineWidgets) return Math.max(this.getLineWidgetMaxWidth(), this.screenWidth); return this.screenWidth; } @@ -1144,7 +1150,7 @@ class EditSession { remove(range) { return this.doc.remove(range); } - + /** * Removes a range of full lines. This method also triggers the `'change'` event. * @param {Number} firstRow The first row to be removed @@ -1218,14 +1224,14 @@ class EditSession { /** * Enables or disables highlighting of the range where an undo occurred. * @param {Boolean} enable If `true`, selects the range of the reinserted change - * + * **/ setUndoSelect(enable) { this.$undoSelect = enable; } /** - * + * * @param {Delta[]} deltas * @param {boolean} [isUndo] * @return {Range} @@ -1248,7 +1254,7 @@ class EditSession { } continue; } - + if (isInsert(delta)) { point = delta.start; if (range.compare(point.row, point.column) == -1) { @@ -1381,7 +1387,7 @@ class EditSession { } /** - * + * * @param {number} firstRow * @param {number} lastRow * @param [dir] @@ -1411,7 +1417,7 @@ class EditSession { x.end.row += diff; return x; }); - + var lines = dir == 0 ? this.doc.getLines(firstRow, lastRow) : this.doc.removeFullLines(firstRow, lastRow); @@ -1521,7 +1527,7 @@ class EditSession { } return range; } - + /** * Sets whether or not line wrapping is enabled. If `useWrapMode` is different than the current value, the `'changeWrapMode'` event is emitted. * @param {Boolean} useWrapMode Enable (or disable) wrap mode @@ -1597,7 +1603,7 @@ class EditSession { } /** - * + * * @param {number} wrapLimit * @param {number} [min] * @param {number} [max] @@ -1620,7 +1626,7 @@ class EditSession { getWrapLimit() { return this.$wrapLimit; } - + /** * Sets the line length for soft wrap in the editor. Lines will break * at a minimum of the given length minus 20 chars and at a maximum @@ -1630,7 +1636,7 @@ class EditSession { setWrapLimit(limit) { this.setWrapLimitRange(limit, limit); } - + /** * Returns an object that defines the minimum and maximum of the wrap limit; it looks something like this: * @@ -1658,7 +1664,7 @@ class EditSession { var lastRow = end.row; var len = lastRow - firstRow; var removedFolds = null; - + this.$updating = true; if (len != 0) { if (action === "remove") { @@ -2053,13 +2059,13 @@ class EditSession { var h = 1; if (this.lineWidgets) h += this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0; - + if (!this.$useWrapMode || !this.$wrapData[row]) return h; else return this.$wrapData[row].length + h; } - + /** * @param {Number} row * @returns {Number} @@ -2351,7 +2357,7 @@ class EditSession { wrapIndent = screenRowOffset > 0 ? wrapRow.indent : 0; } } - + if (this.lineWidgets && this.lineWidgets[row] && this.lineWidgets[row].rowsAbove) screenRow += this.lineWidgets[row].rowsAbove; @@ -2434,7 +2440,7 @@ class EditSession { if (!maxScreenColumn) maxScreenColumn = Infinity; screenColumn = screenColumn || 0; - + var c, column; for (column = 0; column < str.length; column++) { c = str.charAt(column); @@ -2448,7 +2454,7 @@ class EditSession { break; } } - + return [screenColumn, column]; }; } @@ -2522,7 +2528,7 @@ EditSession.prototype.$wrapLimitRange = { max : null }; /** - * + * * @type {null | import("../ace-internal").Ace.LineWidget[]} */ EditSession.prototype.lineWidgets = null; @@ -2619,7 +2625,7 @@ config.defineOptions(EditSession.prototype, "session", { return "off"; }, handlesSet: true - }, + }, wrapMethod: { /** * @param {"code"|"text"|"auto"|boolean} val @@ -2649,7 +2655,7 @@ config.defineOptions(EditSession.prototype, "session", { this.setUseWrapMode(true); } }, - initialValue: true + initialValue: true }, firstLineNumber: { set: function() {this._signal("changeBreakpoint");}, diff --git a/src/editor.js b/src/editor.js index 62e1d613910..2ad6199af47 100644 --- a/src/editor.js +++ b/src/editor.js @@ -49,9 +49,9 @@ class Editor { constructor(renderer, session, options) { /**@type{EditSession}*/this.session; this.$toDestroy = []; - + var container = renderer.getContainerElement(); - /**@type {HTMLElement & {env?, value?}}*/ + /**@type {HTMLElement & {env?:any, value?:any}}*/ this.container = container; /**@type {VirtualRenderer}*/ this.renderer = renderer; @@ -104,7 +104,7 @@ class Editor { this.session.startOperation(commandEvent); } - /** + /** * @arg e */ endOperation(e) { @@ -121,7 +121,7 @@ class Editor { } } - /** + /** * @arg e */ onEndOperation(e) { @@ -168,7 +168,7 @@ class Editor { } } - /** + /** * @param e */ $historyTracker(e) { @@ -238,7 +238,7 @@ class Editor { } - + /** * Sets a new editsession to use. This method also emits the `'changeSession'` event. * @param {EditSession} [session] The new session to use @@ -246,7 +246,7 @@ class Editor { setSession(session) { if (this.session == session) return; - + // make sure operationEnd events are not emitted to wrong session if (this.curOp) this.endOperation(); this.curOp = {}; @@ -280,49 +280,49 @@ class Editor { this.$onDocumentChange = this.onDocumentChange.bind(this); session.on("change", this.$onDocumentChange); this.renderer.setSession(session); - + this.$onChangeMode = this.onChangeMode.bind(this); session.on("changeMode", this.$onChangeMode); - + this.$onTokenizerUpdate = this.onTokenizerUpdate.bind(this); session.on("tokenizerUpdate", this.$onTokenizerUpdate); - + this.$onChangeTabSize = this.renderer.onChangeTabSize.bind(this.renderer); session.on("changeTabSize", this.$onChangeTabSize); - + this.$onChangeWrapLimit = this.onChangeWrapLimit.bind(this); session.on("changeWrapLimit", this.$onChangeWrapLimit); - + this.$onChangeWrapMode = this.onChangeWrapMode.bind(this); session.on("changeWrapMode", this.$onChangeWrapMode); - + this.$onChangeFold = this.onChangeFold.bind(this); session.on("changeFold", this.$onChangeFold); - + this.$onChangeFrontMarker = this.onChangeFrontMarker.bind(this); this.session.on("changeFrontMarker", this.$onChangeFrontMarker); - + this.$onChangeBackMarker = this.onChangeBackMarker.bind(this); this.session.on("changeBackMarker", this.$onChangeBackMarker); - + this.$onChangeBreakpoint = this.onChangeBreakpoint.bind(this); this.session.on("changeBreakpoint", this.$onChangeBreakpoint); - + this.$onChangeAnnotation = this.onChangeAnnotation.bind(this); this.session.on("changeAnnotation", this.$onChangeAnnotation); - + this.$onCursorChange = this.onCursorChange.bind(this); this.session.on("changeOverwrite", this.$onCursorChange); - + this.$onScrollTopChange = this.onScrollTopChange.bind(this); this.session.on("changeScrollTop", this.$onScrollTopChange); - + this.$onScrollLeftChange = this.onScrollLeftChange.bind(this); this.session.on("changeScrollLeft", this.$onScrollLeftChange); - + this.selection = session.getSelection(); this.selection.on("changeCursor", this.$onCursorChange); - + this.$onSelectionChange = this.onSelectionChange.bind(this); this.selection.on("changeSelection", this.$onSelectionChange); @@ -330,11 +330,11 @@ class Editor { this.session.on("startOperation", this.$onStartOperation); this.$onEndOperation = this.onEndOperation.bind(this); this.session.on("endOperation", this.$onEndOperation); - + this.onChangeMode(); - + this.onCursorChange(); - + this.onScrollTopChange(); this.onScrollLeftChange(); this.onSelectionChange(); @@ -353,12 +353,12 @@ class Editor { session: session, oldSession: oldSession }); - + this.curOp = null; - + oldSession && oldSession._signal("changeEditor", {oldEditor: this}); session && session._signal("changeEditor", {editor: this}); - + if (session && !session.destroyed) session.bgTokenizer.scheduleStart(); } @@ -459,7 +459,7 @@ class Editor { /** * Gets the current font size of the editor text. - * @return {string} + * @return {string | number} */ getFontSize() { return this.getOption("fontSize") || @@ -468,7 +468,7 @@ class Editor { /** * Set a new font size (in pixels) for the editor text. - * @param {String} size A font size ( _e.g._ "12px") + * @param {String | number} size A font size ( _e.g._ "12px") **/ setFontSize(size) { this.setOption("fontSize", size); @@ -569,6 +569,7 @@ class Editor { /** * Emitted once the editor comes into focus. + * @internal **/ onFocus(e) { if (this.$isFocused) @@ -581,6 +582,7 @@ class Editor { /** * Emitted once the editor has been blurred. + * @internal **/ onBlur(e) { if (!this.$isFocused) @@ -602,6 +604,7 @@ class Editor { /** * Emitted whenever the document is changed. * @param {import("../ace-internal").Ace.Delta} delta Contains a single property, `data`, which has the delta of changes + * @internal **/ onDocumentChange(delta) { // Rerender and emit "change" event. @@ -610,27 +613,36 @@ class Editor { this.renderer.updateLines(delta.start.row, lastRow, wrap); this._signal("change", delta); - + // Update cursor because tab characters can influence the cursor position. this.$cursorChange(); } + /** + * @internal + */ onTokenizerUpdate(e) { var rows = e.data; this.renderer.updateLines(rows.first, rows.last); } - + /** + * @internal + */ onScrollTopChange() { this.renderer.scrollToY(this.session.getScrollTop()); } + /** + * @internal + */ onScrollLeftChange() { this.renderer.scrollToX(this.session.getScrollLeft()); } /** * Emitted when the selection changes. + * @internal **/ onCursorChange() { this.$cursorChange(); @@ -668,8 +680,8 @@ class Editor { } /** - * * @param e + * @internal */ onSelectionChange(e) { var session = this.session; @@ -703,9 +715,9 @@ class Editor { var startColumn = selection.start.column; var endColumn = selection.end.column; var line = session.getLine(selection.start.row); - + var needle = line.substring(startColumn, endColumn); - // maximum allowed size for regular expressions in 32000, + // maximum allowed size for regular expressions in 32000, // but getting close to it has significant impact on the performance if (needle.length > 5000 || !/[\w\d]/.test(needle)) return; @@ -715,51 +727,68 @@ class Editor { caseSensitive: true, needle: needle }); - + var wordWithBoundary = line.substring(startColumn - 1, endColumn + 1); if (!re.test(wordWithBoundary)) return; - + return re; } - + /** + * @internal + */ onChangeFrontMarker() { this.renderer.updateFrontMarkers(); } + /** + * @internal + */ onChangeBackMarker() { this.renderer.updateBackMarkers(); } - + /** + * @internal + */ onChangeBreakpoint() { this.renderer.updateBreakpoints(); } + /** + * @internal + */ onChangeAnnotation() { this.renderer.setAnnotations(this.session.getAnnotations()); } /** * @param e + * @internal */ onChangeMode (e) { this.renderer.updateText(); this._emit("changeMode", e); } - + /** + * @internal + */ onChangeWrapLimit() { this.renderer.updateFull(); } + /** + * @internal + */ onChangeWrapMode() { this.renderer.onResize(true); } /** + * @internal */ onChangeFold() { // Update the active line marker as due to folding changes the current @@ -769,7 +798,7 @@ class Editor { this.renderer.updateFull(); } - + /** * Returns the string of text currently highlighted. * @returns {String} @@ -777,8 +806,8 @@ class Editor { getSelectedText() { return this.session.getTextRange(this.getSelectionRange()); } - - + + /** * Returns the string of text currently highlighted. * @returns {String} @@ -805,6 +834,7 @@ class Editor { /** * Called whenever a text "copy" happens. + * @internal **/ onCopy() { this.commands.exec("copy", this); @@ -812,6 +842,7 @@ class Editor { /** * Called whenever a text "cut" happens. + * @internal **/ onCut() { this.commands.exec("cut", this); @@ -822,6 +853,7 @@ class Editor { * Called whenever a text "paste" happens. * @param {String} text The pasted text * @param {any} event + * @internal **/ onPaste(text, event) { var e = {text: text, event: event}; @@ -829,12 +861,12 @@ class Editor { } /** - * + * * @param e * @returns {boolean} */ $handlePaste(e) { - if (typeof e == "string") + if (typeof e == "string") e = {text: e}; this._signal("paste", e); var text = e.text; @@ -853,23 +885,23 @@ class Editor { } else { var lines = text.split(/\r\n|\r|\n/); var ranges = this.selection.rangeList.ranges; - + var isFullLine = lines.length == 2 && (!lines[0] || !lines[1]); if (lines.length != ranges.length || isFullLine) return this.commands.exec("insertstring", this, text); - + for (var i = ranges.length; i--;) { var range = ranges[i]; if (!range.isEmpty()) session.remove(range); - + session.insert(range.start, lines[i]); } } } /** - * + * * @param {string | string[]} command * @param [args] * @return {boolean} @@ -903,7 +935,7 @@ class Editor { } } - + if (text == "\t") text = this.session.getTabString(); @@ -974,7 +1006,7 @@ class Editor { for (var i = 0; i < ranges.length; i++) { var startRow = ranges[i].start.row; var endRow = ranges[i].end.row; - + for (var row = startRow; row <= endRow; row++) { if (row > 0) { prevLineState = session.getState(row - 1); @@ -1000,15 +1032,16 @@ class Editor { } /** - * + * * @param text * @param composition * @returns {*} + * @internal */ onTextInput(text, composition) { if (!composition) return this.keyBinding.onTextInput(text); - + this.startOperation({command: { name: "insertstring" }}); var applyComposition = this.applyComposition.bind(this, text, composition); if (this.selection.rangeCount) @@ -1045,6 +1078,9 @@ class Editor { } } + /** + * @internal + */ onCommandKey(e, hashId, keyCode) { return this.keyBinding.onCommandKey(e, hashId, keyCode); } @@ -1118,7 +1154,7 @@ class Editor { /** * Returns the current selection style. - * @returns {import("../ace-internal").Ace.EditorOptions["selectionStyle"]} + * @returns {import("../ace-internal").Ace.EditorOptions["selectionStyle"]} **/ getSelectionStyle() { return this.getOption("selectionStyle"); @@ -1351,7 +1387,7 @@ class Editor { else this.selection.selectRight(); } - + var range = this.getSelectionRange(); if (this.getBehavioursEnabled()) { var session = this.session; @@ -1445,7 +1481,7 @@ class Editor { * Set the "ghost" text in provided position. "Ghost" text is a kind of * preview text inside the editor which can be used to preview some code * inline in the editor such as, for example, code completions. - * + * * @param {String} text Text to be inserted as "ghost" text * @param {Point} [position] Position to insert text to */ @@ -1544,7 +1580,7 @@ class Editor { return; } } - + var line = session.getLine(range.start.row); var position = range.start; var size = session.getTabSize(); @@ -1837,7 +1873,7 @@ class Editor { * @param {Range} range The range of text you want moved within the document * @param {Point} toPosition The location (row and column) where you want to move the text to * @param {boolean} [copy] - * + * * @returns {Range} The new range where the text was moved to. * @related EditSession.moveText **/ @@ -1882,7 +1918,7 @@ class Editor { // @ts-expect-error TODO: possible bug, no args in parameters selection.rangeList.detach(this.session); this.inVirtualSelectionMode = true; - + var diff = 0; var totalDiff = 0; var l = ranges.length; @@ -1911,7 +1947,7 @@ class Editor { if (!copy) diff = 0; totalDiff += diff; } - + selection.fromOrientedRange(selection.ranges[0]); selection.rangeList.attach(this.session); this.inVirtualSelectionMode = false; @@ -1936,14 +1972,23 @@ class Editor { }; } + /** + * @internal + */ onCompositionStart(compositionState) { this.renderer.showComposition(compositionState); } + /** + * @internal + */ onCompositionUpdate(text) { this.renderer.setCompositionText(text); } + /** + * @internal + */ onCompositionEnd() { this.renderer.hideComposition(); } @@ -2127,7 +2172,7 @@ class Editor { getSelectionRange() { return this.selection.getRange(); } - + /** * Selects all the text in editor. * @related Selection.selectAll @@ -2610,7 +2655,7 @@ class Editor { } /** - * + * * @param {Range} range * @param {boolean} [animate] */ @@ -2798,7 +2843,7 @@ config.defineOptions(Editor.prototype, "editor", { readOnly: { set: function(readOnly) { this.textInput.setReadOnly(readOnly); - this.$resetCursorStyle(); + this.$resetCursorStyle(); }, initialValue: false }, @@ -2840,7 +2885,7 @@ config.defineOptions(Editor.prototype, "editor", { handlesSet: true, hidden: true }, - + showLineNumbers: { set: function(show) { this.renderer.$gutterLayer.setShowLineNumbers(show); @@ -2909,10 +2954,10 @@ config.defineOptions(Editor.prototype, "editor", { if (e.target == this.renderer.scroller && e.keyCode === keys['enter']){ e.preventDefault(); var row = this.getCursorPosition().row; - + if (!this.isRowVisible(row)) this.scrollToLine(row, true, true); - + this.focus(); } }; @@ -2973,7 +3018,7 @@ config.defineOptions(Editor.prototype, "editor", { this.renderer.scroller.removeAttribute("aria-roledescription"); this.renderer.scroller.classList.remove(this.renderer.keyboardFocusClassName); this.renderer.scroller.removeAttribute("aria-label"); - + this.renderer.scroller.removeEventListener("keyup", focusOnEnterKeyup.bind(this)); this.commands.removeCommand(blurCommand); diff --git a/src/ext/code_lens.js b/src/ext/code_lens.js index 7a2c89a1228..7098c1e9984 100644 --- a/src/ext/code_lens.js +++ b/src/ext/code_lens.js @@ -1,7 +1,7 @@ "use strict"; /** * @typedef {import("../edit_session").EditSession} EditSession - * @typedef {import("../virtual_renderer").VirtualRenderer & {$textLayer: import("../layer/text").Text &{$lenses}}} VirtualRenderer + * @typedef {import("../virtual_renderer").VirtualRenderer & {$textLayer: import("../layer/text").Text &{$lenses: any}}} VirtualRenderer */ var LineWidgets = require("../line_widgets").LineWidgets; @@ -108,9 +108,9 @@ function clearCodeLensWidgets(session) { } /** - * + * * @param {EditSession} session - * @param lenses + * @param {import("../../ace-internal").Ace.CodeLense[]} lenses * @return {number} */ exports.setLenses = function(session, lenses) { @@ -189,7 +189,7 @@ function attachToEditor(editor) { var row = session.documentToScreenRow(cursor); var lineHeight = editor.renderer.layerConfig.lineHeight; var top = session.getScrollTop() + (row - oldRow) * lineHeight; - // special case for the lens on line 0, because it can't be scrolled into view with keyboard + // special case for the lens on line 0, because it can't be scrolled into view with keyboard if (firstRow == 0 && scrollTop < lineHeight /4 && scrollTop > -lineHeight/4) { top = -lineHeight; } @@ -215,7 +215,7 @@ function detachFromEditor(editor) { /** * @param {import("../editor").Editor} editor - * @param codeLensProvider + * @param {import("../../ace-internal").Ace.CodeLenseProvider} codeLensProvider */ exports.registerCodeLensProvider = function(editor, codeLensProvider) { editor.setOption("enableCodeLens", true); diff --git a/src/ext/searchbox.js b/src/ext/searchbox.js index f676da50803..e26a9003919 100644 --- a/src/ext/searchbox.js +++ b/src/ext/searchbox.js @@ -17,8 +17,8 @@ dom.importCssString(searchboxCss, "ace_searchbox", false); class SearchBox { /** * @param {Editor} editor - * @param {undefined} [range] - * @param {undefined} [showReplaceForm] + * @param {never} [range] + * @param {never} [showReplaceForm] */ constructor(editor, range, showReplaceForm) { /**@type {any}*/ @@ -66,7 +66,7 @@ class SearchBox { /**@type {Editor}*/ this.editor = editor; } - + setSession(e) { this.searchRange = null; this.$syncOptions(true); @@ -97,12 +97,12 @@ class SearchBox { /**@type {HTMLElement}*/ this.searchCounter = sb.querySelector(".ace_search_counter"); } - + $init() { var sb = this.element; - + this.$initElements(sb); - + var _this = this; event.addListener(sb, "mousedown", function(e) { setTimeout(function(){ @@ -213,11 +213,11 @@ class SearchBox { var value = this.searchRange ? editor.session.getTextRange(this.searchRange) : editor.getValue(); - + var offset = editor.session.doc.positionToIndex(editor.selection.anchor); if (this.searchRange) offset -= editor.session.doc.positionToIndex(this.searchRange.start); - + var last = regex.lastIndex = 0; var m; while ((m = regex.exec(value))) { @@ -243,7 +243,7 @@ class SearchBox { this.find(true, true); } findAll(){ - var range = this.editor.findAll(this.searchInput.value, { + var range = this.editor.findAll(this.searchInput.value, { regExp: this.regExpOption.checked, caseSensitive: this.caseSensitiveOption.checked, wholeWord: this.wholeWordOption.checked @@ -258,7 +258,7 @@ class SearchBox { replace() { if (!this.editor.getReadOnly()) this.editor.replace(this.replaceInput.value); - } + } replaceAndFindNext() { if (!this.editor.getReadOnly()) { this.editor.replace(this.replaceInput.value); @@ -274,7 +274,7 @@ class SearchBox { this.active = false; this.setSearchRange(null); this.editor.off("changeSession", this.setSession); - + this.element.style.display = "none"; this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb); this.editor.focus(); @@ -289,15 +289,15 @@ class SearchBox { this.editor.on("changeSession", this.setSession); this.element.style.display = ""; this.replaceOption.checked = isReplace; - + if (value) this.searchInput.value = value; - + this.searchInput.focus(); this.searchInput.select(); this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb); - + this.$syncOptions(true); } @@ -404,7 +404,7 @@ SearchBox.prototype.$closeSearchBarKb = $closeSearchBarKb; exports.SearchBox = SearchBox; /** - * + * * @param {Editor} editor * @param {boolean} [isReplace] */ diff --git a/src/ext/static_highlight.js b/src/ext/static_highlight.js index 427f626a8d4..ada36bfc023 100644 --- a/src/ext/static_highlight.js +++ b/src/ext/static_highlight.js @@ -1,4 +1,9 @@ "use strict"; +/** + * @typedef {import("../../ace-internal").Ace.SyntaxMode} SyntaxMode + * @typedef {import("../../ace-internal").Ace.Theme} Theme + */ + var EditSession = require("../edit_session").EditSession; var TextLayer = require("../layer/text").Text; @@ -75,9 +80,9 @@ var SimpleTextLayer = function() { SimpleTextLayer.prototype = TextLayer.prototype; /** - * + * * @param {HTMLElement} el - * @param opts + * @param {import("../../ace-internal").Ace.StaticHighlightOptions} opts * @param [callback] * @returns {boolean} */ @@ -87,7 +92,7 @@ var highlight = function(el, opts, callback) { if (!mode) return false; var theme = opts.theme || "ace/theme/textmate"; - + var data = ""; var nodes = []; @@ -108,13 +113,13 @@ var highlight = function(el, opts, callback) { if (opts.trim) data = data.trim(); } - + highlight.render(data, mode, theme, opts.firstLineNumber, !opts.showGutter, function (highlighted) { dom.importCssString(highlighted.css, "ace_highlight", true); el.innerHTML = highlighted.html; - /** + /** * TODO: check if child exists - * @type {any} + * @type {any} */ var container = el.firstChild.firstChild; for (var i = 0; i < nodes.length; i += 2) { @@ -131,10 +136,10 @@ var highlight = function(el, opts, callback) { * Transforms a given input code snippet into HTML using the given mode * * @param {string} input Code snippet - * @param {string|import("../../ace-internal").Ace.SyntaxMode} mode String specifying the mode to load such as + * @param {string | SyntaxMode} mode String specifying the mode to load such as * `ace/mode/javascript` or, a mode loaded from `/ace/mode` * (use 'ServerSideHiglighter.getMode'). - * @param {string} theme String specifying the theme to load such as + * @param {string | Theme} theme String specifying the theme to load such as * `ace/theme/twilight` or, a theme loaded from `/ace/theme`. * @param {number} lineStart A number indicating the first line number. Defaults * to 1. @@ -177,7 +182,7 @@ highlight.render = function(input, mode, theme, lineStart, disableGutter, callba // loads or passes the specified mode module then calls renderer function done() { - var result = highlight.renderSync(input, mode, theme, lineStart, disableGutter); + var result = highlight.renderSync(input, mode, /**@type{Theme}*/(theme), lineStart, disableGutter); return callback ? callback(result) : result; } return --waiting || done(); @@ -186,8 +191,8 @@ highlight.render = function(input, mode, theme, lineStart, disableGutter, callba /** * Transforms a given input code snippet into HTML using the given mode * @param {string} input Code snippet - * @param {import("../../ace-internal").Ace.SyntaxMode|string} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode') - * @param {any} theme + * @param {SyntaxMode | string} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode') + * @param {Theme} theme * @param {any} lineStart * @param {boolean} disableGutter * @returns {object} An object containing: html, css @@ -212,10 +217,10 @@ highlight.renderSync = function(input, mode, theme, lineStart, disableGutter) { session.setValue(input); var length = session.getLength(); - + var outerEl = simpleDom.createElement("div"); outerEl.className = theme.cssClass; - + var innerEl = simpleDom.createElement("div"); innerEl.className = "ace_static_highlight" + (disableGutter ? "" : " ace_show_gutter"); innerEl.style["counter-reset"] = "ace_line " + (lineStart - 1); @@ -223,7 +228,7 @@ highlight.renderSync = function(input, mode, theme, lineStart, disableGutter) { for (var ix = 0; ix < length; ix++) { var lineEl = simpleDom.createElement("div"); lineEl.className = "ace_line"; - + if (!disableGutter) { var gutterEl = simpleDom.createElement("span"); gutterEl.className ="ace_gutter ace_gutter-cell"; diff --git a/src/incremental_search.js b/src/incremental_search.js index 58ba6725414..8b6a88ea7c5 100644 --- a/src/incremental_search.js +++ b/src/incremental_search.js @@ -68,7 +68,7 @@ class IncrementalSearch extends Search { this.$options.backwards = backwards; editor.keyBinding.addKeyboardHandler(this.$keyboardHandler); // we need to completely intercept paste, just registering an event handler does not work - this.$originalEditorOnPaste = editor.onPaste; + this.$originalEditorOnPaste = editor.onPaste; editor.onPaste = this.onPaste.bind(this); this.$mousedownHandler = editor.on('mousedown', this.onMouseDown.bind(this)); this.selectionFix(editor); @@ -207,6 +207,9 @@ class IncrementalSearch extends Search { }); } + /** + * @internal + */ onMouseDown(evt) { // when mouse interaction happens then we quit incremental search this.deactivate(); @@ -215,6 +218,7 @@ class IncrementalSearch extends Search { /** * @param {string} text + * @internal */ onPaste(text) { this.addString(text); diff --git a/src/keyboard/keybinding.js b/src/keyboard/keybinding.js index 5de3ab8251c..16cff02b4de 100644 --- a/src/keyboard/keybinding.js +++ b/src/keyboard/keybinding.js @@ -85,7 +85,7 @@ class KeyBinding { getKeyboardHandler() { return this.$handlers[this.$handlers.length - 1]; } - + getStatusText() { var data = this.$data; var editor = data.editor; @@ -106,7 +106,7 @@ class KeyBinding { ); if (!toExecute || !toExecute.command) continue; - + // allow keyboardHandler to consume keys if (toExecute.command == "null") { success = true; @@ -115,7 +115,7 @@ class KeyBinding { success = commands.exec(toExecute.command, this.$editor, toExecute.args, e); } // do not stop input events to not break repeating - if (success && e && hashId != -1 && + if (success && e && hashId != -1 && toExecute["passEvent"] != true && toExecute.command["passEvent"] != true ) { event.stopEvent(e); @@ -123,15 +123,15 @@ class KeyBinding { if (success) break; } - + if (!success && hashId == -1) { toExecute = {command: "insertstring"}; success = commands.exec("insertstring", this.$editor, keyString); } - + if (success && this.$editor._signal) this.$editor._signal("keyboardActivity", toExecute); - + return success; } @@ -140,6 +140,7 @@ class KeyBinding { * @param {number} hashId * @param {number} keyCode * @return {boolean} + * @internal */ onCommandKey(e, hashId, keyCode) { var keyString = keyUtil.keyCodeToString(keyCode); @@ -149,6 +150,7 @@ class KeyBinding { /** * @param {string} text * @return {boolean} + * @internal */ onTextInput(text) { return this.$callKeyboardHandlers(-1, text); diff --git a/src/lib/app_config.js b/src/lib/app_config.js index 905998d9f57..85849947896 100644 --- a/src/lib/app_config.js +++ b/src/lib/app_config.js @@ -67,12 +67,12 @@ class AppConfig { messages = defaultEnglishMessages; nlsPlaceholders = "dollarSigns"; } - + /** * @param {Object} obj * @param {string} path * @param {{ [key: string]: any }} options - * @returns {AppConfig} + * @returns {import("../../ace-internal").Ace.AppConfig} */ defineOptions(obj, path, options) { if (!obj.$options) @@ -160,7 +160,7 @@ class AppConfig { if (!messages[defaultString]) { warn("No message found for the default string '" + defaultString + "' in the provided messages. Falling back to the default English message."); } - } + } var translated = messages[key] || messages[defaultString] || defaultString; if (params) { diff --git a/src/lib/lang.js b/src/lib/lang.js index 950fb271a54..857f1525839 100644 --- a/src/lib/lang.js +++ b/src/lib/lang.js @@ -4,6 +4,8 @@ exports.last = function(a) { return a[a.length - 1]; }; + +/** @param {string} string */ exports.stringReverse = function(string) { return string.split("").reverse().join(""); }; @@ -30,8 +32,13 @@ exports.stringTrimLeft = function (string) { exports.stringTrimRight = function (string) { return string.replace(trimEndRegexp, ''); }; - +/** + * @template T + * @param {T} obj + * @return {T} + */ exports.copyObject = function(obj) { + /** @type Object*/ var copy = {}; for (var key in obj) { copy[key] = obj[key]; @@ -44,7 +51,7 @@ exports.copyArray = function(array){ for (var i=0, l=array.length; i 0 && !lineWidgets[first]) first--; - + this.firstRow = config.firstRow; this.lastRow = config.lastRow; @@ -403,16 +404,16 @@ class LineWidgets { if (!w.coverLine) top += config.lineHeight * this.session.getRowLineCount(w.row); w.el.style.top = top - config.offset + "px"; - + var left = w.coverGutter ? 0 : renderer.gutterWidth; if (!w.fixedWidth) left -= renderer.scrollLeft; w.el.style.left = left + "px"; - + if (w.fullWidth && w.screenWidth) { w.el.style.minWidth = config.width + 2 * config.padding + "px"; } - + if (w.fixedWidth) { w.el.style.right = renderer.scrollBar.getWidth() + "px"; } else { @@ -420,7 +421,7 @@ class LineWidgets { } } } - + } diff --git a/src/marker_group.js b/src/marker_group.js index 45304eb7255..2775f843cc1 100644 --- a/src/marker_group.js +++ b/src/marker_group.js @@ -25,7 +25,7 @@ class MarkerGroup { constructor(session, options) { if (options) this.markerType = options.markerType; - + /**@type {import("../ace-internal").Ace.MarkerGroupItem[]}*/ this.markers = []; /**@type {EditSession}*/ this.session = session; @@ -35,8 +35,8 @@ class MarkerGroup { /** * Finds the first marker containing pos - * @param {import("../ace-internal").Ace.Point} pos - * @returns {import("../ace-internal").Ace.MarkerGroupItem | undefined} + * @param {import("../ace-internal").Ace.Point} pos + * @returns {import("../ace-internal").Ace.MarkerGroupItem | undefined} */ getMarkerAtPosition(pos) { return this.markers.find(function(marker) { @@ -46,7 +46,7 @@ class MarkerGroup { /** * Comparator for Array.sort function, which sorts marker definitions by their positions - * + * * @param {MarkerGroupItem} a first marker. * @param {MarkerGroupItem} b second marker. * @returns {number} negative number if a should be before b, positive number if b should be before a, 0 otherwise. diff --git a/src/mode/behaviour.js b/src/mode/behaviour.js index 764843849e3..3a89b28e0e0 100644 --- a/src/mode/behaviour.js +++ b/src/mode/behaviour.js @@ -1,9 +1,5 @@ "use strict"; -/** - * @typedef {Behaviour & {[key: string]: any}} IBehaviour - */ -/**@type {any}*/ var Behaviour; Behaviour = function() { this.$behaviours = {}; @@ -57,7 +53,7 @@ Behaviour = function() { }; /** - * + * * @param [filter] * @returns {{}|*} * @this {Behaviour & this} diff --git a/src/mode/behaviour/css.js b/src/mode/behaviour/css.js index 90acc7653f1..2f05f7919d8 100644 --- a/src/mode/behaviour/css.js +++ b/src/mode/behaviour/css.js @@ -5,6 +5,7 @@ var Behaviour = require("../behaviour").Behaviour; var CstyleBehaviour = require("./cstyle").CstyleBehaviour; var TokenIterator = require("../../token_iterator").TokenIterator; +/**@type {(new() => Partial)}*/ var CssBehaviour = function () { this.inherit(CstyleBehaviour); diff --git a/src/mode/behaviour/cstyle.js b/src/mode/behaviour/cstyle.js index 707fc663879..9af7ce17c9b 100644 --- a/src/mode/behaviour/cstyle.js +++ b/src/mode/behaviour/cstyle.js @@ -47,7 +47,6 @@ var getWrapped = function(selection, selected, opening, closing) { }; /** * Creates a new Cstyle behaviour object with the specified options. - * @constructor * @param {Object} [options] - The options for the Cstyle behaviour object. * @param {boolean} [options.braces] - Whether to force braces auto-pairing. * @param {boolean} [options.closeDocComment] - enables automatic insertion of closing tags for documentation comments. @@ -244,7 +243,7 @@ CstyleBehaviour = function(options) { this.add("string_dquotes", "insertion", function(state, action, editor, session, text) { var quotes = session.$mode.$quotes || defaultQuotes; if (text.length == 1 && quotes[text]) { - if (this.lineCommentStart && this.lineCommentStart.indexOf(text) != -1) + if (this.lineCommentStart && this.lineCommentStart.indexOf(text) != -1) return; initContext(editor); var quote = text; @@ -257,16 +256,16 @@ CstyleBehaviour = function(options) { var line = session.doc.getLine(cursor.row); var leftChar = line.substring(cursor.column-1, cursor.column); var rightChar = line.substring(cursor.column, cursor.column + 1); - + var token = session.getTokenAt(cursor.row, cursor.column); var rightToken = session.getTokenAt(cursor.row, cursor.column + 1); // We're escaped. if (leftChar == "\\" && token && /escape/.test(token.type)) return null; - + var stringBefore = token && /string|escape/.test(token.type); var stringAfter = !rightToken || /string|escape/.test(rightToken.type); - + var pair; if (rightChar == quote) { pair = stringBefore !== stringAfter; @@ -285,7 +284,7 @@ CstyleBehaviour = function(options) { var pairQuotesAfter = session.$mode.$pairQuotesAfter; var shouldPairQuotes = pairQuotesAfter && pairQuotesAfter[quote] && pairQuotesAfter[quote].test(leftChar); - + if ((!shouldPairQuotes && isWordBefore) || isWordAfter) return null; // before or after alphanumeric if (rightChar && !/[\s;,.})\]\\]/.test(rightChar)) @@ -317,7 +316,7 @@ CstyleBehaviour = function(options) { } } }); - + if (options.closeDocComment !== false) { this.add("doc comment end", "insertion", function (state, action, editor, session, text) { if (state === "doc-start" && (text === "\n" || text === "\r\n") && editor.selection.isEmpty()) { @@ -349,7 +348,7 @@ CstyleBehaviour = function(options) { // Check for the pattern `*/` followed by `/**` within the token var closeDocPos = currentToken.value.indexOf("*/"); var openDocPos = currentToken.value.indexOf("/**", closeDocPos > - 1 ? closeDocPos + 2 : 0); - + if (openDocPos !== -1 && cursorPosInToken > openDocPos && cursorPosInToken < openDocPos + 3) { return; } @@ -394,7 +393,7 @@ CstyleBehaviour = function(options) { CstyleBehaviour.isSaneInsertion = function(editor, session) { var cursor = editor.getCursorPosition(); var iterator = new TokenIterator(session, cursor.row, cursor.column); - + // Don't insert in the middle of a keyword/identifier/lexical if (!this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) { if (/[)}\]]/.test(editor.session.getLine(cursor.row)[cursor.column])) @@ -404,7 +403,7 @@ CstyleBehaviour.isSaneInsertion = function(editor, session) { if (!this.$matchTokenType(iterator2.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) return false; } - + // Only insert in front of whitespace/comments iterator.stepForward(); return iterator.getCurrentTokenRow() !== cursor.row || diff --git a/src/mode/behaviour/html.js b/src/mode/behaviour/html.js index 23c779cb7d3..da248493a3d 100644 --- a/src/mode/behaviour/html.js +++ b/src/mode/behaviour/html.js @@ -3,6 +3,7 @@ var oop = require("../../lib/oop"); var XmlBehaviour = require("../behaviour/xml").XmlBehaviour; +/**@type {(new() => Partial)}*/ var HtmlBehaviour = function () { XmlBehaviour.call(this); diff --git a/src/mode/behaviour/liquid.js b/src/mode/behaviour/liquid.js index 750278235d0..abbc864ab36 100644 --- a/src/mode/behaviour/liquid.js +++ b/src/mode/behaviour/liquid.js @@ -10,6 +10,7 @@ return token && token.type.lastIndexOf(type + ".xml") > -1; } +/**@type {(new() => Partial)}*/ var LiquidBehaviour = function () { XmlBehaviour.call(this); this.add("autoBraceTagClosing","insertion", function (state, action, editor, session, text) { diff --git a/src/mode/behaviour/xml.js b/src/mode/behaviour/xml.js index dcea0a1f0ee..3b785a695a3 100644 --- a/src/mode/behaviour/xml.js +++ b/src/mode/behaviour/xml.js @@ -8,6 +8,7 @@ function is(token, type) { return token && token.type.lastIndexOf(type + ".xml") > -1; } +/**@type {(new() => Partial)}*/ var XmlBehaviour = function () { this.add("string_dquotes", "insertion", function (state, action, editor, session, text) { @@ -91,7 +92,7 @@ var XmlBehaviour = function () { iterator.stepBackward(); } } - + if (/^\s*>/.test(session.getLine(position.row).slice(position.column))) return; diff --git a/src/mode/behaviour/xquery.js b/src/mode/behaviour/xquery.js index 4d72f38269a..38bd9d399f6 100644 --- a/src/mode/behaviour/xquery.js +++ b/src/mode/behaviour/xquery.js @@ -18,12 +18,13 @@ function hasType(token, type) { }); return hasType; } - + +/**@type {(new() => Partial)}*/ var XQueryBehaviour = function () { - + this.inherit(CstyleBehaviour, ["braces", "parens", "string_dquotes"]); // Get string behaviour this.inherit(XmlBehaviour); // Get xml behaviour - + this.add("autoclosing", "insertion", function (state, action, editor, session, text) { if (text == '>') { var position = editor.getCursorPosition(); diff --git a/src/mode/text.js b/src/mode/text.js index da1ce98c4bb..7bdc201a8ee 100644 --- a/src/mode/text.js +++ b/src/mode/text.js @@ -1,4 +1,8 @@ "use strict"; +/** + * @typedef {import("../../ace-internal").Ace.SyntaxMode} SyntaxMode + */ + var config = require("../config"); var Tokenizer = require("../tokenizer").Tokenizer; @@ -10,7 +14,7 @@ var lang = require("../lib/lang"); var TokenIterator = require("../token_iterator").TokenIterator; var Range = require("../range").Range; -var Mode; +var Mode; Mode = function() { this.HighlightRules = TextHighlightRules; }; @@ -23,7 +27,7 @@ Mode = function() { this.nonTokenRe = new RegExp("^(?:[^" + unicode.wordChars + "\\$_]|\\s])+", "g"); /** - * @this {import("../../ace-internal").Ace.SyntaxMode} + * @this {SyntaxMode} */ this.getTokenizer = function() { if (!this.$tokenizer) { @@ -37,7 +41,7 @@ Mode = function() { this.blockComment = ""; /** - * @this {import("../../ace-internal").Ace.SyntaxMode} + * @this {SyntaxMode} */ this.toggleCommentLines = function(state, session, startRow, endRow) { var doc = session.doc; @@ -97,7 +101,7 @@ Mode = function() { var lineCommentStart = this.lineCommentStart; } regexpStart = new RegExp("^(\\s*)(?:" + regexpStart + ") ?"); - + insertAtTabStop = session.getUseSoftTabs(); var uncomment = function(line, i) { @@ -121,7 +125,7 @@ Mode = function() { var testRemove = function(line, i) { return regexpStart.test(line); }; - + var shouldInsertSpace = function(line, before, after) { var spaces = 0; while (before-- && line.charAt(before) == " ") @@ -170,7 +174,7 @@ Mode = function() { }; /** - * @this {import("../../ace-internal").Ace.SyntaxMode} + * @this {SyntaxMode} */ this.toggleBlockComment = function(state, session, range, cursor) { var comment = this.blockComment; @@ -268,14 +272,14 @@ Mode = function() { } } - var delegations = ["toggleBlockComment", "toggleCommentLines", "getNextLineIndent", + var delegations = ["toggleBlockComment", "toggleCommentLines", "getNextLineIndent", "checkOutdent", "autoOutdent", "transformAction", "getCompletions"]; for (let i = 0; i < delegations.length; i++) { (function(scope) { var functionName = delegations[i]; var defaultHandler = scope[functionName]; - scope[delegations[i]] = + scope[delegations[i]] = /** @this {import("../../ace-internal").Ace.SyntaxMode} */ function () { return this.$delegator(functionName, arguments, defaultHandler); @@ -285,7 +289,7 @@ Mode = function() { }; /** - * @this {import("../../ace-internal").Ace.SyntaxMode} + * @this {SyntaxMode} */ this.$delegator = function(method, args, defaultHandler) { var state = args[0] || "start"; @@ -298,7 +302,7 @@ Mode = function() { } state = state[0] || "start"; } - + for (var i = 0; i < this.$embeds.length; i++) { if (!this.$modes[this.$embeds[i]]) continue; @@ -314,7 +318,7 @@ Mode = function() { }; /** - * @this {import("../../ace-internal").Ace.SyntaxMode} + * @this {SyntaxMode} */ this.transformAction = function(state, action, editor, session, param) { if (this.$behaviour) { @@ -331,7 +335,7 @@ Mode = function() { }; /** - * @this {import("../../ace-internal").Ace.SyntaxMode} + * @this {SyntaxMode} */ this.getKeywords = function(append) { // this is for autocompletion to pick up regexp'ed keywords @@ -346,7 +350,7 @@ Mode = function() { completionKeywords.push(ruleItr[r].regex); } else if (typeof ruleItr[r].token === "object") { - for (var a = 0, aLength = ruleItr[r].token.length; a < aLength; a++) { + for (var a = 0, aLength = ruleItr[r].token.length; a < aLength; a++) { if (/keyword|support|storage/.test(ruleItr[r].token[a])) { // drop surrounding parens var rule = ruleItr[r].regex.match(/\(.+?\)/g)[a]; @@ -365,7 +369,7 @@ Mode = function() { }; /** - * @this {import("../../ace-internal").Ace.SyntaxMode} + * @this {SyntaxMode} */ this.$createKeywordList = function() { if (!this.$highlightRules) @@ -374,7 +378,7 @@ Mode = function() { }; /** - * @this {import("../../ace-internal").Ace.SyntaxMode} + * @this {SyntaxMode} */ this.getCompletions = function(state, session, pos, prefix) { var keywords = this.$keywordList || this.$createKeywordList(); diff --git a/src/mouse/mouse_handler.js b/src/mouse/mouse_handler.js index 7ec0623020e..3d582b70c48 100644 --- a/src/mouse/mouse_handler.js +++ b/src/mouse/mouse_handler.js @@ -80,7 +80,7 @@ class MouseHandler { } else { renderer.setCursorStyle(""); } - + }, //@ts-expect-error TODO: seems mistyping - should be boolean editor); } @@ -100,7 +100,7 @@ class MouseHandler { } /** - * @param {string} name + * @param {any} name * @param {{ wheelX: number; wheelY: number; }} e */ onMouseWheel(name, e) { @@ -112,7 +112,7 @@ class MouseHandler { this.editor._emit(name, mouseEvent); } - + setState(state) { this.state = state; } @@ -168,7 +168,7 @@ class MouseHandler { var onOperationEnd = function(e) { if (!self.releaseMouse) return; - // some touchpads fire mouseup event after a slight delay, + // some touchpads fire mouseup event after a slight delay, // which can cause problems if user presses a keyboard shortcut quickly if (editor.curOp.command.name && editor.curOp.selectionChanged) { self[self.state + "End"] && self[self.state + "End"](); diff --git a/src/multi_select.js b/src/multi_select.js index 4b03c6decf4..d2a39007522 100644 --- a/src/multi_select.js +++ b/src/multi_select.js @@ -49,7 +49,7 @@ var EditSession = require("./edit_session").EditSession; /**@type {RangeList | null} */ this.rangeList = null; - /** + /** * Adds a range to a selection by entering multiselect mode, if necessary. * @param {Range} range The new range to add * @param {Boolean} $blockChangeEvents Whether or not to block changing events @@ -254,7 +254,7 @@ var EditSession = require("./edit_session").EditSession; /** * Gets list of ranges composing rectangular block on the screen - * + * * @param {ScreenCoordinates} screenCursor The cursor to use * @param {ScreenCoordinates} screenAnchor The anchor to use * @param {Boolean} [includeEmptyLines] If true, this includes ranges inside the block which are empty due to clipping @@ -335,8 +335,8 @@ var EditSession = require("./edit_session").EditSession; var Editor = require("./editor").Editor; (function() { - /** - * + /** + * * Updates the cursor and marker layers. * @method Editor.updateSelectionMarkers * @this {Editor} @@ -346,7 +346,7 @@ var Editor = require("./editor").Editor; this.renderer.updateBackMarkers(); }; - /** + /** * Adds the selection and cursor. * @param {Range & {marker?}} orientedRange A range containing a cursor * @returns {Range & {marker?}} @@ -364,7 +364,7 @@ var Editor = require("./editor").Editor; return orientedRange; }; - /** + /** * Removes the selection marker. * @param {Range & {marker?}} range The selection range added with [[Editor.addSelectionMarker `addSelectionMarker()`]]. * @this {Editor} @@ -478,13 +478,13 @@ var Editor = require("./editor").Editor; return result; }; - /** + /** * Executes a command for each selection range. * @param {any} cmd The command to execute * @param {String} [args] Any arguments for the command * @param {Object|true} [options] * @this {Editor} - **/ + **/ this.forEachSelection = function(cmd, args, options) { if (this.inVirtualSelectionMode) return; @@ -495,10 +495,10 @@ var Editor = require("./editor").Editor; var rangeList = selection.rangeList; var ranges = (keepOrder ? selection : rangeList).ranges; var result; - + if (!ranges.length) return cmd.exec ? cmd.exec(this, args || {}) : cmd(this, args || {}); - + var reg = selection._eventRegistry; selection._eventRegistry = {}; var tmpSel = new Selection(session); @@ -524,17 +524,17 @@ var Editor = require("./editor").Editor; selection.mergeOverlappingRanges(); if (selection.ranges[0]) selection.fromOrientedRange(selection.ranges[0]); - + var anim = this.renderer.$scrollAnimation; this.onCursorChange(); this.onSelectionChange(); if (anim && anim.from == anim.to) this.renderer.animateScrolling(anim.from); - + return result; }; - /** + /** * Removes all the selections except the last added one. * @this {Editor} **/ @@ -579,7 +579,7 @@ var Editor = require("./editor").Editor; var pos = anchor == this.multiSelect.anchor ? range.cursor == range.start ? range.end : range.start : range.cursor; - if (pos.row != anchor.row + if (pos.row != anchor.row || this.session.$clipPositionToDocument(pos.row, pos.column).column != anchor.column) this.multiSelect.toSingleRange(this.multiSelect.toOrientedRange()); else @@ -593,7 +593,7 @@ var Editor = require("./editor").Editor; * @param {Partial} [options] The search options * @param {Boolean} [additive] keeps * - * @returns {Number} The cumulative count of all found matches + * @returns {Number} The cumulative count of all found matches * @this {Editor} **/ this.findAll = function(needle, options, additive) { @@ -604,9 +604,9 @@ var Editor = require("./editor").Editor; ? this.selection.getWordRange() : this.selection.getRange(); options.needle = this.session.getTextRange(range); - } + } this.$search.set(options); - + var ranges = this.$search.findAll(this.session); if (!ranges.length) return 0; @@ -622,17 +622,17 @@ var Editor = require("./editor").Editor; // keep old selection as primary if possible if (range && selection.rangeList.rangeAtPoint(range.start)) selection.addRange(range, true); - + return ranges.length; }; /** * Adds a cursor above or below the active cursor. - * + * * @param {Number} dir The direction of lines to select: -1 for up, 1 for down * @param {Boolean} [skip] If `true`, removes the active selection range * - * @this {Editor} + * @this {Editor} */ this.selectMoreLines = function(dir, skip) { var range = this.selection.toOrientedRange(); @@ -674,7 +674,7 @@ var Editor = require("./editor").Editor; this.selection.substractPoint(toRemove); }; - /** + /** * Transposes the selected ranges. * @param {Number} dir The direction to rotate selections * @this {Editor} @@ -717,7 +717,7 @@ var Editor = require("./editor").Editor; sel.fromOrientedRange(sel.ranges[0]); }; - /** + /** * Finds the next occurrence of text in an active selection and adds it to the selections. * @param {Number} dir The direction of lines to select: -1 for up, 1 for down * @param {Boolean} [skip] If `true`, removes the active selection range @@ -749,7 +749,7 @@ var Editor = require("./editor").Editor; this.multiSelect.substractPoint(range.cursor); }; - /** + /** * Aligns the cursors or selected text. * @this {Editor} **/ @@ -764,7 +764,7 @@ var Editor = require("./editor").Editor; return true; row = r.cursor.row; }); - + if (!ranges.length || sameRowRanges.length == ranges.length - 1) { var range = this.selection.getRange(); var fr = range.start.row, lr = range.end.row; @@ -778,7 +778,7 @@ var Editor = require("./editor").Editor; do { line = this.session.getLine(fr); } while (/[=:]/.test(line) && --fr > 0); - + if (fr < 0) fr = 0; if (lr >= max) lr = max - 1; } @@ -900,7 +900,7 @@ function isSamePoint(p1, p2) { * patch * adds multicursor support to a session * @this {Editor} - * @type {(e) => void} + * @type {(e: any) => void} */ exports.onSessionChange = function(e) { var session = e.session; diff --git a/src/placeholder.js b/src/placeholder.js index a3e84f76e78..2f3548b54ef 100644 --- a/src/placeholder.js +++ b/src/placeholder.js @@ -6,7 +6,7 @@ var Range = require("./range").Range; var EventEmitter = require("./lib/event_emitter").EventEmitter; var oop = require("./lib/oop"); -class PlaceHolder { +class PlaceHolder { /** * @param {EditSession} session * @param {Number} length @@ -51,7 +51,7 @@ class PlaceHolder { var _self = this; var doc = this.doc; var session = this.session; - + this.selectionBefore = session.selection.toJSON(); if (session.selection.inMultiSelectMode) session.selection.toSingleRange(); @@ -70,7 +70,7 @@ class PlaceHolder { }); session.setUndoSelect(false); } - + /** * PlaceHolder.showOtherMarkers() * @@ -86,7 +86,7 @@ class PlaceHolder { anchor.markerId = session.addMarker(new Range(anchor.row, anchor.column, anchor.row, anchor.column+_self.length), _self.othersClass, null, false); }); } - + /** * PlaceHolder.hideOtherMarkers() * @@ -103,14 +103,15 @@ class PlaceHolder { /** * PlaceHolder@onUpdate(e) - * + * * Emitted when the place holder updates. * @param {import("../ace-internal").Ace.Delta} delta + * @internal */ onUpdate(delta) { if (this.$updating) return this.updateAnchors(delta); - + var range = delta; if (range.start.row !== range.end.row) return; if (range.start.row !== this.pos.row) return; @@ -118,9 +119,9 @@ class PlaceHolder { var lengthDiff = delta.action === "insert" ? range.end.column - range.start.column : range.start.column - range.end.column; var inMainRange = range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1; var distanceFromStart = range.start.column - this.pos.column; - + this.updateAnchors(delta); - + if (inMainRange) this.length += lengthDiff; @@ -139,7 +140,7 @@ class PlaceHolder { } } } - + this.$updating = false; this.updateMarkers(); } @@ -153,7 +154,7 @@ class PlaceHolder { this.others[i].onChange(delta); this.updateMarkers(); } - + updateMarkers() { if (this.$updating) return; @@ -171,9 +172,10 @@ class PlaceHolder { /** * PlaceHolder@onCursorChange(e) - * + * * Emitted when the cursor changes. * @param {any} [event] + * @internal */ onCursorChange(event) { if (this.$updating || !this.session) return; @@ -186,13 +188,13 @@ class PlaceHolder { this._emit("cursorLeave", event); } } - + /** * PlaceHolder.detach() - * + * * TODO * - **/ + **/ detach() { this.session.removeMarker(this.pos && this.pos.markerId); this.hideOtherMarkers(); @@ -201,10 +203,10 @@ class PlaceHolder { this.session.setUndoSelect(true); this.session = null; } - + /** * PlaceHolder.cancel() - * + * * TODO * **/ diff --git a/src/scrollbar.js b/src/scrollbar.js index 70cc2cc02af..877978a493b 100644 --- a/src/scrollbar.js +++ b/src/scrollbar.js @@ -37,7 +37,7 @@ class Scrollbar { event.addListener(this.element, "scroll", this.onScroll.bind(this)); event.addListener(this.element, "mousedown", event.preventDefault); } - + setVisible(isVisible) { this.element.style.display = isVisible ? "" : "none"; this.isVisible = isVisible; @@ -64,18 +64,19 @@ class VScrollBar extends Scrollbar { // element to show the scrollbar but still pretend that the scrollbar has a width // of 0px // in Firefox 6+ scrollbar is hidden if element has the same width as scrollbar - // make element a little bit wider to retain scrollbar when page is zoomed + // make element a little bit wider to retain scrollbar when page is zoomed renderer.$scrollbarWidth = this.width = dom.scrollbarWidth(parent.ownerDocument); this.inner.style.width = this.element.style.width = (this.width || 15) + 5 + "px"; this.$minWidth = 0; } - + /** * Emitted when the scroll bar, well, scrolls. * @event scroll + * @internal **/ onScroll() { @@ -105,7 +106,7 @@ class VScrollBar extends Scrollbar { setHeight(height) { this.element.style.height = height + "px"; } - + /** * Sets the scroll height of the scroll bar, in pixels. * @param {Number} height The new scroll height @@ -162,15 +163,16 @@ class HScrollBar extends Scrollbar { // element to show the scrollbar but still pretend that the scrollbar has a width // of 0px // in Firefox 6+ scrollbar is hidden if element has the same width as scrollbar - // make element a little bit wider to retain scrollbar when page is zoomed + // make element a little bit wider to retain scrollbar when page is zoomed this.height = renderer.$scrollbarWidth; this.inner.style.height = this.element.style.height = (this.height || 15) + 5 + "px"; } - + /** * Emitted when the scroll bar, well, scrolls. * @event scroll + * @internal **/ onScroll() { if (!this.skipEvent) { diff --git a/src/scrollbar_custom.js b/src/scrollbar_custom.js index 095d2038ba8..1f261175851 100644 --- a/src/scrollbar_custom.js +++ b/src/scrollbar_custom.js @@ -91,7 +91,7 @@ oop.implement(ScrollBar.prototype, EventEmitter); * @constructor **/ class VScrollBar extends ScrollBar { - + constructor(parent, renderer) { super(parent, '-v'); this.scrollTop = 0; @@ -102,9 +102,10 @@ class VScrollBar extends ScrollBar { this.inner.style.width = this.element.style.width = (this.width || 15) + "px"; this.$minWidth = 0; } - + /** * Emitted when the scroll thumb dragged or scrollbar canvas clicked. + * @internal **/ onMouseDown(eType, e) { if (eType !== "mousedown") return; @@ -238,9 +239,10 @@ class HScrollBar extends ScrollBar { this.inner.style.height = this.element.style.height = (this.height || 12) + "px"; this.renderer = renderer; } - + /** * Emitted when the scroll thumb dragged or scrollbar canvas clicked. + * @internal **/ onMouseDown(eType, e) { if (eType !== "mousedown") return; diff --git a/src/search.js b/src/search.js index b19bd87ef50..17a7c63222d 100644 --- a/src/search.js +++ b/src/search.js @@ -1,6 +1,7 @@ "use strict"; /** * @typedef {import("./edit_session").EditSession} EditSession + * @typedef {import("../ace-internal").Ace.SearchOptions} SearchOptions */ var lang = require("./lib/lang"); var oop = require("./lib/oop"); @@ -10,34 +11,15 @@ var Range = require("./range").Range; * A class designed to handle all sorts of text searches within a [[Document `Document`]]. **/ class Search { - /** - * Creates a new `Search` object. The following search options are available: - * @typedef SearchOptions - * - * @property {string|RegExp} [needle] - The string or regular expression you're looking for - * @property {boolean} [backwards] - Whether to search backwards from where cursor currently is - * @property {boolean} [wrap] - Whether to wrap the search back to the beginning when it hits the end - * @property {boolean} [caseSensitive] - Whether the search ought to be case-sensitive - * @property {boolean} [wholeWord] - Whether the search matches only on whole words - * @property {Range|null} [range] - The [[Range]] to search within. Set this to `null` for the whole document - * @property {boolean} [regExp] - Whether the search is a regular expression or not - * @property {Range|import("../ace-internal").Ace.Position} [start] - The starting [[Range]] or cursor position to begin the search - * @property {boolean} [skipCurrent] - Whether or not to include the current line in the search - * @property {boolean} [$isMultiLine] - true, if needle has \n or \r\n - * @property {boolean} [preserveCase] - * @property {boolean} [preventScroll] - * @property {boolean} [$supportsUnicodeFlag] - internal property, determine if browser supports unicode flag - * @property {any} [re] - **/ - + constructor() { - /**@type {SearchOptions}*/ + /**@type {Partial}*/ this.$options = {}; } - + /** * Sets the search options via the `options` parameter. - * @param {Partial} options An object containing all the new search properties + * @param {Partial} options An object containing all the new search properties * @returns {Search} * @chainable **/ @@ -48,15 +30,15 @@ class Search { /** * [Returns an object containing all the search options.]{: #Search.getOptions} - * @returns {Partial} + * @returns {Partial} **/ getOptions() { return lang.copyObject(this.$options); } - + /** * Sets the search options via the `options` parameter. - * @param {SearchOptions} options object containing all the search propertie + * @param {Partial} options object containing all the search propertie * @related Search.set **/ setOptions(options) { @@ -83,7 +65,7 @@ class Search { firstRange = null; return false; } - + return true; }); @@ -116,12 +98,12 @@ class Search { for (var j = 0; j < len; j++) if (lines[row + j].search(re[j]) == -1) continue outer; - + var startLine = lines[row]; var line = lines[row + len - 1]; var startIndex = startLine.length - startLine.match(re[0])[0].length; var endIndex = line.match(re[len - 1])[0].length; - + if (prevRange && prevRange.end.row === row && prevRange.end.column > startIndex ) { @@ -153,7 +135,7 @@ class Search { var endRow = range.end.row - range.start.row; while (i < j && ranges[j].end.column > endColumn && ranges[j].end.row == endRow) j--; - + ranges = ranges.slice(i, j + 1); for (i = 0, j = ranges.length; i < j; i++) { ranges[i].start.row += range.start.row; @@ -171,7 +153,7 @@ class Search { * + (String): If `options.regExp` is `true`, this function returns `input` with the replacement already made. Otherwise, this function just returns `replacement`.
    * If `options.needle` was not found, this function returns `null`. * - * + * * @returns {String} **/ replace(input, replacement) { @@ -190,7 +172,7 @@ class Search { if (!options.regExp) { replacement = replacement.replace(/\$/g, "$$$$"); } - + replacement = input.replace(re, replacement); if (options.preserveCase) { replacement = replacement.split(""); @@ -203,20 +185,20 @@ class Search { } replacement = replacement.join(""); } - + return replacement; } /** - * - * @param {SearchOptions} options + * + * @param {Partial} options * @param {boolean} [$disableFakeMultiline] * @return {RegExp|boolean|*[]|*} */ $assembleRegExp(options, $disableFakeMultiline) { if (options.needle instanceof RegExp) return options.re = options.needle; - + var needle = options.needle; if (!options.needle) @@ -237,7 +219,7 @@ class Search { if (options.wholeWord) needle = addWordBoundary(needle, options); - + options.$isMultiLine = !$disableFakeMultiline && /[\n\r]/.test(needle); if (options.$isMultiLine) return options.re = this.$assembleMultilineRegExp(needle, modifier); @@ -281,13 +263,13 @@ class Search { var start = options.start; if (!start) start = range ? range[backwards ? "end" : "start"] : session.selection.getRange(); - + if (start.start) start = start[skipCurrent != backwards ? "end" : "start"]; var firstRow = range ? range.start.row : 0; var lastRow = range ? range.end.row : session.getLength() - 1; - + if (backwards) { var forEach = function(callback) { var row = start.row; @@ -318,7 +300,7 @@ class Search { return; }; } - + if (options.$isMultiLine) { var len = re.length; var forEachInLine = function(row, offset, callback) { @@ -387,9 +369,9 @@ class Search { } /** - * + * * @param {string} needle - * @param {SearchOptions} options + * @param {Partial} options * @return {string} */ function addWordBoundary(needle, options) { diff --git a/src/snippets.js b/src/snippets.js index 263434e0f67..6b7b53abfe8 100644 --- a/src/snippets.js +++ b/src/snippets.js @@ -119,7 +119,7 @@ class SnippetManager { getTokenizer() { return SnippetManager["$tokenizer"] || this.createTokenizer(); } - + createTokenizer() { function TabstopToken(str) { str = str.substr(1); @@ -131,7 +131,7 @@ class SnippetManager { return "(?:[^\\\\" + ch + "]|\\\\.)"; } var formatMatcher = { - regex: "/(" + escape("/") + "+)/", + regex: "/(" + escape("/") + "+)/", onMatch: function(val, state, stack) { var ts = stack[0]; ts.fmtString = true; @@ -141,7 +141,7 @@ class SnippetManager { }, next: "formatString" }; - + SnippetManager["$tokenizer"] = new Tokenizer({ start: [ {regex: /\\./, onMatch: function(val, state, stack) { @@ -246,13 +246,13 @@ class SnippetManager { return x.value || x; }); } - + getVariableValue(editor, name, indentation) { if (/^\d+$/.test(name)) return (this.variables.__ || {})[name] || ""; if (/^[A-Z]\d+$/.test(name)) return (this.variables[name[0] + "__"] || {})[name.substr(1)] || ""; - + name = name.replace(/^TM_/, ""); if (!this.variables.hasOwnProperty(name)) return ""; @@ -261,7 +261,7 @@ class SnippetManager { value = this.variables[name](editor, name, indentation); return value == null ? "" : value; } - + // returns string formatted according to http://manual.macromates.com/en/regular_expressions#replacement_string_syntax_format_strings tmStrFormat(str, ch, editor) { if (!ch.fmt) return str; @@ -302,7 +302,7 @@ class SnippetManager { }); return formatted; } - + tmFormatFunction(str, ch, editor) { if (ch.formatFunction == "upcase") return str.toUpperCase(); @@ -331,21 +331,21 @@ class SnippetManager { } if (!ch) continue; afterNewLine = false; - + if (ch.fmtString) { var j = snippet.indexOf(ch, i + 1); if (j == -1) j = snippet.length; ch.fmt = snippet.slice(i + 1, j); i = j; } - + if (ch.text) { var value = this.getVariableValue(editor, ch.text, indentation) + ""; if (ch.fmtString) value = this.tmStrFormat(value, ch, editor); if (ch.formatFunction) value = this.tmFormatFunction(value, ch, editor); - + if (value && !ch.ifEnd) { result.push(value); gotoNext(ch); @@ -375,7 +375,7 @@ class SnippetManager { insertSnippetForSelection(editor, snippetText, options={}) { var processedSnippet = processSnippetText.call(this, editor, snippetText, options); - + var range = editor.getSelectionRange(); var end = editor.session.replace(range, processedSnippet.text); @@ -388,11 +388,11 @@ class SnippetManager { var self = this; if (editor.inVirtualSelectionMode) return self.insertSnippetForSelection(editor, snippetText, options); - + editor.forEachSelection(function() { self.insertSnippetForSelection(editor, snippetText, options); }, null, {keepOrder: true}); - + if (editor.tabstopManager) editor.tabstopManager.tabNext(); } @@ -402,7 +402,7 @@ class SnippetManager { scope = scope.split("/").pop(); if (scope === "html" || scope === "php") { // PHP is actually HTML - if (scope === "php" && !editor.session.$mode.inlinePhp) + if (scope === "php" && !editor.session.$mode.inlinePhp) scope = "html"; var c = editor.getCursorPosition(); var state = editor.session.getState(c.row); @@ -418,7 +418,7 @@ class SnippetManager { scope = "php"; } } - + return scope; } @@ -442,7 +442,7 @@ class SnippetManager { editor.tabstopManager.tabNext(); return result; } - + expandSnippetForSelection(editor, options) { var cursor = editor.getCursorPosition(); var line = editor.session.getLine(cursor.row); @@ -508,10 +508,10 @@ class SnippetManager { var snippetMap = this.snippetMap; var snippetNameMap = this.snippetNameMap; var self = this; - - if (!snippets) + + if (!snippets) snippets = []; - + function wrapRegexp(src) { if (src && !/^\^?\(.*\)\$?$|^\\b$/.test(src)) src = "(?:" + src + ")"; @@ -562,10 +562,10 @@ class SnippetManager { s.guard = "\\b"; s.trigger = lang.escapeRegExp(s.tabTrigger); } - + if (!s.trigger && !s.guard && !s.endTrigger && !s.endGuard) return; - + s.startRe = guardedRegexp(s.trigger, s.guard, true); s.triggerRe = new RegExp(s.trigger); @@ -657,7 +657,7 @@ var processSnippetText = function(editor, snippetText, options={}) { var line = editor.session.getLine(cursor.row); var tabString = editor.session.getTabString(); var indentString = line.match(/^\s*/)[0]; - + if (cursor.column < indentString.length) indentString = indentString.slice(0, cursor.column); @@ -749,7 +749,7 @@ var processSnippetText = function(editor, snippetText, options={}) { if (ts.indexOf(p) === -1) ts.push(p); } - + // convert to plain text var row = 0, column = 0; var text = ""; @@ -818,7 +818,9 @@ class TabstopManager { this.session = null; this.editor = null; } - + /** + * @internal + */ onChange(delta) { var isRemove = delta.action[0] == "r"; var selectedTabstop = this.selectedTabstop || {}; @@ -828,7 +830,7 @@ class TabstopManager { var ts = tabstops[i]; var active = ts == selectedTabstop || parents[ts.index]; ts.rangeList.$bias = active ? 0 : 1; - + if (delta.action == "remove" && ts !== selectedTabstop) { var parentActive = ts.parents && ts.parents[selectedTabstop.index]; var startIndex = ts.rangeList.pointIndex(delta.start, parentActive); @@ -862,10 +864,16 @@ class TabstopManager { } this.$inChange = false; } + /** + * @internal + */ onAfterExec(e) { if (e.command && !e.command.readOnly) this.updateLinkedFields(); } + /** + * @internal + */ onChangeSelection() { if (!this.editor) return; @@ -882,6 +890,9 @@ class TabstopManager { } this.detach(); } + /** + * @internal + */ onChangeSession() { this.detach(); } @@ -906,7 +917,7 @@ class TabstopManager { ts = this.tabstops[this.index]; if (!ts || !ts.length) return; - + this.selectedTabstop = ts; var range = ts.firstNonLinked || ts; if (ts.choices) range.cursor = range.start; @@ -921,14 +932,14 @@ class TabstopManager { } else { this.editor.selection.fromOrientedRange(range); } - + this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); if (this.selectedTabstop && this.selectedTabstop.choices) this.editor.execCommand("startAutocomplete", {matches: this.selectedTabstop.choices}); } addTabstops(tabstops, start, end) { var useLink = this.useLink || !this.editor.getOption("enableMultiselect"); - + if (!this.$openTabstops) this.$openTabstops = []; // add final tabstop if missing @@ -977,7 +988,7 @@ class TabstopManager { dest.rangeList.$bias = 0; dest.rangeList.addList(dest); }, this); - + if (arg.length > 2) { // when adding new snippet inside existing one, make sure 0 tabstop is at the end if (this.tabstops.length) diff --git a/src/tooltip.js b/src/tooltip.js index fc62ae7a52a..f0f69951739 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -21,7 +21,7 @@ class Tooltip { this.$element = null; this.$parentNode = parentNode; } - + $init() { this.$element = dom.createElement("div"); this.$element.className = CLASSNAME; @@ -112,7 +112,7 @@ class Tooltip { getWidth() { return this.getElement().offsetWidth; } - + destroy() { this.isOpen = false; if (this.$element && this.$element.parentNode) { @@ -160,7 +160,7 @@ class PopupManager { break; } } - + if (shouldDisplay) { visiblepopups.push(popup); } else { @@ -192,23 +192,23 @@ exports.Tooltip = Tooltip; class HoverTooltip extends Tooltip { constructor(parentNode=document.body) { super(parentNode); - + this.timeout = undefined; this.lastT = 0; this.idleTime = 350; this.lastEvent = undefined; - + this.onMouseOut = this.onMouseOut.bind(this); this.onMouseMove = this.onMouseMove.bind(this); this.waitForHover = this.waitForHover.bind(this); this.hide = this.hide.bind(this); - + var el = this.getElement(); el.style.whiteSpace = "pre-wrap"; el.style.pointerEvents = "auto"; el.addEventListener("mouseout", this.onMouseOut); el.tabIndex = -1; - + el.addEventListener("blur", function() { if (!el.contains(document.activeElement)) this.hide(); }.bind(this)); @@ -241,6 +241,7 @@ class HoverTooltip extends Tooltip { /** * @param {MouseEvent} e * @param {Editor} editor + * @internal */ onMouseMove(e, editor) { this.lastEvent = e; @@ -249,7 +250,7 @@ class HoverTooltip extends Tooltip { if (this.isOpen) { var pos = this.lastEvent && this.lastEvent.getDocumentPosition(); if ( - !this.range + !this.range || !this.range.contains(pos.row, pos.column) || isMousePressed || this.isOutsideOfText(this.lastEvent) @@ -268,7 +269,7 @@ class HoverTooltip extends Tooltip { this.timeout = setTimeout(this.waitForHover, this.idleTime - dt); return; } - + this.timeout = null; if (this.lastEvent && !this.isOutsideOfText(this.lastEvent)) { this.$gatherData(this.lastEvent, this.lastEvent.editor); @@ -296,7 +297,7 @@ class HoverTooltip extends Tooltip { } /** - * @param {any} value + * @param {(event: MouseEvent, editor: Editor) => void} value */ setDataProvider(value) { this.$gatherData = value; @@ -305,14 +306,14 @@ class HoverTooltip extends Tooltip { /** * @param {Editor} editor * @param {Range} range - * @param {any} domNode + * @param {HTMLElement} domNode * @param {MouseEvent} startingEvent */ showForRange(editor, range, domNode, startingEvent) { var MARGIN = 10; if (startingEvent && startingEvent != this.lastEvent) return; if (this.isOpen && document.activeElement == this.getElement()) return; - + var renderer = editor.renderer; if (!this.isOpen) { popupManager.addPopup(this); @@ -320,23 +321,23 @@ class HoverTooltip extends Tooltip { this.setTheme(renderer.theme); } this.isOpen = true; - + this.addMarker(range, editor.session); this.range = Range.fromPoints(range.start, range.end); var position = renderer.textToScreenCoordinates(range.start.row, range.start.column); - + var rect = renderer.scroller.getBoundingClientRect(); // clip position to visible area of the editor if (position.pageX < rect.left) position.pageX = rect.left; - + var element = this.getElement(); element.innerHTML = ""; element.appendChild(domNode); - + element.style.maxHeight = ""; - element.style.display = "block"; - + element.style.display = "block"; + // measure the size of tooltip, without constraints on its height var labelHeight = element.clientHeight; var labelWidth = element.clientWidth; @@ -347,11 +348,11 @@ class HoverTooltip extends Tooltip { if (position.pageY - labelHeight < 0 && position.pageY < spaceBelow) { isAbove = false; } - + element.style.maxHeight = (isAbove ? position.pageY : spaceBelow) - MARGIN + "px"; element.style.top = isAbove ? "" : position.pageY + renderer.lineHeight + "px"; element.style.bottom = isAbove ? window.innerHeight - position.pageY + "px" : ""; - + // try to align tooltip left with the range, but keep it on screen element.style.left = Math.min(position.pageX, window.innerWidth - labelWidth - MARGIN) + "px"; } @@ -367,7 +368,7 @@ class HoverTooltip extends Tooltip { this.$markerSession = session; this.marker = session && session.addMarker(range, "ace_highlight-marker", "text"); } - + hide(e) { if (!e && document.activeElement == this.getElement()) return; @@ -397,6 +398,9 @@ class HoverTooltip extends Tooltip { window.removeEventListener("mousedown", this.hide, true); } + /** + * @internal + */ onMouseOut(e) { if (this.timeout) { clearTimeout(this.timeout); diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 7c0a7fc2d06..6efa58d7d6b 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -29,14 +29,14 @@ dom.importCssString(editorCss, "ace_editor.css", false); /** * The class that is responsible for drawing everything you see on the screen! - * @related editor.renderer + * @related editor.renderer **/ class VirtualRenderer { /** * Constructs a new `VirtualRenderer` within the `container` specified, applying the given `theme`. * @param {HTMLElement | null} [container] The root element of the editor * @param {String} [theme] The starting theme - + **/ constructor(container, theme) { var _self = this; @@ -204,7 +204,7 @@ class VirtualRenderer { setSession(session) { if (this.session) this.session.doc.off("changeNewLineMode", this.onChangeNewLineMode); - + this.session = session; if (session && this.scrollMargin.top && session.getScrollTop() <= 0) session.setScrollTop(-this.scrollMargin.top); @@ -216,11 +216,11 @@ class VirtualRenderer { this.$textLayer.setSession(session); if (!session) return; - + this.$loop.schedule(this.CHANGE_FULL); this.session.$setFontMetrics(this.$fontMetrics); this.scrollBarH.scrollLeft = this.scrollBarV.scrollTop = null; - + this.onChangeNewLineMode = this.onChangeNewLineMode.bind(this); this.onChangeNewLineMode(); this.session.doc.on("changeNewLineMode", this.onChangeNewLineMode); @@ -265,12 +265,18 @@ class VirtualRenderer { this.$loop.schedule(this.CHANGE_LINES); } + /** + * @internal + */ onChangeNewLineMode() { this.$loop.schedule(this.CHANGE_TEXT); this.$textLayer.$updateEolChar(); this.session.$bidiHandler.setEolChar(this.$textLayer.EOL_CHAR); } - + + /** + * @internal + */ onChangeTabSize() { this.$loop.schedule(this.CHANGE_TEXT | this.CHANGE_MARKER); this.$textLayer.onChangeTabSize(); @@ -286,7 +292,7 @@ class VirtualRenderer { /** * Triggers a full update of all the layers, for all the rows. * @param {Boolean} [force] If `true`, forces the changes through - + **/ updateFull(force) { if (force) @@ -314,7 +320,7 @@ class VirtualRenderer { * @param {Number} [gutterWidth] The width of the gutter in pixels * @param {Number} [width] The width of the editor in pixels * @param {Number} [height] The hiehgt of the editor, in pixels - + * @internal **/ onResize(force, gutterWidth, width, height) { if (this.resizing > 2) @@ -341,7 +347,7 @@ class VirtualRenderer { var changes = this.$updateCachedSize(force, gutterWidth, width, height); if (this.$resizeTimer) this.$resizeTimer.cancel(); - + if (!this.$size.scrollerHeight || (!width && !height)) return this.resizing = 0; @@ -369,7 +375,7 @@ class VirtualRenderer { * @param [width] * @param [height] * @return {number} - + */ $updateCachedSize(force, gutterWidth, width, height) { height -= (this.$extraHeight || 0); @@ -388,7 +394,7 @@ class VirtualRenderer { size.scrollerHeight = size.height; if (this.$horizScroll) size.scrollerHeight -= this.scrollBarH.getHeight(); - + this.scrollBarV.setHeight(size.scrollerHeight); this.scrollBarV.element.style.bottom = this.scrollBarH.getHeight() + "px"; @@ -398,29 +404,29 @@ class VirtualRenderer { if (width && (force || size.width != width)) { changes |= this.CHANGE_SIZE; size.width = width; - + if (gutterWidth == null) gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; - + this.gutterWidth = gutterWidth; - + dom.setStyle(this.scrollBarH.element.style, "left", gutterWidth + "px"); dom.setStyle(this.scroller.style, "left", gutterWidth + this.margin.left + "px"); size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBarV.getWidth() - this.margin.h); dom.setStyle(this.$gutter.style, "left", this.margin.left + "px"); - + var right = this.scrollBarV.getWidth() + "px"; dom.setStyle(this.scrollBarH.element.style, "right", right); dom.setStyle(this.scroller.style, "right", right); dom.setStyle(this.scroller.style, "bottom", this.scrollBarH.getHeight()); - + this.scrollBarH.setWidth(size.scrollerWidth); if (this.session && this.session.getUseWrapMode() && this.adjustWrapLimit() || force) { changes |= this.CHANGE_FULL; } } - + size.$dirty = !width || !height; if (changes) @@ -430,9 +436,9 @@ class VirtualRenderer { } /** - * + * * @param {number} width - + * @internal */ onGutterResize(width) { var gutterWidth = this.$showGutter ? width : 0; @@ -450,7 +456,7 @@ class VirtualRenderer { /** * Adjusts the wrap limit, which is the number of characters that can fit within the width of the edit area on screen. - + **/ adjustWrapLimit() { var availableWidth = this.$size.scrollerWidth - this.$padding * 2; @@ -461,7 +467,7 @@ class VirtualRenderer { /** * Identifies whether you want to have an animated scroll or not. * @param {Boolean} shouldAnimate Set to `true` to show animated scrolls - + **/ setAnimatedScroll(shouldAnimate){ this.setOption("animatedScroll", shouldAnimate); @@ -470,7 +476,7 @@ class VirtualRenderer { /** * Returns whether an animated scroll happens or not. * @returns {Boolean} - + **/ getAnimatedScroll() { return this.$animatedScroll; @@ -479,7 +485,7 @@ class VirtualRenderer { /** * Identifies whether you want to show invisible characters or not. * @param {Boolean} showInvisibles Set to `true` to show invisibles - + **/ setShowInvisibles(showInvisibles) { this.setOption("showInvisibles", showInvisibles); @@ -489,7 +495,7 @@ class VirtualRenderer { /** * Returns whether invisible characters are being shown or not. * @returns {Boolean} - + **/ getShowInvisibles() { return this.getOption("showInvisibles"); @@ -497,7 +503,7 @@ class VirtualRenderer { /** * @return {boolean} - + */ getDisplayIndentGuides() { return this.getOption("displayIndentGuides"); @@ -505,14 +511,14 @@ class VirtualRenderer { /** * @param {boolean} display - + */ setDisplayIndentGuides(display) { this.setOption("displayIndentGuides", display); } /** - + * @return {boolean} */ getHighlightIndentGuides() { @@ -520,7 +526,7 @@ class VirtualRenderer { } /** - + * @param {boolean} highlight */ setHighlightIndentGuides(highlight) { @@ -530,7 +536,7 @@ class VirtualRenderer { /** * Identifies whether you want to show the print margin or not. * @param {Boolean} showPrintMargin Set to `true` to show the print margin - + **/ setShowPrintMargin(showPrintMargin) { this.setOption("showPrintMargin", showPrintMargin); @@ -539,7 +545,7 @@ class VirtualRenderer { /** * Returns whether the print margin is being shown or not. * @returns {Boolean} - + **/ getShowPrintMargin() { return this.getOption("showPrintMargin"); @@ -547,7 +553,7 @@ class VirtualRenderer { /** * Identifies whether you want to show the print margin column or not. * @param {number} printMarginColumn Set to `true` to show the print margin column - + **/ setPrintMarginColumn(printMarginColumn) { this.setOption("printMarginColumn", printMarginColumn); @@ -556,7 +562,7 @@ class VirtualRenderer { /** * Returns whether the print margin column is being shown or not. * @returns {number} - + **/ getPrintMarginColumn() { return this.getOption("printMarginColumn"); @@ -565,7 +571,7 @@ class VirtualRenderer { /** * Returns `true` if the gutter is being shown. * @returns {Boolean} - + **/ getShowGutter(){ return this.getOption("showGutter"); @@ -574,14 +580,14 @@ class VirtualRenderer { /** * Identifies whether you want to show the gutter or not. * @param {Boolean} show Set to `true` to show the gutter - + **/ setShowGutter(show){ return this.setOption("showGutter", show); } /** - + * @returns {boolean} */ getFadeFoldWidgets(){ @@ -589,7 +595,7 @@ class VirtualRenderer { } /** - + * @param {boolean} show */ setFadeFoldWidgets(show) { @@ -605,7 +611,7 @@ class VirtualRenderer { } /** - + * @returns {boolean} */ getHighlightGutterLine() { @@ -613,7 +619,7 @@ class VirtualRenderer { } /** - + */ $updatePrintMargin() { if (!this.$showPrintMargin && !this.$printMarginEl) @@ -631,7 +637,7 @@ class VirtualRenderer { var style = this.$printMarginEl.style; style.left = Math.round(this.characterWidth * this.$printMarginColumn + this.$padding) + "px"; style.visibility = this.$showPrintMargin ? "visible" : "hidden"; - + if (this.session && this.session.$wrap == -1) this.adjustWrapLimit(); } @@ -666,7 +672,7 @@ class VirtualRenderer { // move text input over the cursor // this is required for IME /** - + */ $moveTextAreaToCursor() { if (this.$isMousePressed) return; @@ -681,7 +687,7 @@ class VirtualRenderer { return; if (composition && composition.markerRange) pixelPos = this.$cursorLayer.getPixelPosition(composition.markerRange.start, true); - + var config = this.layerConfig; var posTop = pixelPos.top; var posLeft = pixelPos.left; @@ -707,7 +713,7 @@ class VirtualRenderer { posTop += this.lineHeight + 2; } } - + posLeft -= this.scrollLeft; if (posLeft > this.$size.scrollerWidth - w) posLeft = this.$size.scrollerWidth - w; @@ -762,7 +768,7 @@ class VirtualRenderer { /** * Sets the padding for all the layers. * @param {Number} padding A new padding value (in pixels) - + **/ setPadding(padding) { this.$padding = padding; @@ -775,12 +781,12 @@ class VirtualRenderer { } /** - * + * * @param {number} [top] * @param {number} [bottom] * @param {number} [left] * @param {number} [right] - + */ setScrollMargin(top, bottom, left, right) { var sm = this.scrollMargin; @@ -801,7 +807,7 @@ class VirtualRenderer { * @param {number} [bottom] * @param {number} [left] * @param {number} [right] - + */ setMargin(top, bottom, left, right) { var sm = this.margin; @@ -818,7 +824,7 @@ class VirtualRenderer { /** * Returns whether the horizontal scrollbar is set to be always visible. * @returns {Boolean} - + **/ getHScrollBarAlwaysVisible() { return this.$hScrollBarAlwaysVisible; @@ -827,7 +833,7 @@ class VirtualRenderer { /** * Identifies whether you want to show the horizontal scrollbar or not. * @param {Boolean} alwaysVisible Set to `true` to make the horizontal scroll bar visible - + **/ setHScrollBarAlwaysVisible(alwaysVisible) { this.setOption("hScrollBarAlwaysVisible", alwaysVisible); @@ -835,7 +841,7 @@ class VirtualRenderer { /** * Returns whether the horizontal scrollbar is set to be always visible. * @returns {Boolean} - + **/ getVScrollBarAlwaysVisible() { return this.$vScrollBarAlwaysVisible; @@ -850,7 +856,7 @@ class VirtualRenderer { } /** - + */ $updateScrollBarV() { var scrollHeight = this.layerConfig.maxHeight; @@ -873,17 +879,17 @@ class VirtualRenderer { freeze() { this.$frozen = true; } - + unfreeze() { this.$frozen = false; } /** - * + * * @param {number} changes * @param {boolean} [force] * @returns {number} - + */ $renderChanges(changes, force) { if (this.$changes) { @@ -892,8 +898,8 @@ class VirtualRenderer { } if ((!this.session || !this.container.offsetWidth || this.$frozen) || (!changes && !force)) { this.$changes |= changes; - return; - } + return; + } if (this.$size.$dirty) { this.$changes |= changes; return this.onResize(true); @@ -902,9 +908,9 @@ class VirtualRenderer { this.$textLayer.checkForSizeChanges(); } // this.$logChanges(changes); - + this._signal("beforeRender", changes); - + if (this.session && this.session.$bidiHandler) this.session.$bidiHandler.updateCharacterWidths(this.$fontMetrics); @@ -920,7 +926,7 @@ class VirtualRenderer { changes |= this.$computeLayerConfig() | this.$loop.clear(); // If a change is made offscreen and wrapMode is on, then the onscreen // lines may have been pushed down. If so, the first screen row will not - // have changed, but the first actual row will. In that case, adjust + // have changed, but the first actual row will. In that case, adjust // scrollTop so that the cursor and onscreen content stays in the same place. // TODO: find a better way to handle this, that works non wrapped case and doesn't compute layerConfig twice if (config.firstRow != this.layerConfig.firstRow && config.firstRowScreen == this.layerConfig.firstRowScreen) { @@ -937,16 +943,16 @@ class VirtualRenderer { this.$updateScrollBarV(); if (changes & this.CHANGE_H_SCROLL) this.$updateScrollBarH(); - + dom.translate(this.content, -this.scrollLeft, -config.offset); - + var width = config.width + 2 * this.$padding + "px"; var height = config.minHeight + "px"; - + dom.setStyle(this.content.style, "width", width); dom.setStyle(this.content.style, "height", height); } - + // horizontal scrolling if (changes & this.CHANGE_H_SCROLL) { dom.translate(this.content, -this.scrollLeft, -config.offset); @@ -1046,53 +1052,53 @@ class VirtualRenderer { } /** - + */ $autosize() { var height = this.session.getScreenLength() * this.lineHeight; var maxHeight = this.$maxLines * this.lineHeight; - var desiredHeight = Math.min(maxHeight, + var desiredHeight = Math.min(maxHeight, Math.max((this.$minLines || 1) * this.lineHeight, height) ) + this.scrollMargin.v + (this.$extraHeight || 0); if (this.$horizScroll) desiredHeight += this.scrollBarH.getHeight(); if (this.$maxPixelHeight && desiredHeight > this.$maxPixelHeight) desiredHeight = this.$maxPixelHeight; - + var hideScrollbars = desiredHeight <= 2 * this.lineHeight; var vScroll = !hideScrollbars && height > maxHeight; - + if (desiredHeight != this.desiredHeight || this.$size.height != this.desiredHeight || vScroll != this.$vScroll) { if (vScroll != this.$vScroll) { this.$vScroll = vScroll; this.scrollBarV.setVisible(vScroll); } - + var w = this.container.clientWidth; this.container.style.height = desiredHeight + "px"; this.$updateCachedSize(true, this.$gutterWidth, w, desiredHeight); // this.$loop.changes = 0; this.desiredHeight = desiredHeight; - + this._signal("autosize"); } } /** - + * @returns {number} */ $computeLayerConfig() { var session = this.session; var size = this.$size; - + var hideScrollbars = size.height <= 2 * this.lineHeight; var screenLines = this.session.getScreenLength(); var maxHeight = screenLines * this.lineHeight; var longestLine = this.$getLongestLine(); - + var horizScroll = !hideScrollbars && (this.$hScrollBarAlwaysVisible || size.scrollerWidth - longestLine - 2 * this.$padding < 0); @@ -1107,19 +1113,19 @@ class VirtualRenderer { this.$autosize(); var minHeight = size.scrollerHeight + this.lineHeight; - + var scrollPastEnd = !this.$maxLines && this.$scrollPastEnd ? (size.scrollerHeight - this.lineHeight) * this.$scrollPastEnd : 0; maxHeight += scrollPastEnd; - + var sm = this.scrollMargin; this.session.setScrollTop(Math.max(-sm.top, Math.min(this.scrollTop, maxHeight - size.scrollerHeight + sm.bottom))); - this.session.setScrollLeft(Math.max(-sm.left, Math.min(this.scrollLeft, + this.session.setScrollLeft(Math.max(-sm.left, Math.min(this.scrollLeft, longestLine + 2 * this.$padding - size.scrollerWidth + sm.right))); - + var vScroll = !hideScrollbars && (this.$vScrollBarAlwaysVisible || size.scrollerHeight - maxHeight + scrollPastEnd < 0 || this.scrollTop > sm.top); var vScrollChanged = vScrollBefore !== vScroll; @@ -1155,7 +1161,7 @@ class VirtualRenderer { offset = this.scrollTop - firstRowScreen * lineHeight; var changes = 0; - if (this.layerConfig.width != longestLine || hScrollChanged) + if (this.layerConfig.width != longestLine || hScrollChanged) changes = this.CHANGE_H_SCROLL; // Horizontal scrollbar visibility may have changed, which changes // the client height of the scroller @@ -1165,7 +1171,7 @@ class VirtualRenderer { if (vScrollChanged) longestLine = this.$getLongestLine(); } - + this.layerConfig = { width : longestLine, padding : this.$padding, @@ -1191,7 +1197,7 @@ class VirtualRenderer { /** * @returns {boolean | undefined} - + */ $updateLines() { if (!this.$changedLines) return; @@ -1218,15 +1224,15 @@ class VirtualRenderer { } /** - * + * * @returns {number} - + */ $getLongestLine() { var charCount = this.session.getScreenWidth(); if (this.showInvisibles && !this.session.$useWrapMode) charCount += 1; - + if (this.$textLayer && charCount > this.$textLayer.MAX_LINE_LENGTH) charCount = this.$textLayer.MAX_LINE_LENGTH + 30; @@ -1268,7 +1274,7 @@ class VirtualRenderer { } /** - * + * * Redraw breakpoints. * @param {any} [rows] */ @@ -1312,7 +1318,7 @@ class VirtualRenderer { } /** - * + * * @param {Point} anchor * @param {Point} lead * @param {number} [offset] @@ -1324,7 +1330,7 @@ class VirtualRenderer { } /** - * + * * Scrolls the cursor into the first visibile area of the editor * @param {Point} [cursor] * @param {number} [offset] @@ -1426,7 +1432,7 @@ class VirtualRenderer { } /** - * + * * @param {Point} cursor * @param {number} [alignment] * @returns {number} @@ -1444,7 +1450,7 @@ class VirtualRenderer { } /** - * + * * @param {number} fromValue * @param {number} toValue * @returns {*[]} @@ -1470,7 +1476,7 @@ class VirtualRenderer { * @param {Boolean} center If `true`, centers the editor the to indicated line * @param {Boolean} animate If `true` animates scrolling * @param {() => void} [callback] Function to be called after the animation has finished - + **/ scrollToLine(line, center, animate, callback) { var pos = this.$cursorLayer.getPixelPosition({row: line, column: 0}); @@ -1485,20 +1491,20 @@ class VirtualRenderer { } /** - * + * * @param fromValue * @param [callback] - + */ animateScrolling(fromValue, callback) { var toValue = this.scrollTop; if (!this.$animatedScroll) return; var _self = this; - + if (fromValue == toValue) return; - + if (this.$scrollAnimation) { var oldSteps = this.$scrollAnimation.steps; if (oldSteps.length) { @@ -1507,7 +1513,7 @@ class VirtualRenderer { return; } } - + var steps = _self.$calcSteps(fromValue, toValue); this.$scrollAnimation = {from: fromValue, to: toValue, steps: steps}; @@ -1516,7 +1522,7 @@ class VirtualRenderer { _self.session.setScrollTop(steps.shift()); // trick session to think it's already scrolled to not loose toValue _self.session.$scrollTop = toValue; - + function endAnimation() { // @ts-ignore _self.$timer = clearInterval(_self.$timer); @@ -1524,14 +1530,14 @@ class VirtualRenderer { _self.$stopAnimation = false; callback && callback(); } - + this.$timer = setInterval(function() { if (_self.$stopAnimation) { endAnimation(); return; } - if (!_self.session) + if (!_self.session) return clearInterval(_self.$timer); if (steps.length) { _self.session.setScrollTop(steps.shift()); @@ -1579,7 +1585,7 @@ class VirtualRenderer { this.session.setScrollTop(y); this.session.setScrollLeft(x); } - + /** * Scrolls the editor across both x- and y-axes. * @param {Number} deltaX The x value to scroll by @@ -1611,11 +1617,11 @@ class VirtualRenderer { } /** - * + * * @param {number} x * @param {number} y * @returns {import("../ace-internal").Ace.ScreenCoordinates} - + */ pixelToScreenCoordinates(x, y) { var canvasPos; @@ -1627,7 +1633,7 @@ class VirtualRenderer { } else { canvasPos = this.scroller.getBoundingClientRect(); } - + var offsetX = x + this.scrollLeft - canvasPos.left - this.$padding; var offset = offsetX / this.characterWidth; var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight); @@ -1637,11 +1643,11 @@ class VirtualRenderer { } /** - * + * * @param {number} x * @param {number} y * @returns {Point} - + */ screenToTextCoordinates(x, y) { var canvasPos; @@ -1677,7 +1683,7 @@ class VirtualRenderer { var x = this.$padding + (this.session.$bidiHandler.isBidiRow(pos.row, row) ? this.session.$bidiHandler.getPosLeft(pos.column) : Math.round(pos.column * this.characterWidth)); - + var y = pos.row * this.lineHeight; return { @@ -1704,7 +1710,7 @@ class VirtualRenderer { /** * @param {Object} composition - + **/ showComposition(composition) { this.$composition = composition; @@ -1713,7 +1719,7 @@ class VirtualRenderer { } if (composition.useTextareaForIME == undefined) composition.useTextareaForIME = this.$useTextareaForIME; - + if (this.$useTextareaForIME) { dom.addCssClass(this.textarea, "ace_composition"); this.textarea.style.cssText = ""; @@ -1729,7 +1735,7 @@ class VirtualRenderer { * @param {String} text A string of text to use * * Sets the inner text of the current composition to `text`. - + **/ setCompositionText(text) { var cursor = this.session.selection.cursor; @@ -1740,12 +1746,12 @@ class VirtualRenderer { /** * * Hides the current composition. - + **/ hideComposition() { if (!this.$composition) return; - + if (this.$composition.markerId) this.session.removeMarker(this.$composition.markerId); @@ -1766,10 +1772,10 @@ class VirtualRenderer { var insertPosition = position || { row: cursor.row, column: cursor.column }; this.removeGhostText(); - + var textChunks = this.$calculateWrappedTextChunks(text, insertPosition); this.addToken(textChunks[0].text, "ghost_text", insertPosition.row, insertPosition.column); - + this.$ghostText = { text: text, position: { @@ -1777,7 +1783,7 @@ class VirtualRenderer { column: insertPosition. column } }; - + var widgetDiv = dom.createElement("div"); if (textChunks.length > 1) { // If there are tokens to the right of the cursor, hide those. @@ -1787,20 +1793,20 @@ class VirtualRenderer { textChunks.slice(1).forEach(el => { var chunkDiv = dom.createElement("div"); var chunkSpan = dom.createElement("span"); - chunkSpan.className = "ace_ghost_text"; + chunkSpan.className = "ace_ghost_text"; // If the line is wider than the viewport, wrap the line if (el.wrapped) chunkDiv.className = "ghost_text_line_wrapped"; - // If a given line doesn't have text (e.g. it's a line of whitespace), set a space as the + // If a given line doesn't have text (e.g. it's a line of whitespace), set a space as the // textcontent so that browsers render the empty line div. - if (el.text.length === 0) el.text = " "; - + if (el.text.length === 0) el.text = " "; + chunkSpan.appendChild(dom.createTextNode(el.text)); chunkDiv.appendChild(chunkSpan); widgetDiv.appendChild(chunkDiv); - // Overwrite lastLineDiv every iteration so at the end it points to + // Overwrite lastLineDiv every iteration so at the end it points to // the last added element. lastLineDiv = chunkDiv; }); @@ -1812,7 +1818,7 @@ class VirtualRenderer { element.appendChild(dom.createTextNode(token.value)); lastLineDiv.appendChild(element); }); - + this.$ghostTextWidget = { el: widgetDiv, row: insertPosition.row, @@ -1830,7 +1836,7 @@ class VirtualRenderer { // If it fits, no action needed if (fitsY) return; - + // If it can fully fit in the screen, scroll down until it fits on the screen // if it cannot fully fit, scroll so that the row with the cursor // is at the top of the screen. @@ -1838,13 +1844,13 @@ class VirtualRenderer { this.scrollBy(0, (textChunks.length - 1) * this.lineHeight); } else { this.scrollToRow(insertPosition.row); - } + } } - + } /** - * Calculates and organizes text into wrapped chunks. Initially splits the text by newline characters, + * Calculates and organizes text into wrapped chunks. Initially splits the text by newline characters, * then further processes each line based on display tokens and session settings for tab size and wrapping limits. * * @param {string} text @@ -1913,7 +1919,7 @@ class VirtualRenderer { var diff = token.value.length - (l - column); var before = token.value.slice(0, diff); var after = token.value.slice(diff); - + tokens.splice(i, 1, {type: token.type, value: before}, newToken, {type: token.type, value: after}); break; } @@ -1942,10 +1948,10 @@ class VirtualRenderer { continue; } // We call this method after we call addToken, so we are guaranteed a new token starts at the cursor position. - // Once we reached that point in the loop, flip the flag. + // Once we reached that point in the loop, flip the flag. if (l === column) { hasPassedCursor = true; - } + } } this.updateLines(row, row); return hiddenTokens; @@ -1960,7 +1966,7 @@ class VirtualRenderer { * [Sets a new theme for the editor. `theme` should exist, and be a directory path, like `ace/theme/textmate`.]{: #VirtualRenderer.setTheme} * @param {String | Theme} [theme] The path to a theme * @param {() => void} [cb] optional callback - + **/ setTheme(theme, cb) { var _self = this; @@ -1994,11 +2000,11 @@ class VirtualRenderer { if (_self.theme) dom.removeCssClass(_self.container, _self.theme.cssClass); /**@type {any}*/ - var padding = "padding" in module ? module.padding + var padding = "padding" in module ? module.padding : "padding" in (_self.theme || {}) ? 4 : _self.$padding; if (_self.$padding && padding != _self.$padding) _self.setPadding(padding); - + // this is kept only for backwards compatibility _self.$theme = module.cssClass; @@ -2067,14 +2073,14 @@ class VirtualRenderer { setMouseCursor(cursorStyle) { dom.setStyle(this.scroller.style, "cursor", cursorStyle); } - + attachToShadowRoot() { dom.importCssString(editorCss, "ace_editor.css", this.container); } /** * Destroys the text and cursor layers for this renderer. - + **/ destroy() { this.freeze(); @@ -2086,7 +2092,7 @@ class VirtualRenderer { } /** - * + * * @param {boolean} [val] */ $updateCustomScrollbar(val) { @@ -2127,7 +2133,7 @@ class VirtualRenderer { } /** - + */ $addResizeObserver() { if (!window.ResizeObserver || this.$resizeObserver) return; @@ -2214,7 +2220,7 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { this.$updatePrintMargin(); }, get: function() { - return this.$showPrintMargin && this.$printMarginColumn; + return this.$showPrintMargin && this.$printMarginColumn; } }, showGutter: { From 6ff93a86fe8c4855789ee7e7c156f7b376c0f935 Mon Sep 17 00:00:00 2001 From: babalaui Date: Mon, 4 Nov 2024 11:34:58 +0100 Subject: [PATCH 1175/1293] fix(a11y): update aria-label of textinput on cursor move (#5665) --- src/keyboard/textinput.js | 28 ++++++++++++++++++---------- src/keyboard/textinput_test.js | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/keyboard/textinput.js b/src/keyboard/textinput.js index 81743b7f242..fb657872b75 100644 --- a/src/keyboard/textinput.js +++ b/src/keyboard/textinput.js @@ -73,6 +73,19 @@ TextInput= function(parentNode, host) { numberOfExtraLines = number; }; + + this.setAriaLabel = function() { + var ariaLabel = ""; + if (host.$textInputAriaLabel) { + ariaLabel += `${host.$textInputAriaLabel}, `; + } + if(host.session) { + var row = host.session.selection.cursor.row; + ariaLabel += nls("text-input.aria-label", "Cursor at row $0", [row + 1]); + } + text.setAttribute("aria-label", ariaLabel); + }; + this.setAriaOptions = function(options) { if (options.activeDescendant) { text.setAttribute("aria-haspopup", "true"); @@ -88,19 +101,11 @@ TextInput= function(parentNode, host) { } if (options.setLabel) { text.setAttribute("aria-roledescription", nls("text-input.aria-roledescription", "editor")); - var arialLabel = ""; - if (host.$textInputAriaLabel) { - arialLabel += `${host.$textInputAriaLabel}, `; - } - if(host.session) { - var row = host.session.selection.cursor.row; - arialLabel += nls("text-input.aria-label", "Cursor at row $0", [row + 1]); - } - text.setAttribute("aria-label", arialLabel); + this.setAriaLabel(); } }; - this.setAriaOptions({role: "textbox"}); + this.setAriaOptions({role: "textbox"}); event.addListener(text, "blur", function(e) { if (ignoreFocusEvents) return; @@ -191,6 +196,9 @@ TextInput= function(parentNode, host) { // sync value of textarea resetSelection(); }); + + // if cursor changes position, we need to update the label with the correct row + host.on("changeSelection", this.setAriaLabel); // Convert from row,column position to the linear position with respect to the current // block of lines in the textarea. diff --git a/src/keyboard/textinput_test.js b/src/keyboard/textinput_test.js index f912bfbf250..e84e8e65ab7 100644 --- a/src/keyboard/textinput_test.js +++ b/src/keyboard/textinput_test.js @@ -789,7 +789,24 @@ module.exports = { let text = editor.container.querySelector(".ace_text-input"); assert.equal(text.getAttribute("aria-label"), "super cool editor, Cursor at row 1"); - } + }, + + "test: text input aria label updated on cursor move": function() { + editor.setValue("line1\nline2\nline3", -1); + editor.setOption('enableKeyboardAccessibility', true); + editor.renderer.$loop._flush(); + + let text = editor.container.querySelector(".ace_text-input"); + assert.equal(text.getAttribute("aria-label"), "Cursor at row 1"); + + editor.focus(); + sendEvent("keydown", {key: { code: "ArrowDown", key: "ArrowDown", keyCode: 40}}); + sendEvent("keydown", {key: { code: "ArrowDown", key: "ArrowDown", keyCode: 40}}); + sendEvent("keydown", {key: { code: "ArrowRight", key: "ArrowRight", keyCode: 39}}); + editor.renderer.$loop._flush(); + + assert.equal(text.getAttribute("aria-label"), "Cursor at row 3"); + }, }; From 9a8da4c27471dcbfa1474d15099b0a29461728fc Mon Sep 17 00:00:00 2001 From: Ion Babalau Date: Mon, 4 Nov 2024 14:16:40 +0100 Subject: [PATCH 1176/1293] release v1.36.4 --- CHANGELOG.md | 7 +++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3be87ca7eb5..4d76bee1a01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.36.4](https://github.com/ajaxorg/ace/compare/v1.36.3...v1.36.4) (2024-11-04) + + +### Bug Fixes + +* **a11y:** update aria-label of textinput on cursor move ([#5665](https://github.com/ajaxorg/ace/issues/5665)) ([6ff93a8](https://github.com/ajaxorg/ace/commit/6ff93a86fe8c4855789ee7e7c156f7b376c0f935)) + ### [1.36.3](https://github.com/ajaxorg/ace/compare/v1.36.2...v1.36.3) (2024-10-21) diff --git a/build b/build index a10728b1a3e..af770649d71 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit a10728b1a3ed6f87e4c0cf308523f002daa7ffef +Subproject commit af770649d71c0604f21cd972f23f5ab9d99702bc diff --git a/package.json b/package.json index e89bbd1bbff..a9125532d03 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.36.3", + "version": "1.36.4", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index d4662231f17..4b6b70e01e3 100644 --- a/src/config.js +++ b/src/config.js @@ -194,6 +194,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.36.3"; +exports.version = "1.36.4"; From 74e95d106bdc9ab89ebc8465f4f369e8ea5ae3e9 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Fri, 8 Nov 2024 13:57:17 +0400 Subject: [PATCH 1177/1293] Fix star and fork buttons on homepage (#5668) --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index b08366aea11..8a7ed99d81f 100644 --- a/index.html +++ b/index.html @@ -25,8 +25,8 @@

    The high performance code editor for the web.

    From 5e1e524d7ef04e13291b5a979fb4166e973e61f0 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:48:17 +0400 Subject: [PATCH 1178/1293] fix: vue-directives regex bug (#5671) --- demo/kitchen-sink/docs/vue.vue | 2 ++ src/mode/_test/tokens_vue.json | 23 +++++++++++++++++++++++ src/mode/vue_highlight_rules.js | 2 +- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/demo/kitchen-sink/docs/vue.vue b/demo/kitchen-sink/docs/vue.vue index fda787f2d37..b1ff66bbc67 100644 --- a/demo/kitchen-sink/docs/vue.vue +++ b/demo/kitchen-sink/docs/vue.vue @@ -115,3 +115,5 @@ html, body each item in items li= item + + diff --git a/src/mode/_test/tokens_vue.json b/src/mode/_test/tokens_vue.json index 81d362b521f..9cd3f4942a7 100644 --- a/src/mode/_test/tokens_vue.json +++ b/src/mode/_test/tokens_vue.json @@ -733,4 +733,27 @@ ["meta.tag.punctuation.tag-close.xml",">"] ],[ "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","template"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","v-"], + ["entity.other.attribute-name.xml","slot"], + ["entity.other.attribute-name.xml",":item"], + ["entity.other.attribute-name.xml",".parentkey.subkey.subkey.subkey.subkey.subkey"], + ["punctuation.separator.key-value.xml","="], + ["string","\""], + ["paren.lparen","{"], + ["text"," "], + ["identifier","value"], + ["text"," "], + ["paren.rparen","}"], + ["string","\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" ]] \ No newline at end of file diff --git a/src/mode/vue_highlight_rules.js b/src/mode/vue_highlight_rules.js index eb3223a9eae..36d4408e19d 100644 --- a/src/mode/vue_highlight_rules.js +++ b/src/mode/vue_highlight_rules.js @@ -84,7 +84,7 @@ var VueHighlightRules = function (options) { var self = this; VueRules.tag_stuff.unshift({//vue-directives token: "string", - regex: /(?:\b(v-)|(:|@))(\[?[a-zA-Z\-.]+\]?)(?:(\:\[?[a-zA-Z\-]+\]?))?(?:(\.[a-zA-Z\-]+))*(\s*)(=)(\s*)(["'])/, + regex: /(?:\b(v-)|(:|@))(\[?[a-zA-Z\-.]+\]?)(?:(\:\[?[a-zA-Z\-]+\]?))?((?:\.[a-zA-Z\-]+)*)(\s*)(=)(\s*)(["'])/, onMatch: function (value, currentState, stack) { var quote = value[value.length - 1]; stack.unshift(quote, currentState); From f5d0c196c69d06a9dda1bdeb379fa20ecbf75590 Mon Sep 17 00:00:00 2001 From: nlujjawal <164378643+nlujjawal@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:13:34 +0100 Subject: [PATCH 1179/1293] Feat: exposing getter setter for widget manager created using line widgets (#5673) * Feat: exposing getter setter for widget manager from edit_session created using line widgets --- ace-internal.d.ts | 16 +++++++++------- ace.d.ts | 24 +++++++++++++++++++++++- src/edit_session.js | 32 ++++++++++++++++++++++++++++++++ src/editor.js | 9 ++------- src/ext/code_lens.js | 6 ------ src/ext/error_marker.js | 6 ------ 6 files changed, 66 insertions(+), 27 deletions(-) diff --git a/ace-internal.d.ts b/ace-internal.d.ts index 96d51a66eb3..65783e456d7 100644 --- a/ace-internal.d.ts +++ b/ace-internal.d.ts @@ -293,21 +293,23 @@ export namespace Ace { } interface LineWidget { - el: HTMLElement; - rowCount: number; - hidden: boolean; - _inDocument: boolean; + editor?: Editor, + el?: HTMLElement; + rowCount?: number; + hidden?: boolean; + _inDocument?: boolean; column?: number; - row?: number; + row: number; $oldWidget?: LineWidget, - session: EditSession, + session?: EditSession, html?: string, text?: string, className?: string, coverGutter?: boolean, pixelHeight?: number, $fold?: Fold, - editor: Editor, + type?:any, + destroy?:()=>void; coverLine?: boolean, fixedWidth?: boolean, fullWidth?: boolean, diff --git a/ace.d.ts b/ace.d.ts index 88560068eb7..de9f7f75e17 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -513,7 +513,7 @@ export namespace Ace { name?: string; }; }; - + widgetManager:WidgetManager; // TODO: define BackgroundTokenizer on(name: 'changeFold', @@ -1107,6 +1107,28 @@ export namespace Ace { tryShow(pos: Point, lineHeight: number, anchor: "top" | "bottom" | undefined, forceShow?: boolean): boolean; goTo(where: AcePopupNavigation): void; } + + export interface LineWidget { + el: HTMLElement; + row: number; + rowCount?: number; + hidden: boolean; + editor: Editor, + session: EditSession, + column?: number; + className?: string, + coverGutter?: boolean, + pixelHeight?: number, + fixedWidth?: boolean, + fullWidth?: boolean, + screenWidth?: number, + } + + export class WidgetManager { + constructor(session: EditSession); + addLineWidget(w: LineWidget): LineWidget; + removeLineWidget(w: LineWidget): void; + } } diff --git a/src/edit_session.js b/src/edit_session.js index 7fef86d933d..f9717aa4779 100644 --- a/src/edit_session.js +++ b/src/edit_session.js @@ -6,6 +6,7 @@ * @typedef {import("../ace-internal").Ace.Delta} Delta * @typedef {import("../ace-internal").Ace.IRange} IRange * @typedef {import("../ace-internal").Ace.SyntaxMode} SyntaxMode + * @typedef {import("../ace-internal").Ace.LineWidget} LineWidget */ var oop = require("./lib/oop"); @@ -16,6 +17,7 @@ var EventEmitter = require("./lib/event_emitter").EventEmitter; var Selection = require("./selection").Selection; var TextMode = require("./mode/text").Mode; var Range = require("./range").Range; +var LineWidgets = require("./line_widgets").LineWidgets; var Document = require("./document").Document; var BackgroundTokenizer = require("./background_tokenizer").BackgroundTokenizer; var SearchHighlight = require("./search_highlight").SearchHighlight; @@ -45,6 +47,7 @@ class EditSession { this.$backMarkers = {}; this.$markerId = 1; this.$undoSelect = true; + this.$editor = null; this.prevOp = {}; /** @type {FoldLine[]} */ @@ -187,6 +190,35 @@ class EditSession { return this.doc; } + /** + * Get "widgetManager" from EditSession + * + * @returns {LineWidgets} object + */ + get widgetManager() { + const widgetManager = new LineWidgets(this); + // todo remove the widgetManger assignement from lineWidgets constructor when introducing breaking changes + this.widgetManager = widgetManager; + + if (this.$editor) + widgetManager.attach(this.$editor); + + return widgetManager; + } + + /** + * Set "widgetManager" in EditSession + * + * @returns void + */ + set widgetManager(value) { + Object.defineProperty(this, "widgetManager", { + writable: true, + enumerable: true, + configurable: true, + value: value, + }); + } /** * @param {Number} docRow The row to work with * diff --git a/src/editor.js b/src/editor.js index 2ad6199af47..db888515deb 100644 --- a/src/editor.js +++ b/src/editor.js @@ -23,7 +23,6 @@ var CommandManager = require("./commands/command_manager").CommandManager; var defaultCommands = require("./commands/default_commands").commands; var config = require("./config"); var TokenIterator = require("./token_iterator").TokenIterator; -var LineWidgets = require("./line_widgets").LineWidgets; var GutterKeyboardHandler = require("./keyboard/gutter_handler").GutterKeyboardHandler; var nls = require("./config").nls; @@ -357,7 +356,9 @@ class Editor { this.curOp = null; oldSession && oldSession._signal("changeEditor", {oldEditor: this}); + if (oldSession) oldSession.$editor = null; session && session._signal("changeEditor", {editor: this}); + if (session) session.$editor = this; if (session && !session.destroyed) session.bgTokenizer.scheduleStart(); @@ -1486,10 +1487,6 @@ class Editor { * @param {Point} [position] Position to insert text to */ setGhostText(text, position) { - if (!this.session.widgetManager) { - this.session.widgetManager = new LineWidgets(this.session); - this.session.widgetManager.attach(this); - } this.renderer.setGhostText(text, position); } @@ -1497,8 +1494,6 @@ class Editor { * Removes "ghost" text currently displayed in the editor. */ removeGhostText() { - if (!this.session.widgetManager) return; - this.renderer.removeGhostText(); } diff --git a/src/ext/code_lens.js b/src/ext/code_lens.js index 7098c1e9984..44748bec7b5 100644 --- a/src/ext/code_lens.js +++ b/src/ext/code_lens.js @@ -4,7 +4,6 @@ * @typedef {import("../virtual_renderer").VirtualRenderer & {$textLayer: import("../layer/text").Text &{$lenses: any}}} VirtualRenderer */ -var LineWidgets = require("../line_widgets").LineWidgets; var event = require("../lib/event"); var lang = require("../lib/lang"); var dom = require("../lib/dom"); @@ -157,11 +156,6 @@ function attachToEditor(editor) { var session = editor.session; if (!session) return; - if (!session.widgetManager) { - session.widgetManager = new LineWidgets(session); - session.widgetManager.attach(editor); - } - var providersToWaitNum = editor.codeLensProviders.length; var lenses = []; editor.codeLensProviders.forEach(function(provider) { diff --git a/src/ext/error_marker.js b/src/ext/error_marker.js index 1c4bc5aa7e6..2da3838a7ca 100644 --- a/src/ext/error_marker.js +++ b/src/ext/error_marker.js @@ -1,5 +1,4 @@ "use strict"; -var LineWidgets = require("../line_widgets").LineWidgets; var dom = require("../lib/dom"); var Range = require("../range").Range; var nls = require("../config").nls; @@ -70,11 +69,6 @@ function findAnnotations(session, row, dir) { */ exports.showErrorMarker = function(editor, dir) { var session = editor.session; - if (!session.widgetManager) { - session.widgetManager = new LineWidgets(session); - session.widgetManager.attach(editor); - } - var pos = editor.getCursorPosition(); var row = pos.row; var oldWidget = session.widgetManager.getWidgetsAtRow(row).filter(function(w) { From 6dfb903237193bb237d6f5102c4d2fbe8c7bc205 Mon Sep 17 00:00:00 2001 From: nlujjawal Date: Thu, 14 Nov 2024 15:45:40 +0100 Subject: [PATCH 1180/1293] release v1.36.5 --- CHANGELOG.md | 12 ++++++++++++ build | 2 +- package.json | 2 +- src/config.js | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d76bee1a01..58427732eb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.36.5](https://github.com/ajaxorg/ace/compare/v1.36.4...v1.36.5) (2024-11-14) + + +### Features + +* exposing getter setter for widget manager created using line widgets ([#5673](https://github.com/ajaxorg/ace/issues/5673)) ([f5d0c19](https://github.com/ajaxorg/ace/commit/f5d0c196c69d06a9dda1bdeb379fa20ecbf75590)) + + +### Bug Fixes + +* vue-directives regex bug ([#5671](https://github.com/ajaxorg/ace/issues/5671)) ([5e1e524](https://github.com/ajaxorg/ace/commit/5e1e524d7ef04e13291b5a979fb4166e973e61f0)) + ### [1.36.4](https://github.com/ajaxorg/ace/compare/v1.36.3...v1.36.4) (2024-11-04) diff --git a/build b/build index af770649d71..fb1f105576c 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit af770649d71c0604f21cd972f23f5ab9d99702bc +Subproject commit fb1f105576c9ea77dfaa5319dbf7312b6d0befbf diff --git a/package.json b/package.json index a9125532d03..26fe8060271 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.36.4", + "version": "1.36.5", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 4b6b70e01e3..a3e621980c0 100644 --- a/src/config.js +++ b/src/config.js @@ -194,6 +194,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.36.4"; +exports.version = "1.36.5"; From 442680c68e66531c2d5ac80d80444ed600262ec1 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:56:22 +0400 Subject: [PATCH 1181/1293] fix: wrong behaviour rules in modes (#5682) --- src/mode/java.js | 1 + src/mode/scala.js | 1 + src/mode/wollok.js | 1 + 3 files changed, 3 insertions(+) diff --git a/src/mode/java.js b/src/mode/java.js index 0ef16d49244..fcd44ab81ba 100644 --- a/src/mode/java.js +++ b/src/mode/java.js @@ -9,6 +9,7 @@ var Mode = function() { JavaScriptMode.call(this); this.HighlightRules = JavaHighlightRules; this.foldingRules = new JavaFoldMode(); + this.$behaviour = this.$defaultBehaviour; }; oop.inherits(Mode, JavaScriptMode); diff --git a/src/mode/scala.js b/src/mode/scala.js index 55a2b3842fa..be96ceecdcc 100644 --- a/src/mode/scala.js +++ b/src/mode/scala.js @@ -7,6 +7,7 @@ var ScalaHighlightRules = require("./scala_highlight_rules").ScalaHighlightRules var Mode = function() { JavaScriptMode.call(this); this.HighlightRules = ScalaHighlightRules; + this.$behaviour = this.$defaultBehaviour; }; oop.inherits(Mode, JavaScriptMode); diff --git a/src/mode/wollok.js b/src/mode/wollok.js index 905e30980a6..4bce1ee3e25 100644 --- a/src/mode/wollok.js +++ b/src/mode/wollok.js @@ -7,6 +7,7 @@ var WollokHighlightRules = require("./wollok_highlight_rules").WollokHighlightRu var Mode = function() { JavaScriptMode.call(this); this.HighlightRules = WollokHighlightRules; + this.$behaviour = this.$defaultBehaviour; }; oop.inherits(Mode, JavaScriptMode); From b3625f36a7c48514e93626e679a56cc32dd2c4f0 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Thu, 21 Nov 2024 14:36:57 +0100 Subject: [PATCH 1182/1293] chore: small tweaks LineWidget type (#5683) Co-authored-by: Alice Koreman --- ace.d.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index de9f7f75e17..659d31b780c 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1112,16 +1112,16 @@ export namespace Ace { el: HTMLElement; row: number; rowCount?: number; - hidden: boolean; - editor: Editor, - session: EditSession, + hidden?: boolean; + editor?: Editor; + session?: EditSession; column?: number; - className?: string, - coverGutter?: boolean, - pixelHeight?: number, - fixedWidth?: boolean, - fullWidth?: boolean, - screenWidth?: number, + className?: string; + coverGutter?: boolean; + pixelHeight?: number; + fixedWidth?: boolean; + fullWidth?: boolean; + screenWidth?: number; } export class WidgetManager { From 690052db9e7a56ced8dfd87fc9864943f77584b4 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Sat, 23 Nov 2024 17:40:01 +0400 Subject: [PATCH 1183/1293] Generate public types from ace-internal.d.ts (#5427) --- .github/workflows/nodejs.yml | 15 +- Makefile.dryice.js | 45 +- ace-extensions.d.ts | 20 - ace-internal.d.ts | 8 - ace-modes.d.ts | 852 ++--- ace.d.ts | 2162 ++++++------ demo/test_package/index.ts | 114 + demo/test_package/package.json | 16 + demo/test_package/tsconfig.json | 26 + package.json | 8 +- src/autocomplete.js | 50 +- src/autocomplete_test.js | 8 + src/config.js | 3 + src/document.js | 4 +- src/edit_session.js | 2 +- src/ext/prompt.js | 2 +- src/keyboard/hash_handler.js | 6 +- src/lib/dom.js | 5 + src/lib/event.js | 10 +- src/lib/lang.js | 12 +- src/mode/behaviour/css.js | 1 - tool/ace_declaration_generator.js | 662 ++++ tool/modes-declaration-generator.js | 3 +- tool/test-npm-package.sh | 36 + tsconfig.json | 7 +- types/ace-ext.d.ts | 610 ++++ types/ace-lib.d.ts | 221 ++ types/ace-modules.d.ts | 4745 +++++++++++++++++++++++++++ types/ace-snippets.d.ts | 402 +++ types/ace-theme.d.ts | 437 +++ 30 files changed, 8781 insertions(+), 1711 deletions(-) delete mode 100644 ace-extensions.d.ts create mode 100644 demo/test_package/index.ts create mode 100644 demo/test_package/package.json create mode 100644 demo/test_package/tsconfig.json create mode 100644 tool/ace_declaration_generator.js create mode 100755 tool/test-npm-package.sh create mode 100644 types/ace-ext.d.ts create mode 100644 types/ace-lib.d.ts create mode 100644 types/ace-modules.d.ts create mode 100644 types/ace-snippets.d.ts create mode 100644 types/ace-theme.d.ts diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 2eb07029b0b..50d9f943b0a 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -52,10 +52,17 @@ jobs: fi fi # check types - - run: npm run update-types - - run: node_modules/.bin/tsc --noImplicitAny --strict --noUnusedLocals --noImplicitReturns --noUnusedParameters --noImplicitThis ace.d.ts - - run: npm run typecheck - - run: git diff --exit-code ./ace-modes.d.ts ./ace.d.ts + - run: | + set -x; + npx tsc -v; + npm run update-types; + git diff --color --exit-code ./ace*d.ts; + npm run typecheck; + node_modules/.bin/tsc --noImplicitAny --strict --noUnusedLocals --noImplicitReturns --noUnusedParameters --noImplicitThis ace.d.ts; + - run: | + set -x; + ./tool/test-npm-package.sh + # upload to codecov - uses: codecov/codecov-action@v3 with: token: d8edca4b-8e97-41e5-b54e-34c7cf3b2d47 diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 7ac4d0cb023..5c4eeaef012 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -35,6 +35,11 @@ var fs = require("fs"); var path = require("path"); var copy = require('architect-build/copy'); var build = require('architect-build/build'); +var { + updateDeclarationModuleNames, + generateDeclaration, + SEPARATE_MODULES +} = require('./tool/ace_declaration_generator'); var ACE_HOME = __dirname; var BUILD_DIR = ACE_HOME + "/build"; @@ -174,20 +179,30 @@ function ace() { } } +function correctDeclarationsForBuild(path, additionalDeclarations) { + var definitions = fs.readFileSync(path, 'utf8'); + var newDefinitions = updateDeclarationModuleNames(definitions); + if (additionalDeclarations) { + newDefinitions = newDefinitions + '\n' + additionalDeclarations; + } + fs.writeFileSync(path, newDefinitions); +} + function buildTypes() { - var aceCodeModeDefinitions = '/// '; - var aceCodeExtensionDefinitions = '/// '; // ace-builds package has different structure and can't use mode types defined for the ace-code. - // ace-builds modes are declared along with other modules in the ace-modules.d.ts file below. - var definitions = fs.readFileSync(ACE_HOME + '/ace.d.ts', 'utf8').replace(aceCodeModeDefinitions, '').replace(aceCodeExtensionDefinitions, ''); var paths = fs.readdirSync(BUILD_DIR + '/src-noconflict'); - var moduleRef = '/// '; + + var typeDir = BUILD_DIR + "/types"; + + if (!fs.existsSync(typeDir)) { + fs.mkdirSync(typeDir); + } fs.readdirSync(BUILD_DIR + '/src-noconflict/snippets').forEach(function(path) { paths.push("snippets/" + path); }); - var moduleNameRegex = /^(mode|theme|ext|keybinding)-|^snippets\//; + var moduleNameRegex = /^(keybinding)-/; var pathModules = [ "declare module 'ace-builds/webpack-resolver';", @@ -199,9 +214,21 @@ function buildTypes() { return "declare module 'ace-builds/src-noconflict/" + moduleName + "';"; } }).filter(Boolean)).join("\n") + "\n"; - - fs.writeFileSync(BUILD_DIR + '/ace.d.ts', moduleRef + '\n' + definitions); - fs.writeFileSync(BUILD_DIR + '/ace-modules.d.ts', pathModules); + + fs.copyFileSync(ACE_HOME + '/ace-internal.d.ts', BUILD_DIR + '/ace.d.ts'); + generateDeclaration(BUILD_DIR + '/ace.d.ts'); + fs.copyFileSync(ACE_HOME + '/ace-modes.d.ts', BUILD_DIR + '/ace-modes.d.ts'); + correctDeclarationsForBuild(BUILD_DIR + '/ace.d.ts', pathModules); + correctDeclarationsForBuild(BUILD_DIR + '/ace-modes.d.ts'); + + let allModules = SEPARATE_MODULES; + allModules.push("modules"); // core modules + allModules.forEach(function (key) { + let fileName = '/ace-' + key + '.d.ts'; + fs.copyFileSync(ACE_HOME + '/types' + fileName, BUILD_DIR + '/types' + fileName); + correctDeclarationsForBuild(BUILD_DIR + '/types' + fileName); + }); + var esmUrls = []; var loader = paths.map(function(path) { diff --git a/ace-extensions.d.ts b/ace-extensions.d.ts deleted file mode 100644 index d6988579647..00000000000 --- a/ace-extensions.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -declare module "ace-code/src/ext/simple_tokenizer" { - export type TokenizeResult = Array> - export function tokenize(content: string, highlightRules: import("./ace").Ace.HighlightRules): TokenizeResult; -} - -declare module "ace-code/src/ext/modelist" { - export type Mode = { - name: string; - caption: string; - mode: string; - extensions: string; - supportsFile(filename: string): boolean; - } - export function getModeForPath(path: string): Mode; - export const modes: Mode[]; - export const modesByName: Record; -} diff --git a/ace-internal.d.ts b/ace-internal.d.ts index 65783e456d7..154614fd961 100644 --- a/ace-internal.d.ts +++ b/ace-internal.d.ts @@ -1335,7 +1335,6 @@ declare module "./src/edit_session" { $useWorker?: boolean, $wrapAsCode?: boolean, $indentedSoftWrap?: boolean, - widgetManager?: any, $bracketHighlight?: any, $selectionMarker?: number, lineWidgetsWidth?: number, @@ -1357,12 +1356,6 @@ declare module "./src/edit_session" { $occurMatchingLines?: any, $useEmacsStyleLineStart?: boolean, $selectLongWords?: boolean, - curOp?: { - command: {}, - args: string, - scrollTop: number, - [key: string]: any; - }, getSelectionMarkers(): any[], } @@ -1375,7 +1368,6 @@ declare module "./src/edit_session/fold" { } } -// @ts-expect-error declare module "./src/placeholder" { export interface PlaceHolder extends Ace.EventEmitter { } diff --git a/ace-modes.d.ts b/ace-modes.d.ts index f2da9f47c56..93c4d8f8fe4 100644 --- a/ace-modes.d.ts +++ b/ace-modes.d.ts @@ -1,290 +1,290 @@ declare module "ace-code/src/mode/abap_highlight_rules" { - export const AbapHighlightRules: new () => import(".").Ace.HighlightRules; + export const AbapHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/abap" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/abc_highlight_rules" { - export const ABCHighlightRules: new () => import(".").Ace.HighlightRules; + export const ABCHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/abc" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/actionscript_highlight_rules" { - export const ActionScriptHighlightRules: new () => import(".").Ace.HighlightRules; + export const ActionScriptHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/actionscript" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/ada_highlight_rules" { - export const AdaHighlightRules: new () => import(".").Ace.HighlightRules; + export const AdaHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/ada" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/alda_highlight_rules" { - export const AldaHighlightRules: new () => import(".").Ace.HighlightRules; + export const AldaHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/alda" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/apache_conf_highlight_rules" { - export const ApacheConfHighlightRules: new () => import(".").Ace.HighlightRules; + export const ApacheConfHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/apache_conf" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/apex_highlight_rules" { - export const ApexHighlightRules: new () => import(".").Ace.HighlightRules; + export const ApexHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/apex" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/applescript_highlight_rules" { - export const AppleScriptHighlightRules: new () => import(".").Ace.HighlightRules; + export const AppleScriptHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/applescript" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/aql_highlight_rules" { - export const AqlHighlightRules: new () => import(".").Ace.HighlightRules; + export const AqlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/aql" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/asciidoc_highlight_rules" { - export const AsciidocHighlightRules: new () => import(".").Ace.HighlightRules; + export const AsciidocHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/asciidoc" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/asl_highlight_rules" { - export const ASLHighlightRules: new () => import(".").Ace.HighlightRules; + export const ASLHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/asl" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/assembly_arm32_highlight_rules" { - export const AssemblyARM32HighlightRules: new () => import(".").Ace.HighlightRules; + export const AssemblyARM32HighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/assembly_arm32" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/assembly_x86_highlight_rules" { - export const AssemblyX86HighlightRules: new () => import(".").Ace.HighlightRules; + export const AssemblyX86HighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/assembly_x86" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/astro_highlight_rules" { - export const AstroHighlightRules: new () => import(".").Ace.HighlightRules; + export const AstroHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/astro" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/autohotkey_highlight_rules" { - export const AutoHotKeyHighlightRules: new () => import(".").Ace.HighlightRules; + export const AutoHotKeyHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/autohotkey" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/basic_highlight_rules" { - export const BasicHighlightRules: new () => import(".").Ace.HighlightRules; + export const BasicHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/basic" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/batchfile_highlight_rules" { - export const BatchFileHighlightRules: new () => import(".").Ace.HighlightRules; + export const BatchFileHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/batchfile" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/behaviour" { - export const Behaviour: new () => import(".").Ace.Behaviour; + export const Behaviour: new () => import("ace-code").Ace.Behaviour; } declare module "ace-code/src/mode/behaviour/css" { - export const CssBehaviour: new () => import(".").Ace.Behaviour; + export const CssBehaviour: new () => import("ace-code").Ace.Behaviour; } declare module "ace-code/src/mode/behaviour/cstyle" { - export const CstyleBehaviour: new () => import(".").Ace.Behaviour; + export const CstyleBehaviour: new () => import("ace-code").Ace.Behaviour; } declare module "ace-code/src/mode/behaviour/html" { - export const HtmlBehaviour: new () => import(".").Ace.Behaviour; + export const HtmlBehaviour: new () => import("ace-code").Ace.Behaviour; } declare module "ace-code/src/mode/behaviour/javascript" { - export const JavaScriptBehaviour: new () => import(".").Ace.Behaviour; + export const JavaScriptBehaviour: new () => import("ace-code").Ace.Behaviour; } declare module "ace-code/src/mode/behaviour/liquid" { - export const LiquidBehaviour: new () => import(".").Ace.Behaviour; + export const LiquidBehaviour: new () => import("ace-code").Ace.Behaviour; } declare module "ace-code/src/mode/behaviour/xml" { - export const XmlBehaviour: new () => import(".").Ace.Behaviour; + export const XmlBehaviour: new () => import("ace-code").Ace.Behaviour; } declare module "ace-code/src/mode/behaviour/xquery" { - export const XQueryBehaviour: new () => import(".").Ace.Behaviour; + export const XQueryBehaviour: new () => import("ace-code").Ace.Behaviour; } declare module "ace-code/src/mode/bibtex_highlight_rules" { - export const BibTeXHighlightRules: new () => import(".").Ace.HighlightRules; + export const BibTeXHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/bibtex" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/c_cpp_highlight_rules" { export const cFunctions: string; - export const c_cppHighlightRules: new () => import(".").Ace.HighlightRules; + export const c_cppHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/c_cpp" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/c9search_highlight_rules" { - export const C9SearchHighlightRules: new () => import(".").Ace.HighlightRules; + export const C9SearchHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/c9search" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/cirru_highlight_rules" { - export const CirruHighlightRules: new () => import(".").Ace.HighlightRules; + export const CirruHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/cirru" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/clojure_highlight_rules" { - export const ClojureHighlightRules: new () => import(".").Ace.HighlightRules; + export const ClojureHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/clojure" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/cobol_highlight_rules" { - export const CobolHighlightRules: new () => import(".").Ace.HighlightRules; + export const CobolHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/cobol" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/coffee_highlight_rules" { - export const CoffeeHighlightRules: new () => import(".").Ace.HighlightRules; + export const CoffeeHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/coffee" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/coldfusion_highlight_rules" { - export const ColdfusionHighlightRules: new () => import(".").Ace.HighlightRules; + export const ColdfusionHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/coldfusion" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/crystal_highlight_rules" { - export const CrystalHighlightRules: new () => import(".").Ace.HighlightRules; + export const CrystalHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/crystal" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/csharp_highlight_rules" { - export const CSharpHighlightRules: new () => import(".").Ace.HighlightRules; + export const CSharpHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/csharp" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/csound_document_highlight_rules" { - export const CsoundDocumentHighlightRules: new () => import(".").Ace.HighlightRules; + export const CsoundDocumentHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/csound_document" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/csound_orchestra_highlight_rules" { - export const CsoundOrchestraHighlightRules: new () => import(".").Ace.HighlightRules; + export const CsoundOrchestraHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/csound_orchestra" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/csound_preprocessor_highlight_rules" { - export const CsoundPreprocessorHighlightRules: new () => import(".").Ace.HighlightRules; + export const CsoundPreprocessorHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/csound_score_highlight_rules" { - export const CsoundScoreHighlightRules: new () => import(".").Ace.HighlightRules; + export const CsoundScoreHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/csound_score" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/csp_highlight_rules" { - export const CspHighlightRules: new () => import(".").Ace.HighlightRules; + export const CspHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/csp" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/css_completions" { - export const CssCompletions: new () => import(".").Ace.Completion; + export const CssCompletions: new () => import("ace-code").Ace.Completion; } declare module "ace-code/src/mode/css_highlight_rules" { @@ -296,1042 +296,1042 @@ declare module "ace-code/src/mode/css_highlight_rules" { export const numRe: string; export const pseudoElements: string; export const pseudoClasses: string; - export const CssHighlightRules: new () => import(".").Ace.HighlightRules; + export const CssHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/css" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/curly_highlight_rules" { - export const CurlyHighlightRules: new () => import(".").Ace.HighlightRules; + export const CurlyHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/curly" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/cuttlefish_highlight_rules" { - export const CuttlefishHighlightRules: new () => import(".").Ace.HighlightRules; + export const CuttlefishHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/cuttlefish" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/d_highlight_rules" { - export const DHighlightRules: new () => import(".").Ace.HighlightRules; + export const DHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/d" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/dart_highlight_rules" { - export const DartHighlightRules: new () => import(".").Ace.HighlightRules; + export const DartHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/dart" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/diff_highlight_rules" { - export const DiffHighlightRules: new () => import(".").Ace.HighlightRules; + export const DiffHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/diff" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/django" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/doc_comment_highlight_rules" { - export const DocCommentHighlightRules: new () => import(".").Ace.HighlightRules; + export const DocCommentHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/dockerfile_highlight_rules" { - export const DockerfileHighlightRules: new () => import(".").Ace.HighlightRules; + export const DockerfileHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/dockerfile" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/dot_highlight_rules" { - export const DotHighlightRules: new () => import(".").Ace.HighlightRules; + export const DotHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/dot" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/drools_highlight_rules" { - export const DroolsHighlightRules: new () => import(".").Ace.HighlightRules; + export const DroolsHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/drools" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/edifact_highlight_rules" { - export const EdifactHighlightRules: new () => import(".").Ace.HighlightRules; + export const EdifactHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/edifact" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/eiffel_highlight_rules" { - export const EiffelHighlightRules: new () => import(".").Ace.HighlightRules; + export const EiffelHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/eiffel" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/ejs" { - export const EjsHighlightRules: new () => import(".").Ace.HighlightRules; - export const Mode: new () => import(".").Ace.SyntaxMode; + export const EjsHighlightRules: new () => import("ace-code").Ace.HighlightRules; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/elixir_highlight_rules" { - export const ElixirHighlightRules: new () => import(".").Ace.HighlightRules; + export const ElixirHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/elixir" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/elm_highlight_rules" { - export const ElmHighlightRules: new () => import(".").Ace.HighlightRules; + export const ElmHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/elm" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/erlang_highlight_rules" { - export const ErlangHighlightRules: new () => import(".").Ace.HighlightRules; + export const ErlangHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/erlang" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/flix_highlight_rules" { - export const FlixHighlightRules: new () => import(".").Ace.HighlightRules; + export const FlixHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/flix" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/folding/asciidoc" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/basic" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/c9search" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/coffee" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/csharp" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/cstyle" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/diff" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/drools" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/fold_mode" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/haskell_cabal" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/html" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/ini" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/java" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/javascript" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/latex" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/lua" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/markdown" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/mixed" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/php" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/pythonic" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/ruby" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/sql" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/sqlserver" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/vbscript" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/velocity" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/xml" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/folding/yaml" { - export const FoldMode: new () => import(".").Ace.Folding; + export const FoldMode: new () => import("ace-code").Ace.Folding; } declare module "ace-code/src/mode/forth_highlight_rules" { - export const ForthHighlightRules: new () => import(".").Ace.HighlightRules; + export const ForthHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/forth" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/fortran_highlight_rules" { - export const FortranHighlightRules: new () => import(".").Ace.HighlightRules; + export const FortranHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/fortran" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/fsharp_highlight_rules" { - export const FSharpHighlightRules: new () => import(".").Ace.HighlightRules; + export const FSharpHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/fsharp" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/fsl_highlight_rules" { - export const FSLHighlightRules: new () => import(".").Ace.HighlightRules; + export const FSLHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/fsl" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/ftl_highlight_rules" { - export const FtlHighlightRules: new () => import(".").Ace.HighlightRules; + export const FtlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/ftl" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/gcode_highlight_rules" { - export const GcodeHighlightRules: new () => import(".").Ace.HighlightRules; + export const GcodeHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/gcode" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/gherkin_highlight_rules" { - export const GherkinHighlightRules: new () => import(".").Ace.HighlightRules; + export const GherkinHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/gherkin" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/gitignore_highlight_rules" { - export const GitignoreHighlightRules: new () => import(".").Ace.HighlightRules; + export const GitignoreHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/gitignore" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/glsl_highlight_rules" { - export const glslHighlightRules: new () => import(".").Ace.HighlightRules; + export const glslHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/glsl" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/gobstones_highlight_rules" { - export const GobstonesHighlightRules: new () => import(".").Ace.HighlightRules; + export const GobstonesHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/gobstones" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/golang_highlight_rules" { - export const GolangHighlightRules: new () => import(".").Ace.HighlightRules; + export const GolangHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/golang" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/graphqlschema_highlight_rules" { - export const GraphQLSchemaHighlightRules: new () => import(".").Ace.HighlightRules; + export const GraphQLSchemaHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/graphqlschema" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/groovy_highlight_rules" { - export const GroovyHighlightRules: new () => import(".").Ace.HighlightRules; + export const GroovyHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/groovy" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/haml_highlight_rules" { - export const HamlHighlightRules: new () => import(".").Ace.HighlightRules; + export const HamlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/haml" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/handlebars_highlight_rules" { - export const HandlebarsHighlightRules: new () => import(".").Ace.HighlightRules; + export const HandlebarsHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/handlebars" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/haskell_cabal_highlight_rules" { - export const CabalHighlightRules: new () => import(".").Ace.HighlightRules; + export const CabalHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/haskell_cabal" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/haskell_highlight_rules" { - export const HaskellHighlightRules: new () => import(".").Ace.HighlightRules; + export const HaskellHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/haskell" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/haxe_highlight_rules" { - export const HaxeHighlightRules: new () => import(".").Ace.HighlightRules; + export const HaxeHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/haxe" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/hjson_highlight_rules" { - export const HjsonHighlightRules: new () => import(".").Ace.HighlightRules; + export const HjsonHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/hjson" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/html_completions" { - export const HtmlCompletions: new () => import(".").Ace.Completion; + export const HtmlCompletions: new () => import("ace-code").Ace.Completion; } declare module "ace-code/src/mode/html_elixir_highlight_rules" { - export const HtmlElixirHighlightRules: new () => import(".").Ace.HighlightRules; + export const HtmlElixirHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/html_elixir" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/html_highlight_rules" { - export const HtmlHighlightRules: new () => import(".").Ace.HighlightRules; + export const HtmlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/html_ruby_highlight_rules" { - export const HtmlRubyHighlightRules: new () => import(".").Ace.HighlightRules; + export const HtmlRubyHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/html_ruby" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/html" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/ini_highlight_rules" { - export const IniHighlightRules: new () => import(".").Ace.HighlightRules; + export const IniHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/ini" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/io_highlight_rules" { - export const IoHighlightRules: new () => import(".").Ace.HighlightRules; + export const IoHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/io" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/ion_highlight_rules" { - export const IonHighlightRules: new () => import(".").Ace.HighlightRules; + export const IonHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/ion" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/jack_highlight_rules" { - export const JackHighlightRules: new () => import(".").Ace.HighlightRules; + export const JackHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/jack" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/jade_highlight_rules" { - export const JadeHighlightRules: new () => import(".").Ace.HighlightRules; + export const JadeHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/jade" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/java_highlight_rules" { - export const JavaHighlightRules: new () => import(".").Ace.HighlightRules; + export const JavaHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/java" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/javascript_highlight_rules" { - export const JavaScriptHighlightRules: new () => import(".").Ace.HighlightRules; + export const JavaScriptHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/javascript" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/jexl_highlight_rules" { - export const JexlHighlightRules: new () => import(".").Ace.HighlightRules; + export const JexlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/jexl" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/js_regex_highlight_rules" { - export const JsRegexHighlightRules: new () => import(".").Ace.HighlightRules; + export const JsRegexHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/jsdoc_comment_highlight_rules" { - export const JsDocCommentHighlightRules: new () => import(".").Ace.HighlightRules; + export const JsDocCommentHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/json_highlight_rules" { - export const JsonHighlightRules: new () => import(".").Ace.HighlightRules; + export const JsonHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/json" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/json5_highlight_rules" { - export const Json5HighlightRules: new () => import(".").Ace.HighlightRules; + export const Json5HighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/json5" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/jsp_highlight_rules" { - export const JspHighlightRules: new () => import(".").Ace.HighlightRules; + export const JspHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/jsp" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/jssm_highlight_rules" { - export const JSSMHighlightRules: new () => import(".").Ace.HighlightRules; + export const JSSMHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/jssm" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/jsx_highlight_rules" { - export const JsxHighlightRules: new () => import(".").Ace.HighlightRules; + export const JsxHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/jsx" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/julia_highlight_rules" { - export const JuliaHighlightRules: new () => import(".").Ace.HighlightRules; + export const JuliaHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/julia" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/kotlin_highlight_rules" { - export const KotlinHighlightRules: new () => import(".").Ace.HighlightRules; + export const KotlinHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/kotlin" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/latex_highlight_rules" { - export const LatexHighlightRules: new () => import(".").Ace.HighlightRules; + export const LatexHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/latex" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/latte_highlight_rules" { - export const LatteHighlightRules: new () => import(".").Ace.HighlightRules; + export const LatteHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/latte" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/less_highlight_rules" { - export const LessHighlightRules: new () => import(".").Ace.HighlightRules; + export const LessHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/less" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/liquid_highlight_rules" { - export const LiquidHighlightRules: new () => import(".").Ace.HighlightRules; + export const LiquidHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/liquid" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/lisp_highlight_rules" { - export const LispHighlightRules: new () => import(".").Ace.HighlightRules; + export const LispHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/lisp" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/livescript" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/logiql_highlight_rules" { - export const LogiQLHighlightRules: new () => import(".").Ace.HighlightRules; + export const LogiQLHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/logiql" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/logtalk_highlight_rules" { - export const LogtalkHighlightRules: new () => import(".").Ace.HighlightRules; + export const LogtalkHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/logtalk" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/lsl_highlight_rules" { - export const LSLHighlightRules: new () => import(".").Ace.HighlightRules; + export const LSLHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/lsl" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/lua_highlight_rules" { - export const LuaHighlightRules: new () => import(".").Ace.HighlightRules; + export const LuaHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/lua" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/luapage_highlight_rules" { - export const LuaPageHighlightRules: new () => import(".").Ace.HighlightRules; + export const LuaPageHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/luapage" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/lucene_highlight_rules" { - export const LuceneHighlightRules: new () => import(".").Ace.HighlightRules; + export const LuceneHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/lucene" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/makefile_highlight_rules" { - export const MakefileHighlightRules: new () => import(".").Ace.HighlightRules; + export const MakefileHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/makefile" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/markdown_highlight_rules" { - export const MarkdownHighlightRules: new () => import(".").Ace.HighlightRules; + export const MarkdownHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/markdown" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/mask_highlight_rules" { - export const MaskHighlightRules: new () => import(".").Ace.HighlightRules; + export const MaskHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/mask" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/matching_brace_outdent" { - export const MatchingBraceOutdent: new () => import(".").Ace.Outdent; + export const MatchingBraceOutdent: new () => import("ace-code").Ace.Outdent; } declare module "ace-code/src/mode/matching_parens_outdent" { - export const MatchingParensOutdent: new () => import(".").Ace.Outdent; + export const MatchingParensOutdent: new () => import("ace-code").Ace.Outdent; } declare module "ace-code/src/mode/matlab_highlight_rules" { - export const MatlabHighlightRules: new () => import(".").Ace.HighlightRules; + export const MatlabHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/matlab" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/maze_highlight_rules" { - export const MazeHighlightRules: new () => import(".").Ace.HighlightRules; + export const MazeHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/maze" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/mediawiki_highlight_rules" { - export const MediaWikiHighlightRules: new () => import(".").Ace.HighlightRules; + export const MediaWikiHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/mediawiki" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/mel_highlight_rules" { - export const MELHighlightRules: new () => import(".").Ace.HighlightRules; + export const MELHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/mel" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/mips_highlight_rules" { - export const MIPSHighlightRules: new () => import(".").Ace.HighlightRules; + export const MIPSHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/mips" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/mixal_highlight_rules" { - export const MixalHighlightRules: new () => import(".").Ace.HighlightRules; + export const MixalHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/mixal" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/mushcode_highlight_rules" { - export const MushCodeRules: new () => import(".").Ace.HighlightRules; + export const MushCodeRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/mushcode" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/mysql_highlight_rules" { - export const MysqlHighlightRules: new () => import(".").Ace.HighlightRules; + export const MysqlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/mysql" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/nasal_highlight_rules" { - export const NasalHighlightRules: new () => import(".").Ace.HighlightRules; + export const NasalHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/nasal" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/nginx_highlight_rules" { - export const NginxHighlightRules: new () => import(".").Ace.HighlightRules; + export const NginxHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/nginx" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/nim_highlight_rules" { - export const NimHighlightRules: new () => import(".").Ace.HighlightRules; + export const NimHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/nim" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/nix_highlight_rules" { - export const NixHighlightRules: new () => import(".").Ace.HighlightRules; + export const NixHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/nix" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/nsis_highlight_rules" { - export const NSISHighlightRules: new () => import(".").Ace.HighlightRules; + export const NSISHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/nsis" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/nunjucks_highlight_rules" { - export const NunjucksHighlightRules: new () => import(".").Ace.HighlightRules; + export const NunjucksHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/nunjucks" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/objectivec_highlight_rules" { - export const ObjectiveCHighlightRules: new () => import(".").Ace.HighlightRules; + export const ObjectiveCHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/objectivec" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/ocaml_highlight_rules" { - export const OcamlHighlightRules: new () => import(".").Ace.HighlightRules; + export const OcamlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/ocaml" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/odin_highlight_rules" { - export const OdinHighlightRules: new () => import(".").Ace.HighlightRules; + export const OdinHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/odin" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/partiql_highlight_rules" { - export const PartiqlHighlightRules: new () => import(".").Ace.HighlightRules; + export const PartiqlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/partiql" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/pascal_highlight_rules" { - export const PascalHighlightRules: new () => import(".").Ace.HighlightRules; + export const PascalHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/pascal" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/perl_highlight_rules" { - export const PerlHighlightRules: new () => import(".").Ace.HighlightRules; + export const PerlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/perl" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/pgsql_highlight_rules" { - export const PgsqlHighlightRules: new () => import(".").Ace.HighlightRules; + export const PgsqlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/pgsql" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/php_completions" { - export const PhpCompletions: new () => import(".").Ace.Completion; + export const PhpCompletions: new () => import("ace-code").Ace.Completion; } declare module "ace-code/src/mode/php_highlight_rules" { - export const PhpHighlightRules: new () => import(".").Ace.HighlightRules; - export const PhpLangHighlightRules: new () => import(".").Ace.HighlightRules; + export const PhpHighlightRules: new () => import("ace-code").Ace.HighlightRules; + export const PhpLangHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/php_laravel_blade_highlight_rules" { - export const PHPLaravelBladeHighlightRules: new () => import(".").Ace.HighlightRules; + export const PHPLaravelBladeHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/php_laravel_blade" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/php" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/pig_highlight_rules" { - export const PigHighlightRules: new () => import(".").Ace.HighlightRules; + export const PigHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/pig" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/plain_text" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/plsql_highlight_rules" { - export const plsqlHighlightRules: new () => import(".").Ace.HighlightRules; + export const plsqlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/plsql" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/powershell_highlight_rules" { - export const PowershellHighlightRules: new () => import(".").Ace.HighlightRules; + export const PowershellHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/powershell" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/praat_highlight_rules" { - export const PraatHighlightRules: new () => import(".").Ace.HighlightRules; + export const PraatHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/praat" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/prisma_highlight_rules" { - export const PrismaHighlightRules: new () => import(".").Ace.HighlightRules; + export const PrismaHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/prisma" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/prolog_highlight_rules" { - export const PrologHighlightRules: new () => import(".").Ace.HighlightRules; + export const PrologHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/prolog" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/properties_highlight_rules" { - export const PropertiesHighlightRules: new () => import(".").Ace.HighlightRules; + export const PropertiesHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/properties" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/protobuf_highlight_rules" { - export const ProtobufHighlightRules: new () => import(".").Ace.HighlightRules; + export const ProtobufHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/protobuf" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/prql_highlight_rules" { - export const PrqlHighlightRules: new () => import(".").Ace.HighlightRules; + export const PrqlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/prql" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/puppet_highlight_rules" { - export const PuppetHighlightRules: new () => import(".").Ace.HighlightRules; + export const PuppetHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/puppet" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/python_highlight_rules" { - export const PythonHighlightRules: new () => import(".").Ace.HighlightRules; + export const PythonHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/python" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/qml_highlight_rules" { - export const QmlHighlightRules: new () => import(".").Ace.HighlightRules; + export const QmlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/qml" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/r_highlight_rules" { - export const RHighlightRules: new () => import(".").Ace.HighlightRules; + export const RHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/r" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/raku_highlight_rules" { - export const RakuHighlightRules: new () => import(".").Ace.HighlightRules; + export const RakuHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/raku" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/razor_completions" { - export const RazorCompletions: new () => import(".").Ace.Completion; + export const RazorCompletions: new () => import("ace-code").Ace.Completion; } declare module "ace-code/src/mode/razor_highlight_rules" { - export const RazorHighlightRules: new () => import(".").Ace.HighlightRules; - export const RazorLangHighlightRules: new () => import(".").Ace.HighlightRules; + export const RazorHighlightRules: new () => import("ace-code").Ace.HighlightRules; + export const RazorLangHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/razor" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/rdoc_highlight_rules" { - export const RDocHighlightRules: new () => import(".").Ace.HighlightRules; + export const RDocHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/rdoc" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/red_highlight_rules" { - export const RedHighlightRules: new () => import(".").Ace.HighlightRules; + export const RedHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/red" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/redshift_highlight_rules" { - export const RedshiftHighlightRules: new () => import(".").Ace.HighlightRules; + export const RedshiftHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/redshift" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/rhtml_highlight_rules" { - export const RHtmlHighlightRules: new () => import(".").Ace.HighlightRules; + export const RHtmlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/rhtml" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/robot_highlight_rules" { - export const RobotHighlightRules: new () => import(".").Ace.HighlightRules; + export const RobotHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/robot" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/rst_highlight_rules" { - export const RSTHighlightRules: new () => import(".").Ace.HighlightRules; + export const RSTHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/rst" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/ruby_highlight_rules" { @@ -1347,362 +1347,362 @@ declare module "ace-code/src/mode/ruby_highlight_rules" { export const constantNumericComplex: { token: string; regex: RegExp; }; export const constantNumericFloat: { token: string; regex: string; }; export const instanceVariable: { token: string; regex: string; }; - export const RubyHighlightRules: new () => import(".").Ace.HighlightRules; + export const RubyHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/ruby" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/rust_highlight_rules" { - export const RustHighlightRules: new () => import(".").Ace.HighlightRules; + export const RustHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/rust" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/sac_highlight_rules" { - export const sacHighlightRules: new () => import(".").Ace.HighlightRules; + export const sacHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/sac" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/sass_highlight_rules" { - export const SassHighlightRules: new () => import(".").Ace.HighlightRules; + export const SassHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/sass" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/scad_highlight_rules" { - export const scadHighlightRules: new () => import(".").Ace.HighlightRules; + export const scadHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/scad" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/scala_highlight_rules" { - export const ScalaHighlightRules: new () => import(".").Ace.HighlightRules; + export const ScalaHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/scala" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/scheme_highlight_rules" { - export const SchemeHighlightRules: new () => import(".").Ace.HighlightRules; + export const SchemeHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/scheme" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/scrypt_highlight_rules" { - export const scryptHighlightRules: new () => import(".").Ace.HighlightRules; + export const scryptHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/scrypt" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/scss_highlight_rules" { - export const ScssHighlightRules: new () => import(".").Ace.HighlightRules; + export const ScssHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/scss" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/sh_highlight_rules" { export const reservedKeywords: string; export const languageConstructs: string; - export const ShHighlightRules: new () => import(".").Ace.HighlightRules; + export const ShHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/sh" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/sjs_highlight_rules" { - export const SJSHighlightRules: new () => import(".").Ace.HighlightRules; + export const SJSHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/sjs" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/slim_highlight_rules" { - export const SlimHighlightRules: new () => import(".").Ace.HighlightRules; + export const SlimHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/slim" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/smarty_highlight_rules" { - export const SmartyHighlightRules: new () => import(".").Ace.HighlightRules; + export const SmartyHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/smarty" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/smithy_highlight_rules" { - export const SmithyHighlightRules: new () => import(".").Ace.HighlightRules; + export const SmithyHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/smithy" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/snippets" { - export const SnippetHighlightRules: new () => import(".").Ace.HighlightRules; - export const SnippetGroupHighlightRules: new () => import(".").Ace.HighlightRules; - export const Mode: new () => import(".").Ace.SyntaxMode; + export const SnippetHighlightRules: new () => import("ace-code").Ace.HighlightRules; + export const SnippetGroupHighlightRules: new () => import("ace-code").Ace.HighlightRules; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/soy_template_highlight_rules" { - export const SoyTemplateHighlightRules: new () => import(".").Ace.HighlightRules; + export const SoyTemplateHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/soy_template" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/space_highlight_rules" { - export const SpaceHighlightRules: new () => import(".").Ace.HighlightRules; + export const SpaceHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/space" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/sparql_highlight_rules" { - export const SPARQLHighlightRules: new () => import(".").Ace.HighlightRules; + export const SPARQLHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/sparql" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/sql_highlight_rules" { - export const SqlHighlightRules: new () => import(".").Ace.HighlightRules; + export const SqlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/sql" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/sqlserver_highlight_rules" { - export const SqlHighlightRules: new () => import(".").Ace.HighlightRules; + export const SqlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/sqlserver" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/stylus_highlight_rules" { - export const StylusHighlightRules: new () => import(".").Ace.HighlightRules; + export const StylusHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/stylus" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/svg_highlight_rules" { - export const SvgHighlightRules: new () => import(".").Ace.HighlightRules; + export const SvgHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/svg" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/swift_highlight_rules" { - export const HighlightRules: new () => import(".").Ace.HighlightRules; - export const SwiftHighlightRules: new () => import(".").Ace.HighlightRules; + export const HighlightRules: new () => import("ace-code").Ace.HighlightRules; + export const SwiftHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/swift" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/tcl_highlight_rules" { - export const TclHighlightRules: new () => import(".").Ace.HighlightRules; + export const TclHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/tcl" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/terraform_highlight_rules" { - export const TerraformHighlightRules: new () => import(".").Ace.HighlightRules; + export const TerraformHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/terraform" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/tex_highlight_rules" { - export const TexHighlightRules: new () => import(".").Ace.HighlightRules; + export const TexHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/tex" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/text_highlight_rules" { - export const TextHighlightRules: new () => import(".").Ace.HighlightRules; + export const TextHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/text" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/textile_highlight_rules" { - export const TextileHighlightRules: new () => import(".").Ace.HighlightRules; + export const TextileHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/textile" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/toml_highlight_rules" { - export const TomlHighlightRules: new () => import(".").Ace.HighlightRules; + export const TomlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/toml" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/tsx_highlight_rules" { - export const TsxHighlightRules: new () => import(".").Ace.HighlightRules; + export const TsxHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/tsx" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/turtle_highlight_rules" { - export const TurtleHighlightRules: new () => import(".").Ace.HighlightRules; + export const TurtleHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/turtle" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/twig_highlight_rules" { - export const TwigHighlightRules: new () => import(".").Ace.HighlightRules; + export const TwigHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/twig" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/typescript_highlight_rules" { - export const TypeScriptHighlightRules: new () => import(".").Ace.HighlightRules; + export const TypeScriptHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/typescript" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/vala_highlight_rules" { - export const ValaHighlightRules: new () => import(".").Ace.HighlightRules; + export const ValaHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/vala" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/vbscript_highlight_rules" { - export const VBScriptHighlightRules: new () => import(".").Ace.HighlightRules; + export const VBScriptHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/vbscript" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/velocity_highlight_rules" { - export const VelocityHighlightRules: new () => import(".").Ace.HighlightRules; + export const VelocityHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/velocity" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/verilog_highlight_rules" { - export const VerilogHighlightRules: new () => import(".").Ace.HighlightRules; + export const VerilogHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/verilog" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/vhdl_highlight_rules" { - export const VHDLHighlightRules: new () => import(".").Ace.HighlightRules; + export const VHDLHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/vhdl" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/visualforce_highlight_rules" { - export const VisualforceHighlightRules: new () => import(".").Ace.HighlightRules; + export const VisualforceHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/visualforce" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/vue_highlight_rules" { - export const VueHighlightRules: new () => import(".").Ace.HighlightRules; + export const VueHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/vue" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/wollok_highlight_rules" { - export const WollokHighlightRules: new () => import(".").Ace.HighlightRules; + export const WollokHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/wollok" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/xml_highlight_rules" { - export const XmlHighlightRules: new () => import(".").Ace.HighlightRules; + export const XmlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/xml" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/yaml_highlight_rules" { - export const YamlHighlightRules: new () => import(".").Ace.HighlightRules; + export const YamlHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/yaml" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/zeek_highlight_rules" { - export const ZeekHighlightRules: new () => import(".").Ace.HighlightRules; + export const ZeekHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/zeek" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } declare module "ace-code/src/mode/zig_highlight_rules" { - export const ZigHighlightRules: new () => import(".").Ace.HighlightRules; + export const ZigHighlightRules: new () => import("ace-code").Ace.HighlightRules; } declare module "ace-code/src/mode/zig" { - export const Mode: new () => import(".").Ace.SyntaxMode; + export const Mode: new () => import("ace-code").Ace.SyntaxMode; } \ No newline at end of file diff --git a/ace.d.ts b/ace.d.ts index 659d31b780c..190a64cf866 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1,1201 +1,965 @@ -/// -/// - -export namespace Ace { - export type NewLineMode = 'auto' | 'unix' | 'windows'; - - export interface Anchor extends EventEmitter { - getPosition(): Position; - getDocument(): Document; - setPosition(row: number, column: number, noClip?: boolean): void; - detach(): void; - attach(doc: Document): void; - } - - export interface Document extends EventEmitter { - setValue(text: string): void; - getValue(): string; - createAnchor(row: number, column: number): Anchor; - getNewLineCharacter(): string; - setNewLineMode(newLineMode: NewLineMode): void; - getNewLineMode(): NewLineMode; - isNewLine(text: string): boolean; - getLine(row: number): string; - getLines(firstRow: number, lastRow: number): string[]; - getAllLines(): string[]; - getLength(): number; - getTextRange(range: Range): string; - getLinesForRange(range: Range): string[]; - insert(position: Position, text: string): Position; - insert(position: {row: number, column: number}, text: string): Position; - insertInLine(position: Position, text: string): Position; - insertNewLine(position: Point): Point; - clippedPos(row: number, column: number): Point; - clonePos(pos: Point): Point; - pos(row: number, column: number): Point; - insertFullLines(row: number, lines: string[]): void; - insertMergedLines(position: Position, lines: string[]): Point; - remove(range: Range): Position; - removeInLine(row: number, startColumn: number, endColumn: number): Position; - removeFullLines(firstRow: number, lastRow: number): string[]; - removeNewLine(row: number): void; - replace(range: Range, text: string): Position; - applyDeltas(deltas: Delta[]): void; - revertDeltas(deltas: Delta[]): void; - applyDelta(delta: Delta, doNotValidate?: boolean): void; - revertDelta(delta: Delta): void; - indexToPosition(index: number, startRow: number): Position; - positionToIndex(pos: Position, startRow?: number): number; - } - - export interface FoldLine { - folds: Fold[]; - range: Range; - start: Point; - end: Point; - - shiftRow(shift: number): void; - addFold(fold: Fold): void; - containsRow(row: number): boolean; - walk(callback: Function, endRow?: number, endColumn?: number): void; - getNextFoldTo(row: number, column: number): null | { fold: Fold, kind: string }; - addRemoveChars(row: number, column: number, len: number): void; - split(row: number, column: number): FoldLine; - merge(foldLineNext: FoldLine): void; - idxToPosition(idx: number): Point; - } - - export interface Fold { - range: Range; - start: Point; - end: Point; - foldLine?: FoldLine; - sameRow: boolean; - subFolds: Fold[]; - - setFoldLine(foldLine: FoldLine): void; - clone(): Fold; - addSubFold(fold: Fold): Fold; - restoreRange(range: Range): void; - } - - interface Folding { - getFoldAt(row: number, column: number, side: number): Fold; - getFoldsInRange(range: Range): Fold[]; - getFoldsInRangeList(ranges: Range[]): Fold[]; - getAllFolds(): Fold[]; - getFoldStringAt(row: number, - column: number, - trim?: number, - foldLine?: FoldLine): string | null; - getFoldLine(docRow: number, startFoldLine?: FoldLine): FoldLine | null; - getNextFoldLine(docRow: number, startFoldLine?: FoldLine): FoldLine | null; - getFoldedRowCount(first: number, last: number): number; - addFold(placeholder: string | Fold, range?: Range): Fold; - addFolds(folds: Fold[]): void; - removeFold(fold: Fold): void; - removeFolds(folds: Fold[]): void; - expandFold(fold: Fold): void; - expandFolds(folds: Fold[]): void; - unfold(location: null | number | Point | Range, - expandInner?: boolean): Fold[] | undefined; - isRowFolded(docRow: number, startFoldRow?: FoldLine): boolean; - getFoldRowEnd(docRow: number, startFoldRow?: FoldLine): number; - getFoldRowStart(docRow: number, startFoldRow?: FoldLine): number; - getFoldDisplayLine(foldLine: FoldLine, - endRow: number | null, - endColumn: number | null, - startRow: number | null, - startColumn: number | null): string; - getDisplayLine(row: number, - endColumn: number | null, - startRow: number | null, - startColumn: number | null): string; - toggleFold(tryToUnfold?: boolean): void; - getCommentFoldRange(row: number, - column: number, - dir: number): Range | undefined; - foldAll(startRow?: number, endRow?: number, depth?: number): void; - setFoldStyle(style: string): void; - getParentFoldRangeData(row: number, ignoreCurrent?: boolean): { - range?: Range, - firstRange: Range - }; - toggleFoldWidget(toggleParent?: boolean): void; - updateFoldWidgets(delta: Delta): void; - } - - export interface Range { - start: Point; - end: Point; - - isEqual(range: Range): boolean; - toString(): string; - contains(row: number, column: number): boolean; - compareRange(range: Range): number; - comparePoint(p: Point): number; - containsRange(range: Range): boolean; - intersects(range: Range): boolean; - isEnd(row: number, column: number): boolean; - isStart(row: number, column: number): boolean; - setStart(row: number, column: number): void; - setEnd(row: number, column: number): void; - inside(row: number, column: number): boolean; - insideStart(row: number, column: number): boolean; - insideEnd(row: number, column: number): boolean; - compare(row: number, column: number): number; - compareStart(row: number, column: number): number; - compareEnd(row: number, column: number): number; - compareInside(row: number, column: number): number; - clipRows(firstRow: number, lastRow: number): Range; - extend(row: number, column: number): Range; - isEmpty(): boolean; - isMultiLine(): boolean; - clone(): Range; - collapseRows(): Range; - toScreenRange(session: EditSession): Range; - moveBy(row: number, column: number): void; - } - - export interface EditSessionOptions { - wrap: "off" | "free" | "printmargin" | boolean | number; - wrapMethod: 'code' | 'text' | 'auto'; - indentedSoftWrap: boolean; - firstLineNumber: number; - useWorker: boolean; - useSoftTabs: boolean; - tabSize: number; - navigateWithinSoftTabs: boolean; - foldStyle: 'markbegin' | 'markbeginend' | 'manual'; - overwrite: boolean; - newLineMode: NewLineMode; - mode: string; - } - - export interface VirtualRendererOptions { - animatedScroll: boolean; - showInvisibles: boolean; - showPrintMargin: boolean; - printMarginColumn: number; - printMargin: boolean | number; - showGutter: boolean; - fadeFoldWidgets: boolean; - showFoldWidgets: boolean; - showLineNumbers: boolean; - displayIndentGuides: boolean; - highlightIndentGuides: boolean; - highlightGutterLine: boolean; - hScrollBarAlwaysVisible: boolean; - vScrollBarAlwaysVisible: boolean; - fontSize: number; - fontFamily: string; - maxLines: number; - minLines: number; - scrollPastEnd: number; - fixedWidthGutter: boolean; - customScrollbar: boolean; - theme: string; - hasCssTransforms: boolean; - maxPixelHeight: number; - useSvgGutterIcons: boolean; - showFoldedAnnotations: boolean; - } - - export interface MouseHandlerOptions { - scrollSpeed: number; - dragDelay: number; - dragEnabled: boolean; - focusTimeout: number; - tooltipFollowsMouse: boolean; - } - - export interface EditorOptions extends EditSessionOptions, - MouseHandlerOptions, - VirtualRendererOptions { - selectionStyle: string; - highlightActiveLine: boolean; - highlightSelectedWord: boolean; - readOnly: boolean; - copyWithEmptySelection: boolean; - cursorStyle: 'ace' | 'slim' | 'smooth' | 'wide'; - mergeUndoDeltas: true | false | 'always'; - behavioursEnabled: boolean; - wrapBehavioursEnabled: boolean; - enableAutoIndent: boolean; - enableBasicAutocompletion: boolean | Completer[]; - enableLiveAutocompletion: boolean | Completer[]; - liveAutocompletionDelay: number; - liveAutocompletionThreshold: number; - enableSnippets: boolean; - autoScrollEditorIntoView: boolean; - keyboardHandler: string | null; - placeholder: string; - value: string; - session: EditSession; - relativeLineNumbers: boolean; - enableMultiselect: boolean; - enableKeyboardAccessibility: boolean; - textInputAriaLabel: string; - enableMobileMenu: boolean; - } - - export interface SearchOptions { - needle: string | RegExp; - preventScroll: boolean; - backwards: boolean; - start: Range; - skipCurrent: boolean; - range: Range; - preserveCase: boolean; - regExp: boolean; - wholeWord: boolean; - caseSensitive: boolean; - wrap: boolean; - } - - export interface EventEmitter { - once(name: string, callback: Function): void; - setDefaultHandler(name: string, callback: Function): void; - removeDefaultHandler(name: string, callback: Function): void; - on(name: string, callback: Function, capturing?: boolean): void; - addEventListener(name: string, callback: Function, capturing?: boolean): void; - off(name: string, callback: Function): void; - removeListener(name: string, callback: Function): void; - removeEventListener(name: string, callback: Function): void; - removeAllListeners(name?: string): void; - } - - export interface Point { - row: number; - column: number; - } - - export interface Delta { - action: 'insert' | 'remove'; - start: Point; - end: Point; - lines: string[]; - } - - export interface Annotation { - row?: number; - column?: number; - text: string; - type: string; - } - - export interface MarkerGroupItem { - range: Range; - className: string; - } - - export class MarkerGroup { - constructor(session: EditSession, options?: {markerType?: "fullLine" | "line"}); - setMarkers(markers: MarkerGroupItem[]): void; - getMarkerAtPosition(pos: Position): MarkerGroupItem | undefined; - } - - - export interface Command { - name?: string; - bindKey?: string | { mac?: string, win?: string }; - readOnly?: boolean; - exec: (editor: Editor, args?: any) => void; - } - - export type CommandLike = Command | ((editor: Editor) => void); - - export interface KeyboardHandler { - handleKeyboard: Function; - } - - export interface MarkerLike { - range?: Range; - type: string; - renderer?: MarkerRenderer; - clazz: string; - inFront: boolean; - id: number; - update?: (html: string[], - // TODO maybe define Marker class - marker: any, - session: EditSession, - config: any) => void; - } - - export type MarkerRenderer = (html: string[], - range: Range, - left: number, - top: number, - config: any) => void; - - export interface Token { - type: string; - value: string; - index?: number; - start?: number; - } - - interface BaseCompletion { - score?: number; - meta?: string; - caption?: string; - docHTML?: string; - docText?: string; - completerId?: string; - } - - export interface SnippetCompletion extends BaseCompletion { - snippet: string; - } - - export interface ValueCompletion extends BaseCompletion { - value: string; - } - - export type Completion = SnippetCompletion | ValueCompletion - - export interface Tokenizer { - removeCapturingGroups(src: string): string; - createSplitterRegexp(src: string, flag?: string): RegExp; - getLineTokens(line: string, startState: string | string[]): Token[]; - } - - interface TokenIterator { - getCurrentToken(): Token; - getCurrentTokenColumn(): number; - getCurrentTokenRow(): number; - getCurrentTokenPosition(): Point; - getCurrentTokenRange(): Range; - stepBackward(): Token; - stepForward(): Token; - } - - export type HighlightRule = {defaultToken: string} | {include: string} | {todo: string} | { - token: string | string[] | ((value: string) => string); - regex: string | RegExp; - next?: string; - push?: string; - comment?: string; - caseInsensitive?: boolean; - } - - export type HighlightRulesMap = Record; - - export type KeywordMapper = (keyword: string) => string; - - export interface HighlightRules { - addRules(rules: HighlightRulesMap, prefix?: string): void; - getRules(): HighlightRulesMap; - embedRules(rules: (new () => HighlightRules) | HighlightRulesMap, prefix: string, escapeRules?: boolean, append?: boolean): void; - getEmbeds(): string[]; - normalizeRules(): void; - createKeywordMapper(map: Record, defaultToken?: string, ignoreCase?: boolean, splitChar?: string): KeywordMapper; - } - - export interface FoldMode { - foldingStartMarker: RegExp; - foldingStopMarker?: RegExp; - getFoldWidget(session: EditSession, foldStyle: string, row: number): string; - getFoldWidgetRange(session: EditSession, foldStyle: string, row: number, forceMultiline?: boolean): Range | undefined; - indentationBlock(session: EditSession, row: number, column?: number): Range | undefined; - openingBracketBlock(session: EditSession, bracket: string, row: number, column: number, typeRe?: RegExp): Range | undefined; - closingBracketBlock(session: EditSession, bracket: string, row: number, column: number, typeRe?: RegExp): Range | undefined; - } - - type BehaviorAction = (state: string, action: string, editor: Editor, session: EditSession, text: string) => {text: string, selection: number[]} | Range | undefined; - type BehaviorMap = Record>; - - export interface Behaviour { - add(name: string, action: string, callback: BehaviorAction): void; - addBehaviours(behaviours: BehaviorMap): void; - remove(name: string): void; - inherit(mode: SyntaxMode | (new () => SyntaxMode), filter: string[]): void; - getBehaviours(filter: string[]): BehaviorMap; - } - - export interface Outdent { - checkOutdent(line: string, input: string): boolean; - autoOutdent(doc: Document, row: number): number | undefined; - } - - export interface SyntaxMode { - HighlightRules: new () => HighlightRules; - foldingRules?: FoldMode; - $behaviour?: Behaviour; - $defaultBehaviour?: Behaviour; - lineCommentStart?: string; - getTokenizer(): Tokenizer; - toggleCommentLines(state: any, - session: EditSession, - startRow: number, - endRow: number): void; - toggleBlockComment(state: any, - session: EditSession, - range: Range, - cursor: Point): void; - getNextLineIndent(state: any, line: string, tab: string): string; - checkOutdent(state: any, line: string, input: string): boolean; - autoOutdent(state: any, doc: Document, row: number): void; - // TODO implement WorkerClient types - createWorker(session: EditSession): any; - createModeDelegates(mapping: { [key: string]: string }): void; - transformAction: BehaviorAction; - getKeywords(append?: boolean): Array; - getCompletions(state: string, - session: EditSession, - pos: Point, - prefix: string): Completion[]; - } - - type AfterLoadCallback = (err: Error | null, module: unknown) => void; - type LoaderFunction = (moduleName: string, afterLoad: AfterLoadCallback) => void; - - export interface Config { - get(key: string): any; - set(key: string, value: any): void; - all(): { [key: string]: any }; - moduleUrl(name: string, component?: string): string; - setModuleUrl(name: string, subst: string): string; - setLoader(cb: LoaderFunction): void; - setModuleLoader(name: string, onLoad: Function): void; - loadModule(moduleName: string | [string, string], - onLoad?: (module: any) => void): void; - init(packaged: any): any; - defineOptions(obj: any, path: string, options: { [key: string]: any }): Config; - resetOptions(obj: any): void; - setDefaultValue(path: string, name: string, value: any): void; - setDefaultValues(path: string, optionHash: { [key: string]: any }): void; - } - - export interface OptionsProvider { - setOptions(optList: { [key: string]: any }): void; - getOptions(optionNames?: string[] | { [key: string]: any }): { [key: string]: any }; - setOption(name: string, value: any): void; - getOption(name: string): any; - } - - export interface UndoManager { - addSession(session: EditSession): void; - add(delta: Delta, allowMerge: boolean, session: EditSession): void; - addSelection(selection: string, rev?: number): void; - startNewGroup(): void; - markIgnored(from: number, to?: number): void; - getSelection(rev: number, after?: boolean): { value: string, rev: number }; - getRevision(): number; - getDeltas(from: number, to?: number): Delta[]; - undo(session: EditSession, dontSelect?: boolean): void; - redo(session: EditSession, dontSelect?: boolean): void; - reset(): void; - canUndo(): boolean; - canRedo(): boolean; - bookmark(rev?: number): void; - isAtBookmark(): boolean; - hasUndo(): boolean; - hasRedo(): boolean; - isClean(): boolean; - markClean(rev?: number): void; - toJSON(): object; - fromJSON(json: object): void; - } +/* This file is generated using `npm run update-types` */ - export interface Position { - row: number, - column: number - } - - export interface EditSession extends EventEmitter, OptionsProvider, Folding { - selection: Selection; - curOp?: { - docChanged?: boolean; - selectionChanged?: boolean; - command?: { - name?: string; - }; - }; - widgetManager:WidgetManager; - // TODO: define BackgroundTokenizer - - on(name: 'changeFold', - callback: (obj: { data: Fold, action: string }) => void): Function; - on(name: 'changeScrollLeft', callback: (scrollLeft: number) => void): Function; - on(name: 'changeScrollTop', callback: (scrollTop: number) => void): Function; - on(name: 'tokenizerUpdate', - callback: (obj: { data: { first: number, last: number } }) => void): Function; - on(name: 'change', callback: () => void): Function; - on(name: 'changeTabSize', callback: () => void): Function; - on(name: "beforeEndOperation", callback: () => void): Function; - - setOption(name: T, value: EditSessionOptions[T]): void; - getOption(name: T): EditSessionOptions[T]; - - readonly doc: Document; - - setDocument(doc: Document): void; - getDocument(): Document; - resetCaches(): void; - setValue(text: string): void; - getValue(): string; - getSelection(): Selection; - getState(row: number): string; - getTokens(row: number): Token[]; - getTokenAt(row: number, column: number): Token | null; - setUndoManager(undoManager: UndoManager): void; - markUndoGroup(): void; - getUndoManager(): UndoManager; - getTabString(): string; - setUseSoftTabs(val: boolean): void; - getUseSoftTabs(): boolean; - setTabSize(tabSize: number): void; - getTabSize(): number; - isTabStop(position: Position): boolean; - setNavigateWithinSoftTabs(navigateWithinSoftTabs: boolean): void; - getNavigateWithinSoftTabs(): boolean; - setOverwrite(overwrite: boolean): void; - getOverwrite(): boolean; - toggleOverwrite(): void; - addGutterDecoration(row: number, className: string): void; - removeGutterDecoration(row: number, className: string): void; - getBreakpoints(): string[]; - setBreakpoints(rows: number[]): void; - clearBreakpoints(): void; - setBreakpoint(row: number, className: string): void; - clearBreakpoint(row: number): void; - addMarker(range: Range, - className: string, - type: "fullLine" | "screenLine" | "text" | MarkerRenderer, - inFront?: boolean): number; - addDynamicMarker(marker: MarkerLike, inFront: boolean): MarkerLike; - removeMarker(markerId: number): void; - getMarkers(inFront?: boolean): {[id: number]: MarkerLike}; - highlight(re: RegExp): void; - highlightLines(startRow: number, - endRow: number, - className: string, - inFront?: boolean): Range; - setAnnotations(annotations: Annotation[]): void; - getAnnotations(): Annotation[]; - clearAnnotations(): void; - getWordRange(row: number, column: number): Range; - getAWordRange(row: number, column: number): Range; - setNewLineMode(newLineMode: NewLineMode): void; - getNewLineMode(): NewLineMode; - setUseWorker(useWorker: boolean): void; - getUseWorker(): boolean; - setMode(mode: string | SyntaxMode, callback?: () => void): void; - getMode(): SyntaxMode; - setScrollTop(scrollTop: number): void; - getScrollTop(): number; - setScrollLeft(scrollLeft: number): void; - getScrollLeft(): number; - getScreenWidth(): number; - getLineWidgetMaxWidth(): number; - getLine(row: number): string; - getLines(firstRow: number, lastRow: number): string[]; - getLength(): number; - getTextRange(range: Range): string; - insert(position: Position, text: string): void; - remove(range: Range): void; - removeFullLines(firstRow: number, lastRow: number): void; - undoChanges(deltas: Delta[], dontSelect?: boolean): void; - redoChanges(deltas: Delta[], dontSelect?: boolean): void; - setUndoSelect(enable: boolean): void; - replace(range: Range, text: string): void; - moveText(fromRange: Range, toPosition: Position, copy?: boolean): void; - indentRows(startRow: number, endRow: number, indentString: string): void; - outdentRows(range: Range): void; - moveLinesUp(firstRow: number, lastRow: number): void; - moveLinesDown(firstRow: number, lastRow: number): void; - duplicateLines(firstRow: number, lastRow: number): void; - setUseWrapMode(useWrapMode: boolean): void; - getUseWrapMode(): boolean; - setWrapLimitRange(min: number, max: number): void; - adjustWrapLimit(desiredLimit: number): boolean; - getWrapLimit(): number; - setWrapLimit(limit: number): void; - getWrapLimitRange(): { min: number, max: number }; - getRowLineCount(row: number): number; - getRowWrapIndent(screenRow: number): number; - getScreenLastRowColumn(screenRow: number): number; - getDocumentLastRowColumn(docRow: number, docColumn: number): number; - getdocumentLastRowColumnPosition(docRow: number, docColumn: number): Position; - getRowSplitData(row: number): string | undefined; - getScreenTabSize(screenColumn: number): number; - screenToDocumentRow(screenRow: number, screenColumn: number): number; - screenToDocumentColumn(screenRow: number, screenColumn: number): number; - screenToDocumentPosition(screenRow: number, - screenColumn: number, - offsetX?: number): Position; - documentToScreenPosition(docRow: number, docColumn: number): Position; - documentToScreenPosition(position: Position): Position; - documentToScreenColumn(row: number, docColumn: number): number; - documentToScreenRow(docRow: number, docColumn: number): number; - getScreenLength(): number; - getPrecedingCharacter(): string; - startOperation(commandEvent: {command: {name: string}}): void; - endOperation(): void; - toJSON(): Object; - destroy(): void; - } - - export interface KeyBinding { - setDefaultHandler(handler: KeyboardHandler): void; - setKeyboardHandler(handler: KeyboardHandler): void; - addKeyboardHandler(handler: KeyboardHandler, pos?: number): void; - removeKeyboardHandler(handler: KeyboardHandler): boolean; - getKeyboardHandler(): KeyboardHandler; - getStatusText(): string; - onCommandKey(e: any, hashId: number, keyCode: number): boolean; - onTextInput(text: string): boolean; - } - - interface CommandMap { - [name: string]: Command; - } - - type execEventHandler = (obj: { - editor: Editor, - command: Command, - args: any[] - }) => void; - - export interface CommandManager extends EventEmitter { - byName: CommandMap, - commands: CommandMap, - on(name: 'exec', callback: execEventHandler): Function; - on(name: 'afterExec', callback: execEventHandler): Function; - once(name: string, callback: Function): void; - setDefaultHandler(name: string, callback: Function): void; - removeDefaultHandler(name: string, callback: Function): void; - on(name: string, callback: Function, capturing?: boolean): void; - addEventListener(name: string, callback: Function, capturing?: boolean): void; - off(name: string, callback: Function): void; - removeListener(name: string, callback: Function): void; - removeEventListener(name: string, callback: Function): void; - - exec(command: string | string[] | Command, editor: Editor, args: any): boolean; - canExecute(command: string | Command, editor: Editor): boolean; - toggleRecording(editor: Editor): void; - replay(editor: Editor): void; - addCommand(command: Command): void; - addCommands(command: Command[]): void; - removeCommand(command: Command | string, keepCommand?: boolean): void; - removeCommands(command: Command[]): void; - bindKey(key: string | { mac?: string, win?: string}, - command: CommandLike, - position?: number): void; - bindKeys(keys: {[s: string]: Function}): void; - parseKeys(keyPart: string): {key: string, hashId: number}; - findKeyCommand(hashId: number, keyString: string): string | undefined; - handleKeyboard(data: {}, hashId: number, keyString: string, keyCode: string | number): void | {command: string}; - getStatusText(editor: Editor, data: {}): string; - } - - export interface VirtualRenderer extends OptionsProvider, EventEmitter { - readonly container: HTMLElement; - readonly scroller: HTMLElement; - readonly content: HTMLElement; - readonly characterWidth: number; - readonly lineHeight: number; - readonly scrollLeft: number; - readonly scrollTop: number; - readonly $padding: number; - - setOption(name: T, value: VirtualRendererOptions[T]): void; - getOption(name: T): VirtualRendererOptions[T]; - - setSession(session: EditSession): void; - updateLines(firstRow: number, lastRow: number, force?: boolean): void; - updateText(): void; - updateFull(force?: boolean): void; - updateFontSize(): void; - adjustWrapLimit(): boolean; - setAnimatedScroll(shouldAnimate: boolean): void; - getAnimatedScroll(): boolean; - setShowInvisibles(showInvisibles: boolean): void; - getShowInvisibles(): boolean; - setDisplayIndentGuides(display: boolean): void; - getDisplayIndentGuides(): boolean; - setShowPrintMargin(showPrintMargin: boolean): void; - getShowPrintMargin(): boolean; - setPrintMarginColumn(showPrintMargin: boolean): void; - getPrintMarginColumn(): boolean; - setShowGutter(show: boolean): void; - getShowGutter(): boolean; - setFadeFoldWidgets(show: boolean): void; - getFadeFoldWidgets(): boolean; - setHighlightGutterLine(shouldHighlight: boolean): void; - getHighlightGutterLine(): boolean; - getContainerElement(): HTMLElement; - getMouseEventTarget(): HTMLElement; - getTextAreaContainer(): HTMLElement; - getFirstVisibleRow(): number; - getFirstFullyVisibleRow(): number; - getLastFullyVisibleRow(): number; - getLastVisibleRow(): number; - setPadding(padding: number): void; - setScrollMargin(top: number, - bottom: number, - left: number, - right: number): void; - setHScrollBarAlwaysVisible(alwaysVisible: boolean): void; - getHScrollBarAlwaysVisible(): boolean; - setVScrollBarAlwaysVisible(alwaysVisible: boolean): void; - getVScrollBarAlwaysVisible(): boolean; - freeze(): void; - unfreeze(): void; - updateFrontMarkers(): void; - updateBackMarkers(): void; - updateBreakpoints(): void; - setAnnotations(annotations: Annotation[]): void; - updateCursor(): void; - hideCursor(): void; - showCursor(): void; - scrollSelectionIntoView(anchor: Position, - lead: Position, - offset?: number): void; - scrollCursorIntoView(cursor: Position, offset?: number): void; - getScrollTop(): number; - getScrollLeft(): number; - getScrollTopRow(): number; - getScrollBottomRow(): number; - scrollToRow(row: number): void; - alignCursor(cursor: Position | number, alignment: number): number; - scrollToLine(line: number, - center: boolean, - animate: boolean, - callback: () => void): void; - animateScrolling(fromValue: number, callback: () => void): void; - scrollToY(scrollTop: number): void; - scrollToX(scrollLeft: number): void; - scrollTo(x: number, y: number): void; - scrollBy(deltaX: number, deltaY: number): void; - isScrollableBy(deltaX: number, deltaY: number): boolean; - textToScreenCoordinates(row: number, column: number): { pageX: number, pageY: number}; - pixelToScreenCoordinates(x: number, y: number): {row: number, column: number, side: 1|-1, offsetX: number}; - visualizeFocus(): void; - visualizeBlur(): void; - showComposition(position: number): void; - setCompositionText(text: string): void; - hideComposition(): void; - setGhostText(text: string, position: Point): void; - removeGhostText(): void; - setTheme(theme: string, callback?: () => void): void; - getTheme(): string; - setStyle(style: string, include?: boolean): void; - unsetStyle(style: string): void; - setCursorStyle(style: string): void; - setMouseCursor(cursorStyle: string): void; - attachToShadowRoot(): void; - destroy(): void; - } - - - export interface Selection extends EventEmitter { - moveCursorWordLeft(): void; - moveCursorWordRight(): void; - fromOrientedRange(range: Range): void; - setSelectionRange(match: any): void; - getAllRanges(): Range[]; - addRange(range: Range): void; - isEmpty(): boolean; - isMultiLine(): boolean; - setCursor(row: number, column: number): void; - setAnchor(row: number, column: number): void; - getAnchor(): Position; - getCursor(): Position; - isBackwards(): boolean; - getRange(): Range; - clearSelection(): void; - selectAll(): void; - setRange(range: Range, reverse?: boolean): void; - selectTo(row: number, column: number): void; - selectToPosition(pos: any): void; - selectUp(): void; - selectDown(): void; - selectRight(): void; - selectLeft(): void; - selectLineStart(): void; - selectLineEnd(): void; - selectFileEnd(): void; - selectFileStart(): void; - selectWordRight(): void; - selectWordLeft(): void; - getWordRange(): void; - selectWord(): void; - selectAWord(): void; - selectLine(): void; - moveCursorUp(): void; - moveCursorDown(): void; - moveCursorLeft(): void; - moveCursorRight(): void; - moveCursorLineStart(): void; - moveCursorLineEnd(): void; - moveCursorFileEnd(): void; - moveCursorFileStart(): void; - moveCursorLongWordRight(): void; - moveCursorLongWordLeft(): void; - moveCursorBy(rows: number, chars: number): void; - moveCursorToPosition(position: any): void; - moveCursorTo(row: number, column: number, keepDesiredColumn?: boolean): void; - moveCursorToScreen(row: number, column: number, keepDesiredColumn: boolean): void; - - toJSON(): SavedSelection | SavedSelection[]; - fromJSON(selection: SavedSelection | SavedSelection[]): void; - } - interface SavedSelection { - start: Point; - end: Point; - isBackwards: boolean; - } - - var Selection: { - new(session: EditSession): Selection; - } - - export interface TextInput { - resetSelection(): void; - setAriaOption(activeDescendant: string, role: string): void; - } - - export interface Editor extends OptionsProvider, EventEmitter { - container: HTMLElement; - renderer: VirtualRenderer; - id: string; - commands: CommandManager; - keyBinding: KeyBinding; - session: EditSession; - selection: Selection; - textInput: TextInput; - - on(name: 'blur', callback: (e: Event) => void): void; - on(name: 'input', callback: () => void): void; - on(name: 'change', callback: (delta: Delta) => void): void; - on(name: 'changeSelectionStyle', callback: (obj: { data: string }) => void): void; - on(name: 'changeSession', - callback: (obj: { session: EditSession, oldSession: EditSession }) => void): void; - on(name: 'copy', callback: (obj: { text: string }) => void): void; - on(name: 'focus', callback: (e: Event) => void): void; - on(name: 'paste', callback: (obj: { text: string }) => void): void; - on(name: 'mousemove', callback: (e: any) => void): void; - on(name: 'mouseup', callback: (e: any) => void): void; - on(name: 'mousewheel', callback: (e: any) => void): void; - on(name: 'click', callback: (e: any) => void): void; - on(name: 'guttermousedown', callback: (e: any) => void): void; - on(name: 'gutterkeydown', callback: (e: any) => void): void; - - onPaste(text: string, event: any): void; - - setOption(name: T, value: EditorOptions[T]): void; - getOption(name: T): EditorOptions[T]; - - setKeyboardHandler(keyboardHandler: string, callback?: () => void): void; - setKeyboardHandler(keyboardHandler: KeyboardHandler|null): void; - getKeyboardHandler(): string; - setSession(session: EditSession | undefined): void; - getSession(): EditSession; - setValue(val: string, cursorPos?: number): string; - getValue(): string; - getSelection(): Selection; - resize(force?: boolean): void; - setTheme(theme: string, callback?: () => void): void; - getTheme(): string; - setStyle(style: string): void; - unsetStyle(style: string): void; - getFontSize(): string; - setFontSize(size: number|string): void; - focus(): void; - isFocused(): boolean; - blur(): void; - getSelectedText(): string; - getCopyText(): string; - execCommand(command: string | string[], args?: any): boolean; - insert(text: string, pasted?: boolean): void; - setOverwrite(overwrite: boolean): void; - getOverwrite(): boolean; - toggleOverwrite(): void; - setScrollSpeed(speed: number): void; - getScrollSpeed(): number; - setDragDelay(dragDelay: number): void; - getDragDelay(): number; - setSelectionStyle(val: string): void; - getSelectionStyle(): string; - setHighlightActiveLine(shouldHighlight: boolean): void; - getHighlightActiveLine(): boolean; - setHighlightGutterLine(shouldHighlight: boolean): void; - getHighlightGutterLine(): boolean; - setHighlightSelectedWord(shouldHighlight: boolean): void; - getHighlightSelectedWord(): boolean; - setAnimatedScroll(shouldAnimate: boolean): void; - getAnimatedScroll(): boolean; - setShowInvisibles(showInvisibles: boolean): void; - getShowInvisibles(): boolean; - setDisplayIndentGuides(display: boolean): void; - getDisplayIndentGuides(): boolean; - setShowPrintMargin(showPrintMargin: boolean): void; - getShowPrintMargin(): boolean; - setPrintMarginColumn(showPrintMargin: number): void; - getPrintMarginColumn(): number; - setReadOnly(readOnly: boolean): void; - getReadOnly(): boolean; - setBehavioursEnabled(enabled: boolean): void; - getBehavioursEnabled(): boolean; - setWrapBehavioursEnabled(enabled: boolean): void; - getWrapBehavioursEnabled(): boolean; - setShowFoldWidgets(show: boolean): void; - getShowFoldWidgets(): boolean; - setFadeFoldWidgets(fade: boolean): void; - getFadeFoldWidgets(): boolean; - remove(dir?: 'left' | 'right'): void; - removeWordRight(): void; - removeWordLeft(): void; - removeLineToEnd(): void; - splitLine(): void; - setGhostText(text: string, position: Point): void; - removeGhostText(): void; - transposeLetters(): void; - toLowerCase(): void; - toUpperCase(): void; - indent(): void; - blockIndent(): void; - blockOutdent(): void; - sortLines(): void; - toggleCommentLines(): void; - toggleBlockComment(): void; - modifyNumber(amount: number): void; - removeLines(): void; - duplicateSelection(): void; - moveLinesDown(): void; - moveLinesUp(): void; - moveText(range: Range, toPosition: Point, copy?: boolean): Range; - copyLinesUp(): void; - copyLinesDown(): void; - getFirstVisibleRow(): number; - getLastVisibleRow(): number; - isRowVisible(row: number): boolean; - isRowFullyVisible(row: number): boolean; - selectPageDown(): void; - selectPageUp(): void; - gotoPageDown(): void; - gotoPageUp(): void; - scrollPageDown(): void; - scrollPageUp(): void; - scrollToRow(row: number): void; - scrollToLine(line: number, center: boolean, animate: boolean, callback: () => void): void; - centerSelection(): void; - getCursorPosition(): Point; - getCursorPositionScreen(): Point; - getSelectionRange(): Range; - selectAll(): void; - clearSelection(): void; - moveCursorTo(row: number, column: number): void; - moveCursorToPosition(pos: Point): void; - jumpToMatching(select: boolean, expand: boolean): void; - gotoLine(lineNumber: number, column: number, animate: boolean): void; - navigateTo(row: number, column: number): void; - navigateUp(times?: number): void; - navigateDown(times?: number): void; - navigateLeft(times?: number): void; - navigateRight(times?: number): void; - navigateLineStart(): void; - navigateLineEnd(): void; - navigateFileEnd(): void; - navigateFileStart(): void; - navigateWordRight(): void; - navigateWordLeft(): void; - replace(replacement: string, options?: Partial): number; - replaceAll(replacement: string, options?: Partial): number; - getLastSearchOptions(): Partial; - find(needle: string | RegExp, options?: Partial, animate?: boolean): Ace.Range | undefined; - findNext(options?: Partial, animate?: boolean): void; - findPrevious(options?: Partial, animate?: boolean): void; - findAll(needle: string | RegExp, options?: Partial, additive?: boolean): number; - undo(): void; - redo(): void; - destroy(): void; - setAutoScrollEditorIntoView(enable: boolean): void; - completers: Completer[]; - } - - type CompleterCallback = (error: any, completions: Completion[]) => void; - - interface Completer { - identifierRegexps?: Array, - getCompletions(editor: Editor, - session: EditSession, - position: Point, - prefix: string, - callback: CompleterCallback): void; - getDocTooltip?(item: Completion): undefined | string | Completion; - onSeen?: (editor: Ace.Editor, completion: Completion) => void; - onInsert?: (editor: Ace.Editor, completion: Completion) => void; - cancel?(): void; - id?: string; - triggerCharacters?: string[]; - hideInlinePreview?: boolean; - } - - export class AceInline { - show(editor: Editor, completion: Completion, prefix: string): void; - isOpen(): void; - hide(): void; - destroy(): void; - } - - interface CompletionOptions { - matches?: Completion[]; - } - - type CompletionProviderOptions = { - exactMatch?: boolean; - ignoreCaption?: boolean; - } - - type CompletionRecord = { - all: Completion[]; - filtered: Completion[]; - filterText: string; - } | CompletionProviderOptions - - type GatherCompletionRecord = { - prefix: string; - matches: Completion[]; - finished: boolean; - } - - type CompletionCallbackFunction = (err: Error | undefined, data: GatherCompletionRecord) => void; - type CompletionProviderCallback = (err: Error | undefined, completions: CompletionRecord, finished: boolean) => void; - - export class CompletionProvider { - insertByIndex(editor: Editor, index: number, options: CompletionProviderOptions): boolean; - insertMatch(editor: Editor, data: Completion, options: CompletionProviderOptions): boolean; - completions: CompletionRecord; - gatherCompletions(editor: Editor, callback: CompletionCallbackFunction): boolean; - provideCompletions(editor: Editor, options: CompletionProviderOptions, callback: CompletionProviderCallback): void; - detach(): void; - } - - export class Autocomplete { - constructor(); - autoInsert?: boolean; - autoSelect?: boolean; - autoShown?: boolean; - exactMatch?: boolean; - inlineEnabled?: boolean; - parentNode?: HTMLElement; - setSelectOnHover?: Boolean; - stickySelectionDelay?: Number; - ignoreCaption?: Boolean; - showLoadingState?: Boolean; - emptyMessage?(prefix: String): String; - getPopup(): AcePopup; - showPopup(editor: Editor, options: CompletionOptions): void; - detach(): void; - destroy(): void; - } - - type AcePopupNavigation = "up" | "down" | "start" | "end"; - - export class AcePopup { - constructor(parentNode: HTMLElement); - setData(list: Completion[], filterText: string): void; - getData(row: number): Completion; - getRow(): number; - getRow(line: number): void; - hide(): void; - show(pos: Point, lineHeight: number, topdownOnly: boolean): void; - tryShow(pos: Point, lineHeight: number, anchor: "top" | "bottom" | undefined, forceShow?: boolean): boolean; - goTo(where: AcePopupNavigation): void; - } - - export interface LineWidget { - el: HTMLElement; - row: number; - rowCount?: number; - hidden?: boolean; - editor?: Editor; - session?: EditSession; - column?: number; - className?: string; - coverGutter?: boolean; - pixelHeight?: number; - fixedWidth?: boolean; - fullWidth?: boolean; - screenWidth?: number; - } - - export class WidgetManager { - constructor(session: EditSession); - addLineWidget(w: LineWidget): LineWidget; - removeLineWidget(w: LineWidget): void; - } -} - - -export const version: string; -export const config: Ace.Config; -export function require(name: string): any; -export function edit(el: Element | string, options?: Partial): Ace.Editor; -export function createEditSession(text: Ace.Document | string, mode: Ace.SyntaxMode): Ace.EditSession; -export const VirtualRenderer: { - new(container: HTMLElement, theme?: string): Ace.VirtualRenderer; -}; -export const EditSession: { - new(text: string | Ace.Document, mode?: Ace.SyntaxMode): Ace.EditSession; -}; -export const UndoManager: { - new(): Ace.UndoManager; -}; -export const Editor: { - new(): Ace.Editor; -}; -export const Range: { - new(startRow: number, startColumn: number, endRow: number, endColumn: number): Ace.Range; - fromPoints(start: Ace.Point, end: Ace.Point): Ace.Range; - comparePoints(p1: Ace.Point, p2: Ace.Point): number; -}; - - -type InlineAutocompleteAction = "prev" | "next" | "first" | "last"; - -type TooltipCommandFunction = (editor: Ace.Editor) => T; - -interface TooltipCommand extends Ace.Command { - enabled: TooltipCommandFunction | boolean, - getValue?: TooltipCommandFunction, - type: "button" | "text" | "checkbox" - iconCssClass: string, - cssClass: string -} - -export class InlineAutocomplete { - constructor(); - getInlineRenderer(): Ace.AceInline; - getInlineTooltip(): CommandBarTooltip; - getCompletionProvider(): Ace.CompletionProvider; - show(editor: Ace.Editor): void; - isOpen(): boolean; - detach(): void; - destroy(): void; - goTo(action: InlineAutocompleteAction): void; - tooltipEnabled: boolean; - commands: Record - getIndex(): number; - setIndex(value: number): void; - getLength(): number; - getData(index?: number): Ace.Completion | undefined; - updateCompletions(options: Ace.CompletionOptions): void; -} - -export class CommandBarTooltip { - constructor(parentElement: HTMLElement); - registerCommand(id: string, command: TooltipCommand): void; - attach(editor: Ace.Editor): void; - updatePosition(): void; - update(): void; - isShown(): boolean; - getAlwaysShow(): boolean; - setAlwaysShow(alwaysShow: boolean): void; - detach(): void; - destroy(): void; +/// +/// +/// +/// +/// +/// +declare module "ace-code" { + export namespace Ace { + type Anchor = import("ace-code/src/anchor").Anchor; + type Editor = import("ace-code/src/editor").Editor; + type EditSession = import("ace-code/src/edit_session").EditSession; + type Document = import("ace-code/src/document").Document; + type Fold = import("ace-code/src/edit_session/fold").Fold; + type FoldLine = import("ace-code/src/edit_session/fold_line").FoldLine; + type Range = import("ace-code/src/range").Range; + type VirtualRenderer = import("ace-code/src/virtual_renderer").VirtualRenderer; + type UndoManager = import("ace-code/src/undomanager").UndoManager; + type Tokenizer = import("ace-code/src/tokenizer").Tokenizer; + type TokenIterator = import("ace-code/src/token_iterator").TokenIterator; + type Selection = import("ace-code/src/selection").Selection; + type Autocomplete = import("ace-code/src/autocomplete").Autocomplete; + type InlineAutocomplete = import("ace-code/src/ext/inline_autocomplete").InlineAutocomplete; + type CompletionProvider = import("ace-code/src/autocomplete").CompletionProvider; + type AcePopup = import("ace-code/src/autocomplete/popup").AcePopup; + type AceInline = import("ace-code/src/autocomplete/inline").AceInline; + type MouseEvent = import("ace-code/src/mouse/mouse_event").MouseEvent; + type RangeList = import("ace-code/src/range_list").RangeList; + type FilteredList = import("ace-code/src/autocomplete").FilteredList; + type LineWidgets = import("ace-code/src/line_widgets").LineWidgets; + type SearchBox = import("ace-code/src/ext/searchbox").SearchBox; + type Occur = import("ace-code/src/occur").Occur; + type DefaultHandlers = import("ace-code/src/mouse/default_handlers").DefaultHandlers; + type GutterHandler = import("ace-code/src/mouse/default_gutter_handler").GutterHandler; + type DragdropHandler = import("ace-code/src/mouse/dragdrop_handler").DragdropHandler; + type AppConfig = import("ace-code/src/lib/app_config").AppConfig; + type Config = typeof import("ace-code/src/config"); + type AfterLoadCallback = (err: Error | null, module: unknown) => void; + type LoaderFunction = (moduleName: string, afterLoad: AfterLoadCallback) => void; + export interface ConfigOptions { + packaged: boolean; + workerPath: string | null; + modePath: string | null; + themePath: string | null; + basePath: string; + suffix: string; + loadWorkerFromBlob: boolean; + sharedPopups: boolean; + useStrictCSP: boolean | null; + } + interface Theme { + cssClass?: string; + cssText?: string; + padding?: number | string; + isDark?: boolean; + } + interface ScrollBar { + setVisible(visible: boolean): void; + [key: string]: any; + } + interface HScrollbar extends ScrollBar { + setWidth(width: number): void; + } + interface VScrollbar extends ScrollBar { + setHeight(width: number): void; + } + interface LayerConfig { + width: number; + padding: number; + firstRow: number; + firstRowScreen: number; + lastRow: number; + lineHeight: number; + characterWidth: number; + minHeight: number; + maxHeight: number; + offset: number; + height: number; + gutterOffset: number; + } + interface HardWrapOptions { + startRow: number; + endRow: number; + allowMerge?: boolean; + column?: number; + } + interface CommandBarOptions { + maxElementsOnTooltip: number; + alwaysShow: boolean; + showDelay: number; + hideDelay: number; + } + interface ScreenCoordinates { + row: number; + column: number; + side?: 1 | -1; + offsetX?: number; + } + interface Folding { + /** + * Looks up a fold at a given row/column. Possible values for side: + * -1: ignore a fold if fold.start = row/column + * +1: ignore a fold if fold.end = row/column + **/ + getFoldAt(row: number, column: number, side?: number): Ace.Fold; + /** + * Returns all folds in the given range. Note, that this will return folds + **/ + getFoldsInRange(range: Ace.Range | Ace.Delta): Ace.Fold[]; + getFoldsInRangeList(ranges: Ace.Range[] | Ace.Range): Ace.Fold[]; + /** + * Returns all folds in the document + */ + getAllFolds(): Ace.Fold[]; + /** + * Returns the string between folds at the given position. + * E.g. + * foob|arwolrd -> "bar" + * foobarwol|rd -> "world" + * foobarwolrd -> + * + * where | means the position of row/column + * + * The trim option determs if the return string should be trimed according + * to the "side" passed with the trim value: + * + * E.g. + * foob|arwolrd -trim=-1> "b" + * foobarwol|rd -trim=+1> "rld" + * fo|obarwolrd -trim=00> "foo" + */ + getFoldStringAt(row: number, column: number, trim?: number, foldLine?: Ace.FoldLine): string | null; + getFoldLine(docRow: number, startFoldLine?: Ace.FoldLine): null | Ace.FoldLine; + /** + * Returns the fold which starts after or contains docRow + */ + getNextFoldLine(docRow: number, startFoldLine?: Ace.FoldLine): null | Ace.FoldLine; + getFoldedRowCount(first: number, last: number): number; + /** + * Adds a new fold. + * The new created Fold object or an existing fold object in case the + * passed in range fits an existing fold exactly. + */ + addFold(placeholder: Ace.Fold | string, range?: Ace.Range): Ace.Fold; + addFolds(folds: Ace.Fold[]): void; + removeFold(fold: Ace.Fold): void; + removeFolds(folds: Ace.Fold[]): void; + expandFold(fold: Ace.Fold): void; + expandFolds(folds: Ace.Fold[]): void; + unfold(location?: number | null | Ace.Point | Ace.Range | Ace.Range[], expandInner?: boolean): Ace.Fold[] | undefined; + /** + * Checks if a given documentRow is folded. This is true if there are some + * folded parts such that some parts of the line is still visible. + **/ + isRowFolded(docRow: number, startFoldRow?: Ace.FoldLine): boolean; + getRowFoldEnd(docRow: number, startFoldRow?: Ace.FoldLine): number; + getRowFoldStart(docRow: number, startFoldRow?: Ace.FoldLine): number; + getFoldDisplayLine(foldLine: Ace.FoldLine, endRow?: number | null, endColumn?: number | null, startRow?: number | null, startColumn?: number | null): string; + getDisplayLine(row: number, endColumn: number | null, startRow: number | null, startColumn: number | null): string; + toggleFold(tryToUnfold?: boolean): void; + getCommentFoldRange(row: number, column: number, dir?: number): Ace.Range | undefined; + foldAll(startRow?: number | null, endRow?: number | null, depth?: number | null, test?: Function): void; + foldToLevel(level: number): void; + foldAllComments(): void; + setFoldStyle(style: string): void; + foldWidgets: any[]; + getFoldWidget: any; + getFoldWidgetRange: any; + getParentFoldRangeData(row: number, ignoreCurrent?: boolean): { + range?: Ace.Range; + firstRange?: Ace.Range; + }; + onFoldWidgetClick(row: number, e: any): void; + toggleFoldWidget(toggleParent?: boolean): void; + updateFoldWidgets(delta: Ace.Delta): void; + tokenizerUpdateFoldWidgets(e: any): void; + } + interface BracketMatch { + findMatchingBracket: (position: Point, chr?: string) => Point; + getBracketRange: (pos: Point) => null | Range; + /** + * Returns: + * * null if there is no any bracket at `pos`; + * * two Ranges if there is opening and closing brackets; + * * one Range if there is only one bracket + */ + getMatchingBracketRanges: (pos: Point, isBackwards?: boolean) => null | Range[]; + /** + * Returns [[Range]]'s for matching tags and tag names, if there are any + */ + getMatchingTags: (pos: Point) => { + closeTag: Range; + closeTagName: Range; + openTag: Range; + openTagName: Range; + }; + } + interface IRange { + start: Point; + end: Point; + } + interface LineWidget { + editor?: Editor; + el?: HTMLElement; + rowCount?: number; + hidden?: boolean; + column?: number; + row: number; + session?: EditSession; + html?: string; + text?: string; + className?: string; + coverGutter?: boolean; + pixelHeight?: number; + type?: any; + destroy?: () => void; + coverLine?: boolean; + fixedWidth?: boolean; + fullWidth?: boolean; + screenWidth?: number; + rowsAbove?: number; + lenses?: any[]; + } + type NewLineMode = "auto" | "unix" | "windows"; + interface EditSessionOptions { + wrap: "off" | "free" | "printmargin" | boolean | number; + wrapMethod: "code" | "text" | "auto"; + indentedSoftWrap: boolean; + firstLineNumber: number; + useWorker: boolean; + useSoftTabs: boolean; + tabSize: number; + navigateWithinSoftTabs: boolean; + foldStyle: "markbegin" | "markbeginend" | "manual"; + overwrite: boolean; + newLineMode: NewLineMode; + mode: string; + } + interface VirtualRendererOptions { + animatedScroll: boolean; + showInvisibles: boolean; + showPrintMargin: boolean; + printMarginColumn: number; + printMargin: boolean | number; + showGutter: boolean; + fadeFoldWidgets: boolean; + showFoldWidgets: boolean; + showLineNumbers: boolean; + displayIndentGuides: boolean; + highlightIndentGuides: boolean; + highlightGutterLine: boolean; + hScrollBarAlwaysVisible: boolean; + vScrollBarAlwaysVisible: boolean; + fontSize: string | number; + fontFamily: string; + maxLines: number; + minLines: number; + scrollPastEnd: number; + fixedWidthGutter: boolean; + customScrollbar: boolean; + theme: string; + hasCssTransforms: boolean; + maxPixelHeight: number; + useSvgGutterIcons: boolean; + showFoldedAnnotations: boolean; + useResizeObserver: boolean; + } + interface MouseHandlerOptions { + scrollSpeed: number; + dragDelay: number; + dragEnabled: boolean; + focusTimeout: number; + tooltipFollowsMouse: boolean; + } + interface EditorOptions extends EditSessionOptions, MouseHandlerOptions, VirtualRendererOptions { + selectionStyle: "fullLine" | "screenLine" | "text" | "line"; + highlightActiveLine: boolean; + highlightSelectedWord: boolean; + readOnly: boolean; + copyWithEmptySelection: boolean; + cursorStyle: "ace" | "slim" | "smooth" | "wide"; + mergeUndoDeltas: true | false | "always"; + behavioursEnabled: boolean; + wrapBehavioursEnabled: boolean; + enableAutoIndent: boolean; + enableBasicAutocompletion: boolean | Completer[]; + enableLiveAutocompletion: boolean | Completer[]; + liveAutocompletionDelay: number; + liveAutocompletionThreshold: number; + enableSnippets: boolean; + autoScrollEditorIntoView: boolean; + keyboardHandler: string | null; + placeholder: string; + value: string; + session: EditSession; + relativeLineNumbers: boolean; + enableMultiselect: boolean; + enableKeyboardAccessibility: boolean; + enableCodeLens: boolean; + textInputAriaLabel: string; + enableMobileMenu: boolean; + } + interface EventsBase { + [key: string]: any; + } + interface EditSessionEvents { + /** + * Emitted when the document changes. + */ + "change": (delta: Delta) => void; + /** + * Emitted when the tab size changes, via [[EditSession.setTabSize]]. + */ + "changeTabSize": () => void; + /** + * Emitted when the ability to overwrite text changes, via [[EditSession.setOverwrite]]. + */ + "changeOverwrite": (overwrite: boolean) => void; + /** + * Emitted when the gutter changes, either by setting or removing breakpoints, or when the gutter decorations change. + */ + "changeBreakpoint": (e?: { + row?: number; + breakpoint?: boolean; + }) => void; + /** + * Emitted when a front marker changes. + */ + "changeFrontMarker": () => void; + /** + * Emitted when a back marker changes. + */ + "changeBackMarker": () => void; + /** + * Emitted when an annotation changes, like through [[EditSession.setAnnotations]]. + */ + "changeAnnotation": (e: {}) => void; + /** + * Emitted when a background tokenizer asynchronously processes new rows. + */ + "tokenizerUpdate": (e: { + data: { + first: number; + last: number; + }; + }) => void; + /** + * Emitted when the current mode changes. + */ + "changeMode": (e: any) => void; + /** + * Emitted when the wrap mode changes. + */ + "changeWrapMode": (e: any) => void; + /** + * Emitted when the wrapping limit changes. + */ + "changeWrapLimit": (e: any) => void; + /** + * Emitted when a code fold is added or removed. + */ + "changeFold": (e: any, session?: EditSession) => void; + /** + * Emitted when the scroll top changes. + * @param scrollTop The new scroll top value + **/ + "changeScrollTop": (scrollTop: number) => void; + /** + * Emitted when the scroll left changes. + * @param scrollLeft The new scroll left value + **/ + "changeScrollLeft": (scrollLeft: number) => void; + "changeEditor": (e: { + editor?: Editor; + oldEditor?: Editor; + }) => void; + "changeSelection": () => void; + "startOperation": (op?: { + command?: { + name?: string; + }; + args?: any; + }) => void; + "endOperation": (op?: any) => void; + "beforeEndOperation": () => void; + } + interface EditorEvents { + "change": (delta: Delta) => void; + "changeSelection": () => void; + "input": () => void; + /** + * Emitted whenever the [[EditSession]] changes. + * @param e An object with two properties, `oldSession` and `session`, that represent the old and new [[EditSession]]s. + **/ + "changeSession": (e: { + oldSession: EditSession; + session: EditSession; + }) => void; + "blur": (e: any) => void; + "mousedown": (e: MouseEvent) => void; + "mousemove": (e: MouseEvent & { + scrollTop?: any; + }, editor?: Editor) => void; + "changeStatus": (e: any) => void; + "keyboardActivity": (e: any) => void; + "mousewheel": (e: MouseEvent) => void; + "mouseup": (e: MouseEvent) => void; + "beforeEndOperation": (e: any) => void; + "nativecontextmenu": (e: any) => void; + "destroy": (e: any) => void; + "focus": (e?: any) => void; + /** + * Emitted when text is copied. + * @param text The copied text + **/ + "copy": (e: { + text: string; + }) => void; + /** + * Emitted when text is pasted. + **/ + "paste": (text: string, event: any) => void; + /** + * Emitted when the selection style changes, via [[Editor.setSelectionStyle]]. + * @param data Contains one property, `data`, which indicates the new selection style + **/ + "changeSelectionStyle": (data: "fullLine" | "screenLine" | "text" | "line") => void; + "changeMode": (e: { + mode?: Ace.SyntaxMode; + oldMode?: Ace.SyntaxMode; + }) => void; + //from searchbox extension + "findSearchBox": (e: { + match: boolean; + }) => void; + //from code_lens extension + "codeLensClick": (e: any) => void; + "select": () => void; + } + interface AcePopupEvents { + "click": (e: MouseEvent) => void; + "dblclick": (e: MouseEvent) => void; + "tripleclick": (e: MouseEvent) => void; + "quadclick": (e: MouseEvent) => void; + "show": () => void; + "hide": () => void; + "select": (hide: boolean) => void; + "changeHoverMarker": (e: any) => void; + } + interface DocumentEvents { + /** + * Fires whenever the document changes. + * Several methods trigger different `"change"` events. Below is a list of each action type, followed by each property that's also available: + * * `"insert"` + * * `range`: the [[Range]] of the change within the document + * * `lines`: the lines being added + * * `"remove"` + * * `range`: the [[Range]] of the change within the document + * * `lines`: the lines being removed + * + **/ + "change": (e: Delta) => void; + "changeNewLineMode": () => void; + } + interface AnchorEvents { + /** + * Fires whenever the anchor position changes. + * Both of these objects have a `row` and `column` property corresponding to the position. + * Events that can trigger this function include [[Anchor.setPosition `setPosition()`]]. + * @param {Object} e An object containing information about the anchor position. It has two properties: + * - `old`: An object describing the old Anchor position + * - `value`: An object describing the new Anchor position + **/ + "change": (e: { + old: Point; + value: Point; + }) => void; + } + interface BackgroundTokenizerEvents { + /** + * Fires whenever the background tokeniziers between a range of rows are going to be updated. + * @param e An object containing two properties, `first` and `last`, which indicate the rows of the region being updated. + **/ + "update": (e: { + data: { + first: number; + last: number; + }; + }) => void; + } + interface SelectionEvents { + /** + * Emitted when the cursor position changes. + **/ + "changeCursor": () => void; + /** + * Emitted when the cursor selection changes. + **/ + "changeSelection": () => void; + } + interface MultiSelectionEvents extends SelectionEvents { + "multiSelect": () => void; + "addRange": (e: { + range: Range; + }) => void; + "removeRange": (e: { + ranges: Range[]; + }) => void; + "singleSelect": () => void; + } + interface PlaceHolderEvents { + "cursorEnter": (e: any) => void; + "cursorLeave": (e: any) => void; + } + interface GutterEvents { + "changeGutterWidth": (width: number) => void; + "afterRender": () => void; + } + interface TextEvents { + "changeCharacterSize": (e: any) => void; + } + interface VirtualRendererEvents { + "afterRender": (e?: any, renderer?: VirtualRenderer) => void; + "beforeRender": (e: any, renderer?: VirtualRenderer) => void; + "themeLoaded": (e: { + theme: string | Theme; + }) => void; + "themeChange": (e: { + theme: string | Theme; + }) => void; + "scrollbarVisibilityChanged": () => void; + "changeCharacterSize": (e: any) => void; + "resize": (e?: any) => void; + "autosize": () => void; + } + class EventEmitter { + once(name: K, callback: T[K]): void; + setDefaultHandler(name: string, callback: Function): void; + removeDefaultHandler(name: string, callback: Function): void; + on(name: K, callback: T[K], capturing?: boolean): T[K]; + addEventListener(name: K, callback: T[K], capturing?: boolean): T[K]; + off(name: K, callback: T[K]): void; + removeListener(name: K, callback: T[K]): void; + removeEventListener(name: K, callback: T[K]): void; + removeAllListeners(name?: string): void; + } + interface SearchOptions { + /**The string or regular expression you're looking for*/ + needle: string | RegExp; + preventScroll: boolean; + /**Whether to search backwards from where cursor currently is*/ + backwards: boolean; + /**The starting [[Range]] or cursor position to begin the search*/ + start: Range; + /**Whether or not to include the current line in the search*/ + skipCurrent: boolean; + /**The [[Range]] to search within. Set this to `null` for the whole document*/ + range: Range | null; + preserveCase: boolean; + /**Whether the search is a regular expression or not*/ + regExp: boolean; + /**Whether the search matches only on whole words*/ + wholeWord: boolean; + /**Whether the search ought to be case-sensitive*/ + caseSensitive: boolean; + /**Whether to wrap the search back to the beginning when it hits the end*/ + wrap: boolean; + re: any; + } + interface Point { + row: number; + column: number; + } + type Position = Point; + interface Delta { + action: "insert" | "remove"; + start: Point; + end: Point; + lines: string[]; + id?: number; + folds?: Fold[]; + } + interface Annotation { + row: number; + column: number; + text: string; + type: string; + } + export interface MarkerGroupItem { + range: Range; + className: string; + } + type MarkerGroup = import("ace-code/src/marker_group").MarkerGroup; + export interface Command { + name?: string; + bindKey?: string | { + mac?: string; + win?: string; + }; + readOnly?: boolean; + exec?: (editor?: Editor | any, args?: any) => void; + isAvailable?: (editor: Editor) => boolean; + description?: string; + multiSelectAction?: "forEach" | "forEachLine" | Function; + scrollIntoView?: true | "cursor" | "center" | "selectionPart" | "animate" | "selection" | "none"; + aceCommandGroup?: string; + passEvent?: boolean; + level?: number; + action?: string; + } + type CommandLike = Command | ((editor: Editor) => void) | ((sb: SearchBox) => void); + type KeyboardHandler = Partial & { + attach?: (editor: Editor) => void; + detach?: (editor: Editor) => void; + getStatusText?: (editor?: any, data?: any) => string; + }; + export interface MarkerLike { + range?: Range; + type: string; + renderer?: MarkerRenderer; + clazz: string; + inFront?: boolean; + id?: number; + update?: (html: string[], + // TODO maybe define Marker class + marker: any, session: EditSession, config: any) => void; + [key: string]: any; + } + type MarkerRenderer = (html: string[], range: Range, left: number, top: number, config: any) => void; + interface Token { + type: string; + value: string; + index?: number; + start?: number; + } + type BaseCompletion = import("ace-code/src/autocomplete").BaseCompletion; + type SnippetCompletion = import("ace-code/src/autocomplete").SnippetCompletion; + type ValueCompletion = import("ace-code/src/autocomplete").ValueCompletion; + type Completion = import("ace-code/src/autocomplete").Completion; + type HighlightRule = ({ + defaultToken: string; + } | { + include: string; + } | { + todo: string; + } | { + token: string | string[] | ((value: string) => string); + regex: string | RegExp; + next?: string | (() => void); + push?: string; + comment?: string; + caseInsensitive?: boolean; + nextState?: string; + }) & { + [key: string]: any; + }; + type HighlightRulesMap = Record; + type KeywordMapper = (keyword: string) => string; + interface HighlightRules { + addRules(rules: HighlightRulesMap, prefix?: string): void; + getRules(): HighlightRulesMap; + embedRules(rules: (new () => HighlightRules) | HighlightRulesMap, prefix: string, escapeRules?: boolean, append?: boolean): void; + getEmbeds(): string[]; + normalizeRules(): void; + createKeywordMapper(map: Record, defaultToken?: string, ignoreCase?: boolean, splitChar?: string): KeywordMapper; + } + type FoldWidget = "start" | "end" | ""; + interface FoldMode { + foldingStartMarker: RegExp; + foldingStopMarker?: RegExp; + getFoldWidget(session: EditSession, foldStyle: string, row: number): FoldWidget; + getFoldWidgetRange(session: EditSession, foldStyle: string, row: number): Range | undefined; + indentationBlock(session: EditSession, row: number, column?: number): Range | undefined; + openingBracketBlock(session: EditSession, bracket: string, row: number, column: number, typeRe?: RegExp): Range | undefined; + closingBracketBlock(session: EditSession, bracket: string, row: number, column: number, typeRe?: RegExp): Range | undefined; + } + type BehaviorAction = (state: string | string[], action: string, editor: Editor, session: EditSession, text: string | Range) => ({ + text: string; + selection: number[]; + } | Range) & { + [key: string]: any; + } | undefined; + type BehaviorMap = Record>; + interface Behaviour { + add(name: string, action: string, callback: BehaviorAction): void; + addBehaviours(behaviours: BehaviorMap): void; + remove(name: string): void; + inherit(mode: SyntaxMode | (new () => SyntaxMode), filter: string[]): void; + getBehaviours(filter?: string[]): BehaviorMap; + } + interface Outdent { + checkOutdent(line: string, input: string): boolean; + autoOutdent(doc: Document, row: number): number | undefined; + } + interface SyntaxMode { + HighlightRules: { + new(config: any): HighlightRules; + }; //TODO: fix this + foldingRules?: FoldMode; + /** + * characters that indicate the start of a line comment + */ + lineCommentStart?: string; + /** + * characters that indicate the start and end of a block comment + */ + blockComment?: { + start: string; + end: string; + }; + tokenRe?: RegExp; + nonTokenRe?: RegExp; + completionKeywords: string[]; + transformAction: BehaviorAction; + path?: string; + getTokenizer(): Tokenizer; + toggleCommentLines(state: string | string[], session: EditSession, startRow: number, endRow: number): void; + toggleBlockComment(state: string | string[], session: EditSession, range: Range, cursor: Point): void; + getNextLineIndent(state: string | string[], line: string, tab: string): string; + checkOutdent(state: string | string[], line: string, input: string): boolean; + autoOutdent(state: string | string[], doc: EditSession, row: number): void; + // TODO implement WorkerClient types + createWorker(session: EditSession): any; + createModeDelegates(mapping: { + [key: string]: string; + }): void; + getKeywords(append?: boolean): Array; + getCompletions(state: string | string[], session: EditSession, pos: Point, prefix: string): Completion[]; + } + interface OptionsBase { + [key: string]: any; + } + class OptionsProvider { + setOptions(optList: Partial): void; + getOptions(optionNames?: Array | Partial): Partial; + setOption(name: K, value: T[K]): void; + getOption(name: K): T[K]; + } + type KeyBinding = import("ace-code/src/keyboard/keybinding").KeyBinding; + interface CommandMap { + [name: string]: Command; + } + type execEventHandler = (obj: { + editor: Editor; + command: Command; + args: any[]; + }) => void; + interface CommandManagerEvents { + on(name: "exec", callback: execEventHandler): Function; + on(name: "afterExec", callback: execEventHandler): Function; + } + type CommandManager = import("ace-code/src/commands/command_manager").CommandManager; + interface SavedSelection { + start: Point; + end: Point; + isBackwards: boolean; + } + var Selection: { + new(session: EditSession): Selection; + }; + interface TextInput { + resetSelection(): void; + setAriaOption(options?: { + activeDescendant: string; + role: string; + setLabel: any; + }): void; + } + type CompleterCallback = (error: any, completions: Completion[]) => void; + interface Completer { + identifierRegexps?: Array; + getCompletions(editor: Editor, session: EditSession, position: Point, prefix: string, callback: CompleterCallback): void; + getDocTooltip?(item: Completion): void | string | Completion; + onSeen?: (editor: Ace.Editor, completion: Completion) => void; + onInsert?: (editor: Ace.Editor, completion: Completion) => void; + cancel?(): void; + id?: string; + triggerCharacters?: string[]; + hideInlinePreview?: boolean; + insertMatch?: (editor: Editor, data: Completion) => void; + } + interface CompletionOptions { + matches?: Completion[]; + } + type CompletionProviderOptions = { + exactMatch?: boolean; + ignoreCaption?: boolean; + }; + type GatherCompletionRecord = { + prefix: string; + matches: Completion[]; + finished: boolean; + }; + type CompletionCallbackFunction = (err: Error | undefined, data: GatherCompletionRecord) => void; + type CompletionProviderCallback = (this: import("ace-code/src/autocomplete").Autocomplete, err: Error | undefined, completions: import("ace-code/src/autocomplete").FilteredList, finished: boolean) => void; + type AcePopupNavigation = "up" | "down" | "start" | "end"; + interface EditorMultiSelectProperties { + inMultiSelectMode?: boolean; + /** + * Updates the cursor and marker layers. + **/ + updateSelectionMarkers: () => void; + /** + * Adds the selection and cursor. + * @param orientedRange A range containing a cursor + **/ + addSelectionMarker: (orientedRange: Ace.Range & { + marker?: any; + }) => Ace.Range & { + marker?: any; + }; + /** + * Removes the selection marker. + * @param range The selection range added with [[Editor.addSelectionMarker `addSelectionMarker()`]]. + **/ + removeSelectionMarker: (range: Ace.Range & { + marker?: any; + }) => void; + removeSelectionMarkers: (ranges: (Ace.Range & { + marker?: any; + })[]) => void; + /** + * Executes a command for each selection range. + * @param cmd The command to execute + * @param [args] Any arguments for the command + **/ + forEachSelection: (cmd: Object, args?: string, options?: Object) => void; + /** + * Removes all the selections except the last added one. + **/ + exitMultiSelectMode: () => void; + getSelectedText: () => string; + /** + * Finds and selects all the occurrences of `needle`. + * @param needle The text to find + * @param options The search options + * @param additive keeps + * @returns {Number} The cumulative count of all found matches + **/ + findAll: (needle?: string, options?: Partial, additive?: boolean) => number; + /** + * Adds a cursor above or below the active cursor. + * @param dir The direction of lines to select: -1 for up, 1 for down + * @param [skip] If `true`, removes the active selection range + */ + selectMoreLines: (dir: number, skip?: boolean) => void; + /** + * Transposes the selected ranges. + * @param {Number} dir The direction to rotate selections + **/ + transposeSelections: (dir: number) => void; + /** + * Finds the next occurrence of text in an active selection and adds it to the selections. + * @param {Number} dir The direction of lines to select: -1 for up, 1 for down + * @param {Boolean} [skip] If `true`, removes the active selection range + **/ + selectMore: (dir: number, skip?: boolean, stopAtFirst?: boolean) => void; + /** + * Aligns the cursors or selected text. + **/ + alignCursors: () => void; + multiSelect?: any; + } + interface CodeLenseProvider { + provideCodeLenses: (session: EditSession, callback: (err: any, payload: CodeLense[]) => void) => void; + } + interface CodeLense { + start: Point; + command: any; + } + interface CodeLenseEditorExtension { + codeLensProviders?: CodeLenseProvider[]; + } + interface ElasticTabstopsEditorExtension { + elasticTabstops?: import("ace-code/src/ext/elastic_tabstops_lite").ElasticTabstopsLite; + } + interface TextareaEditorExtension { + setDisplaySettings?: (settings: any) => void; + } + interface PromptEditorExtension { + cmdLine?: Editor; + } + interface OptionsEditorExtension { + } + interface MultiSelectProperties { + ranges: Ace.Range[] | null; + rangeList: Ace.RangeList | null; + /** + * Adds a range to a selection by entering multiselect mode, if necessary. + * @param {Ace.Range} range The new range to add + * @param {Boolean} [$blockChangeEvents] Whether or not to block changing events + **/ + addRange(range: Ace.Range, $blockChangeEvents?: boolean): any; + inMultiSelectMode: boolean; + toSingleRange(range?: Ace.Range): void; + /** + * Removes a Range containing pos (if it exists). + * @param {Ace.Point} pos The position to remove, as a `{row, column}` object + **/ + substractPoint(pos: Ace.Point): any; + /** + * Merges overlapping ranges ensuring consistency after changes + **/ + mergeOverlappingRanges(): void; + rangeCount: number; + /** + * Returns a concatenation of all the ranges. + **/ + getAllRanges(): Ace.Range[]; + /** + * Splits all the ranges into lines. + **/ + splitIntoLines(): void; + joinSelections(): void; + toggleBlockSelection(): void; + /** + * + * Gets list of ranges composing rectangular block on the screen + * + * @param {Ace.ScreenCoordinates} screenCursor The cursor to use + * @param {Ace.ScreenCoordinates} screenAnchor The anchor to use + * @param {Boolean} [includeEmptyLines] If true, this includes ranges inside the block which are empty due to clipping + **/ + rectangularRangeBlock(screenCursor: Ace.ScreenCoordinates, screenAnchor: Ace.ScreenCoordinates, includeEmptyLines?: boolean): Ace.Range[]; + index?: number; + } + type AcePopupEventsCombined = Ace.EditorEvents & Ace.AcePopupEvents; + type AcePopupWithEditor = Ace.EventEmitter & Ace.Editor; + type InlineAutocompleteAction = "prev" | "next" | "first" | "last"; + type TooltipCommandFunction = (editor: Ace.Editor) => T; + export interface TooltipCommand extends Ace.Command { + enabled?: TooltipCommandFunction | boolean; + getValue?: TooltipCommandFunction; + type: "button" | "text" | "checkbox"; + iconCssClass?: string; + cssClass?: string; + } + export type CommandBarTooltip = import("ace-code/src/ext/command_bar").CommandBarTooltip; + export type TokenizeResult = Array>; + export interface StaticHighlightOptions { + mode?: string | SyntaxMode; + theme?: string | Theme; + trim?: boolean; + firstLineNumber?: number; + showGutter?: boolean; + } + } + export const config: typeof import("ace-code/src/config"); + export function edit(el?: string | (HTMLElement & { + env?: any; + value?: any; + }) | null, options?: any): Editor; + export function createEditSession(text: import("ace-code/src/document").Document | string, mode?: import("ace-code").Ace.SyntaxMode): EditSession; + import { Editor } from "ace-code/src/editor"; + import { EditSession } from "ace-code/src/edit_session"; + import { Range } from "ace-code/src/range"; + import { UndoManager } from "ace-code/src/undomanager"; + import { VirtualRenderer as Renderer } from "ace-code/src/virtual_renderer"; + export var version: "1.36.5"; + export { Range, Editor, EditSession, UndoManager, Renderer as VirtualRenderer }; } diff --git a/demo/test_package/index.ts b/demo/test_package/index.ts new file mode 100644 index 00000000000..b1e62243572 --- /dev/null +++ b/demo/test_package/index.ts @@ -0,0 +1,114 @@ +import * as ace from "ace-code"; +import {Range} from "ace-code"; +import {Autocomplete} from "ace-code/src/autocomplete"; +import {beautify} from "ace-code/src/ext/beautify"; +import {registerCodeLensProvider, setLenses} from "ace-code/src/ext/code_lens"; +import {CommandBarTooltip} from "ace-code/src/ext/command_bar"; +import {ElasticTabstopsLite} from "ace-code/src/ext/elastic_tabstops_lite"; +import {MarkerGroup, MarkerGroupItem} from "ace-code/src/marker_group"; +import {HoverTooltip} from "ace-code/src/tooltip"; +import {hardWrap} from "ace-code/src/ext/hardwrap"; +import {SearchBox} from "ace-code/src/ext/searchbox"; + +import("ace-code/src/ext/language_tools"); +import "../../src/test/mockdom.js"; +import {tokenize} from "ace-code/src/ext/simple_tokenizer"; +import {JavaScriptHighlightRules} from "ace-code/src/mode/javascript_highlight_rules"; +import {highlight} from "ace-code/src/ext/static_highlight"; + +// TODO this does not work in node +// import "ace-code/esm-resolver"; +import { config } from "ace-code"; +config.setLoader(async function(moduleName, cb) { + moduleName = moduleName.replace("ace/", "ace-code/src/") + let module = await import(moduleName); + cb(null, module); +}); + +const editor = ace.edit(null); // should not be an error +editor.setTheme("ace/theme/monokai"); +editor.session.setMode("ace/mode/javascript"); + +function configure(config: ace.Ace.Config) { + config.setDefaultValues("editor", { + fontSize: 14, + showPrintMargin: false, + }) +} + +configure(ace.config) // should not be a error + +Autocomplete.for(editor).getCompletionProvider() // should not be an error + +const markerGroup = new MarkerGroup(editor.session); +const markers: MarkerGroupItem[] = [ + { + range: new Range(0, 0, 10, 10), + className: "test-class" + } +] +markerGroup.setMarkers(markers); +markerGroup.markers.every(marker => { + console.log(marker.range); + return true; +}); + +const hover = new HoverTooltip(); +hover.setDataProvider((e, editor) => { + const domNode = document.createElement("div"); + hover.showForRange(editor, new Range(1, 3, 3, 1), domNode, e); +}); +hover.addToEditor(editor); + +beautify(editor.session); + +registerCodeLensProvider(editor, { + provideCodeLenses: function (session, callback) { + const lenses = [{ + start: {row: 2, column: 1}, + command: {title: "2"} + }]; + setTimeout(function () { + callback(null, [{ + start: {row: 2, column: 1}, + command: {title: "2"} + }]); + + setLenses(session, lenses); + }); + } +}); + +var commandBar = new CommandBarTooltip(editor.container); +var command: ace.Ace.TooltipCommand = { + name: "test", + exec: function (editor: ace.Editor) { + alert(editor.getValue()); + }, + type: "checkbox" +} +commandBar.registerCommand("test", command); + +const elasticTabStopLite = new ElasticTabstopsLite(editor); +elasticTabStopLite.processRows([1, 2, 4]); + + +hardWrap(editor, { + startRow: 1, + endRow: 2, +}); + + +const searchBox = new SearchBox(editor); + +searchBox.show("Test", true); + +tokenize("some content", new JavaScriptHighlightRules()); +highlight(editor.container, { + mode: "ace/mode/abap", + showGutter: true +}) + +setTimeout(function() { + editor.destroy(); +}, 20) \ No newline at end of file diff --git a/demo/test_package/package.json b/demo/test_package/package.json new file mode 100644 index 00000000000..a0c3782e21c --- /dev/null +++ b/demo/test_package/package.json @@ -0,0 +1,16 @@ +{ + "name": "ace-test-package", + "version": "1.0.0", + "description": "Test package for Ace", + "main": "index.js", + "scripts": { + "build": "tsc -p tsconfig.json", + "test": "node index.js" + }, + "dependencies": { + "ace-code": "file:../../ace-code-latest.tgz" + }, + "devDependencies": { + "typescript": "^5.6.2" + } +} diff --git a/demo/test_package/tsconfig.json b/demo/test_package/tsconfig.json new file mode 100644 index 00000000000..1f23bf07327 --- /dev/null +++ b/demo/test_package/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "module": "commonjs", + "target": "es2020", + "moduleResolution": "node" + }, + "include": ["*.ts"], + "exclude": ["node_modules"] +} diff --git a/package.json b/package.json index 26fe8060271..ca6d03ad47d 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "eslint": "^8.20.0", "istanbul": "^0.4.5", "standard-version": "^9.3.2", - "typescript": "^5.2.2" + "typescript": "^5.6.3" }, "mappings": { "ace": "." @@ -32,7 +32,7 @@ "styles", "ace.d.ts", "ace-modes.d.ts", - "ace-extensions.d.ts", + "types", "esm-resolver.js", "translations", "!**/*_test.js", @@ -45,9 +45,9 @@ "lint": "eslint \"src/**/*.js\" \"*.js\"", "fix": "npm run lint -- --fix", "typecheck": "tsc -p tsconfig.json", - "update-types": "node ./tool/modes-declaration-generator.js", + "update-types": "node ./tool/ace_declaration_generator.js", "changelog": "standard-version", - "prepack": "node tool/esm_resolver_generator.js && node Makefile.dryice.js css --target build-styles && rm -rf styles && mv build-styles/css styles" + "prepack": "node tool/esm_resolver_generator.js && node tool/ace_declaration_generator.js && node Makefile.dryice.js css --target build-styles && rm -rf styles && mv build-styles/css styles" }, "standard-version": { "skip": { diff --git a/src/autocomplete.js b/src/autocomplete.js index a46dfc3704b..75a96e2f527 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -39,14 +39,14 @@ var preventParentScroll = require("./lib/scroll").preventParentScroll; /** * @typedef {BaseCompletion & {snippet: string}} SnippetCompletion - * @property {string} snippet + * @property {string} snippet * @property {string} [value] * @export */ /** * @typedef {BaseCompletion & {value: string}} ValueCompletion - * @property {string} value + * @property {string} value * @property {string} [snippet] * @export */ @@ -83,7 +83,7 @@ class Autocomplete { /** * @property {Boolean} showLoadingState - A boolean indicating whether the loading states of the Autocompletion should be shown to the end-user. If enabled * it shows a loading indicator on the popup while autocomplete is loading. - * + * * Experimental: This visualisation is not yet considered stable and might change in the future. */ this.showLoadingState = false; @@ -130,7 +130,7 @@ class Autocomplete { $init() { /**@type {AcePopup}**/ - this.popup = new AcePopup(this.parentNode || document.body || document.documentElement); + this.popup = new AcePopup(this.parentNode || document.body || document.documentElement); this.popup.on("click", function(e) { this.insertMatch(); e.stop(); @@ -306,7 +306,7 @@ class Autocomplete { if (this.popup.tryShow(pos, lineHeight, "top")) { return; } - + this.popup.show(pos, lineHeight); } @@ -339,17 +339,17 @@ class Autocomplete { } editor.keyBinding.addKeyboardHandler(this.keyboardHandler); - + var newRow; if (this.stickySelection) - newRow = this.popup.data.indexOf(previousSelectedItem); - if (!newRow || newRow === -1) + newRow = this.popup.data.indexOf(previousSelectedItem); + if (!newRow || newRow === -1) newRow = 0; - + this.popup.setRow(this.autoSelect ? newRow : -1); - + // If we stay on the same row, but the content is different, we want to update the popup. - if (newRow === oldRow && previousSelectedItem !== this.completions.filtered[newRow]) + if (newRow === oldRow && previousSelectedItem !== this.completions.filtered[newRow]) this.$onPopupChange(); // If we stay on the same line and have inlinePreview enabled, we want to make sure the @@ -472,7 +472,7 @@ class Autocomplete { this.detach(); return result; } - + /** * This is the entry point for the autocompletion class, triggers the actions which collect and display suggestions * @param {Editor} editor @@ -539,7 +539,7 @@ class Autocomplete { this.openPopup(this.editor, prefix, keepPopupPosition); return; } - + if (options && options.matches) { var pos = this.editor.getSelectionRange().start; this.base = this.editor.session.doc.createAnchor(pos.row, pos.column); @@ -602,7 +602,7 @@ class Autocomplete { } // If showLoadingState is true and there is still a completer loading, show 'Loading...' // in the top row of the completer popup. - this.completions = !finished && this.showLoadingState ? + this.completions = !finished && this.showLoadingState ? new FilteredList( Autocomplete.completionsForLoading.concat(filtered), completions.filterText ) : @@ -630,7 +630,7 @@ class Autocomplete { var doc = null; if (!selected || !this.editor || !this.popup.isOpen) return this.hideDocTooltip(); - + var completersLength = this.editor.completers.length; for (var i = 0; i < completersLength; i++) { var completer = this.editor.completers[i]; @@ -819,7 +819,7 @@ Autocomplete.startCommand = { * This class is responsible for providing completions and inserting them to the editor */ class CompletionProvider { - + /** * @param {{pos: Position, prefix: string}} [initialPosition] @@ -859,7 +859,7 @@ class CompletionProvider { // TODO add support for options.deleteSuffix if (!this.completions) return false; - + var replaceBefore = this.completions.filterText.length; var replaceAfter = 0; if (data.range && data.range.start.row === data.range.end.row) { @@ -882,7 +882,7 @@ class CompletionProvider { editor.session.remove(range); } } - + if (data.snippet) { snippetManager.insertSnippet(editor, data.snippet); } @@ -892,7 +892,7 @@ class CompletionProvider { if (data.completer && data.completer.onInsert && typeof data.completer.onInsert == "function") { data.completer.onInsert(editor, data); } - + if (data.command && data.command === "startAutocomplete") { editor.execCommand(data.command); } @@ -917,9 +917,9 @@ class CompletionProvider { gatherCompletions(editor, callback) { var session = editor.getSession(); var pos = editor.getCursorPosition(); - + var prefix = util.getCompletionPrefix(editor); - + var matches = []; this.completers = editor.completers; var total = editor.completers.length; @@ -993,7 +993,7 @@ class CompletionProvider { processResults(results); }.bind(this)); - + isImmediate = false; if (immediateResults) { var results = immediateResults; @@ -1020,7 +1020,7 @@ class FilteredList { this.exactMatch = false; this.ignoreCaption = false; } - + setFilter(str) { if (str.length > this.filterText && str.lastIndexOf(this.filterText, 0) === 0) var matches = this.filtered; @@ -1030,7 +1030,7 @@ class FilteredList { this.filterText = str; matches = this.filterCompletions(matches, this.filterText); matches = matches.sort(function(a, b) { - return b.exactMatch - a.exactMatch || b.$score - a.$score + return b.exactMatch - a.exactMatch || b.$score - a.$score || (a.caption || a.value).localeCompare(b.caption || b.value); }); @@ -1045,7 +1045,7 @@ class FilteredList { this.filtered = matches; } - + filterCompletions(items, needle) { var results = []; var upper = needle.toUpperCase(); diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index b48ec080b21..c9a5f5e0f83 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -12,6 +12,7 @@ var user = require("./test/user"); var Range = require("./range").Range; require("./ext/language_tools"); var Autocomplete = require("./autocomplete").Autocomplete; +var config = require("./config"); var MouseEvent = function(type, opts){ var e = document.createEvent("MouseEvents"); @@ -1542,6 +1543,13 @@ module.exports = { // Popup should be closed now assert.equal(completer.popup.isOpen, false); + }, + "test: should set create shared Autocomplete with sharedPopups on": function() { + assert.equal(Autocomplete.$sharedInstance == undefined, true); + config.set("sharedPopups", true); + var editor = initEditor(""); + var completer = Autocomplete.for(editor); + assert.equal(Autocomplete.$sharedInstance == undefined, false); } }; diff --git a/src/config.js b/src/config.js index a3e621980c0..a00a27ff614 100644 --- a/src/config.js +++ b/src/config.js @@ -1,4 +1,5 @@ "no use strict"; + var lang = require("./lib/lang"); var net = require("./lib/net"); var dom = require("./lib/dom"); @@ -103,6 +104,8 @@ var loader = function(moduleName, cb) { console.error("loader is not configured"); }; var customLoader; + +/** @arg {(name: string, callback: (error: any, module: any) => void) => void} cb */ exports.setLoader = function(cb) { customLoader = cb; }; diff --git a/src/document.js b/src/document.js index 0d8d243f107..8501e1027fc 100644 --- a/src/document.js +++ b/src/document.js @@ -95,7 +95,7 @@ class Document { /** * [Sets the new line mode.]{: #Document.setNewLineMode.desc} - * @param {NewLineMode} newLineMode [The newline mode to use; can be either `windows`, `unix`, or `auto`]{: #Document.setNewLineMode.param} + * @param {NewLineMode} newLineMode [The newline mode to use; can be either `windows`, `unix`, or `auto`] **/ setNewLineMode(newLineMode) { @@ -107,7 +107,7 @@ class Document { } /** - * [Returns the type of newlines being used; either `windows`, `unix`, or `auto`]{: #Document.getNewLineMode} + * Returns the type of newlines being used; either `windows`, `unix`, or `auto` * @returns {NewLineMode} **/ getNewLineMode() { diff --git a/src/edit_session.js b/src/edit_session.js index f9717aa4779..f7364e0c4be 100644 --- a/src/edit_session.js +++ b/src/edit_session.js @@ -1199,7 +1199,7 @@ class EditSession { /** * Reverts previous changes to your document. * @param {Delta[]} deltas An array of previous changes - * @param {Boolean} [dontSelect] [If `true`, doesn't select the range of where the change occured]{: #dontSelect} + * @param {Boolean} [dontSelect] If `true`, doesn't select the range of where the change occured **/ undoChanges(deltas, dontSelect) { if (!deltas.length) diff --git a/src/ext/prompt.js b/src/ext/prompt.js index 620fb8c9e69..9dc7e46e36f 100644 --- a/src/ext/prompt.js +++ b/src/ext/prompt.js @@ -21,7 +21,7 @@ var openPrompt; * @typedef PromptOptions * @property {String} name Prompt name. * @property {String} $type Use prompt of specific type (gotoLine|commands|modes or default if empty). - * @property {[start: number, end: number]} selection Defines which part of the predefined value should be highlited. + * @property {[number, number]} selection Defines which part of the predefined value should be highlighted. * @property {Boolean} hasDescription Set to true if prompt has description below input box. * @property {String} prompt Description below input box. * @property {String} placeholder Placeholder for value. diff --git a/src/keyboard/hash_handler.js b/src/keyboard/hash_handler.js index d445f5f2924..fb9eca6afdb 100644 --- a/src/keyboard/hash_handler.js +++ b/src/keyboard/hash_handler.js @@ -167,7 +167,7 @@ class MultiHashHandler { } /** - * @param {Record} commands + * @param {Record} commands */ removeCommands(commands) { Object.keys(commands).forEach(function(name) { @@ -176,7 +176,7 @@ class MultiHashHandler { } /** - * @param {Record} keyList + * @param {Record} keyList */ bindKeys(keyList) { Object.keys(keyList).forEach(function(key) { @@ -230,7 +230,7 @@ class MultiHashHandler { } /** - * @param {{ $keyChain: string | any[]; }} data + * @param {any} data * @param {number} hashId * @param {string} keyString * @param {number} keyCode diff --git a/src/lib/dom.js b/src/lib/dom.js index 6a53ef8ae11..8ed64b6dd21 100644 --- a/src/lib/dom.js +++ b/src/lib/dom.js @@ -230,6 +230,11 @@ function insertPendingStyles() { }); } +/** + * @param {string} cssText + * @param {string} [id] + * @param {any} [target] + */ function importCssString(cssText, id, target) { if (typeof document == "undefined") return; diff --git a/src/lib/event.js b/src/lib/event.js index 6025acfc17a..95e250f4cf3 100644 --- a/src/lib/event.js +++ b/src/lib/event.js @@ -35,7 +35,15 @@ EventListener.prototype.destroy = function() { this.elem = this.type = this.callback = undefined; }; -var addListener = exports.addListener = function(elem, type, callback, /**@type{any?}*/destroyer) { +/** + * Adds an event listener to the specified element. + * + * @param {any} elem - The element to add the event listener to. + * @param {string} type - The type of event to listen for. + * @param {any} callback - The callback function to be executed when the event is triggered. + * @param {any} [destroyer] - An optional object that will have the created EventListener instance added to its $toDestroy array, allowing it to be easily destroyed later. + */ +var addListener = exports.addListener = function(elem, type, callback, destroyer) { elem.addEventListener(type, callback, getListenerOptions()); if (destroyer) destroyer.$toDestroy.push(new EventListener(elem, type, callback)); diff --git a/src/lib/lang.js b/src/lib/lang.js index 857f1525839..9cd2d58b67d 100644 --- a/src/lib/lang.js +++ b/src/lib/lang.js @@ -143,19 +143,25 @@ exports.deferredCall = function(fcn) { return deferred; }; - +/** + * @param {number} [defaultTimeout] + */ exports.delayedCall = function(fcn, defaultTimeout) { var timer = null; var callback = function() { timer = null; fcn(); }; - + /** + * @param {number} [timeout] + */ var _self = function(timeout) { if (timer == null) timer = setTimeout(callback, timeout || defaultTimeout); }; - + /** + * @param {number} [timeout] + */ _self.delay = function(timeout) { timer && clearTimeout(timer); timer = setTimeout(callback, timeout || defaultTimeout); diff --git a/src/mode/behaviour/css.js b/src/mode/behaviour/css.js index 2f05f7919d8..39da652cc38 100644 --- a/src/mode/behaviour/css.js +++ b/src/mode/behaviour/css.js @@ -1,5 +1,4 @@ "use strict"; - var oop = require("../../lib/oop"); var Behaviour = require("../behaviour").Behaviour; var CstyleBehaviour = require("./cstyle").CstyleBehaviour; diff --git a/tool/ace_declaration_generator.js b/tool/ace_declaration_generator.js new file mode 100644 index 00000000000..40b4b8bd44d --- /dev/null +++ b/tool/ace_declaration_generator.js @@ -0,0 +1,662 @@ +const ts = require('typescript'); +const fs = require("fs"); +const path = require("path"); + +const SEPARATE_MODULES = ["ext", "theme", "snippets", "lib"]; // adjust this list for more granularity + +const AUTO_GENERATED_HEADER = "/* This file is generated using `npm run update-types` */\n\n"; + +const defaultFormatCodeSettings = { + baseIndentSize: 0, + indentSize: 4, + tabSize: 4, + indentStyle: ts.IndentStyle.Smart, + newLineCharacter: "\n", + convertTabsToSpaces: true, + insertSpaceAfterCommaDelimiter: true, + insertSpaceAfterSemicolonInForStatements: true, + insertSpaceBeforeAndAfterBinaryOperators: true, + insertSpaceAfterConstructor: false, + insertSpaceAfterKeywordsInControlFlowStatements: true, + insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true, + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false, + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false, + insertSpaceAfterTypeAssertion: false, + insertSpaceBeforeFunctionParenthesis: false, + placeOpenBraceOnNewLineForFunctions: false, + placeOpenBraceOnNewLineForControlBlocks: false, + insertSpaceBeforeTypeAnnotation: false +}; + +/** + * @param {string} directoryPath + */ +function getParsedConfigFromDirectory(directoryPath) { + const configPath = ts.findConfigFile(directoryPath, ts.sys.fileExists, 'tsconfig.json'); + if (!configPath) throw new Error("Could not find tsconfig.json"); + + const configFile = ts.readConfigFile(configPath, ts.sys.readFile); + const parseConfigHost = { + fileExists: ts.sys.fileExists, + readFile: ts.sys.readFile, + readDirectory: ts.sys.readDirectory, + useCaseSensitiveFileNames: true + }; + configFile.config.compilerOptions.noEmit = false; + configFile.config.compilerOptions.emitDeclarationOnly = true; + configFile.config.compilerOptions.outFile = "./types/index.d.ts"; + + return ts.parseJsonConfigFileContent(configFile.config, parseConfigHost, directoryPath); +} + +/** + * @return {string} + */ +function generateInitialDeclaration(excludeDir) { + const baseDirectory = path.resolve(__dirname, '..'); + const parsedConfig = getParsedConfigFromDirectory(baseDirectory); + const defaultCompilerHost = ts.createCompilerHost({}); + let fileContent; + + const customCompilerHost = { + ...defaultCompilerHost, + writeFile: function (fileName, content) { + fileContent = content; + return; + }, + getSourceFile: function (fileName, languageVersion, onError, shouldCreateNewSourceFile) { + if (fileName.includes(excludeDir)) { + return undefined; + } + return defaultCompilerHost.getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile); + } + }; + + const program = ts.createProgram(parsedConfig.fileNames, parsedConfig.options, customCompilerHost); + program.emit(); + return fileContent; +} + +/** + * Creates a custom TypeScript compiler host that uses the provided source file content instead of reading from the file system. + * @param {string} fileName - The name of the source file. + * @param {string} content - The content of the source file. + * @returns {ts.CompilerHost} - A custom compiler host that uses the provided source file content. + */ +function createCustomCompilerHost(fileName, content) { + const newSourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS); + + const defaultCompilerHost = ts.createCompilerHost({}); + return { + ...defaultCompilerHost, + getSourceFile: (name, languageVersion) => { + if (name === fileName) { + return newSourceFile; + } + return defaultCompilerHost.getSourceFile(name, languageVersion); + }, + fileExists: (name) => { + if (name === fileName) { + return true; + } + return defaultCompilerHost.fileExists(name); + }, + readFile: (name) => { + if (name === fileName) { + return content; + } + return defaultCompilerHost.readFile(name); + } + }; +} + +function updateMainAceModule(node) { + if (node.body && ts.isModuleBlock(node.body)) { + const updatedStatements = node.body.statements.map(statement => { + //create type alias for config + if (ts.isVariableStatement(statement) && statement.declarationList.declarations[0]?.name?.text + === "config") { + + const originalDeclaration = statement.declarationList.declarations[0]; + + const importTypeNode = ts.factory.createImportTypeNode( + ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral('ace-code/src/config')), undefined, + undefined, false + ); + + const typeOfImportTypeNode = ts.factory.createTypeOperatorNode( + ts.SyntaxKind.TypeOfKeyword, importTypeNode); + + return ts.factory.updateVariableStatement(statement, statement.modifiers, + ts.factory.updateVariableDeclarationList(statement.declarationList, [ + ts.factory.updateVariableDeclaration(originalDeclaration, originalDeclaration.name, + originalDeclaration.exclamationToken, typeOfImportTypeNode, undefined + ) + ]) + ); + } + return statement; + }); + + return ts.factory.updateModuleDeclaration(node, node.modifiers, node.name, + ts.factory.createModuleBlock(updatedStatements) + ); + } +} + +/** + * Updates the module declaration for the "keys" and "linking" modules by adding the corresponding internal statements + * to support mixins (EventEmitter, OptionsProvider, etc.). + * + * @param {ts.ModuleDeclaration} node - The module declaration node to update. + * @param {Object} internalStatements - An object containing the internal statements to add to the module. + * @returns {ts.ModuleDeclaration} - The updated module declaration. + */ +function updateKeysAndLinksStatements(node, internalStatements) { + let statements = []; + if (internalStatements[node.name.text]) { + statements = internalStatements[node.name.text]; + } + const newBody = ts.factory.createModuleBlock(statements); + return ts.factory.updateModuleDeclaration(node, node.modifiers, node.name, newBody); +} + +/** + * Updates a module declaration by adding internal statements to support mixins (EventEmitter, OptionsProvider, etc.). + * + * @param {ts.ModuleDeclaration} node - The module declaration node to update. + * @param {Object} internalStatements - An object containing the internal statements to add to the module. + * @returns {ts.ModuleDeclaration} - The updated module declaration. + */ +function updateModuleWithInternalStatements(node, internalStatements) { + const newBody = ts.factory.createModuleBlock( + node.body.statements.concat(internalStatements[node.name.text]).filter(statement => { + if (node.name.text.endsWith("autocomplete")) { + return !(ts.isModuleDeclaration(statement) && statement.name.text === 'Autocomplete'); + } + return true; + })); + return ts.factory.updateModuleDeclaration(node, node.modifiers, node.name, newBody); +} + +/** + * Fixes interfaces with empty extends clauses by either removing the entire interface declaration if it has no members, + * or by removing the empty extends clause. + * + * @param {ts.InterfaceDeclaration} node - The interface declaration node to fix. + * @param {ts.TransformationContext} context - The transformation context. + * @returns {ts.InterfaceDeclaration} - The updated interface declaration. + */ +function fixWrongInterfaces(node, context) { + for (const clause of node.heritageClauses) { + if (clause.token === ts.SyntaxKind.ExtendsKeyword && clause.types.length === 0) { + if (node.members.length === 0) { + return; // remove entire interface declaration + } + // Remove the extends clause if it's empty + return context.factory.updateInterfaceDeclaration(node, node.modifiers, node.name, node.typeParameters, [], + node.members + ); + } + } + return node; +} + +/** + * Fixes heritage clauses in class declarations by removing any inheritance from undefined types. + * + * @param {ts.ClassDeclaration} node - The class declaration node to fix. + * @param {ts.TransformationContext} context - The transformation context. + * @param {ts.TypeChecker} checker - The TypeScript type checker. + * @returns {ts.ClassDeclaration} - The updated class declaration with fixed heritage clauses. + */ +function fixWrongHeritageClauses(node, context, checker) { + let updatedHeritageClauses = []; + // remove inheritances from undefined types + for (let i = 0; i < node.heritageClauses.length; i++) { + let clause = node.heritageClauses[i]; + if (clause.token === ts.SyntaxKind.ExtendsKeyword) { + const updatedTypes = clause.types.filter(type => { + const symbol = checker.getSymbolAtLocation(type.expression); + if (symbol) { + const declaredType = checker.getDeclaredTypeOfSymbol(symbol); + + return declaredType.flags !== ts.TypeFlags.Undefined && declaredType["intrinsicName"] !== "error"; + } + return true; // keep the type if the symbol can't be resolved + }); + if (updatedTypes.length === 0) { + continue; + } + var updatedHeritageClause = clause; + if (updatedTypes.length !== clause.types.length) { + updatedHeritageClause = context.factory.createHeritageClause( + ts.SyntaxKind.ExtendsKeyword, updatedTypes); + } + } + if (updatedHeritageClause) { + updatedHeritageClauses.push(updatedHeritageClause); + } + else { + updatedHeritageClauses.push(clause); + } + } + return context.factory.updateClassDeclaration(node, node.modifiers, node.name, node.typeParameters, + updatedHeritageClauses, node.members + ); +} + +/** + * @param {string} content + * @param {string} aceNamespacePath + */ +function fixDeclaration(content, aceNamespacePath) { + const temporaryName = "temp.d.ts"; + const customCompilerHost = createCustomCompilerHost(temporaryName, content); + const program = ts.createProgram([temporaryName], { + noEmit: true + }, customCompilerHost); + + var checker = program.getTypeChecker(); + let internalStatements = collectStatements(aceNamespacePath); + const finalDeclarations = []; + + /** + * Transforms the source file by updating certain module declarations and interface/class heritage clauses. + * + * @param {ts.TransformationContext} context - The transformation context. + * @returns {function(ts.SourceFile): ts.SourceFile} - A function that transforms the source file. + */ + function transformer(context) { + return (sourceFile) => { + function visit(node) { + let updatedNode = node; + // Update module declarations for certain module names + if (ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name)) { + if (node.name.text === "ace-code") { + return updateMainAceModule(node); + } else if (node.name.text.endsWith("lib/keys") || node.name.text.endsWith("linking")) { + updatedNode = updateKeysAndLinksStatements(node, internalStatements); + } else if (internalStatements[node.name.text]) { + updatedNode = updateModuleWithInternalStatements(node, internalStatements); + } else if (node.name.text.endsWith("static_highlight")) { + if (node.body && ts.isModuleBlock(node.body)) { + const newBody = ts.factory.createModuleBlock(node.body.statements.filter(statement => { + return !ts.isExportAssignment(statement); + })); + updatedNode = ts.factory.updateModuleDeclaration(node, node.modifiers, node.name, newBody); + } + } + } + // Fix wrong interface and class heritage clauses + else if (ts.isInterfaceDeclaration(node) && node.heritageClauses) { + return fixWrongInterfaces(node, context); + } else if (ts.isClassDeclaration(node) && node.heritageClauses) { + return fixWrongHeritageClauses(node, context, checker); + } + return ts.visitEachChild(updatedNode, visit, context); + }; + + return ts.visitNode(sourceFile, visit); + }; + } + + function pathBasedTransformer(context) { + return (sourceFile) => { + const moduleOutputs = {}; + + function visit(node) { + if (ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name)) { + let pathKey = 'modules'; + if (node.name.text === "ace-code") { + pathKey = "ace"; + if (!moduleOutputs[pathKey]) { + moduleOutputs[pathKey] = []; + } //TODO: + moduleOutputs[pathKey].push(node); + } + else { + SEPARATE_MODULES.some(module => { + if (node.name.text.includes("/" + module + "/")) { + pathKey = module; + return true; + } + }); + if (!moduleOutputs[pathKey]) { + moduleOutputs[pathKey] = []; + } + moduleOutputs[pathKey].push(node); + } + + return node; + } + return ts.visitEachChild(node, visit, context); + } + + ts.visitNode(sourceFile, visit); + + // Generate new source files for each module path + let modules = Object.keys(moduleOutputs); + + modules.forEach(key => { + const newSourceFile = context.factory.updateSourceFile(sourceFile, moduleOutputs[key]); + const dirPath = path.dirname(aceNamespacePath.replace("ace-internal", "ace")); + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath); + } + const outputName = key === "ace" ? `${dirPath}/ace.d.ts` : `${dirPath}/types/ace-${key}.d.ts`; + finalDeclarations.push(outputName); + + const printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed}, { + substituteNode(hint, node) { + if (ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name) && node.name.text === "ace-code/src/ext/textarea") { + return ts.factory.createNotEmittedStatement(node); + } else + // remove all private members + if (ts.isMethodDeclaration(node) || ts.isMethodSignature(node) || ts.isPropertyDeclaration(node) + || ts.isPropertySignature(node)) { + const isPrivate = node.modifiers?.some( + modifier => modifier.kind === ts.SyntaxKind.PrivateKeyword); + + const startsWithDollar = ts.isIdentifier(node.name) && /^[$_]/.test(node.name.text); + + if (isPrivate || startsWithDollar || hasInternalTag(node)) { + return ts.factory.createNotEmittedStatement(node); + } + } + else if (ts.isVariableStatement(node)) { + if (node.text && node.getText().indexOf("export const $") > -1) { + return ts.factory.createNotEmittedStatement(node); + } + // Remove variable statements like 'const {any_identifier}_base: undefined;' + const declarations = node.declarationList.declarations; + + // Filter out declarations that match the pattern + const filteredDeclarations = declarations.filter(declaration => { + if (ts.isIdentifier(declaration.name) && /_base\w*$/.test(declaration.name.text) + && /:\s*undefined$/.test(declaration.getText())) { + return false; + } + return true; + }); + + if (filteredDeclarations.length === 0) { + return ts.factory.createNotEmittedStatement(node); + } + else if (filteredDeclarations.length < declarations.length) { + return ts.factory.updateVariableStatement(node, node.modifiers, + ts.factory.updateVariableDeclarationList(node.declarationList, filteredDeclarations) + ); + } + } + //remove empty exports + else if (ts.isExportDeclaration(node) && /export\s*{\s*}/.test(node.getText())) { + return ts.factory.createNotEmittedStatement(node); + } + } + }); + let output = printer.printFile(newSourceFile); + if (key === "ace") { + let referencePaths = modules.filter((el) => el != "ace").map((el) => { + return `/// `; + }); + let allReferences = referencePaths.join("\n") + "\n/// \n"; + output = allReferences + output; + } + output = correctImportStatements(output); + output = cleanComments(output); + output = formatDts(outputName, output); + output = AUTO_GENERATED_HEADER + output; + fs.writeFileSync(outputName, output); + }); + + return sourceFile; + }; + } + + const sourceCode = program.getSourceFile(temporaryName); + const result = ts.transform(sourceCode, [transformer, pathBasedTransformer]); + + result.dispose(); + + checkFinalDeclaration(finalDeclarations); +} + +/** + * Corrects the import statements in the provided text by replacing the old-style + * `require()` imports with modern ES6 `import` statements. + */ +function correctImportStatements(text) { + text = text.replace( + /import\s*\w+_\d+\s*=\s*require\(([\w\/"-]+)\);?.\s*import\s*(\w+)\s*=\s*\w+_\d+\.(\w+);?/gs, + (match, path, importName, exportName) => { + if (importName !== exportName) { + return `import {${exportName} as ${importName}} from ${path};`; + } + return `import {${exportName}} from ${path};`; + } + ); + return text; +} + +function cleanComments(text) { + text = text.replace(/^\s*\*\s*@(param|template|returns?|this|typedef)\s*({.+})?(\s*\[?[$\w]+\]?)?\s*$/gm, ''); + text = text.replace(/@type\s*({.+})/g, ''); + text = text.replace(/\/\*(\s|\*)*\*\//g, ''); + text = text.replace(/^\s*[\r\n]/gm, ''); + + return text; +} + +function hasInternalTag(node) { + const sourceFile = node.getSourceFile(); + if (!sourceFile) return false; + + const jsDocs = ts.getJSDocTags(node).filter(tag => tag.tagName.text === 'internal'); + return jsDocs.length > 0; +} + +function createMinimalLanguageServiceHost() { + return { + files: {}, + addFile(fileName, text) { + this.files[fileName] = ts.ScriptSnapshot.fromString(text); + }, + "getCompilationSettings": function () { + return ts.getDefaultCompilerOptions(); + }, + "getScriptFileNames": function () { + return Object.keys(this.files); + }, + "getScriptVersion": function (_fileName) { + return "0"; + }, + "getScriptSnapshot": function (fileName) { + return this.files[fileName]; + }, + "getCurrentDirectory": function () { + return ""; + } + }; + +} + +function formatDts(filename, text) { + var host = createMinimalLanguageServiceHost(); + host.addFile(filename, text); + const languageService = ts.createLanguageService(host); + let formatEdits = languageService.getFormattingEditsForDocument(filename, defaultFormatCodeSettings); + formatEdits + .sort((a, b) => a.span.start - b.span.start) + .reverse() + .forEach(edit => { + const head = text.slice(0, edit.span.start); + const tail = text.slice(edit.span.start + edit.span.length); + text = `${head}${edit.newText}${tail}`; + }); + return text; +} + + +/** + * @param {string[]} declarationNames + */ +function checkFinalDeclaration(declarationNames) { + const program = ts.createProgram(declarationNames, { + noEmit: true, + target: ts.ScriptTarget.ES2019, + lib: ["lib.es2019.d.ts", "lib.dom.d.ts"] + }); + const diagnostics = ts.getPreEmitDiagnostics(program); + + diagnostics.forEach(diagnostic => { + if (diagnostic.file) { + const { + line, + character + } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); + const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); + console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`); + } + else { + console.log(ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')); + } + }); +} + +/** + * Collect statements (interfaces and function declarations) from the ace-internal. + * @param {string} aceNamespacePath + */ +function collectStatements(aceNamespacePath) { + const program = ts.createProgram([aceNamespacePath], { + noEmit: true + }); + const sourceFile = program.getSourceFile(aceNamespacePath); + const result = {}; + const printer = ts.createPrinter(); + let packageName = "ace-code"; + + function visit(node) { + if (node && ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name)) { + let nodes = []; + if (node.body && ts.isModuleBlock(node.body)) { + ts.forEachChild(node.body, (child) => { + if (ts.isInterfaceDeclaration(child) || ts.isFunctionDeclaration(child)) nodes.push(child); + }); + } + if (nodes.length > 0) { + const interfaceStrings = nodes.map( + interfaceNode => printer.printNode(ts.EmitHint.Unspecified, interfaceNode, sourceFile)); + + let concatenatedInterfaceStrings = interfaceStrings.join('\n\n'); + let identifiers = concatenatedInterfaceStrings.match(/Ace\.[\w]+ 0) { + identifiers = [...new Set(identifiers)]; + let importAlias = ''; + identifiers.forEach(identifier => { + let typeName = identifier.replace("Ace.", ""); + + if (typeName.includes("<")) { + typeName = typeName + "T>"; + } + importAlias += "type " + typeName + " = import(\"" + packageName + "\").Ace." + typeName + + ";\n\n"; + }); + concatenatedInterfaceStrings = "namespace Ace {" + importAlias + "}" + concatenatedInterfaceStrings; + } + + const newSourceFile = ts.createSourceFile( + 'temp.d.ts', concatenatedInterfaceStrings, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS); + nodes = newSourceFile.statements; + } + result[node.name.text.replace("./", packageName + "/")] = nodes; + } + ts.forEachChild(node, visit); + } + + visit(sourceFile); + + return result; +} + +/** + * @param {string} aceNamespacePath + * @return {string} + */ +function cloneAceNamespace(aceNamespacePath) { + + const program = ts.createProgram([aceNamespacePath], { + noEmit: true + }); + const sourceFile = program.getSourceFile(aceNamespacePath); + if (!sourceFile) { + throw new Error("Could not find ace.d.ts"); + } + const printer = ts.createPrinter(); + for (let i = 0; i < sourceFile.statements.length; i++) { + const node = sourceFile.statements[i]; + if (ts.isModuleDeclaration(node) && node.name.text == "Ace") { + let aceModule = printer.printNode(ts.EmitHint.Unspecified, node, sourceFile); + aceModule = aceModule.replace(/"\.\/src/g, "\"ace-code/src"); + aceModule = '\n' + aceModule + '\n'; + return aceModule; + } + } +} + +/** + * @param {string} [aceNamespacePath] + */ +function generateDeclaration(aceNamespacePath) { + if (!aceNamespacePath) { + aceNamespacePath = __dirname + "/../ace-internal.d.ts"; + } + const excludeDir = "src/mode"; //TODO: remove, when modes are ES6 + + let data = generateInitialDeclaration(excludeDir); + let packageName = "ace-code"; + + let updatedContent = data.replace(/(declare module ")/g, "$1" + packageName + "/src/"); + + updatedContent = updatedContent.replace(/(require\(")/g, "$1" + packageName + "/src/"); + updatedContent = updatedContent.replace(/(import\(")[./]*ace(?:\-internal)?("\).Ace)/g, "$1" + packageName + "$2"); + updatedContent = updatedContent.replace(/(import\(")(?:[./]*)(?!(?:ace\-code))/g, "$1" + packageName + "/src/"); + updatedContent = updatedContent.replace(/ace\-(?:code|builds)(\/src)?\/ace(?:\-internal)?/g, packageName); + let aceModule = cloneAceNamespace(aceNamespacePath); + + updatedContent = updatedContent.replace(/(declare\s+module\s+"ace-(?:code|builds)"\s+{)/, "$1" + aceModule); + updatedContent = updatedContent.replace(/(?:export)?\snamespace(?!\sAce)/g, "export namespace"); + fixDeclaration(updatedContent, aceNamespacePath); +} + +/** + * Updates the declaration module names in the provided content. + * This function replaces references to "ace-code" with "ace-builds" and "ace-builds-internal" as appropriate. + * + * @param {string} content - The content to update. + * @returns {string} The updated content with the module names replaced. + */ +function updateDeclarationModuleNames(content) { + let output = content.replace( + /ace\-code(?:\/src)?\/(mode(?!\/(?:matching_brace_outdent|matching_parens_outdent|behaviour|folding))|theme|ext|keybinding|snippets)\//g, + "ace-builds/src-noconflict/$1-" + ); + output = output.replace(/"ace\-code"/g, "\"ace-builds\""); + output = output.replace(/ace\-code(?:\/src)?/g, "ace-builds-internal"); + return output; +} + + +if (!module.parent) { + require("./modes-declaration-generator"); + generateDeclaration(); +} +else { + exports.generateDeclaration = generateDeclaration; + exports.updateDeclarationModuleNames = updateDeclarationModuleNames; + exports.SEPARATE_MODULES = SEPARATE_MODULES; +} diff --git a/tool/modes-declaration-generator.js b/tool/modes-declaration-generator.js index 372a5f818e1..8a326a9c1bb 100644 --- a/tool/modes-declaration-generator.js +++ b/tool/modes-declaration-generator.js @@ -100,7 +100,8 @@ function getExportType(exportName) { aceType = "Outdent"; } - return ts.factory.createImportTypeNode(ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(".")), + return ts.factory.createImportTypeNode( + ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral("ace-code")), undefined, ts.factory.createQualifiedName(ts.factory.createIdentifier("Ace"), ts.factory.createIdentifier(aceType)), undefined, false diff --git a/tool/test-npm-package.sh b/tool/test-npm-package.sh new file mode 100755 index 00000000000..abbe623b48e --- /dev/null +++ b/tool/test-npm-package.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -euxo pipefail + +# Navigate to the ace repository root +cd "$(dirname "$0")/.." + +# npm pack the ace repository +npm pack + +rm -f ace-code-latest.tgz + +# Get the name of the packed file +PACKAGE_FILE=$(ls ace-*.tgz | sort -V | tail -n 1) + +mv "$PACKAGE_FILE" ace-code-latest.tgz + + +# Install the ace package from the npm pack result +# npm install "../../$PACKAGE_FILE" + +cd demo/test_package + +# Clean up previous installation +rm -rf node_modules/ace-code +rm -f package-lock.json + +# Install TypeScript +npm install + +# Run TypeScript type checking +npm run build +npm run test + +# Clean up +cd ../.. +rm ace-code-latest.tgz diff --git a/tsconfig.json b/tsconfig.json index 2f50ebab64c..dee9e071dae 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,8 +8,7 @@ "allowJs": true, "checkJs": true, "declaration": true, - "emitDeclarationOnly": true, - "outFile": "./types/index.d.ts" + "noEmit": true, }, "exclude": [ "node_modules", @@ -21,10 +20,12 @@ "src/keyboard/vscode.js", "src/mode", "./ace-internal.d.ts", + "./ace-modes.d.ts", "src/**/* *" ], "include": [ "./src/**/*", - "./ace.d.ts" + "./ace.d.ts", + "./types/ace_*.d.ts" ] } diff --git a/types/ace-ext.d.ts b/types/ace-ext.d.ts new file mode 100644 index 00000000000..984dcdce743 --- /dev/null +++ b/types/ace-ext.d.ts @@ -0,0 +1,610 @@ +/* This file is generated using `npm run update-types` */ + +declare module "ace-code/src/ext/command_bar" { + /** + * Displays a command tooltip above the currently active line selection, with clickable elements. + * + * Internally it is a composite of two tooltips, one for the main tooltip and one for the + * overflowing commands. + * The commands are added sequentially in registration order. + * When attached to an editor, it is either always shown or only when the active line is hovered + * with mouse, depending on the alwaysShow property. + */ + export class CommandBarTooltip { + constructor(parentNode: HTMLElement, options?: Partial); + parentNode: HTMLElement; + tooltip: Tooltip; + moreOptions: Tooltip; + maxElementsOnTooltip: number; + eventListeners: {}; + elements: {}; + commands: {}; + tooltipEl: any[] | HTMLElement | Text; + moreOptionsEl: any[] | HTMLElement | Text; + /** + * Registers a command on the command bar tooltip. + * + * The commands are added in sequential order. If there is not enough space on the main + * toolbar, the remaining elements are added to the overflow menu. + * + */ + registerCommand(id: string, command: TooltipCommand): void; + isShown(): boolean; + isMoreOptionsShown(): boolean; + getAlwaysShow(): boolean; + /** + * Sets the display mode of the tooltip + * + * When true, the tooltip is always displayed while it is attached to an editor. + * When false, the tooltip is displayed only when the mouse hovers over the active editor line. + * + */ + setAlwaysShow(alwaysShow: boolean): void; + /** + * Attaches the clickable command bar tooltip to an editor + * + * Depending on the alwaysShow parameter it either displays the tooltip immediately, + * or subscribes to the necessary events to display the tooltip on hover. + * + */ + attach(editor: Editor): void; + editor: import("ace-code/src/editor").Editor; + /** + * Updates the position of the command bar tooltip. It aligns itself above the active line in the editor. + */ + updatePosition(): void; + /** + * Updates each command element in the tooltip. + * + * This is automatically called on certain events, but can be called manually as well. + */ + update(): void; + /** + * Detaches the tooltip from the editor. + */ + detach(): void; + destroy(): void; + } + export type Editor = import("ace-code/src/editor").Editor; + export type TooltipCommand = import("ace-code").Ace.TooltipCommand; + import { Tooltip } from "ace-code/src/tooltip"; + export var TOOLTIP_CLASS_NAME: string; + export var BUTTON_CLASS_NAME: string; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + } + export interface CommandBarTooltip extends Ace.EventEmitter { + } +} +declare module "ace-code/src/ext/language_tools" { + export function setCompleters(val: any): void; + export function addCompleter(completer: any): void; + import textCompleter = require("ace-code/src/autocomplete/text_completer"); + export var keyWordCompleter: import("ace-code").Ace.Completer; + export var snippetCompleter: import("ace-code").Ace.Completer; + export { textCompleter }; +} +declare module "ace-code/src/ext/inline_autocomplete" { + /** + * This class controls the inline-only autocompletion components and their lifecycle. + * This is more lightweight than the popup-based autocompletion, as it can only work with exact prefix matches. + * There is an inline ghost text renderer and an optional command bar tooltip inside. + */ + export class InlineAutocomplete { + constructor(editor: Editor); + editor: Editor; + keyboardHandler: HashHandler; + blurListener(e: any): void; + changeListener(e: any): void; + changeTimer: { + (timeout?: number): void; + delay(timeout?: number): void; + schedule: any; + call(): void; + cancel(): void; + isPending(): any; + }; + getInlineRenderer(): AceInline; + inlineRenderer: AceInline; + getInlineTooltip(): CommandBarTooltip; + inlineTooltip: CommandBarTooltip; + /** + * This function is the entry point to the class. This triggers the gathering of the autocompletion and displaying the results; + */ + show(options: import("ace-code").Ace.CompletionOptions): void; + activated: boolean; + insertMatch(): boolean; + goTo(where: import("ace-code").Ace.InlineAutocompleteAction): void; + getLength(): any; + getData(index?: number): import("ace-code").Ace.Completion | undefined; + getIndex(): number; + isOpen(): boolean; + setIndex(value: number): void; + getCompletionProvider(initialPosition: any): CompletionProvider; + completionProvider: CompletionProvider; + updateCompletions(options?: import("ace-code").Ace.CompletionOptions): void; + base: import("ace-code/src/anchor").Anchor; + completions: FilteredList; + detach(): void; + destroy(): void; + updateDocTooltip(): void; + commands: { + [key: string]: import("ace-code").Ace.Command; + }; + } + export namespace InlineAutocomplete { + function _for(editor: any): any; + export { _for as for }; + export namespace startCommand { + let name: string; + function exec(editor: any, options: any): void; + export namespace bindKey { + let win: string; + let mac: string; + } + } + /** + * Factory method to create a command bar tooltip for inline autocomplete. + * + * @param {HTMLElement} parentEl The parent element where the tooltip HTML elements will be added. + * @returns {CommandBarTooltip} The command bar tooltip for inline autocomplete + */ + export function createInlineTooltip(parentEl: HTMLElement): CommandBarTooltip; + } + import { Editor } from "ace-code/src/editor"; + import { HashHandler } from "ace-code/src/keyboard/hash_handler"; + import { AceInline } from "ace-code/src/autocomplete/inline"; + import { CommandBarTooltip } from "ace-code/src/ext/command_bar"; + import { CompletionProvider } from "ace-code/src/autocomplete"; + import { FilteredList } from "ace-code/src/autocomplete"; +} +declare module "ace-code/src/ext/searchbox-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/ext/searchbox" { + export function Search(editor: Editor, isReplace?: boolean): void; + export type Editor = import("ace-code/src/editor").Editor; + export class SearchBox { + constructor(editor: Editor, range?: never, showReplaceForm?: never); + activeInput: any; + element: any; + setSession(e: any): void; + setEditor(editor: Editor): void; + editor: Editor; + searchRange: any; + searchBox: HTMLElement; + replaceBox: HTMLElement; + searchOption: HTMLInputElement; + replaceOption: HTMLInputElement; + regExpOption: HTMLInputElement; + caseSensitiveOption: HTMLInputElement; + wholeWordOption: HTMLInputElement; + searchInput: HTMLInputElement; + replaceInput: HTMLInputElement; + searchCounter: HTMLElement; + setSearchRange(range: any): void; + searchRangeMarker: number; + highlight(re?: RegExp): void; + find(skipCurrent: boolean, backwards: boolean, preventScroll?: any): void; + updateCounter(): void; + findNext(): void; + findPrev(): void; + findAll(): void; + replace(): void; + replaceAndFindNext(): void; + replaceAll(): void; + hide(): void; + active: boolean; + show(value: string, isReplace?: boolean): void; + isFocused(): boolean; + } + import { HashHandler } from "ace-code/src/keyboard/hash_handler"; +} +declare module "ace-code/src/ext/elastic_tabstops_lite" { + export class ElasticTabstopsLite { + constructor(editor: Editor); + onAfterExec: () => void; + onExec: () => void; + onChange: (delta: any) => void; + processRows(rows: number[]): void; + } + import { Editor } from "ace-code/src/editor"; +} +declare module "ace-code/src/ext/error_marker" { + export function showErrorMarker(editor: import("ace-code/src/editor").Editor, dir: number): void; +} +declare module "ace-code/src/ext/beautify" { + export const singletonTags: string[]; + export const blockTags: string[]; + export const formatOptions: { + lineBreaksAfterCommasInCurlyBlock?: boolean; + }; + export function beautify(session: import("ace-code/src/edit_session").EditSession): void; + export const commands: { + name: string; + description: string; + exec: (editor: any) => void; + bindKey: string; + }[]; +} +declare module "ace-code/src/ext/code_lens" { + export function setLenses(session: EditSession, lenses: import("ace-code").Ace.CodeLense[]): number; + export function registerCodeLensProvider(editor: import("ace-code/src/editor").Editor, codeLensProvider: import("ace-code").Ace.CodeLenseProvider): void; + export function clear(session: EditSession): void; + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type VirtualRenderer = import("ace-code/src/virtual_renderer").VirtualRenderer & { + }; + import { Editor } from "ace-code/src/editor"; +} +declare module "ace-code/src/ext/emmet" { + export const commands: HashHandler; + export function runEmmetCommand(editor: Editor): number | boolean; + export function updateCommands(editor: Editor, enabled?: boolean): void; + export function isSupportedMode(mode: any): boolean; + export function isAvailable(editor: Editor, command: string): boolean; + export function load(cb: any): boolean; + export function setCore(e: any): void; + import { HashHandler } from "ace-code/src/keyboard/hash_handler"; + import { Editor } from "ace-code/src/editor"; + /** + * Implementation of {@link IEmmetEditor} interface for Ace + */ + export class AceEmmetEditor { + setupContext(editor: Editor): void; + ace: Editor; + indentation: string; + /** + * Returns character indexes of selected text: object with start + * and end properties. If there's no selection, should return + * object with start and end properties referring + * to current caret position + * @example + * var selection = editor.getSelectionRange(); + * alert(selection.start + ', ' + selection.end); + */ + getSelectionRange(): any; + /** + * Creates selection from start to end character + * indexes. If end is ommited, this method should place caret + * and start index + * @example + * editor.createSelection(10, 40); + * + * //move caret to 15th character + * editor.createSelection(15); + */ + createSelection(start: number, end?: number): void; + /** + * Returns current line's start and end indexes as object with start + * and end properties + * @example + * var range = editor.getCurrentLineRange(); + * alert(range.start + ', ' + range.end); + */ + getCurrentLineRange(): any; + /** + * Returns current caret position + */ + getCaretPos(): number | null; + /** + * Set new caret position + * @param {Number} index Caret position + */ + setCaretPos(index: number): void; + /** + * Returns content of current line + */ + getCurrentLine(): string; + /** + * Replace editor's content or it's part (from start to + * end index). If value contains + * caret_placeholder, the editor will put caret into + * this position. If you skip start and end + * arguments, the whole target's content will be replaced with + * value. + * + * If you pass start argument only, + * the value will be placed at start string + * index of current content. + * + * If you pass start and end arguments, + * the corresponding substring of current target's content will be + * replaced with value. + * @param {String} value Content you want to paste + * @param {Number} [start] Start index of editor's content + * @param {Number} [end] End index of editor's content + * @param {Boolean} [noIndent] Do not auto indent value + */ + replaceContent(value: string, start?: number, end?: number, noIndent?: boolean): void; + /** + * Returns editor's content + */ + getContent(): string; + /** + * Returns current editor's syntax mode + */ + getSyntax(): string; + /** + * Returns current output profile name (@see emmet#setupProfile) + */ + getProfileName(): string; + /** + * Ask user to enter something + * @param {String} title Dialog title + * @return {String} Entered data + * @since 0.65 + */ + prompt(title: string): string; + /** + * Returns current selection + * @since 0.65 + */ + getSelection(): string; + /** + * Returns current editor's file path + * @since 0.65 + */ + getFilePath(): string; + } +} +declare module "ace-code/src/ext/hardwrap" { + export function hardWrap(editor: import("ace-code/src/editor").Editor, options: import("ace-code").Ace.HardWrapOptions): void; + import { Editor } from "ace-code/src/editor"; +} +declare module "ace-code/src/ext/menu_tools/settings_menu.css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/ext/menu_tools/overlay_page" { + export function overlayPage(editor: any, contentElement: HTMLElement, callback?: any): { + close: () => void; + setIgnoreFocusOut: (ignore: boolean) => void; + }; +} +declare module "ace-code/src/ext/menu_tools/get_editor_keyboard_shortcuts" { + export function getEditorKeybordShortcuts(editor: import("ace-code/src/editor").Editor): any[]; +} +declare module "ace-code/src/ext/keybinding_menu" { + export function init(editor: Editor): void; + import { Editor } from "ace-code/src/editor"; +} +declare module "ace-code/src/ext/linking" { } +declare module "ace-code/src/ext/modelist" { + /** + * Suggests a mode based on the file extension present in the given path + * @param {string} path The path to the file + * @returns {Mode} Returns an object containing information about the + * suggested mode. + */ + export function getModeForPath(path: string): Mode; + export var modes: any[]; + export var modesByName: {}; + class Mode { + constructor(name: string, caption: string, extensions: string); + name: string; + caption: string; + mode: string; + extensions: string; + extRe: RegExp; + supportsFile(filename: string): RegExpMatchArray; + } +} +declare module "ace-code/src/ext/themelist" { + export const themesByName: {}; + export const themes: { + caption: string; + theme: string; + isDark: boolean; + name: string; + }[]; +} +declare module "ace-code/src/ext/options" { + export class OptionPanel { + constructor(editor: Editor, element?: HTMLElement); + editor: import("ace-code/src/editor").Editor; + container: HTMLElement; + groups: any[]; + options: {}; + add(config: any): void; + render(): void; + renderOptionGroup(group: any): any[]; + renderOptionControl(key: string, option: any): any; + renderOption(key: any, option: any): (string | any[] | { + class: string; + })[]; + setOption(option: string | number | any, value: string | number | boolean): void; + getOption(option: any): any; + } + export type Editor = import("ace-code/src/editor").Editor; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + } + export interface OptionPanel extends Ace.EventEmitter { + } +} +declare module "ace-code/src/ext/prompt" { + export type PromptOptions = { + /** + * Prompt name. + */ + name: string; + /** + * Defines which part of the predefined value should be highlighted. + */ + selection: [ + number, + number + ]; + /** + * Set to true if prompt has description below input box. + */ + hasDescription: boolean; + /** + * Description below input box. + */ + prompt: string; + /** + * Placeholder for value. + */ + placeholder: string; + /** + * Set to true to keep the prompt open when focus moves to another part of the editor. + */ + ignoreFocusOut: boolean; + /** + * Function for defining list of options for value. + */ + getCompletions: Function; + /** + * Function for defining current value prefix. + */ + getPrefix: Function; + /** + * Function called when Enter is pressed. + */ + onAccept: Function; + /** + * Function called when input is added to prompt input box. + */ + onInput: Function; + /** + * Function called when Esc|Shift-Esc is pressed. + */ + onCancel: Function; + /** + * Function for defining history list. + */ + history: Function; + maxHistoryCount: number; + addToHistory: Function; + }; + export type Editor = import("ace-code/src/editor").Editor; + /** + * @property {String} name Prompt name. + * @property {String} $type Use prompt of specific type (gotoLine|commands|modes or default if empty). + * @property {[number, number]} selection Defines which part of the predefined value should be highlighted. + * @property {Boolean} hasDescription Set to true if prompt has description below input box. + * @property {String} prompt Description below input box. + * @property {String} placeholder Placeholder for value. + * @property {Object} $rules Specific rules for input like password or regexp. + * @property {Boolean} ignoreFocusOut Set to true to keep the prompt open when focus moves to another part of the editor. + * @property {Function} getCompletions Function for defining list of options for value. + * @property {Function} getPrefix Function for defining current value prefix. + * @property {Function} onAccept Function called when Enter is pressed. + * @property {Function} onInput Function called when input is added to prompt input box. + * @property {Function} onCancel Function called when Esc|Shift-Esc is pressed. + * @property {Function} history Function for defining history list. + * @property {number} maxHistoryCount + * @property {Function} addToHistory + */ + /** + * Prompt plugin is used for getting input from user. + * + * @param {Editor} editor Ouside editor related to this prompt. Will be blurred when prompt is open. + * @param {String | Partial} message Predefined value of prompt input box. + * @param {Partial} options Cusomizable options for this prompt. + * @param {Function} [callback] Function called after done. + * */ + export function prompt(editor: Editor, message: string | Partial, options: Partial, callback?: Function): any; + export namespace prompt { + function gotoLine(editor: Editor, callback?: Function): void; + function commands(editor: Editor, callback?: Function): void; + function modes(editor: Editor, callback?: Function): void; + } +} +declare module "ace-code/src/ext/rtl" { +} +declare module "ace-code/src/ext/settings_menu" { + export function init(): void; +} +declare module "ace-code/src/ext/simple_tokenizer" { + /** + * Parses provided content according to provided highlighting rules and return tokens. + * Tokens either have the className set according to Ace themes or have no className if they are just pure text tokens. + * Result is a list of list of tokens, where each line from the provided content is a separate list of tokens. + * + * @param {string} content to tokenize + * @param {import("ace-code").Ace.HighlightRules} highlightRules defining the language grammar + * @returns {import("ace-code").Ace.TokenizeResult} tokenization result containing a list of token for each of the lines from content + */ + export function tokenize(content: string, highlightRules: import("ace-code").Ace.HighlightRules): import("ace-code").Ace.TokenizeResult; +} +declare module "ace-code/src/ext/spellcheck" { + export function contextMenuHandler(e: any): void; +} +declare module "ace-code/src/ext/split" { + const _exports: typeof import("ace-code/src/split"); + export = _exports; +} +declare module "ace-code/src/ext/static-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/ext/static_highlight" { + function highlight(el: HTMLElement, opts: import("ace-code").Ace.StaticHighlightOptions, callback?: any): boolean; + export namespace highlight { + export { render, renderSync, highlight, SyntaxMode, Theme }; + } + /** + * Transforms a given input code snippet into HTML using the given mode + * + * @param {string} input Code snippet + * @param {string | SyntaxMode} mode String specifying the mode to load such as + * `ace/mode/javascript` or, a mode loaded from `/ace/mode` + * (use 'ServerSideHiglighter.getMode'). + * @param {string | Theme} theme String specifying the theme to load such as + * `ace/theme/twilight` or, a theme loaded from `/ace/theme`. + * @param {number} lineStart A number indicating the first line number. Defaults + * to 1. + * @param {boolean} disableGutter Specifies whether or not to disable the gutter. + * `true` disables the gutter, `false` enables the gutter. Defaults to `false`. + * @param {function} [callback] When specifying the mode or theme as a string, + * this method has no return value and you must specify a callback function. The + * callback will receive the rendered object containing the properties `html` + * and `css`. + * @returns {object} An object containing the properties `html` and `css`. + */ + function render(input: string, mode: string | SyntaxMode, theme: string | Theme, lineStart: number, disableGutter: boolean, callback?: Function): object; + /** + * Transforms a given input code snippet into HTML using the given mode + * @param {string} input Code snippet + * @param {SyntaxMode | string} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode') + * @returns {object} An object containing: html, css + */ + function renderSync(input: string, mode: SyntaxMode | string, theme: Theme, lineStart: any, disableGutter: boolean): object; + type SyntaxMode = import("ace-code").Ace.SyntaxMode; + type Theme = import("ace-code").Ace.Theme; +} +declare module "ace-code/src/ext/statusbar" { + export type Editor = import("ace-code/src/editor").Editor; + /** simple statusbar **/ + export class StatusBar { + constructor(editor: Editor, parentNode: HTMLElement); + element: HTMLDivElement; + updateStatus(editor: Editor): void; + } +} +declare module "ace-code/src/ext/whitespace" { + export function $detectIndentation(lines: string[], fallback?: any): { + ch?: string; + length?: number; + }; + export function detectIndentation(session: EditSession): { + ch?: string; + length?: number; + } | {}; + export function trimTrailingSpace(session: EditSession, options: { + trimEmpty?: boolean; + keepCursorPosition?: boolean; + }): void; + export function convertIndentation(session: EditSession, ch: string, len: number): void; + export function $parseStringArg(text: string): {}; + export function $parseArg(arg: any): any; + export const commands: { + name: string; + description: string; + exec: (editor: any, args: any) => void; + }[]; + export type EditSession = import("ace-code/src/edit_session").EditSession; +} diff --git a/types/ace-lib.d.ts b/types/ace-lib.d.ts new file mode 100644 index 00000000000..6135bd4d95b --- /dev/null +++ b/types/ace-lib.d.ts @@ -0,0 +1,221 @@ +/* This file is generated using `npm run update-types` */ + +declare module "ace-code/src/lib/useragent" { + export namespace OS { + let LINUX: string; + let MAC: string; + let WINDOWS: string; + } + export function getOS(): string; + export const isWin: boolean; + export const isMac: boolean; + export const isLinux: boolean; + export const isIE: number; + export const isOldIE: boolean; + export const isGecko: any; + export const isMozilla: any; + export const isOpera: boolean; + export const isWebKit: number; + export const isChrome: number; + export const isSafari: true; + export const isEdge: number; + export const isAIR: boolean; + export const isAndroid: boolean; + export const isChromeOS: boolean; + export const isIOS: boolean; + export const isMobile: boolean; +} +declare module "ace-code/src/lib/dom" { + export function buildDom(arr: any, parent?: HTMLElement, refs?: any): HTMLElement | Text | any[]; + export function getDocumentHead(doc?: Document): HTMLHeadElement | HTMLElement; + export function createElement(tag: T | string, ns?: string): HTMLElementTagNameMap[T]; + export function removeChildren(element: HTMLElement): void; + export function createTextNode(textContent: string, element?: HTMLElement): Text; + export function createFragment(element?: HTMLElement): DocumentFragment; + export function hasCssClass(el: HTMLElement, name: string): boolean; + export function addCssClass(el: HTMLElement, name: string): void; + export function removeCssClass(el: HTMLElement, name: string): void; + export function toggleCssClass(el: HTMLElement, name: string): boolean; + export function setCssClass(node: HTMLElement, className: string, include: boolean): void; + export function hasCssString(id: string, doc?: Document): boolean; + export function removeElementById(id: string, doc?: Document): void; + export function useStrictCSP(value: any): void; + export function importCssStylsheet(uri: string, doc?: Document): void; + export function scrollbarWidth(doc?: Document): number; + export function computedStyle(element: Element, style?: any): Partial; + export function setStyle(styles: CSSStyleDeclaration, property: string, value: string): void; + export const HAS_CSS_ANIMATION: boolean; + export const HAS_CSS_TRANSFORMS: boolean; + export const HI_DPI: boolean; + export function translate(element: any, tx: any, ty: any): void; + export function importCssString(cssText: string, id?: string, target?: any): number; +} +declare module "ace-code/src/lib/oop" { + export function inherits(ctor: any, superCtor: any): void; + export function mixin(obj: T, mixin: any): T & any; + export function implement(proto: T, mixin: any): T & any; +} +declare module "ace-code/src/lib/deep_copy" { + export function deepCopy(obj: any): any; +} +declare module "ace-code/src/lib/lang" { + export function last(a: any): any; + export function stringReverse(string: string): string; + export function stringRepeat(string: any, count: any): string; + export function stringTrimLeft(string: any): any; + export function stringTrimRight(string: any): any; + export function copyObject(obj: T): T; + export function copyArray(array: any): any[]; + export const deepCopy: (obj: any) => any; + export function arrayToMap(arr: any): {}; + export function createMap(props: any): any; + export function arrayRemove(array: any, value: any): void; + export function escapeRegExp(str: any): any; + export function escapeHTML(str: any): string; + export function getMatchOffsets(string: any, regExp: any): any[]; + export function deferredCall(fcn: any): { + (timeout: any): any; + schedule: any; + call(): any; + cancel(): any; + isPending(): any; + }; + export function delayedCall(fcn: any, defaultTimeout?: number): { + (timeout?: number): void; + delay(timeout?: number): void; + schedule: any; + call(): void; + cancel(): void; + isPending(): any; + }; + export function supportsLookbehind(): boolean; + export function skipEmptyMatch(line: any, last: any, supportsUnicodeFlag: any): 1 | 2; +} +declare module "ace-code/src/lib/keys" { + export function keyCodeToString(keyCode: number): string; +} +declare module "ace-code/src/lib/event" { + export function addListener(elem: any, type: string, callback: any, destroyer?: any): void; + export function removeListener(elem: any, type: any, callback: any): void; + export function stopEvent(e: any): boolean; + export function stopPropagation(e: any): void; + export function preventDefault(e: any): void; + export function getButton(e: any): any; + export function capture(el: any, eventHandler: any, releaseCaptureHandler: any): (e: any) => void; + export function addMouseWheelListener(el: any, callback: any, destroyer?: any): void; + export function addMultiMouseDownListener(elements: any, timeouts: any, eventHandler: any, callbackName: any, destroyer?: any): void; + export function getModifierString(e: KeyboardEvent | MouseEvent): any; + export function addCommandKeyListener(el: EventTarget, callback: (e: KeyboardEvent, hashId: number, keyCode: number) => void, destroyer?: any): void; + export function nextTick(callback: any, win: any): void; + export const $idleBlocked: boolean; + export function onIdle(cb: any, timeout: any): number; + export const $idleBlockId: number; + export function blockIdle(delay: any): void; + export const nextFrame: any; +} +declare module "ace-code/src/lib/event_emitter" { + export var EventEmitter: any; +} +declare module "ace-code/src/lib/net" { + export function get(url: any, callback: any): void; + export function loadScript(path: any, callback: any): void; + export function qualifyURL(url: any): string; +} +declare module "ace-code/src/lib/report_error" { + export function reportError(msg: any, data: any): void; +} +declare module "ace-code/src/lib/default_english_messages" { + export var defaultEnglishMessages: { + "autocomplete.popup.aria-roledescription": string; + "autocomplete.popup.aria-label": string; + "autocomplete.popup.item.aria-roledescription": string; + "autocomplete.loading": string; + "editor.scroller.aria-roledescription": string; + "editor.scroller.aria-label": string; + "editor.gutter.aria-roledescription": string; + "editor.gutter.aria-label": string; + "error-marker.good-state": string; + "prompt.recently-used": string; + "prompt.other-commands": string; + "prompt.no-matching-commands": string; + "search-box.find.placeholder": string; + "search-box.find-all.text": string; + "search-box.replace.placeholder": string; + "search-box.replace-next.text": string; + "search-box.replace-all.text": string; + "search-box.toggle-replace.title": string; + "search-box.toggle-regexp.title": string; + "search-box.toggle-case.title": string; + "search-box.toggle-whole-word.title": string; + "search-box.toggle-in-selection.title": string; + "search-box.search-counter": string; + "text-input.aria-roledescription": string; + "text-input.aria-label": string; + "gutter.code-folding.range.aria-label": string; + "gutter.code-folding.closed.aria-label": string; + "gutter.code-folding.open.aria-label": string; + "gutter.code-folding.closed.title": string; + "gutter.code-folding.open.title": string; + "gutter.annotation.aria-label.error": string; + "gutter.annotation.aria-label.warning": string; + "gutter.annotation.aria-label.info": string; + "inline-fold.closed.title": string; + "gutter-tooltip.aria-label.error.singular": string; + "gutter-tooltip.aria-label.error.plural": string; + "gutter-tooltip.aria-label.warning.singular": string; + "gutter-tooltip.aria-label.warning.plural": string; + "gutter-tooltip.aria-label.info.singular": string; + "gutter-tooltip.aria-label.info.plural": string; + "gutter.annotation.aria-label.security": string; + "gutter.annotation.aria-label.hint": string; + "gutter-tooltip.aria-label.security.singular": string; + "gutter-tooltip.aria-label.security.plural": string; + "gutter-tooltip.aria-label.hint.singular": string; + "gutter-tooltip.aria-label.hint.plural": string; + }; +} +declare module "ace-code/src/lib/app_config" { + export class AppConfig { + defineOptions(obj: any, path: string, options: { + [key: string]: any; + }): import("ace-code").Ace.AppConfig; + resetOptions(obj: any): void; + setDefaultValue(path: string, name: string, value: any): boolean; + setDefaultValues(path: string, optionHash: { + [key: string]: any; + }): void; + setMessages(value: any, options?: { + placeholders?: "dollarSigns" | "curlyBrackets"; + }): void; + nls(key: string, defaultString: string, params?: { + [x: string]: any; + }): any; + warn: typeof warn; + reportError: (msg: any, data: any) => void; + } + function warn(message: any, ...args: any[]): void; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + } + export interface AppConfig extends Ace.EventEmitter { + } +} +declare module "ace-code/src/lib/scroll" { + export function preventParentScroll(event: any): void; +} +declare module "ace-code/src/lib/bidiutil" { + export const ON_R: 3; + export const AN: 4; + export const R_H: 5; + export const B: 6; + export const RLE: 7; + export const DOT: "·"; + export function doBidiReorder(text: string, textCharTypes: any[], isRtl: boolean): any; + export function hasBidiCharacters(text: string, textCharTypes: any[]): boolean; + export function getVisualFromLogicalIdx(logIdx: number, rowMap: any): number; + export var L: number; + export var R: number; + export var EN: number; +} +declare module "ace-code/src/lib/fixoldbrowsers" { +} diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts new file mode 100644 index 00000000000..dcd0faae0cd --- /dev/null +++ b/types/ace-modules.d.ts @@ -0,0 +1,4745 @@ +/* This file is generated using `npm run update-types` */ + +declare module "ace-code/src/layer/font_metrics" { + export class FontMetrics { + constructor(parentEl: HTMLElement); + el: HTMLDivElement; + checkForSizeChanges(size: any): void; + charSizes: any; + allowBoldFonts: boolean; + setPolling(val: boolean): void; + getCharacterWidth(ch: any): any; + destroy(): void; + els: any[] | HTMLElement | Text; + transformCoordinates(clientPos: any, elPos: any): any[]; + } + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + } + export interface FontMetrics extends Ace.EventEmitter { + } +} +declare module "ace-code/src/apply_delta" { + export function applyDelta(docLines: string[], delta: import("ace-code").Ace.Delta, doNotValidate?: any): void; +} +declare module "ace-code/src/document" { + /** + * Contains the text of the document. Document can be attached to several [[EditSession `EditSession`]]s. + * At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index. + **/ + export class Document { + /** + * + * Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty. + * @param {String | String[]} textOrLines text The starting text + **/ + constructor(textOrLines: string | string[]); + /** + * Replaces all the lines in the current `Document` with the value of `text`. + * + * @param {String} text The text to use + **/ + setValue(text: string): void; + /** + * Returns all the lines in the document as a single string, joined by the new line character. + **/ + getValue(): string; + /** + * Creates a new `Anchor` to define a floating point in the document. + * @param {Number} row The row number to use + * @param {Number} column The column number to use + **/ + createAnchor(row: number, column: number): Anchor; + /** + * Returns the newline character that's being used, depending on the value of `newLineMode`. + * @returns {String} If `newLineMode == windows`, `\r\n` is returned. + * If `newLineMode == unix`, `\n` is returned. + * If `newLineMode == auto`, the value of `autoNewLine` is returned. + * + **/ + getNewLineCharacter(): string; + /** + * [Sets the new line mode.]{: #Document.setNewLineMode.desc} + * @param {NewLineMode} newLineMode [The newline mode to use; can be either `windows`, `unix`, or `auto`] + **/ + setNewLineMode(newLineMode: NewLineMode): void; + /** + * Returns the type of newlines being used; either `windows`, `unix`, or `auto` + **/ + getNewLineMode(): NewLineMode; + /** + * Returns `true` if `text` is a newline character (either `\r\n`, `\r`, or `\n`). + * @param {String} text The text to check + **/ + isNewLine(text: string): boolean; + /** + * Returns a verbatim copy of the given line as it is in the document + * @param {Number} row The row index to retrieve + **/ + getLine(row: number): string; + /** + * Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`. + * @param {Number} firstRow The first row index to retrieve + * @param {Number} lastRow The final row index to retrieve + **/ + getLines(firstRow: number, lastRow: number): string[]; + /** + * Returns all lines in the document as string array. + **/ + getAllLines(): string[]; + /** + * Returns the number of rows in the document. + **/ + getLength(): number; + /** + * Returns all the text within `range` as a single string. + * @param {IRange} range The range to work with. + * + **/ + getTextRange(range: IRange): string; + /** + * Returns all the text within `range` as an array of lines. + * @param {IRange} range The range to work with. + * + **/ + getLinesForRange(range: IRange): string[]; + /** + * @deprecated + */ + insertLines(row: any, lines: any): void; + /** + * @deprecated + */ + removeLines(firstRow: any, lastRow: any): string[]; + /** + * @deprecated + */ + insertNewLine(position: any): Point; + /** + * Inserts a block of `text` at the indicated `position`. + * @param {Point} position The position to start inserting at; it's an object that looks like `{ row: row, column: column}` + * @param {String} text A chunk of text to insert + * @returns {Point} The position ({row, column}) of the last line of `text`. If the length of `text` is 0, this function simply returns `position`. + **/ + insert(position: Point, text: string): Point; + /** + * Inserts `text` into the `position` at the current row. This method also triggers the `"change"` event. + * + * This differs from the `insert` method in two ways: + * 1. This does NOT handle newline characters (single-line text only). + * 2. This is faster than the `insert` method for single-line text insertions. + * + * @param {Point} position The position to insert at; it's an object that looks like `{ row: row, column: column}` + * @param {String} text A chunk of text without new lines + * @returns {Point} Returns the position of the end of the inserted text + **/ + insertInLine(position: Point, text: string): Point; + clippedPos(row: number, column: number): Point; + clonePos(pos: Point): Point; + pos(row: number, column: number): Point; + /** + * Inserts the elements in `lines` into the document as full lines (does not merge with existing line), starting at the row index given by `row`. This method also triggers the `"change"` event. + * @param {Number} row The index of the row to insert at + * @param {string[]} lines An array of strings + **/ + insertFullLines(row: number, lines: string[]): void; + /** + * Inserts the elements in `lines` into the document, starting at the position index given by `row`. This method also triggers the `"change"` event. + * @param {string[]} lines An array of strings + * @returns {Point} Contains the final row and column, like this: + * ``` + * {row: endRow, column: 0} + * ``` + * If `lines` is empty, this function returns an object containing the current row, and column, like this: + * ``` + * {row: row, column: 0} + * ``` + **/ + insertMergedLines(position: Point, lines: string[]): Point; + /** + * Removes the `range` from the document. + * @param {IRange} range A specified Range to remove + * @returns {Point} Returns the new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`. + **/ + remove(range: IRange): Point; + /** + * Removes the specified columns from the `row`. This method also triggers a `"change"` event. + * @param {Number} row The row to remove from + * @param {Number} startColumn The column to start removing at + * @param {Number} endColumn The column to stop removing at + * @returns {Point} Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.
    If `startColumn` is equal to `endColumn`, this function returns nothing. + **/ + removeInLine(row: number, startColumn: number, endColumn: number): Point; + /** + * Removes a range of full lines. This method also triggers the `"change"` event. + * @param {Number} firstRow The first row to be removed + * @param {Number} lastRow The last row to be removed + * @returns {String[]} Returns all the removed lines. + **/ + removeFullLines(firstRow: number, lastRow: number): string[]; + /** + * Removes the new line between `row` and the row immediately following it. This method also triggers the `"change"` event. + * @param {Number} row The row to check + * + **/ + removeNewLine(row: number): void; + /** + * Replaces a range in the document with the new `text`. + * @param {Range | IRange} range A specified Range to replace + * @param {String} text The new text to use as a replacement + * @returns {Point} Returns an object containing the final row and column, like this: + * {row: endRow, column: 0} + * If the text and range are empty, this function returns an object containing the current `range.start` value. + * If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value. + * + **/ + replace(range: Range | IRange, text: string): Point; + /** + * Applies all changes in `deltas` to the document. + * @param {Delta[]} deltas An array of delta objects (can include "insert" and "remove" actions) + **/ + applyDeltas(deltas: Delta[]): void; + /** + * Reverts all changes in `deltas` from the document. + * @param {Delta[]} deltas An array of delta objects (can include "insert" and "remove" actions) + **/ + revertDeltas(deltas: Delta[]): void; + /** + * Applies `delta` to the document. + * @param {Delta} delta A delta object (can include "insert" and "remove" actions) + **/ + applyDelta(delta: Delta, doNotValidate?: boolean): void; + /** + * Reverts `delta` from the document. + * @param {Delta} delta A delta object (can include "insert" and "remove" actions) + **/ + revertDelta(delta: Delta): void; + /** + * Converts an index position in a document to a `{row, column}` object. + * + * Index refers to the "absolute position" of a character in the document. For example: + * + * ```javascript + * var x = 0; // 10 characters, plus one for newline + * var y = -1; + * ``` + * + * Here, `y` is an index 15: 11 characters for the first row, and 5 characters until `y` in the second. + * + * @param {Number} index An index to convert + * @param {Number} [startRow=0] The row from which to start the conversion + * @returns {Point} A `{row, column}` object of the `index` position + */ + indexToPosition(index: number, startRow?: number): Point; + /** + * Converts the `{row, column}` position in a document to the character's index. + * + * Index refers to the "absolute position" of a character in the document. For example: + * + * ```javascript + * var x = 0; // 10 characters, plus one for newline + * var y = -1; + * ``` + * + * Here, `y` is an index 15: 11 characters for the first row, and 5 characters until `y` in the second. + * + * @param {Point} pos The `{row, column}` to convert + * @param {Number} [startRow=0] The row from which to start the conversion + * @returns {Number} The index position in the document + */ + positionToIndex(pos: Point, startRow?: number): number; + } + export type Delta = import("ace-code").Ace.Delta; + export type Point = import("ace-code").Ace.Point; + export type IRange = import("ace-code").Ace.IRange; + export type NewLineMode = import("ace-code").Ace.NewLineMode; + import { Anchor } from "ace-code/src/anchor"; + import { Range } from "ace-code/src/range"; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + type DocumentEvents = import("ace-code").Ace.DocumentEvents; + } + export interface Document extends Ace.EventEmitter { + } +} +declare module "ace-code/src/anchor" { + /** + * Defines a floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the anchor is updated. + **/ + export class Anchor { + /** + * Creates a new `Anchor` and associates it with a document. + * + * @param {Document} doc The document to associate with the anchor + * @param {Number|import("ace-code").Ace.Point} row The starting row position + * @param {Number} [column] The starting column position + **/ + constructor(doc: Document, row: number | import("ace-code").Ace.Point, column?: number); + /** + * Returns an object identifying the `row` and `column` position of the current anchor. + **/ + getPosition(): import("ace-code").Ace.Point; + /** + * + * Returns the current document. + **/ + getDocument(): Document; + /** + * Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not clipped. + * @param {Number} row The row index to move the anchor to + * @param {Number} column The column index to move the anchor to + * @param {Boolean} [noClip] Identifies if you want the position to be clipped + **/ + setPosition(row: number, column: number, noClip?: boolean): void; + row: any; + column: number; + /** + * When called, the `"change"` event listener is removed. + * + **/ + detach(): void; + /** + * When called, the `"change"` event listener is appended. + * @param {Document} doc The document to associate with + * + **/ + attach(doc: Document): void; + document: Document; + markerId?: number; + } + export type Document = import("ace-code/src/document").Document; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + type AnchorEvents = import("ace-code").Ace.AnchorEvents; + type Document = import("ace-code").Ace.Document; + } + export interface Anchor extends Ace.EventEmitter { + markerId?: number; + document: Ace.Document; + } +} +declare module "ace-code/src/config" { + const _exports: { + defineOptions(obj: any, path: string, options: { + [key: string]: any; + }): import("ace-code").Ace.AppConfig; + resetOptions(obj: any): void; + setDefaultValue(path: string, name: string, value: any): boolean; + setDefaultValues(path: string, optionHash: { + [key: string]: any; + }): void; + setMessages(value: any, options?: { + placeholders?: "dollarSigns" | "curlyBrackets"; + }): void; + nls(key: string, defaultString: string, params?: { + [x: string]: any; + }): any; + warn: (message: any, ...args: any[]) => void; + reportError: (msg: any, data: any) => void; + once(name: K, callback: any): void; + setDefaultHandler(name: string, callback: Function): void; + removeDefaultHandler(name: string, callback: Function): void; + on(name: K, callback: any, capturing?: boolean): any; + addEventListener(name: K, callback: any, capturing?: boolean): any; + off(name: K, callback: any): void; + removeListener(name: K, callback: any): void; + removeEventListener(name: K, callback: any): void; + removeAllListeners(name?: string): void; + /** + * @param {K} key - The key of the config option to retrieve. + * @returns {import("ace-code").Ace.ConfigOptions[K]} - The value of the config option. + */ + get: (key: K) => import("ace-code").Ace.ConfigOptions[K]; + set: (key: K, value: import("ace-code").Ace.ConfigOptions[K]) => void; + all: () => import("ace-code").Ace.ConfigOptions; + /** + * module loading + */ + moduleUrl: (name: string, component?: string) => string; + setModuleUrl: (name: string, subst: string) => string; + /** @arg {(name: string, callback: (error: any, module: any) => void) => void} cb */ + setLoader: (cb: (name: string, callback: (error: any, module: any) => void) => void) => void; + dynamicModules: any; + loadModule: (moduleId: string | [ + string, + string + ], onLoad: (module: any) => void) => void; + setModuleLoader: (moduleName: any, onLoad: any) => void; + version: "1.36.5"; + }; + export = _exports; +} +declare module "ace-code/src/layer/lines" { + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type LayerConfig = import("ace-code").Ace.LayerConfig; + export class Lines { + constructor(element: HTMLElement, canvasHeight?: number); + element: HTMLElement; + canvasHeight: number; + cells: any[]; + cellCache: any[]; + moveContainer(config: LayerConfig): void; + pageChanged(oldConfig: LayerConfig, newConfig: LayerConfig): boolean; + computeLineTop(row: number, config: Partial, session: EditSession): number; + computeLineHeight(row: number, config: LayerConfig, session: EditSession): number; + getLength(): number; + get(index: number): any; + shift(): void; + pop(): void; + push(cell: any): void; + unshift(cell: any): void; + last(): any; + createCell(row: any, config: any, session: any, initElement: any): any; + } +} +declare module "ace-code/src/layer/gutter" { + export class Gutter { + constructor(parentEl: HTMLElement); + element: HTMLDivElement; + gutterWidth: number; + setSession(session: EditSession): void; + session: import("ace-code/src/edit_session").EditSession; + addGutterDecoration(row: number, className: string): void; + removeGutterDecoration(row: number, className: string): void; + setAnnotations(annotations: any[]): void; + update(config: LayerConfig): void; + config: import("ace-code").Ace.LayerConfig; + oldLastRow: number; + updateLineHighlight(): void; + scrollLines(config: LayerConfig): void; + setHighlightGutterLine(highlightGutterLine: boolean): void; + setShowLineNumbers(show: boolean): void; + getShowLineNumbers(): boolean; + setShowFoldWidgets(show?: boolean): void; + getShowFoldWidgets(): boolean; + getRegion(point: { + x: number; + }): "markers" | "foldWidgets"; + } + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type LayerConfig = import("ace-code").Ace.LayerConfig; + import { Lines } from "ace-code/src/layer/lines"; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + type GutterEvents = import("ace-code").Ace.GutterEvents; + } + export interface Gutter extends Ace.EventEmitter { + } +} +declare module "ace-code/src/layer/marker" { + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type LayerConfig = import("ace-code").Ace.LayerConfig; + export class Marker { + constructor(parentEl: HTMLElement); + element: HTMLDivElement; + setPadding(padding: number): void; + setSession(session: EditSession): void; + session: import("ace-code/src/edit_session").EditSession; + setMarkers(markers: { + [x: number]: import("ace-code").Ace.MarkerLike; + }): void; + markers: { + [x: number]: import("ace-code").Ace.MarkerLike; + }; + elt(className: string, css: string): void; + i: number; + update(config: LayerConfig): void; + config: import("ace-code").Ace.LayerConfig; + drawTextMarker(stringBuilder: undefined, range: Range, clazz: string, layerConfig: Partial, extraStyle?: string): void; + drawMultiLineMarker(stringBuilder: undefined, range: Range, clazz: string, config: LayerConfig, extraStyle?: string): void; + drawSingleLineMarker(stringBuilder: undefined, range: Range, clazz: string, config: Partial, extraLength?: number, extraStyle?: string): void; + drawBidiSingleLineMarker(stringBuilder: undefined, range: Range, clazz: string, config: Partial, extraLength: number, extraStyle: string): void; + drawFullLineMarker(stringBuilder: undefined, range: Range, clazz: string, config: Partial, extraStyle?: undefined): void; + drawScreenLineMarker(stringBuilder: undefined, range: Range, clazz: string, config: Partial, extraStyle?: undefined): void; + } + import { Range } from "ace-code/src/range"; +} +declare module "ace-code/src/layer/text_util" { + export function isTextToken(tokenType: any): boolean; +} +declare module "ace-code/src/layer/text" { + export class Text { + constructor(parentEl: HTMLElement); + dom: typeof dom; + element: HTMLDivElement; + EOL_CHAR: any; + setPadding(padding: number): void; + getLineHeight(): number; + getCharacterWidth(): number; + checkForSizeChanges(): void; + setSession(session: EditSession): void; + session: EditSession; + setShowInvisibles(showInvisibles: string): boolean; + showInvisibles: any; + showSpaces: boolean; + showTabs: boolean; + showEOL: boolean; + setDisplayIndentGuides(display: boolean): boolean; + displayIndentGuides: any; + setHighlightIndentGuides(highlight: boolean): boolean; + tabSize: number; + updateLines(config: LayerConfig, firstRow: number, lastRow: number): void; + config?: import("ace-code").Ace.LayerConfig; + scrollLines(config: LayerConfig): void; + update(config: LayerConfig): void; + renderIndentGuide(parent: any, value: any, max: any): any; + EOF_CHAR: string; + EOL_CHAR_LF: string; + EOL_CHAR_CRLF: string; + TAB_CHAR: string; + SPACE_CHAR: string; + MAX_LINE_LENGTH: number; + destroy: {}; + onChangeTabSize: () => void; + } + export type LayerConfig = import("ace-code").Ace.LayerConfig; + export type EditSession = import("ace-code/src/edit_session").EditSession; + import dom = require("ace-code/src/lib/dom"); + import { Lines } from "ace-code/src/layer/lines"; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + type TextEvents = import("ace-code").Ace.TextEvents; + type LayerConfig = import("ace-code").Ace.LayerConfig; + } + export interface Text extends Ace.EventEmitter { + config?: Ace.LayerConfig; + } +} +declare module "ace-code/src/layer/cursor" { + export class Cursor { + constructor(parentEl: HTMLElement); + element: HTMLDivElement; + isVisible: boolean; + isBlinking: boolean; + blinkInterval: number; + smoothBlinking: boolean; + cursors: any[]; + cursor: HTMLDivElement; + setPadding(padding: number): void; + setSession(session: EditSession): void; + session: import("ace-code/src/edit_session").EditSession; + setBlinking(blinking: boolean): void; + setBlinkInterval(blinkInterval: number): void; + setSmoothBlinking(smoothBlinking: boolean): void; + addCursor(): HTMLDivElement; + removeCursor(): any; + hideCursor(): void; + showCursor(): void; + restartTimer(): void; + intervalId: number; + getPixelPosition(position?: import("ace-code").Ace.Point, onScreen?: boolean): { + left: number; + top: number; + }; + isCursorInView(pixelPos: any, config: any): boolean; + update(config: any): void; + config: any; + overwrite: any; + destroy(): void; + drawCursor: any; + timeoutId?: number; + } + export type EditSession = import("ace-code/src/edit_session").EditSession; + export interface Cursor { + timeoutId?: number; + } +} +declare module "ace-code/src/scrollbar" { + const VScrollBar_base: typeof Scrollbar; + /** + * Represents a vertical scroll bar. + **/ + export class VScrollBar extends Scrollbar { + /** + * Creates a new `VScrollBar`. `parent` is the owner of the scroll bar. + * @param {Element} parent A DOM element + * @param {Object} renderer An editor renderer + **/ + constructor(parent: Element, renderer: any); + scrollTop: number; + scrollHeight: number; + width: number; + /** + * Returns the width of the scroll bar. + **/ + getWidth(): number; + /** + * Sets the height of the scroll bar, in pixels. + * @param {Number} height The new height + **/ + setHeight(height: number): void; + /** + * Sets the scroll height of the scroll bar, in pixels. + * @param {Number} height The new scroll height + **/ + setScrollHeight(height: number): void; + /** + * Sets the scroll top of the scroll bar. + * @param {Number} scrollTop The new scroll top + **/ + setScrollTop(scrollTop: number): void; + /** + * Sets the inner height of the scroll bar, in pixels. + * @param {Number} height The new inner height + * @deprecated Use setScrollHeight instead + **/ + setInnerHeight: (height: number) => void; + } + const HScrollBar_base: typeof Scrollbar; + /** + * Represents a horisontal scroll bar. + **/ + export class HScrollBar extends Scrollbar { + /** + * Creates a new `HScrollBar`. `parent` is the owner of the scroll bar. + * @param {Element} parent A DOM element + * @param {Object} renderer An editor renderer + **/ + constructor(parent: Element, renderer: any); + scrollLeft: number; + height: any; + /** + * Returns the height of the scroll bar. + **/ + getHeight(): number; + /** + * Sets the width of the scroll bar, in pixels. + * @param {Number} width The new width + **/ + setWidth(width: number): void; + /** + * Sets the inner width of the scroll bar, in pixels. + * @param {Number} width The new inner width + * @deprecated Use setScrollWidth instead + **/ + setInnerWidth(width: number): void; + /** + * Sets the scroll width of the scroll bar, in pixels. + * @param {Number} width The new scroll width + **/ + setScrollWidth(width: number): void; + /** + * Sets the scroll left of the scroll bar. + * @param {Number} scrollLeft The new scroll left + **/ + setScrollLeft(scrollLeft: number): void; + } + /** + * An abstract class representing a native scrollbar control. + **/ + class Scrollbar { + /** + * Creates a new `ScrollBar`. `parent` is the owner of the scroll bar. + * @param {Element} parent A DOM element + **/ + constructor(parent: Element, classSuffix: string); + element: HTMLDivElement; + inner: HTMLDivElement; + skipEvent: boolean; + setVisible(isVisible: any): void; + isVisible: any; + coeff: number; + } + export { VScrollBar as ScrollBar, VScrollBar as ScrollBarV, HScrollBar as ScrollBarH }; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + } + export interface VScrollBar extends Ace.EventEmitter { + } + export interface HScrollBar extends Ace.EventEmitter { + } +} +declare module "ace-code/src/scrollbar_custom" { + const VScrollBar_base: typeof ScrollBar; + /** + * Represents a vertical scroll bar. + * @class VScrollBar + **/ + /** + * Creates a new `VScrollBar`. `parent` is the owner of the scroll bar. + * @param {Element} parent A DOM element + * @param {Object} renderer An editor renderer + * + * @constructor + **/ + export class VScrollBar extends ScrollBar { + constructor(parent: any, renderer: any); + scrollTop: number; + scrollHeight: number; + parent: any; + width: number; + renderer: any; + getHeight(): number; + /** + * Returns new top for scroll thumb + **/ + scrollTopFromThumbTop(thumbTop: number): number; + /** + * Returns the width of the scroll bar. + **/ + getWidth(): number; + /** + * Sets the height of the scroll bar, in pixels. + * @param {Number} height The new height + **/ + setHeight(height: number): void; + height: number; + slideHeight: number; + viewHeight: number; + /** + * Sets the inner and scroll height of the scroll bar, in pixels. + * @param {Number} height The new inner height + * + * @param {boolean} force Forcely update height + **/ + setScrollHeight(height: number, force: boolean): void; + pageHeight: any; + thumbHeight: number; + /** + * Sets the scroll top of the scroll bar. + * @param {Number} scrollTop The new scroll top + **/ + setScrollTop(scrollTop: number): void; + thumbTop: number; + setInnerHeight: (height: number, force: boolean) => void; + } + const HScrollBar_base: typeof ScrollBar; + /** + * Represents a horizontal scroll bar. + **/ + export class HScrollBar extends ScrollBar { + /** + * Creates a new `HScrollBar`. `parent` is the owner of the scroll bar. + * @param {Element} parent A DOM element + * @param {Object} renderer An editor renderer + **/ + constructor(parent: Element, renderer: any); + scrollLeft: number; + scrollWidth: number; + height: number; + renderer: any; + /** + * Returns the height of the scroll bar. + **/ + getHeight(): number; + /** + * Returns new left for scroll thumb + **/ + scrollLeftFromThumbLeft(thumbLeft: number): number; + /** + * Sets the width of the scroll bar, in pixels. + * @param {Number} width The new width + **/ + setWidth(width: number): void; + width: number; + slideWidth: number; + viewWidth: number; + /** + * Sets the inner and scroll width of the scroll bar, in pixels. + * @param {Number} width The new inner width + * @param {boolean} force Forcely update width + **/ + setScrollWidth(width: number, force: boolean): void; + pageWidth: any; + thumbWidth: number; + /** + * Sets the scroll left of the scroll bar. + * @param {Number} scrollLeft The new scroll left + **/ + setScrollLeft(scrollLeft: number): void; + thumbLeft: number; + setInnerWidth: (width: number, force: boolean) => void; + } + /** + * An abstract class representing a native scrollbar control. + **/ + class ScrollBar { + /** + * Creates a new `ScrollBar`. `parent` is the owner of the scroll bar. + * @param {Element} parent A DOM element + **/ + constructor(parent: Element, classSuffix: string); + element: HTMLDivElement; + inner: HTMLDivElement; + VScrollWidth: number; + HScrollHeight: number; + skipEvent: boolean; + setVisible(isVisible: any): void; + isVisible: any; + coeff: number; + } + export { VScrollBar as ScrollBar, VScrollBar as ScrollBarV, HScrollBar as ScrollBarH }; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + } + export interface VScrollBar extends Ace.EventEmitter { + } + export interface HScrollBar extends Ace.EventEmitter { + } +} +declare module "ace-code/src/renderloop" { + /** + * Batches changes (that force something to be redrawn) in the background. + **/ + export class RenderLoop { + constructor(onRender: any, win: any); + onRender: any; + pending: boolean; + changes: number; + window: any; + schedule(change: any): void; + clear(change: any): number; + } +} +declare module "ace-code/src/css/editor-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/layer/decorators" { + export class Decorator { + constructor(parent: any, renderer: any); + canvas: HTMLCanvasElement; + renderer: any; + pixelRatio: number; + maxHeight: any; + lineHeight: any; + canvasHeight: any; + heightRatio: number; + canvasWidth: any; + minDecorationHeight: number; + halfMinDecorationHeight: number; + colors: {}; + compensateFoldRows(row: any, foldData: any): number; + } +} +declare module "ace-code/src/virtual_renderer" { + /** + * The class that is responsible for drawing everything you see on the screen! + * @related editor.renderer + **/ + export class VirtualRenderer { + /** + * Constructs a new `VirtualRenderer` within the `container` specified, applying the given `theme`. + * @param {HTMLElement | null} [container] The root element of the editor + * @param {String} [theme] The starting theme + **/ + constructor(container?: HTMLElement | null, theme?: string); + container: HTMLElement; + scroller: HTMLElement; + content: HTMLElement; + canvas: HTMLDivElement; + scrollBar: VScrollBar; + scrollBarV: import("ace-code").Ace.VScrollbar; + scrollBarH: import("ace-code").Ace.HScrollbar; + scrollTop: number; + scrollLeft: number; + cursorPos: { + row: number; + column: number; + }; + layerConfig: { + width: number; + padding: number; + firstRow: number; + firstRowScreen: number; + lastRow: number; + lineHeight: number; + characterWidth: number; + minHeight: number; + maxHeight: number; + offset: number; + height: number; + gutterOffset: number; + }; + scrollMargin: { + left: number; + right: number; + top: number; + bottom: number; + v: number; + h: number; + }; + margin: { + left: number; + right: number; + top: number; + bottom: number; + v: number; + h: number; + }; + updateCharacterSize(): void; + characterWidth: number; + lineHeight: number; + /** + * + * Associates the renderer with an [[EditSession `EditSession`]]. + * @param {EditSession} session The session to associate with + **/ + setSession(session: EditSession): void; + session: import("ace-code").Ace.EditSession; + /** + * Triggers a partial update of the text, from the range given by the two parameters. + * @param {Number} firstRow The first row to update + * @param {Number} lastRow The last row to update + **/ + updateLines(firstRow: number, lastRow: number, force?: boolean): void; + /** + * Triggers a full update of the text, for all the rows. + **/ + updateText(): void; + /** + * Triggers a full update of all the layers, for all the rows. + * @param {Boolean} [force] If `true`, forces the changes through + **/ + updateFull(force?: boolean): void; + /** + * Updates the font size. + **/ + updateFontSize(): void; + resizing: number; + gutterWidth: any; + /** + * Adjusts the wrap limit, which is the number of characters that can fit within the width of the edit area on screen. + **/ + adjustWrapLimit(): boolean; + /** + * Identifies whether you want to have an animated scroll or not. + * @param {Boolean} shouldAnimate Set to `true` to show animated scrolls + **/ + setAnimatedScroll(shouldAnimate: boolean): void; + /** + * Returns whether an animated scroll happens or not. + **/ + getAnimatedScroll(): boolean; + /** + * Identifies whether you want to show invisible characters or not. + * @param {Boolean} showInvisibles Set to `true` to show invisibles + **/ + setShowInvisibles(showInvisibles: boolean): void; + /** + * Returns whether invisible characters are being shown or not. + **/ + getShowInvisibles(): boolean; + getDisplayIndentGuides(): boolean; + setDisplayIndentGuides(display: boolean): void; + getHighlightIndentGuides(): boolean; + setHighlightIndentGuides(highlight: boolean): void; + /** + * Identifies whether you want to show the print margin or not. + * @param {Boolean} showPrintMargin Set to `true` to show the print margin + **/ + setShowPrintMargin(showPrintMargin: boolean): void; + /** + * Returns whether the print margin is being shown or not. + **/ + getShowPrintMargin(): boolean; + /** + * Identifies whether you want to show the print margin column or not. + * @param {number} printMarginColumn Set to `true` to show the print margin column + **/ + setPrintMarginColumn(printMarginColumn: number): void; + /** + * Returns whether the print margin column is being shown or not. + **/ + getPrintMarginColumn(): number; + /** + * Returns `true` if the gutter is being shown. + **/ + getShowGutter(): boolean; + /** + * Identifies whether you want to show the gutter or not. + * @param {Boolean} show Set to `true` to show the gutter + **/ + setShowGutter(show: boolean): void; + getFadeFoldWidgets(): boolean; + setFadeFoldWidgets(show: boolean): void; + setHighlightGutterLine(shouldHighlight: boolean): void; + getHighlightGutterLine(): boolean; + /** + * + * Returns the root element containing this renderer. + **/ + getContainerElement(): HTMLElement; + /** + * + * Returns the element that the mouse events are attached to + **/ + getMouseEventTarget(): HTMLElement; + /** + * + * Returns the element to which the hidden text area is added. + **/ + getTextAreaContainer(): HTMLElement; + /** + * [Returns the index of the first visible row.]{: #VirtualRenderer.getFirstVisibleRow} + **/ + getFirstVisibleRow(): number; + /** + * + * Returns the index of the first fully visible row. "Fully" here means that the characters in the row are not truncated; that the top and the bottom of the row are on the screen. + **/ + getFirstFullyVisibleRow(): number; + /** + * + * Returns the index of the last fully visible row. "Fully" here means that the characters in the row are not truncated; that the top and the bottom of the row are on the screen. + **/ + getLastFullyVisibleRow(): number; + /** + * + * [Returns the index of the last visible row.]{: #VirtualRenderer.getLastVisibleRow} + **/ + getLastVisibleRow(): number; + /** + * Sets the padding for all the layers. + * @param {Number} padding A new padding value (in pixels) + **/ + setPadding(padding: number): void; + setScrollMargin(top?: number, bottom?: number, left?: number, right?: number): void; + setMargin(top?: number, bottom?: number, left?: number, right?: number): void; + /** + * Returns whether the horizontal scrollbar is set to be always visible. + **/ + getHScrollBarAlwaysVisible(): boolean; + /** + * Identifies whether you want to show the horizontal scrollbar or not. + * @param {Boolean} alwaysVisible Set to `true` to make the horizontal scroll bar visible + **/ + setHScrollBarAlwaysVisible(alwaysVisible: boolean): void; + /** + * Returns whether the horizontal scrollbar is set to be always visible. + **/ + getVScrollBarAlwaysVisible(): boolean; + /** + * Identifies whether you want to show the horizontal scrollbar or not. + * @param {Boolean} alwaysVisible Set to `true` to make the horizontal scroll bar visible + **/ + setVScrollBarAlwaysVisible(alwaysVisible: boolean): void; + freeze(): void; + unfreeze(): void; + desiredHeight: any; + /** + * Schedules an update to all the front markers in the document. + **/ + updateFrontMarkers(): void; + /** + * + * Schedules an update to all the back markers in the document. + **/ + updateBackMarkers(): void; + /** + * + * Deprecated; (moved to [[EditSession]]) + * @deprecated + **/ + addGutterDecoration(row: any, className: any): void; + /** + * Deprecated; (moved to [[EditSession]]) + * @deprecated + **/ + removeGutterDecoration(row: any, className: any): void; + /** + * + * Redraw breakpoints. + */ + updateBreakpoints(rows?: any): void; + /** + * Sets annotations for the gutter. + * @param {import("ace-code").Ace.Annotation[]} annotations An array containing annotations + * + **/ + setAnnotations(annotations: import("ace-code").Ace.Annotation[]): void; + /** + * + * Updates the cursor icon. + **/ + updateCursor(): void; + /** + * + * Hides the cursor icon. + **/ + hideCursor(): void; + /** + * + * Shows the cursor icon. + **/ + showCursor(): void; + scrollSelectionIntoView(anchor: Point, lead: Point, offset?: number): void; + /** + * + * Scrolls the cursor into the first visibile area of the editor + */ + scrollCursorIntoView(cursor?: Point, offset?: number, $viewMargin?: { + top?: any; + bottom?: any; + }): void; + /** + * {:EditSession.getScrollTop} + * @related EditSession.getScrollTop + **/ + getScrollTop(): number; + /** + * {:EditSession.getScrollLeft} + * @related EditSession.getScrollLeft + **/ + getScrollLeft(): number; + /** + * Returns the first visible row, regardless of whether it's fully visible or not. + **/ + getScrollTopRow(): number; + /** + * Returns the last visible row, regardless of whether it's fully visible or not. + **/ + getScrollBottomRow(): number; + /** + * Gracefully scrolls from the top of the editor to the row indicated. + * @param {Number} row A row id + * + * @related EditSession.setScrollTop + **/ + scrollToRow(row: number): void; + alignCursor(cursor: Point, alignment?: number): number; + /** + * Gracefully scrolls the editor to the row indicated. + * @param {Number} line A line number + * @param {Boolean} center If `true`, centers the editor the to indicated line + * @param {Boolean} animate If `true` animates scrolling + * @param {() => void} [callback] Function to be called after the animation has finished + **/ + scrollToLine(line: number, center: boolean, animate: boolean, callback?: () => void): void; + animateScrolling(fromValue: any, callback?: any): void; + /** + * Scrolls the editor to the y pixel indicated. + * @param {Number} scrollTop The position to scroll to + **/ + scrollToY(scrollTop: number): void; + /** + * Scrolls the editor across the x-axis to the pixel indicated. + * @param {Number} scrollLeft The position to scroll to + **/ + scrollToX(scrollLeft: number): void; + /** + * Scrolls the editor across both x- and y-axes. + * @param {Number} x The x value to scroll to + * @param {Number} y The y value to scroll to + **/ + scrollTo(x: number, y: number): void; + /** + * Scrolls the editor across both x- and y-axes. + * @param {Number} deltaX The x value to scroll by + * @param {Number} deltaY The y value to scroll by + **/ + scrollBy(deltaX: number, deltaY: number): void; + /** + * Returns `true` if you can still scroll by either parameter; in other words, you haven't reached the end of the file or line. + * @param {Number} deltaX The x value to scroll by + * @param {Number} deltaY The y value to scroll by + * + **/ + isScrollableBy(deltaX: number, deltaY: number): boolean; + pixelToScreenCoordinates(x: number, y: number): import("ace-code").Ace.ScreenCoordinates; + screenToTextCoordinates(x: number, y: number): Point; + /** + * Returns an object containing the `pageX` and `pageY` coordinates of the document position. + * @param {Number} row The document row position + * @param {Number} column The document column position + * + **/ + textToScreenCoordinates(row: number, column: number): { + pageX: number; + pageY: number; + }; + /** + * + * Focuses the current container. + **/ + visualizeFocus(): void; + /** + * + * Blurs the current container. + **/ + visualizeBlur(): void; + showComposition(composition: any): void; + /** + * @param {String} text A string of text to use + * + * Sets the inner text of the current composition to `text`. + **/ + setCompositionText(text: string): void; + /** + * + * Hides the current composition. + **/ + hideComposition(): void; + setGhostText(text: string, position?: Point): void; + removeGhostText(): void; + addToken(text: string, type: string, row: number, column?: number): void; + hideTokensAfterPosition(row: any, column: any): { + type: string; + value: string; + }[]; + removeExtraToken(row: any, column: any): void; + /** + * [Sets a new theme for the editor. `theme` should exist, and be a directory path, like `ace/theme/textmate`.]{: #VirtualRenderer.setTheme} + * @param {String | Theme} [theme] The path to a theme + * @param {() => void} [cb] optional callback + **/ + setTheme(theme?: string | Theme, cb?: () => void): void; + /** + * [Returns the path of the current theme.]{: #VirtualRenderer.getTheme} + **/ + getTheme(): string; + /** + * [Adds a new class, `style`, to the editor.]{: #VirtualRenderer.setStyle} + * @param {String} style A class name + **/ + setStyle(style: string, include?: boolean): void; + /** + * [Removes the class `style` from the editor.]{: #VirtualRenderer.unsetStyle} + * @param {String} style A class name + * + **/ + unsetStyle(style: string): void; + setCursorStyle(style: string): void; + /** + * @param {String} cursorStyle A css cursor style + **/ + setMouseCursor(cursorStyle: string): void; + attachToShadowRoot(): void; + /** + * Destroys the text and cursor layers for this renderer. + **/ + destroy(): void; + CHANGE_CURSOR: number; + CHANGE_MARKER: number; + CHANGE_GUTTER: number; + CHANGE_SCROLL: number; + CHANGE_LINES: number; + CHANGE_TEXT: number; + CHANGE_SIZE: number; + CHANGE_MARKER_BACK: number; + CHANGE_MARKER_FRONT: number; + CHANGE_FULL: number; + CHANGE_H_SCROLL: number; + STEPS: number; + textarea?: HTMLTextAreaElement; + enableKeyboardAccessibility?: boolean; + showInvisibles?: boolean; + theme?: any; + destroyed?: boolean; + keyboardFocusClassName?: string; + } + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type Point = import("ace-code").Ace.Point; + export type Theme = import("ace-code").Ace.Theme; + import { Gutter as GutterLayer } from "ace-code/src/layer/gutter"; + import { Marker as MarkerLayer } from "ace-code/src/layer/marker"; + import { Text as TextLayer } from "ace-code/src/layer/text"; + import { Cursor as CursorLayer } from "ace-code/src/layer/cursor"; + import { VScrollBar } from "ace-code/src/scrollbar"; + import { FontMetrics } from "ace-code/src/layer/font_metrics"; + import { RenderLoop } from "ace-code/src/renderloop"; + import { Decorator } from "ace-code/src/layer/decorators"; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + type VirtualRendererEvents = import("ace-code").Ace.VirtualRendererEvents; + type OptionsProvider = import("ace-code").Ace.OptionsProvider; + type VirtualRendererOptions = import("ace-code").Ace.VirtualRendererOptions; + type EditSession = import("ace-code").Ace.EditSession; + } + export interface VirtualRenderer extends Ace.EventEmitter, Ace.OptionsProvider { + textarea?: HTMLTextAreaElement; + enableKeyboardAccessibility?: boolean; + showInvisibles?: boolean; + theme?: any; + destroyed?: boolean; + session: Ace.EditSession; + keyboardFocusClassName?: string; + } +} +declare module "ace-code/src/selection" { + export class Selection { + /** + * Creates a new `Selection` object. + * @param {EditSession} session The session to use + * @constructor + **/ + constructor(session: EditSession); + session: EditSession; + doc: import("ace-code/src/document").Document; + cursor: Anchor; + lead: Anchor; + anchor: Anchor; + /** + * Returns `true` if the selection is empty. + **/ + isEmpty(): boolean; + /** + * Returns `true` if the selection is a multi-line. + **/ + isMultiLine(): boolean; + /** + * Returns an object containing the `row` and `column` current position of the cursor. + **/ + getCursor(): Point; + /** + * Sets the row and column position of the anchor. This function also emits the `'changeSelection'` event. + * @param {Number} row The new row + * @param {Number} column The new column + * + **/ + setAnchor(row: number, column: number): void; + /** + * Returns an object containing the `row` and `column` of the calling selection anchor. + * + * @related Anchor.getPosition + **/ + getAnchor(): Point; + /** + * Returns an object containing the `row` and `column` of the calling selection lead. + **/ + getSelectionLead(): any; + /** + * Returns `true` if the selection is going backwards in the document. + **/ + isBackwards(): boolean; + /** + * [Returns the [[Range]] for the selected text.]{: #Selection.getRange} + **/ + getRange(): Range; + /** + * [Empties the selection (by de-selecting it). This function also emits the `'changeSelection'` event.]{: #Selection.clearSelection} + **/ + clearSelection(): void; + /** + * Selects all the text in the document. + **/ + selectAll(): void; + /** + * Sets the selection to the provided range. + * @param {import("ace-code").Ace.IRange} range The range of text to select + * @param {Boolean} [reverse] Indicates if the range should go backwards (`true`) or not + **/ + setRange(range: import("ace-code").Ace.IRange, reverse?: boolean): void; + /** + * Moves the selection cursor to the indicated row and column. + * @param {Number} row The row to select to + * @param {Number} column The column to select to + **/ + selectTo(row: number, column: number): void; + /** + * Moves the selection cursor to the row and column indicated by `pos`. + * @param {Point} pos An object containing the row and column + **/ + selectToPosition(pos: Point): void; + /** + * Moves the selection cursor to the indicated row and column. + * @param {Number} row The row to select to + * @param {Number} column The column to select to + **/ + moveTo(row: number, column: number): void; + /** + * Moves the selection cursor to the row and column indicated by `pos`. + * @param {Object} pos An object containing the row and column + **/ + moveToPosition(pos: any): void; + /** + * Moves the selection up one row. + **/ + selectUp(): void; + /** + * Moves the selection down one row. + **/ + selectDown(): void; + /** + * Moves the selection right one column. + **/ + selectRight(): void; + /** + * Moves the selection left one column. + **/ + selectLeft(): void; + /** + * Moves the selection to the beginning of the current line. + **/ + selectLineStart(): void; + /** + * Moves the selection to the end of the current line. + **/ + selectLineEnd(): void; + /** + * Moves the selection to the end of the file. + **/ + selectFileEnd(): void; + /** + * Moves the selection to the start of the file. + **/ + selectFileStart(): void; + /** + * Moves the selection to the first word on the right. + **/ + selectWordRight(): void; + /** + * Moves the selection to the first word on the left. + **/ + selectWordLeft(): void; + /** + * Moves the selection to highlight the entire word. + * @related EditSession.getWordRange + **/ + getWordRange(row: any, column: any): Range; + /** + * Selects an entire word boundary. + **/ + selectWord(): void; + /** + * Selects a word, including its right whitespace. + * @related EditSession.getAWordRange + **/ + selectAWord(): void; + getLineRange(row: any, excludeLastChar: any): Range; + /** + * Selects the entire line. + **/ + selectLine(): void; + /** + * Moves the cursor up one row. + **/ + moveCursorUp(): void; + /** + * Moves the cursor down one row. + **/ + moveCursorDown(): void; + /** + * + * Returns `true` if moving the character next to the cursor in the specified direction is a soft tab. + * @param {Point} cursor the current cursor position + * @param {Number} tabSize the tab size + * @param {Number} direction 1 for right, -1 for left + */ + wouldMoveIntoSoftTab(cursor: Point, tabSize: number, direction: number): boolean; + /** + * Moves the cursor left one column. + **/ + moveCursorLeft(): void; + /** + * Moves the cursor right one column. + **/ + moveCursorRight(): void; + /** + * Moves the cursor to the start of the line. + **/ + moveCursorLineStart(): void; + /** + * Moves the cursor to the end of the line. + **/ + moveCursorLineEnd(): void; + /** + * Moves the cursor to the end of the file. + **/ + moveCursorFileEnd(): void; + /** + * Moves the cursor to the start of the file. + **/ + moveCursorFileStart(): void; + /** + * Moves the cursor to the word on the right. + **/ + moveCursorLongWordRight(): void; + /** + * + * Moves the cursor to the word on the left. + **/ + moveCursorLongWordLeft(): void; + moveCursorShortWordRight(): void; + moveCursorShortWordLeft(): void; + moveCursorWordRight(): void; + moveCursorWordLeft(): void; + /** + * Moves the cursor to position indicated by the parameters. Negative numbers move the cursor backwards in the document. + * @param {Number} rows The number of rows to move by + * @param {Number} chars The number of characters to move by + * + * @related EditSession.documentToScreenPosition + **/ + moveCursorBy(rows: number, chars: number): void; + /** + * Moves the selection to the position indicated by its `row` and `column`. + * @param {Point} position The position to move to + **/ + moveCursorToPosition(position: Point): void; + /** + * Moves the cursor to the row and column provided. [If `preventUpdateDesiredColumn` is `true`, then the cursor stays in the same column position as its original point.]{: #preventUpdateBoolDesc} + * @param {Number} row The row to move to + * @param {Number} column The column to move to + **/ + moveCursorTo(row: number, column: number, keepDesiredColumn?: boolean): void; + /** + * Moves the cursor to the screen position indicated by row and column. {:preventUpdateBoolDesc} + * @param {Number} row The row to move to + * @param {Number} column The column to move to + **/ + moveCursorToScreen(row: number, column: number, keepDesiredColumn: boolean): void; + detach(): void; + fromOrientedRange(range: Range & { + desiredColumn?: number; + }): void; + toOrientedRange(range?: Range & { + desiredColumn?: number; + }): Range & { + desiredColumn?: number; + }; + /** + * Saves the current cursor position and calls `func` that can change the cursor + * postion. The result is the range of the starting and eventual cursor position. + * Will reset the cursor position. + * @param {Function} func The callback that should change the cursor position + **/ + getRangeOfMovements(func: Function): Range; + toJSON(): Range | Range[]; + fromJSON(data: any): void; + isEqual(data: any): boolean; + /** + * Left for backward compatibility + * @deprecated + */ + setSelectionAnchor: (row: number, column: number) => void; + /** + * Left for backward compatibility + * @deprecated + */ + getSelectionAnchor: () => Point; + setSelectionRange: (range: import("ace-code").Ace.IRange, reverse?: boolean) => void; + } + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type Anchor = import("ace-code/src/anchor").Anchor; + export type Point = import("ace-code").Ace.Point; + import { Range } from "ace-code/src/range"; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + type MultiSelectionEvents = import("ace-code").Ace.MultiSelectionEvents; + type MultiSelectProperties = import("ace-code").Ace.MultiSelectProperties; + } + export interface Selection extends Ace.EventEmitter, Ace.MultiSelectProperties { + } +} +declare module "ace-code/src/clipboard" { + export let lineMode: string | false; + export function pasteCancelled(): boolean; + export function cancel(): void; +} +declare module "ace-code/src/keyboard/textinput" { + export function $setUserAgentForTests(_isMobile: any, _isIOS: any): void; + export var TextInput: any; +} +declare module "ace-code/src/mouse/mouse_event" { + export class MouseEvent { + constructor(domEvent: any, editor: any); + speed: number; + wheelX: number; + wheelY: number; + domEvent: any; + editor: any; + x: any; + clientX: any; + y: any; + clientY: any; + propagationStopped: boolean; + defaultPrevented: boolean; + stopPropagation(): void; + preventDefault(): void; + stop(): void; + /** + * Get the document position below the mouse cursor + * + * @return {Object} 'row' and 'column' of the document position + */ + getDocumentPosition(): any; + /** + * Get the relative position within the gutter. + * + * @return {Number} 'row' within the gutter. + */ + getGutterRow(): number; + /** + * Check if the mouse cursor is inside of the text selection + * + * @return {Boolean} whether the mouse cursor is inside of the selection + */ + inSelection(): boolean; + /** + * Get the clicked mouse button + * + * @return {Number} 0 for left button, 1 for middle button, 2 for right button + */ + getButton(): number; + /** + * @return {Boolean} whether the shift key was pressed when the event was emitted + */ + getShiftKey(): boolean; + getAccelKey(): any; + time?: number; + } + export interface MouseEvent { + time?: number; + } +} +declare module "ace-code/src/mouse/default_handlers" { + export type MouseHandler = import("ace-code/src/mouse/mouse_handler").MouseHandler; + export type MouseEvent = import("ace-code/src/mouse/mouse_event").MouseEvent; + export class DefaultHandlers { + constructor(mouseHandler: MouseHandler); + onMouseDown(this: import("ace-code/src/mouse/mouse_handler").MouseHandler, ev: MouseEvent): void; + mousedownEvent: import("ace-code/src/mouse/mouse_event").MouseEvent; + startSelect(this: import("ace-code/src/mouse/mouse_handler").MouseHandler, pos?: import("ace-code").Ace.Position, waitForClickSelection?: boolean): void; + select(this: import("ace-code/src/mouse/mouse_handler").MouseHandler): void; + extendSelectionBy(this: import("ace-code/src/mouse/mouse_handler").MouseHandler, unitName: string | number): void; + selectByLinesEnd(this: import("ace-code/src/mouse/mouse_handler").MouseHandler): void; + focusWait(this: import("ace-code/src/mouse/mouse_handler").MouseHandler): void; + onDoubleClick(this: import("ace-code/src/mouse/mouse_handler").MouseHandler, ev: MouseEvent): void; + onTripleClick(this: import("ace-code/src/mouse/mouse_handler").MouseHandler, ev: MouseEvent): void; + onQuadClick(this: import("ace-code/src/mouse/mouse_handler").MouseHandler, ev: MouseEvent): void; + onMouseWheel(this: import("ace-code/src/mouse/mouse_handler").MouseHandler, ev: MouseEvent): void; + selectEnd: (this: import("ace-code/src/mouse/mouse_handler").MouseHandler) => void; + selectAllEnd: (this: import("ace-code/src/mouse/mouse_handler").MouseHandler) => void; + selectByWordsEnd: (this: import("ace-code/src/mouse/mouse_handler").MouseHandler) => void; + } +} +declare module "ace-code/src/tooltip" { + export class HoverTooltip extends Tooltip { + constructor(parentNode?: HTMLElement); + timeout: number; + lastT: number; + idleTime: number; + lastEvent: import("ace-code/src/mouse/mouse_event").MouseEvent; + waitForHover(): void; + addToEditor(editor: Editor): void; + removeFromEditor(editor: Editor): void; + isOutsideOfText(e: MouseEvent): boolean; + setDataProvider(value: (event: MouseEvent, editor: Editor) => void): void; + showForRange(editor: Editor, range: Range, domNode: HTMLElement, startingEvent: MouseEvent): void; + range: Range; + addMarker(range: Range, session?: EditSession): void; + marker: number; + row: number; + } + export type Editor = import("ace-code/src/editor").Editor; + export type MouseEvent = import("ace-code/src/mouse/mouse_event").MouseEvent; + export type EditSession = import("ace-code/src/edit_session").EditSession; + export var popupManager: PopupManager; + export class Tooltip { + constructor(parentNode: Element); + isOpen: boolean; + getElement(): HTMLElement; + setText(text: string): void; + setHtml(html: string): void; + setPosition(x: number, y: number): void; + setClassName(className: string): void; + setTheme(theme: import("ace-code").Ace.Theme): void; + show(text?: string, x?: number, y?: number): void; + hide(e: any): void; + getHeight(): number; + getWidth(): number; + destroy(): void; + } + import { Range } from "ace-code/src/range"; + class PopupManager { + popups: Tooltip[]; + addPopup(popup: Tooltip): void; + removePopup(popup: Tooltip): void; + updatePopups(): void; + doPopupsOverlap(popupA: Tooltip, popupB: Tooltip): boolean; + } + export interface HoverTooltip { + row: number; + } +} +declare module "ace-code/src/mouse/default_gutter_handler" { + export function GutterHandler(this: import("ace-code/src/mouse/mouse_handler").MouseHandler, mouseHandler: MouseHandler): void; + export interface GutterHandler { + } + export type MouseHandler = import("ace-code/src/mouse/mouse_handler").MouseHandler; + export class GutterTooltip extends Tooltip { + static get annotationLabels(): { + error: { + singular: any; + plural: any; + }; + security: { + singular: any; + plural: any; + }; + warning: { + singular: any; + plural: any; + }; + info: { + singular: any; + plural: any; + }; + hint: { + singular: any; + plural: any; + }; + }; + static annotationsToSummaryString(annotations: any): string; + constructor(editor: any); + editor: any; + setPosition(x: any, y: any): void; + showTooltip(row: any): void; + hideTooltip(): void; + } + import { Tooltip } from "ace-code/src/tooltip"; + export interface GutterHandler { + } +} +declare module "ace-code/src/mouse/dragdrop_handler" { + export type MouseHandler = import("ace-code/src/mouse/mouse_handler").MouseHandler; + export function DragdropHandler(mouseHandler: MouseHandler): void; + export class DragdropHandler { + constructor(mouseHandler: MouseHandler); + onDragStart: (this: import("ace-code/src/mouse/mouse_handler").MouseHandler, e: any) => any; + onDragEnd: (this: import("ace-code/src/mouse/mouse_handler").MouseHandler, e: any) => any; + onDragEnter: (this: import("ace-code/src/mouse/mouse_handler").MouseHandler, e: any) => any; + onDragOver: (this: import("ace-code/src/mouse/mouse_handler").MouseHandler, e: any) => any; + onDragLeave: (e: any) => void; + onDrop: (this: import("ace-code/src/mouse/mouse_handler").MouseHandler, e: any) => any; + } +} +declare module "ace-code/src/mouse/touch_handler" { + export function addTouchListeners(el: any, editor: any): void; +} +declare module "ace-code/src/mouse/mouse_handler" { + export class MouseHandler { + constructor(editor: Editor); + mouseEvent: MouseEvent; + editor: import("ace-code/src/editor").Editor; + onMouseEvent(name: any, e: any): void; + onMouseMove(name: any, e: any): void; + onMouseWheel(name: any, e: { + wheelX: number; + wheelY: number; + }): void; + setState(state: any): void; + state: any; + captureMouse(ev: any, mouseMoveHandler: any): number; + x: any; + y: any; + isMousePressed: boolean; + releaseMouse: (e: any) => void; + cancelContextMenu(): void; + destroy(): void; + cancelDrag?: boolean; + mousedownEvent?: import("ace-code").Ace.MouseEvent; + startSelect?: (pos?: import("ace-code").Ace.Point, waitForClickSelection?: boolean) => void; + select?: () => void; + selectEnd?: () => void; + } + export type Editor = import("ace-code/src/editor").Editor; + import { MouseEvent } from "ace-code/src/mouse/mouse_event"; + namespace Ace { + type Range = import("ace-code").Ace.Range; + type MouseEvent = import("ace-code").Ace.MouseEvent; + type Point = import("ace-code").Ace.Point; + } + export interface MouseHandler { + cancelDrag?: boolean; + mousedownEvent?: Ace.MouseEvent; + startSelect?: (pos?: Ace.Point, waitForClickSelection?: boolean) => void; + select?: () => void; + selectEnd?: () => void; + } +} +declare module "ace-code/src/mouse/fold_handler" { + export class FoldHandler { + constructor(editor: any); + } +} +declare module "ace-code/src/keyboard/keybinding" { + export type Editor = import("ace-code/src/editor").Editor; + export type KeyboardHandler = import("ace-code").Ace.KeyboardHandler; + export class KeyBinding { + constructor(editor: Editor); + setDefaultHandler(kb: KeyboardHandler): void; + setKeyboardHandler(kb: KeyboardHandler): void; + addKeyboardHandler(kb?: KeyboardHandler & { + attach?: (editor: any) => void; + detach?: (editor: any) => void; + }, pos?: number): void; + removeKeyboardHandler(kb: KeyboardHandler & { + attach?: (editor: any) => void; + detach?: (editor: any) => void; + }): boolean; + getKeyboardHandler(): KeyboardHandler; + getStatusText(): string; + } +} +declare module "ace-code/src/search" { + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type SearchOptions = import("ace-code").Ace.SearchOptions; + /** + * A class designed to handle all sorts of text searches within a [[Document `Document`]]. + **/ + export class Search { + /** + * Sets the search options via the `options` parameter. + * @param {Partial} options An object containing all the new search properties + * @chainable + **/ + set(options: Partial): Search; + /** + * [Returns an object containing all the search options.]{: #Search.getOptions} + **/ + getOptions(): Partial; + /** + * Sets the search options via the `options` parameter. + * @param {Partial} options object containing all the search propertie + * @related Search.set + **/ + setOptions(options: Partial): void; + /** + * Searches for `options.needle`. If found, this method returns the [[Range `Range`]] where the text first occurs. If `options.backwards` is `true`, the search goes backwards in the session. + * @param {EditSession} session The session to search with + **/ + find(session: EditSession): Range | false; + /** + * Searches for all occurrances `options.needle`. If found, this method returns an array of [[Range `Range`s]] where the text first occurs. If `options.backwards` is `true`, the search goes backwards in the session. + * @param {EditSession} session The session to search with + **/ + findAll(session: EditSession): Range[]; + /** + * Searches for `options.needle` in `input`, and, if found, replaces it with `replacement`. + * @param {String} input The text to search in + * @param {any} replacement The replacing text + * + (String): If `options.regExp` is `true`, this function returns `input` with the replacement already made. Otherwise, this function just returns `replacement`.
    + * If `options.needle` was not found, this function returns `null`. + * + * + **/ + replace(input: string, replacement: any): string; + } + import { Range } from "ace-code/src/range"; +} +declare module "ace-code/src/keyboard/hash_handler" { + export type Command = import("ace-code").Ace.Command; + export type CommandLike = import("ace-code").Ace.CommandLike; + export class HashHandler extends MultiHashHandler { + } + export namespace HashHandler { + function call(thisArg: any, config: any, platform: any): void; + } + export class MultiHashHandler { + constructor(config?: Record | Command[], platform?: string); + platform: string; + commands: Record; + commandKeyBinding: {}; + addCommand(command: Command): void; + removeCommand(command: Command | string, keepCommand?: boolean): void; + bindKey(key: string | { + win?: string; + mac?: string; + position?: number; + }, command: CommandLike | string, position?: number): void; + addCommands(commands?: Record | Command[]): void; + removeCommands(commands: Record): void; + bindKeys(keyList: Record): void; + /** + * Accepts keys in the form ctrl+Enter or ctrl-Enter + * keys without modifiers or shift only + */ + parseKeys(keys: string): { + key: string; + hashId: number; + } | false; + findKeyCommand(hashId: number, keyString: string): Command; + handleKeyboard(data: any, hashId: number, keyString: string, keyCode: number): { + command: string; + } | void; + getStatusText(editor?: any, data?: any): string; + } + export namespace MultiHashHandler { + function call(thisArg: any, config: any, platform: any): void; + } +} +declare module "ace-code/src/commands/command_manager" { + const CommandManager_base: typeof MultiHashHandler; + export class CommandManager extends MultiHashHandler { + /** + * new CommandManager(platform, commands) + * @param {String} platform Identifier for the platform; must be either `"mac"` or `"win"` + * @param {any[]} commands A list of commands + **/ + constructor(platform: string, commands: any[]); + byName: Record; + exec(command: string | string[] | import("ace-code").Ace.Command, editor: Editor, args: any): boolean; + canExecute(command: string | import("ace-code").Ace.Command, editor: Editor): boolean; + toggleRecording(editor: Editor): boolean; + macro: any; + recording: boolean; + oldMacro: any; + replay(editor: Editor): boolean; + trimMacro(m: any): any; + } + export type Editor = import("ace-code/src/editor").Editor; + import { MultiHashHandler } from "ace-code/src/keyboard/hash_handler"; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + } + export interface CommandManager extends Ace + .EventEmitter { + } +} +declare module "ace-code/src/commands/default_commands" { + export const commands: import("ace-code").Ace.Command[]; +} +declare module "ace-code/src/token_iterator" { + export type EditSession = import("ace-code/src/edit_session").EditSession; + /** + * This class provides an essay way to treat the document as a stream of tokens, and provides methods to iterate over these tokens. + **/ + export class TokenIterator { + /** + * Creates a new token iterator object. The inital token index is set to the provided row and column coordinates. + * @param {EditSession} session The session to associate with + * @param {Number} initialRow The row to start the tokenizing at + * @param {Number} initialColumn The column to start the tokenizing at + **/ + constructor(session: EditSession, initialRow: number, initialColumn: number); + /** + * Moves iterator position to the start of previous token. + **/ + stepBackward(): import("ace-code").Ace.Token | null; + /** + * Moves iterator position to the start of next token. + **/ + stepForward(): import("ace-code").Ace.Token | null; + /** + * + * Returns current token. + **/ + getCurrentToken(): import("ace-code").Ace.Token; + /** + * + * Returns the current row. + **/ + getCurrentTokenRow(): number; + /** + * + * Returns the current column. + **/ + getCurrentTokenColumn(): number; + /** + * Return the current token position. + */ + getCurrentTokenPosition(): import("ace-code").Ace.Point; + /** + * Return the current token range. + */ + getCurrentTokenRange(): Range; + } + import { Range } from "ace-code/src/range"; +} +declare module "ace-code/src/keyboard/gutter_handler" { + export class GutterKeyboardHandler { + constructor(editor: any); + editor: any; + gutterLayer: any; + element: any; + lines: any; + activeRowIndex: any; + activeLane: string; + annotationTooltip: GutterTooltip; + addListener(): void; + removeListener(): void; + lane: any; + } + export class GutterKeyboardEvent { + constructor(domEvent: any, gutterKeyboardHandler: any); + gutterKeyboardHandler: any; + domEvent: any; + /** + * Returns the key that was presssed. + * + * @return {string} the key that was pressed. + */ + getKey(): string; + /** + * Returns the row in the gutter that was focused after the keyboard event was handled. + * + * @return {number} the key that was pressed. + */ + getRow(): number; + /** + * Returns whether focus is on the annotation lane after the keyboard event was handled. + * + * @return {boolean} true if focus was on the annotation lane after the keyboard event. + */ + isInAnnotationLane(): boolean; + /** + * Returns whether focus is on the fold lane after the keyboard event was handled. + * + * @return {boolean} true if focus was on the fold lane after the keyboard event. + */ + isInFoldLane(): boolean; + } + import { GutterTooltip } from "ace-code/src/mouse/default_gutter_handler"; +} +declare module "ace-code/src/editor" { + /** + * The main entry point into the Ace functionality. + * + * The `Editor` manages the [[EditSession]] (which manages [[Document]]s), as well as the [[VirtualRenderer]], which draws everything to the screen. + * + * Event sessions dealing with the mouse and keyboard are bubbled up from `Document` to the `Editor`, which decides what to do with them. + **/ + export class Editor { + /** + * Creates a new `Editor` object. + * + * @param {VirtualRenderer} renderer Associated `VirtualRenderer` that draws everything + * @param {EditSession} [session] The `EditSession` to refer to + * @param {Partial} [options] The default options + **/ + constructor(renderer: VirtualRenderer, session?: EditSession, options?: Partial); + session: EditSession; + container: HTMLElement & { + env?: any; + value?: any; + }; + renderer: VirtualRenderer; + id: string; + commands: CommandManager; + textInput: any; + keyBinding: KeyBinding; + startOperation(commandEvent: any): void; + /** + * @arg e + */ + endOperation(e: any): void; + onStartOperation(commandEvent: any): void; + curOp: {}; + prevOp: {}; + previousCommand: any; + /** + * @arg e + */ + onEndOperation(e: any): void; + mergeNextCommand: boolean; + sequenceStartTime: number; + /** + * Sets a new key handler, such as "vim" or "windows". + * @param {String | import("ace-code").Ace.KeyboardHandler | null} keyboardHandler The new key handler + **/ + setKeyboardHandler(keyboardHandler: string | import("ace-code").Ace.KeyboardHandler | null, cb?: () => void): void; + /** + * Returns the keyboard handler, such as "vim" or "windows". + **/ + getKeyboardHandler(): any; + /** + * Sets a new editsession to use. This method also emits the `'changeSession'` event. + * @param {EditSession} [session] The new session to use + **/ + setSession(session?: EditSession): void; + selection: import("ace-code/src/selection").Selection; + /** + * Returns the current session being used. + **/ + getSession(): EditSession; + /** + * Sets the current document to `val`. + * @param {String} val The new value to set for the document + * @param {Number} [cursorPos] Where to set the new value. `undefined` or 0 is selectAll, -1 is at the document start, and 1 is at the end + * + * @returns {String} The current document value + * @related Document.setValue + **/ + setValue(val: string, cursorPos?: number): string; + /** + * Returns the current session's content. + * + * @related EditSession.getValue + **/ + getValue(): string; + /** + * + * Returns the currently highlighted selection. + * @returns {Selection} The selection object + **/ + getSelection(): Selection; + /** + * {:VirtualRenderer.onResize} + * @param {Boolean} [force] If `true`, recomputes the size, even if the height and width haven't changed + * @related VirtualRenderer.onResize + **/ + resize(force?: boolean): void; + /** + * {:VirtualRenderer.setTheme} + * @param {string | import("ace-code").Ace.Theme} theme The path to a theme + * @param {() => void} [cb] optional callback called when theme is loaded + **/ + setTheme(theme: string | import("ace-code").Ace.Theme, cb?: () => void): void; + /** + * {:VirtualRenderer.getTheme} + * + * @returns {String} The set theme + * @related VirtualRenderer.getTheme + **/ + getTheme(): string; + /** + * {:VirtualRenderer.setStyle} + * @param {String} style A class name + * @related VirtualRenderer.setStyle + **/ + setStyle(style: string): void; + /** + * {:VirtualRenderer.unsetStyle} + * @related VirtualRenderer.unsetStyle + */ + unsetStyle(style: string): void; + /** + * Gets the current font size of the editor text. + */ + getFontSize(): string | number; + /** + * Set a new font size (in pixels) for the editor text. + * @param {String | number} size A font size ( _e.g._ "12px") + **/ + setFontSize(size: string | number): void; + /** + * + * Brings the current `textInput` into focus. + **/ + focus(): void; + /** + * Returns `true` if the current `textInput` is in focus. + **/ + isFocused(): boolean; + /** + * + * Blurs the current `textInput`. + **/ + blur(): void; + /** + * Returns the string of text currently highlighted. + **/ + getCopyText(): string; + execCommand(command: string | string[], args?: any): boolean; + /** + * Inserts `text` into wherever the cursor is pointing. + * @param {String} text The new text to add + **/ + insert(text: string, pasted?: boolean): void; + autoIndent(): void; + applyComposition(text?: string, composition?: any): void; + /** + * Pass in `true` to enable overwrites in your session, or `false` to disable. If overwrites is enabled, any text you enter will type over any text after it. If the value of `overwrite` changes, this function also emits the `changeOverwrite` event. + * @param {Boolean} overwrite Defines whether or not to set overwrites + * @related EditSession.setOverwrite + **/ + setOverwrite(overwrite: boolean): void; + /** + * Returns `true` if overwrites are enabled; `false` otherwise. + * @related EditSession.getOverwrite + **/ + getOverwrite(): boolean; + /** + * Sets the value of overwrite to the opposite of whatever it currently is. + * @related EditSession.toggleOverwrite + **/ + toggleOverwrite(): void; + /** + * Sets how fast the mouse scrolling should do. + * @param {Number} speed A value indicating the new speed (in milliseconds) + **/ + setScrollSpeed(speed: number): void; + /** + * Returns the value indicating how fast the mouse scroll speed is (in milliseconds). + **/ + getScrollSpeed(): number; + /** + * Sets the delay (in milliseconds) of the mouse drag. + * @param {Number} dragDelay A value indicating the new delay + **/ + setDragDelay(dragDelay: number): void; + /** + * Returns the current mouse drag delay. + **/ + getDragDelay(): number; + /** + * Draw selection markers spanning whole line, or only over selected text. Default value is "line" + * @param {"fullLine" | "screenLine" | "text" | "line"} val The new selection style "line"|"text" + **/ + setSelectionStyle(val: "fullLine" | "screenLine" | "text" | "line"): void; + /** + * Returns the current selection style. + **/ + getSelectionStyle(): import("ace-code").Ace.EditorOptions["selectionStyle"]; + /** + * Determines whether or not the current line should be highlighted. + * @param {Boolean} shouldHighlight Set to `true` to highlight the current line + **/ + setHighlightActiveLine(shouldHighlight: boolean): void; + /** + * Returns `true` if current lines are always highlighted. + **/ + getHighlightActiveLine(): boolean; + setHighlightGutterLine(shouldHighlight: boolean): void; + getHighlightGutterLine(): boolean; + /** + * Determines if the currently selected word should be highlighted. + * @param {Boolean} shouldHighlight Set to `true` to highlight the currently selected word + **/ + setHighlightSelectedWord(shouldHighlight: boolean): void; + /** + * Returns `true` if currently highlighted words are to be highlighted. + **/ + getHighlightSelectedWord(): boolean; + setAnimatedScroll(shouldAnimate: boolean): void; + getAnimatedScroll(): boolean; + /** + * If `showInvisibles` is set to `true`, invisible characters—like spaces or new lines—are show in the editor. + * @param {Boolean} showInvisibles Specifies whether or not to show invisible characters + **/ + setShowInvisibles(showInvisibles: boolean): void; + /** + * Returns `true` if invisible characters are being shown. + **/ + getShowInvisibles(): boolean; + setDisplayIndentGuides(display: boolean): void; + getDisplayIndentGuides(): boolean; + setHighlightIndentGuides(highlight: boolean): void; + getHighlightIndentGuides(): boolean; + /** + * If `showPrintMargin` is set to `true`, the print margin is shown in the editor. + * @param {Boolean} showPrintMargin Specifies whether or not to show the print margin + * + **/ + setShowPrintMargin(showPrintMargin: boolean): void; + /** + * Returns `true` if the print margin is being shown. + **/ + getShowPrintMargin(): boolean; + /** + * Sets the column defining where the print margin should be. + * @param {Number} showPrintMargin Specifies the new print margin + * + **/ + setPrintMarginColumn(showPrintMargin: number): void; + /** + * Returns the column number of where the print margin is. + **/ + getPrintMarginColumn(): number; + /** + * If `readOnly` is true, then the editor is set to read-only mode, and none of the content can change. + * @param {Boolean} readOnly Specifies whether the editor can be modified or not + **/ + setReadOnly(readOnly: boolean): void; + /** + * Returns `true` if the editor is set to read-only mode. + **/ + getReadOnly(): boolean; + /** + * Specifies whether to use behaviors or not. ["Behaviors" in this case is the auto-pairing of special characters, like quotation marks, parenthesis, or brackets.]{: #BehaviorsDef} + * @param {Boolean} enabled Enables or disables behaviors + **/ + setBehavioursEnabled(enabled: boolean): void; + /** + * Returns `true` if the behaviors are currently enabled. {:BehaviorsDef} + **/ + getBehavioursEnabled(): boolean; + /** + * Specifies whether to use wrapping behaviors or not, i.e. automatically wrapping the selection with characters such as brackets + * when such a character is typed in. + * @param {Boolean} enabled Enables or disables wrapping behaviors + **/ + setWrapBehavioursEnabled(enabled: boolean): void; + /** + * Returns `true` if the wrapping behaviors are currently enabled. + **/ + getWrapBehavioursEnabled(): boolean; + /** + * Indicates whether the fold widgets should be shown or not. + * @param {Boolean} show Specifies whether the fold widgets are shown + **/ + setShowFoldWidgets(show: boolean): void; + /** + * Returns `true` if the fold widgets are shown. + **/ + getShowFoldWidgets(): boolean; + setFadeFoldWidgets(fade: boolean): void; + getFadeFoldWidgets(): boolean; + /** + * Removes the current selection or one character. + * @param {'left' | 'right'} [dir] The direction of the deletion to occur, either "left" or "right" + **/ + remove(dir?: "left" | "right"): void; + /** + * Removes the word directly to the right of the current selection. + **/ + removeWordRight(): void; + /** + * Removes the word directly to the left of the current selection. + **/ + removeWordLeft(): void; + /** + * Removes all the words to the left of the current selection, until the start of the line. + **/ + removeToLineStart(): void; + /** + * Removes all the words to the right of the current selection, until the end of the line. + **/ + removeToLineEnd(): void; + /** + * Splits the line at the current selection (by inserting an `'\n'`). + **/ + splitLine(): void; + /** + * Set the "ghost" text in provided position. "Ghost" text is a kind of + * preview text inside the editor which can be used to preview some code + * inline in the editor such as, for example, code completions. + * + * @param {String} text Text to be inserted as "ghost" text + * @param {Point} [position] Position to insert text to + */ + setGhostText(text: string, position?: Point): void; + /** + * Removes "ghost" text currently displayed in the editor. + */ + removeGhostText(): void; + /** + * Transposes current line. + **/ + transposeLetters(): void; + /** + * Converts the current selection entirely into lowercase. + **/ + toLowerCase(): void; + /** + * Converts the current selection entirely into uppercase. + **/ + toUpperCase(): void; + /** + * Inserts an indentation into the current cursor position or indents the selected lines. + * + * @related EditSession.indentRows + **/ + indent(): void; + /** + * Indents the current line. + * @related EditSession.indentRows + **/ + blockIndent(): void; + /** + * Outdents the current line. + * @related EditSession.outdentRows + **/ + blockOutdent(): void; + sortLines(): void; + /** + * Given the currently selected range, this function either comments all the lines, or uncomments all of them. + **/ + toggleCommentLines(): void; + toggleBlockComment(): void; + /** + * Works like [[EditSession.getTokenAt]], except it returns a number. + **/ + getNumberAt(row: any, column: any): any; + /** + * If the character before the cursor is a number, this functions changes its value by `amount`. + * @param {Number} amount The value to change the numeral by (can be negative to decrease value) + **/ + modifyNumber(amount: number): void; + toggleWord(): void; + /** + * Finds link at defined {row} and {column} + **/ + findLinkAt(row: any, column: any): string; + /** + * Open valid url under cursor in another tab + **/ + openLink(): boolean; + /** + * Removes all the lines in the current selection + * @related EditSession.remove + **/ + removeLines(): void; + duplicateSelection(): void; + /** + * Shifts all the selected lines down one row. + * + * @related EditSession.moveLinesUp + **/ + moveLinesDown(): void; + /** + * Shifts all the selected lines up one row. + * @related EditSession.moveLinesDown + **/ + moveLinesUp(): void; + /** + * Moves a range of text from the given range to the given position. `toPosition` is an object that looks like this: + * ```json + * { row: newRowLocation, column: newColumnLocation } + * ``` + * @param {Range} range The range of text you want moved within the document + * @param {Point} toPosition The location (row and column) where you want to move the text to + * + * @returns {Range} The new range where the text was moved to. + * @related EditSession.moveText + **/ + moveText(range: Range, toPosition: Point, copy?: boolean): Range; + /** + * Copies all the selected lines up one row. + * + **/ + copyLinesUp(): void; + /** + * Copies all the selected lines down one row. + * @related EditSession.duplicateLines + * + **/ + copyLinesDown(): void; + inVirtualSelectionMode: boolean; + /** + * {:VirtualRenderer.getFirstVisibleRow} + * + * @related VirtualRenderer.getFirstVisibleRow + **/ + getFirstVisibleRow(): number; + /** + * {:VirtualRenderer.getLastVisibleRow} + * + * @related VirtualRenderer.getLastVisibleRow + **/ + getLastVisibleRow(): number; + /** + * Indicates if the row is currently visible on the screen. + * @param {Number} row The row to check + * + **/ + isRowVisible(row: number): boolean; + /** + * Indicates if the entire row is currently visible on the screen. + * @param {Number} row The row to check + * + * + **/ + isRowFullyVisible(row: number): boolean; + /** + * Selects the text from the current position of the document until where a "page down" finishes. + **/ + selectPageDown(): void; + /** + * Selects the text from the current position of the document until where a "page up" finishes. + **/ + selectPageUp(): void; + /** + * Shifts the document to wherever "page down" is, as well as moving the cursor position. + **/ + gotoPageDown(): void; + /** + * Shifts the document to wherever "page up" is, as well as moving the cursor position. + **/ + gotoPageUp(): void; + /** + * Scrolls the document to wherever "page down" is, without changing the cursor position. + **/ + scrollPageDown(): void; + /** + * Scrolls the document to wherever "page up" is, without changing the cursor position. + **/ + scrollPageUp(): void; + /** + * Moves the editor to the specified row. + * @related VirtualRenderer.scrollToRow + */ + scrollToRow(row: number): void; + /** + * Scrolls to a line. If `center` is `true`, it puts the line in middle of screen (or attempts to). + * @param {Number} line The line to scroll to + * @param {Boolean} center If `true` + * @param {Boolean} animate If `true` animates scrolling + * @param {() => void} [callback] Function to be called when the animation has finished + * + * @related VirtualRenderer.scrollToLine + **/ + scrollToLine(line: number, center: boolean, animate: boolean, callback?: () => void): void; + /** + * Attempts to center the current selection on the screen. + **/ + centerSelection(): void; + /** + * Gets the current position of the cursor. + * @returns {Point} An object that looks something like this: + * + * ```json + * { row: currRow, column: currCol } + * ``` + * + * @related Selection.getCursor + **/ + getCursorPosition(): Point; + /** + * Returns the screen position of the cursor. + * @related EditSession.documentToScreenPosition + **/ + getCursorPositionScreen(): Point; + /** + * {:Selection.getRange} + * @related Selection.getRange + **/ + getSelectionRange(): Range; + /** + * Selects all the text in editor. + * @related Selection.selectAll + **/ + selectAll(): void; + /** + * {:Selection.clearSelection} + * @related Selection.clearSelection + **/ + clearSelection(): void; + /** + * Moves the cursor to the specified row and column. Note that this does not de-select the current selection. + * @param {Number} row The new row number + * @param {Number} column The new column number + * @related Selection.moveCursorTo + **/ + moveCursorTo(row: number, column: number): void; + /** + * Moves the cursor to the position indicated by `pos.row` and `pos.column`. + * @param {Point} pos An object with two properties, row and column + * @related Selection.moveCursorToPosition + **/ + moveCursorToPosition(pos: Point): void; + /** + * Moves the cursor's row and column to the next matching bracket or HTML tag. + */ + jumpToMatching(select?: boolean, expand?: boolean): void; + /** + * Moves the cursor to the specified line number, and also into the indicated column. + * @param {Number} lineNumber The line number to go to + * @param {Number} [column] A column number to go to + * @param {Boolean} [animate] If `true` animates scolling + **/ + gotoLine(lineNumber: number, column?: number, animate?: boolean): void; + /** + * Moves the cursor to the specified row and column. Note that this does de-select the current selection. + * @param {Number} row The new row number + * @param {Number} column The new column number + * + * @related Editor.moveCursorTo + **/ + navigateTo(row: number, column: number): void; + /** + * Moves the cursor up in the document the specified number of times. Note that this does de-select the current selection. + * @param {Number} [times] The number of times to change navigation + * + **/ + navigateUp(times?: number): void; + /** + * Moves the cursor down in the document the specified number of times. Note that this does de-select the current selection. + * @param {Number} [times] The number of times to change navigation + * + **/ + navigateDown(times?: number): void; + /** + * Moves the cursor left in the document the specified number of times. Note that this does de-select the current selection. + * @param {Number} [times] The number of times to change navigation + * + **/ + navigateLeft(times?: number): void; + /** + * Moves the cursor right in the document the specified number of times. Note that this does de-select the current selection. + * @param {Number} [times] The number of times to change navigation + * + **/ + navigateRight(times?: number): void; + /** + * + * Moves the cursor to the start of the current line. Note that this does de-select the current selection. + **/ + navigateLineStart(): void; + /** + * + * Moves the cursor to the end of the current line. Note that this does de-select the current selection. + **/ + navigateLineEnd(): void; + /** + * + * Moves the cursor to the end of the current file. Note that this does de-select the current selection. + **/ + navigateFileEnd(): void; + /** + * + * Moves the cursor to the start of the current file. Note that this does de-select the current selection. + **/ + navigateFileStart(): void; + /** + * + * Moves the cursor to the word immediately to the right of the current position. Note that this does de-select the current selection. + **/ + navigateWordRight(): void; + /** + * + * Moves the cursor to the word immediately to the left of the current position. Note that this does de-select the current selection. + **/ + navigateWordLeft(): void; + /** + * Replaces the first occurrence of `options.needle` with the value in `replacement`. + * @param {String} [replacement] The text to replace with + * @param {Partial} [options] The [[Search `Search`]] options to use + **/ + replace(replacement?: string, options?: Partial): number; + /** + * Replaces all occurrences of `options.needle` with the value in `replacement`. + * @param {String} [replacement] The text to replace with + * @param {Partial} [options] The [[Search `Search`]] options to use + **/ + replaceAll(replacement?: string, options?: Partial): number; + /** + * {:Search.getOptions} For more information on `options`, see [[Search `Search`]]. + * @related Search.getOptions + **/ + getLastSearchOptions(): Partial; + /** + * Attempts to find `needle` within the document. For more information on `options`, see [[Search `Search`]]. + * @param {String|RegExp|Object} needle The text to search for (optional) + * @param {Partial} [options] An object defining various search properties + * @param {Boolean} [animate] If `true` animate scrolling + * @related Search.find + **/ + find(needle: string | RegExp | any, options?: Partial, animate?: boolean): false | Range; + /** + * Performs another search for `needle` in the document. For more information on `options`, see [[Search `Search`]]. + * @param {Partial} [options] search options + * @param {Boolean} [animate] If `true` animate scrolling + * + * @related Editor.find + **/ + findNext(options?: Partial, animate?: boolean): void; + /** + * Performs a search for `needle` backwards. For more information on `options`, see [[Search `Search`]]. + * @param {Partial} [options] search options + * @param {Boolean} [animate] If `true` animate scrolling + * + * @related Editor.find + **/ + findPrevious(options?: Partial, animate?: boolean): void; + revealRange(range: Range, animate?: boolean): void; + /** + * {:UndoManager.undo} + * @related UndoManager.undo + **/ + undo(): void; + /** + * {:UndoManager.redo} + * @related UndoManager.redo + **/ + redo(): void; + /** + * + * Cleans up the entire editor. + **/ + destroy(): void; + /** + * Enables automatic scrolling of the cursor into view when editor itself is inside scrollable element + * @param {Boolean} enable default true + **/ + setAutoScrollEditorIntoView(enable: boolean): void; + /** + * opens a prompt displaying message + **/ + prompt(message: any, options: any, callback: any): void; + env?: any; + widgetManager?: import("ace-code").Ace.LineWidgets; + completer?: import("ace-code").Ace.Autocomplete | import("ace-code").Ace.InlineAutocomplete; + completers: import("ace-code").Ace.Completer[]; + showKeyboardShortcuts?: () => void; + showSettingsMenu?: () => void; + searchBox?: import("ace-code").Ace.SearchBox; + } + export namespace Editor { + export { $uid }; + } + export type VirtualRenderer = import("ace-code/src/virtual_renderer").VirtualRenderer; + export type Selection = import("ace-code/src/selection").Selection; + export type Point = import("ace-code").Ace.Point; + export type SearchOptions = import("ace-code").Ace.SearchOptions; + import { EditSession } from "ace-code/src/edit_session"; + import { CommandManager } from "ace-code/src/commands/command_manager"; + import { MouseHandler } from "ace-code/src/mouse/mouse_handler"; + import { KeyBinding } from "ace-code/src/keyboard/keybinding"; + import { Search } from "ace-code/src/search"; + import { Range } from "ace-code/src/range"; + var $uid: number; + namespace Ace { + type EditorMultiSelectProperties = import("ace-code").Ace.EditorMultiSelectProperties; + type OptionsProvider = import("ace-code").Ace.OptionsProvider; + type EditorOptions = import("ace-code").Ace.EditorOptions; + type EventEmitter = import("ace-code").Ace.EventEmitter; + type EditorEvents = import("ace-code").Ace.EditorEvents; + type CodeLenseEditorExtension = import("ace-code").Ace.CodeLenseEditorExtension; + type ElasticTabstopsEditorExtension = import("ace-code").Ace.ElasticTabstopsEditorExtension; + type TextareaEditorExtension = import("ace-code").Ace.TextareaEditorExtension; + type PromptEditorExtension = import("ace-code").Ace.PromptEditorExtension; + type OptionsEditorExtension = import("ace-code").Ace.OptionsEditorExtension; + type EditSession = import("ace-code").Ace.EditSession; + type LineWidgets = import("ace-code").Ace.LineWidgets; + type Autocomplete = import("ace-code").Ace.Autocomplete; + type InlineAutocomplete = import("ace-code").Ace.InlineAutocomplete; + type Completer = import("ace-code").Ace.Completer; + type SearchBox = import("ace-code").Ace.SearchBox; + } + export interface Editor extends Ace.EditorMultiSelectProperties, Ace.OptionsProvider, Ace.EventEmitter, Ace.CodeLenseEditorExtension, Ace.ElasticTabstopsEditorExtension, Ace.TextareaEditorExtension, Ace.PromptEditorExtension, Ace.OptionsEditorExtension { + session: Ace.EditSession; + env?: any; + widgetManager?: Ace.LineWidgets; + completer?: Ace.Autocomplete | Ace.InlineAutocomplete; + completers: Ace.Completer[]; + showKeyboardShortcuts?: () => void; + showSettingsMenu?: () => void; + searchBox?: Ace.SearchBox; + } +} +declare module "ace-code/src/undomanager" { + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type Delta = import("ace-code").Ace.Delta; + export type Point = import("ace-code").Ace.Point; + export type IRange = import("ace-code").Ace.IRange; + /** + * This object maintains the undo stack for an [[EditSession `EditSession`]]. + **/ + export class UndoManager { + addSession(session: EditSession): void; + /** + * Provides a means for implementing your own undo manager. `options` has one property, `args`, an [[Array `Array`]], with two elements: + * + * - `args[0]` is an array of deltas + * - `args[1]` is the document to associate with + * + **/ + add(delta: import("ace-code").Ace.Delta, allowMerge: boolean, session?: EditSession): void; + lastDeltas: any[]; + addSelection(selection: any, rev?: number): void; + startNewGroup(): any; + markIgnored(from: number, to?: number): void; + getSelection(rev: number, after?: boolean): { + value: string; + rev: number; + }; + getRevision(): number; + getDeltas(from: number, to?: number): import("ace-code").Ace.Delta[]; + getChangedRanges(from: number, to?: number): void; + getChangedLines(from: number, to?: number): void; + /** + * [Perform an undo operation on the document, reverting the last change.]{: #UndoManager.undo} + **/ + undo(session: EditSession, dontSelect?: boolean): void; + /** + * [Perform a redo operation on the document, reimplementing the last change.]{: #UndoManager.redo} + * + **/ + redo(session: EditSession, dontSelect?: boolean): void; + /** + * Destroys the stack of undo and redo redo operations. + **/ + reset(): void; + mark: number; + selections: any[]; + /** + * Returns `true` if there are undo operations left to perform. + **/ + canUndo(): boolean; + /** + * Returns `true` if there are redo operations left to perform. + **/ + canRedo(): boolean; + /** + * Marks the current status clean + */ + bookmark(rev?: number): void; + /** + * Returns if the current status is clean + **/ + isAtBookmark(): boolean; + /** + * Returns an object which can be safely stringified into JSON + */ + toJSON(): object; + /** + * Takes in an object which was returned from the toJSON method above, + * and resets the current undoManager instance to use the previously exported + * instance state. + */ + fromJSON(json: object): void; + hasUndo: () => boolean; + hasRedo: () => boolean; + isClean: () => boolean; + markClean: (rev?: number) => void; + } +} +declare module "ace-code/src/tokenizer" { + /** + * This class takes a set of highlighting rules, and creates a tokenizer out of them. For more information, see [the wiki on extending highlighters](https://github.com/ajaxorg/ace/wiki/Creating-or-Extending-an-Edit-Mode#wiki-extendingTheHighlighter). + **/ + export class Tokenizer { + /** + * Constructs a new tokenizer based on the given rules and flags. + * @param {Object} rules The highlighting rules + **/ + constructor(rules: any); + splitRegex: RegExp; + states: any; + regExps: {}; + matchMappings: {}; + removeCapturingGroups(src: string): string; + createSplitterRegexp(src: string, flag: string): RegExp; + /** + * Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state. + */ + getLineTokens(line: string, startState: string | string[]): { + tokens: import("ace-code").Ace.Token[]; + state: string | string[]; + }; + reportError: (msg: any, data: any) => void; + } +} +declare module "ace-code/src/autocomplete/popup" { + /** + * This object is used in some places where needed to show popups - like prompt; autocomplete etc. + */ + export class AcePopup { + /** + * Creates and renders single line editor in popup window. If `parentNode` param is isset, then attaching it to this element. + */ + constructor(parentNode?: Element); + setSelectOnHover: (val: boolean) => void; + setRow: (line: number) => void; + getRow: () => number; + getHoveredRow: () => number; + filterText: string; + isOpen: boolean; + isTopdown: boolean; + autoSelect: boolean; + data: import("ace-code").Ace.Completion[]; + setData: (data: import("ace-code").Ace.Completion[], filterText: string) => void; + getData: (row: number) => import("ace-code").Ace.Completion; + hide: () => void; + anchor: "top" | "bottom"; + anchorPosition: import("ace-code").Ace.Point; + tryShow: (pos: any, lineHeight: number, anchor: "top" | "bottom", forceShow?: boolean) => boolean; + show: (pos: any, lineHeight: number, topdownOnly?: boolean) => void; + goTo: (where: import("ace-code").Ace.AcePopupNavigation) => void; + getTextLeftOffset: () => number; + anchorPos: any; + isMouseOver?: boolean; + selectedNode?: HTMLElement; + } + export function $singleLineEditor(el?: HTMLElement): Editor; + export function getAriaId(index: any): string; + import { Editor } from "ace-code/src/editor"; + namespace Ace { + type AcePopupWithEditor = import("ace-code").Ace.AcePopupWithEditor; + type Completion = import("ace-code").Ace.Completion; + type Point = import("ace-code").Ace.Point; + type AcePopupNavigation = import("ace-code").Ace.AcePopupNavigation; + } + export interface AcePopup extends Ace.AcePopupWithEditor { + setSelectOnHover: (val: boolean) => void; + setRow: (line: number) => void; + getRow: () => number; + getHoveredRow: () => number; + filterText: string; + isOpen: boolean; + isTopdown: boolean; + autoSelect: boolean; + data: Ace.Completion[]; + setData: (data: Ace.Completion[], filterText: string) => void; + getData: (row: number) => Ace.Completion; + hide: () => void; + anchor: "top" | "bottom"; + anchorPosition: Ace.Point; + tryShow: (pos: any, lineHeight: number, anchor: "top" | "bottom", forceShow?: boolean) => boolean; + show: (pos: any, lineHeight: number, topdownOnly?: boolean) => void; + goTo: (where: Ace.AcePopupNavigation) => void; + getTextLeftOffset: () => number; + anchorPos: any; + isMouseOver?: boolean; + selectedNode?: HTMLElement; + } +} +declare module "ace-code/src/range_list" { + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type Point = import("ace-code").Ace.Point; + export class RangeList { + ranges: any[]; + pointIndex(pos: Point, excludeEdges?: boolean, startIndex?: number): number; + add(range: Range): any[]; + addList(list: Range[]): any[]; + substractPoint(pos: Point): any[]; + merge(): any[]; + contains(row: number, column: number): boolean; + containsPoint(pos: Point): boolean; + rangeAtPoint(pos: Point): any; + clipRows(startRow: number, endRow: number): any[]; + removeAll(): any[]; + attach(session: EditSession): void; + session: import("ace-code/src/edit_session").EditSession; + onChange: any; + detach(): void; + comparePoints: (p1: import("ace-code/src/range").Point, p2: import("ace-code/src/range").Point) => number; + } + import { Range } from "ace-code/src/range"; +} +declare module "ace-code/src/snippets" { + export const snippetManager: SnippetManager; + export type Snippet = { + content?: string; + replaceBefore?: string; + replaceAfter?: string; + startRe?: RegExp; + endRe?: RegExp; + triggerRe?: RegExp; + endTriggerRe?: RegExp; + trigger?: string; + endTrigger?: string; + matchBefore?: string[]; + matchAfter?: string[]; + name?: string; + tabTrigger?: string; + guard?: string; + endGuard?: string; + }; + class SnippetManager { + snippetMap: {}; + snippetNameMap: {}; + variables: { + CURRENT_WORD: (editor: any) => any; + SELECTION: (editor: any, name: any, indentation: any) => any; + CURRENT_LINE: (editor: any) => any; + PREV_LINE: (editor: any) => any; + LINE_INDEX: (editor: any) => any; + LINE_NUMBER: (editor: any) => any; + SOFT_TABS: (editor: any) => "YES" | "NO"; + TAB_SIZE: (editor: any) => any; + CLIPBOARD: (editor: any) => any; + FILENAME: (editor: any) => string; + FILENAME_BASE: (editor: any) => string; + DIRECTORY: (editor: any) => string; + FILEPATH: (editor: any) => string; + WORKSPACE_NAME: () => string; + FULLNAME: () => string; + BLOCK_COMMENT_START: (editor: any) => any; + BLOCK_COMMENT_END: (editor: any) => any; + LINE_COMMENT: (editor: any) => any; + CURRENT_YEAR: any; + CURRENT_YEAR_SHORT: any; + CURRENT_MONTH: any; + CURRENT_MONTH_NAME: any; + CURRENT_MONTH_NAME_SHORT: any; + CURRENT_DATE: any; + CURRENT_DAY_NAME: any; + CURRENT_DAY_NAME_SHORT: any; + CURRENT_HOUR: any; + CURRENT_MINUTE: any; + CURRENT_SECOND: any; + }; + getTokenizer(): Tokenizer; + createTokenizer(): any; + tokenizeTmSnippet(str: any, startState: any): (string | import("ace-code").Ace.Token)[]; + getVariableValue(editor: any, name: any, indentation: any): any; + tmStrFormat(str: any, ch: any, editor: any): any; + tmFormatFunction(str: any, ch: any, editor: any): any; + resolveVariables(snippet: any, editor: any): any[]; + getDisplayTextForSnippet(editor: any, snippetText: any): any; + insertSnippetForSelection(editor: any, snippetText: any, options?: {}): void; + insertSnippet(editor: any, snippetText: any, options?: {}): void; + getActiveScopes(editor: any): any[]; + expandWithTab(editor: any, options: any): any; + expandSnippetForSelection(editor: any, options: any): boolean; + findMatchingSnippet(snippetList: Snippet[], before: string, after: string): Snippet; + register(snippets: any[], scope: string): void; + unregister(snippets: any, scope: any): void; + parseSnippetFile(str: any): Snippet[]; + getSnippetByName(name: any, editor: any): undefined; + } + import { Tokenizer } from "ace-code/src/tokenizer"; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + } + interface SnippetManager extends Ace.EventEmitter { + } +} +declare module "ace-code/src/autocomplete/inline_screenreader" { + /** + * This object is used to communicate inline code completions rendered into an editor with ghost text to screen reader users. + */ + export class AceInlineScreenReader { + /** + * Creates the off-screen div in which the ghost text content in redered and which the screen reader reads. + */ + constructor(editor: import("ace-code/src/editor").Editor); + editor: import("ace-code/src/editor").Editor; + screenReaderDiv: HTMLDivElement; + /** + * Set the ghost text content to the screen reader div + */ + setScreenReaderContent(content: string): void; + popup: import("ace-code/src/autocomplete/popup").AcePopup; + destroy(): void; + /** + * Take this._lines, render it as blocks and add those to the screen reader div. + */ + createCodeBlock(): HTMLPreElement; + } +} +declare module "ace-code/src/autocomplete/inline" { + export type Editor = import("ace-code/src/editor").Editor; + /** + * This object is used to manage inline code completions rendered into an editor with ghost text. + */ + export class AceInline { + editor: any; + /** + * Renders the completion as ghost text to the current cursor position + * @returns {boolean} True if the completion could be rendered to the editor, false otherwise + */ + show(editor: Editor, completion: import("ace-code").Ace.Completion, prefix: string): boolean; + inlineScreenReader: AceInlineScreenReader; + isOpen(): boolean; + hide(): boolean; + destroy(): void; + } + import { AceInlineScreenReader } from "ace-code/src/autocomplete/inline_screenreader"; +} +declare module "ace-code/src/autocomplete/util" { + export function parForEach(array: any, fn: any, callback: any): void; + export function retrievePrecedingIdentifier(text: any, pos: any, regex: any): string; + export function retrieveFollowingIdentifier(text: any, pos: any, regex: any): any[]; + export function getCompletionPrefix(editor: any): string; + export function triggerAutocomplete(editor: Editor, previousChar?: string): boolean; + export type Editor = import("ace-code/src/editor").Editor; +} +declare module "ace-code/src/autocomplete" { + /** + * This object controls the autocompletion components and their lifecycle. + * There is an autocompletion popup, an optional inline ghost text renderer and a docuent tooltip popup inside. + */ + export class Autocomplete { + static get completionsForLoading(): { + caption: any; + value: string; + }[]; + static for(editor: Editor): Autocomplete; + autoInsert: boolean; + autoSelect: boolean; + autoShown: boolean; + exactMatch: boolean; + inlineEnabled: boolean; + keyboardHandler: HashHandler; + parentNode: any; + setSelectOnHover: boolean; + /** + * @property {Boolean} showLoadingState - A boolean indicating whether the loading states of the Autocompletion should be shown to the end-user. If enabled + * it shows a loading indicator on the popup while autocomplete is loading. + * + * Experimental: This visualisation is not yet considered stable and might change in the future. + */ + showLoadingState: boolean; + /** + * @property {number} stickySelectionDelay - a numerical value that determines after how many ms the popup selection will become 'sticky'. + * Normally, when new elements are added to an open popup, the selection is reset to the first row of the popup. If sticky, the focus will remain + * on the currently selected item when new items are added to the popup. Set to a negative value to disable this feature and never set selection to sticky. + */ + stickySelectionDelay: number; + blurListener(e: any): void; + changeListener(e: any): void; + mousedownListener(e: any): void; + mousewheelListener(e: any): void; + changeTimer: { + (timeout?: number): void; + delay(timeout?: number): void; + schedule: any; + call(): void; + cancel(): void; + isPending(): any; + }; + tooltipTimer: { + (timeout?: number): void; + delay(timeout?: number): void; + schedule: any; + call(): void; + cancel(): void; + isPending(): any; + }; + popupTimer: { + (timeout?: number): void; + delay(timeout?: number): void; + schedule: any; + call(): void; + cancel(): void; + isPending(): any; + }; + stickySelectionTimer: { + (timeout?: number): void; + delay(timeout?: number): void; + schedule: any; + call(): void; + cancel(): void; + isPending(): any; + }; + popup: AcePopup; + inlineRenderer: AceInline; + getPopup(): AcePopup; + stickySelection: boolean; + observeLayoutChanges(): void; + unObserveLayoutChanges(): void; + openPopup(editor: Editor, prefix: string, keepPopupPosition?: boolean): void; + /** + * Detaches all elements from the editor, and cleans up the data for the session + */ + detach(): void; + activated: boolean; + completionProvider: CompletionProvider; + completions: FilteredList; + base: import("ace-code/src/anchor").Anchor; + mouseOutListener(e: any): void; + goTo(where: any): void; + insertMatch(data: Completion, options?: undefined): boolean | void; + /** + * This is the entry point for the autocompletion class, triggers the actions which collect and display suggestions + */ + showPopup(editor: Editor, options?: CompletionOptions): void; + editor: import("ace-code/src/editor").Editor; + getCompletionProvider(initialPosition?: { + pos: Position; + prefix: string; + }): CompletionProvider; + /** + * This method is deprecated, it is only kept for backwards compatibility. + * Use the same method include CompletionProvider instead for the same functionality. + * @deprecated + */ + gatherCompletions(editor: any, callback: any): boolean; + updateCompletions(keepPopupPosition: boolean, options?: CompletionOptions): void; + cancelContextMenu(): void; + updateDocTooltip(): void; + showDocTooltip(item: any): void; + tooltipNode: HTMLDivElement; + hideDocTooltip(): void; + destroy(): void; + commands: { + Up: (editor: any) => void; + Down: (editor: any) => void; + "Ctrl-Up|Ctrl-Home": (editor: any) => void; + "Ctrl-Down|Ctrl-End": (editor: any) => void; + Esc: (editor: any) => void; + Return: (editor: any) => any; + "Shift-Return": (editor: any) => void; + Tab: (editor: any) => any; + Backspace: (editor: any) => void; + PageUp: (editor: any) => void; + PageDown: (editor: any) => void; + }; + emptyMessage?: Function; + } + /** + * This class is responsible for providing completions and inserting them to the editor + */ + export class CompletionProvider { + constructor(initialPosition?: { + pos: Position; + prefix: string; + }); + initialPosition: { + pos: Position; + prefix: string; + }; + active: boolean; + insertByIndex(editor: Editor, index: number, options?: CompletionProviderOptions): boolean; + insertMatch(editor: Editor, data: Completion, options?: CompletionProviderOptions): boolean; + gatherCompletions(editor: Editor, callback: import("ace-code").Ace.CompletionCallbackFunction): boolean; + completers: import("ace-code").Ace.Completer[]; + /** + * This is the entry point to the class, it gathers, then provides the completions asynchronously via callback. + * The callback function may be called multiple times, the last invokation is marked with a `finished` flag + */ + provideCompletions(editor: Editor, options: CompletionProviderOptions, callback: (err: Error | undefined, completions: FilteredList | [ + ], finished: boolean) => void): void; + detach(): void; + completions: import("ace-code").Ace.FilteredList; + } + export type Editor = import("ace-code/src/editor").Editor; + export type CompletionProviderOptions = import("ace-code").Ace.CompletionProviderOptions; + export type CompletionOptions = import("ace-code").Ace.CompletionOptions; + export type Position = import("ace-code").Ace.Position; + export type BaseCompletion = { + /** + * - a numerical value that determines the order in which completions would be displayed. + * A lower score means that the completion would be displayed further from the start + */ + score?: number; + /** + * - a short description of the completion + */ + meta?: string; + /** + * - the text that would be displayed in the completion list. If omitted, value or snippet + * would be shown instead. + */ + caption?: string; + /** + * - an HTML string that would be displayed as an additional popup + */ + docHTML?: string; + /** + * - a plain text that would be displayed as an additional popup. If `docHTML` exists, + * it would be used instead of `docText`. + */ + docText?: string; + /** + * - the identifier of the completer + */ + completerId?: string; + /** + * - An object specifying the range of text to be replaced with the new completion value (experimental) + */ + range?: import("ace-code").Ace.IRange; + /** + * - A command to be executed after the completion is inserted (experimental) + */ + command?: string; + /** + * - a text snippet that would be inserted when the completion is selected + */ + snippet?: string; + /** + * - The text that would be inserted when selecting this completion. + */ + value?: string; + completer?: import("ace-code").Ace.Completer; + hideInlinePreview?: boolean; + }; + export type SnippetCompletion = BaseCompletion & { + snippet: string; + }; + export type ValueCompletion = BaseCompletion & { + value: string; + }; + /** + * Represents a suggested text snippet intended to complete a user's input + */ + export type Completion = SnippetCompletion | ValueCompletion; + import { HashHandler } from "ace-code/src/keyboard/hash_handler"; + import { AcePopup } from "ace-code/src/autocomplete/popup"; + import { AceInline } from "ace-code/src/autocomplete/inline"; + export class FilteredList { + constructor(array: any, filterText: any); + all: any; + filtered: any; + filterText: any; + exactMatch: boolean; + ignoreCaption: boolean; + setFilter(str: any): void; + filterCompletions(items: any, needle: any): any[]; + } + export namespace startCommand { + let name: string; + function exec(editor: any, options: any): void; + let bindKey: string; + } + namespace Ace { + type AcePopup = import("ace-code").Ace.AcePopup; + type FilteredList = import("ace-code").Ace.FilteredList; + } + export interface Autocomplete { + popup: Ace.AcePopup; + emptyMessage?: Function; + } + export interface CompletionProvider { + completions: Ace.FilteredList; + } +} +declare module "ace-code/src/autocomplete/text_completer" { + export function getCompletions(editor: any, session: any, pos: any, prefix: any, callback: any): void; +} +declare module "ace-code/src/line_widgets" { + export class LineWidgets { + constructor(session: EditSession); + session: import("ace-code/src/edit_session").EditSession; + updateOnChange(delta: import("ace-code").Ace.Delta): void; + renderWidgets(e: any, renderer: VirtualRenderer): void; + measureWidgets(e: any, renderer: VirtualRenderer): void; + getRowLength(row: number): number; + attach(editor: Editor): void; + editor: Editor; + detach(e: any): void; + updateOnFold(e: any, session: EditSession): void; + addLineWidget(w: LineWidget): LineWidget; + removeLineWidget(w: LineWidget): void; + getWidgetsAtRow(row: number): LineWidget[]; + firstRow: number; + lastRow: number; + lineWidgets: import("ace-code").Ace.LineWidget[]; + } + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type Editor = import("ace-code/src/editor").Editor; + export type VirtualRenderer = import("ace-code/src/virtual_renderer").VirtualRenderer; + export type LineWidget = import("ace-code").Ace.LineWidget; + namespace Ace { + type LineWidget = import("ace-code").Ace.LineWidget; + type Editor = import("ace-code").Ace.Editor; + } + export interface LineWidgets { + lineWidgets: Ace.LineWidget[]; + editor: Ace.Editor; + } +} +declare module "ace-code/src/search_highlight" { + export type Marker = import("ace-code/src/layer/marker").Marker; + export type EditSession = import("ace-code/src/edit_session").EditSession; + export class SearchHighlight { + constructor(regExp: any, clazz: string, type?: string); + clazz: string; + type: string; + setRegexp(regExp: any): void; + regExp: any; + cache: any[]; + update(html: any, markerLayer: Marker, session: EditSession, config: Partial): void; + MAX_RANGES: number; + } +} +declare module "ace-code/src/occur" { + export type Editor = import("ace-code/src/editor").Editor; + export type Point = import("ace-code").Ace.Point; + export type SearchOptions = import("ace-code").Ace.SearchOptions; + /** + * Finds all lines matching a search term in the current [[Document + * `Document`]] and displays them instead of the original `Document`. Keeps + * track of the mapping between the occur doc and the original doc. + **/ + export class Occur extends Search { + /** + * Enables occur mode. expects that `options.needle` is a search term. + * This search term is used to filter out all the lines that include it + * and these are then used as the content of a new [[Document + * `Document`]]. The current cursor position of editor will be translated + * so that the cursor is on the matching row/column as it was before. + * @param {Object} options options.needle should be a String + * @return {Boolean} Whether occur activation was successful + * + **/ + enter(editor: Editor, options: any): boolean; + /** + * Disables occur mode. Resets the [[Sessions `EditSession`]] [[Document + * `Document`]] back to the original doc. If options.translatePosition is + * truthy also maps the [[Editors `Editor`]] cursor position accordingly. + * @param {Object} options options.translatePosition + * @return {Boolean} Whether occur deactivation was successful + * + **/ + exit(editor: Editor, options: any): boolean; + highlight(sess: EditSession, regexp: RegExp): void; + displayOccurContent(editor: Editor, options: Partial): void; + displayOriginalContent(editor: Editor): void; + /** + * Translates the position from the original document to the occur lines in + * the document or the beginning if the doc {row: 0, column: 0} if not + * found. + * @param {EditSession} session The occur session + * @param {Point} pos The position in the original document + * @return {Point} position in occur doc + **/ + originalToOccurPosition(session: EditSession, pos: Point): Point; + /** + * Translates the position from the occur document to the original document + * or `pos` if not found. + * @param {EditSession} session The occur session + * @param {Point} pos The position in the occur session document + **/ + occurToOriginalPosition(session: EditSession, pos: Point): Point; + matchingLines(session: EditSession, options: Partial): any[]; + } + import { Search } from "ace-code/src/search"; + import { EditSession } from "ace-code/src/edit_session"; +} +declare module "ace-code/src/marker_group" { + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type MarkerGroupItem = { + range: import("ace-code/src/range").Range; + className: string; + }; + export type LayerConfig = import("ace-code").Ace.LayerConfig; + export type Marker = import("ace-code/src/layer/marker").Marker; + export class MarkerGroup { + /** + * @param {{markerType: "fullLine" | "line" | undefined}} [options] Options controlling the behvaiour of the marker. + * User `markerType` to control how the markers which are part of this group will be rendered: + * - `undefined`: uses `text` type markers where only text characters within the range will be highlighted. + * - `fullLine`: will fully highlight all the rows within the range, including the characters before and after the range on the respective rows. + * - `line`: will fully highlight the lines within the range but will only cover the characters between the start and end of the range. + */ + constructor(session: EditSession, options?: { + markerType: "fullLine" | "line" | undefined; + }); + markerType: "line" | "fullLine"; + markers: import("ace-code").Ace.MarkerGroupItem[]; + session: EditSession; + /** + * Finds the first marker containing pos + */ + getMarkerAtPosition(pos: import("ace-code").Ace.Point): import("ace-code").Ace.MarkerGroupItem | undefined; + /** + * Comparator for Array.sort function, which sorts marker definitions by their positions + * + * @param {MarkerGroupItem} a first marker. + * @param {MarkerGroupItem} b second marker. + * @returns {number} negative number if a should be before b, positive number if b should be before a, 0 otherwise. + */ + markersComparator(a: MarkerGroupItem, b: MarkerGroupItem): number; + /** + * Sets marker definitions to be rendered. Limits the number of markers at MAX_MARKERS. + * @param {MarkerGroupItem[]} markers an array of marker definitions. + */ + setMarkers(markers: MarkerGroupItem[]): void; + update(html: any, markerLayer: Marker, session: EditSession, config: LayerConfig): void; + MAX_MARKERS: number; + } +} +declare module "ace-code/src/edit_session/fold" { + export class Fold extends RangeList { + constructor(range: Range, placeholder: any); + foldLine: import("ace-code/src/edit_session/fold_line").FoldLine; + placeholder: any; + range: import("ace-code/src/range").Range; + start: import("ace-code").Ace.Point; + end: import("ace-code").Ace.Point; + sameRow: boolean; + subFolds: Fold[]; + setFoldLine(foldLine: FoldLine): void; + clone(): Fold; + addSubFold(fold: Fold): any; + restoreRange(range: IRange): void; + collapseChildren?: number; + } + export type FoldLine = import("ace-code/src/edit_session/fold_line").FoldLine; + export type Range = import("ace-code/src/range").Range; + export type Point = import("ace-code").Ace.Point; + export type IRange = import("ace-code").Ace.IRange; + import { RangeList } from "ace-code/src/range_list"; + export interface Fold { + collapseChildren?: number; + } +} +declare module "ace-code/src/edit_session/fold_line" { + export type Fold = import("ace-code/src/edit_session/fold").Fold; + export class FoldLine { + /** + * If an array is passed in, the folds are expected to be sorted already. + */ + constructor(foldData: FoldLine[], folds: Fold[] | Fold); + foldData: FoldLine[]; + folds: Fold[]; + range: Range; + start: import("ace-code").Ace.Point; + end: import("ace-code").Ace.Point; + /** + * Note: This doesn't update wrapData! + */ + shiftRow(shift: number): void; + addFold(fold: Fold): void; + containsRow(row: number): boolean; + walk(callback: Function, endRow: number, endColumn: number): void; + getNextFoldTo(row: number, column: number): { + fold: Fold; + kind: string; + } | null; + addRemoveChars(row: number, column: number, len: number): void; + split(row: number, column: number): FoldLine | null; + merge(foldLineNext: FoldLine): void; + toString(): string; + idxToPosition(idx: number): import("ace-code").Ace.Point; + } + import { Range } from "ace-code/src/range"; +} +declare module "ace-code/src/bidihandler" { + export type EditSession = import("ace-code/src/edit_session").EditSession; + /** + * This object is used to ensure Bi-Directional support (for languages with text flowing from right to left, like Arabic or Hebrew) + * including correct caret positioning, text selection mouse and keyboard arrows functioning + **/ + export class BidiHandler { + /** + * Creates a new `BidiHandler` object + * @param {EditSession} session The session to use + **/ + constructor(session: EditSession); + session: import("ace-code/src/edit_session").EditSession; + bidiMap: {}; + currentRow: any; + bidiUtil: typeof bidiUtil; + charWidths: any[]; + EOL: string; + showInvisibles: boolean; + isRtlDir: boolean; + line: string; + wrapIndent: number; + EOF: string; + RLE: string; + contentWidth: number; + fontMetrics: any; + rtlLineOffset: number; + wrapOffset: number; + isMoveLeftOperation: boolean; + seenBidi: boolean; + /** + * Returns 'true' if row contains Bidi characters, in such case + * creates Bidi map to be used in operations related to selection + * (keyboard arrays, mouse click, select) + * @param {Number} screenRow the screen row to be checked + * @param {Number} [docRow] the document row to be checked [optional] + * @param {Number} [splitIndex] the wrapped screen line index [ optional] + **/ + isBidiRow(screenRow: number, docRow?: number, splitIndex?: number): any; + getDocumentRow(): number; + getSplitIndex(): number; + updateRowLine(docRow: any, splitIndex: any): void; + updateBidiMap(): void; + /** + * Resets stored info related to current screen row + **/ + markAsDirty(): void; + /** + * Updates array of character widths + * @param {Object} fontMetrics metrics + * + **/ + updateCharacterWidths(fontMetrics: any): void; + characterWidth: any; + setShowInvisibles(showInvisibles: any): void; + setEolChar(eolChar: any): void; + setContentWidth(width: any): void; + isRtlLine(row: any): boolean; + setRtlDirection(editor: any, isRtlDir: any): void; + /** + * Returns offset of character at position defined by column. + * @param {Number} col the screen column position + * + * @return {Number} horizontal pixel offset of given screen column + **/ + getPosLeft(col: number): number; + /** + * Returns 'selections' - array of objects defining set of selection rectangles + * @param {Number} startCol the start column position + * @param {Number} endCol the end column position + * + * @return {Object[]} Each object contains 'left' and 'width' values defining selection rectangle. + **/ + getSelections(startCol: number, endCol: number): any[]; + /** + * Converts character coordinates on the screen to respective document column number + * @param {Number} posX character horizontal offset + * + * @return {Number} screen column number corresponding to given pixel offset + **/ + offsetToCol(posX: number): number; + } + import bidiUtil = require("ace-code/src/lib/bidiutil"); +} +declare module "ace-code/src/background_tokenizer" { + /** + * Tokenizes the current [[Document `Document`]] in the background, and caches the tokenized rows for future use. + * + * If a certain row is changed, everything below that row is re-tokenized. + **/ + export class BackgroundTokenizer { + /** + * Creates a new `BackgroundTokenizer` object. + * @param {Tokenizer} tokenizer The tokenizer to use + * @param {EditSession} [session] The editor session to associate with + **/ + constructor(tokenizer: Tokenizer, session?: EditSession); + running: false | number; + lines: any[]; + states: string[] | string[][]; + currentLine: number; + tokenizer: import("ace-code/src/tokenizer").Tokenizer; + /** + * Sets a new tokenizer for this object. + * @param {Tokenizer} tokenizer The new tokenizer to use + **/ + setTokenizer(tokenizer: Tokenizer): void; + /** + * Sets a new document to associate with this object. + * @param {Document} doc The new document to associate with + **/ + setDocument(doc: Document): void; + doc: import("ace-code/src/document").Document; + /** + * Emits the `'update'` event. `firstRow` and `lastRow` are used to define the boundaries of the region to be updated. + * @param {Number} firstRow The starting row region + * @param {Number} lastRow The final row region + **/ + fireUpdateEvent(firstRow: number, lastRow: number): void; + /** + * Starts tokenizing at the row indicated. + * @param {Number} startRow The row to start at + **/ + start(startRow: number): void; + /** + * Sets pretty long delay to prevent the tokenizer from interfering with the user + */ + scheduleStart(): void; + /** + * Stops tokenizing. + **/ + stop(): void; + /** + * Gives list of [[Token]]'s of the row. (tokens are cached) + * @param {Number} row The row to get tokens at + **/ + getTokens(row: number): import("ace-code").Ace.Token[]; + /** + * Returns the state of tokenization at the end of a row. + * @param {Number} row The row to get state at + **/ + getState(row: number): string | string[]; + cleanup(): void; + } + export type Document = import("ace-code/src/document").Document; + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type Tokenizer = import("ace-code/src/tokenizer").Tokenizer; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + type BackgroundTokenizerEvents = import("ace-code").Ace.BackgroundTokenizerEvents; + } + export interface BackgroundTokenizer extends Ace.EventEmitter { + } +} +declare module "ace-code/src/edit_session/folding" { + export type IFolding = import("ace-code/src/edit_session").EditSession & import("ace-code").Ace.Folding; + export type Delta = import("ace-code").Ace.Delta; + export function Folding(this: IFolding): void; + export class Folding { + /** + * Looks up a fold at a given row/column. Possible values for side: + * -1: ignore a fold if fold.start = row/column + * +1: ignore a fold if fold.end = row/column + **/ + getFoldAt: (row: number, column: number, side?: number) => import("ace-code").Ace.Fold; + /** + * Returns all folds in the given range. Note, that this will return folds + **/ + getFoldsInRange: (range: import("ace-code").Ace.Range | import("ace-code").Ace.Delta) => import("ace-code").Ace.Fold[]; + getFoldsInRangeList: (ranges: import("ace-code").Ace.Range[] | import("ace-code").Ace.Range) => import("ace-code").Ace.Fold[]; + /** + * Returns all folds in the document + */ + getAllFolds: () => import("ace-code").Ace.Fold[]; + /** + * Returns the string between folds at the given position. + * E.g. + * foob|arwolrd -> "bar" + * foobarwol|rd -> "world" + * foobarwolrd -> + * + * where | means the position of row/column + * + * The trim option determs if the return string should be trimed according + * to the "side" passed with the trim value: + * + * E.g. + * foob|arwolrd -trim=-1> "b" + * foobarwol|rd -trim=+1> "rld" + * fo|obarwolrd -trim=00> "foo" + */ + getFoldStringAt: (row: number, column: number, trim?: number, foldLine?: import("ace-code").Ace.FoldLine) => string | null; + getFoldLine: (docRow: number, startFoldLine?: import("ace-code").Ace.FoldLine) => null | import("ace-code").Ace.FoldLine; + /** + * Returns the fold which starts after or contains docRow + */ + getNextFoldLine: (docRow: number, startFoldLine?: import("ace-code").Ace.FoldLine) => null | import("ace-code").Ace.FoldLine; + getFoldedRowCount: (first: number, last: number) => number; + /** + * Adds a new fold. + * + * The new created Fold object or an existing fold object in case the + * passed in range fits an existing fold exactly. + */ + addFold: (placeholder: import("ace-code").Ace.Fold | string, range?: import("ace-code").Ace.Range) => import("ace-code").Ace.Fold; + addFolds: (folds: import("ace-code").Ace.Fold[]) => void; + removeFold: (fold: import("ace-code").Ace.Fold) => void; + removeFolds: (folds: import("ace-code").Ace.Fold[]) => void; + expandFold: (fold: import("ace-code").Ace.Fold) => void; + expandFolds: (folds: import("ace-code").Ace.Fold[]) => void; + unfold: (location?: number | null | import("ace-code").Ace.Point | import("ace-code").Ace.Range | import("ace-code").Ace.Range[], expandInner?: boolean) => import("ace-code").Ace.Fold[] | undefined; + /** + * Checks if a given documentRow is folded. This is true if there are some + * folded parts such that some parts of the line is still visible. + **/ + isRowFolded: (docRow: number, startFoldRow?: import("ace-code").Ace.FoldLine) => boolean; + getRowFoldEnd: (docRow: number, startFoldRow?: import("ace-code").Ace.FoldLine) => number; + getRowFoldStart: (docRow: number, startFoldRow?: import("ace-code").Ace.FoldLine) => number; + getFoldDisplayLine: (foldLine: import("ace-code").Ace.FoldLine, endRow?: number | null, endColumn?: number | null, startRow?: number | null, startColumn?: number | null) => string; + getDisplayLine: (row: number, endColumn: number | null, startRow: number | null, startColumn: number | null) => string; + toggleFold: (tryToUnfold?: boolean) => void; + getCommentFoldRange: (row: number, column: number, dir?: number) => import("ace-code").Ace.Range | undefined; + foldAll: (startRow?: number | null, endRow?: number | null, depth?: number | null, test?: Function) => void; + foldToLevel: (level: number) => void; + foldAllComments: () => void; + setFoldStyle: (style: string) => void; + getParentFoldRangeData: (row: number, ignoreCurrent?: boolean) => { + range?: import("ace-code").Ace.Range; + firstRange?: import("ace-code").Ace.Range; + }; + onFoldWidgetClick: (row: number, e: any) => void; + toggleFoldWidget: (toggleParent?: boolean) => void; + updateFoldWidgets: (delta: import("ace-code").Ace.Delta) => void; + tokenizerUpdateFoldWidgets: (e: any) => void; + } +} +declare module "ace-code/src/edit_session/bracket_match" { + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type Point = import("ace-code/src/edit_session").Point; + export function BracketMatch(): void; + export class BracketMatch { + findMatchingBracket: (this: import("ace-code/src/edit_session").EditSession, position: Point, chr?: string) => import("ace-code").Ace.Point; + getBracketRange: (this: import("ace-code/src/edit_session").EditSession, pos: Point) => null | Range; + /** + * Returns: + * * null if there is no any bracket at `pos`; + * * two Ranges if there is opening and closing brackets; + * * one Range if there is only one bracket + * + */ + getMatchingBracketRanges: (this: import("ace-code/src/edit_session").EditSession, pos: Point, isBackwards?: boolean) => null | Range[]; + /** + * Returns [[Range]]'s for matching tags and tag names, if there are any + */ + getMatchingTags: (this: import("ace-code/src/edit_session").EditSession, pos: Point) => { + closeTag: Range; + closeTagName: Range; + openTag: Range; + openTagName: Range; + } | undefined; + } + import { Range } from "ace-code/src/range"; +} +declare module "ace-code/src/edit_session" { + /** + * Stores all the data about [[Editor `Editor`]] state providing easy way to change editors state. + * + * `EditSession` can be attached to only one [[Document `Document`]]. Same `Document` can be attached to several `EditSession`s. + **/ + export class EditSession { + /** + * Returns a new instance of EditSession with state from JSON. + * @method fromJSON + * @param {string|object} session The EditSession state. + */ + static fromJSON(session: string | object): EditSession; + /** + * Sets up a new `EditSession` and associates it with the given `Document` and `Mode`. + **/ + constructor(text?: Document | string, mode?: SyntaxMode); + doc: Document; + prevOp: {}; + id: string; + bgTokenizer: BackgroundTokenizer; + selection: Selection; + destroyed: boolean; + curOp: { + command: { + name?: string; + }; + args: any; + }; + /** + * Start an Ace operation, which will then batch all the subsequent changes (to either content or selection) under a single atomic operation. + * @param {{command?: {name?: string}, args?: any}|undefined} [commandEvent] Optional name for the operation + */ + startOperation(commandEvent?: { + command?: { + name?: string; + }; + args?: any; + } | undefined): void; + /** + * End current Ace operation. + * Emits "beforeEndOperation" event just before clearing everything, where the current operation can be accessed through `curOp` property. + */ + endOperation(e: any): void; + /** + * Sets the `EditSession` to point to a new `Document`. If a `BackgroundTokenizer` exists, it also points to `doc`. + * + * @param {Document} doc The new `Document` to use + * + **/ + setDocument(doc: Document): void; + /** + * Returns the `Document` associated with this session. + **/ + getDocument(): Document; + /** + * Set "widgetManager" in EditSession + * + */ + set widgetManager(value: LineWidgets); + /** + * Get "widgetManager" from EditSession + * + */ + get widgetManager(): LineWidgets; + resetCaches(): void; + mergeUndoDeltas: boolean; + onSelectionChange(): void; + /** + * Sets the session text. + * @param {String} text The new text to place + **/ + setValue(text: string): void; + /** + * Returns the current edit session. + * @method toJSON + */ + toJSON(): any; + /** + * Returns selection object. + **/ + getSelection(): Selection; + /** + * {:BackgroundTokenizer.getState} + * @param {Number} row The row to start at + * @related BackgroundTokenizer.getState + **/ + getState(row: number): string | string[]; + /** + * Starts tokenizing at the row indicated. Returns a list of objects of the tokenized rows. + * @param {Number} row The row to start at + **/ + getTokens(row: number): import("ace-code").Ace.Token[]; + /** + * Returns an object indicating the token at the current row. The object has two properties: `index` and `start`. + * @param {Number} row The row number to retrieve from + * @param {Number} column The column number to retrieve from + * + **/ + getTokenAt(row: number, column: number): import("ace-code").Ace.Token; + /** + * Sets the undo manager. + * @param {UndoManager} undoManager The new undo manager + **/ + setUndoManager(undoManager: UndoManager): void; + /** + * starts a new group in undo history + **/ + markUndoGroup(): void; + /** + * Returns the current undo manager. + **/ + getUndoManager(): UndoManager; + /** + * Returns the current value for tabs. If the user is using soft tabs, this will be a series of spaces (defined by [[EditSession.getTabSize `getTabSize()`]]); otherwise it's simply `'\t'`. + **/ + getTabString(): string; + /** + * Pass `true` to enable the use of soft tabs. Soft tabs means you're using spaces instead of the tab character (`'\t'`). + * @param {Boolean} val Value indicating whether or not to use soft tabs + **/ + setUseSoftTabs(val: boolean): void; + /** + * Returns `true` if soft tabs are being used, `false` otherwise. + **/ + getUseSoftTabs(): boolean; + /** + * Set the number of spaces that define a soft tab; for example, passing in `4` transforms the soft tabs to be equivalent to four spaces. This function also emits the `changeTabSize` event. + * @param {Number} tabSize The new tab size + **/ + setTabSize(tabSize: number): void; + /** + * Returns the current tab size. + **/ + getTabSize(): number; + /** + * Returns `true` if the character at the position is a soft tab. + * @param {Point} position The position to check + **/ + isTabStop(position: Point): boolean; + /** + * Set whether keyboard navigation of soft tabs moves the cursor within the soft tab, rather than over + * @param {Boolean} navigateWithinSoftTabs Value indicating whether or not to navigate within soft tabs + **/ + setNavigateWithinSoftTabs(navigateWithinSoftTabs: boolean): void; + /** + * Returns `true` if keyboard navigation moves the cursor within soft tabs, `false` if it moves the cursor over soft tabs. + **/ + getNavigateWithinSoftTabs(): boolean; + /** + * Pass in `true` to enable overwrites in your session, or `false` to disable. + * + * If overwrites is enabled, any text you enter will type over any text after it. If the value of `overwrite` changes, this function also emits the `changeOverwrite` event. + * + * @param {Boolean} overwrite Defines whether or not to set overwrites + * + **/ + setOverwrite(overwrite: boolean): void; + /** + * Returns `true` if overwrites are enabled; `false` otherwise. + **/ + getOverwrite(): boolean; + /** + * Sets the value of overwrite to the opposite of whatever it currently is. + **/ + toggleOverwrite(): void; + /** + * Adds `className` to the `row`, to be used for CSS stylings and whatnot. + * @param {Number} row The row number + * @param {String} className The class to add + **/ + addGutterDecoration(row: number, className: string): void; + /** + * Removes `className` from the `row`. + * @param {Number} row The row number + * @param {String} className The class to add + **/ + removeGutterDecoration(row: number, className: string): void; + /** + * Returns an array of strings, indicating the breakpoint class (if any) applied to each row. + **/ + getBreakpoints(): string[]; + /** + * Sets a breakpoint on every row number given by `rows`. This function also emites the `'changeBreakpoint'` event. + * @param {number[]} rows An array of row indices + **/ + setBreakpoints(rows: number[]): void; + /** + * Removes all breakpoints on the rows. This function also emits the `'changeBreakpoint'` event. + **/ + clearBreakpoints(): void; + /** + * Sets a breakpoint on the row number given by `row`. This function also emits the `'changeBreakpoint'` event. + * @param {Number} row A row index + * @param {String} className Class of the breakpoint + **/ + setBreakpoint(row: number, className: string): void; + /** + * Removes a breakpoint on the row number given by `row`. This function also emits the `'changeBreakpoint'` event. + * @param {Number} row A row index + **/ + clearBreakpoint(row: number): void; + /** + * Adds a new marker to the given `Range`. If `inFront` is `true`, a front marker is defined, and the `'changeFrontMarker'` event fires; otherwise, the `'changeBackMarker'` event fires. + * @param {Range} range Define the range of the marker + * @param {String} clazz Set the CSS class for the marker + * @param {import("ace-code").Ace.MarkerRenderer | "fullLine" | "screenLine" | "text" | "line"} [type] Identify the renderer type of the marker. If string provided, corresponding built-in renderer is used. Supported string types are "fullLine", "screenLine", "text" or "line". If a Function is provided, that Function is used as renderer. + * @param {Boolean} [inFront] Set to `true` to establish a front marker + * + * @return {Number} The new marker id + **/ + addMarker(range: Range, clazz: string, type?: import("ace-code").Ace.MarkerRenderer | "fullLine" | "screenLine" | "text" | "line", inFront?: boolean): number; + /** + * Adds a dynamic marker to the session. + * @param {import("ace-code").Ace.MarkerLike} marker object with update method + * @param {Boolean} [inFront] Set to `true` to establish a front marker + * + * @return {import("ace-code").Ace.MarkerLike} The added marker + **/ + addDynamicMarker(marker: import("ace-code").Ace.MarkerLike, inFront?: boolean): import("ace-code").Ace.MarkerLike; + /** + * Removes the marker with the specified ID. If this marker was in front, the `'changeFrontMarker'` event is emitted. If the marker was in the back, the `'changeBackMarker'` event is emitted. + * @param {Number} markerId A number representing a marker + **/ + removeMarker(markerId: number): void; + /** + * Returns an object containing all of the markers, either front or back. + * @param {Boolean} [inFront] If `true`, indicates you only want front markers; `false` indicates only back markers + * + **/ + getMarkers(inFront?: boolean): { + [id: number]: import("ace-code").Ace.MarkerLike; + }; + highlight(re: RegExp): void; + /** + * experimental + */ + highlightLines(startRow: number, endRow: number, clazz: string, inFront?: boolean): Range; + /** + * Sets annotations for the `EditSession`. This functions emits the `'changeAnnotation'` event. + * @param {import("ace-code").Ace.Annotation[]} annotations A list of annotations + **/ + setAnnotations(annotations: import("ace-code").Ace.Annotation[]): void; + /** + * Returns the annotations for the `EditSession`. + **/ + getAnnotations(): import("ace-code").Ace.Annotation[]; + /** + * Clears all the annotations for this session. This function also triggers the `'changeAnnotation'` event. + **/ + clearAnnotations(): void; + /** + * Given a starting row and column, this method returns the `Range` of the first word boundary it finds. + * @param {Number} row The row to start at + * @param {Number} column The column to start at + * + **/ + getWordRange(row: number, column: number): Range; + /** + * Gets the range of a word, including its right whitespace. + * @param {Number} row The row number to start from + * @param {Number} column The column number to start from + * + **/ + getAWordRange(row: number, column: number): Range; + /** + * {:Document.setNewLineMode.desc} + * + * + * @related Document.setNewLineMode + **/ + setNewLineMode(newLineMode: import("ace-code").Ace.NewLineMode): void; + /** + * + * Returns the current new line mode. + * @related Document.getNewLineMode + **/ + getNewLineMode(): import("ace-code").Ace.NewLineMode; + /** + * Identifies if you want to use a worker for the `EditSession`. + * @param {Boolean} useWorker Set to `true` to use a worker + **/ + setUseWorker(useWorker: boolean): void; + /** + * Returns `true` if workers are being used. + **/ + getUseWorker(): boolean; + /** + * Sets a new text mode for the `EditSession`. This method also emits the `'changeMode'` event. If a [[BackgroundTokenizer `BackgroundTokenizer`]] is set, the `'tokenizerUpdate'` event is also emitted. + * @param {SyntaxMode | string} mode Set a new text mode + * @param {() => void} [cb] optional callback + **/ + setMode(mode: SyntaxMode | string, cb?: () => void): void; + tokenRe: RegExp; + nonTokenRe: RegExp; + /** + * Returns the current text mode. + * @returns {TextMode} The current text mode + **/ + getMode(): TextMode; + /** + * This function sets the scroll top value. It also emits the `'changeScrollTop'` event. + * @param {Number} scrollTop The new scroll top value + **/ + setScrollTop(scrollTop: number): void; + /** + * [Returns the value of the distance between the top of the editor and the topmost part of the visible content.]{: #EditSession.getScrollTop} + **/ + getScrollTop(): number; + /** + * [Sets the value of the distance between the left of the editor and the leftmost part of the visible content.]{: #EditSession.setScrollLeft} + */ + setScrollLeft(scrollLeft: number): void; + /** + * [Returns the value of the distance between the left of the editor and the leftmost part of the visible content.]{: #EditSession.getScrollLeft} + **/ + getScrollLeft(): number; + /** + * Returns the width of the screen. + **/ + getScreenWidth(): number; + getLineWidgetMaxWidth(): number; + lineWidgetWidth: number; + screenWidth: any; + /** + * Returns a verbatim copy of the given line as it is in the document + * @param {Number} row The row to retrieve from + **/ + getLine(row: number): string; + /** + * Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`. + * @param {Number} firstRow The first row index to retrieve + * @param {Number} lastRow The final row index to retrieve + * + * + **/ + getLines(firstRow: number, lastRow: number): string[]; + /** + * Returns the number of rows in the document. + **/ + getLength(): number; + /** + * {:Document.getTextRange.desc} + * @param {IRange} [range] The range to work with + * + **/ + getTextRange(range?: IRange): string; + /** + * Inserts a block of `text` and the indicated `position`. + * @param {Point} position The position {row, column} to start inserting at + * @param {String} text A chunk of text to insert + * @returns {Point} The position of the last line of `text`. If the length of `text` is 0, this function simply returns `position`. + **/ + insert(position: Point, text: string): Point; + /** + * Removes the `range` from the document. + * @param {IRange} range A specified Range to remove + * @returns {Point} The new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`. + **/ + remove(range: IRange): Point; + /** + * Removes a range of full lines. This method also triggers the `'change'` event. + * @param {Number} firstRow The first row to be removed + * @param {Number} lastRow The last row to be removed + * @returns {String[]} Returns all the removed lines. + * + * @related Document.removeFullLines + * + **/ + removeFullLines(firstRow: number, lastRow: number): string[]; + /** + * Reverts previous changes to your document. + * @param {Delta[]} deltas An array of previous changes + * @param {Boolean} [dontSelect] If `true`, doesn't select the range of where the change occured + **/ + undoChanges(deltas: Delta[], dontSelect?: boolean): void; + /** + * Re-implements a previously undone change to your document. + * @param {Delta[]} deltas An array of previous changes + **/ + redoChanges(deltas: Delta[], dontSelect?: boolean): void; + /** + * Enables or disables highlighting of the range where an undo occurred. + * @param {Boolean} enable If `true`, selects the range of the reinserted change + * + **/ + setUndoSelect(enable: boolean): void; + /** + * Replaces a range in the document with the new `text`. + * + * @param {IRange} range A specified Range to replace + * @param {String} text The new text to use as a replacement + * @returns {Point} An object containing the final row and column, like this: + * ``` + * {row: endRow, column: 0} + * ``` + * If the text and range are empty, this function returns an object containing the current `range.start` value. + * If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value. + * + * @related Document.replace + **/ + replace(range: IRange, text: string): Point; + /** + * Moves a range of text from the given range to the given position. `toPosition` is an object that looks like this: + * ```json + * { row: newRowLocation, column: newColumnLocation } + * ``` + * @param {Range} fromRange The range of text you want moved within the document + * @param {Point} toPosition The location (row and column) where you want to move the text to + * @returns {Range} The new range where the text was moved to. + **/ + moveText(fromRange: Range, toPosition: Point, copy?: boolean): Range; + /** + * Indents all the rows, from `startRow` to `endRow` (inclusive), by prefixing each row with the token in `indentString`. + * + * If `indentString` contains the `'\t'` character, it's replaced by whatever is defined by [[EditSession.getTabString `getTabString()`]]. + * @param {Number} startRow Starting row + * @param {Number} endRow Ending row + * @param {String} indentString The indent token + **/ + indentRows(startRow: number, endRow: number, indentString: string): void; + /** + * Outdents all the rows defined by the `start` and `end` properties of `range`. + * @param {Range} range A range of rows + **/ + outdentRows(range: Range): void; + /** + * Shifts all the lines in the document up one, starting from `firstRow` and ending at `lastRow`. + * @param {Number} firstRow The starting row to move up + * @param {Number} lastRow The final row to move up + * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. + **/ + moveLinesUp(firstRow: number, lastRow: number): number; + /** + * Shifts all the lines in the document down one, starting from `firstRow` and ending at `lastRow`. + * @param {Number} firstRow The starting row to move down + * @param {Number} lastRow The final row to move down + * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. + **/ + moveLinesDown(firstRow: number, lastRow: number): number; + /** + * Duplicates all the text between `firstRow` and `lastRow`. + * @param {Number} firstRow The starting row to duplicate + * @param {Number} lastRow The final row to duplicate + * @returns {Number} Returns the number of new rows added; in other words, `lastRow - firstRow + 1`. + **/ + duplicateLines(firstRow: number, lastRow: number): number; + /** + * Sets whether or not line wrapping is enabled. If `useWrapMode` is different than the current value, the `'changeWrapMode'` event is emitted. + * @param {Boolean} useWrapMode Enable (or disable) wrap mode + **/ + setUseWrapMode(useWrapMode: boolean): void; + /** + * Returns `true` if wrap mode is being used; `false` otherwise. + **/ + getUseWrapMode(): boolean; + /** + * Sets the boundaries of wrap. Either value can be `null` to have an unconstrained wrap, or, they can be the same number to pin the limit. If the wrap limits for `min` or `max` are different, this method also emits the `'changeWrapMode'` event. + * @param {Number} min The minimum wrap value (the left side wrap) + * @param {Number} max The maximum wrap value (the right side wrap) + **/ + setWrapLimitRange(min: number, max: number): void; + /** + * This should generally only be called by the renderer when a resize is detected. + * @param {Number} desiredLimit The new wrap limit + **/ + adjustWrapLimit(desiredLimit: number, $printMargin?: any): boolean; + /** + * Returns the value of wrap limit. + * @returns {Number} The wrap limit. + **/ + getWrapLimit(): number; + /** + * Sets the line length for soft wrap in the editor. Lines will break + * at a minimum of the given length minus 20 chars and at a maximum + * of the given number of chars. + * @param {number} limit The maximum line length in chars, for soft wrapping lines. + */ + setWrapLimit(limit: number): void; + /** + * Returns an object that defines the minimum and maximum of the wrap limit; it looks something like this: + * + * { min: wrapLimitRange_min, max: wrapLimitRange_max } + * + **/ + getWrapLimitRange(): { + min: number; + max: number; + }; + /** + * Returns number of screenrows in a wrapped line. + * @param {Number} row The row number to check + **/ + getRowLength(row: number): number; + getRowLineCount(row: number): number; + getRowWrapIndent(screenRow: number): number; + /** + * Returns the position (on screen) for the last character in the provided screen row. + * @param {Number} screenRow The screen row to check + * + * @related EditSession.documentToScreenColumn + **/ + getScreenLastRowColumn(screenRow: number): number; + /** + * For the given document row and column, this returns the column position of the last screen row. + **/ + getDocumentLastRowColumn(docRow: number, docColumn: number): number; + /** + * For the given document row and column, this returns the document position of the last row. + **/ + getDocumentLastRowColumnPosition(docRow: number, docColumn: number): Point; + /** + * For the given row, this returns the split data. + */ + getRowSplitData(row: number): string | undefined; + /** + * The distance to the next tab stop at the specified screen column. + * @param {Number} screenColumn The screen column to check + * + **/ + getScreenTabSize(screenColumn: number): number; + screenToDocumentRow(screenRow: number, screenColumn: number): number; + screenToDocumentColumn(screenRow: number, screenColumn: number): number; + /** + * Converts characters coordinates on the screen to characters coordinates within the document. [This takes into account code folding, word wrap, tab size, and any other visual modifications.]{: #conversionConsiderations} + * @param {Number} screenRow The screen row to check + * @param {Number} screenColumn The screen column to check + * @param {Number} [offsetX] screen character x-offset [optional] + * + * @returns {Point} The object returned has two properties: `row` and `column`. + * + * @related EditSession.documentToScreenPosition + **/ + screenToDocumentPosition(screenRow: number, screenColumn: number, offsetX?: number): Point; + /** + * Converts document coordinates to screen coordinates. {:conversionConsiderations} + * @param {Number|Point} docRow The document row to check + * @param {Number|undefined} [docColumn] The document column to check + * @returns {Point} The object returned by this method has two properties: `row` and `column`. + * + * @related EditSession.screenToDocumentPosition + **/ + documentToScreenPosition(docRow: number | Point, docColumn?: number | undefined): Point; + /** + * For the given document row and column, returns the screen column. + **/ + documentToScreenColumn(row: number | Point, docColumn?: number): number; + /** + * For the given document row and column, returns the screen row. + **/ + documentToScreenRow(docRow: number | Point, docColumn?: number): number; + /** + * Returns the length of the screen. + **/ + getScreenLength(): number; + /** + * @returns {string} the last character preceding the cursor in the editor + */ + getPrecedingCharacter(): string; + destroy(): void; + /** + * Returns the current [[Document `Document`]] as a string. + * @method getValue + * @alias EditSession.toString + **/ + getValue: () => string; + lineWidgets: null | import("ace-code").Ace.LineWidget[]; + isFullWidth: typeof isFullWidth; + lineWidgetsWidth?: number; + gutterRenderer?: any; + selectionMarkerCount?: number; + multiSelect?: any; + getSelectionMarkers(): any[]; + } + export namespace EditSession { + export { $uid }; + } + export type FontMetrics = import("ace-code/src/layer/font_metrics").FontMetrics; + export type FoldLine = import("ace-code/src/edit_session/fold_line").FoldLine; + export type Point = import("ace-code").Ace.Point; + export type Delta = import("ace-code").Ace.Delta; + export type IRange = import("ace-code").Ace.IRange; + export type SyntaxMode = import("ace-code").Ace.SyntaxMode; + export type LineWidget = import("ace-code").Ace.LineWidget; + export type TextMode = SyntaxMode; + import { Document } from "ace-code/src/document"; + import { BackgroundTokenizer } from "ace-code/src/background_tokenizer"; + import { Selection } from "ace-code/src/selection"; + import { BidiHandler } from "ace-code/src/bidihandler"; + import { Range } from "ace-code/src/range"; + import { LineWidgets } from "ace-code/src/line_widgets"; + import { UndoManager } from "ace-code/src/undomanager"; + function isFullWidth(c: any): boolean; + var $uid: number; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + type EditSessionEvents = import("ace-code").Ace.EditSessionEvents; + type OptionsProvider = import("ace-code").Ace.OptionsProvider; + type EditSessionOptions = import("ace-code").Ace.EditSessionOptions; + type Folding = import("ace-code").Ace.Folding; + type BracketMatch = import("ace-code").Ace.BracketMatch; + type Document = import("ace-code").Ace.Document; + type Point = import("ace-code").Ace.Point; + type Occur = import("ace-code").Ace.Occur; + } + export interface EditSession extends Ace.EventEmitter, Ace.OptionsProvider, Ace.Folding, Ace.BracketMatch { + doc: Ace.Document; + lineWidgetsWidth?: number; + gutterRenderer?: any; + selectionMarkerCount?: number; + multiSelect?: any; + getSelectionMarkers(): any[]; + } +} +declare module "ace-code/src/range" { + /** + * This object is used in various places to indicate a region within the editor. To better visualize how this works, imagine a rectangle. Each quadrant of the rectangle is analogous to a range, as ranges contain a starting row and starting column, and an ending row, and ending column. + **/ + export class Range { + /** + * Creates a new `Range` object with the given starting and ending rows and columns. + * @param {Number} [startRow] The starting row + * @param {Number} [startColumn] The starting column + * @param {Number} [endRow] The ending row + * @param {Number} [endColumn] The ending column + * @constructor + **/ + constructor(startRow?: number, startColumn?: number, endRow?: number, endColumn?: number); + start: Point; + end: Point; + /** + * Returns `true` if and only if the starting row and column, and ending row and column, are equivalent to those given by `range`. + * @param {IRange} range A range to check against + **/ + isEqual(range: IRange): boolean; + /** + * Returns a string containing the range's row and column information, given like this: + * ``` + * [start.row/start.column] -> [end.row/end.column] + * ``` + **/ + toString(): string; + /** + * Returns `true` if the `row` and `column` provided are within the given range. This can better be expressed as returning `true` if: + * ```javascript + * this.start.row <= row <= this.end.row && + * this.start.column <= column <= this.end.column + * ``` + * @param {Number} row A row to check for + * @param {Number} column A column to check for + * @related [[Range.compare]] + **/ + contains(row: number, column: number): boolean; + /** + * Compares `this` range (A) with another range (B). + * @param {IRange} range A range to compare with + * @related [[Range.compare]] + * @returns {Number} This method returns one of the following numbers: + * * `-2`: (B) is in front of (A), and doesn't intersect with (A) + * * `-1`: (B) begins before (A) but ends inside of (A) + * * `0`: (B) is completely inside of (A) + * * `+1`: (B) begins inside of (A) but ends outside of (A) + * * `+2`: (B) is after (A) and doesn't intersect with (A) + * * `42`: FTW state: (B) ends in (A) but starts outside of (A) + **/ + compareRange(range: IRange): number; + /** + * Compares the row and column of `p` with the starting and ending [[Point]]'s of the calling range (by calling [[Range.compare]]). + * @param {Point} p A point to compare with + * @related [[Range.compare]] + **/ + comparePoint(p: Point): number; + /** + * Checks the start and end [[Point]]'s of `range` and compares them to the calling range. Returns `true` if the `range` is contained within the caller's range. + * @param {IRange} range A range to compare with + * @related [[Range.comparePoint]] + **/ + containsRange(range: IRange): boolean; + /** + * Returns `true` if passed in `range` intersects with the one calling this method. + * @param {IRange} range A range to compare with + **/ + intersects(range: IRange): boolean; + /** + * Returns `true` if the caller's ending row is the same as `row`, and if the caller's ending column is the same as `column`. + * @param {Number} row A row to compare with + * @param {Number} column A column to compare with + **/ + isEnd(row: number, column: number): boolean; + /** + * Returns `true` if the caller's starting row is the same as `row`, and if the caller's starting column is the same as `column`. + * @param {Number} row A row to compare with + * @param {Number} column A column to compare with + **/ + isStart(row: number, column: number): boolean; + /** + * Sets the starting row and column for the range. + * @param {Number|Point} row A row to set + * @param {Number} [column] A column to set + * + **/ + setStart(row: number | Point, column?: number): void; + /** + * Sets the starting row and column for the range. + * @param {Number|Point} row A row to set + * @param {Number} [column] A column to set + * + **/ + setEnd(row: number | Point, column?: number): void; + /** + * Returns `true` if the `row` and `column` are within the given range. + * @param {Number} row A row to compare with + * @param {Number} column A column to compare with + * @related [[Range.compare]] + **/ + inside(row: number, column: number): boolean; + /** + * Returns `true` if the `row` and `column` are within the given range's starting [[Point]]. + * @param {Number} row A row to compare with + * @param {Number} column A column to compare with + * @related [[Range.compare]] + **/ + insideStart(row: number, column: number): boolean; + /** + * Returns `true` if the `row` and `column` are within the given range's ending [[Point]]. + * @param {Number} row A row to compare with + * @param {Number} column A column to compare with + * @related [[Range.compare]] + * + **/ + insideEnd(row: number, column: number): boolean; + /** + * Compares the `row` and `column` with the starting and ending [[Point]]'s of the calling range. + * @param {Number} row A row to compare with + * @param {Number} column A column to compare with + * @returns {Number} This method returns one of the following numbers: + * * `1` if `row` is greater than the calling range + * * `-1` if `row` is less then the calling range + * * `0` otherwise + * + * If the starting row of the calling range is equal to `row`, and: + * * `column` is greater than or equal to the calling range's starting column, this returns `0` + * * Otherwise, it returns -1 + * + * If the ending row of the calling range is equal to `row`, and: + * * `column` is less than or equal to the calling range's ending column, this returns `0` + * * Otherwise, it returns 1 + **/ + compare(row: number, column: number): number; + /** + * Compares the `row` and `column` with the starting and ending [[Point]]'s of the calling range. + * @param {Number} row A row to compare with + * @param {Number} column A column to compare with + * @returns {Number} This method returns one of the following numbers: + * * `-1` if calling range's starting column and calling range's starting row are equal `row` and `column` + * * Otherwise, it returns the value after calling [[Range.compare `compare()`]]. + **/ + compareStart(row: number, column: number): number; + /** + * Compares the `row` and `column` with the starting and ending [[Point]]'s of the calling range. + * @param {Number} row A row to compare with + * @param {Number} column A column to compare with + * @returns {Number} This method returns one of the following numbers: + * * `1` if calling range's ending column and calling range's ending row are equal `row` and `column`. + * * Otherwise, it returns the value after calling [[Range.compare `compare()`]]. + */ + compareEnd(row: number, column: number): number; + /** + * Compares the `row` and `column` with the start and end [[Point]]'s of the calling range. + * @param {Number} row A row to compare with + * @param {Number} column A column to compare with + * @returns {Number} This method returns one of the following numbers: + * * `1` if the ending row of the calling range is equal to `row`, and the ending column of the calling range is equal to `column` + * * `-1` if the starting row of the calling range is equal to `row`, and the starting column of the calling range is equal to `column` + * * Otherwise, it returns the value after calling [[Range.compare `compare()`]]. + **/ + compareInside(row: number, column: number): number; + /** + * Returns the part of the current `Range` that occurs within the boundaries of `firstRow` and `lastRow` as a new `Range` object. + * @param {Number} firstRow The starting row + * @param {Number} lastRow The ending row + **/ + clipRows(firstRow: number, lastRow: number): Range; + /** + * Changes the `row` and `column` for the calling range for both the starting and ending [[Point]]'s. + * @param {Number} row A new row to extend to + * @param {Number} column A new column to extend to + * @returns {Range} The original range with the new row + **/ + extend(row: number, column: number): Range; + /** + * Returns `true` if the calling range is empty (starting [[Point]] == ending [[Point]]). + **/ + isEmpty(): boolean; + /** + * Returns `true` if the range spans across multiple lines. + **/ + isMultiLine(): boolean; + /** + * Returns a duplicate of the calling range. + **/ + clone(): Range; + /** + * Returns a range containing the starting and ending rows of the original range, but with a column value of `0`. + **/ + collapseRows(): Range; + /** + * Given the current `Range`, this function converts those starting and ending [[Point]]'s into screen positions, and then returns a new `Range` object. + * @param {EditSession} session The `EditSession` to retrieve coordinates from + **/ + toScreenRange(session: EditSession): Range; + /** + * Shift the calling range by `row` and `column` values. + * @experimental + */ + moveBy(row: number, column: number): void; + id?: number; + cursor?: import("ace-code").Ace.Point; + isBackwards?: boolean; + } + export namespace Range { + export { fromPoints, comparePoints }; + } + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type IRange = import("ace-code").Ace.IRange; + export type Point = import("ace-code").Ace.Point; + /** + * Creates and returns a new `Range` based on the `start` [[Point]] and `end` [[Point]] of the given parameters. + * @param {Point} start A starting point to use + * @param {Point} end An ending point to use + **/ + function fromPoints(start: Point, end: Point): Range; + /** + * Compares `p1` and `p2` [[Point]]'s, useful for sorting + */ + function comparePoints(p1: Point, p2: Point): number; + namespace Ace { + type Point = import("ace-code").Ace.Point; + } + export interface Range { + id?: number; + cursor?: Ace.Point; + isBackwards?: boolean; + } +} +declare module "ace-code/src/worker/worker_client" { + export var WorkerClient: any; +} +declare module "ace-code/src/placeholder" { + export class PlaceHolder { + constructor(session: EditSession, length: number, pos: import("ace-code").Ace.Point, others: any[], mainClass: string, othersClass: string); + length: number; + session: import("ace-code/src/edit_session").EditSession; + doc: import("ace-code/src/document").Document; + mainClass: string; + othersClass: string; + /** + * PlaceHolder.setup() + * + * TODO + * + **/ + setup(): void; + selectionBefore: Range | Range[]; + pos: import("ace-code/src/anchor").Anchor; + others: any[]; + /** + * PlaceHolder.showOtherMarkers() + * + * TODO + * + **/ + showOtherMarkers(): void; + othersActive: boolean; + /** + * PlaceHolder.hideOtherMarkers() + * + * Hides all over markers in the [[EditSession `EditSession`]] that are not the currently selected one. + * + **/ + hideOtherMarkers(): void; + updateAnchors(delta: import("ace-code").Ace.Delta): void; + updateMarkers(): void; + /** + * PlaceHolder.detach() + * + * TODO + * + **/ + detach(): void; + /** + * PlaceHolder.cancel() + * + * TODO + * + **/ + cancel(): void; + } + export type EditSession = import("ace-code/src/edit_session").EditSession; + import { Range } from "ace-code/src/range"; + namespace Ace { + type EventEmitter = import("ace-code").Ace.EventEmitter; + type PlaceHolderEvents = import("ace-code").Ace.PlaceHolderEvents; + } + export interface PlaceHolder extends Ace.EventEmitter { + } +} +declare module "ace-code/src/mouse/multi_select_handler" { + export function onMouseDown(e: any): any; +} +declare module "ace-code/src/commands/multi_select_commands" { + export const defaultCommands: import("ace-code").Ace.Command[]; + export const multiSelectCommands: import("ace-code").Ace.Command[]; + export const keyboardHandler: HashHandler; + import { HashHandler } from "ace-code/src/keyboard/hash_handler"; +} +declare module "ace-code/src/multi_select" { + export const commands: import("ace-code").Ace.Command[]; + export const onSessionChange: (e: any) => void; + export type Anchor = import("ace-code/src/anchor").Anchor; + export type Point = import("ace-code").Ace.Point; + export type ScreenCoordinates = import("ace-code").Ace.ScreenCoordinates; + export function MultiSelect(editor: Editor): void; + import { Editor } from "ace-code/src/editor"; +} +declare module "ace-code/src/commands/occur_commands" { + export namespace occurStartCommand { + let name: string; + function exec(editor: any, options: any): void; + let readOnly: boolean; + } +} +declare module "ace-code/src/commands/incremental_search_commands" { + export const iSearchStartCommands: ({ + name: string; + bindKey: { + win: string; + mac: string; + }; + exec: (editor: any, options: any) => void; + readOnly: boolean; + } | { + name: string; + exec: (editor: any, jumpToNext: any) => void; + readOnly: boolean; + bindKey?: undefined; + })[]; + export const iSearchCommands: ({ + name: string; + bindKey: { + win: string; + mac: string; + }; + exec: (iSearch: any, options: any) => void; + } | { + name: string; + exec: (iSearch: any, string: any) => void; + bindKey?: undefined; + } | { + name: string; + bindKey: string; + exec: (iSearch: any) => void; + })[]; + export function IncrementalSearchKeyboardHandler(iSearch: any): void; + export class IncrementalSearchKeyboardHandler { + constructor(iSearch: any); + } +} +declare module "ace-code/src/incremental_search" { + /** + * Implements immediate searching while the user is typing. When incremental + * search is activated, keystrokes into the editor will be used for composing + * a search term. Immediately after every keystroke the search is updated: + * - so-far-matching characters are highlighted + * - the cursor is moved to the next match + * + **/ + export class IncrementalSearch extends Search { + activate(editor: any, backwards: boolean): void; + deactivate(reset?: boolean): void; + selectionFix(editor: Editor): void; + highlight(regexp: RegExp): void; + cancelSearch(reset?: boolean): Range; + highlightAndFindWithNeedle(moveToNext: boolean, needleUpdateFunc: Function): false | Range; + addString(s: string): false | Range; + removeChar(c: any): false | Range; + next(options: any): false | Range; + convertNeedleToRegExp(): false | Range; + convertNeedleToString(): false | Range; + statusMessage(found: any): void; + message(msg: any): void; + } + import { Search } from "ace-code/src/search"; + import iSearchCommandModule = require("ace-code/src/commands/incremental_search_commands"); + import { Editor } from "ace-code/src/editor"; + import { Range } from "ace-code/src/range"; +} +declare module "ace-code/src/split" { + export type ISplit = import("ace-code").Ace.EventEmitter & { + [key: string]: any; + }; + export var Split: any; +} +declare module "ace-code/src/tokenizer_dev" { + export class Tokenizer extends BaseTokenizer { + /** + * Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state. + **/ + getLineTokens(line: any, startState: any): any; + } + import { Tokenizer as BaseTokenizer } from "ace-code/src/tokenizer"; +} +declare module "ace-code/src/unicode" { + export const wordChars: any; +} +declare module "ace-code/src/keyboard/textarea" { + export const handler: HashHandler; + import { HashHandler } from "ace-code/src/keyboard/hash_handler"; +} diff --git a/types/ace-snippets.d.ts b/types/ace-snippets.d.ts new file mode 100644 index 00000000000..a3a14cb8cbe --- /dev/null +++ b/types/ace-snippets.d.ts @@ -0,0 +1,402 @@ +/* This file is generated using `npm run update-types` */ + +declare module "ace-code/src/snippets/abc.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/abc" { + export const snippetText: string; + export const scope: "abc"; +} +declare module "ace-code/src/snippets/actionscript.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/actionscript" { + export const snippetText: string; + export const scope: "actionscript"; +} +declare module "ace-code/src/snippets/c_cpp.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/c_cpp" { + export const snippetText: string; + export const scope: "c_cpp"; +} +declare module "ace-code/src/snippets/clojure.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/clojure" { + export const snippetText: string; + export const scope: "clojure"; +} +declare module "ace-code/src/snippets/coffee.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/coffee" { + export const snippetText: string; + export const scope: "coffee"; +} +declare module "ace-code/src/snippets/csound_document.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/csound_document" { + export const snippetText: string; + export const scope: "csound_document"; +} +declare module "ace-code/src/snippets/csound_orchestra.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/csound_orchestra" { + export const snippetText: string; + export const scope: "csound_orchestra"; +} +declare module "ace-code/src/snippets/css.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/css" { + export const snippetText: string; + export const scope: "css"; +} +declare module "ace-code/src/snippets/dart.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/dart" { + export const snippetText: string; + export const scope: "dart"; +} +declare module "ace-code/src/snippets/diff.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/diff" { + export const snippetText: string; + export const scope: "diff"; +} +declare module "ace-code/src/snippets/django.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/django" { + export const snippetText: string; + export const scope: "django"; +} +declare module "ace-code/src/snippets/drools.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/drools" { + export const snippetText: string; + export const scope: "drools"; +} +declare module "ace-code/src/snippets/edifact.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/edifact" { + export const snippetText: string; + export const scope: "edifact"; +} +declare module "ace-code/src/snippets/erlang.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/erlang" { + export const snippetText: string; + export const scope: "erlang"; +} +declare module "ace-code/src/snippets/fsl.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/fsl" { + export const snippetText: string; + export const scope: "fsl"; +} +declare module "ace-code/src/snippets/gobstones.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/gobstones" { + export const snippetText: string; + export const scope: "gobstones"; +} +declare module "ace-code/src/snippets/graphqlschema.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/graphqlschema" { + export const snippetText: string; + export const scope: "graphqlschema"; +} +declare module "ace-code/src/snippets/haml.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/haml" { + export const snippetText: string; + export const scope: "haml"; +} +declare module "ace-code/src/snippets/haskell.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/haskell" { + export const snippetText: string; + export const scope: "haskell"; +} +declare module "ace-code/src/snippets/html.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/html" { + export const snippetText: string; + export const scope: "html"; +} +declare module "ace-code/src/snippets/io" { + export const snippets: ({ + content: string; + name: string; + scope: string; + tabTrigger: string; + keyEquivalent?: undefined; + } | { + content: string; + keyEquivalent: string; + name: string; + scope: string; + tabTrigger: string; + } | { + content: string; + keyEquivalent: string; + name: string; + scope: string; + tabTrigger?: undefined; + })[]; + export const scope: "io"; +} +declare module "ace-code/src/snippets/java.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/java" { + export const snippetText: string; + export const scope: "java"; +} +declare module "ace-code/src/snippets/javascript.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/javascript" { + export const snippetText: string; + export const scope: "javascript"; +} +declare module "ace-code/src/snippets/jsp.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/jsp" { + export const snippetText: string; + export const scope: "jsp"; +} +declare module "ace-code/src/snippets/liquid.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/liquid" { + export const snippetText: string; + export const scope: "liquid"; +} +declare module "ace-code/src/snippets/lsl.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/lsl" { + export const snippetText: string; + export const scope: "lsl"; +} +declare module "ace-code/src/snippets/lua.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/lua" { + export const snippetText: string; + export const scope: "lua"; +} +declare module "ace-code/src/snippets/makefile.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/makefile" { + export const snippetText: string; + export const scope: "makefile"; +} +declare module "ace-code/src/snippets/markdown.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/markdown" { + export const snippetText: string; + export const scope: "markdown"; +} +declare module "ace-code/src/snippets/maze.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/maze" { + export const snippetText: string; + export const scope: "maze"; +} +declare module "ace-code/src/snippets/perl.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/perl" { + export const snippetText: string; + export const scope: "perl"; +} +declare module "ace-code/src/snippets/php.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/php" { + export const snippetText: string; + export const scope: "php"; +} +declare module "ace-code/src/snippets/python.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/python" { + export const snippetText: string; + export const scope: "python"; +} +declare module "ace-code/src/snippets/r.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/r" { + export const snippetText: string; + export const scope: "r"; +} +declare module "ace-code/src/snippets/razor.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/razor" { + export const snippetText: string; + export const scope: "razor"; +} +declare module "ace-code/src/snippets/robot.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/robot" { + export const snippetText: string; + export const scope: "robot"; +} +declare module "ace-code/src/snippets/rst.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/rst" { + export const snippetText: string; + export const scope: "rst"; +} +declare module "ace-code/src/snippets/ruby.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/ruby" { + export const snippetText: string; + export const scope: "ruby"; +} +declare module "ace-code/src/snippets/sh.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/sh" { + export const snippetText: string; + export const scope: "sh"; +} +declare module "ace-code/src/snippets/snippets.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/snippets" { + export const snippetText: string; + export const scope: "snippets"; +} +declare module "ace-code/src/snippets/sql.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/sql" { + export const snippetText: string; + export const scope: "sql"; +} +declare module "ace-code/src/snippets/sqlserver.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/sqlserver" { + export const snippetText: string; + export const scope: "sqlserver"; +} +declare module "ace-code/src/snippets/tcl.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/tcl" { + export const snippetText: string; + export const scope: "tcl"; +} +declare module "ace-code/src/snippets/tex.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/tex" { + export const snippetText: string; + export const scope: "tex"; +} +declare module "ace-code/src/snippets/textile.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/textile" { + export const snippetText: string; + export const scope: "textile"; +} +declare module "ace-code/src/snippets/vala" { + export const snippets: { + content: string; + name: string; + scope: string; + tabTrigger: string; + }[]; + export const scope: ""; +} +declare module "ace-code/src/snippets/velocity.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/velocity" { + export const snippetText: string; + export const scope: "velocity"; + export const includeScopes: string[]; +} +declare module "ace-code/src/snippets/wollok.snippets" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/snippets/wollok" { + export const snippetText: string; + export const scope: "wollok"; +} diff --git a/types/ace-theme.d.ts b/types/ace-theme.d.ts new file mode 100644 index 00000000000..363dd69b787 --- /dev/null +++ b/types/ace-theme.d.ts @@ -0,0 +1,437 @@ +/* This file is generated using `npm run update-types` */ + +declare module "ace-code/src/theme/textmate-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/textmate" { + export const isDark: false; + export const cssClass: "ace-tm"; + export const cssText: string; + export const $id: "ace/theme/textmate"; +} +declare module "ace-code/src/theme/ambiance-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/ambiance" { + export const isDark: true; + export const cssClass: "ace-ambiance"; + export const cssText: string; +} +declare module "ace-code/src/theme/chaos-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/chaos" { + export const isDark: true; + export const cssClass: "ace-chaos"; + export const cssText: string; +} +declare module "ace-code/src/theme/chrome-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/chrome" { + export const isDark: false; + export const cssClass: "ace-chrome"; + export const cssText: string; +} +declare module "ace-code/src/theme/cloud9_day-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/cloud9_day" { + export const isDark: false; + export const cssClass: "ace-cloud9-day"; + export const cssText: string; +} +declare module "ace-code/src/theme/cloud9_night-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/cloud9_night" { + export const isDark: true; + export const cssClass: "ace-cloud9-night"; + export const cssText: string; +} +declare module "ace-code/src/theme/cloud9_night_low_color-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/cloud9_night_low_color" { + export const isDark: true; + export const cssClass: "ace-cloud9-night-low-color"; + export const cssText: string; +} +declare module "ace-code/src/theme/cloud_editor-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/cloud_editor" { + export const isDark: false; + export const cssClass: "ace-cloud_editor"; + export const cssText: string; +} +declare module "ace-code/src/theme/cloud_editor_dark-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/cloud_editor_dark" { + export const isDark: true; + export const cssClass: "ace-cloud_editor_dark"; + export const cssText: string; +} +declare module "ace-code/src/theme/clouds-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/clouds" { + export const isDark: false; + export const cssClass: "ace-clouds"; + export const cssText: string; +} +declare module "ace-code/src/theme/clouds_midnight-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/clouds_midnight" { + export const isDark: true; + export const cssClass: "ace-clouds-midnight"; + export const cssText: string; +} +declare module "ace-code/src/theme/cobalt-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/cobalt" { + export const isDark: true; + export const cssClass: "ace-cobalt"; + export const cssText: string; +} +declare module "ace-code/src/theme/crimson_editor-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/crimson_editor" { + export const isDark: false; + export const cssText: string; + export const cssClass: "ace-crimson-editor"; +} +declare module "ace-code/src/theme/dawn-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/dawn" { + export const isDark: false; + export const cssClass: "ace-dawn"; + export const cssText: string; +} +declare module "ace-code/src/theme/dracula-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/dracula" { + export const isDark: true; + export const cssClass: "ace-dracula"; + export const cssText: string; + export const $selectionColorConflict: true; +} +declare module "ace-code/src/theme/dreamweaver-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/dreamweaver" { + export const isDark: false; + export const cssClass: "ace-dreamweaver"; + export const cssText: string; +} +declare module "ace-code/src/theme/eclipse-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/eclipse" { + export const isDark: false; + export const cssText: string; + export const cssClass: "ace-eclipse"; +} +declare module "ace-code/src/theme/github-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/github" { + export const isDark: false; + export const cssClass: "ace-github"; + export const cssText: string; +} +declare module "ace-code/src/theme/github_dark-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/github_dark" { + export const isDark: true; + export const cssClass: "ace-github-dark"; + export const cssText: string; +} +declare module "ace-code/src/theme/github_light_default-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/github_light_default" { + export const isDark: false; + export const cssClass: "ace-github-light-default"; + export const cssText: string; +} +declare module "ace-code/src/theme/gob-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/gob" { + export const isDark: true; + export const cssClass: "ace-gob"; + export const cssText: string; +} +declare module "ace-code/src/theme/gruvbox-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/gruvbox" { + export const isDark: true; + export const cssClass: "ace-gruvbox"; + export const cssText: string; +} +declare module "ace-code/src/theme/gruvbox_dark_hard-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/gruvbox_dark_hard" { + export const isDark: true; + export const cssClass: "ace-gruvbox-dark-hard"; + export const cssText: string; +} +declare module "ace-code/src/theme/gruvbox_light_hard-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/gruvbox_light_hard" { + export const isDark: false; + export const cssClass: "ace-gruvbox-light-hard"; + export const cssText: string; +} +declare module "ace-code/src/theme/idle_fingers-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/idle_fingers" { + export const isDark: true; + export const cssClass: "ace-idle-fingers"; + export const cssText: string; +} +declare module "ace-code/src/theme/iplastic-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/iplastic" { + export const isDark: false; + export const cssClass: "ace-iplastic"; + export const cssText: string; +} +declare module "ace-code/src/theme/katzenmilch-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/katzenmilch" { + export const isDark: false; + export const cssClass: "ace-katzenmilch"; + export const cssText: string; +} +declare module "ace-code/src/theme/kr_theme-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/kr_theme" { + export const isDark: true; + export const cssClass: "ace-kr-theme"; + export const cssText: string; +} +declare module "ace-code/src/theme/kuroir-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/kuroir" { + export const isDark: false; + export const cssClass: "ace-kuroir"; + export const cssText: string; +} +declare module "ace-code/src/theme/merbivore-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/merbivore" { + export const isDark: true; + export const cssClass: "ace-merbivore"; + export const cssText: string; +} +declare module "ace-code/src/theme/merbivore_soft-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/merbivore_soft" { + export const isDark: true; + export const cssClass: "ace-merbivore-soft"; + export const cssText: string; +} +declare module "ace-code/src/theme/mono_industrial-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/mono_industrial" { + export const isDark: true; + export const cssClass: "ace-mono-industrial"; + export const cssText: string; +} +declare module "ace-code/src/theme/monokai-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/monokai" { + export const isDark: true; + export const cssClass: "ace-monokai"; + export const cssText: string; +} +declare module "ace-code/src/theme/nord_dark-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/nord_dark" { + export const isDark: true; + export const cssClass: "ace-nord-dark"; + export const cssText: string; + export const $selectionColorConflict: true; +} +declare module "ace-code/src/theme/one_dark-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/one_dark" { + export const isDark: true; + export const cssClass: "ace-one-dark"; + export const cssText: string; +} +declare module "ace-code/src/theme/pastel_on_dark-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/pastel_on_dark" { + export const isDark: true; + export const cssClass: "ace-pastel-on-dark"; + export const cssText: string; +} +declare module "ace-code/src/theme/solarized_dark-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/solarized_dark" { + export const isDark: true; + export const cssClass: "ace-solarized-dark"; + export const cssText: string; +} +declare module "ace-code/src/theme/solarized_light-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/solarized_light" { + export const isDark: false; + export const cssClass: "ace-solarized-light"; + export const cssText: string; +} +declare module "ace-code/src/theme/sqlserver-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/sqlserver" { + export const isDark: false; + export const cssClass: "ace-sqlserver"; + export const cssText: string; +} +declare module "ace-code/src/theme/terminal-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/terminal" { + export const isDark: true; + export const cssClass: "ace-terminal-theme"; + export const cssText: string; +} +declare module "ace-code/src/theme/tomorrow-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/tomorrow" { + export const isDark: false; + export const cssClass: "ace-tomorrow"; + export const cssText: string; +} +declare module "ace-code/src/theme/tomorrow_night-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/tomorrow_night" { + export const isDark: true; + export const cssClass: "ace-tomorrow-night"; + export const cssText: string; +} +declare module "ace-code/src/theme/tomorrow_night_blue-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/tomorrow_night_blue" { + export const isDark: true; + export const cssClass: "ace-tomorrow-night-blue"; + export const cssText: string; +} +declare module "ace-code/src/theme/tomorrow_night_bright-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/tomorrow_night_bright" { + export const isDark: true; + export const cssClass: "ace-tomorrow-night-bright"; + export const cssText: string; +} +declare module "ace-code/src/theme/tomorrow_night_eighties-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/tomorrow_night_eighties" { + export const isDark: true; + export const cssClass: "ace-tomorrow-night-eighties"; + export const cssText: string; +} +declare module "ace-code/src/theme/twilight-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/twilight" { + export const isDark: true; + export const cssClass: "ace-twilight"; + export const cssText: string; +} +declare module "ace-code/src/theme/vibrant_ink-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/vibrant_ink" { + export const isDark: true; + export const cssClass: "ace-vibrant-ink"; + export const cssText: string; +} +declare module "ace-code/src/theme/xcode-css" { + const _exports: string; + export = _exports; +} +declare module "ace-code/src/theme/xcode" { + export const isDark: false; + export const cssClass: "ace-xcode"; + export const cssText: string; +} From 16a75fc98ac7694dac50dfca9027ecac5157695a Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Thu, 28 Nov 2024 19:14:52 +0400 Subject: [PATCH 1184/1293] Fix test runner (#5686) * fix test runner not opening in browser * remove unused amd-loader * remove spurious warnings about messages in tests * fix sckipped mode loading test --- src/anchor_test.js | 4 -- src/background_tokenizer_test.js | 4 -- src/commands/command_manager_test.js | 4 -- src/config_test.js | 9 ++--- src/document_test.js | 4 -- src/edit_session_test.js | 52 +++++++++++++++++++------- src/ext/beautify_test.js | 4 -- src/ext/emmet_test.js | 4 -- src/ext/error_marker_test.js | 4 -- src/ext/hardwrap_test.js | 4 -- src/ext/static_highlight_test.js | 4 -- src/ext/whitespace_test.js | 4 -- src/incremental_search_test.js | 4 -- src/keyboard/keybinding_test.js | 4 -- src/keyboard/textinput_test.js | 4 -- src/keyboard/vim_ace_test.js | 4 -- src/lib/app_config.js | 2 +- src/lib/event_emitter_test.js | 4 -- src/mode/_test/highlight_rules_test.js | 2 - src/mode/ada_test.js | 4 -- src/mode/coldfusion_test.js | 4 -- src/mode/css_test.js | 4 -- src/mode/folding/basic_test.js | 3 -- src/mode/folding/coffee_test.js | 3 -- src/mode/folding/cstyle_test.js | 3 -- src/mode/folding/fold_mode_test.js | 3 -- src/mode/folding/html_test.js | 3 -- src/mode/folding/javascript_test.js | 3 -- src/mode/folding/latex_test.js | 2 - src/mode/folding/lua_test.js | 2 - src/mode/folding/php_test.js | 2 - src/mode/folding/pythonic_test.js | 3 -- src/mode/folding/ruby_test.js | 3 -- src/mode/folding/vbscript_test.js | 3 -- src/mode/folding/xml_test.js | 3 -- src/mode/folding/yaml_test.js | 3 -- src/mode/html_test.js | 4 -- src/mode/javascript_test.js | 4 -- src/mode/logiql_test.js | 4 -- src/mode/odin_test.js | 4 -- src/mode/php_test.js | 4 -- src/mode/plain_text_test.js | 4 -- src/mode/python_test.js | 4 -- src/mode/ruby_test.js | 4 -- src/mode/text_test.js | 4 -- src/mode/vbscript_test.js | 4 -- src/mode/xml_test.js | 4 -- src/occur_test.js | 4 -- src/range_list_test.js | 4 -- src/range_test.js | 4 -- src/search_test.js | 6 +-- src/selection_test.js | 4 -- src/test/benchmark.js | 4 -- src/test/tests.html | 2 +- static.js | 27 +++++++------ translations/am.json | 8 +++- translations/es.json | 8 +++- translations/ru.json | 8 +++- 58 files changed, 83 insertions(+), 216 deletions(-) diff --git a/src/anchor_test.js b/src/anchor_test.js index 0512cd6b6c3..4f9a2ecbcd0 100644 --- a/src/anchor_test.js +++ b/src/anchor_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var Document = require("./document").Document; diff --git a/src/background_tokenizer_test.js b/src/background_tokenizer_test.js index f761d47c03d..d3d83628367 100644 --- a/src/background_tokenizer_test.js +++ b/src/background_tokenizer_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("./edit_session").EditSession; diff --git a/src/commands/command_manager_test.js b/src/commands/command_manager_test.js index 24d8c674df2..68719ab1adc 100644 --- a/src/commands/command_manager_test.js +++ b/src/commands/command_manager_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var CommandManager = require("./command_manager").CommandManager; diff --git a/src/config_test.js b/src/config_test.js index 9dbc5048b2a..0b658a53bc3 100644 --- a/src/config_test.js +++ b/src/config_test.js @@ -1,14 +1,13 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var config = require("./config"); var assert = require("./test/assertions"); +var {defaultEnglishMessages} = require("./lib/default_english_messages"); module.exports = { - + tearDown: function() { + config.setMessages(defaultEnglishMessages); + }, "test: path resolution" : function(done) { config.set("packaged", true); var url = config.moduleUrl("kr_theme", "theme"); diff --git a/src/document_test.js b/src/document_test.js index 841b0f5d9c9..0599a93254a 100644 --- a/src/document_test.js +++ b/src/document_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var Document = require("./document").Document; diff --git a/src/edit_session_test.js b/src/edit_session_test.js index ca65b12bde2..ae6db72d769 100644 --- a/src/edit_session_test.js +++ b/src/edit_session_test.js @@ -1106,24 +1106,50 @@ module.exports = { }, "test: mode loading" : function(next) { - if (!require.undef) { - console.log("Skipping test: This test only runs in the browser"); - next(); - return; - } + delete EditSession.prototype.$modes["ace/mode/javascript"]; + delete EditSession.prototype.$modes["ace/mode/css"]; + delete EditSession.prototype.$modes["ace/mode/sh"]; + require("./config").setLoader(function(name, onLoad) { + if (name == "ace/mode/javascript") { + return onLoad(null, require("./mode/javascript")); + } + if (name == "ace/mode/sh") { + return setTimeout(function() { + return onLoad(null, require("./mode/sh")); + }); + } + if (name == "ace/mode/css") { + return setTimeout(function() { + return onLoad(null, require("./mode/css")); + }); + } + }); var session = new EditSession([]); session.setMode("ace/mode/javascript"); - assert.equal(session.$modeid, "ace/mode/javascript"); - session.on("changeMode", function() { - assert.equal(session.$modeid, "ace/mode/javascript"); + assert.equal(session.$modeId, "ace/mode/javascript"); + + var modeChangeCallbacks = 0; + session.once("changeMode", function() { + assert.equal(session.$modeId, "ace/mode/sh"); + modeChangeCallbacks++; }); - session.setMode("ace/mode/sh", function(mode) { - assert.ok(!mode); + session.setMode("ace/mode/sh", function() { + assert.equal(session.$mode.$id, "ace/mode/sh"); + modeChangeCallbacks++; }); + assert.equal(session.$modeId, "ace/mode/sh"); + assert.equal(session.$mode.$id, "ace/mode/javascript"); setTimeout(function() { - session.setMode("ace/mode/javascript", function(mode) { - session.setMode("ace/mode/javascript"); - assert.equal(session.$modeid, "ace/mode/javascript"); + assert.equal(modeChangeCallbacks, 2); + session.setMode("ace/mode/javascript"); + assert.equal(session.$mode.$id, "ace/mode/javascript"); + session.setMode("ace/mode/sh"); + assert.equal(session.$mode.$id, "ace/mode/sh"); + session.setMode("ace/mode/css"); + assert.equal(session.$mode.$id, "ace/mode/sh"); + // TODO this should not error + // session.destroy(); + setTimeout(function() { next(); }); }, 0); diff --git a/src/ext/beautify_test.js b/src/ext/beautify_test.js index 035abc9223b..376d330f481 100644 --- a/src/ext/beautify_test.js +++ b/src/ext/beautify_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var assert = require("assert"); diff --git a/src/ext/emmet_test.js b/src/ext/emmet_test.js index 56df33299f1..03eeb4551f0 100644 --- a/src/ext/emmet_test.js +++ b/src/ext/emmet_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; require("../test/mockdom"); diff --git a/src/ext/error_marker_test.js b/src/ext/error_marker_test.js index c7abfe81caf..6c22d21bc26 100644 --- a/src/ext/error_marker_test.js +++ b/src/ext/error_marker_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var assert = require("./../test/assertions"); diff --git a/src/ext/hardwrap_test.js b/src/ext/hardwrap_test.js index e083dc7c40b..1972d3b3e64 100644 --- a/src/ext/hardwrap_test.js +++ b/src/ext/hardwrap_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var assert = require("./../test/assertions"); diff --git a/src/ext/static_highlight_test.js b/src/ext/static_highlight_test.js index 6275fe88dab..6a683fe0f25 100644 --- a/src/ext/static_highlight_test.js +++ b/src/ext/static_highlight_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var assert = require("assert"); diff --git a/src/ext/whitespace_test.js b/src/ext/whitespace_test.js index 12cda72bb71..a04cbb5024b 100644 --- a/src/ext/whitespace_test.js +++ b/src/ext/whitespace_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; require("../test/mockdom"); diff --git a/src/incremental_search_test.js b/src/incremental_search_test.js index 70d46fd2535..deb295bcb83 100644 --- a/src/incremental_search_test.js +++ b/src/incremental_search_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var emacs = require('./keyboard/emacs'); diff --git a/src/keyboard/keybinding_test.js b/src/keyboard/keybinding_test.js index fb1114bff36..475f64ece71 100644 --- a/src/keyboard/keybinding_test.js +++ b/src/keyboard/keybinding_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("./../edit_session").EditSession, diff --git a/src/keyboard/textinput_test.js b/src/keyboard/textinput_test.js index e84e8e65ab7..0ccd008989b 100644 --- a/src/keyboard/textinput_test.js +++ b/src/keyboard/textinput_test.js @@ -1,9 +1,5 @@ /*global CustomEvent*/ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; require("../test/mockdom"); diff --git a/src/keyboard/vim_ace_test.js b/src/keyboard/vim_ace_test.js index abe45f4173b..dcf9f75de59 100644 --- a/src/keyboard/vim_ace_test.js +++ b/src/keyboard/vim_ace_test.js @@ -1,9 +1,5 @@ /*global CustomEvent*/ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var assert = require("./../test/assertions"); diff --git a/src/lib/app_config.js b/src/lib/app_config.js index 85849947896..3b7e53765b7 100644 --- a/src/lib/app_config.js +++ b/src/lib/app_config.js @@ -156,7 +156,7 @@ class AppConfig { */ nls(key, defaultString, params) { if (!messages[key]) { - warn("No message found for the key '" + key + "' in the provided messages, trying to find a translation for the default string '" + defaultString + "'."); + warn("No message found for the key '" + key + "' in messages with id " + messages.$id + ", trying to find a translation for the default string '" + defaultString + "'."); if (!messages[defaultString]) { warn("No message found for the default string '" + defaultString + "' in the provided messages. Falling back to the default English message."); } diff --git a/src/lib/event_emitter_test.js b/src/lib/event_emitter_test.js index 688838fb43f..5e3be3ca9c7 100644 --- a/src/lib/event_emitter_test.js +++ b/src/lib/event_emitter_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var oop = require("../lib/oop"); diff --git a/src/mode/_test/highlight_rules_test.js b/src/mode/_test/highlight_rules_test.js index 9bbab769557..a2f84d80326 100644 --- a/src/mode/_test/highlight_rules_test.js +++ b/src/mode/_test/highlight_rules_test.js @@ -10,8 +10,6 @@ var editor = new Editor(new MockRenderer()); if (!fs.existsSync) fs.existsSync = path.existsSync; -require("amd-loader"); - var cwd = __dirname + "/"; var root = path.normalize(cwd + Array(4).join("../")); diff --git a/src/mode/ada_test.js b/src/mode/ada_test.js index 3c4b835adbc..d7e56f1faa4 100644 --- a/src/mode/ada_test.js +++ b/src/mode/ada_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/coldfusion_test.js b/src/mode/coldfusion_test.js index 5b9ae3fd426..26e71b48e67 100644 --- a/src/mode/coldfusion_test.js +++ b/src/mode/coldfusion_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/css_test.js b/src/mode/css_test.js index edd6f8d3605..63af54c296e 100644 --- a/src/mode/css_test.js +++ b/src/mode/css_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/folding/basic_test.js b/src/mode/folding/basic_test.js index a1fd2475c7f..be152807835 100644 --- a/src/mode/folding/basic_test.js +++ b/src/mode/folding/basic_test.js @@ -1,6 +1,3 @@ -if (typeof process !== "undefined") - require("amd-loader"); - "use strict"; var BasicMode = require("../basic").Mode; diff --git a/src/mode/folding/coffee_test.js b/src/mode/folding/coffee_test.js index f271d33ba89..a7c51bdfc3a 100644 --- a/src/mode/folding/coffee_test.js +++ b/src/mode/folding/coffee_test.js @@ -1,6 +1,3 @@ -if (typeof process !== "undefined") - require("amd-loader"); - "use strict"; var CoffeeMode = require("../coffee").Mode; diff --git a/src/mode/folding/cstyle_test.js b/src/mode/folding/cstyle_test.js index 5b48032c604..9af2dd2d2ba 100644 --- a/src/mode/folding/cstyle_test.js +++ b/src/mode/folding/cstyle_test.js @@ -1,6 +1,3 @@ -if (typeof process !== "undefined") - require("amd-loader"); - "use strict"; var JavaScriptMode = require("../javascript").Mode; diff --git a/src/mode/folding/fold_mode_test.js b/src/mode/folding/fold_mode_test.js index 76d857a2d85..c5e06aa3eab 100644 --- a/src/mode/folding/fold_mode_test.js +++ b/src/mode/folding/fold_mode_test.js @@ -1,6 +1,3 @@ -if (typeof process !== "undefined") - require("amd-loader"); - "use strict"; var MarkdownMode = require("../markdown").Mode; diff --git a/src/mode/folding/html_test.js b/src/mode/folding/html_test.js index 33be7d72e4d..5f484a171ad 100644 --- a/src/mode/folding/html_test.js +++ b/src/mode/folding/html_test.js @@ -1,6 +1,3 @@ -if (typeof process !== "undefined") - require("amd-loader"); - "use strict"; var HtmlMode = require("../html").Mode; diff --git a/src/mode/folding/javascript_test.js b/src/mode/folding/javascript_test.js index 366968f4124..5c36ad3172d 100644 --- a/src/mode/folding/javascript_test.js +++ b/src/mode/folding/javascript_test.js @@ -1,6 +1,3 @@ -if (typeof process !== "undefined") - require("amd-loader"); - "use strict"; var JavaScriptMode = require("../javascript").Mode; diff --git a/src/mode/folding/latex_test.js b/src/mode/folding/latex_test.js index f4ce60ff4f6..0a32b1b12b2 100644 --- a/src/mode/folding/latex_test.js +++ b/src/mode/folding/latex_test.js @@ -1,5 +1,3 @@ -if (typeof process !== "undefined") require("amd-loader"); - "use strict"; var LatexMode = require("../latex").Mode; diff --git a/src/mode/folding/lua_test.js b/src/mode/folding/lua_test.js index 380d9874e43..63c50dcbc65 100644 --- a/src/mode/folding/lua_test.js +++ b/src/mode/folding/lua_test.js @@ -1,5 +1,3 @@ -if (typeof process !== "undefined") require("amd-loader"); - "use strict"; var LuaMode = require("../lua").Mode; diff --git a/src/mode/folding/php_test.js b/src/mode/folding/php_test.js index 026c25edd79..ac003b76cc7 100644 --- a/src/mode/folding/php_test.js +++ b/src/mode/folding/php_test.js @@ -1,5 +1,3 @@ -if (typeof process !== "undefined") require("amd-loader"); - "use strict"; var PHPMode = require("../php").Mode; diff --git a/src/mode/folding/pythonic_test.js b/src/mode/folding/pythonic_test.js index a69aed161aa..4a65476110b 100644 --- a/src/mode/folding/pythonic_test.js +++ b/src/mode/folding/pythonic_test.js @@ -1,6 +1,3 @@ -if (typeof process !== "undefined") - require("amd-loader"); - "use strict"; var PythonMode = require("../python").Mode; diff --git a/src/mode/folding/ruby_test.js b/src/mode/folding/ruby_test.js index d888cdae727..7b74125af84 100644 --- a/src/mode/folding/ruby_test.js +++ b/src/mode/folding/ruby_test.js @@ -1,6 +1,3 @@ -if (typeof process !== "undefined") - require("amd-loader"); - "use strict"; var RubyMode = require("../ruby").Mode; diff --git a/src/mode/folding/vbscript_test.js b/src/mode/folding/vbscript_test.js index 4070f427faa..14945579c4a 100644 --- a/src/mode/folding/vbscript_test.js +++ b/src/mode/folding/vbscript_test.js @@ -1,6 +1,3 @@ -if (typeof process !== "undefined") - require("amd-loader"); - "use strict"; var VBScriptMode = require("../vbscript").Mode; diff --git a/src/mode/folding/xml_test.js b/src/mode/folding/xml_test.js index ea9d799ab57..5171312d4ba 100644 --- a/src/mode/folding/xml_test.js +++ b/src/mode/folding/xml_test.js @@ -1,6 +1,3 @@ -if (typeof process !== "undefined") - require("amd-loader"); - "use strict"; var XmlMode = require("../xml").Mode; diff --git a/src/mode/folding/yaml_test.js b/src/mode/folding/yaml_test.js index a04c0f69145..febdefd2b5f 100644 --- a/src/mode/folding/yaml_test.js +++ b/src/mode/folding/yaml_test.js @@ -1,6 +1,3 @@ -if (typeof process !== "undefined") - require("amd-loader"); - "use strict"; var YamlMode = require("../yaml").Mode; diff --git a/src/mode/html_test.js b/src/mode/html_test.js index 8db137af600..0b6a1acb8f4 100644 --- a/src/mode/html_test.js +++ b/src/mode/html_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/javascript_test.js b/src/mode/javascript_test.js index 57e90b3c89c..fe26cde8d39 100644 --- a/src/mode/javascript_test.js +++ b/src/mode/javascript_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/logiql_test.js b/src/mode/logiql_test.js index 3b0c1f35152..5e45d4ea5bb 100644 --- a/src/mode/logiql_test.js +++ b/src/mode/logiql_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/odin_test.js b/src/mode/odin_test.js index fb49592042f..f40b6c3e41c 100644 --- a/src/mode/odin_test.js +++ b/src/mode/odin_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/php_test.js b/src/mode/php_test.js index fec408e44e3..c44c2bc63f8 100644 --- a/src/mode/php_test.js +++ b/src/mode/php_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/plain_text_test.js b/src/mode/plain_text_test.js index 30e17a1fffe..bdf06155432 100644 --- a/src/mode/plain_text_test.js +++ b/src/mode/plain_text_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/python_test.js b/src/mode/python_test.js index 5e7dad57eaf..ab97905d0ca 100644 --- a/src/mode/python_test.js +++ b/src/mode/python_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/ruby_test.js b/src/mode/ruby_test.js index 1bcc46284d0..fa5b4092cf9 100644 --- a/src/mode/ruby_test.js +++ b/src/mode/ruby_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/text_test.js b/src/mode/text_test.js index 54a2d098721..e29742de6f4 100644 --- a/src/mode/text_test.js +++ b/src/mode/text_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/vbscript_test.js b/src/mode/vbscript_test.js index bae545073aa..b7ea9c21caa 100644 --- a/src/mode/vbscript_test.js +++ b/src/mode/vbscript_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/mode/xml_test.js b/src/mode/xml_test.js index 7c4860c6a14..fb5fe3dc70a 100644 --- a/src/mode/xml_test.js +++ b/src/mode/xml_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/occur_test.js b/src/occur_test.js index 882e1a758b7..66b576341ca 100644 --- a/src/occur_test.js +++ b/src/occur_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("./edit_session").EditSession; diff --git a/src/range_list_test.js b/src/range_list_test.js index 292fe2c21bc..bd370573ecd 100644 --- a/src/range_list_test.js +++ b/src/range_list_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var Range = require("./range").Range; diff --git a/src/range_test.js b/src/range_test.js index 2cd3271a3de..625a9d9426e 100644 --- a/src/range_test.js +++ b/src/range_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var Range = require("./range").Range; diff --git a/src/search_test.js b/src/search_test.js index 0ac18959e7d..637c5281004 100644 --- a/src/search_test.js +++ b/src/search_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("./edit_session").EditSession; @@ -142,7 +138,7 @@ module.exports = { "test: fallback to nonUnicode mode on edge cases": function() { var session = new EditSession([ /* eslint-disable no-octal-escape*/ - "string with \251 symbol", // test octal escape sequence + "string with \xa9 symbol", // test octal escape sequence "bracket ab{2}" // test lone quantifier brackets ]); diff --git a/src/selection_test.js b/src/selection_test.js index c8e7850ba47..dd4e4f05ead 100644 --- a/src/selection_test.js +++ b/src/selection_test.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var LineWidgets = require("./line_widgets").LineWidgets; diff --git a/src/test/benchmark.js b/src/test/benchmark.js index 102055a9861..c5054c12fd5 100644 --- a/src/test/benchmark.js +++ b/src/test/benchmark.js @@ -1,7 +1,3 @@ -if (typeof process !== "undefined") { - require("amd-loader"); -} - "use strict"; var EditSession = require("../edit_session").EditSession; diff --git a/src/test/tests.html b/src/test/tests.html index 3c6e5b3fca6..c67f2bc81f7 100644 --- a/src/test/tests.html +++ b/src/test/tests.html @@ -27,7 +27,7 @@ + + + + + + +
    + + + + + + + + + + + + + + +
    + +
    + + + + + + diff --git a/demo/kitchen-sink/util.js b/demo/kitchen-sink/util.js index bc2b0af15af..544050a362f 100644 --- a/demo/kitchen-sink/util.js +++ b/demo/kitchen-sink/util.js @@ -49,7 +49,9 @@ exports.createSplitEditor = function(el) { var split = {$container: el}; split.editor0 = split[0] = new Editor(new Renderer(e0)); + split.editor0.session.setUndoManager(new UndoManager()); split.editor1 = split[1] = new Editor(new Renderer(e1)); + split.editor1.session.setUndoManager(new UndoManager()); split.splitter = s; s.ratio = 0.5; diff --git a/src/editor.js b/src/editor.js index 099fca450b8..f9394b66d20 100644 --- a/src/editor.js +++ b/src/editor.js @@ -48,6 +48,8 @@ class Editor { * @param {Partial} [options] The default options **/ constructor(renderer, session, options) { + /**@type {string}*/ + this.id = "editor" + (++Editor.$uid); /**@type{EditSession}*/this.session; this.$toDestroy = []; @@ -56,8 +58,6 @@ class Editor { this.container = container; /**@type {VirtualRenderer}*/ this.renderer = renderer; - /**@type {string}*/ - this.id = "editor" + (++Editor.$uid); this.commands = new CommandManager(useragent.isMac ? "mac" : "win", defaultCommands); if (typeof document == "object") { this.textInput = new TextInput(renderer.getTextAreaContainer(), this); @@ -445,10 +445,11 @@ class Editor { /** * {:VirtualRenderer.setStyle} * @param {String} style A class name + * @param {boolean} [incluude] pass false to remove the class name * @related VirtualRenderer.setStyle **/ - setStyle(style) { - this.renderer.setStyle(style); + setStyle(style, incluude) { + this.renderer.setStyle(style, incluude); } /** diff --git a/src/ext/diff/base_diff_view.js b/src/ext/diff/base_diff_view.js new file mode 100644 index 00000000000..ba469540b1a --- /dev/null +++ b/src/ext/diff/base_diff_view.js @@ -0,0 +1,854 @@ +"use strict"; + +var oop = require("../../lib/oop"); +var Range = require("../../range").Range; +var dom = require("../../lib/dom"); +var config = require("../../config"); + +// @ts-ignore +var css = require("./styles-css.js").cssText; + +var Editor = require("../../editor").Editor; +var Renderer = require("../../virtual_renderer").VirtualRenderer; +var UndoManager = require("../../undomanager").UndoManager; +require("../../theme/textmate"); +// enable multiselect +require("../../multi_select"); + +var EditSession = require("../../edit_session").EditSession; + +var MinimalGutterDiffDecorator = require("./gutter_decorator").MinimalGutterDiffDecorator; + +class BaseDiffView { + /** + * Constructs a new base DiffView instance. + * @param {boolean} [inlineDiffEditor] - Whether to use an inline diff editor. + * @param {HTMLElement} [container] - optional container element for the DiffView. + */ + constructor(inlineDiffEditor, container) { + this.onChangeTheme = this.onChangeTheme.bind(this); + this.onInput = this.onInput.bind(this); + this.onChangeFold = this.onChangeFold.bind(this); + this.realign = this.realign.bind(this); + this.onSelect = this.onSelect.bind(this); + this.realignPending = false; + + /**@type{{sessionA: EditSession, sessionB: EditSession, chunks: DiffChunk[]}}*/this.diffSession; + /**@type DiffChunk[]*/this.chunks; + this.inlineDiffEditor = inlineDiffEditor || false; + this.currentDiffIndex = 0; + this.diffProvider = { + compute: function(val1, val2, options) { + return []; + } + }; + + if (container) { + this.container = container; + } + + dom.importCssString(css, "diffview.css"); + this.options = { + ignoreTrimWhitespace: true, + maxComputationTimeMs: 0, // time in milliseconds, 0 => no computation limit. + syncSelections: false //experimental option + }; + oop.mixin(this.options, { + maxDiffs: 5000 + }); + + this.markerB = new DiffHighlight(this, 1); + this.markerA = new DiffHighlight(this, -1); + } + + /** + * @param {Object} options - The configuration options for the DiffView. + * @param {boolean} [options.ignoreTrimWhitespace=true] - Whether to ignore whitespace changes when computing diffs. + * @param {boolean} [options.foldUnchanged=false] - Whether to fold unchanged regions in the diff view. + * @param {number} [options.maxComputationTimeMs=0] - The maximum time in milliseconds to spend computing diffs (0 means no limit). + * @param {boolean} [options.syncSelections=false] - Whether to synchronize selections between the original and edited views. + */ + setOptions(options) { + this.options = { + ignoreTrimWhitespace: options.ignoreTrimWhitespace || true, + foldUnchanged: options.foldUnchanged || false, + maxComputationTimeMs: options.maxComputationTimeMs || 0, // time in milliseconds, 0 => no computation limit. + syncSelections: options.syncSelections || false //experimental option + }; + oop.mixin(this.options, { + maxDiffs: 5000 + }); + config.resetOptions(this); + } + + /** + * @param {Object} [diffModel] - The model for the diff view. + * @param {Editor} [diffModel.editorA] - The editor for the original view. + * @param {Editor} [diffModel.editorB] - The editor for the edited view. + * @param {EditSession} [diffModel.sessionA] - The edit session for the original view. + * @param {EditSession} [diffModel.sessionB] - The edit session for the edited view. + * @param {string} [diffModel.valueA] - The original content. + * @param {string} [diffModel.valueB] - The modified content. + * @param {boolean} [diffModel.showSideA] - Whether to show the original view or modified view. + */ + $setupModels(diffModel) { + this.showSideA = diffModel.showSideA == undefined ? true : diffModel.showSideA; + var diffEditorOptions = /**@type {Partial}*/({ + scrollPastEnd: 0.5, + highlightActiveLine: false, + highlightGutterLine: false, + animatedScroll: true, + customScrollbar: true, + vScrollBarAlwaysVisible: true, + fadeFoldWidgets: true, + selectionStyle: "text", + }); + + this.savedOptionsA = diffModel.editorA && diffModel.editorA.getOptions(diffEditorOptions); + this.savedOptionsB = diffModel.editorB && diffModel.editorB.getOptions(diffEditorOptions); + + if (!this.inlineDiffEditor || diffModel.showSideA) { + this.editorA = diffModel.editorA || this.$setupModel(diffModel.sessionA, diffModel.valueA); + this.container && this.container.appendChild(this.editorA.container); + this.editorA.setOptions(diffEditorOptions); + } + if (!this.inlineDiffEditor || !diffModel.showSideA) { + this.editorB = diffModel.editorB || this.$setupModel(diffModel.sessionB, diffModel.valueB); + this.container && this.container.appendChild(this.editorB.container); + this.editorB.setOptions(diffEditorOptions); + } + + if (this.inlineDiffEditor) { + this.activeEditor = diffModel.showSideA ? this.editorA : this.editorB; + this.otherSession = diffModel.showSideA ? this.sessionB : this.sessionA; + var cloneOptions = this.activeEditor.getOptions(); + cloneOptions.readOnly = true; + delete cloneOptions.mode; + this.otherEditor = new Editor(new Renderer(null), undefined, cloneOptions); + if (diffModel.showSideA) { + this.editorB = this.otherEditor; + } else { + this.editorA = this.otherEditor; + } + } + + this.setDiffSession({ + sessionA: diffModel.sessionA || (diffModel.editorA ? diffModel.editorA.session : new EditSession( + diffModel.valueA || "")), + sessionB: diffModel.sessionB || (diffModel.editorB ? diffModel.editorB.session : new EditSession( + diffModel.valueB || "")), + chunks: [] + }); + } + + addGutterDecorators() { + if (!this.gutterDecoratorA) + this.gutterDecoratorA = new MinimalGutterDiffDecorator(this.editorA, -1); + if (!this.gutterDecoratorB) + this.gutterDecoratorB = new MinimalGutterDiffDecorator(this.editorB, 1); + } + + /** + * @param {EditSession} [session] + * @param {string} [value] + */ + $setupModel(session, value) { + var editor = new Editor(new Renderer(), session); + editor.session.setUndoManager(new UndoManager()); + // editor.renderer.setOption("decoratorType", "diff"); + if (value) { + editor.setValue(value, -1); + } + return editor; + } + + foldUnchanged() { + this.sessionA.unfold(); + this.sessionB.unfold(); + + var chunks = this.chunks; + var placeholder = "-".repeat(120); + var prev = { + old: new Range(0, 0, 0, 0), + new: new Range(0, 0, 0, 0) + }; + for (var i = 0; i < chunks.length + 1; i++) { + let current = chunks[i] || { + old: new Range(this.sessionA.getLength(), 0, this.sessionA.getLength(), 0), + new: new Range(this.sessionB.getLength(), 0, this.sessionB.getLength(), 0) + }; + var l = current.new.start.row - prev.new.end.row - 5; + if (l > 2) { + var s = prev.old.end.row + 2; + var fold1 = this.sessionA.addFold(placeholder, new Range(s, 0, s + l, Number.MAX_VALUE)); + s = prev.new.end.row + 2; + var fold2 = this.sessionB.addFold(placeholder, new Range(s, 0, s + l, Number.MAX_VALUE)); + if (fold2 && fold1) { + fold1["other"] = fold2; + fold2["other"] = fold1; + } + } + + prev = current; + } + + } + + /** + * @param {{ sessionA: any; sessionB: EditSession; chunks: DiffChunk[] }} session + */ + setDiffSession(session) { + if (this.diffSession) { + this.$detachSessionsEventHandlers(); + this.clearSelectionMarkers(); + } + this.diffSession = session; + this.sessionA = this.sessionB = null; + if (this.diffSession) { + this.chunks = this.diffSession.chunks; + this.editorA && this.editorA.setSession(session.sessionA); + this.editorB && this.editorB.setSession(session.sessionB); + this.sessionA = this.diffSession.sessionA; + this.sessionB = this.diffSession.sessionB; + this.$attachSessionsEventHandlers(); + this.initSelectionMarkers(); + } + + this.otherSession = this.showSideA ? this.sessionB : this.sessionA; + } + + /** + * @abstract + */ + $attachSessionsEventHandlers() { + } + + /** + * @abstract + */ + $detachSessionsEventHandlers() { + } + + getDiffSession() { + return this.diffSession; + } + + setTheme(theme) { + this.editorA && this.editorA.setTheme(theme); + this.editorB && this.editorB.setTheme(theme); + } + + getTheme() { + return (this.editorA || this.editorB).getTheme(); + } + + onChangeTheme() { + this.editorA && this.editorA.setTheme(this.getTheme()); + this.editorB && this.editorB.setTheme(this.getTheme()); + } + + resize(force) { + this.editorA && this.editorA.resize(force); + this.editorB && this.editorB.resize(force); + } + + onInput() { + var val1 = this.sessionA.doc.getAllLines(); + var val2 = this.sessionB.doc.getAllLines(); + + this.selectionRangeA = null; + this.selectionRangeB = null; + + var chunks = this.$diffLines(val1, val2); + + this.diffSession.chunks = this.chunks = chunks; + this.gutterDecoratorA && this.gutterDecoratorA.setDecorations(chunks); + this.gutterDecoratorB && this.gutterDecoratorB.setDecorations(chunks); + // if we"re dealing with too many chunks, fail silently + if (this.chunks && this.chunks.length > this.options.maxDiffs) { + return; + } + + this.align(); + + this.editorA && this.editorA.renderer.updateBackMarkers(); + this.editorB && this.editorB.renderer.updateBackMarkers(); + + //this.updateScrollBarDecorators(); + + if (this.options.foldUnchanged) { + this.foldUnchanged(); + } + } + + /** + * + * @param {string[]} val1 + * @param {string[]} val2 + * @return {DiffChunk[]} + */ + $diffLines(val1, val2) { + return this.diffProvider.compute(val1, val2, { + ignoreTrimWhitespace: this.options.ignoreTrimWhitespace, + maxComputationTimeMs: this.options.maxComputationTimeMs + }); + } + + /** + * @param {import("./providers/default").DiffProvider} provider + */ + setProvider(provider) { + this.diffProvider = provider; + } + + /** scroll locking + * @abstract + **/ + align() { + } + onSelect(e, selection) { + this.searchHighlight(selection); + this.syncSelect(selection); + } + + syncSelect(selection) { + if (this.$updatingSelection) return; + var isOld = selection.session === this.sessionA; + var selectionRange = selection.getRange(); + + var currSelectionRange = isOld ? this.selectionRangeA : this.selectionRangeB; + if (currSelectionRange && selectionRange.isEqual(currSelectionRange)) + return; + + if (isOld) { + this.selectionRangeA = selectionRange; + } else { + this.selectionRangeB = selectionRange; + } + + this.$updatingSelection = true; + var newRange = this.transformRange(selectionRange, isOld); + + if (this.options.syncSelections) { + (isOld ? this.editorB : this.editorA).session.selection.setSelectionRange(newRange); + } + this.$updatingSelection = false; + + if (isOld) { + this.selectionRangeA = selectionRange; + this.selectionRangeB = newRange; + } else { + this.selectionRangeA = newRange; + this.selectionRangeB = selectionRange; + } + + this.updateSelectionMarker(this.syncSelectionMarkerA, this.sessionA, this.selectionRangeA); + this.updateSelectionMarker(this.syncSelectionMarkerB, this.sessionB, this.selectionRangeB); + } + + updateSelectionMarker(marker, session, range) { + marker.setRange(range); + session._signal("changeFrontMarker"); + } + + /** + * @param ev + * @param {EditSession} session + */ + onChangeFold(ev, session) { + var fold = ev.data; + if (this.$syncingFold || !fold || !ev.action) return; + if (!this.realignPending) { + this.realignPending = true; + this.editorA.renderer.on("beforeRender", this.realign); + this.editorB.renderer.on("beforeRender", this.realign); + } + + const isOrig = session === this.sessionA; + const other = isOrig ? this.sessionB : this.sessionA; + + if (ev.action === "remove") { + if (fold.other) { + fold.other.other = null; + other.removeFold(fold.other); + } + else if (fold.lineWidget) { + other.widgetManager.addLineWidget(fold.lineWidget); + fold.lineWidget = null; + if (other["$editor"]) { + other["$editor"].renderer.updateBackMarkers(); + } + } + } + + if (ev.action === "add") { + const range = this.transformRange(fold.range, isOrig); + if (range.isEmpty()) { + const row = range.start.row + 1; + if (other.lineWidgets[row]) { + fold.lineWidget = other.lineWidgets[row]; + other.widgetManager.removeLineWidget(fold.lineWidget); + if (other["$editor"]) { + other["$editor"].renderer.updateBackMarkers(); + } + } + } + else { + this.$syncingFold = true; + + fold.other = other.addFold(fold.placeholder, range); + if (fold.other) { + fold.other.other = fold; + } + this.$syncingFold = false; + } + } + } + + realign() { + this.realignPending = true; + this.editorA.renderer.off("beforeRender", this.realign); + this.editorB.renderer.off("beforeRender", this.realign); + this.align(); + this.realignPending = false; + } + + detach() { + if (!this.editorA || !this.editorB) return; + this.editorA.setOptions(this.savedOptionsA); + this.editorB.setOptions(this.savedOptionsB); + this.editorA.renderer.off("beforeRender", this.realign); + this.editorB.renderer.off("beforeRender", this.realign); + this.$detachEventHandlers(); + this.$removeLineWidgets(this.sessionA); + this.$removeLineWidgets(this.sessionB); + this.gutterDecoratorA && this.gutterDecoratorA.dispose(); + this.gutterDecoratorB && this.gutterDecoratorB.dispose(); + this.sessionA.selection.clearSelection(); + this.sessionB.selection.clearSelection(); + this.editorA = this.editorB = null; + + } + + $removeLineWidgets(session) { + // TODO remove only our widgets + // session.widgetManager.removeLineWidget + session.lineWidgets = []; + session.widgetManager.lineWidgets = []; + session._signal("changeFold", {data: {start: {row: 0}}}); + } + + /** + * @abstract + */ + $detachEventHandlers() { + + } + + destroy() { + this.detach(); + this.editorA && this.editorA.destroy(); + this.editorB && this.editorB.destroy(); + } + + gotoNext(dir) { + var ace = this.activeEditor || this.editorA; + if (this.inlineDiffEditor) { + ace = this.editorA; + } + var sideA = ace == this.editorA; + + var row = ace.selection.lead.row; + var i = this.findChunkIndex(this.chunks, row, sideA); + var chunk = this.chunks[i + dir] || this.chunks[i]; + + var scrollTop = ace.session.getScrollTop(); + if (chunk) { + var range = chunk[sideA ? "old" : "new"]; + var line = Math.max(range.start.row, range.end.row - 1); + ace.selection.setRange(new Range(line, 0, line, 0)); + } + ace.renderer.scrollSelectionIntoView(ace.selection.lead, ace.selection.anchor, 0.5); + ace.renderer.animateScrolling(scrollTop); + } + + + firstDiffSelected() { + return this.currentDiffIndex <= 1; + } + + lastDiffSelected() { + return this.currentDiffIndex > this.chunks.length - 1; + } + + /** + * @param {Range} range + * @param {boolean} isOriginal + */ + transformRange(range, isOriginal) { + return Range.fromPoints(this.transformPosition(range.start, isOriginal), this.transformPosition(range.end, isOriginal)); + } + + /** + * @param {import("ace-code").Ace.Point} pos + * @param {boolean} isOriginal + * @return {import("ace-code").Ace.Point} + */ + transformPosition(pos, isOriginal) { + var chunkIndex = this.findChunkIndex(this.chunks, pos.row, isOriginal); + + var chunk = this.chunks[chunkIndex]; + + var clonePos = this.sessionB.doc.clonePos; + var result = clonePos(pos); + + var [from, to] = isOriginal ? ["old", "new"] : ["new", "old"]; + var deltaChar = 0; + var ignoreIndent = false; + + if (chunk) { + if (chunk[from].end.row <= pos.row) { + result.row -= chunk[from].end.row - chunk[to].end.row; + } + else if (chunk.charChanges) { + for (let i = 0; i < chunk.charChanges.length; i++) { + let change = chunk.charChanges[i]; + + let fromRange = change[from]; + let toRange = change[to]; + + if (fromRange.end.row < pos.row) continue; + + if (fromRange.start.row > pos.row) break; + + if (fromRange.isMultiLine() && fromRange.contains(pos.row, pos.column)) { + result.row = toRange.start.row + pos.row - fromRange.start.row; + var maxRow = toRange.end.row; + if (toRange.end.column === 0) maxRow--; + + if (result.row > maxRow) { + result.row = maxRow; + result.column = (isOriginal ? this.sessionB : this.sessionA).getLine(maxRow).length; + ignoreIndent = true; + } + result.row = Math.min(result.row, maxRow); + } + else { + result.row = toRange.start.row; + if (fromRange.start.column > pos.column) break; + ignoreIndent = true; + + if (!fromRange.isEmpty() && fromRange.contains(pos.row, pos.column)) { + result.column = toRange.start.column; + deltaChar = pos.column - fromRange.start.column; + deltaChar = Math.min(deltaChar, toRange.end.column - toRange.start.column); + } + else { + result = clonePos(toRange.end); + deltaChar = pos.column - fromRange.end.column; + } + } + } + } + else if (chunk[from].start.row <= pos.row) { + result.row += chunk[to].start.row - chunk[from].start.row; + if (result.row >= chunk[to].end.row) { + result.row = chunk[to].end.row - 1; + result.column = (isOriginal ? this.sessionB : this.sessionA).getLine(result.row).length; + } + } + } + + + if (!ignoreIndent) { //TODO: + var [fromEditSession, toEditSession] = isOriginal ? [this.sessionA, this.sessionB] : [ + this.sessionB, this.sessionA + ]; + deltaChar -= this.$getDeltaIndent(fromEditSession, toEditSession, pos.row, result.row); + } + + result.column += deltaChar; + return result; + } + + /** + * @param {EditSession} fromEditSession + * @param {EditSession} toEditSession + * @param {number} fromLine + * @param {number} toLine + */ + $getDeltaIndent(fromEditSession, toEditSession, fromLine, toLine) { + let origIndent = this.$getIndent(fromEditSession, fromLine); + let editIndent = this.$getIndent(toEditSession, toLine); + return origIndent - editIndent; + } + + /** + * @param {EditSession} editSession + * @param {number} line + */ + $getIndent(editSession, line) { + return editSession.getLine(line).match(/^\s*/)[0].length; + } + + printDiffs() { + this.chunks.forEach((diff) => { + console.log(diff.toString()); + }); + } + + /** + * + * @param {DiffChunk[]} chunks + * @param {number} row + * @param {boolean} isOriginal + * @return {number} + */ + findChunkIndex(chunks, row, isOriginal) { + for (var i = 0; i < chunks.length; i++) { + var ch = chunks[i]; + var chunk = isOriginal ? ch.old : ch.new; + if (chunk.end.row < row) continue; + if (chunk.start.row > row) break; + } + + this.currentDiffIndex = i; + + return i - 1; + } + + searchHighlight(selection) { + if (this.options.syncSelections || this.inlineDiffEditor) { + return; + } + let currSession = selection.session; + let otherSession = currSession === this.sessionA + ? this.sessionB : this.sessionA; + otherSession.highlight(currSession.$searchHighlight.regExp); + otherSession._signal("changeBackMarker"); + } + + initSelectionMarkers() { + this.syncSelectionMarkerA = new SyncSelectionMarker(); + this.syncSelectionMarkerB = new SyncSelectionMarker(); + this.sessionA.addDynamicMarker(this.syncSelectionMarkerA, true); + this.sessionB.addDynamicMarker(this.syncSelectionMarkerB, true); + } + clearSelectionMarkers() { + this.sessionA.removeMarker(this.syncSelectionMarkerA.id); + this.sessionB.removeMarker(this.syncSelectionMarkerB.id); + } + +} + +/*** options ***/ + +config.defineOptions(BaseDiffView.prototype, "DiffView", { + showOtherLineNumbers: { + set: function(value) { + if (this.gutterLayer) { + this.gutterLayer.$renderer = value ? null : emptyGutterRenderer; + } + }, + initialValue: false + }, + folding: { + set: function(value) { + this.editorA.setOption("fadeFoldWidgets", value); + this.editorB.setOption("fadeFoldWidgets", value); + this.editorA.setOption("showFoldWidgets", value); + this.editorB.setOption("showFoldWidgets", value); + } + }, + syncSelections: { + set: function(value) { + this.options.syncSelections = value; + }, + }, + ignoreTrimWhitespace: { + set: function(value) { + this.options.ignoreTrimWhitespace = value; + }, + }, +}); + +var emptyGutterRenderer = { + getText: function name(params) { + return ""; + }, + getWidth() { + return 0; + } +}; + +exports.BaseDiffView = BaseDiffView; + + +class DiffChunk { + /** + * @param {Range} originalRange + * @param {Range} modifiedRange + * @param {{originalStartLineNumber: number, originalStartColumn: number, + * originalEndLineNumber: number, originalEndColumn: number, modifiedStartLineNumber: number, + * modifiedStartColumn: number, modifiedEndLineNumber: number, modifiedEndColumn: number}[]} [charChanges] + */ + constructor(originalRange, modifiedRange, charChanges) { + this.old = originalRange; + this.new = modifiedRange; + this.charChanges = charChanges && charChanges.map(m => new DiffChunk( + new Range(m.originalStartLineNumber, m.originalStartColumn, + m.originalEndLineNumber, m.originalEndColumn + ), new Range(m.modifiedStartLineNumber, m.modifiedStartColumn, + m.modifiedEndLineNumber, m.modifiedEndColumn + ))); + } +} + +class DiffHighlight { + /** + * @param {import("./base_diff_view").BaseDiffView} diffView + * @param type + */ + constructor(diffView, type) { + /**@type{number}*/this.id; + this.diffView = diffView; + this.type = type; + } + + update(html, markerLayer, session, config) { + let dir, operation, opOperation; + var diffView = this.diffView; + if (this.type === -1) {// original editor + dir = "old"; + operation = "delete"; + opOperation = "insert"; + } + else { //modified editor + dir = "new"; + operation = "insert"; + opOperation = "delete"; + } + + var ignoreTrimWhitespace = diffView.options.ignoreTrimWhitespace; + var lineChanges = diffView.chunks; + + if (session.lineWidgets && !diffView.inlineDiffEditor) { + for (var row = config.firstRow; row <= config.lastRow; row++) { + var lineWidget = session.lineWidgets[row]; + if (!lineWidget || lineWidget.hidden) + continue; + + let start = session.documentToScreenRow(row, 0); + + if (lineWidget.rowsAbove > 0) { + start -= lineWidget.rowsAbove; + } else { + start++; + } + let end = start + lineWidget.rowCount - 1; + var range = new Range(start, 0, end, Number.MAX_VALUE); + markerLayer.drawFullLineMarker(html, range, "ace_diff aligned_diff", config); + } + } + + lineChanges.forEach((lineChange) => { + let startRow = lineChange[dir].start.row; + let endRow = lineChange[dir].end.row; + if (endRow < config.firstRow || startRow > config.lastRow) + return; + let range = new Range(startRow, 0, endRow - 1, 1 << 30); + if (startRow !== endRow) { + range = range.toScreenRange(session); + + markerLayer.drawFullLineMarker(html, range, "ace_diff " + operation, config); + } + + if (lineChange.charChanges) { + for (var i = 0; i < lineChange.charChanges.length; i++) { + var changeRange = lineChange.charChanges[i][dir]; + if (changeRange.end.column == 0 && changeRange.end.row > changeRange.start.row && changeRange.end.row == lineChange[dir].end.row ) { + changeRange.end.row --; + changeRange.end.column = Number.MAX_VALUE; + } + + if (ignoreTrimWhitespace) { + for (let lineNumber = changeRange.start.row; + lineNumber <= changeRange.end.row; lineNumber++) { + let startColumn; + let endColumn; + let sessionLineStart = session.getLine(lineNumber).match(/^\s*/)[0].length; + let sessionLineEnd = session.getLine(lineNumber).length; + + if (lineNumber === changeRange.start.row) { + startColumn = changeRange.start.column; + } + else { + startColumn = sessionLineStart; + } + if (lineNumber === changeRange.end.row) { + endColumn = changeRange.end.column; + } + else { + endColumn = sessionLineEnd; + } + let range = new Range(lineNumber, startColumn, lineNumber, endColumn); + var screenRange = range.toScreenRange(session); + + if (sessionLineStart === startColumn && sessionLineEnd === endColumn) { + continue; + } + + let cssClass = "inline " + operation; + if (range.isEmpty() && startColumn !== 0) { + cssClass = "inline " + opOperation + " empty"; + } + + markerLayer.drawSingleLineMarker(html, screenRange, "ace_diff " + cssClass, config); + } + } + else { + let range = new Range(changeRange.start.row, changeRange.start.column, + changeRange.end.row, changeRange.end.column + ); + var screenRange = range.toScreenRange(session); + let cssClass = "inline " + operation; + if (range.isEmpty() && changeRange.start.column !== 0) { + cssClass = "inline empty " + opOperation; + } + + if (screenRange.isMultiLine()) { + markerLayer.drawTextMarker(html, screenRange, "ace_diff " + cssClass, config); + } + else { + markerLayer.drawSingleLineMarker(html, screenRange, "ace_diff " + cssClass, config); + } + } + } + } + }); + } +} + +class SyncSelectionMarker { + constructor() { + /**@type{number}*/this.id; + this.type = "fullLine"; + this.clazz = "ace_diff selection"; + } + + update(html, markerLayer, session, config) { + } + + /** + * @param {Range} range + */ + setRange(range) {//TODO + var newRange = range.clone(); + newRange.end.column++; + + this.range = newRange; + } +} + +exports.DiffChunk = DiffChunk; +exports.DiffHighlight = DiffHighlight; \ No newline at end of file diff --git a/src/ext/diff/diff_test.js b/src/ext/diff/diff_test.js new file mode 100644 index 00000000000..6329e0273ff --- /dev/null +++ b/src/ext/diff/diff_test.js @@ -0,0 +1,147 @@ +"use strict"; + +var assert = require("../../test/assertions"); +require("../../test/mockdom"); + +var {InlineDiffView} = require("./inline_diff_view"); +var {DiffView} = require("./diff_view"); + +var ace = require("../../ace"); +var Range = require("../../range").Range; +var editorA, editorB, diffView; + +function createEditor() { + var editor = ace.edit(null); + document.body.appendChild(editor.container); + editor.container.style.height = "200px"; + editor.container.style.width = "300px"; + editor.container.style.position = "absolute"; + editor.container.style.outline = "solid"; + return editor; +} + +module.exports = { + setUpSuite: function() { + ace.config.setLoader(function(moduleName, cb) { + if (moduleName == "ace/ext/error_marker") + return cb(null, require("../error_marker")); + }); + editorA = createEditor(); + editorB = createEditor(); + editorB.container.style.left = "301px"; + editorA.focus(); + }, + tearDownSuite: function() { + [editorA, editorB].forEach(function(editor) { + if (editor) { + editor.destroy(); + editor.container.remove(); + editor = null; + } + }); + }, + tearDown: function() { + if (diffView) { + diffView.detach(); + diffView = null; + } + }, + "test: clean detach": function() { + var values = [ + ["a"], + ["b"], + ["c"], + [null, "inserted1"], + [null, "inserted2"], + ["e"], + ["f"], + ["g", "edited g"], + ["h"], + ["i"], + ]; + + editorA.session.setValue( + values.map(function(v) { + return v[0]; + }).filter(function(x) { + return x != null; + }).join("\n") + ); + + editorB.session.setValue( + values.map(function(v) { + return v.length == 2 ? v[1] : v[0]; + }).filter(function(x) { + return x != null; + }).join("\n") + ); + assert.ok(!!editorA.session.widgetManager); + assert.ok(!!editorB.session.widgetManager); + + var uid = 0; + var saved = {}; + function saveEventRegistry(object) { + var id = object.id; + if (!id) { + id = object.id = "unknown" + (uid++); + } + var eventRegistry = {}; + for (var key in object._eventRegistry) { + var handlers = object._eventRegistry[key]; + eventRegistry[key] = handlers.slice(0); + } + saved[id] = [eventRegistry, object]; + } + function checkEventRegistry() { + for (var id in saved) { + var object = saved[id][1]; + var eventRegistry = saved[id][0]; + for (var eventName in object._eventRegistry) { + var handlers = object._eventRegistry[eventName]; + var savedHandlers = eventRegistry[eventName] || []; + assert.notEqual(handlers, savedHandlers); + assert.equal(handlers.length, savedHandlers.length, id + ":" + eventName); + for (var j = 0; j < handlers.length; j++) { + assert.equal(handlers[j], eventRegistry[eventName][j], id + ":" + eventName); + } + } + } + } + saveEventRegistry(editorA); + saveEventRegistry(editorB); + saveEventRegistry(editorA.session); + saveEventRegistry(editorB.session); + saveEventRegistry(editorA.renderer); + saveEventRegistry(editorB.renderer); + + var diffView = new InlineDiffView({ + editorA, editorB, + showSideA: true + }); + editorA.session.addFold("---", new Range(0, 0, 2, 0)); + diffView.resize(true); + + assert.equal(editorA.session.$foldData.length, 1); + assert.equal(editorB.session.$foldData.length, 1); + + diffView.detach(); + var sessionB = editorB.session; + sessionB.widgetManager.attach(editorB); + checkEventRegistry(); + + diffView = new DiffView({editorA, editorB}); + editorB.session.addFold("---", new Range(5, 0, 7, 0)); + editorB.renderer.$loop._flush(); + editorA.renderer.$loop._flush(); + assert.equal(editorA.session.$foldData.length, 2); + assert.equal(editorB.session.$foldData.length, 2); + + diffView.detach(); + checkEventRegistry(); + } +}; + + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/src/ext/diff/diff_view.js b/src/ext/diff/diff_view.js new file mode 100644 index 00000000000..a534ee02a51 --- /dev/null +++ b/src/ext/diff/diff_view.js @@ -0,0 +1,240 @@ +"use strict"; + +var LineWidgets = require("../../line_widgets").LineWidgets; + +var BaseDiffView = require("./base_diff_view").BaseDiffView; +var config = require("../../config"); + +class DiffView extends BaseDiffView { + /** + * Constructs a new side by side DiffView instance. + * + * @param {Object} [diffModel] - The model for the diff view. + * @param {import("../../editor").Editor} [diffModel.editorA] - The editor for the original view. + * @param {import("../../editor").Editor} [diffModel.editorB] - The editor for the edited view. + * @param {import("../../edit_session").EditSession} [diffModel.sessionA] - The edit session for the original view. + * @param {import("../../edit_session").EditSession} [diffModel.sessionB] - The edit session for the edited view. + * @param {string} [diffModel.valueA] - The original content. + * @param {string} [diffModel.valueB] - The modified content. + */ + constructor(diffModel) { + diffModel = diffModel || {}; + super(); + this.init(diffModel); + } + + init(diffModel) { + this.onChangeTheme = this.onChangeTheme.bind(this); + this.onMouseWheel = this.onMouseWheel.bind(this); + this.onScroll = this.onScroll.bind(this); + + this.$setupModels(diffModel); + + this.addGutterDecorators(); + + this.onChangeTheme(); + + config.resetOptions(this); + config["_signal"]("diffView", this); + + this.$attachEventHandlers(); + } + + /*** scroll locking ***/ + align() { + var diffView = this; + + function add(session, w) { + let lineWidget = session.lineWidgets[w.row]; + if (lineWidget) { + w.rowsAbove += lineWidget.rowsAbove > w.rowsAbove ? lineWidget.rowsAbove : w.rowsAbove; + w.rowCount += lineWidget.rowCount; + } + session.lineWidgets[w.row] = w; + session.widgetManager.lineWidgets[w.row] = w; + session.$resetRowCache(w.row); + var fold = session.getFoldAt(w.row, 0); + if (fold) { + session.widgetManager.updateOnFold({ + data: fold, + action: "add", + }, session); + } + } + + function init(editor) { + var session = editor.session; + if (!session.widgetManager) { + session.widgetManager = new LineWidgets(session); + session.widgetManager.attach(editor); + } + editor.session.lineWidgets = []; + editor.session.widgetManager.lineWidgets = []; + editor.session.$resetRowCache(0); + } + + init(diffView.editorA); + init(diffView.editorB); + + diffView.chunks.forEach(function (ch) { + var diff1 = diffView.sessionA.documentToScreenPosition(ch.old.start).row; + var diff2 = diffView.sessionB.documentToScreenPosition(ch.new.start).row; + + if (diff1 < diff2) { + add(diffView.sessionA, { + rowCount: diff2 - diff1, + rowsAbove: ch.old.start.row === 0 ? diff2 - diff1 : 0, + row: ch.old.start.row === 0 ? 0 : ch.old.start.row - 1 + }); + } + else if (diff1 > diff2) { + add(diffView.sessionB, { + rowCount: diff1 - diff2, + rowsAbove: ch.new.start.row === 0 ? diff1 - diff2 : 0, + row: ch.new.start.row === 0 ? 0 : ch.new.start.row - 1 + }); + } + + var diff1 = diffView.sessionA.documentToScreenPosition(ch.old.end).row; + var diff2 = diffView.sessionB.documentToScreenPosition(ch.new.end).row; + if (diff1 < diff2) { + add(diffView.sessionA, { + rowCount: diff2 - diff1, + rowsAbove: ch.old.end.row === 0 ? diff2 - diff1 : 0, + row: ch.old.end.row === 0 ? 0 : ch.old.end.row - 1 + }); + } + else if (diff1 > diff2) { + add(diffView.sessionB, { + rowCount: diff1 - diff2, + rowsAbove: ch.new.end.row === 0 ? diff1 - diff2 : 0, + row: ch.new.end.row === 0 ? 0 : ch.new.end.row - 1 + }); + } + }); + diffView.sessionA["_emit"]("changeFold", {data: {start: {row: 0}}}); + diffView.sessionB["_emit"]("changeFold", {data: {start: {row: 0}}}); + } + + onScroll(e, session) { + this.syncScroll(this.sessionA === session ? this.editorA.renderer : this.editorB.renderer); + } + + /** + * @param {import("../../virtual_renderer").VirtualRenderer} renderer + */ + syncScroll(renderer) { + if (this.$syncScroll == false) return; + + var r1 = this.editorA.renderer; + var r2 = this.editorB.renderer; + var isOrig = renderer == r1; + if (r1["$scrollAnimation"] && r2["$scrollAnimation"]) return; + + var now = Date.now(); + if (this.scrollSetBy != renderer && now - this.scrollSetAt < 500) return; + + var r = isOrig ? r1 : r2; + if (this.scrollSetBy != renderer) { + if (isOrig && this.scrollA == r.session.getScrollTop()) return; else if (!isOrig && this.scrollB + == r.session.getScrollTop()) return; + } + var rOther = isOrig ? r2 : r1; + + var targetPos = r.session.getScrollTop(); + + this.$syncScroll = false; + + if (isOrig) { + this.scrollA = r.session.getScrollTop(); + this.scrollB = targetPos; + } + else { + this.scrollA = targetPos; + this.scrollB = r.session.getScrollTop(); + } + this.scrollSetBy = renderer; + rOther.session.setScrollTop(targetPos); + this.$syncScroll = true; + this.scrollSetAt = now; + } + + onMouseWheel(ev) { + if (ev.getAccelKey()) return; + if (ev.getShiftKey() && ev.wheelY && !ev.wheelX) { + ev.wheelX = ev.wheelY; + ev.wheelY = 0; + } + + var editor = ev.editor; + var isScrolable = editor.renderer.isScrollableBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed); + if (!isScrolable) { + var other = editor == this.editorA ? this.editorB : this.editorA; + if (other.renderer.isScrollableBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed)) other.renderer.scrollBy( + ev.wheelX * ev.speed, ev.wheelY * ev.speed); + return ev.stop(); + } + } + + $attachSessionsEventHandlers() { + this.$attachSessionEventHandlers(this.editorA, this.markerA); + this.$attachSessionEventHandlers(this.editorB, this.markerB); + } + + /** + * @param {import("../../editor").Editor} editor + * @param {import("./base_diff_view").DiffHighlight} marker + */ + $attachSessionEventHandlers(editor, marker) { + editor.session.on("changeScrollTop", this.onScroll); + editor.session.on("changeFold", this.onChangeFold); + // @ts-expect-error + editor.session.addDynamicMarker(marker); + editor.selection.on("changeCursor", this.onSelect); + editor.selection.on("changeSelection", this.onSelect); + } + + $detachSessionsEventHandlers() { + this.$detachSessionHandlers(this.editorA, this.markerA); + this.$detachSessionHandlers(this.editorB, this.markerB); + } + + /** + * @param {import("../../editor").Editor} editor + * @param {import("./base_diff_view").DiffHighlight} marker + */ + $detachSessionHandlers(editor, marker) { + editor.session.off("changeScrollTop", this.onScroll); + editor.session.off("changeFold", this.onChangeFold); + editor.session.removeMarker(marker.id); + editor.selection.off("changeCursor", this.onSelect); + editor.selection.off("changeSelection", this.onSelect); + } + + $attachEventHandlers() { + this.editorA.renderer.on("themeLoaded", this.onChangeTheme); + + this.editorA.on("mousewheel", this.onMouseWheel); + this.editorB.on("mousewheel", this.onMouseWheel); + + this.editorA.on("input", this.onInput); + this.editorB.on("input", this.onInput); + + } + + $detachEventHandlers() { + this.$detachSessionsEventHandlers(); + this.clearSelectionMarkers(); + this.editorA.renderer.off("themeLoaded", this.onChangeTheme); + this.$detachEditorEventHandlers(this.editorA); + this.$detachEditorEventHandlers(this.editorB); + } + + $detachEditorEventHandlers(editor) { + editor.off("mousewheel", this.onMouseWheel); + editor.off("input", this.onInput); + } +} + + +exports.DiffView = DiffView; diff --git a/src/ext/diff/gutter_decorator.js b/src/ext/diff/gutter_decorator.js new file mode 100644 index 00000000000..36e65d22e09 --- /dev/null +++ b/src/ext/diff/gutter_decorator.js @@ -0,0 +1,70 @@ +var dom = require("../../lib/dom"); + +class MinimalGutterDiffDecorator { + /** + * @param {import("../../editor").Editor} editor + * @param {number} type + */ + constructor(editor, type) { + this.gutterClass ="ace_mini-diff_gutter-enabled"; + this.gutterCellsClasses = { + add: "mini-diff-added", + delete: "mini-diff-deleted", + }; + + this.editor = editor; + this.type = type; + this.chunks = []; + this.attachToEditor(); + } + + attachToEditor() { + this.renderGutters = this.renderGutters.bind(this); + + dom.addCssClass( + this.editor.renderer.$gutterLayer.element, + this.gutterClass + ); + this.editor.renderer.$gutterLayer.on( + "afterRender", + this.renderGutters + ); + } + + renderGutters(e, gutterLayer) { + const cells = this.editor.renderer.$gutterLayer.$lines.cells; + cells.forEach((cell) => { + cell.element.classList.remove(Object.values(this.gutterCellsClasses)); + }); + const dir = this.type === -1 ? "old" : "new"; + const diffClass = this.type === -1 ? this.gutterCellsClasses.delete : this.gutterCellsClasses.add; + this.chunks.forEach((lineChange) => { + let startRow = lineChange[dir].start.row; + let endRow = lineChange[dir].end.row - 1; + + cells.forEach((cell) => { + if (cell.row >= startRow && cell.row <= endRow) { + cell.element.classList.add(diffClass); + } + }); + }); + } + + setDecorations(changes) { + this.chunks = changes; + this.renderGutters(); + } + + dispose() { + dom.removeCssClass( + this.editor.renderer.$gutterLayer.element, + this.gutterClass + ); + this.editor.renderer.$gutterLayer.off( + "afterRender", + this.renderGutters + ); + } +} + +exports.MinimalGutterDiffDecorator = MinimalGutterDiffDecorator; diff --git a/src/ext/diff/inline_diff_view.js b/src/ext/diff/inline_diff_view.js new file mode 100644 index 00000000000..9346b0b5a46 --- /dev/null +++ b/src/ext/diff/inline_diff_view.js @@ -0,0 +1,387 @@ +"use strict"; + +var LineWidgets = require("../../line_widgets").LineWidgets; + +const BaseDiffView = require("./base_diff_view").BaseDiffView; +const config = require("../../config"); + +class InlineDiffView extends BaseDiffView { + /** + * Constructs a new inline DiffView instance. + * @param {Object} [diffModel] - The model for the diff view. + * @param {import("ace-code").Editor} [diffModel.editorA] - The editor for the original view. + * @param {import("ace-code").Editor} [diffModel.editorB] - The editor for the edited view. + * @param {import("ace-code").EditSession} [diffModel.sessionA] - The edit session for the original view. + * @param {import("ace-code").EditSession} [diffModel.sessionB] - The edit session for the edited view. + * @param {string} [diffModel.valueA] - The original content. + * @param {string} [diffModel.valueB] - The modified content. + * @param {boolean} [diffModel.showSideA] - Whether to show the original view or modified view. + * @param {HTMLElement} [container] - optional container element for the DiffView. + */ + constructor(diffModel, container) { + diffModel = diffModel || {}; + super( true, container); + this.init(diffModel); + } + + init(diffModel) { + this.onSelect = this.onSelect.bind(this); + this.onAfterRender = this.onAfterRender.bind(this); + + + this.$setupModels(diffModel); + this.onChangeTheme(); + config.resetOptions(this); + config["_signal"]("diffView", this); + + var padding = this.activeEditor.renderer.$padding; + + this.addGutterDecorators(); + + this.otherEditor.renderer.setPadding(padding); + this.textLayer = this.otherEditor.renderer.$textLayer; + this.markerLayer = this.otherEditor.renderer.$markerBack; + this.gutterLayer = this.otherEditor.renderer.$gutterLayer; + this.cursorLayer = this.otherEditor.renderer.$cursorLayer; + + this.otherEditor.renderer.$updateCachedSize = function() { + }; + + var textLayerElement = this.activeEditor.renderer.$textLayer.element; + textLayerElement.parentNode.insertBefore( + this.textLayer.element, + textLayerElement + ); + + var markerLayerElement = this.activeEditor.renderer.$markerBack.element; + markerLayerElement.parentNode.insertBefore( + this.markerLayer.element, + markerLayerElement.nextSibling + ); + + var gutterLayerElement = this.activeEditor.renderer.$gutterLayer.element; + gutterLayerElement.parentNode.insertBefore( + this.gutterLayer.element, + gutterLayerElement + ); + gutterLayerElement.style.position = "absolute"; + this.gutterLayer.element.style.position = "absolute"; + this.gutterLayer.element.style.width = "100%"; + this.editorA.renderer.$gutterLayer.element.style.pointerEvents = "none"; + + + this.gutterLayer.$updateGutterWidth = function() {}; + this.initMouse(); + this.initTextInput(); + this.initTextLayer(); + + this.$attachEventHandlers(); + } + + initTextLayer() { + var renderLine = this.textLayer.$renderLine; + var diffView = this; + this.otherEditor.renderer.$textLayer.$renderLine = function(parent, row, foldLIne) { + if (isVisibleRow(diffView.chunks, row)) { + renderLine.call(this, parent, row, foldLIne); + } + }; + var side = this.showSideA ? "new" : "old"; + function isVisibleRow(chunks, row) { + var min = 0; + var max = chunks.length - 1; + var result = -1; + while (min < max) { + var mid = Math.floor((min + max) / 2); + var chunkStart = chunks[mid][side].start.row; + if (chunkStart < row) { + result = mid; + min = mid + 1; + } else if (chunkStart > row) { + max = mid - 1; + } else { + result = mid; + break; + } + } + if (chunks[result + 1] && chunks[result + 1][side].start.row <= row) { + result++; + } + var range = chunks[result] && chunks[result][side]; + if (range && range.end.row > row) { + return true; + } + return false; + } + } + + initTextInput(restore) { + if (restore) { + this.otherEditor.textInput = this.othertextInput; + this.otherEditor.container = this.otherEditorContainer; + } else { + this.othertextInput = this.otherEditor.textInput; + this.otherEditor.textInput = this.activeEditor.textInput; + this.otherEditorContainer = this.otherEditor.container; + this.otherEditor.container = this.activeEditor.container; + } + } + + selectEditor(editor) { + if (editor == this.activeEditor) { + this.otherEditor.selection.clearSelection(); + this.activeEditor.textInput.setHost(this.activeEditor); + this.activeEditor.setStyle("ace_diff_other", false); + this.cursorLayer.element.remove(); + this.activeEditor.renderer.$cursorLayer.element.style.display = "block"; + if (this.showSideA) { + this.sessionA.removeMarker(this.syncSelectionMarkerA.id); + this.sessionA.addDynamicMarker(this.syncSelectionMarkerA, true); + } + } else { + this.activeEditor.selection.clearSelection(); + this.activeEditor.textInput.setHost(this.otherEditor); + this.activeEditor.setStyle("ace_diff_other"); + this.activeEditor.renderer.$cursorLayer.element.parentNode.appendChild( + this.cursorLayer.element + ); + this.activeEditor.renderer.$cursorLayer.element.style.display = "none"; + if (this.activeEditor.$isFocused) { + this.otherEditor.onFocus(); + } + if (this.showSideA) { + this.sessionA.removeMarker(this.syncSelectionMarkerA.id); + } + } + } + initMouse() { + this.otherEditor.renderer.$loop = this.activeEditor.renderer.$loop; + + this.otherEditor.renderer.scroller = { + getBoundingClientRect: () => { + return this.activeEditor.renderer.scroller.getBoundingClientRect(); + }, + style: this.activeEditor.renderer.scroller.style, + }; + + var forwardEvent = (ev) => { + if (!ev.domEvent) return; + var screenPos = ev.editor.renderer.pixelToScreenCoordinates(ev.clientX, ev.clientY); + var posA = this.sessionA.screenToDocumentPosition(screenPos.row, screenPos.column, screenPos.offsetX); + var posB = this.sessionB.screenToDocumentPosition(screenPos.row, screenPos.column, screenPos.offsetX); + + var posAx = this.sessionA.documentToScreenPosition(posA); + var posBx = this.sessionB.documentToScreenPosition(posB); + + if (ev.editor == this.activeEditor) { + if (posBx.row == screenPos.row && posAx.row != screenPos.row) { + if (ev.type == "mousedown") { + this.selectEditor(this.otherEditor); + } + ev.propagationStopped = true; + ev.defaultPrevented = true; + this.otherEditor.$mouseHandler.onMouseEvent(ev.type, ev.domEvent); + } else if (ev.type == "mousedown") { + this.selectEditor(this.activeEditor); + } + } + }; + + + var events = [ + "mousedown", + "click", + "mouseup", + "dblclick", + "tripleclick", + "quadclick", + ]; + events.forEach((event) => { + this.activeEditor.on(event, forwardEvent, true); + this.activeEditor.on("gutter" + event, forwardEvent, true); + }); + + var onFocus = (e) => { + this.activeEditor.onFocus(e); + }; + var onBlur = (e) => { + this.activeEditor.onBlur(e); + }; + this.otherEditor.on("focus", onFocus); + this.otherEditor.on("blur", onBlur); + + this.onMouseDetach = () => { + events.forEach((event) => { + this.activeEditor.off(event, forwardEvent, true); + this.activeEditor.off("gutter" + event, forwardEvent, true); + }); + this.otherEditor.off("focus", onFocus); + this.otherEditor.off("blur", onBlur); + }; + } + + align() { + var diffView = this; + + function add(session, w) { + let lineWidget = session.lineWidgets[w.row]; + if (lineWidget) { + w.rowsAbove += lineWidget.rowsAbove > w.rowsAbove ? lineWidget.rowsAbove : w.rowsAbove; + w.rowCount += lineWidget.rowCount; + } + session.lineWidgets[w.row] = w; + session.widgetManager.lineWidgets[w.row] = w; + session.$resetRowCache(w.row); + var fold = session.getFoldAt(w.row, 0); + if (fold) { + session.widgetManager.updateOnFold({ + data: fold, + action: "add", + }, session); + } + } + + function init(editor) { + var session = editor.session; + if (!session.widgetManager) { + session.widgetManager = new LineWidgets(session); + session.widgetManager.attach(editor); + } + editor.session.lineWidgets = []; + editor.session.widgetManager.lineWidgets = []; + editor.session.$resetRowCache(0); + } + + init(diffView.editorA); + init(diffView.editorB); + + diffView.chunks.forEach(function (ch) { + var diff1 = diffView.sessionA.documentToScreenPosition(ch.old.end).row + - diffView.sessionA.documentToScreenPosition(ch.old.start).row; + var diff2 = diffView.sessionB.documentToScreenPosition(ch.new.end).row + - diffView.sessionB.documentToScreenPosition(ch.new.start).row; + + add(diffView.sessionA, { + rowCount: diff2, + rowsAbove: ch.old.end.row === 0 ? diff2 : 0, + row: ch.old.end.row === 0 ? 0 : ch.old.end.row - 1 + }); + add(diffView.sessionB, { + rowCount: diff1, + rowsAbove: diff1, + row: ch.new.start.row, + }); + + }); + diffView.sessionA["_emit"]("changeFold", {data: {start: {row: 0}}}); + diffView.sessionB["_emit"]("changeFold", {data: {start: {row: 0}}}); + } + + + $attachSessionsEventHandlers() { + this.$attachSessionEventHandlers(this.editorA, this.markerA); + this.$attachSessionEventHandlers(this.editorB, this.markerB); + } + + $attachSessionEventHandlers(editor, marker) { + editor.session.on("changeFold", this.onChangeFold); + editor.session.addDynamicMarker(marker); + editor.selection.on("changeCursor", this.onSelect); + editor.selection.on("changeSelection", this.onSelect); + } + + $detachSessionsEventHandlers() { + this.$detachSessionHandlers(this.editorA, this.markerA); + this.$detachSessionHandlers(this.editorB, this.markerB); + this.otherSession.bgTokenizer.lines.fill(undefined); + } + + $detachSessionHandlers(editor, marker) { + editor.session.removeMarker(marker.id); + editor.selection.off("changeCursor", this.onSelect); + editor.selection.off("changeSelection", this.onSelect); + editor.session.off("changeFold", this.onChangeFold); + } + + $attachEventHandlers() { + this.activeEditor.on("input", this.onInput); + this.activeEditor.renderer.on("afterRender", this.onAfterRender); + this.otherSession.on("change", this.onInput); + } + + $detachEventHandlers() { + this.$detachSessionsEventHandlers(); + this.clearSelectionMarkers(); + this.activeEditor.off("input", this.onInput); + this.activeEditor.renderer.off("afterRender", this.onAfterRender); + this.otherSession.off("change", this.onInput); + + this.textLayer.element.textContent = ""; + this.textLayer.element.remove(); + this.gutterLayer.element.textContent = ""; + this.gutterLayer.element.remove(); + this.markerLayer.element.textContent = ""; + this.markerLayer.element.remove(); + + this.onMouseDetach(); + + this.selectEditor(this.activeEditor); + this.otherEditor.setSession(null); + this.otherEditor.renderer.$loop = null; + this.initTextInput(true); + + this.otherEditor.destroy(); + } + + /** + * @param {number} changes + * @param {import("ace-code").VirtualRenderer} renderer + */ + onAfterRender(changes, renderer) { + var config = renderer.layerConfig; + + var session = this.otherSession; + var cloneRenderer = this.otherEditor.renderer; + + session.$scrollTop = renderer.scrollTop; + session.$scrollLeft = renderer.scrollLeft; + + [ + "characterWidth", + "lineHeight", + "scrollTop", + "scrollLeft", + "scrollMargin", + "$padding", + "$size", + "layerConfig", + "$horizScroll", + "$vScroll", + ]. forEach(function(prop) { + cloneRenderer[prop] = renderer[prop]; + }); + + cloneRenderer.$computeLayerConfig(); + + var newConfig = cloneRenderer.layerConfig; + + this.gutterLayer.update(newConfig); + + newConfig.firstRowScreen = config.firstRowScreen; + + cloneRenderer.$cursorLayer.config = newConfig; + cloneRenderer.$cursorLayer.update(newConfig); + + if (changes & cloneRenderer.CHANGE_LINES + || changes & cloneRenderer.CHANGE_FULL + || changes & cloneRenderer.CHANGE_SCROLL + || changes & cloneRenderer.CHANGE_TEXT + ) + this.textLayer.update(newConfig); + + this.markerLayer.setMarkers(this.otherSession.getMarkers()); + this.markerLayer.update(newConfig); + } +} + +exports.InlineDiffView = InlineDiffView; diff --git a/src/ext/diff/providers/default.js b/src/ext/diff/providers/default.js new file mode 100644 index 00000000000..27ff9d09f97 --- /dev/null +++ b/src/ext/diff/providers/default.js @@ -0,0 +1,2477 @@ +'use strict'; + +function equals(one, other, itemEquals = (a, b) => a === b) { + if (one === other) { + return true; + } + if (!one || !other) { + return false; + } + if (one.length !== other.length) { + return false; + } + for (let i = 0, len = one.length; i < len; i++) { + if (!itemEquals(one[i], other[i])) { + return false; + } + } + return true; +} +function* groupAdjacentBy(items, shouldBeGrouped) { + let currentGroup; + let last; + for (const item of items) { + if (last !== undefined && shouldBeGrouped(last, item)) { + currentGroup.push(item); + } else { + if (currentGroup) { + yield currentGroup; + } + currentGroup = [item]; + } + last = item; + } + if (currentGroup) { + yield currentGroup; + } +} +function forEachAdjacent(arr, f) { + for (let i = 0; i <= arr.length; i++) { + f(i === 0 ? undefined : arr[i - 1], i === arr.length ? undefined : arr[i]); + } +} +function forEachWithNeighbors(arr, f) { + for (let i = 0; i < arr.length; i++) { + f(i === 0 ? undefined : arr[i - 1], arr[i], i + 1 === arr.length ? undefined : arr[i + 1]); + } +} +function pushMany(arr, items) { + for (const item of items) { + arr.push(item); + } +} +function compareBy(selector, comparator) { + return (a, b) => comparator(selector(a), selector(b)); +} +const numberComparator = (a, b) => a - b; +function reverseOrder(comparator) { + return (a, b) => -comparator(a, b); +} + +class BugIndicatingError extends Error { + constructor(message) { + super(message || "An unexpected bug occurred."); + Object.setPrototypeOf(this, BugIndicatingError.prototype); + } +} + +function assert(condition, message = "unexpected state") { + if (!condition) { + throw new BugIndicatingError(`Assertion Failed: ${message}`); + } +} +function assertFn(condition) { + condition(); +} +function checkAdjacentItems(items, predicate) { + let i = 0; + while (i < items.length - 1) { + const a = items[i]; + const b = items[i + 1]; + if (!predicate(a, b)) { + return false; + } + i++; + } + return true; +} + +class OffsetRange { + constructor(start, endExclusive) { + this.start = start; + this.endExclusive = endExclusive; + if (start > endExclusive) { + throw new BugIndicatingError(`Invalid range: ${this.toString()}`); + } + } + static fromTo(start, endExclusive) { + return new OffsetRange(start, endExclusive); + } + static addRange(range, sortedRanges) { + let i = 0; + while (i < sortedRanges.length && sortedRanges[i].endExclusive < range.start) { + i++; + } + let j = i; + while (j < sortedRanges.length && sortedRanges[j].start <= range.endExclusive) { + j++; + } + if (i === j) { + sortedRanges.splice(i, 0, range); + } else { + const start = Math.min(range.start, sortedRanges[i].start); + const end = Math.max(range.endExclusive, sortedRanges[j - 1].endExclusive); + sortedRanges.splice(i, j - i, new OffsetRange(start, end)); + } + } + static tryCreate(start, endExclusive) { + if (start > endExclusive) { + return undefined; + } + return new OffsetRange(start, endExclusive); + } + static ofLength(length) { + return new OffsetRange(0, length); + } + static ofStartAndLength(start, length) { + return new OffsetRange(start, start + length); + } + static emptyAt(offset) { + return new OffsetRange(offset, offset); + } + get isEmpty() { + return this.start === this.endExclusive; + } + delta(offset) { + return new OffsetRange(this.start + offset, this.endExclusive + offset); + } + deltaStart(offset) { + return new OffsetRange(this.start + offset, this.endExclusive); + } + deltaEnd(offset) { + return new OffsetRange(this.start, this.endExclusive + offset); + } + get length() { + return this.endExclusive - this.start; + } + toString() { + return `[${this.start}, ${this.endExclusive})`; + } + equals(other) { + return this.start === other.start && this.endExclusive === other.endExclusive; + } + containsRange(other) { + return this.start <= other.start && other.endExclusive <= this.endExclusive; + } + contains(offset) { + return this.start <= offset && offset < this.endExclusive; + } + /** + * for all numbers n: range1.contains(n) or range2.contains(n) => range1.join(range2).contains(n) + * The joined range is the smallest range that contains both ranges. + */ + join(other) { + return new OffsetRange(Math.min(this.start, other.start), Math.max(this.endExclusive, other.endExclusive)); + } + /** + * for all numbers n: range1.contains(n) and range2.contains(n) <=> range1.intersect(range2).contains(n) + * + * The resulting range is empty if the ranges do not intersect, but touch. + * If the ranges don't even touch, the result is undefined. + */ + intersect(other) { + const start = Math.max(this.start, other.start); + const end = Math.min(this.endExclusive, other.endExclusive); + if (start <= end) { + return new OffsetRange(start, end); + } + return undefined; + } + intersectionLength(range) { + const start = Math.max(this.start, range.start); + const end = Math.min(this.endExclusive, range.endExclusive); + return Math.max(0, end - start); + } + intersects(other) { + const start = Math.max(this.start, other.start); + const end = Math.min(this.endExclusive, other.endExclusive); + return start < end; + } + intersectsOrTouches(other) { + const start = Math.max(this.start, other.start); + const end = Math.min(this.endExclusive, other.endExclusive); + return start <= end; + } + isBefore(other) { + return this.endExclusive <= other.start; + } + isAfter(other) { + return this.start >= other.endExclusive; + } + slice(arr) { + return arr.slice(this.start, this.endExclusive); + } + substring(str) { + return str.substring(this.start, this.endExclusive); + } + /** + * Returns the given value if it is contained in this instance, otherwise the closest value that is contained. + * The range must not be empty. + */ + clip(value) { + if (this.isEmpty) { + throw new BugIndicatingError(`Invalid clipping range: ${this.toString()}`); + } + return Math.max(this.start, Math.min(this.endExclusive - 1, value)); + } + /** + * Returns `r := value + k * length` such that `r` is contained in this range. + * The range must not be empty. + * + * E.g. `[5, 10).clipCyclic(10) === 5`, `[5, 10).clipCyclic(11) === 6` and `[5, 10).clipCyclic(4) === 9`. + */ + clipCyclic(value) { + if (this.isEmpty) { + throw new BugIndicatingError(`Invalid clipping range: ${this.toString()}`); + } + if (value < this.start) { + return this.endExclusive - (this.start - value) % this.length; + } + if (value >= this.endExclusive) { + return this.start + (value - this.start) % this.length; + } + return value; + } + map(f) { + const result = []; + for (let i = this.start; i < this.endExclusive; i++) { + result.push(f(i)); + } + return result; + } + forEach(f) { + for (let i = this.start; i < this.endExclusive; i++) { + f(i); + } + } +} + +class Position { + constructor(lineNumber, column) { + this.lineNumber = lineNumber; + this.column = column; + } + /** + * Test if this position equals other position + */ + equals(other) { + return Position.equals(this, other); + } + /** + * Test if position `a` equals position `b` + */ + static equals(a, b) { + if (!a && !b) { + return true; + } + return !!a && !!b && a.lineNumber === b.lineNumber && a.column === b.column; + } + /** + * Test if this position is before other position. + * If the two positions are equal, the result will be false. + */ + isBefore(other) { + return Position.isBefore(this, other); + } + /** + * Test if position `a` is before position `b`. + * If the two positions are equal, the result will be false. + */ + static isBefore(a, b) { + if (a.lineNumber < b.lineNumber) { + return true; + } + if (b.lineNumber < a.lineNumber) { + return false; + } + return a.column < b.column; + } + /** + * Test if this position is before other position. + * If the two positions are equal, the result will be true. + */ + isBeforeOrEqual(other) { + return Position.isBeforeOrEqual(this, other); + } + /** + * Test if position `a` is before position `b`. + * If the two positions are equal, the result will be true. + */ + static isBeforeOrEqual(a, b) { + if (a.lineNumber < b.lineNumber) { + return true; + } + if (b.lineNumber < a.lineNumber) { + return false; + } + return a.column <= b.column; + } +} + +class Range { + constructor(startLineNumber, startColumn, endLineNumber, endColumn) { + if (startLineNumber > endLineNumber || startLineNumber === endLineNumber && startColumn > endColumn) { + this.startLineNumber = endLineNumber; + this.startColumn = endColumn; + this.endLineNumber = startLineNumber; + this.endColumn = startColumn; + } else { + this.startLineNumber = startLineNumber; + this.startColumn = startColumn; + this.endLineNumber = endLineNumber; + this.endColumn = endColumn; + } + } + /** + * Test if this range is empty. + */ + isEmpty() { + return Range.isEmpty(this); + } + /** + * Test if `range` is empty. + */ + static isEmpty(range) { + return range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn; + } + /** + * Test if position is in this range. If the position is at the edges, will return true. + */ + containsPosition(position) { + return Range.containsPosition(this, position); + } + /** + * Test if `position` is in `range`. If the position is at the edges, will return true. + */ + static containsPosition(range, position) { + if (position.lineNumber < range.startLineNumber || position.lineNumber > range.endLineNumber) { + return false; + } + if (position.lineNumber === range.startLineNumber && position.column < range.startColumn) { + return false; + } + if (position.lineNumber === range.endLineNumber && position.column > range.endColumn) { + return false; + } + return true; + } + /** + * Test if range is in this range. If the range is equal to this range, will return true. + */ + containsRange(range) { + return Range.containsRange(this, range); + } + /** + * Test if `otherRange` is in `range`. If the ranges are equal, will return true. + */ + static containsRange(range, otherRange) { + if (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) { + return false; + } + if (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) { + return false; + } + if (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn < range.startColumn) { + return false; + } + if (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn > range.endColumn) { + return false; + } + return true; + } + /** + * Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true. + */ + strictContainsRange(range) { + return Range.strictContainsRange(this, range); + } + /** + * Test if `otherRange` is strictly in `range` (must start after, and end before). If the ranges are equal, will return false. + */ + static strictContainsRange(range, otherRange) { + if (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) { + return false; + } + if (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) { + return false; + } + if (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn <= range.startColumn) { + return false; + } + if (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn >= range.endColumn) { + return false; + } + return true; + } + /** + * A reunion of the two ranges. + * The smallest position will be used as the start point, and the largest one as the end point. + */ + plusRange(range) { + return Range.plusRange(this, range); + } + /** + * A reunion of the two ranges. + * The smallest position will be used as the start point, and the largest one as the end point. + */ + static plusRange(a, b) { + let startLineNumber; + let startColumn; + let endLineNumber; + let endColumn; + if (b.startLineNumber < a.startLineNumber) { + startLineNumber = b.startLineNumber; + startColumn = b.startColumn; + } else if (b.startLineNumber === a.startLineNumber) { + startLineNumber = b.startLineNumber; + startColumn = Math.min(b.startColumn, a.startColumn); + } else { + startLineNumber = a.startLineNumber; + startColumn = a.startColumn; + } + if (b.endLineNumber > a.endLineNumber) { + endLineNumber = b.endLineNumber; + endColumn = b.endColumn; + } else if (b.endLineNumber === a.endLineNumber) { + endLineNumber = b.endLineNumber; + endColumn = Math.max(b.endColumn, a.endColumn); + } else { + endLineNumber = a.endLineNumber; + endColumn = a.endColumn; + } + return new Range(startLineNumber, startColumn, endLineNumber, endColumn); + } + /** + * A intersection of the two ranges. + */ + intersectRanges(range) { + return Range.intersectRanges(this, range); + } + /** + * A intersection of the two ranges. + */ + static intersectRanges(a, b) { + let resultStartLineNumber = a.startLineNumber; + let resultStartColumn = a.startColumn; + let resultEndLineNumber = a.endLineNumber; + let resultEndColumn = a.endColumn; + const otherStartLineNumber = b.startLineNumber; + const otherStartColumn = b.startColumn; + const otherEndLineNumber = b.endLineNumber; + const otherEndColumn = b.endColumn; + if (resultStartLineNumber < otherStartLineNumber) { + resultStartLineNumber = otherStartLineNumber; + resultStartColumn = otherStartColumn; + } else if (resultStartLineNumber === otherStartLineNumber) { + resultStartColumn = Math.max(resultStartColumn, otherStartColumn); + } + if (resultEndLineNumber > otherEndLineNumber) { + resultEndLineNumber = otherEndLineNumber; + resultEndColumn = otherEndColumn; + } else if (resultEndLineNumber === otherEndLineNumber) { + resultEndColumn = Math.min(resultEndColumn, otherEndColumn); + } + if (resultStartLineNumber > resultEndLineNumber) { + return null; + } + if (resultStartLineNumber === resultEndLineNumber && resultStartColumn > resultEndColumn) { + return null; + } + return new Range(resultStartLineNumber, resultStartColumn, resultEndLineNumber, resultEndColumn); + } + /** + * Test if this range equals other. + */ + equalsRange(other) { + return Range.equalsRange(this, other); + } + /** + * Test if range `a` equals `b`. + */ + static equalsRange(a, b) { + if (!a && !b) { + return true; + } + return !!a && !!b && a.startLineNumber === b.startLineNumber && a.startColumn === b.startColumn && a.endLineNumber === b.endLineNumber && a.endColumn === b.endColumn; + } + /** + * Return the end position (which will be after or equal to the start position) + */ + getEndPosition() { + return Range.getEndPosition(this); + } + /** + * Return the end position (which will be after or equal to the start position) + */ + static getEndPosition(range) { + return new Position(range.endLineNumber, range.endColumn); + } + /** + * Return the start position (which will be before or equal to the end position) + */ + getStartPosition() { + return Range.getStartPosition(this); + } + /** + * Return the start position (which will be before or equal to the end position) + */ + static getStartPosition(range) { + return new Position(range.startLineNumber, range.startColumn); + } + /** + * Create a new empty range using this range's start position. + */ + collapseToStart() { + return Range.collapseToStart(this); + } + /** + * Create a new empty range using this range's start position. + */ + static collapseToStart(range) { + return new Range(range.startLineNumber, range.startColumn, range.startLineNumber, range.startColumn); + } + /** + * Create a new empty range using this range's end position. + */ + collapseToEnd() { + return Range.collapseToEnd(this); + } + /** + * Create a new empty range using this range's end position. + */ + static collapseToEnd(range) { + return new Range(range.endLineNumber, range.endColumn, range.endLineNumber, range.endColumn); + } + // --- + static fromPositions(start, end = start) { + return new Range(start.lineNumber, start.column, end.lineNumber, end.column); + } +} + +function findLastMonotonous(array, predicate) { + const idx = findLastIdxMonotonous(array, predicate); + return idx === -1 ? undefined : array[idx]; +} +function findLastIdxMonotonous(array, predicate, startIdx = 0, endIdxEx = array.length) { + let i = startIdx; + let j = endIdxEx; + while (i < j) { + const k = Math.floor((i + j) / 2); + if (predicate(array[k])) { + i = k + 1; + } else { + j = k; + } + } + return i - 1; +} +function findFirstMonotonous(array, predicate) { + const idx = findFirstIdxMonotonousOrArrLen(array, predicate); + return idx === array.length ? undefined : array[idx]; +} +function findFirstIdxMonotonousOrArrLen(array, predicate, startIdx = 0, endIdxEx = array.length) { + let i = startIdx; + let j = endIdxEx; + while (i < j) { + const k = Math.floor((i + j) / 2); + if (predicate(array[k])) { + j = k; + } else { + i = k + 1; + } + } + return i; +} +class MonotonousArray { + constructor(_array) { + this._array = _array; + this._findLastMonotonousLastIdx = 0; + } + static { + this.assertInvariants = false; + } + /** + * The predicate must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`! + * For subsequent calls, current predicate must be weaker than (or equal to) the previous predicate, i.e. more entries must be `true`. + */ + findLastMonotonous(predicate) { + if (MonotonousArray.assertInvariants) { + if (this._prevFindLastPredicate) { + for (const item of this._array) { + if (this._prevFindLastPredicate(item) && !predicate(item)) { + throw new Error("MonotonousArray: current predicate must be weaker than (or equal to) the previous predicate."); + } + } + } + this._prevFindLastPredicate = predicate; + } + const idx = findLastIdxMonotonous(this._array, predicate, this._findLastMonotonousLastIdx); + this._findLastMonotonousLastIdx = idx + 1; + return idx === -1 ? undefined : this._array[idx]; + } +} + +class LineRange { + static fromRangeInclusive(range) { + return new LineRange(range.startLineNumber, range.endLineNumber + 1); + } + static join(lineRanges) { + if (lineRanges.length === 0) { + throw new BugIndicatingError("lineRanges cannot be empty"); + } + let startLineNumber = lineRanges[0].startLineNumber; + let endLineNumberExclusive = lineRanges[0].endLineNumberExclusive; + for (let i = 1; i < lineRanges.length; i++) { + startLineNumber = Math.min(startLineNumber, lineRanges[i].startLineNumber); + endLineNumberExclusive = Math.max(endLineNumberExclusive, lineRanges[i].endLineNumberExclusive); + } + return new LineRange(startLineNumber, endLineNumberExclusive); + } + static ofLength(startLineNumber, length) { + return new LineRange(startLineNumber, startLineNumber + length); + } + constructor(startLineNumber, endLineNumberExclusive) { + if (startLineNumber > endLineNumberExclusive) { + throw new BugIndicatingError(`startLineNumber ${startLineNumber} cannot be after endLineNumberExclusive ${endLineNumberExclusive}`); + } + this.startLineNumber = startLineNumber; + this.endLineNumberExclusive = endLineNumberExclusive; + } + /** + * Indicates if this line range is empty. + */ + get isEmpty() { + return this.startLineNumber === this.endLineNumberExclusive; + } + /** + * Moves this line range by the given offset of line numbers. + */ + delta(offset) { + return new LineRange(this.startLineNumber + offset, this.endLineNumberExclusive + offset); + } + /** + * The number of lines this line range spans. + */ + get length() { + return this.endLineNumberExclusive - this.startLineNumber; + } + /** + * Creates a line range that combines this and the given line range. + */ + join(other) { + return new LineRange( + Math.min(this.startLineNumber, other.startLineNumber), + Math.max(this.endLineNumberExclusive, other.endLineNumberExclusive) + ); + } + /** + * The resulting range is empty if the ranges do not intersect, but touch. + * If the ranges don't even touch, the result is undefined. + */ + intersect(other) { + const startLineNumber = Math.max(this.startLineNumber, other.startLineNumber); + const endLineNumberExclusive = Math.min(this.endLineNumberExclusive, other.endLineNumberExclusive); + if (startLineNumber <= endLineNumberExclusive) { + return new LineRange(startLineNumber, endLineNumberExclusive); + } + return undefined; + } + overlapOrTouch(other) { + return this.startLineNumber <= other.endLineNumberExclusive && other.startLineNumber <= this.endLineNumberExclusive; + } + toInclusiveRange() { + if (this.isEmpty) { + return null; + } + return new Range(this.startLineNumber, 1, this.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER); + } + /** + * Converts this 1-based line range to a 0-based offset range (subtracts 1!). + * @internal + */ + toOffsetRange() { + return new OffsetRange(this.startLineNumber - 1, this.endLineNumberExclusive - 1); + } +} +class LineRangeSet { + constructor(_normalizedRanges = []) { + this._normalizedRanges = _normalizedRanges; + } + get ranges() { + return this._normalizedRanges; + } + addRange(range) { + if (range.length === 0) { + return; + } + const joinRangeStartIdx = findFirstIdxMonotonousOrArrLen(this._normalizedRanges, (r) => r.endLineNumberExclusive >= range.startLineNumber); + const joinRangeEndIdxExclusive = findLastIdxMonotonous(this._normalizedRanges, (r) => r.startLineNumber <= range.endLineNumberExclusive) + 1; + if (joinRangeStartIdx === joinRangeEndIdxExclusive) { + this._normalizedRanges.splice(joinRangeStartIdx, 0, range); + } else if (joinRangeStartIdx === joinRangeEndIdxExclusive - 1) { + const joinRange = this._normalizedRanges[joinRangeStartIdx]; + this._normalizedRanges[joinRangeStartIdx] = joinRange.join(range); + } else { + const joinRange = this._normalizedRanges[joinRangeStartIdx].join(this._normalizedRanges[joinRangeEndIdxExclusive - 1]).join(range); + this._normalizedRanges.splice(joinRangeStartIdx, joinRangeEndIdxExclusive - joinRangeStartIdx, joinRange); + } + } + contains(lineNumber) { + const rangeThatStartsBeforeEnd = findLastMonotonous(this._normalizedRanges, (r) => r.startLineNumber <= lineNumber); + return !!rangeThatStartsBeforeEnd && rangeThatStartsBeforeEnd.endLineNumberExclusive > lineNumber; + } + /** + * Subtracts all ranges in this set from `range` and returns the result. + */ + subtractFrom(range) { + const joinRangeStartIdx = findFirstIdxMonotonousOrArrLen(this._normalizedRanges, (r) => r.endLineNumberExclusive >= range.startLineNumber); + const joinRangeEndIdxExclusive = findLastIdxMonotonous(this._normalizedRanges, (r) => r.startLineNumber <= range.endLineNumberExclusive) + 1; + if (joinRangeStartIdx === joinRangeEndIdxExclusive) { + return new LineRangeSet([range]); + } + const result = []; + let startLineNumber = range.startLineNumber; + for (let i = joinRangeStartIdx; i < joinRangeEndIdxExclusive; i++) { + const r = this._normalizedRanges[i]; + if (r.startLineNumber > startLineNumber) { + result.push(new LineRange(startLineNumber, r.startLineNumber)); + } + startLineNumber = r.endLineNumberExclusive; + } + if (startLineNumber < range.endLineNumberExclusive) { + result.push(new LineRange(startLineNumber, range.endLineNumberExclusive)); + } + return new LineRangeSet(result); + } + getIntersection(other) { + const result = []; + let i1 = 0; + let i2 = 0; + while (i1 < this._normalizedRanges.length && i2 < other._normalizedRanges.length) { + const r1 = this._normalizedRanges[i1]; + const r2 = other._normalizedRanges[i2]; + const i = r1.intersect(r2); + if (i && !i.isEmpty) { + result.push(i); + } + if (r1.endLineNumberExclusive < r2.endLineNumberExclusive) { + i1++; + } else { + i2++; + } + } + return new LineRangeSet(result); + } + getWithDelta(value) { + return new LineRangeSet(this._normalizedRanges.map((r) => r.delta(value))); + } +} + +class TextLength { + constructor(lineCount, columnCount) { + this.lineCount = lineCount; + this.columnCount = columnCount; + } + static { + this.zero = new TextLength(0, 0); + } + toLineRange() { + return LineRange.ofLength(1, this.lineCount); + } + addToPosition(position) { + if (this.lineCount === 0) { + return new Position(position.lineNumber, position.column + this.columnCount); + } else { + return new Position(position.lineNumber + this.lineCount, this.columnCount + 1); + } + } +} + + +class LineBasedText { + constructor(_getLineContent, _lineCount) { + assert(_lineCount >= 1); + this._getLineContent = _getLineContent; + this._lineCount = _lineCount; + } + getValueOfRange(range) { + if (range.startLineNumber === range.endLineNumber) { + return this._getLineContent(range.startLineNumber).substring(range.startColumn - 1, range.endColumn - 1); + } + let result = this._getLineContent(range.startLineNumber).substring(range.startColumn - 1); + for (let i = range.startLineNumber + 1; i < range.endLineNumber; i++) { + result += "\n" + this._getLineContent(i); + } + result += "\n" + this._getLineContent(range.endLineNumber).substring(0, range.endColumn - 1); + return result; + } + getLineLength(lineNumber) { + return this._getLineContent(lineNumber).length; + } + get length() { + const lastLine = this._getLineContent(this._lineCount); + return new TextLength(this._lineCount - 1, lastLine.length); + } +} +class ArrayText extends LineBasedText { + constructor(lines) { + super( + (lineNumber) => lines[lineNumber - 1], + lines.length + ); + } +} + +class LinesDiff { + constructor(changes, moves, hitTimeout) { + this.changes = changes; + this.moves = moves; + this.hitTimeout = hitTimeout; + } +} +class MovedText { + constructor(lineRangeMapping, changes) { + this.lineRangeMapping = lineRangeMapping; + this.changes = changes; + } +} + +class LineRangeMapping { + constructor(originalRange, modifiedRange) { + this.original = originalRange; + this.modified = modifiedRange; + } + join(other) { + return new LineRangeMapping( + this.original.join(other.original), + this.modified.join(other.modified) + ); + } + get changedLineCount() { + return Math.max(this.original.length, this.modified.length); + } + /** + * This method assumes that the LineRangeMapping describes a valid diff! + * I.e. if one range is empty, the other range cannot be the entire document. + * It avoids various problems when the line range points to non-existing line-numbers. + */ + toRangeMapping() { + const origInclusiveRange = this.original.toInclusiveRange(); + const modInclusiveRange = this.modified.toInclusiveRange(); + if (origInclusiveRange && modInclusiveRange) { + return new RangeMapping(origInclusiveRange, modInclusiveRange); + } else if (this.original.startLineNumber === 1 || this.modified.startLineNumber === 1) { + if (!(this.modified.startLineNumber === 1 && this.original.startLineNumber === 1)) { + throw new BugIndicatingError("not a valid diff"); + } + return new RangeMapping( + new Range(this.original.startLineNumber, 1, this.original.endLineNumberExclusive, 1), + new Range(this.modified.startLineNumber, 1, this.modified.endLineNumberExclusive, 1) + ); + } else { + return new RangeMapping( + new Range(this.original.startLineNumber - 1, Number.MAX_SAFE_INTEGER, this.original.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER), + new Range(this.modified.startLineNumber - 1, Number.MAX_SAFE_INTEGER, this.modified.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER) + ); + } + } + /** + * This method assumes that the LineRangeMapping describes a valid diff! + * I.e. if one range is empty, the other range cannot be the entire document. + * It avoids various problems when the line range points to non-existing line-numbers. + */ + toRangeMapping2(original, modified) { + if (isValidLineNumber(this.original.endLineNumberExclusive, original) && isValidLineNumber(this.modified.endLineNumberExclusive, modified)) { + return new RangeMapping( + new Range(this.original.startLineNumber, 1, this.original.endLineNumberExclusive, 1), + new Range(this.modified.startLineNumber, 1, this.modified.endLineNumberExclusive, 1) + ); + } + if (!this.original.isEmpty && !this.modified.isEmpty) { + return new RangeMapping( + Range.fromPositions( + new Position(this.original.startLineNumber, 1), + normalizePosition(new Position(this.original.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER), original) + ), + Range.fromPositions( + new Position(this.modified.startLineNumber, 1), + normalizePosition(new Position(this.modified.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER), modified) + ) + ); + } + if (this.original.startLineNumber > 1 && this.modified.startLineNumber > 1) { + return new RangeMapping( + Range.fromPositions( + normalizePosition(new Position(this.original.startLineNumber - 1, Number.MAX_SAFE_INTEGER), original), + normalizePosition(new Position(this.original.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER), original) + ), + Range.fromPositions( + normalizePosition(new Position(this.modified.startLineNumber - 1, Number.MAX_SAFE_INTEGER), modified), + normalizePosition(new Position(this.modified.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER), modified) + ) + ); + } + throw new BugIndicatingError(); + } +} +function normalizePosition(position, content) { + if (position.lineNumber < 1) { + return new Position(1, 1); + } + if (position.lineNumber > content.length) { + return new Position(content.length, content[content.length - 1].length + 1); + } + const line = content[position.lineNumber - 1]; + if (position.column > line.length + 1) { + return new Position(position.lineNumber, line.length + 1); + } + return position; +} +function isValidLineNumber(lineNumber, lines) { + return lineNumber >= 1 && lineNumber <= lines.length; +} +class DetailedLineRangeMapping extends LineRangeMapping { + static fromRangeMappings(rangeMappings) { + const originalRange = LineRange.join(rangeMappings.map((r) => LineRange.fromRangeInclusive(r.originalRange))); + const modifiedRange = LineRange.join(rangeMappings.map((r) => LineRange.fromRangeInclusive(r.modifiedRange))); + return new DetailedLineRangeMapping(originalRange, modifiedRange, rangeMappings); + } + constructor(originalRange, modifiedRange, innerChanges) { + super(originalRange, modifiedRange); + this.innerChanges = innerChanges; + } + flip() { + return new DetailedLineRangeMapping(this.modified, this.original, this.innerChanges?.map((c) => c.flip())); + } + withInnerChangesFromLineRanges() { + return new DetailedLineRangeMapping(this.original, this.modified, [this.toRangeMapping()]); + } +} +class RangeMapping { + static join(rangeMappings) { + if (rangeMappings.length === 0) { + throw new BugIndicatingError("Cannot join an empty list of range mappings"); + } + let result = rangeMappings[0]; + for (let i = 1; i < rangeMappings.length; i++) { + result = result.join(rangeMappings[i]); + } + return result; + } + static assertSorted(rangeMappings) { + for (let i = 1; i < rangeMappings.length; i++) { + const previous = rangeMappings[i - 1]; + const current = rangeMappings[i]; + if (!(previous.originalRange.getEndPosition().isBeforeOrEqual(current.originalRange.getStartPosition()) && previous.modifiedRange.getEndPosition().isBeforeOrEqual(current.modifiedRange.getStartPosition()))) { + throw new BugIndicatingError("Range mappings must be sorted"); + } + } + } + constructor(originalRange, modifiedRange) { + this.originalRange = originalRange; + this.modifiedRange = modifiedRange; + } + flip() { + return new RangeMapping(this.modifiedRange, this.originalRange); + } + /** + * Creates a single text edit that describes the change from the original to the modified text. + */ + join(other) { + return new RangeMapping( + this.originalRange.plusRange(other.originalRange), + this.modifiedRange.plusRange(other.modifiedRange) + ); + } +} +function lineRangeMappingFromRangeMappings(alignments, originalLines, modifiedLines, dontAssertStartLine = false) { + const changes = []; + for (const g of groupAdjacentBy( + alignments.map((a) => getLineRangeMapping(a, originalLines, modifiedLines)), + (a1, a2) => a1.original.overlapOrTouch(a2.original) || a1.modified.overlapOrTouch(a2.modified) + )) { + const first = g[0]; + const last = g[g.length - 1]; + changes.push(new DetailedLineRangeMapping( + first.original.join(last.original), + first.modified.join(last.modified), + g.map((a) => a.innerChanges[0]) + )); + } + assertFn(() => { + if (!dontAssertStartLine && changes.length > 0) { + if (changes[0].modified.startLineNumber !== changes[0].original.startLineNumber) { + return false; + } + if (modifiedLines.length.lineCount - changes[changes.length - 1].modified.endLineNumberExclusive !== originalLines.length.lineCount - changes[changes.length - 1].original.endLineNumberExclusive) { + return false; + } + } + return checkAdjacentItems( + changes, + (m1, m2) => m2.original.startLineNumber - m1.original.endLineNumberExclusive === m2.modified.startLineNumber - m1.modified.endLineNumberExclusive && // There has to be an unchanged line in between (otherwise both diffs should have been joined) + m1.original.endLineNumberExclusive < m2.original.startLineNumber && m1.modified.endLineNumberExclusive < m2.modified.startLineNumber + ); + }); + return changes; +} +function getLineRangeMapping(rangeMapping, originalLines, modifiedLines) { + let lineStartDelta = 0; + let lineEndDelta = 0; + if (rangeMapping.modifiedRange.endColumn === 1 && rangeMapping.originalRange.endColumn === 1 && rangeMapping.originalRange.startLineNumber + lineStartDelta <= rangeMapping.originalRange.endLineNumber && rangeMapping.modifiedRange.startLineNumber + lineStartDelta <= rangeMapping.modifiedRange.endLineNumber) { + lineEndDelta = -1; + } + if (rangeMapping.modifiedRange.startColumn - 1 >= modifiedLines.getLineLength(rangeMapping.modifiedRange.startLineNumber) && rangeMapping.originalRange.startColumn - 1 >= originalLines.getLineLength(rangeMapping.originalRange.startLineNumber) && rangeMapping.originalRange.startLineNumber <= rangeMapping.originalRange.endLineNumber + lineEndDelta && rangeMapping.modifiedRange.startLineNumber <= rangeMapping.modifiedRange.endLineNumber + lineEndDelta) { + lineStartDelta = 1; + } + const originalLineRange = new LineRange( + rangeMapping.originalRange.startLineNumber + lineStartDelta, + rangeMapping.originalRange.endLineNumber + 1 + lineEndDelta + ); + const modifiedLineRange = new LineRange( + rangeMapping.modifiedRange.startLineNumber + lineStartDelta, + rangeMapping.modifiedRange.endLineNumber + 1 + lineEndDelta + ); + return new DetailedLineRangeMapping(originalLineRange, modifiedLineRange, [rangeMapping]); +} + +class DiffAlgorithmResult { + constructor(diffs, hitTimeout) { + this.diffs = diffs; + this.hitTimeout = hitTimeout; + } + static trivial(seq1, seq2) { + return new DiffAlgorithmResult([new SequenceDiff(OffsetRange.ofLength(seq1.length), OffsetRange.ofLength(seq2.length))], false); + } + static trivialTimedOut(seq1, seq2) { + return new DiffAlgorithmResult([new SequenceDiff(OffsetRange.ofLength(seq1.length), OffsetRange.ofLength(seq2.length))], true); + } +} +class SequenceDiff { + constructor(seq1Range, seq2Range) { + this.seq1Range = seq1Range; + this.seq2Range = seq2Range; + } + static invert(sequenceDiffs, doc1Length) { + const result = []; + forEachAdjacent(sequenceDiffs, (a, b) => { + result.push(SequenceDiff.fromOffsetPairs( + a ? a.getEndExclusives() : OffsetPair.zero, + b ? b.getStarts() : new OffsetPair(doc1Length, (a ? a.seq2Range.endExclusive - a.seq1Range.endExclusive : 0) + doc1Length) + )); + }); + return result; + } + static fromOffsetPairs(start, endExclusive) { + return new SequenceDiff( + new OffsetRange(start.offset1, endExclusive.offset1), + new OffsetRange(start.offset2, endExclusive.offset2) + ); + } + static assertSorted(sequenceDiffs) { + let last = undefined; + for (const cur of sequenceDiffs) { + if (last) { + if (!(last.seq1Range.endExclusive <= cur.seq1Range.start && last.seq2Range.endExclusive <= cur.seq2Range.start)) { + throw new BugIndicatingError("Sequence diffs must be sorted"); + } + } + last = cur; + } + } + swap() { + return new SequenceDiff(this.seq2Range, this.seq1Range); + } + join(other) { + return new SequenceDiff(this.seq1Range.join(other.seq1Range), this.seq2Range.join(other.seq2Range)); + } + delta(offset) { + if (offset === 0) { + return this; + } + return new SequenceDiff(this.seq1Range.delta(offset), this.seq2Range.delta(offset)); + } + deltaStart(offset) { + if (offset === 0) { + return this; + } + return new SequenceDiff(this.seq1Range.deltaStart(offset), this.seq2Range.deltaStart(offset)); + } + deltaEnd(offset) { + if (offset === 0) { + return this; + } + return new SequenceDiff(this.seq1Range.deltaEnd(offset), this.seq2Range.deltaEnd(offset)); + } + intersect(other) { + const i1 = this.seq1Range.intersect(other.seq1Range); + const i2 = this.seq2Range.intersect(other.seq2Range); + if (!i1 || !i2) { + return undefined; + } + return new SequenceDiff(i1, i2); + } + getStarts() { + return new OffsetPair(this.seq1Range.start, this.seq2Range.start); + } + getEndExclusives() { + return new OffsetPair(this.seq1Range.endExclusive, this.seq2Range.endExclusive); + } +} +class OffsetPair { + constructor(offset1, offset2) { + this.offset1 = offset1; + this.offset2 = offset2; + } + static { + this.zero = new OffsetPair(0, 0); + } + static { + this.max = new OffsetPair(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); + } + delta(offset) { + if (offset === 0) { + return this; + } + return new OffsetPair(this.offset1 + offset, this.offset2 + offset); + } + equals(other) { + return this.offset1 === other.offset1 && this.offset2 === other.offset2; + } +} +class InfiniteTimeout { + static { + this.instance = new InfiniteTimeout(); + } + isValid() { + return true; + } +} +class DateTimeout { + constructor(timeout) { + this.timeout = timeout; + this.startTime = Date.now(); + this.valid = true; + if (timeout <= 0) { + throw new BugIndicatingError("timeout must be positive"); + } + } + // Recommendation: Set a log-point `{this.disable()}` in the body + isValid() { + const valid = Date.now() - this.startTime < this.timeout; + if (!valid && this.valid) { + this.valid = false; + } + return this.valid; + } + disable() { + this.timeout = Number.MAX_SAFE_INTEGER; + this.isValid = () => true; + this.valid = true; + } +} + +class Array2D { + constructor(width, height) { + this.width = width; + this.height = height; + this.array = []; + this.array = new Array(width * height); + } + get(x, y) { + return this.array[x + y * this.width]; + } + set(x, y, value) { + this.array[x + y * this.width] = value; + } +} +function isSpace(charCode) { + return charCode === 32 || charCode === 9; +} +class LineRangeFragment { + constructor(range, lines, source) { + this.range = range; + this.lines = lines; + this.source = source; + this.histogram = []; + let counter = 0; + for (let i = range.startLineNumber - 1; i < range.endLineNumberExclusive - 1; i++) { + const line = lines[i]; + for (let j = 0; j < line.length; j++) { + counter++; + const chr = line[j]; + const key2 = LineRangeFragment.getKey(chr); + this.histogram[key2] = (this.histogram[key2] || 0) + 1; + } + counter++; + const key = LineRangeFragment.getKey("\n"); + this.histogram[key] = (this.histogram[key] || 0) + 1; + } + this.totalCount = counter; + } + static { + this.chrKeys = /* @__PURE__ */ new Map(); + } + static getKey(chr) { + let key = this.chrKeys.get(chr); + if (key === undefined) { + key = this.chrKeys.size; + this.chrKeys.set(chr, key); + } + return key; + } + computeSimilarity(other) { + let sumDifferences = 0; + const maxLength = Math.max(this.histogram.length, other.histogram.length); + for (let i = 0; i < maxLength; i++) { + sumDifferences += Math.abs((this.histogram[i] ?? 0) - (other.histogram[i] ?? 0)); + } + return 1 - sumDifferences / (this.totalCount + other.totalCount); + } +} + +class DynamicProgrammingDiffing { + compute(sequence1, sequence2, timeout = InfiniteTimeout.instance, equalityScore) { + if (sequence1.length === 0 || sequence2.length === 0) { + return DiffAlgorithmResult.trivial(sequence1, sequence2); + } + const lcsLengths = new Array2D(sequence1.length, sequence2.length); + const directions = new Array2D(sequence1.length, sequence2.length); + const lengths = new Array2D(sequence1.length, sequence2.length); + for (let s12 = 0; s12 < sequence1.length; s12++) { + for (let s22 = 0; s22 < sequence2.length; s22++) { + if (!timeout.isValid()) { + return DiffAlgorithmResult.trivialTimedOut(sequence1, sequence2); + } + const horizontalLen = s12 === 0 ? 0 : lcsLengths.get(s12 - 1, s22); + const verticalLen = s22 === 0 ? 0 : lcsLengths.get(s12, s22 - 1); + let extendedSeqScore; + if (sequence1.getElement(s12) === sequence2.getElement(s22)) { + if (s12 === 0 || s22 === 0) { + extendedSeqScore = 0; + } else { + extendedSeqScore = lcsLengths.get(s12 - 1, s22 - 1); + } + if (s12 > 0 && s22 > 0 && directions.get(s12 - 1, s22 - 1) === 3) { + extendedSeqScore += lengths.get(s12 - 1, s22 - 1); + } + extendedSeqScore += equalityScore ? equalityScore(s12, s22) : 1; + } else { + extendedSeqScore = -1; + } + const newValue = Math.max(horizontalLen, verticalLen, extendedSeqScore); + if (newValue === extendedSeqScore) { + const prevLen = s12 > 0 && s22 > 0 ? lengths.get(s12 - 1, s22 - 1) : 0; + lengths.set(s12, s22, prevLen + 1); + directions.set(s12, s22, 3); + } else if (newValue === horizontalLen) { + lengths.set(s12, s22, 0); + directions.set(s12, s22, 1); + } else if (newValue === verticalLen) { + lengths.set(s12, s22, 0); + directions.set(s12, s22, 2); + } + lcsLengths.set(s12, s22, newValue); + } + } + const result = []; + let lastAligningPosS1 = sequence1.length; + let lastAligningPosS2 = sequence2.length; + function reportDecreasingAligningPositions(s12, s22) { + if (s12 + 1 !== lastAligningPosS1 || s22 + 1 !== lastAligningPosS2) { + result.push(new SequenceDiff( + new OffsetRange(s12 + 1, lastAligningPosS1), + new OffsetRange(s22 + 1, lastAligningPosS2) + )); + } + lastAligningPosS1 = s12; + lastAligningPosS2 = s22; + } + let s1 = sequence1.length - 1; + let s2 = sequence2.length - 1; + while (s1 >= 0 && s2 >= 0) { + if (directions.get(s1, s2) === 3) { + reportDecreasingAligningPositions(s1, s2); + s1--; + s2--; + } else { + if (directions.get(s1, s2) === 1) { + s1--; + } else { + s2--; + } + } + } + reportDecreasingAligningPositions(-1, -1); + result.reverse(); + return new DiffAlgorithmResult(result, false); + } +} + +class MyersDiffAlgorithm { + compute(seq1, seq2, timeout = InfiniteTimeout.instance) { + if (seq1.length === 0 || seq2.length === 0) { + return DiffAlgorithmResult.trivial(seq1, seq2); + } + const seqX = seq1; + const seqY = seq2; + function getXAfterSnake(x, y) { + while (x < seqX.length && y < seqY.length && seqX.getElement(x) === seqY.getElement(y)) { + x++; + y++; + } + return x; + } + let d = 0; + const V = new FastInt32Array(); + V.set(0, getXAfterSnake(0, 0)); + const paths = new FastArrayNegativeIndices(); + paths.set(0, V.get(0) === 0 ? null : new SnakePath(null, 0, 0, V.get(0))); + let k = 0; + loop: while (true) { + d++; + if (!timeout.isValid()) { + return DiffAlgorithmResult.trivialTimedOut(seqX, seqY); + } + const lowerBound = -Math.min(d, seqY.length + d % 2); + const upperBound = Math.min(d, seqX.length + d % 2); + for (k = lowerBound; k <= upperBound; k += 2) { + const maxXofDLineTop = k === upperBound ? -1 : V.get(k + 1); + const maxXofDLineLeft = k === lowerBound ? -1 : V.get(k - 1) + 1; + const x = Math.min(Math.max(maxXofDLineTop, maxXofDLineLeft), seqX.length); + const y = x - k; + if (x > seqX.length || y > seqY.length) { + continue; + } + const newMaxX = getXAfterSnake(x, y); + V.set(k, newMaxX); + const lastPath = x === maxXofDLineTop ? paths.get(k + 1) : paths.get(k - 1); + paths.set(k, newMaxX !== x ? new SnakePath(lastPath, x, y, newMaxX - x) : lastPath); + if (V.get(k) === seqX.length && V.get(k) - k === seqY.length) { + break loop; + } + } + } + let path = paths.get(k); + const result = []; + let lastAligningPosS1 = seqX.length; + let lastAligningPosS2 = seqY.length; + while (true) { + const endX = path ? path.x + path.length : 0; + const endY = path ? path.y + path.length : 0; + if (endX !== lastAligningPosS1 || endY !== lastAligningPosS2) { + result.push(new SequenceDiff( + new OffsetRange(endX, lastAligningPosS1), + new OffsetRange(endY, lastAligningPosS2) + )); + } + if (!path) { + break; + } + lastAligningPosS1 = path.x; + lastAligningPosS2 = path.y; + path = path.prev; + } + result.reverse(); + return new DiffAlgorithmResult(result, false); + } +} +class SnakePath { + constructor(prev, x, y, length) { + this.prev = prev; + this.x = x; + this.y = y; + this.length = length; + } +} +class FastInt32Array { + constructor() { + this.positiveArr = new Int32Array(10); + this.negativeArr = new Int32Array(10); + } + get(idx) { + if (idx < 0) { + idx = -idx - 1; + return this.negativeArr[idx]; + } else { + return this.positiveArr[idx]; + } + } + set(idx, value) { + if (idx < 0) { + idx = -idx - 1; + if (idx >= this.negativeArr.length) { + const arr = this.negativeArr; + this.negativeArr = new Int32Array(arr.length * 2); + this.negativeArr.set(arr); + } + this.negativeArr[idx] = value; + } else { + if (idx >= this.positiveArr.length) { + const arr = this.positiveArr; + this.positiveArr = new Int32Array(arr.length * 2); + this.positiveArr.set(arr); + } + this.positiveArr[idx] = value; + } + } +} +class FastArrayNegativeIndices { + constructor() { + this.positiveArr = []; + this.negativeArr = []; + } + get(idx) { + if (idx < 0) { + idx = -idx - 1; + return this.negativeArr[idx]; + } else { + return this.positiveArr[idx]; + } + } + set(idx, value) { + if (idx < 0) { + idx = -idx - 1; + this.negativeArr[idx] = value; + } else { + this.positiveArr[idx] = value; + } + } +} + +class SetMap { + constructor() { + this.map = /* @__PURE__ */ new Map(); + } + add(key, value) { + let values = this.map.get(key); + if (!values) { + values = /* @__PURE__ */ new Set(); + this.map.set(key, values); + } + values.add(value); + } + forEach(key, fn) { + const values = this.map.get(key); + if (!values) { + return; + } + values.forEach(fn); + } + get(key) { + const values = this.map.get(key); + if (!values) { + return /* @__PURE__ */ new Set(); + } + return values; + } +} + +class LinesSliceCharSequence { + constructor(lines, range, considerWhitespaceChanges) { + this.lines = lines; + this.range = range; + this.considerWhitespaceChanges = considerWhitespaceChanges; + this.elements = []; + this.firstElementOffsetByLineIdx = []; + this.lineStartOffsets = []; + this.trimmedWsLengthsByLineIdx = []; + this.firstElementOffsetByLineIdx.push(0); + for (let lineNumber = this.range.startLineNumber; lineNumber <= this.range.endLineNumber; lineNumber++) { + let line = lines[lineNumber - 1]; + let lineStartOffset = 0; + if (lineNumber === this.range.startLineNumber && this.range.startColumn > 1) { + lineStartOffset = this.range.startColumn - 1; + line = line.substring(lineStartOffset); + } + this.lineStartOffsets.push(lineStartOffset); + let trimmedWsLength = 0; + if (!considerWhitespaceChanges) { + const trimmedStartLine = line.trimStart(); + trimmedWsLength = line.length - trimmedStartLine.length; + line = trimmedStartLine.trimEnd(); + } + this.trimmedWsLengthsByLineIdx.push(trimmedWsLength); + const lineLength = lineNumber === this.range.endLineNumber ? Math.min(this.range.endColumn - 1 - lineStartOffset - trimmedWsLength, line.length) : line.length; + for (let i = 0; i < lineLength; i++) { + this.elements.push(line.charCodeAt(i)); + } + if (lineNumber < this.range.endLineNumber) { + this.elements.push("\n".charCodeAt(0)); + this.firstElementOffsetByLineIdx.push(this.elements.length); + } + } + } + toString() { + return `Slice: "${this.text}"`; + } + get text() { + return this.getText(new OffsetRange(0, this.length)); + } + getText(range) { + return this.elements.slice(range.start, range.endExclusive).map((e) => String.fromCharCode(e)).join(""); + } + getElement(offset) { + return this.elements[offset]; + } + get length() { + return this.elements.length; + } + getBoundaryScore(length) { + const prevCategory = getCategory(length > 0 ? this.elements[length - 1] : -1); + const nextCategory = getCategory(length < this.elements.length ? this.elements[length] : -1); + if (prevCategory === 7 /* LineBreakCR */ && nextCategory === 8 /* LineBreakLF */) { + return 0; + } + if (prevCategory === 8 /* LineBreakLF */) { + return 150; + } + let score2 = 0; + if (prevCategory !== nextCategory) { + score2 += 10; + if (prevCategory === 0 /* WordLower */ && nextCategory === 1 /* WordUpper */) { + score2 += 1; + } + } + score2 += getCategoryBoundaryScore(prevCategory); + score2 += getCategoryBoundaryScore(nextCategory); + return score2; + } + translateOffset(offset, preference = "right") { + const i = findLastIdxMonotonous(this.firstElementOffsetByLineIdx, (value) => value <= offset); + const lineOffset = offset - this.firstElementOffsetByLineIdx[i]; + return new Position( + this.range.startLineNumber + i, + 1 + this.lineStartOffsets[i] + lineOffset + (lineOffset === 0 && preference === "left" ? 0 : this.trimmedWsLengthsByLineIdx[i]) + ); + } + translateRange(range) { + const pos1 = this.translateOffset(range.start, "right"); + const pos2 = this.translateOffset(range.endExclusive, "left"); + if (pos2.isBefore(pos1)) { + return Range.fromPositions(pos2, pos2); + } + return Range.fromPositions(pos1, pos2); + } + /** + * Finds the word that contains the character at the given offset + */ + findWordContaining(offset) { + if (offset < 0 || offset >= this.elements.length) { + return undefined; + } + if (!isWordChar(this.elements[offset])) { + return undefined; + } + let start = offset; + while (start > 0 && isWordChar(this.elements[start - 1])) { + start--; + } + let end = offset; + while (end < this.elements.length && isWordChar(this.elements[end])) { + end++; + } + return new OffsetRange(start, end); + } + /** fooBar has the two sub-words foo and bar */ + findSubWordContaining(offset) { + if (offset < 0 || offset >= this.elements.length) { + return undefined; + } + if (!isWordChar(this.elements[offset])) { + return undefined; + } + let start = offset; + while (start > 0 && isWordChar(this.elements[start - 1]) && !isUpperCase(this.elements[start])) { + start--; + } + let end = offset; + while (end < this.elements.length && isWordChar(this.elements[end]) && !isUpperCase(this.elements[end])) { + end++; + } + return new OffsetRange(start, end); + } + countLinesIn(range) { + return this.translateOffset(range.endExclusive).lineNumber - this.translateOffset(range.start).lineNumber; + } + isStronglyEqual(offset1, offset2) { + return this.elements[offset1] === this.elements[offset2]; + } + extendToFullLines(range) { + const start = findLastMonotonous(this.firstElementOffsetByLineIdx, (x) => x <= range.start) ?? 0; + const end = findFirstMonotonous(this.firstElementOffsetByLineIdx, (x) => range.endExclusive <= x) ?? this.elements.length; + return new OffsetRange(start, end); + } +} +function isWordChar(charCode) { + return charCode >= 97 && charCode <= 122 || charCode >= 65 && charCode <= 90 || charCode >= 48 && charCode <= 57; +} +function isUpperCase(charCode) { + return charCode >= 65 && charCode <= 90; +} +const score = { + [0 /* WordLower */]: 0, + [1 /* WordUpper */]: 0, + [2 /* WordNumber */]: 0, + [3 /* End */]: 10, + [4 /* Other */]: 2, + [5 /* Separator */]: 30, + [6 /* Space */]: 3, + [7 /* LineBreakCR */]: 10, + [8 /* LineBreakLF */]: 10 +}; +function getCategoryBoundaryScore(category) { + return score[category]; +} +function getCategory(charCode) { + if (charCode === 10) { + return 8 /* LineBreakLF */; + } else if (charCode === 13) { + return 7 /* LineBreakCR */; + } else if (isSpace(charCode)) { + return 6 /* Space */; + } else if (charCode >= 97 && charCode <= 122) { + return 0 /* WordLower */; + } else if (charCode >= 65 && charCode <= 90) { + return 1 /* WordUpper */; + } else if (charCode >= 48 && charCode <= 57) { + return 2 /* WordNumber */; + } else if (charCode === -1) { + return 3 /* End */; + } else if (charCode === 44 || charCode === 59) { + return 5 /* Separator */; + } else { + return 4 /* Other */; + } +} + +function computeMovedLines(changes, originalLines, modifiedLines, hashedOriginalLines, hashedModifiedLines, timeout) { + let { moves, excludedChanges } = computeMovesFromSimpleDeletionsToSimpleInsertions(changes, originalLines, modifiedLines, timeout); + if (!timeout.isValid()) { + return []; + } + const filteredChanges = changes.filter((c) => !excludedChanges.has(c)); + const unchangedMoves = computeUnchangedMoves(filteredChanges, hashedOriginalLines, hashedModifiedLines, originalLines, modifiedLines, timeout); + pushMany(moves, unchangedMoves); + moves = joinCloseConsecutiveMoves(moves); + moves = moves.filter((current) => { + const lines = current.original.toOffsetRange().slice(originalLines).map((l) => l.trim()); + const originalText = lines.join("\n"); + return originalText.length >= 15 && countWhere(lines, (l) => l.length >= 2) >= 2; + }); + moves = removeMovesInSameDiff(changes, moves); + return moves; +} +function countWhere(arr, predicate) { + let count = 0; + for (const t of arr) { + if (predicate(t)) { + count++; + } + } + return count; +} +function computeMovesFromSimpleDeletionsToSimpleInsertions(changes, originalLines, modifiedLines, timeout) { + const moves = []; + const deletions = changes.filter((c) => c.modified.isEmpty && c.original.length >= 3).map((d) => new LineRangeFragment(d.original, originalLines, d)); + const insertions = new Set(changes.filter((c) => c.original.isEmpty && c.modified.length >= 3).map((d) => new LineRangeFragment(d.modified, modifiedLines, d))); + const excludedChanges = /* @__PURE__ */ new Set(); + for (const deletion of deletions) { + let highestSimilarity = -1; + let best; + for (const insertion of insertions) { + const similarity = deletion.computeSimilarity(insertion); + if (similarity > highestSimilarity) { + highestSimilarity = similarity; + best = insertion; + } + } + if (highestSimilarity > 0.9 && best) { + insertions.delete(best); + moves.push(new LineRangeMapping(deletion.range, best.range)); + excludedChanges.add(deletion.source); + excludedChanges.add(best.source); + } + if (!timeout.isValid()) { + return { moves, excludedChanges }; + } + } + return { moves, excludedChanges }; +} +function computeUnchangedMoves(changes, hashedOriginalLines, hashedModifiedLines, originalLines, modifiedLines, timeout) { + const moves = []; + const original3LineHashes = new SetMap(); + for (const change of changes) { + for (let i = change.original.startLineNumber; i < change.original.endLineNumberExclusive - 2; i++) { + const key = `${hashedOriginalLines[i - 1]}:${hashedOriginalLines[i + 1 - 1]}:${hashedOriginalLines[i + 2 - 1]}`; + original3LineHashes.add(key, { range: new LineRange(i, i + 3) }); + } + } + const possibleMappings = []; + changes.sort(compareBy((c) => c.modified.startLineNumber, numberComparator)); + for (const change of changes) { + let lastMappings = []; + for (let i = change.modified.startLineNumber; i < change.modified.endLineNumberExclusive - 2; i++) { + const key = `${hashedModifiedLines[i - 1]}:${hashedModifiedLines[i + 1 - 1]}:${hashedModifiedLines[i + 2 - 1]}`; + const currentModifiedRange = new LineRange(i, i + 3); + const nextMappings = []; + original3LineHashes.forEach(key, ({ range }) => { + for (const lastMapping of lastMappings) { + if (lastMapping.originalLineRange.endLineNumberExclusive + 1 === range.endLineNumberExclusive && lastMapping.modifiedLineRange.endLineNumberExclusive + 1 === currentModifiedRange.endLineNumberExclusive) { + lastMapping.originalLineRange = new LineRange(lastMapping.originalLineRange.startLineNumber, range.endLineNumberExclusive); + lastMapping.modifiedLineRange = new LineRange(lastMapping.modifiedLineRange.startLineNumber, currentModifiedRange.endLineNumberExclusive); + nextMappings.push(lastMapping); + return; + } + } + const mapping = { + modifiedLineRange: currentModifiedRange, + originalLineRange: range + }; + possibleMappings.push(mapping); + nextMappings.push(mapping); + }); + lastMappings = nextMappings; + } + if (!timeout.isValid()) { + return []; + } + } + possibleMappings.sort(reverseOrder(compareBy((m) => m.modifiedLineRange.length, numberComparator))); + const modifiedSet = new LineRangeSet(); + const originalSet = new LineRangeSet(); + for (const mapping of possibleMappings) { + const diffOrigToMod = mapping.modifiedLineRange.startLineNumber - mapping.originalLineRange.startLineNumber; + const modifiedSections = modifiedSet.subtractFrom(mapping.modifiedLineRange); + const originalTranslatedSections = originalSet.subtractFrom(mapping.originalLineRange).getWithDelta(diffOrigToMod); + const modifiedIntersectedSections = modifiedSections.getIntersection(originalTranslatedSections); + for (const s of modifiedIntersectedSections.ranges) { + if (s.length < 3) { + continue; + } + const modifiedLineRange = s; + const originalLineRange = s.delta(-diffOrigToMod); + moves.push(new LineRangeMapping(originalLineRange, modifiedLineRange)); + modifiedSet.addRange(modifiedLineRange); + originalSet.addRange(originalLineRange); + } + } + moves.sort(compareBy((m) => m.original.startLineNumber, numberComparator)); + const monotonousChanges = new MonotonousArray(changes); + for (let i = 0; i < moves.length; i++) { + const move = moves[i]; + const firstTouchingChangeOrig = monotonousChanges.findLastMonotonous((c) => c.original.startLineNumber <= move.original.startLineNumber); + const firstTouchingChangeMod = findLastMonotonous(changes, (c) => c.modified.startLineNumber <= move.modified.startLineNumber); + const linesAbove = Math.max( + move.original.startLineNumber - firstTouchingChangeOrig.original.startLineNumber, + move.modified.startLineNumber - firstTouchingChangeMod.modified.startLineNumber + ); + const lastTouchingChangeOrig = monotonousChanges.findLastMonotonous((c) => c.original.startLineNumber < move.original.endLineNumberExclusive); + const lastTouchingChangeMod = findLastMonotonous(changes, (c) => c.modified.startLineNumber < move.modified.endLineNumberExclusive); + const linesBelow = Math.max( + lastTouchingChangeOrig.original.endLineNumberExclusive - move.original.endLineNumberExclusive, + lastTouchingChangeMod.modified.endLineNumberExclusive - move.modified.endLineNumberExclusive + ); + let extendToTop; + for (extendToTop = 0; extendToTop < linesAbove; extendToTop++) { + const origLine = move.original.startLineNumber - extendToTop - 1; + const modLine = move.modified.startLineNumber - extendToTop - 1; + if (origLine > originalLines.length || modLine > modifiedLines.length) { + break; + } + if (modifiedSet.contains(modLine) || originalSet.contains(origLine)) { + break; + } + if (!areLinesSimilar(originalLines[origLine - 1], modifiedLines[modLine - 1], timeout)) { + break; + } + } + if (extendToTop > 0) { + originalSet.addRange(new LineRange(move.original.startLineNumber - extendToTop, move.original.startLineNumber)); + modifiedSet.addRange(new LineRange(move.modified.startLineNumber - extendToTop, move.modified.startLineNumber)); + } + let extendToBottom; + for (extendToBottom = 0; extendToBottom < linesBelow; extendToBottom++) { + const origLine = move.original.endLineNumberExclusive + extendToBottom; + const modLine = move.modified.endLineNumberExclusive + extendToBottom; + if (origLine > originalLines.length || modLine > modifiedLines.length) { + break; + } + if (modifiedSet.contains(modLine) || originalSet.contains(origLine)) { + break; + } + if (!areLinesSimilar(originalLines[origLine - 1], modifiedLines[modLine - 1], timeout)) { + break; + } + } + if (extendToBottom > 0) { + originalSet.addRange(new LineRange(move.original.endLineNumberExclusive, move.original.endLineNumberExclusive + extendToBottom)); + modifiedSet.addRange(new LineRange(move.modified.endLineNumberExclusive, move.modified.endLineNumberExclusive + extendToBottom)); + } + if (extendToTop > 0 || extendToBottom > 0) { + moves[i] = new LineRangeMapping( + new LineRange(move.original.startLineNumber - extendToTop, move.original.endLineNumberExclusive + extendToBottom), + new LineRange(move.modified.startLineNumber - extendToTop, move.modified.endLineNumberExclusive + extendToBottom) + ); + } + } + return moves; +} +function areLinesSimilar(line1, line2, timeout) { + if (line1.trim() === line2.trim()) { + return true; + } + if (line1.length > 300 && line2.length > 300) { + return false; + } + const myersDiffingAlgorithm = new MyersDiffAlgorithm(); + const result = myersDiffingAlgorithm.compute( + new LinesSliceCharSequence([line1], new Range(1, 1, 1, line1.length), false), + new LinesSliceCharSequence([line2], new Range(1, 1, 1, line2.length), false), + timeout + ); + let commonNonSpaceCharCount = 0; + const inverted = SequenceDiff.invert(result.diffs, line1.length); + for (const seq of inverted) { + seq.seq1Range.forEach((idx) => { + if (!isSpace(line1.charCodeAt(idx))) { + commonNonSpaceCharCount++; + } + }); + } + function countNonWsChars(str) { + let count = 0; + for (let i = 0; i < line1.length; i++) { + if (!isSpace(str.charCodeAt(i))) { + count++; + } + } + return count; + } + const longerLineLength = countNonWsChars(line1.length > line2.length ? line1 : line2); + const r = commonNonSpaceCharCount / longerLineLength > 0.6 && longerLineLength > 10; + return r; +} +function joinCloseConsecutiveMoves(moves) { + if (moves.length === 0) { + return moves; + } + moves.sort(compareBy((m) => m.original.startLineNumber, numberComparator)); + const result = [moves[0]]; + for (let i = 1; i < moves.length; i++) { + const last = result[result.length - 1]; + const current = moves[i]; + const originalDist = current.original.startLineNumber - last.original.endLineNumberExclusive; + const modifiedDist = current.modified.startLineNumber - last.modified.endLineNumberExclusive; + const currentMoveAfterLast = originalDist >= 0 && modifiedDist >= 0; + if (currentMoveAfterLast && originalDist + modifiedDist <= 2) { + result[result.length - 1] = last.join(current); + continue; + } + result.push(current); + } + return result; +} +function removeMovesInSameDiff(changes, moves) { + const changesMonotonous = new MonotonousArray(changes); + moves = moves.filter((m) => { + const diffBeforeEndOfMoveOriginal = changesMonotonous.findLastMonotonous((c) => c.original.startLineNumber < m.original.endLineNumberExclusive) || new LineRangeMapping(new LineRange(1, 1), new LineRange(1, 1)); + const diffBeforeEndOfMoveModified = findLastMonotonous(changes, (c) => c.modified.startLineNumber < m.modified.endLineNumberExclusive); + const differentDiffs = diffBeforeEndOfMoveOriginal !== diffBeforeEndOfMoveModified; + return differentDiffs; + }); + return moves; +} + +function optimizeSequenceDiffs(sequence1, sequence2, sequenceDiffs) { + let result = sequenceDiffs; + result = joinSequenceDiffsByShifting(sequence1, sequence2, result); + result = joinSequenceDiffsByShifting(sequence1, sequence2, result); + result = shiftSequenceDiffs(sequence1, sequence2, result); + return result; +} +function joinSequenceDiffsByShifting(sequence1, sequence2, sequenceDiffs) { + if (sequenceDiffs.length === 0) { + return sequenceDiffs; + } + const result = []; + result.push(sequenceDiffs[0]); + for (let i = 1; i < sequenceDiffs.length; i++) { + const prevResult = result[result.length - 1]; + let cur = sequenceDiffs[i]; + if (cur.seq1Range.isEmpty || cur.seq2Range.isEmpty) { + const length = cur.seq1Range.start - prevResult.seq1Range.endExclusive; + let d; + for (d = 1; d <= length; d++) { + if (sequence1.getElement(cur.seq1Range.start - d) !== sequence1.getElement(cur.seq1Range.endExclusive - d) || sequence2.getElement(cur.seq2Range.start - d) !== sequence2.getElement(cur.seq2Range.endExclusive - d)) { + break; + } + } + d--; + if (d === length) { + result[result.length - 1] = new SequenceDiff( + new OffsetRange(prevResult.seq1Range.start, cur.seq1Range.endExclusive - length), + new OffsetRange(prevResult.seq2Range.start, cur.seq2Range.endExclusive - length) + ); + continue; + } + cur = cur.delta(-d); + } + result.push(cur); + } + const result2 = []; + for (let i = 0; i < result.length - 1; i++) { + const nextResult = result[i + 1]; + let cur = result[i]; + if (cur.seq1Range.isEmpty || cur.seq2Range.isEmpty) { + const length = nextResult.seq1Range.start - cur.seq1Range.endExclusive; + let d; + for (d = 0; d < length; d++) { + if (!sequence1.isStronglyEqual(cur.seq1Range.start + d, cur.seq1Range.endExclusive + d) || !sequence2.isStronglyEqual(cur.seq2Range.start + d, cur.seq2Range.endExclusive + d)) { + break; + } + } + if (d === length) { + result[i + 1] = new SequenceDiff( + new OffsetRange(cur.seq1Range.start + length, nextResult.seq1Range.endExclusive), + new OffsetRange(cur.seq2Range.start + length, nextResult.seq2Range.endExclusive) + ); + continue; + } + if (d > 0) { + cur = cur.delta(d); + } + } + result2.push(cur); + } + if (result.length > 0) { + result2.push(result[result.length - 1]); + } + return result2; +} +function shiftSequenceDiffs(sequence1, sequence2, sequenceDiffs) { + if (!sequence1.getBoundaryScore || !sequence2.getBoundaryScore) { + return sequenceDiffs; + } + for (let i = 0; i < sequenceDiffs.length; i++) { + const prevDiff = i > 0 ? sequenceDiffs[i - 1] : undefined; + const diff = sequenceDiffs[i]; + const nextDiff = i + 1 < sequenceDiffs.length ? sequenceDiffs[i + 1] : undefined; + const seq1ValidRange = new OffsetRange(prevDiff ? prevDiff.seq1Range.endExclusive + 1 : 0, nextDiff ? nextDiff.seq1Range.start - 1 : sequence1.length); + const seq2ValidRange = new OffsetRange(prevDiff ? prevDiff.seq2Range.endExclusive + 1 : 0, nextDiff ? nextDiff.seq2Range.start - 1 : sequence2.length); + if (diff.seq1Range.isEmpty) { + sequenceDiffs[i] = shiftDiffToBetterPosition(diff, sequence1, sequence2, seq1ValidRange, seq2ValidRange); + } else if (diff.seq2Range.isEmpty) { + sequenceDiffs[i] = shiftDiffToBetterPosition(diff.swap(), sequence2, sequence1, seq2ValidRange, seq1ValidRange).swap(); + } + } + return sequenceDiffs; +} +function shiftDiffToBetterPosition(diff, sequence1, sequence2, seq1ValidRange, seq2ValidRange) { + const maxShiftLimit = 100; + let deltaBefore = 1; + while (diff.seq1Range.start - deltaBefore >= seq1ValidRange.start && diff.seq2Range.start - deltaBefore >= seq2ValidRange.start && sequence2.isStronglyEqual(diff.seq2Range.start - deltaBefore, diff.seq2Range.endExclusive - deltaBefore) && deltaBefore < maxShiftLimit) { + deltaBefore++; + } + deltaBefore--; + let deltaAfter = 0; + while (diff.seq1Range.start + deltaAfter < seq1ValidRange.endExclusive && diff.seq2Range.endExclusive + deltaAfter < seq2ValidRange.endExclusive && sequence2.isStronglyEqual(diff.seq2Range.start + deltaAfter, diff.seq2Range.endExclusive + deltaAfter) && deltaAfter < maxShiftLimit) { + deltaAfter++; + } + if (deltaBefore === 0 && deltaAfter === 0) { + return diff; + } + let bestDelta = 0; + let bestScore = -1; + for (let delta = -deltaBefore; delta <= deltaAfter; delta++) { + const seq2OffsetStart = diff.seq2Range.start + delta; + const seq2OffsetEndExclusive = diff.seq2Range.endExclusive + delta; + const seq1Offset = diff.seq1Range.start + delta; + const score = sequence1.getBoundaryScore(seq1Offset) + sequence2.getBoundaryScore(seq2OffsetStart) + sequence2.getBoundaryScore(seq2OffsetEndExclusive); + if (score > bestScore) { + bestScore = score; + bestDelta = delta; + } + } + return diff.delta(bestDelta); +} +function removeShortMatches(sequence1, sequence2, sequenceDiffs) { + const result = []; + for (const s of sequenceDiffs) { + const last = result[result.length - 1]; + if (!last) { + result.push(s); + continue; + } + if (s.seq1Range.start - last.seq1Range.endExclusive <= 2 || s.seq2Range.start - last.seq2Range.endExclusive <= 2) { + result[result.length - 1] = new SequenceDiff(last.seq1Range.join(s.seq1Range), last.seq2Range.join(s.seq2Range)); + } else { + result.push(s); + } + } + return result; +} +function extendDiffsToEntireWordIfAppropriate(sequence1, sequence2, sequenceDiffs, findParent, force = false) { + const equalMappings = SequenceDiff.invert(sequenceDiffs, sequence1.length); + const additional = []; + let lastPoint = new OffsetPair(0, 0); + function scanWord(pair, equalMapping) { + if (pair.offset1 < lastPoint.offset1 || pair.offset2 < lastPoint.offset2) { + return; + } + const w1 = findParent(sequence1, pair.offset1); + const w2 = findParent(sequence2, pair.offset2); + if (!w1 || !w2) { + return; + } + let w = new SequenceDiff(w1, w2); + const equalPart = w.intersect(equalMapping); + let equalChars1 = equalPart.seq1Range.length; + let equalChars2 = equalPart.seq2Range.length; + while (equalMappings.length > 0) { + const next = equalMappings[0]; + const intersects = next.seq1Range.intersects(w.seq1Range) || next.seq2Range.intersects(w.seq2Range); + if (!intersects) { + break; + } + const v1 = findParent(sequence1, next.seq1Range.start); + const v2 = findParent(sequence2, next.seq2Range.start); + const v = new SequenceDiff(v1, v2); + const equalPart2 = v.intersect(next); + equalChars1 += equalPart2.seq1Range.length; + equalChars2 += equalPart2.seq2Range.length; + w = w.join(v); + if (w.seq1Range.endExclusive >= next.seq1Range.endExclusive) { + equalMappings.shift(); + } else { + break; + } + } + if (force && equalChars1 + equalChars2 < w.seq1Range.length + w.seq2Range.length || equalChars1 + equalChars2 < (w.seq1Range.length + w.seq2Range.length) * 2 / 3) { + additional.push(w); + } + lastPoint = w.getEndExclusives(); + } + while (equalMappings.length > 0) { + const next = equalMappings.shift(); + if (next.seq1Range.isEmpty) { + continue; + } + scanWord(next.getStarts(), next); + scanWord(next.getEndExclusives().delta(-1), next); + } + const merged = mergeSequenceDiffs(sequenceDiffs, additional); + return merged; +} +function mergeSequenceDiffs(sequenceDiffs1, sequenceDiffs2) { + const result = []; + while (sequenceDiffs1.length > 0 || sequenceDiffs2.length > 0) { + const sd1 = sequenceDiffs1[0]; + const sd2 = sequenceDiffs2[0]; + let next; + if (sd1 && (!sd2 || sd1.seq1Range.start < sd2.seq1Range.start)) { + next = sequenceDiffs1.shift(); + } else { + next = sequenceDiffs2.shift(); + } + if (result.length > 0 && result[result.length - 1].seq1Range.endExclusive >= next.seq1Range.start) { + result[result.length - 1] = result[result.length - 1].join(next); + } else { + result.push(next); + } + } + return result; +} +function removeVeryShortMatchingLinesBetweenDiffs(sequence1, _sequence2, sequenceDiffs) { + let diffs = sequenceDiffs; + if (diffs.length === 0) { + return diffs; + } + let counter = 0; + let shouldRepeat; + do { + shouldRepeat = false; + const result = [ + diffs[0] + ]; + for (let i = 1; i < diffs.length; i++) { + let shouldJoinDiffs = function(before, after) { + const unchangedRange = new OffsetRange(lastResult.seq1Range.endExclusive, cur.seq1Range.start); + const unchangedText = sequence1.getText(unchangedRange); + const unchangedTextWithoutWs = unchangedText.replace(/\s/g, ""); + if (unchangedTextWithoutWs.length <= 4 && (before.seq1Range.length + before.seq2Range.length > 5 || after.seq1Range.length + after.seq2Range.length > 5)) { + return true; + } + return false; + }; + const cur = diffs[i]; + const lastResult = result[result.length - 1]; + const shouldJoin = shouldJoinDiffs(lastResult, cur); + if (shouldJoin) { + shouldRepeat = true; + result[result.length - 1] = result[result.length - 1].join(cur); + } else { + result.push(cur); + } + } + diffs = result; + } while (counter++ < 10 && shouldRepeat); + return diffs; +} +function removeVeryShortMatchingTextBetweenLongDiffs(sequence1, sequence2, sequenceDiffs) { + let diffs = sequenceDiffs; + if (diffs.length === 0) { + return diffs; + } + let counter = 0; + let shouldRepeat; + do { + shouldRepeat = false; + const result = [ + diffs[0] + ]; + for (let i = 1; i < diffs.length; i++) { + let shouldJoinDiffs = function(before, after) { + const unchangedRange = new OffsetRange(lastResult.seq1Range.endExclusive, cur.seq1Range.start); + const unchangedLineCount = sequence1.countLinesIn(unchangedRange); + if (unchangedLineCount > 5 || unchangedRange.length > 500) { + return false; + } + const unchangedText = sequence1.getText(unchangedRange).trim(); + if (unchangedText.length > 20 || unchangedText.split(/\r\n|\r|\n/).length > 1) { + return false; + } + const beforeLineCount1 = sequence1.countLinesIn(before.seq1Range); + const beforeSeq1Length = before.seq1Range.length; + const beforeLineCount2 = sequence2.countLinesIn(before.seq2Range); + const beforeSeq2Length = before.seq2Range.length; + const afterLineCount1 = sequence1.countLinesIn(after.seq1Range); + const afterSeq1Length = after.seq1Range.length; + const afterLineCount2 = sequence2.countLinesIn(after.seq2Range); + const afterSeq2Length = after.seq2Range.length; + const max = 2 * 40 + 50; + function cap(v) { + return Math.min(v, max); + } + if (Math.pow(Math.pow(cap(beforeLineCount1 * 40 + beforeSeq1Length), 1.5) + Math.pow(cap(beforeLineCount2 * 40 + beforeSeq2Length), 1.5), 1.5) + Math.pow(Math.pow(cap(afterLineCount1 * 40 + afterSeq1Length), 1.5) + Math.pow(cap(afterLineCount2 * 40 + afterSeq2Length), 1.5), 1.5) > (max ** 1.5) ** 1.5 * 1.3) { + return true; + } + return false; + }; + const cur = diffs[i]; + const lastResult = result[result.length - 1]; + const shouldJoin = shouldJoinDiffs(lastResult, cur); + if (shouldJoin) { + shouldRepeat = true; + result[result.length - 1] = result[result.length - 1].join(cur); + } else { + result.push(cur); + } + } + diffs = result; + } while (counter++ < 10 && shouldRepeat); + const newDiffs = []; + forEachWithNeighbors(diffs, (prev, cur, next) => { + let newDiff = cur; + function shouldMarkAsChanged(text) { + return text.length > 0 && text.trim().length <= 3 && cur.seq1Range.length + cur.seq2Range.length > 100; + } + const fullRange1 = sequence1.extendToFullLines(cur.seq1Range); + const prefix = sequence1.getText(new OffsetRange(fullRange1.start, cur.seq1Range.start)); + if (shouldMarkAsChanged(prefix)) { + newDiff = newDiff.deltaStart(-prefix.length); + } + const suffix = sequence1.getText(new OffsetRange(cur.seq1Range.endExclusive, fullRange1.endExclusive)); + if (shouldMarkAsChanged(suffix)) { + newDiff = newDiff.deltaEnd(suffix.length); + } + const availableSpace = SequenceDiff.fromOffsetPairs( + prev ? prev.getEndExclusives() : OffsetPair.zero, + next ? next.getStarts() : OffsetPair.max + ); + const result = newDiff.intersect(availableSpace); + if (newDiffs.length > 0 && result.getStarts().equals(newDiffs[newDiffs.length - 1].getEndExclusives())) { + newDiffs[newDiffs.length - 1] = newDiffs[newDiffs.length - 1].join(result); + } else { + newDiffs.push(result); + } + }); + return newDiffs; +} + +class LineSequence { + constructor(trimmedHash, lines) { + this.trimmedHash = trimmedHash; + this.lines = lines; + } + getElement(offset) { + return this.trimmedHash[offset]; + } + get length() { + return this.trimmedHash.length; + } + getBoundaryScore(length) { + const indentationBefore = length === 0 ? 0 : getIndentation(this.lines[length - 1]); + const indentationAfter = length === this.lines.length ? 0 : getIndentation(this.lines[length]); + return 1e3 - (indentationBefore + indentationAfter); + } + getText(range) { + return this.lines.slice(range.start, range.endExclusive).join("\n"); + } + isStronglyEqual(offset1, offset2) { + return this.lines[offset1] === this.lines[offset2]; + } +} +function getIndentation(str) { + let i = 0; + while (i < str.length && (str.charCodeAt(i) === 32 || str.charCodeAt(i) === 9)) { + i++; + } + return i; +} + +class DefaultLinesDiffComputer { + constructor() { + this.dynamicProgrammingDiffing = new DynamicProgrammingDiffing(); + this.myersDiffingAlgorithm = new MyersDiffAlgorithm(); + } + computeDiff(originalLines, modifiedLines, options) { + if (originalLines.length <= 1 && equals(originalLines, modifiedLines, (a, b) => a === b)) { + return new LinesDiff([], [], false); + } + if (originalLines.length === 1 && originalLines[0].length === 0 || modifiedLines.length === 1 && modifiedLines[0].length === 0) { + return new LinesDiff([ + new DetailedLineRangeMapping( + new LineRange(1, originalLines.length + 1), + new LineRange(1, modifiedLines.length + 1), + [ + new RangeMapping( + new Range(1, 1, originalLines.length, originalLines[originalLines.length - 1].length + 1), + new Range(1, 1, modifiedLines.length, modifiedLines[modifiedLines.length - 1].length + 1) + ) + ] + ) + ], [], false); + } + const timeout = options.maxComputationTimeMs === 0 ? InfiniteTimeout.instance : new DateTimeout(options.maxComputationTimeMs); + const considerWhitespaceChanges = !options.ignoreTrimWhitespace; + const perfectHashes = /* @__PURE__ */ new Map(); + function getOrCreateHash(text) { + let hash = perfectHashes.get(text); + if (hash === undefined) { + hash = perfectHashes.size; + perfectHashes.set(text, hash); + } + return hash; + } + const originalLinesHashes = originalLines.map((l) => getOrCreateHash(l.trim())); + const modifiedLinesHashes = modifiedLines.map((l) => getOrCreateHash(l.trim())); + const sequence1 = new LineSequence(originalLinesHashes, originalLines); + const sequence2 = new LineSequence(modifiedLinesHashes, modifiedLines); + const lineAlignmentResult = (() => { + if (sequence1.length + sequence2.length < 1700) { + return this.dynamicProgrammingDiffing.compute( + sequence1, + sequence2, + timeout, + (offset1, offset2) => originalLines[offset1] === modifiedLines[offset2] ? modifiedLines[offset2].length === 0 ? 0.1 : 1 + Math.log(1 + modifiedLines[offset2].length) : 0.99 + ); + } + return this.myersDiffingAlgorithm.compute( + sequence1, + sequence2, + timeout + ); + })(); + let lineAlignments = lineAlignmentResult.diffs; + let hitTimeout = lineAlignmentResult.hitTimeout; + lineAlignments = optimizeSequenceDiffs(sequence1, sequence2, lineAlignments); + lineAlignments = removeVeryShortMatchingLinesBetweenDiffs(sequence1, sequence2, lineAlignments); + const alignments = []; + const scanForWhitespaceChanges = (equalLinesCount) => { + if (!considerWhitespaceChanges) { + return; + } + for (let i = 0; i < equalLinesCount; i++) { + const seq1Offset = seq1LastStart + i; + const seq2Offset = seq2LastStart + i; + if (originalLines[seq1Offset] !== modifiedLines[seq2Offset]) { + const characterDiffs = this.refineDiff(originalLines, modifiedLines, new SequenceDiff( + new OffsetRange(seq1Offset, seq1Offset + 1), + new OffsetRange(seq2Offset, seq2Offset + 1) + ), timeout, considerWhitespaceChanges, options); + for (const a of characterDiffs.mappings) { + alignments.push(a); + } + if (characterDiffs.hitTimeout) { + hitTimeout = true; + } + } + } + }; + let seq1LastStart = 0; + let seq2LastStart = 0; + for (const diff of lineAlignments) { + assertFn(() => diff.seq1Range.start - seq1LastStart === diff.seq2Range.start - seq2LastStart); + const equalLinesCount = diff.seq1Range.start - seq1LastStart; + scanForWhitespaceChanges(equalLinesCount); + seq1LastStart = diff.seq1Range.endExclusive; + seq2LastStart = diff.seq2Range.endExclusive; + const characterDiffs = this.refineDiff(originalLines, modifiedLines, diff, timeout, considerWhitespaceChanges, options); + if (characterDiffs.hitTimeout) { + hitTimeout = true; + } + for (const a of characterDiffs.mappings) { + alignments.push(a); + } + } + scanForWhitespaceChanges(originalLines.length - seq1LastStart); + const changes = lineRangeMappingFromRangeMappings(alignments, new ArrayText(originalLines), new ArrayText(modifiedLines)); + let moves = []; + if (options.computeMoves) { + moves = this.computeMoves(changes, originalLines, modifiedLines, originalLinesHashes, modifiedLinesHashes, timeout, considerWhitespaceChanges, options); + } + assertFn(() => { + function validatePosition(pos, lines) { + if (pos.lineNumber < 1 || pos.lineNumber > lines.length) { + return false; + } + const line = lines[pos.lineNumber - 1]; + if (pos.column < 1 || pos.column > line.length + 1) { + return false; + } + return true; + } + function validateRange(range, lines) { + if (range.startLineNumber < 1 || range.startLineNumber > lines.length + 1) { + return false; + } + if (range.endLineNumberExclusive < 1 || range.endLineNumberExclusive > lines.length + 1) { + return false; + } + return true; + } + for (const c of changes) { + if (!c.innerChanges) { + return false; + } + for (const ic of c.innerChanges) { + const valid = validatePosition(ic.modifiedRange.getStartPosition(), modifiedLines) && validatePosition(ic.modifiedRange.getEndPosition(), modifiedLines) && validatePosition(ic.originalRange.getStartPosition(), originalLines) && validatePosition(ic.originalRange.getEndPosition(), originalLines); + if (!valid) { + return false; + } + } + if (!validateRange(c.modified, modifiedLines) || !validateRange(c.original, originalLines)) { + return false; + } + } + return true; + }); + return new LinesDiff(changes, moves, hitTimeout); + } + computeMoves(changes, originalLines, modifiedLines, hashedOriginalLines, hashedModifiedLines, timeout, considerWhitespaceChanges, options) { + const moves = computeMovedLines( + changes, + originalLines, + modifiedLines, + hashedOriginalLines, + hashedModifiedLines, + timeout + ); + const movesWithDiffs = moves.map((m) => { + const moveChanges = this.refineDiff(originalLines, modifiedLines, new SequenceDiff( + m.original.toOffsetRange(), + m.modified.toOffsetRange() + ), timeout, considerWhitespaceChanges, options); + const mappings = lineRangeMappingFromRangeMappings(moveChanges.mappings, new ArrayText(originalLines), new ArrayText(modifiedLines), true); + return new MovedText(m, mappings); + }); + return movesWithDiffs; + } + refineDiff(originalLines, modifiedLines, diff, timeout, considerWhitespaceChanges, options) { + const lineRangeMapping = toLineRangeMapping(diff); + const rangeMapping = lineRangeMapping.toRangeMapping2(originalLines, modifiedLines); + const slice1 = new LinesSliceCharSequence(originalLines, rangeMapping.originalRange, considerWhitespaceChanges); + const slice2 = new LinesSliceCharSequence(modifiedLines, rangeMapping.modifiedRange, considerWhitespaceChanges); + const diffResult = slice1.length + slice2.length < 500 ? this.dynamicProgrammingDiffing.compute(slice1, slice2, timeout) : this.myersDiffingAlgorithm.compute(slice1, slice2, timeout); + let diffs = diffResult.diffs; + diffs = optimizeSequenceDiffs(slice1, slice2, diffs); + diffs = extendDiffsToEntireWordIfAppropriate(slice1, slice2, diffs, (seq, idx) => seq.findWordContaining(idx)); + if (options.extendToSubwords) { + diffs = extendDiffsToEntireWordIfAppropriate(slice1, slice2, diffs, (seq, idx) => seq.findSubWordContaining(idx), true); + } + diffs = removeShortMatches(slice1, slice2, diffs); + diffs = removeVeryShortMatchingTextBetweenLongDiffs(slice1, slice2, diffs); + const result = diffs.map( + (d) => new RangeMapping( + slice1.translateRange(d.seq1Range), + slice2.translateRange(d.seq2Range) + ) + ); + return { + mappings: result, + hitTimeout: diffResult.hitTimeout + }; + } +} +function toLineRangeMapping(sequenceDiff) { + return new LineRangeMapping( + new LineRange(sequenceDiff.seq1Range.start + 1, sequenceDiff.seq1Range.endExclusive + 1), + new LineRange(sequenceDiff.seq2Range.start + 1, sequenceDiff.seq2Range.endExclusive + 1) + ); +} + +function computeDiff(originalLines, modifiedLines, options) { + let diffComputer = new DefaultLinesDiffComputer(); + var result = diffComputer.computeDiff(originalLines, modifiedLines, options); + return result?.changes.map((changes) => { + let originalStartLineNumber; + let originalEndLineNumber; + let modifiedStartLineNumber; + let modifiedEndLineNumber; + let innerChanges = changes.innerChanges; + originalStartLineNumber = changes.original.startLineNumber - 1; + originalEndLineNumber = changes.original.endLineNumberExclusive - 1; + modifiedStartLineNumber = changes.modified.startLineNumber - 1; + modifiedEndLineNumber = changes.modified.endLineNumberExclusive - 1; + return { + origStart: originalStartLineNumber, + origEnd: originalEndLineNumber, + editStart: modifiedStartLineNumber, + editEnd: modifiedEndLineNumber, + charChanges: innerChanges?.map((m) => ({ + originalStartLineNumber: m.originalRange.startLineNumber - 1, + originalStartColumn: m.originalRange.startColumn - 1, + originalEndLineNumber: m.originalRange.endLineNumber - 1, + originalEndColumn: m.originalRange.endColumn - 1, + modifiedStartLineNumber: m.modifiedRange.startLineNumber - 1, + modifiedStartColumn: m.modifiedRange.startColumn - 1, + modifiedEndLineNumber: m.modifiedRange.endLineNumber - 1, + modifiedEndColumn: m.modifiedRange.endColumn - 1 + })) + }; + }); +} + +exports.computeDiff = computeDiff; + +var AceRange = require("../../../range").Range; + +var {DiffChunk} = require("../base_diff_view"); + +/** + * VSCode’s computeDiff provider + */ +class DiffProvider { + compute(originalLines, modifiedLines, opts) { + if (!opts) opts = {}; + if (!opts.maxComputationTimeMs) opts.maxComputationTimeMs = 500; + const chunks = computeDiff(originalLines, modifiedLines, opts) || []; + return chunks.map( + c => new DiffChunk(new AceRange(c.origStart, 0, c.origEnd, 0), new AceRange(c.editStart, 0, c.editEnd, 0), + c.charChanges + )); + } +} + +exports.DiffProvider = DiffProvider; \ No newline at end of file diff --git a/src/ext/diff/styles-css.js b/src/ext/diff/styles-css.js new file mode 100644 index 00000000000..01411a3b181 --- /dev/null +++ b/src/ext/diff/styles-css.js @@ -0,0 +1,118 @@ +exports.cssText = ` +/* + * Line Markers + */ +.ace_diff { + position: absolute; + z-index: 0; +} +.ace_diff.inline { + z-index: 20; +} +/* + * Light Colors + */ +.ace_diff.insert { + background-color: #eaffea; /*rgb(74 251 74 / 12%); */ +} +.ace_diff.delete { + background-color: #ffecec; /*rgb(251 74 74 / 12%);*/ +} +.ace_diff.aligned_diff { + background: rgba(206, 194, 191, 0.26); + background: repeating-linear-gradient( + 45deg, + rgba(122, 111, 108, 0.26), + rgba(122, 111, 108, 0.26) 5px, + #FFFFFF 5px, + #FFFFFF 10px + ); +} + +.ace_diff.insert.inline { + background-color: rgb(74 251 74 / 18%); +} +.ace_diff.delete.inline { + background-color: rgb(251 74 74 / 15%); +} + +.ace_diff.delete.inline.empty { + background-color: rgba(255, 128, 79, 0.8); + width: 2px !important; +} + +.ace_diff.insert.inline.empty { + background-color: rgba(49, 230, 96, 0.8); + width: 2px !important; +} + +.ace_diff.selection { + border-bottom: 1px solid black; + border-top: 1px solid black; + background: transparent; +} + +/* + * Dark Colors + */ + +.ace_dark .ace_diff.insert.inline { + background-color: rgba(0, 130, 58, 0.45); +} +.ace_dark .ace_diff.delete.inline { + background-color: rgba(169, 46, 33, 0.55); +} + +.ace_dark .ace_diff.selection { + border-bottom: 1px solid white; + border-top: 1px solid white; + background: transparent; +} + + +/* gutter changes */ +.ace_mini-diff_gutter-enabled > .ace_gutter-cell { + background-color: #f0f0f0; + padding-right: 13px; +} + +.ace_mini-diff_gutter-enabled > .mini-diff-added { + background-color: #eaffea; + border-left: 3px solid #00FF00; + padding-left: 0; +} + +.ace_mini-diff_gutter-enabled > .mini-diff-deleted { + background-color: #ffecec; + border-left: 3px solid #FF0000; + padding-left: 0; +} + + +.ace_mini-diff_gutter-enabled > .mini-diff-added:after { + position: absolute; + right: 2px; + content: "+"; + color: darkgray; + background-color: inherit; +} + +.ace_mini-diff_gutter-enabled > .mini-diff-deleted:after { + position: absolute; + right: 2px; + content: "-"; + color: darkgray; + background-color: inherit; +} +.ace_fade-fold-widgets:hover .mini-diff-added:after { + display: none; +} +.ace_fade-fold-widgets:hover .mini-diff-deleted:after { + display: none; +} + +.ace_diff_other .ace_selection { + filter: drop-shadow(1px 2px 3px darkgray); +} + +`; diff --git a/src/keyboard/textinput.js b/src/keyboard/textinput.js index 89f06a50c45..e118443245a 100644 --- a/src/keyboard/textinput.js +++ b/src/keyboard/textinput.js @@ -35,6 +35,10 @@ TextInput= function(/**@type{HTMLTextAreaElement} */parentNode, /**@type{import( text.style.opacity = "0"; parentNode.insertBefore(text, parentNode.firstChild); + this.setHost = function(newHost) { + host = newHost; + }; + /**@type{boolean|string}*/var copied = false; var pasted = false; /**@type {(boolean|Object) & {context?: any, useTextareaForIME?: boolean, selectionStart?: number, markerRange?: any}}} */ diff --git a/src/layer/decorators.js b/src/layer/decorators.js index c4a835bef87..c803df5916e 100644 --- a/src/layer/decorators.js +++ b/src/layer/decorators.js @@ -5,19 +5,14 @@ var EventEmitter = require("../lib/event_emitter").EventEmitter; class Decorator { constructor(parent, renderer) { + this.parentEl = parent; this.canvas = dom.createElement("canvas"); this.renderer = renderer; this.pixelRatio = 1; this.maxHeight = renderer.layerConfig.maxHeight; this.lineHeight = renderer.layerConfig.lineHeight; - this.canvasHeight = parent.parent.scrollHeight; - this.heightRatio = this.canvasHeight / this.maxHeight; - this.canvasWidth = parent.width; this.minDecorationHeight = (2 * this.pixelRatio) | 0; this.halfMinDecorationHeight = (this.minDecorationHeight / 2) | 0; - - this.canvas.width = this.canvasWidth; - this.canvas.height = this.canvasHeight; this.canvas.style.top = 0 + "px"; this.canvas.style.right = 0 + "px"; this.canvas.style.zIndex = 7 + "px"; @@ -35,24 +30,15 @@ class Decorator { "info": "rgb(35,68,138)" }; - parent.element.appendChild(this.canvas); + this.setDimensions(); + parent.element.appendChild(this.canvas); } - + $updateDecorators(config) { var colors = (this.renderer.theme.isDark === true) ? this.colors.dark : this.colors.light; - if (config) { - this.maxHeight = config.maxHeight; - this.lineHeight = config.lineHeight; - this.canvasHeight = config.height; - var allLineHeight = (config.lastRow + 1) * this.lineHeight; - if (allLineHeight < this.canvasHeight) { - this.heightRatio = 1; - } - else { - this.heightRatio = this.canvasHeight / this.maxHeight; - } - } + this.setDimensions(config); + var ctx = this.canvas.getContext("2d"); function compare(a, b) { @@ -73,11 +59,10 @@ class Decorator { item.priority = priorities[item.type] || null; }); annotations = annotations.sort(compare); - var foldData = this.renderer.session.$foldData; for (let i = 0; i < annotations.length; i++) { let row = annotations[i].row; - let compensateFold = this.compensateFoldRows(row, foldData); + let compensateFold = this.compensateFoldRows(row); let currentY = Math.round((row - compensateFold) * this.lineHeight * this.heightRatio); let y1 = Math.round(((row - compensateFold) * this.lineHeight * this.heightRatio)); let y2 = Math.round((((row - compensateFold) * this.lineHeight + this.lineHeight) * this.heightRatio)); @@ -100,7 +85,7 @@ class Decorator { } var cursor = this.renderer.session.selection.getCursor(); if (cursor) { - let compensateFold = this.compensateFoldRows(cursor.row, foldData); + let compensateFold = this.compensateFoldRows(cursor.row); let currentY = Math.round((cursor.row - compensateFold) * this.lineHeight * this.heightRatio); ctx.fillStyle = "rgba(0, 0, 0, 0.5)"; ctx.fillRect(0, currentY, this.canvasWidth, 2); @@ -108,7 +93,8 @@ class Decorator { } - compensateFoldRows(row, foldData) { + compensateFoldRows(row) { + let foldData = this.renderer.session.$foldData; let compensateFold = 0; if (foldData && foldData.length > 0) { for (let j = 0; j < foldData.length; j++) { @@ -122,6 +108,43 @@ class Decorator { } return compensateFold; } + + compensateLineWidgets(row) { + const widgetManager = this.renderer.session.widgetManager; + if (widgetManager) { + let delta = 0; + widgetManager.lineWidgets.forEach((el, index) => { + if (row > index) { + delta += el.rowCount || 0; + } + }); + return delta - 1; + } + return 0; + } + + setDimensions(config) { + if (config) { + this.maxHeight = config.maxHeight; + this.lineHeight = config.lineHeight; + this.canvasHeight = config.height; + + if (this.maxHeight < this.canvasHeight) { + this.heightRatio = 1; + } + else { + this.heightRatio = this.canvasHeight / this.maxHeight; + } + } + else { + this.canvasHeight = this.parentEl.parent.scrollHeight || this.canvasHeight; + this.canvasWidth = this.parentEl.width || this.canvasWidth; + this.heightRatio = this.canvasHeight / this.maxHeight; + + this.canvas.width = this.canvasWidth; + this.canvas.height = this.canvasHeight; + } + } } oop.implement(Decorator.prototype, EventEmitter); diff --git a/src/lib/app_config.js b/src/lib/app_config.js index 3b7e53765b7..0785df1e3ea 100644 --- a/src/lib/app_config.js +++ b/src/lib/app_config.js @@ -18,8 +18,7 @@ var optionsProvider = { return !options[key].hidden; }); } else if (!Array.isArray(optionNames)) { - result = optionNames; - optionNames = Object.keys(result); + optionNames = Object.keys(optionNames); } optionNames.forEach(function(key) { result[key] = this.getOption(key); diff --git a/src/search_highlight.js b/src/search_highlight.js index cd9f0f643c1..aa6c7fbb1ff 100644 --- a/src/search_highlight.js +++ b/src/search_highlight.js @@ -37,8 +37,8 @@ class SearchHighlight { var start = config.firstRow; var end = config.lastRow; var renderedMarkerRanges = {}; - var _search = session.$editor.$search; - var mtSearch = _search.$isMultilineSearch(session.$editor.getLastSearchOptions()); + var _search = session.$editor && session.$editor.$search; + var mtSearch = _search && _search.$isMultilineSearch(session.$editor.getLastSearchOptions()); for (var i = start; i <= end; i++) { var ranges = this.cache[i]; diff --git a/src/test/all_browser.js b/src/test/all_browser.js index 12f56bba153..2e143f2c213 100644 --- a/src/test/all_browser.js +++ b/src/test/all_browser.js @@ -39,6 +39,7 @@ var testNames = [ "ace/ext/beautify_test", "ace/ext/code_lens_test", "ace/ext/command_bar_test", + "ace/ext/diff/diff_test", "ace/ext/emmet_test", "ace/ext/error_marker_test", "ace/ext/hardwrap_test", @@ -54,6 +55,7 @@ var testNames = [ "ace/keyboard/textinput_test", "ace/keyboard/vim_ace_test", "ace/keyboard/vim_test", + "ace/layer/gutter_test", "ace/layer/text_test", "ace/lib/event_emitter_test", "ace/marker_group_test", diff --git a/types/ace-ext.d.ts b/types/ace-ext.d.ts index e6aaa0ce834..95ae099e97f 100644 --- a/types/ace-ext.d.ts +++ b/types/ace-ext.d.ts @@ -643,3 +643,240 @@ declare module "ace-code/src/ext/whitespace" { }[]; export type EditSession = import("ace-code/src/edit_session").EditSession; } +declare module "ace-code/src/ext/diff/styles-css" { + export const cssText: "\n/*\n * Line Markers\n */\n.ace_diff {\n position: absolute;\n z-index: 0;\n}\n.ace_diff.inline {\n z-index: 20;\n}\n/*\n * Light Colors \n */\n.ace_diff.insert {\n background-color: #eaffea; /*rgb(74 251 74 / 12%); */\n}\n.ace_diff.delete {\n background-color: #ffecec; /*rgb(251 74 74 / 12%);*/\n}\n.ace_diff.aligned_diff {\n background: rgba(206, 194, 191, 0.26);\n background: repeating-linear-gradient(\n 45deg,\n rgba(122, 111, 108, 0.26),\n rgba(122, 111, 108, 0.26) 5px,\n #FFFFFF 5px,\n #FFFFFF 10px \n );\n}\n\n.ace_diff.insert.inline {\n background-color: rgb(74 251 74 / 18%); \n}\n.ace_diff.delete.inline {\n background-color: rgb(251 74 74 / 15%);\n}\n\n.ace_diff.delete.inline.empty {\n background-color: rgba(255, 128, 79, 0.8);\n width: 2px !important;\n}\n\n.ace_diff.insert.inline.empty {\n background-color: rgba(49, 230, 96, 0.8);\n width: 2px !important;\n}\n\n.ace_diff.selection {\n border-bottom: 1px solid black;\n border-top: 1px solid black;\n background: transparent;\n}\n\n/*\n * Dark Colors \n */\n\n.ace_dark .ace_diff.insert.inline {\n background-color: rgba(0, 130, 58, 0.45);\n}\n.ace_dark .ace_diff.delete.inline {\n background-color: rgba(169, 46, 33, 0.55);\n}\n\n.ace_dark .ace_diff.selection {\n border-bottom: 1px solid white;\n border-top: 1px solid white;\n background: transparent;\n}\n \n\n/* gutter changes */\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell {\n background-color: #f0f0f0;\n padding-right: 13px;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #eaffea;\n border-left: 3px solid #00FF00;\n padding-left: 0;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #ffecec;\n border-left: 3px solid #FF0000;\n padding-left: 0;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added:after {\n position: absolute;\n right: 2px;\n content: \"+\";\n color: darkgray;\n background-color: inherit;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted:after {\n position: absolute;\n right: 2px;\n content: \"-\";\n color: darkgray;\n background-color: inherit;\n}\n.ace_fade-fold-widgets:hover .mini-diff-added:after {\n display: none;\n}\n.ace_fade-fold-widgets:hover .mini-diff-deleted:after {\n display: none;\n}\n\n.ace_diff_other .ace_selection {\n filter: drop-shadow(1px 2px 3px darkgray);\n}\n\n"; +} +declare module "ace-code/src/ext/diff/gutter_decorator" { + export class MinimalGutterDiffDecorator { + constructor(editor: import("ace-code/src/editor").Editor, type: number); + gutterClass: string; + gutterCellsClasses: { + add: string; + delete: string; + }; + editor: import("ace-code/src/editor").Editor; + type: number; + chunks: any[]; + attachToEditor(): void; + renderGutters(e: any, gutterLayer: any): void; + setDecorations(changes: any): void; + dispose(): void; + } +} +declare module "ace-code/src/ext/diff/providers/default" { + export function computeDiff(originalLines: any, modifiedLines: any, options: any): any; + /** + * VSCode’s computeDiff provider + */ + export class DiffProvider { + compute(originalLines: any, modifiedLines: any, opts: any): any; + } +} +declare module "ace-code/src/ext/diff/base_diff_view" { + export class BaseDiffView { + /** + * Constructs a new base DiffView instance. + * @param {boolean} [inlineDiffEditor] - Whether to use an inline diff editor. + * @param {HTMLElement} [container] - optional container element for the DiffView. + */ + constructor(inlineDiffEditor?: boolean, container?: HTMLElement); + onChangeTheme(): void; + onInput(): void; + onChangeFold(ev: any, session: EditSession): void; + realign(): void; + onSelect(e: any, selection: any): void; + realignPending: boolean; + diffSession: { + sessionA: EditSession; + sessionB: EditSession; + chunks: DiffChunk[]; + }; + /**@type DiffChunk[]*/ chunks: DiffChunk[]; + inlineDiffEditor: boolean; + currentDiffIndex: number; + diffProvider: { + compute: (val1: any, val2: any, options: any) => any[]; + }; + container: HTMLElement; + options: { + ignoreTrimWhitespace: boolean; + maxComputationTimeMs: number; + syncSelections: boolean; + }; + markerB: DiffHighlight; + markerA: DiffHighlight; + /** + * @param {Object} options - The configuration options for the DiffView. + * @param {boolean} [options.ignoreTrimWhitespace=true] - Whether to ignore whitespace changes when computing diffs. + * @param {boolean} [options.foldUnchanged=false] - Whether to fold unchanged regions in the diff view. + * @param {number} [options.maxComputationTimeMs=0] - The maximum time in milliseconds to spend computing diffs (0 means no limit). + * @param {boolean} [options.syncSelections=false] - Whether to synchronize selections between the original and edited views. + */ + setOptions(options: { + ignoreTrimWhitespace?: boolean; + foldUnchanged?: boolean; + maxComputationTimeMs?: number; + syncSelections?: boolean; + }): void; + showSideA: boolean; + savedOptionsA: Partial; + savedOptionsB: Partial; + editorA: any; + editorB: any; + activeEditor: any; + otherSession: EditSession; + otherEditor: any; + addGutterDecorators(): void; + gutterDecoratorA: MinimalGutterDiffDecorator; + gutterDecoratorB: MinimalGutterDiffDecorator; + foldUnchanged(): void; + setDiffSession(session: { + sessionA: any; + sessionB: EditSession; + chunks: DiffChunk[]; + }): void; + sessionA: EditSession; + sessionB: EditSession; + getDiffSession(): { + sessionA: EditSession; + sessionB: EditSession; + chunks: DiffChunk[]; + }; + setTheme(theme: any): void; + getTheme(): any; + resize(force: any): void; + selectionRangeA: any; + selectionRangeB: any; + setProvider(provider: import("ace-code/src/ext/diff/providers/default").DiffProvider): void; + /** scroll locking + * @abstract + **/ + align(): void; + syncSelect(selection: any): void; + updateSelectionMarker(marker: any, session: any, range: any): void; + detach(): void; + destroy(): void; + gotoNext(dir: any): void; + firstDiffSelected(): boolean; + lastDiffSelected(): boolean; + transformRange(range: Range, isOriginal: boolean): Range; + transformPosition(pos: import("ace-code").Ace.Point, isOriginal: boolean): import("ace-code").Ace.Point; + printDiffs(): void; + findChunkIndex(chunks: DiffChunk[], row: number, isOriginal: boolean): number; + searchHighlight(selection: any): void; + initSelectionMarkers(): void; + syncSelectionMarkerA: SyncSelectionMarker; + syncSelectionMarkerB: SyncSelectionMarker; + clearSelectionMarkers(): void; + } + export class DiffChunk { + /** + * @param {{originalStartLineNumber: number, originalStartColumn: number, + * originalEndLineNumber: number, originalEndColumn: number, modifiedStartLineNumber: number, + * modifiedStartColumn: number, modifiedEndLineNumber: number, modifiedEndColumn: number}[]} [charChanges] + */ + constructor(originalRange: Range, modifiedRange: Range, charChanges?: { + originalStartLineNumber: number; + originalStartColumn: number; + originalEndLineNumber: number; + originalEndColumn: number; + modifiedStartLineNumber: number; + modifiedStartColumn: number; + modifiedEndLineNumber: number; + modifiedEndColumn: number; + }[]); + old: Range; + new: Range; + charChanges: DiffChunk[]; + } + export class DiffHighlight { + constructor(diffView: import("ace-code/src/ext/diff/base_diff_view").BaseDiffView, type: any); + id: number; + diffView: BaseDiffView; + type: any; + update(html: any, markerLayer: any, session: any, config: any): void; + } + import { EditSession } from "ace-code/src/edit_session"; + import { Editor } from "ace-code/src/editor"; + import { MinimalGutterDiffDecorator } from "ace-code/src/ext/diff/gutter_decorator"; + import { Range } from "ace-code/src/range"; + class SyncSelectionMarker { + id: number; + type: string; + clazz: string; + update(html: any, markerLayer: any, session: any, config: any): void; + setRange(range: Range): void; + range: Range; + } +} +declare module "ace-code/src/ext/diff/diff_view" { + export class DiffView extends BaseDiffView { + /** + * Constructs a new side by side DiffView instance. + * + * @param {Object} [diffModel] - The model for the diff view. + * @param {import("ace-code/src/editor").Editor} [diffModel.editorA] - The editor for the original view. + * @param {import("ace-code/src/editor").Editor} [diffModel.editorB] - The editor for the edited view. + * @param {import("ace-code/src/edit_session").EditSession} [diffModel.sessionA] - The edit session for the original view. + * @param {import("ace-code/src/edit_session").EditSession} [diffModel.sessionB] - The edit session for the edited view. + * @param {string} [diffModel.valueA] - The original content. + * @param {string} [diffModel.valueB] - The modified content. + */ + constructor(diffModel?: { + editorA?: import("ace-code/src/editor").Editor; + editorB?: import("ace-code/src/editor").Editor; + sessionA?: import("ace-code/src/edit_session").EditSession; + sessionB?: import("ace-code/src/edit_session").EditSession; + valueA?: string; + valueB?: string; + }); + init(diffModel: any): void; + onMouseWheel(ev: any): any; + onScroll(e: any, session: any): void; + syncScroll(renderer: import("ace-code/src/virtual_renderer").VirtualRenderer): void; + scrollA: any; + scrollB: any; + scrollSetBy: any; + scrollSetAt: number; + } + import { BaseDiffView } from "ace-code/src/ext/diff/base_diff_view"; +} +declare module "ace-code/src/ext/diff/inline_diff_view" { + export class InlineDiffView extends BaseDiffView { + /** + * Constructs a new inline DiffView instance. + * @param {Object} [diffModel] - The model for the diff view. + * @param {import("ace-code").Editor} [diffModel.editorA] - The editor for the original view. + * @param {import("ace-code").Editor} [diffModel.editorB] - The editor for the edited view. + * @param {import("ace-code").EditSession} [diffModel.sessionA] - The edit session for the original view. + * @param {import("ace-code").EditSession} [diffModel.sessionB] - The edit session for the edited view. + * @param {string} [diffModel.valueA] - The original content. + * @param {string} [diffModel.valueB] - The modified content. + * @param {boolean} [diffModel.showSideA] - Whether to show the original view or modified view. + * @param {HTMLElement} [container] - optional container element for the DiffView. + */ + constructor(diffModel?: { + editorA?: import("ace-code").Editor; + editorB?: import("ace-code").Editor; + sessionA?: import("ace-code").EditSession; + sessionB?: import("ace-code").EditSession; + valueA?: string; + valueB?: string; + showSideA?: boolean; + }, container?: HTMLElement); + init(diffModel: any): void; + onAfterRender(changes: number, renderer: import("ace-code").VirtualRenderer): void; + textLayer: any; + markerLayer: any; + gutterLayer: any; + cursorLayer: any; + initTextLayer(): void; + initTextInput(restore: any): void; + othertextInput: any; + otherEditorContainer: any; + selectEditor(editor: any): void; + initMouse(): void; + onMouseDetach: () => void; + } + import { BaseDiffView } from "ace-code/src/ext/diff/base_diff_view"; +} diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index 1631e0c120b..1d1dee1e2db 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -818,18 +818,21 @@ declare module "ace-code/src/css/editor-css" { declare module "ace-code/src/layer/decorators" { export class Decorator { constructor(parent: any, renderer: any); + parentEl: any; canvas: HTMLCanvasElement; renderer: any; pixelRatio: number; maxHeight: any; lineHeight: any; - canvasHeight: any; - heightRatio: number; - canvasWidth: any; minDecorationHeight: number; halfMinDecorationHeight: number; colors: {}; - compensateFoldRows(row: any, foldData: any): number; + compensateFoldRows(row: any): number; + compensateLineWidgets(row: any): number; + setDimensions(config: any): void; + canvasHeight: any; + heightRatio: number; + canvasWidth: any; } } declare module "ace-code/src/virtual_renderer" { @@ -2036,13 +2039,13 @@ declare module "ace-code/src/editor" { * @param {Partial} [options] The default options **/ constructor(renderer: VirtualRenderer, session?: EditSession, options?: Partial); + id: string; session: EditSession; container: HTMLElement & { env?: any; value?: any; }; renderer: VirtualRenderer; - id: string; commands: CommandManager; textInput: any; keyBinding: KeyBinding; @@ -2123,9 +2126,10 @@ declare module "ace-code/src/editor" { /** * {:VirtualRenderer.setStyle} * @param {String} style A class name + * @param {boolean} [incluude] pass false to remove the class name * @related VirtualRenderer.setStyle **/ - setStyle(style: string): void; + setStyle(style: string, incluude?: boolean): void; /** * {:VirtualRenderer.unsetStyle} * @related VirtualRenderer.unsetStyle From 4e911b38c2fc28f87e402bc9cfe6886709a08acf Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Fri, 2 May 2025 17:34:07 +0200 Subject: [PATCH 1253/1293] release v1.41.0 --- CHANGELOG.md | 2 ++ ace.d.ts | 2 +- build | 2 +- package.json | 2 +- src/config.js | 2 +- types/ace-modules.d.ts | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcc96d6c338..35a8e9ef0bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.40.2](https://github.com/ajaxorg/ace/compare/v1.40.1...v1.40.2) (2025-05-02) + ### [1.40.1](https://github.com/ajaxorg/ace/compare/v1.40.0...v1.40.1) (2025-04-23) diff --git a/ace.d.ts b/ace.d.ts index 36e9936e9fb..8dcfa66ced3 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1041,6 +1041,6 @@ declare module "ace-code" { import { Range } from "ace-code/src/range"; import { UndoManager } from "ace-code/src/undomanager"; import { VirtualRenderer as Renderer } from "ace-code/src/virtual_renderer"; - export var version: "1.40.1"; + export var version: "1.41.0"; export { Range, Editor, EditSession, UndoManager, Renderer as VirtualRenderer }; } diff --git a/build b/build index 0c8b483727d..939251942ec 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 0c8b483727d5c18473df83321424690667125135 +Subproject commit 939251942ecab0d269dd5f9ff0dc824103346198 diff --git a/package.json b/package.json index 2cf7bfdfbe5..5398385ae20 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.40.1", + "version": "1.41.0", "homepage": "https://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 470d4114ebf..82bfeffd088 100644 --- a/src/config.js +++ b/src/config.js @@ -197,6 +197,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.40.1"; +exports.version = "1.41.0"; diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index 1d1dee1e2db..c3c7630b4bd 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -375,7 +375,7 @@ declare module "ace-code/src/config" { string ], onLoad: (module: any) => void) => void; setModuleLoader: (moduleName: any, onLoad: any) => void; - version: "1.40.1"; + version: "1.41.0"; }; export = _exports; } From b20be1a4591e1c566fdb0e205a75fa580885e7c6 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Sat, 3 May 2025 12:53:23 +0400 Subject: [PATCH 1254/1293] fix: missing type aliases and MarkerGroup in `ace-builds` (#5782) --- ace-internal.d.ts | 3 ++ ace.d.ts | 3 ++ demo/test_ace_builds/index.ts | 31 ++++++++++- demo/test_ace_builds/package.json | 2 +- src/ext/language_tools.js | 4 ++ types/ace-ext.d.ts | 3 +- types/ace-modules.d.ts | 86 +++++++++++++++---------------- 7 files changed, 86 insertions(+), 46 deletions(-) diff --git a/ace-internal.d.ts b/ace-internal.d.ts index e64a6e08548..febda4711f1 100644 --- a/ace-internal.d.ts +++ b/ace-internal.d.ts @@ -29,6 +29,9 @@ export namespace Ace { type Config = typeof import("./src/config"); type GutterTooltip = import( "./src/mouse/default_gutter_handler").GutterTooltip; type GutterKeyboardEvent = import( "./src/keyboard/gutter_handler").GutterKeyboardEvent; + type HoverTooltip = import("ace-code/src/tooltip").HoverTooltip; + type Tooltip = import("ace-code/src/tooltip").Tooltip; + type PopupManager = import("ace-code/src/tooltip").PopupManager; type AfterLoadCallback = (err: Error | null, module: unknown) => void; type LoaderFunction = (moduleName: string, afterLoad: AfterLoadCallback) => void; diff --git a/ace.d.ts b/ace.d.ts index 8dcfa66ced3..dddfe9a5ac3 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -38,6 +38,9 @@ declare module "ace-code" { type Config = typeof import("ace-code/src/config"); type GutterTooltip = import("ace-code/src/mouse/default_gutter_handler").GutterTooltip; type GutterKeyboardEvent = import("ace-code/src/keyboard/gutter_handler").GutterKeyboardEvent; + type HoverTooltip = import("ace-code/src/tooltip").HoverTooltip; + type Tooltip = import("ace-code/src/tooltip").Tooltip; + type PopupManager = import("ace-code/src/tooltip").PopupManager; type AfterLoadCallback = (err: Error | null, module: unknown) => void; type LoaderFunction = (moduleName: string, afterLoad: AfterLoadCallback) => void; export interface ConfigOptions { diff --git a/demo/test_ace_builds/index.ts b/demo/test_ace_builds/index.ts index b23b1f110cb..1fa7f5cadb3 100644 --- a/demo/test_ace_builds/index.ts +++ b/demo/test_ace_builds/index.ts @@ -2,10 +2,16 @@ import * as ace from "ace-builds"; import {Range, Ace} from "ace-builds"; import "ace-builds/src-noconflict/ext-language_tools"; import "../../src/test/mockdom.js"; + var HoverTooltip = ace.require("ace/tooltip").HoverTooltip; import "ace-builds/src-noconflict/mode-javascript"; import "ace-builds/src-noconflict/theme-monokai"; +const MarkerGroup = ace.require("ace/marker_group").MarkerGroup; +const MouseEvent = ace.require("ace/mouse/mouse_event").MouseEvent; +var Tooltip = ace.require("ace/tooltip").Tooltip; +var popupManager: Ace.PopupManager = ace.require("ace/tooltip").popupManager; + const editor = ace.edit(null); // should not be an error editor.setTheme("ace/theme/monokai"); editor.session.setMode("ace/mode/javascript"); @@ -19,7 +25,20 @@ function configure(config: Ace.Config) { configure(ace.config) // should not be a error -const hover = new HoverTooltip(); +const markerGroup: Ace.MarkerGroup = new MarkerGroup(editor.session); +const markers: Ace.MarkerGroupItem[] = [ + { + range: new Range(0, 0, 10, 10), + className: "test-class" + } +] +markerGroup.setMarkers(markers); +markerGroup.markers.every(marker => { + console.log(marker.range); + return true; +}); + +const hover: Ace.HoverTooltip = new HoverTooltip(); hover.setDataProvider((e: any, editor: Ace.Editor) => { const domNode = document.createElement("div"); hover.showForRange(editor, new Range(1, 3, 3, 1), domNode, e); @@ -34,4 +53,14 @@ editor.commands.on('exec', ({editor, command}) => { console.log(editor.getValue(), command.name); }); +editor.container.addEventListener('click', (e: MouseEvent) => { + var mouseEvent: Ace.MouseEvent = new MouseEvent(e, editor); + mouseEvent.x = e.x * 2; +}); + +var tooltip: Ace.Tooltip = new Tooltip(editor.container); +tooltip.show('hello'); + +popupManager.addPopup(tooltip); + editor.destroy && editor.destroy(); \ No newline at end of file diff --git a/demo/test_ace_builds/package.json b/demo/test_ace_builds/package.json index 7c637625b13..a6af1786a61 100644 --- a/demo/test_ace_builds/package.json +++ b/demo/test_ace_builds/package.json @@ -11,6 +11,6 @@ "ace-builds": "file:../../ace-builds-latest.tgz" }, "devDependencies": { - "typescript": "^5.7.3" + "typescript": "^5.8.2" } } diff --git a/src/ext/language_tools.js b/src/ext/language_tools.js index b34a8a6680d..5245764ef74 100644 --- a/src/ext/language_tools.js +++ b/src/ext/language_tools.js @@ -6,6 +6,8 @@ var config = require("../config"); var lang = require("../lib/lang"); var util = require("../autocomplete/util"); +var MarkerGroup = require("../marker_group").MarkerGroup; + var textCompleter = require("../autocomplete/text_completer"); /**@type {import("../../ace-internal").Ace.Completer}*/ var keyWordCompleter = { @@ -230,3 +232,5 @@ require("../config").defineOptions(Editor.prototype, "editor", { value: false } }); + +exports.MarkerGroup = MarkerGroup; \ No newline at end of file diff --git a/types/ace-ext.d.ts b/types/ace-ext.d.ts index 95ae099e97f..c5f4c67a4ef 100644 --- a/types/ace-ext.d.ts +++ b/types/ace-ext.d.ts @@ -85,7 +85,8 @@ declare module "ace-code/src/ext/language_tools" { import textCompleter = require("ace-code/src/autocomplete/text_completer"); export var keyWordCompleter: import("ace-code").Ace.Completer; export var snippetCompleter: import("ace-code").Ace.Completer; - export { textCompleter }; + import { MarkerGroup } from "ace-code/src/marker_group"; + export { textCompleter, MarkerGroup }; } declare module "ace-code/src/ext/inline_autocomplete" { /** diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index c3c7630b4bd..5e5f10eab8b 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -3317,6 +3317,49 @@ declare module "ace-code/src/autocomplete" { completions: Ace.FilteredList; } } +declare module "ace-code/src/marker_group" { + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type MarkerGroupItem = { + range: import("ace-code/src/range").Range; + className: string; + }; + export type LayerConfig = import("ace-code").Ace.LayerConfig; + export type Marker = import("ace-code/src/layer/marker").Marker; + export class MarkerGroup { + /** + * @param {{markerType: "fullLine" | "line" | undefined}} [options] Options controlling the behvaiour of the marker. + * User `markerType` to control how the markers which are part of this group will be rendered: + * - `undefined`: uses `text` type markers where only text characters within the range will be highlighted. + * - `fullLine`: will fully highlight all the rows within the range, including the characters before and after the range on the respective rows. + * - `line`: will fully highlight the lines within the range but will only cover the characters between the start and end of the range. + */ + constructor(session: EditSession, options?: { + markerType: "fullLine" | "line" | undefined; + }); + markerType: "line" | "fullLine"; + markers: import("ace-code").Ace.MarkerGroupItem[]; + session: EditSession; + /** + * Finds the first marker containing pos + */ + getMarkerAtPosition(pos: import("ace-code").Ace.Point): import("ace-code").Ace.MarkerGroupItem | undefined; + /** + * Comparator for Array.sort function, which sorts marker definitions by their positions + * + * @param {MarkerGroupItem} a first marker. + * @param {MarkerGroupItem} b second marker. + * @returns {number} negative number if a should be before b, positive number if b should be before a, 0 otherwise. + */ + markersComparator(a: MarkerGroupItem, b: MarkerGroupItem): number; + /** + * Sets marker definitions to be rendered. Limits the number of markers at MAX_MARKERS. + * @param {MarkerGroupItem[]} markers an array of marker definitions. + */ + setMarkers(markers: MarkerGroupItem[]): void; + update(html: any, markerLayer: Marker, session: EditSession, config: LayerConfig): void; + MAX_MARKERS: number; + } +} declare module "ace-code/src/autocomplete/text_completer" { export function getCompletions(editor: any, session: any, pos: any, prefix: any, callback: any): void; } @@ -3421,49 +3464,6 @@ declare module "ace-code/src/occur" { import { Search } from "ace-code/src/search"; import { EditSession } from "ace-code/src/edit_session"; } -declare module "ace-code/src/marker_group" { - export type EditSession = import("ace-code/src/edit_session").EditSession; - export type MarkerGroupItem = { - range: import("ace-code/src/range").Range; - className: string; - }; - export type LayerConfig = import("ace-code").Ace.LayerConfig; - export type Marker = import("ace-code/src/layer/marker").Marker; - export class MarkerGroup { - /** - * @param {{markerType: "fullLine" | "line" | undefined}} [options] Options controlling the behvaiour of the marker. - * User `markerType` to control how the markers which are part of this group will be rendered: - * - `undefined`: uses `text` type markers where only text characters within the range will be highlighted. - * - `fullLine`: will fully highlight all the rows within the range, including the characters before and after the range on the respective rows. - * - `line`: will fully highlight the lines within the range but will only cover the characters between the start and end of the range. - */ - constructor(session: EditSession, options?: { - markerType: "fullLine" | "line" | undefined; - }); - markerType: "line" | "fullLine"; - markers: import("ace-code").Ace.MarkerGroupItem[]; - session: EditSession; - /** - * Finds the first marker containing pos - */ - getMarkerAtPosition(pos: import("ace-code").Ace.Point): import("ace-code").Ace.MarkerGroupItem | undefined; - /** - * Comparator for Array.sort function, which sorts marker definitions by their positions - * - * @param {MarkerGroupItem} a first marker. - * @param {MarkerGroupItem} b second marker. - * @returns {number} negative number if a should be before b, positive number if b should be before a, 0 otherwise. - */ - markersComparator(a: MarkerGroupItem, b: MarkerGroupItem): number; - /** - * Sets marker definitions to be rendered. Limits the number of markers at MAX_MARKERS. - * @param {MarkerGroupItem[]} markers an array of marker definitions. - */ - setMarkers(markers: MarkerGroupItem[]): void; - update(html: any, markerLayer: Marker, session: EditSession, config: LayerConfig): void; - MAX_MARKERS: number; - } -} declare module "ace-code/src/edit_session/fold" { export class Fold extends RangeList { constructor(range: Range, placeholder: any); From 25a471a3ec0a7c657646a54d034709f0d3283f19 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Mon, 5 May 2025 01:03:43 +0400 Subject: [PATCH 1255/1293] fix: editor.completer would init on `enableBasicAutocompletion` option `true` (#5756) --- src/ext/language_tools.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ext/language_tools.js b/src/ext/language_tools.js index 5245764ef74..7628f280647 100644 --- a/src/ext/language_tools.js +++ b/src/ext/language_tools.js @@ -183,6 +183,8 @@ require("../config").defineOptions(Editor.prototype, "editor", { */ set: function(val) { if (val) { + Autocomplete.for(this); + if (!this.completers) this.completers = Array.isArray(val)? val: completers; this.commands.addCommand(Autocomplete.startCommand); From 90d72fc95ed2a3e35725a39fa2b88c2fe6d0a44c Mon Sep 17 00:00:00 2001 From: orca <35243139+thennothinghappened@users.noreply.github.com> Date: Mon, 5 May 2025 07:04:57 +1000 Subject: [PATCH 1256/1293] feat: update mouse selection at user's refresh rate (#5717) * feat: update mouse selection at user's refresh rate (#5716) * fix: redundantly setting `continueCapture` after decl --- src/mouse/mouse_handler.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/mouse/mouse_handler.js b/src/mouse/mouse_handler.js index 21f9a72c842..f99661ebe70 100644 --- a/src/mouse/mouse_handler.js +++ b/src/mouse/mouse_handler.js @@ -135,6 +135,8 @@ class MouseHandler { renderer.$isMousePressed = true; var self = this; + var continueCapture = true; + var onMouseMove = function(e) { if (!e) return; // if editor is loaded inside iframe, and mouseup event is outside @@ -151,8 +153,8 @@ class MouseHandler { var onCaptureEnd = function(e) { editor.off("beforeEndOperation", onOperationEnd); - clearInterval(timerId); - if (editor.session) onCaptureInterval(); + continueCapture = false; + if (editor.session) onCaptureUpdate(); self[self.state + "End"] && self[self.state + "End"](e); self.state = ""; self.isMousePressed = renderer.$isMousePressed = false; @@ -163,11 +165,18 @@ class MouseHandler { editor.endOperation(); }; - var onCaptureInterval = function() { + var onCaptureUpdate = function() { self[self.state] && self[self.state](); self.$mouseMoved = false; }; + var onCaptureInterval = function() { + if (continueCapture) { + onCaptureUpdate(); + event.nextFrame(onCaptureInterval); + } + }; + if (useragent.isOldIE && ev.domEvent.type == "dblclick") { return setTimeout(function() {onCaptureEnd(ev);}); } @@ -188,7 +197,8 @@ class MouseHandler { self.$onCaptureMouseMove = onMouseMove; self.releaseMouse = event.capture(this.editor.container, onMouseMove, onCaptureEnd); - var timerId = setInterval(onCaptureInterval, 20); + + onCaptureInterval(); } cancelContextMenu() { var stop = function(e) { From 63add651d0a2c7b49dbf8ef485656134a4903df0 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Thu, 15 May 2025 16:43:23 +0400 Subject: [PATCH 1257/1293] Improve diffview (#5806) * fix diff selection marker staying after detach * improve diff-view * fix autocomplete test * update types * add more tests * restore value of fold option after detaching * folding fixes --- demo/diff/index.html | 312 +++++++++++++++++-------------- kitchen-sink.html | 3 + src/autocomplete_test.js | 2 +- src/css/editor-css.js | 1 + src/ext/diff/base_diff_view.js | 176 +++++++++++------ src/ext/diff/diff_test.js | 242 ++++++++++++++++++++---- src/ext/diff/diff_view.js | 49 +---- src/ext/diff/inline_diff_view.js | 73 +++----- src/ext/diff/styles-css.js | 20 +- types/ace-ext.d.ts | 21 +-- 10 files changed, 560 insertions(+), 339 deletions(-) diff --git a/demo/diff/index.html b/demo/diff/index.html index d35233ea707..0a60eb3d4bb 100644 --- a/demo/diff/index.html +++ b/demo/diff/index.html @@ -35,158 +35,24 @@ .toolbar button:hover { background: #e6e6e6; } + .toolbar > label { + display: inline-flex; + align-items: center; + } - -
    - - - - - - - - - - - - - - -
    +
    diff --git a/kitchen-sink.html b/kitchen-sink.html index 123b290c58c..73d0ccc56ec 100644 --- a/kitchen-sink.html +++ b/kitchen-sink.html @@ -39,6 +39,9 @@ + diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index a0aa82bfecf..a38b3a38c96 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -581,7 +581,7 @@ module.exports = { user.type(" "); user.type("t"); user.type("e"); - assert.ok(!editor.completer || !editor.completer.popup.isOpen); + assert.ok(!editor.completer.popup || !editor.completer.popup.isOpen); setTimeout(function() { assert.ok(editor.completer.popup.isOpen); assert.ok(editor.completers[1].timeout); diff --git a/src/css/editor-css.js b/src/css/editor-css.js index c55b9c6ae2d..cf7768f4a7b 100644 --- a/src/css/editor-css.js +++ b/src/css/editor-css.js @@ -523,6 +523,7 @@ module.exports = ` border: 1px solid transparent; cursor: pointer; + pointer-events: auto; } .ace_custom-widget { diff --git a/src/ext/diff/base_diff_view.js b/src/ext/diff/base_diff_view.js index ba469540b1a..ad0dd01f8e9 100644 --- a/src/ext/diff/base_diff_view.js +++ b/src/ext/diff/base_diff_view.js @@ -4,6 +4,7 @@ var oop = require("../../lib/oop"); var Range = require("../../range").Range; var dom = require("../../lib/dom"); var config = require("../../config"); +var LineWidgets = require("../../line_widgets").LineWidgets; // @ts-ignore var css = require("./styles-css.js").cssText; @@ -19,6 +20,12 @@ var EditSession = require("../../edit_session").EditSession; var MinimalGutterDiffDecorator = require("./gutter_decorator").MinimalGutterDiffDecorator; +var dummyDiffProvider = { + compute: function(val1, val2, options) { + return []; + } +}; + class BaseDiffView { /** * Constructs a new base DiffView instance. @@ -37,50 +44,23 @@ class BaseDiffView { /**@type DiffChunk[]*/this.chunks; this.inlineDiffEditor = inlineDiffEditor || false; this.currentDiffIndex = 0; - this.diffProvider = { - compute: function(val1, val2, options) { - return []; - } - }; + this.diffProvider = dummyDiffProvider; if (container) { this.container = container; } dom.importCssString(css, "diffview.css"); - this.options = { - ignoreTrimWhitespace: true, - maxComputationTimeMs: 0, // time in milliseconds, 0 => no computation limit. - syncSelections: false //experimental option - }; - oop.mixin(this.options, { - maxDiffs: 5000 - }); + this.$ignoreTrimWhitespace = false; + this.$maxDiffs = 5000; + this.$maxComputationTimeMs = 150; + this.$syncSelections = false; + this.$foldUnchangedOnInput = false; this.markerB = new DiffHighlight(this, 1); this.markerA = new DiffHighlight(this, -1); } - /** - * @param {Object} options - The configuration options for the DiffView. - * @param {boolean} [options.ignoreTrimWhitespace=true] - Whether to ignore whitespace changes when computing diffs. - * @param {boolean} [options.foldUnchanged=false] - Whether to fold unchanged regions in the diff view. - * @param {number} [options.maxComputationTimeMs=0] - The maximum time in milliseconds to spend computing diffs (0 means no limit). - * @param {boolean} [options.syncSelections=false] - Whether to synchronize selections between the original and edited views. - */ - setOptions(options) { - this.options = { - ignoreTrimWhitespace: options.ignoreTrimWhitespace || true, - foldUnchanged: options.foldUnchanged || false, - maxComputationTimeMs: options.maxComputationTimeMs || 0, // time in milliseconds, 0 => no computation limit. - syncSelections: options.syncSelections || false //experimental option - }; - oop.mixin(this.options, { - maxDiffs: 5000 - }); - config.resetOptions(this); - } - /** * @param {Object} [diffModel] - The model for the diff view. * @param {Editor} [diffModel.editorA] - The editor for the original view. @@ -90,8 +70,12 @@ class BaseDiffView { * @param {string} [diffModel.valueA] - The original content. * @param {string} [diffModel.valueB] - The modified content. * @param {boolean} [diffModel.showSideA] - Whether to show the original view or modified view. + * @param {import("./providers/default").DiffProvider} [diffModel.diffProvider] - The diff provider to use. */ $setupModels(diffModel) { + if (diffModel.diffProvider) { + this.setProvider(diffModel.diffProvider); + } this.showSideA = diffModel.showSideA == undefined ? true : diffModel.showSideA; var diffEditorOptions = /**@type {Partial}*/({ scrollPastEnd: 0.5, @@ -101,6 +85,7 @@ class BaseDiffView { customScrollbar: true, vScrollBarAlwaysVisible: true, fadeFoldWidgets: true, + showFoldWidgets: true, selectionStyle: "text", }); @@ -252,7 +237,16 @@ class BaseDiffView { this.editorB && this.editorB.resize(force); } + scheduleOnInput() { + if (this.$onInputTimer) return; + this.$onInputTimer = setTimeout(() => { + this.$onInputTimer = null; + this.onInput(); + }); + } onInput() { + if (this.$onInputTimer) clearTimeout(this.$onInputTimer); + var val1 = this.sessionA.doc.getAllLines(); var val2 = this.sessionB.doc.getAllLines(); @@ -265,7 +259,7 @@ class BaseDiffView { this.gutterDecoratorA && this.gutterDecoratorA.setDecorations(chunks); this.gutterDecoratorB && this.gutterDecoratorB.setDecorations(chunks); // if we"re dealing with too many chunks, fail silently - if (this.chunks && this.chunks.length > this.options.maxDiffs) { + if (this.chunks && this.chunks.length > this.$maxDiffs) { return; } @@ -276,7 +270,7 @@ class BaseDiffView { //this.updateScrollBarDecorators(); - if (this.options.foldUnchanged) { + if (this.$foldUnchangedOnInput) { this.foldUnchanged(); } } @@ -289,8 +283,8 @@ class BaseDiffView { */ $diffLines(val1, val2) { return this.diffProvider.compute(val1, val2, { - ignoreTrimWhitespace: this.options.ignoreTrimWhitespace, - maxComputationTimeMs: this.options.maxComputationTimeMs + ignoreTrimWhitespace: this.$ignoreTrimWhitespace, + maxComputationTimeMs: this.$maxComputationTimeMs }); } @@ -301,6 +295,55 @@ class BaseDiffView { this.diffProvider = provider; } + /** + * @param {EditSession} session + * @param {{ rowCount: number; rowsAbove: number; row: number; }} w + */ + $addWidget(session, w) { + let lineWidget = session.lineWidgets[w.row]; + if (lineWidget) { + w.rowsAbove += lineWidget.rowsAbove > w.rowsAbove ? lineWidget.rowsAbove : w.rowsAbove; + w.rowCount += lineWidget.rowCount; + } + session.lineWidgets[w.row] = w; + session.widgetManager.lineWidgets[w.row] = w; + session.$resetRowCache(w.row); + var fold = session.getFoldAt(w.row, 0); + if (fold) { + session.widgetManager.updateOnFold({ + data: fold, + action: "add", + }, session); + } + } + + /** + * @param {Editor} editor + */ + $initWidgets(editor) { + var session = editor.session; + if (!session.widgetManager) { + session.widgetManager = new LineWidgets(session); + session.widgetManager.attach(editor); + } + editor.session.lineWidgets = []; + editor.session.widgetManager.lineWidgets = []; + editor.session.$resetRowCache(0); + } + + /** + * @param {import("../../../ace-internal").Ace.Point} pos + * @param {EditSession} session + */ + $screenRow(pos, session) { + var row = session.documentToScreenPosition(pos).row; + var afterEnd = pos.row - session.getLength() + 1; + if (afterEnd > 0) { + row += afterEnd; + } + return row; + } + /** scroll locking * @abstract **/ @@ -329,7 +372,7 @@ class BaseDiffView { this.$updatingSelection = true; var newRange = this.transformRange(selectionRange, isOld); - if (this.options.syncSelections) { + if (this.$syncSelections) { (isOld ? this.editorB : this.editorA).session.selection.setSelectionRange(newRange); } this.$updatingSelection = false; @@ -358,11 +401,7 @@ class BaseDiffView { onChangeFold(ev, session) { var fold = ev.data; if (this.$syncingFold || !fold || !ev.action) return; - if (!this.realignPending) { - this.realignPending = true; - this.editorA.renderer.on("beforeRender", this.realign); - this.editorB.renderer.on("beforeRender", this.realign); - } + this.scheduleRealign(); const isOrig = session === this.sessionA; const other = isOrig ? this.sessionB : this.sessionA; @@ -404,6 +443,14 @@ class BaseDiffView { } } } + + scheduleRealign() { + if (!this.realignPending) { + this.realignPending = true; + this.editorA.renderer.on("beforeRender", this.realign); + this.editorB.renderer.on("beforeRender", this.realign); + } + } realign() { this.realignPending = true; @@ -415,8 +462,10 @@ class BaseDiffView { detach() { if (!this.editorA || !this.editorB) return; - this.editorA.setOptions(this.savedOptionsA); - this.editorB.setOptions(this.savedOptionsB); + if (this.savedOptionsA) + this.editorA.setOptions(this.savedOptionsA); + if (this.savedOptionsB) + this.editorB.setOptions(this.savedOptionsB); this.editorA.renderer.off("beforeRender", this.realign); this.editorB.renderer.off("beforeRender", this.realign); this.$detachEventHandlers(); @@ -618,7 +667,7 @@ class BaseDiffView { } searchHighlight(selection) { - if (this.options.syncSelections || this.inlineDiffEditor) { + if (this.$syncSelections || this.inlineDiffEditor) { return; } let currSession = selection.session; @@ -638,7 +687,6 @@ class BaseDiffView { this.sessionA.removeMarker(this.syncSelectionMarkerA.id); this.sessionB.removeMarker(this.syncSelectionMarkerB.id); } - } /*** options ***/ @@ -648,29 +696,49 @@ config.defineOptions(BaseDiffView.prototype, "DiffView", { set: function(value) { if (this.gutterLayer) { this.gutterLayer.$renderer = value ? null : emptyGutterRenderer; + this.editorA.renderer.updateFull(); } }, - initialValue: false + initialValue: true }, folding: { set: function(value) { - this.editorA.setOption("fadeFoldWidgets", value); - this.editorB.setOption("fadeFoldWidgets", value); this.editorA.setOption("showFoldWidgets", value); this.editorB.setOption("showFoldWidgets", value); + if (!value) { + var posA = []; + var posB = []; + if (this.chunks) { + this.chunks.forEach(x=>{ + posA.push(x.old.start, x.old.end); + posB.push(x.new.start, x.new.end); + }); + } + this.sessionA.unfold(posA); + this.sessionB.unfold(posB); + } } }, syncSelections: { set: function(value) { - this.options.syncSelections = value; + }, }, ignoreTrimWhitespace: { set: function(value) { - this.options.ignoreTrimWhitespace = value; + this.scheduleOnInput(); }, }, -}); + wrap: { + set: function(value) { + this.sessionA.setOption("wrap", value); + this.sessionB.setOption("wrap", value); + } + }, + maxDiffs: { + value: 5000, + }, +}); var emptyGutterRenderer = { getText: function name(params) { @@ -729,7 +797,7 @@ class DiffHighlight { opOperation = "delete"; } - var ignoreTrimWhitespace = diffView.options.ignoreTrimWhitespace; + var ignoreTrimWhitespace = diffView.$ignoreTrimWhitespace; var lineChanges = diffView.chunks; if (session.lineWidgets && !diffView.inlineDiffEditor) { diff --git a/src/ext/diff/diff_test.js b/src/ext/diff/diff_test.js index 6329e0273ff..9f95a870cc5 100644 --- a/src/ext/diff/diff_test.js +++ b/src/ext/diff/diff_test.js @@ -5,11 +5,14 @@ require("../../test/mockdom"); var {InlineDiffView} = require("./inline_diff_view"); var {DiffView} = require("./diff_view"); +var {DiffProvider} = require("./providers/default"); var ace = require("../../ace"); var Range = require("../../range").Range; var editorA, editorB, diffView; +var DEBUG = false; + function createEditor() { var editor = ace.edit(null); document.body.appendChild(editor.container); @@ -18,7 +21,51 @@ function createEditor() { editor.container.style.position = "absolute"; editor.container.style.outline = "solid"; return editor; +} + +function getValueA(lines) { + return lines.map(function(v) { + return v[0]; + }).filter(function(x) { + return x != null; + }).join("\n"); } +function getValueB(lines) { + return lines.map(function(v) { + return v.length == 2 ? v[1] : v[0]; + }).filter(function(x) { + return x != null; + }).join("\n"); +} +var simpleDiff = [ + ["a"], + ["b"], + ["c"], + [null, "inserted1"], + [null, "inserted2"], + ["e"], + ["f"], + ["g", "edited g"], + ["h"], + ["i"], +]; +var diffAtEnds = [ + [null, "only new"], + [null, "only new"], + ["a"], + ["b"], + ["c"], + ["d"], + ["e"], + ["f"], + ["g"], + ["h"], + ["i"], + ["j"], + ["k"], + ["only old", null], + ["only old2", null], +]; module.exports = { setUpSuite: function() { @@ -32,6 +79,7 @@ module.exports = { editorA.focus(); }, tearDownSuite: function() { + if (DEBUG) return; [editorA, editorB].forEach(function(editor) { if (editor) { editor.destroy(); @@ -41,40 +89,18 @@ module.exports = { }); }, tearDown: function() { + if (DEBUG) return; if (diffView) { diffView.detach(); diffView = null; } }, "test: clean detach": function() { - var values = [ - ["a"], - ["b"], - ["c"], - [null, "inserted1"], - [null, "inserted2"], - ["e"], - ["f"], - ["g", "edited g"], - ["h"], - ["i"], - ]; - - editorA.session.setValue( - values.map(function(v) { - return v[0]; - }).filter(function(x) { - return x != null; - }).join("\n") - ); - - editorB.session.setValue( - values.map(function(v) { - return v.length == 2 ? v[1] : v[0]; - }).filter(function(x) { - return x != null; - }).join("\n") - ); + var diffProvider = new DiffProvider(); + + editorA.session.setValue(getValueA(simpleDiff)); + editorB.session.setValue(getValueB(simpleDiff)); + assert.ok(!!editorA.session.widgetManager); assert.ok(!!editorB.session.widgetManager); @@ -90,12 +116,15 @@ module.exports = { var handlers = object._eventRegistry[key]; eventRegistry[key] = handlers.slice(0); } - saved[id] = [eventRegistry, object]; + saved[id] = {eventRegistry, object}; + if (/session/.test(id)) { + saved[id].$frontMarkers = Object.keys(object.$frontMarkers); + } } function checkEventRegistry() { for (var id in saved) { - var object = saved[id][1]; - var eventRegistry = saved[id][0]; + var object = saved[id].object; + var eventRegistry = saved[id].eventRegistry; for (var eventName in object._eventRegistry) { var handlers = object._eventRegistry[eventName]; var savedHandlers = eventRegistry[eventName] || []; @@ -105,6 +134,10 @@ module.exports = { assert.equal(handlers[j], eventRegistry[eventName][j], id + ":" + eventName); } } + if (saved[id].$frontMarkers) { + var frontMarkers = Object.keys(object.$frontMarkers); + assert.equal(frontMarkers + "", saved[id].$frontMarkers + "", id); + } } } saveEventRegistry(editorA); @@ -116,9 +149,11 @@ module.exports = { var diffView = new InlineDiffView({ editorA, editorB, - showSideA: true + showSideA: true, + diffProvider, }); editorA.session.addFold("---", new Range(0, 0, 2, 0)); + diffView.onInput(); diffView.resize(true); assert.equal(editorA.session.$foldData.length, 1); @@ -129,16 +164,155 @@ module.exports = { sessionB.widgetManager.attach(editorB); checkEventRegistry(); - diffView = new DiffView({editorA, editorB}); + diffView = new DiffView({editorA, editorB, diffProvider}); editorB.session.addFold("---", new Range(5, 0, 7, 0)); editorB.renderer.$loop._flush(); editorA.renderer.$loop._flush(); assert.equal(editorA.session.$foldData.length, 2); assert.equal(editorB.session.$foldData.length, 2); + diffView.onInput(); + diffView.resize(true); + + diffView.detach(); + checkEventRegistry(); + + + var diffView = new InlineDiffView({ + editorB, valueA: editorA.getValue(), + showSideB: true, + diffProvider, + }); + + diffView.onInput(); + diffView.resize(true); + diffView.detach(); checkEventRegistry(); - } + + }, + "test: diff at ends": function() { + var diffProvider = new DiffProvider(); + + var valueA = getValueA(diffAtEnds); + var valueB = getValueB(diffAtEnds); + + diffView = new InlineDiffView({ + valueA, + valueB, + showSideA: true, + diffProvider, + }, document.body); + diffView.onInput(); + diffView.resize(true); + assert.equal(diffView.chunks.length, 2); + diffView.detach(); + + diffView = new DiffView({ + valueA, + valueB, + diffProvider, + }, document.body); + diffView.onInput(); + diffView.resize(true); + assert.equal(diffView.chunks.length, 2); + + diffView.detach(); + + diffView = new InlineDiffView({ + valueA, + valueB, + showSideA: false, + }, document.body); + diffView.onInput(); + diffView.resize(true); + assert.equal(diffView.chunks.length, 0); + diffView.detach(); + }, + "test scroll": function() { + var diffProvider = new DiffProvider(); + + var valueA = getValueA(diffAtEnds); + var valueB = getValueB(diffAtEnds); + + editorA.session.setValue(valueA); + editorB.session.setValue(valueB); + + diffView = new DiffView({ + editorA, editorB, + diffProvider, + }); + + + diffView.onInput(); + diffView.resize(true); + assert.equal(diffView.chunks.length, 2); + + diffView.setDiffSession({ + sessionA: ace.createEditSession(valueA.repeat(20)), + sessionB: ace.createEditSession(valueB.repeat(20)), + }); + + diffView.onInput(); + diffView.resize(true); + assert.equal(diffView.chunks.length, 21); + diffView.editorA.setOption("animatedScroll", false); + diffView.editorB.setOption("animatedScroll", false); + + diffView.editorA.execCommand("gotoend"); + diffView.editorB.renderer.$loop._flush(); + diffView.editorA.renderer.$loop._flush(); + + assert.ok(diffView.sessionB.$scrollTop > 100); + assert.ok(diffView.sessionA.$scrollTop == diffView.sessionB.$scrollTop); + + diffView.foldUnchanged(); + assert.equal(diffView.sessionA.$foldData.length, 20); + assert.equal(diffView.sessionA.$foldData.length, 20); + + }, + + "test: restore options": function() { + var diffProvider = new DiffProvider(); + + editorA.session.setValue(getValueA(simpleDiff)); + editorB.session.setValue(getValueB(simpleDiff)); + + diffView = new InlineDiffView({ + editorA, editorB, + showSideA: true, + diffProvider, + }); + diffView.onInput(); + diffView.setOptions({ + wrap: true, + folding: false, + showOtherLineNumbers: false, + }); + diffView.resize(true); + assert.equal(diffView.chunks.length, 2); + assert.equal(editorA.getOption("wrap"), "free"); + assert.equal(diffView.editorB.getOption("wrap"), "free"); + + assert.equal(editorA.getOption("fadeFoldWidgets"), true); + assert.equal(diffView.editorB.getOption("fadeFoldWidgets"), true); + + assert.equal(diffView.editorA.getOption("showFoldWidgets"), false); + assert.equal(diffView.editorB.getOption("showFoldWidgets"), false); + + assert.ok(!!diffView.editorB.renderer.$gutterLayer.$renderer); + + diffView.detach(); + + assert.equal(editorA.getOption("wrap"), "free"); + assert.equal(editorA.getOption("fadeFoldWidgets"), false); + assert.equal(editorA.getOption("showFoldWidgets"), true); + + assert.equal(editorB.getOption("wrap"), "free"); + assert.equal(editorB.getOption("fadeFoldWidgets"), false); + assert.equal(editorB.getOption("showFoldWidgets"), true); + assert.ok(!editorB.renderer.$gutterLayer.$renderer); + }, }; diff --git a/src/ext/diff/diff_view.js b/src/ext/diff/diff_view.js index a534ee02a51..f41c80393a1 100644 --- a/src/ext/diff/diff_view.js +++ b/src/ext/diff/diff_view.js @@ -44,68 +44,39 @@ class DiffView extends BaseDiffView { align() { var diffView = this; - function add(session, w) { - let lineWidget = session.lineWidgets[w.row]; - if (lineWidget) { - w.rowsAbove += lineWidget.rowsAbove > w.rowsAbove ? lineWidget.rowsAbove : w.rowsAbove; - w.rowCount += lineWidget.rowCount; - } - session.lineWidgets[w.row] = w; - session.widgetManager.lineWidgets[w.row] = w; - session.$resetRowCache(w.row); - var fold = session.getFoldAt(w.row, 0); - if (fold) { - session.widgetManager.updateOnFold({ - data: fold, - action: "add", - }, session); - } - } - - function init(editor) { - var session = editor.session; - if (!session.widgetManager) { - session.widgetManager = new LineWidgets(session); - session.widgetManager.attach(editor); - } - editor.session.lineWidgets = []; - editor.session.widgetManager.lineWidgets = []; - editor.session.$resetRowCache(0); - } - - init(diffView.editorA); - init(diffView.editorB); + this.$initWidgets(diffView.editorA); + this.$initWidgets(diffView.editorB); diffView.chunks.forEach(function (ch) { - var diff1 = diffView.sessionA.documentToScreenPosition(ch.old.start).row; - var diff2 = diffView.sessionB.documentToScreenPosition(ch.new.start).row; + var diff1 = diffView.$screenRow(ch.old.start, diffView.sessionA); + var diff2 = diffView.$screenRow(ch.new.start, diffView.sessionB); if (diff1 < diff2) { - add(diffView.sessionA, { + diffView.$addWidget(diffView.sessionA, { rowCount: diff2 - diff1, rowsAbove: ch.old.start.row === 0 ? diff2 - diff1 : 0, row: ch.old.start.row === 0 ? 0 : ch.old.start.row - 1 }); } else if (diff1 > diff2) { - add(diffView.sessionB, { + diffView.$addWidget(diffView.sessionB, { rowCount: diff1 - diff2, rowsAbove: ch.new.start.row === 0 ? diff1 - diff2 : 0, row: ch.new.start.row === 0 ? 0 : ch.new.start.row - 1 }); } - var diff1 = diffView.sessionA.documentToScreenPosition(ch.old.end).row; - var diff2 = diffView.sessionB.documentToScreenPosition(ch.new.end).row; + var diff1 = diffView.$screenRow(ch.old.end, diffView.sessionA); + var diff2 = diffView.$screenRow(ch.new.end, diffView.sessionB); if (diff1 < diff2) { - add(diffView.sessionA, { + diffView.$addWidget(diffView.sessionA, { rowCount: diff2 - diff1, rowsAbove: ch.old.end.row === 0 ? diff2 - diff1 : 0, row: ch.old.end.row === 0 ? 0 : ch.old.end.row - 1 }); } else if (diff1 > diff2) { - add(diffView.sessionB, { + diffView.$addWidget(diffView.sessionB, { rowCount: diff1 - diff2, rowsAbove: ch.new.end.row === 0 ? diff1 - diff2 : 0, row: ch.new.end.row === 0 ? 0 : ch.new.end.row - 1 diff --git a/src/ext/diff/inline_diff_view.js b/src/ext/diff/inline_diff_view.js index 9346b0b5a46..f55c8a46e0b 100644 --- a/src/ext/diff/inline_diff_view.js +++ b/src/ext/diff/inline_diff_view.js @@ -1,6 +1,5 @@ "use strict"; -var LineWidgets = require("../../line_widgets").LineWidgets; const BaseDiffView = require("./base_diff_view").BaseDiffView; const config = require("../../config"); @@ -27,6 +26,7 @@ class InlineDiffView extends BaseDiffView { init(diffModel) { this.onSelect = this.onSelect.bind(this); this.onAfterRender = this.onAfterRender.bind(this); + this.onChangeWrapLimit = this.onChangeWrapLimit.bind(this); this.$setupModels(diffModel); @@ -62,12 +62,12 @@ class InlineDiffView extends BaseDiffView { var gutterLayerElement = this.activeEditor.renderer.$gutterLayer.element; gutterLayerElement.parentNode.insertBefore( this.gutterLayer.element, - gutterLayerElement + gutterLayerElement.nextSibling ); gutterLayerElement.style.position = "absolute"; this.gutterLayer.element.style.position = "absolute"; this.gutterLayer.element.style.width = "100%"; - this.editorA.renderer.$gutterLayer.element.style.pointerEvents = "none"; + this.gutterLayer.element.classList.add("ace_mini-diff_gutter_other"); this.gutterLayer.$updateGutterWidth = function() {}; @@ -167,12 +167,14 @@ class InlineDiffView extends BaseDiffView { var forwardEvent = (ev) => { if (!ev.domEvent) return; var screenPos = ev.editor.renderer.pixelToScreenCoordinates(ev.clientX, ev.clientY); - var posA = this.sessionA.screenToDocumentPosition(screenPos.row, screenPos.column, screenPos.offsetX); - var posB = this.sessionB.screenToDocumentPosition(screenPos.row, screenPos.column, screenPos.offsetX); - - var posAx = this.sessionA.documentToScreenPosition(posA); - var posBx = this.sessionB.documentToScreenPosition(posB); + var sessionA = this.activeEditor.session; + var sessionB = this.otherEditor.session; + var posA = sessionA.screenToDocumentPosition(screenPos.row, screenPos.column, screenPos.offsetX); + var posB = sessionB.screenToDocumentPosition(screenPos.row, screenPos.column, screenPos.offsetX); + var posAx = sessionA.documentToScreenPosition(posA); + var posBx = sessionB.documentToScreenPosition(posB); + if (ev.editor == this.activeEditor) { if (posBx.row == screenPos.row && posAx.row != screenPos.row) { if (ev.type == "mousedown") { @@ -223,50 +225,21 @@ class InlineDiffView extends BaseDiffView { align() { var diffView = this; - function add(session, w) { - let lineWidget = session.lineWidgets[w.row]; - if (lineWidget) { - w.rowsAbove += lineWidget.rowsAbove > w.rowsAbove ? lineWidget.rowsAbove : w.rowsAbove; - w.rowCount += lineWidget.rowCount; - } - session.lineWidgets[w.row] = w; - session.widgetManager.lineWidgets[w.row] = w; - session.$resetRowCache(w.row); - var fold = session.getFoldAt(w.row, 0); - if (fold) { - session.widgetManager.updateOnFold({ - data: fold, - action: "add", - }, session); - } - } - - function init(editor) { - var session = editor.session; - if (!session.widgetManager) { - session.widgetManager = new LineWidgets(session); - session.widgetManager.attach(editor); - } - editor.session.lineWidgets = []; - editor.session.widgetManager.lineWidgets = []; - editor.session.$resetRowCache(0); - } - - init(diffView.editorA); - init(diffView.editorB); + this.$initWidgets(diffView.editorA); + this.$initWidgets(diffView.editorB); diffView.chunks.forEach(function (ch) { - var diff1 = diffView.sessionA.documentToScreenPosition(ch.old.end).row - - diffView.sessionA.documentToScreenPosition(ch.old.start).row; - var diff2 = diffView.sessionB.documentToScreenPosition(ch.new.end).row - - diffView.sessionB.documentToScreenPosition(ch.new.start).row; + var diff1 = diffView.$screenRow(ch.old.end, diffView.sessionA) + - diffView.$screenRow(ch.old.start, diffView.sessionA); + var diff2 = diffView.$screenRow(ch.new.end, diffView.sessionB) + - diffView.$screenRow(ch.new.start, diffView.sessionB); - add(diffView.sessionA, { + diffView.$addWidget(diffView.sessionA, { rowCount: diff2, rowsAbove: ch.old.end.row === 0 ? diff2 : 0, row: ch.old.end.row === 0 ? 0 : ch.old.end.row - 1 }); - add(diffView.sessionB, { + diffView.$addWidget(diffView.sessionB, { rowCount: diff1, rowsAbove: diff1, row: ch.new.start.row, @@ -277,10 +250,16 @@ class InlineDiffView extends BaseDiffView { diffView.sessionB["_emit"]("changeFold", {data: {start: {row: 0}}}); } + onChangeWrapLimit() { + this.sessionB.adjustWrapLimit(this.sessionA.$wrapLimit); + this.scheduleRealign(); + } $attachSessionsEventHandlers() { this.$attachSessionEventHandlers(this.editorA, this.markerA); this.$attachSessionEventHandlers(this.editorB, this.markerB); + this.sessionA.on("changeWrapLimit", this.onChangeWrapLimit); + this.sessionA.on("changeWrapMode", this.onChangeWrapLimit); } $attachSessionEventHandlers(editor, marker) { @@ -294,6 +273,8 @@ class InlineDiffView extends BaseDiffView { this.$detachSessionHandlers(this.editorA, this.markerA); this.$detachSessionHandlers(this.editorB, this.markerB); this.otherSession.bgTokenizer.lines.fill(undefined); + this.sessionA.off("changeWrapLimit", this.onChangeWrapLimit); + this.sessionA.off("changeWrapMode", this.onChangeWrapLimit); } $detachSessionHandlers(editor, marker) { @@ -311,7 +292,6 @@ class InlineDiffView extends BaseDiffView { $detachEventHandlers() { this.$detachSessionsEventHandlers(); - this.clearSelectionMarkers(); this.activeEditor.off("input", this.onInput); this.activeEditor.renderer.off("afterRender", this.onAfterRender); this.otherSession.off("change", this.onInput); @@ -326,6 +306,7 @@ class InlineDiffView extends BaseDiffView { this.onMouseDetach(); this.selectEditor(this.activeEditor); + this.clearSelectionMarkers(); this.otherEditor.setSession(null); this.otherEditor.renderer.$loop = null; this.initTextInput(true); diff --git a/src/ext/diff/styles-css.js b/src/ext/diff/styles-css.js index 01411a3b181..466de654367 100644 --- a/src/ext/diff/styles-css.js +++ b/src/ext/diff/styles-css.js @@ -71,21 +71,33 @@ exports.cssText = ` /* gutter changes */ -.ace_mini-diff_gutter-enabled > .ace_gutter-cell { - background-color: #f0f0f0; +.ace_mini-diff_gutter-enabled > .ace_gutter-cell, +.ace_mini-diff_gutter-enabled > .ace_gutter-cell_svg-icons { padding-right: 13px; } +.ace_mini-diff_gutter_other > .ace_gutter-cell, +.ace_mini-diff_gutter_other > .ace_gutter-cell_svg-icons { + display: none; +} + +.ace_mini-diff_gutter_other { + pointer-events: none; +} + + .ace_mini-diff_gutter-enabled > .mini-diff-added { background-color: #eaffea; border-left: 3px solid #00FF00; - padding-left: 0; + padding-left: 16px; + display: block; } .ace_mini-diff_gutter-enabled > .mini-diff-deleted { background-color: #ffecec; border-left: 3px solid #FF0000; - padding-left: 0; + padding-left: 16px; + display: block; } diff --git a/types/ace-ext.d.ts b/types/ace-ext.d.ts index c5f4c67a4ef..c190183b2f1 100644 --- a/types/ace-ext.d.ts +++ b/types/ace-ext.d.ts @@ -699,26 +699,8 @@ declare module "ace-code/src/ext/diff/base_diff_view" { compute: (val1: any, val2: any, options: any) => any[]; }; container: HTMLElement; - options: { - ignoreTrimWhitespace: boolean; - maxComputationTimeMs: number; - syncSelections: boolean; - }; markerB: DiffHighlight; markerA: DiffHighlight; - /** - * @param {Object} options - The configuration options for the DiffView. - * @param {boolean} [options.ignoreTrimWhitespace=true] - Whether to ignore whitespace changes when computing diffs. - * @param {boolean} [options.foldUnchanged=false] - Whether to fold unchanged regions in the diff view. - * @param {number} [options.maxComputationTimeMs=0] - The maximum time in milliseconds to spend computing diffs (0 means no limit). - * @param {boolean} [options.syncSelections=false] - Whether to synchronize selections between the original and edited views. - */ - setOptions(options: { - ignoreTrimWhitespace?: boolean; - foldUnchanged?: boolean; - maxComputationTimeMs?: number; - syncSelections?: boolean; - }): void; showSideA: boolean; savedOptionsA: Partial; savedOptionsB: Partial; @@ -746,6 +728,7 @@ declare module "ace-code/src/ext/diff/base_diff_view" { setTheme(theme: any): void; getTheme(): any; resize(force: any): void; + scheduleOnInput(): void; selectionRangeA: any; selectionRangeB: any; setProvider(provider: import("ace-code/src/ext/diff/providers/default").DiffProvider): void; @@ -755,6 +738,7 @@ declare module "ace-code/src/ext/diff/base_diff_view" { align(): void; syncSelect(selection: any): void; updateSelectionMarker(marker: any, session: any, range: any): void; + scheduleRealign(): void; detach(): void; destroy(): void; gotoNext(dir: any): void; @@ -867,6 +851,7 @@ declare module "ace-code/src/ext/diff/inline_diff_view" { }, container?: HTMLElement); init(diffModel: any): void; onAfterRender(changes: number, renderer: import("ace-code").VirtualRenderer): void; + onChangeWrapLimit(): void; textLayer: any; markerLayer: any; gutterLayer: any; From 5209bd6c50ddddfcc5aa7402bdba6ff6391a4cb0 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Fri, 23 May 2025 13:15:22 +0400 Subject: [PATCH 1258/1293] do not use border-top for styling gutter active line (#5812) --- src/theme/cloud_editor-css.js | 19 ++++++++----------- src/theme/cloud_editor_dark-css.js | 19 ++++++++----------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/theme/cloud_editor-css.js b/src/theme/cloud_editor-css.js index 7b5448299b4..b445e68492d 100644 --- a/src/theme/cloud_editor-css.js +++ b/src/theme/cloud_editor-css.js @@ -46,23 +46,20 @@ module.exports = ` border: 1px solid #697077; } +.ace-cloud_editor .ace_gutter-active-line::before, .ace-cloud_editor .ace_marker-layer .ace_active-line { box-sizing: border-box; border-top: 1px solid #9191ac; border-bottom: 1px solid #9191ac; } -.ace-cloud_editor .ace_gutter-cell_svg-icons { - box-sizing: border-box; - border-top: 1px solid #ffffff; - border-bottom: 1px solid #ffffff; -} - -.ace-cloud_editor .ace_gutter-active-line { - background-repeat: no-repeat; - box-sizing: border-box; - border-top: 1px solid #9191ac; - border-bottom: 1px solid #9191ac; +.ace-cloud_editor .ace_gutter-active-line::before { + content: ""; + position: absolute; + height: 100%; + width: 100%; + left: 0; + z-index: 1; } .ace-cloud_editor .ace_marker-layer .ace_selected-word { diff --git a/src/theme/cloud_editor_dark-css.js b/src/theme/cloud_editor_dark-css.js index 93690c7a495..ac05e7a016e 100644 --- a/src/theme/cloud_editor_dark-css.js +++ b/src/theme/cloud_editor_dark-css.js @@ -46,23 +46,20 @@ module.exports = ` border: 1px solid #e8e8e8; } +.ace-cloud_editor_dark .ace_gutter-active-line::before, .ace-cloud_editor_dark .ace_marker-layer .ace_active-line { box-sizing: border-box; border-top: 1px solid #75777a; border-bottom: 1px solid #75777a; } -.ace-cloud_editor_dark .ace_gutter-cell_svg-icons { - box-sizing: border-box; - border-top: 1px solid #282c34; - border-bottom: 1px solid #282c34; -} - -.ace-cloud_editor_dark .ace_gutter-active-line { - background-repeat: no-repeat; - box-sizing: border-box; - border-top: 1px solid #75777a; - border-bottom: 1px solid #75777a; +.ace-cloud_editor_dark .ace_gutter-active-line::before { + content: ""; + position: absolute; + height: 100%; + width: 100%; + left: 0; + z-index: 1; } .ace-cloud_editor_dark .ace_marker-layer .ace_selected-word { From 63edabce2b15d752be495881a48eb7891154849a Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Tue, 3 Jun 2025 19:06:44 +0400 Subject: [PATCH 1259/1293] Diff view papercuts (#5815) * tweak diff viewer * update diff colors * synchronize scroll width of inline diff view * fix markers on linewidget with rowsAbove * increase coverage * fix wrap in split diff mode * fix firstRowScreen with scrollMargin * fix edge case with two line widgets on the same line --- demo/diff/index.html | 26 ++++----- src/ext/diff/base_diff_view.js | 62 ++++++++++++++++------ src/ext/diff/diff_test.js | 84 ++++++++++++++++++++++++++++-- src/ext/diff/diff_view.js | 16 +++++- src/ext/diff/inline_diff_view.js | 37 ++++++++++++- src/ext/diff/styles-css.js | 78 ++++++++++++++++----------- src/ext/options.js | 1 + src/theme/cloud_editor-css.js | 1 + src/theme/cloud_editor_dark-css.js | 1 + src/virtual_renderer.js | 5 ++ 10 files changed, 246 insertions(+), 65 deletions(-) diff --git a/demo/diff/index.html b/demo/diff/index.html index 0a60eb3d4bb..f3ff2f7b0e8 100644 --- a/demo/diff/index.html +++ b/demo/diff/index.html @@ -76,7 +76,7 @@ var {InlineDiffView} = require("ace/ext/diff/inline_diff_view"); var {DiffView} = require("ace/ext/diff/diff_view"); var {DiffProvider} = require("ace/ext/diff/providers/default"); - var {OptionPanel} = require("ace/ext/options") + var {OptionPanel, optionGroups} = require("ace/ext/options") var {buildDom} = require("ace/lib/dom"); var tollbarButtons = {}; @@ -99,16 +99,6 @@ updateButtonsState(); }; - var foldUnchanged = () => { - var checked = document.getElementById("btn-foldunchanged").checked; - diffView.options.foldUnchanged = checked; - diffView.onInput(); - if (!checked) { - diffView.diffSession.sessionA.unfold(); - diffView.diffSession.sessionB.unfold(); - } - }; - function reset() { editorA.setValue(initialValueA, -1); editorB.setValue(initialValueB, -1); @@ -170,6 +160,7 @@ syncSelections: localStorage.syncSelections != "false", showOtherLineNumbers: localStorage.showOtherLineNumbers != "false", folding: localStorage.folding != "false", + theme: localStorage.theme || "ace/theme/textmate", } function drawToolbar() { @@ -222,8 +213,19 @@ }), "Wrap" ], - ["button", {onclick: function() {diffView.foldUnchanged()}}, "Fold Unchanged"], + ["label", {}, + optionBar.renderOptionControl("", { + path: "folding", + type: "checkbox", + }), + "Folding" + ], + ["button", {onclick: function() {diffView.toggleFoldUnchanged()}}, "Fold Unchanged"], ["button", {id: "btn-reset", onclick: reset}, "Reset"], + ["label", {}, + optionBar.renderOptionControl("", optionGroups.Main.Theme), + "Theme" + ], ] buildDom(data, toolbar, tollbarButtons); } diff --git a/src/ext/diff/base_diff_view.js b/src/ext/diff/base_diff_view.js index ad0dd01f8e9..339b7b7a4e9 100644 --- a/src/ext/diff/base_diff_view.js +++ b/src/ext/diff/base_diff_view.js @@ -38,6 +38,7 @@ class BaseDiffView { this.onChangeFold = this.onChangeFold.bind(this); this.realign = this.realign.bind(this); this.onSelect = this.onSelect.bind(this); + this.onChangeWrapLimit = this.onChangeWrapLimit.bind(this); this.realignPending = false; /**@type{{sessionA: EditSession, sessionB: EditSession, chunks: DiffChunk[]}}*/this.diffSession; @@ -148,15 +149,13 @@ class BaseDiffView { } foldUnchanged() { - this.sessionA.unfold(); - this.sessionB.unfold(); - var chunks = this.chunks; var placeholder = "-".repeat(120); var prev = { old: new Range(0, 0, 0, 0), new: new Range(0, 0, 0, 0) }; + var foldsChanged = false; for (var i = 0; i < chunks.length + 1; i++) { let current = chunks[i] || { old: new Range(this.sessionA.getLength(), 0, this.sessionA.getLength(), 0), @@ -168,6 +167,7 @@ class BaseDiffView { var fold1 = this.sessionA.addFold(placeholder, new Range(s, 0, s + l, Number.MAX_VALUE)); s = prev.new.end.row + 2; var fold2 = this.sessionB.addFold(placeholder, new Range(s, 0, s + l, Number.MAX_VALUE)); + if (fold1 || fold2) foldsChanged = true; if (fold2 && fold1) { fold1["other"] = fold2; fold2["other"] = fold1; @@ -176,7 +176,23 @@ class BaseDiffView { prev = current; } + return foldsChanged; + } + unfoldUnchanged() { + var folds = this.sessionA.getAllFolds(); + for (var i = folds.length - 1; i >= 0; i--) { + var fold = folds[i]; + if (fold.placeholder.length == 120) { + this.sessionA.removeFold(fold); + } + } + } + + toggleFoldUnchanged() { + if (!this.foldUnchanged()) { + this.unfoldUnchanged(); + } } /** @@ -227,9 +243,15 @@ class BaseDiffView { return (this.editorA || this.editorB).getTheme(); } - onChangeTheme() { - this.editorA && this.editorA.setTheme(this.getTheme()); - this.editorB && this.editorB.setTheme(this.getTheme()); + onChangeTheme(e) { + var theme = e && e.theme || this.getTheme(); + + if (this.editorA && this.editorA.getTheme() !== theme) { + this.editorA.setTheme(theme); + } + if (this.editorB && this.editorB.getTheme() !== theme) { + this.editorB.setTheme(theme); + } } resize(force) { @@ -344,11 +366,14 @@ class BaseDiffView { return row; } - /** scroll locking + /** + * scroll locking * @abstract **/ - align() { - } + align() {} + + onChangeWrapLimit(e, session) {} + onSelect(e, selection) { this.searchHighlight(selection); this.syncSelect(selection); @@ -738,6 +763,14 @@ config.defineOptions(BaseDiffView.prototype, "DiffView", { maxDiffs: { value: 5000, }, + theme: { + set: function(value) { + this.setTheme(value); + }, + get: function() { + return this.editorA.getTheme(); + } + }, }); var emptyGutterRenderer = { @@ -809,12 +842,11 @@ class DiffHighlight { let start = session.documentToScreenRow(row, 0); if (lineWidget.rowsAbove > 0) { - start -= lineWidget.rowsAbove; - } else { - start++; + var range = new Range(start - lineWidget.rowsAbove, 0, start - 1, Number.MAX_VALUE); + markerLayer.drawFullLineMarker(html, range, "ace_diff aligned_diff", config); } - let end = start + lineWidget.rowCount - 1; - var range = new Range(start, 0, end, Number.MAX_VALUE); + let end = start + lineWidget.rowCount - (lineWidget.rowsAbove || 0); + var range = new Range(start + 1, 0, end, Number.MAX_VALUE); markerLayer.drawFullLineMarker(html, range, "ace_diff aligned_diff", config); } } @@ -901,7 +933,7 @@ class SyncSelectionMarker { constructor() { /**@type{number}*/this.id; this.type = "fullLine"; - this.clazz = "ace_diff selection"; + this.clazz = "ace_diff-active-line"; } update(html, markerLayer, session, config) { diff --git a/src/ext/diff/diff_test.js b/src/ext/diff/diff_test.js index 9f95a870cc5..ec37791bc4d 100644 --- a/src/ext/diff/diff_test.js +++ b/src/ext/diff/diff_test.js @@ -16,12 +16,15 @@ var DEBUG = false; function createEditor() { var editor = ace.edit(null); document.body.appendChild(editor.container); + setEditorPosition(editor); + return editor; +} +function setEditorPosition(editor) { editor.container.style.height = "200px"; editor.container.style.width = "300px"; editor.container.style.position = "absolute"; editor.container.style.outline = "solid"; - return editor; -} +} function getValueA(lines) { return lines.map(function(v) { @@ -66,12 +69,24 @@ var diffAtEnds = [ ["only old", null], ["only old2", null], ]; - +var longLinesDiff = [ + [null, "0"], + ["a"], + ["b"], + ["c", "edited c ".repeat(100)], + ["e long ".repeat(100)], + ["f"], + ["g " + "to delete ".repeat(100), "edited g"], + ["h"], + ["i"], +]; module.exports = { setUpSuite: function() { ace.config.setLoader(function(moduleName, cb) { if (moduleName == "ace/ext/error_marker") return cb(null, require("../error_marker")); + if (moduleName == "ace/theme/cloud_editor") + return cb(null, require("../../theme/cloud_editor")); }); editorA = createEditor(); editorB = createEditor(); @@ -174,6 +189,14 @@ module.exports = { diffView.onInput(); diffView.resize(true); + diffView.setTheme("ace/theme/cloud_editor"); + assert.equal(diffView.editorA.getTheme(), "ace/theme/cloud_editor"); + assert.equal(diffView.editorB.getTheme(), "ace/theme/cloud_editor"); + + diffView.editorB.setTheme("ace/theme/textmate"); + assert.equal(diffView.editorA.getTheme(), "ace/theme/textmate"); + assert.equal(diffView.editorB.getTheme(), "ace/theme/textmate"); + diffView.detach(); checkEventRegistry(); @@ -203,9 +226,16 @@ module.exports = { showSideA: true, diffProvider, }, document.body); + setEditorPosition(diffView.editorA); diffView.onInput(); diffView.resize(true); + var lineHeight = diffView.editorA.renderer.lineHeight; + assert.ok(diffView.editorA.renderer.lineHeight > 0); assert.equal(diffView.chunks.length, 2); + assert.equal(diffView.editorA.renderer.layerConfig.offset, 0); + diffView.sessionA.setScrollTop(lineHeight * 1.5); + diffView.resize(true); + assert.equal(diffView.editorA.renderer.layerConfig.offset, 0.5 * lineHeight); diffView.detach(); diffView = new DiffView({ @@ -213,6 +243,8 @@ module.exports = { valueB, diffProvider, }, document.body); + setEditorPosition(diffView.editorA); + setEditorPosition(diffView.editorB); diffView.onInput(); diffView.resize(true); assert.equal(diffView.chunks.length, 2); @@ -224,6 +256,7 @@ module.exports = { valueB, showSideA: false, }, document.body); + setEditorPosition(diffView.editorB); diffView.onInput(); diffView.resize(true); assert.equal(diffView.chunks.length, 0); @@ -266,11 +299,54 @@ module.exports = { assert.ok(diffView.sessionB.$scrollTop > 100); assert.ok(diffView.sessionA.$scrollTop == diffView.sessionB.$scrollTop); - diffView.foldUnchanged(); + diffView.toggleFoldUnchanged(); assert.equal(diffView.sessionA.$foldData.length, 20); assert.equal(diffView.sessionA.$foldData.length, 20); + diffView.toggleFoldUnchanged(); + assert.equal(diffView.sessionA.$foldData.length, 0); + assert.equal(diffView.sessionA.$foldData.length, 0); }, + "test line widget at both sides of line": function() { + var diffProvider = new DiffProvider(); + + editorA.session.setValue("a\n"); + editorB.session.setValue("\n\na\n\n"); + + diffView = new DiffView({ + editorA, editorB, + diffProvider, + }); + diffView.onInput(); + diffView.resize(true); + var markers = diffView.editorA.renderer.$markerBack.element.childNodes; + assert.equal(markers[0].className, "ace_diff aligned_diff"); + assert.equal(markers[1].className, "ace_diff aligned_diff"); + assert.equal(markers.length, 4); + }, + + "test: toggle wrap": function() { + var diffProvider = new DiffProvider(); + + editorA.session.setValue(getValueA(longLinesDiff)); + editorB.session.setValue(getValueB(longLinesDiff)); + + diffView = new DiffView({ + editorA, editorB, + diffProvider, + }); + diffView.onInput(); + diffView.setOptions({ + wrap: 20, + syncSelections: true, + }); + diffView.resize(true); + diffView.gotoNext(1); + diffView.gotoNext(1); + var posA = diffView.sessionA.documentToScreenPosition(diffView.editorA.getCursorPosition()); + var posB = diffView.sessionB.documentToScreenPosition(diffView.editorB.getCursorPosition()); + assert.equal(posA.row, posB.row); + }, "test: restore options": function() { var diffProvider = new DiffProvider(); diff --git a/src/ext/diff/diff_view.js b/src/ext/diff/diff_view.js index f41c80393a1..fe030d1bc74 100644 --- a/src/ext/diff/diff_view.js +++ b/src/ext/diff/diff_view.js @@ -40,6 +40,10 @@ class DiffView extends BaseDiffView { this.$attachEventHandlers(); } + onChangeWrapLimit() { + this.scheduleRealign(); + } + /*** scroll locking ***/ align() { var diffView = this; @@ -163,6 +167,9 @@ class DiffView extends BaseDiffView { editor.session.addDynamicMarker(marker); editor.selection.on("changeCursor", this.onSelect); editor.selection.on("changeSelection", this.onSelect); + + editor.session.on("changeWrapLimit", this.onChangeWrapLimit); + editor.session.on("changeWrapMode", this.onChangeWrapLimit); } $detachSessionsEventHandlers() { @@ -180,10 +187,14 @@ class DiffView extends BaseDiffView { editor.session.removeMarker(marker.id); editor.selection.off("changeCursor", this.onSelect); editor.selection.off("changeSelection", this.onSelect); + + editor.session.off("changeWrapLimit", this.onChangeWrapLimit); + editor.session.off("changeWrapMode", this.onChangeWrapLimit); } $attachEventHandlers() { - this.editorA.renderer.on("themeLoaded", this.onChangeTheme); + this.editorA.renderer.on("themeChange", this.onChangeTheme); + this.editorB.renderer.on("themeChange", this.onChangeTheme); this.editorA.on("mousewheel", this.onMouseWheel); this.editorB.on("mousewheel", this.onMouseWheel); @@ -196,7 +207,8 @@ class DiffView extends BaseDiffView { $detachEventHandlers() { this.$detachSessionsEventHandlers(); this.clearSelectionMarkers(); - this.editorA.renderer.off("themeLoaded", this.onChangeTheme); + this.editorA.renderer.off("themeChange", this.onChangeTheme); + this.editorB.renderer.off("themeChange", this.onChangeTheme); this.$detachEditorEventHandlers(this.editorA); this.$detachEditorEventHandlers(this.editorB); } diff --git a/src/ext/diff/inline_diff_view.js b/src/ext/diff/inline_diff_view.js index f55c8a46e0b..22270c81503 100644 --- a/src/ext/diff/inline_diff_view.js +++ b/src/ext/diff/inline_diff_view.js @@ -2,6 +2,7 @@ const BaseDiffView = require("./base_diff_view").BaseDiffView; +const Renderer = require("../../virtual_renderer").VirtualRenderer; const config = require("../../config"); class InlineDiffView extends BaseDiffView { @@ -26,7 +27,6 @@ class InlineDiffView extends BaseDiffView { init(diffModel) { this.onSelect = this.onSelect.bind(this); this.onAfterRender = this.onAfterRender.bind(this); - this.onChangeWrapLimit = this.onChangeWrapLimit.bind(this); this.$setupModels(diffModel); @@ -74,8 +74,25 @@ class InlineDiffView extends BaseDiffView { this.initMouse(); this.initTextInput(); this.initTextLayer(); + this.initRenderer(); this.$attachEventHandlers(); + this.selectEditor(this.activeEditor); + } + + initRenderer(restore) { + if (restore) { + delete this.activeEditor.renderer.$getLongestLine; + } else { + this.editorA.renderer.$getLongestLine = + this.editorB.renderer.$getLongestLine = () => { + var getLongestLine = Renderer.prototype.$getLongestLine; + return Math.max( + getLongestLine.call(this.editorA.renderer), + getLongestLine.call(this.editorB.renderer) + ); + }; + } } initTextLayer() { @@ -138,6 +155,9 @@ class InlineDiffView extends BaseDiffView { this.sessionA.removeMarker(this.syncSelectionMarkerA.id); this.sessionA.addDynamicMarker(this.syncSelectionMarkerA, true); } + this.markerLayer.element.classList.add("ace_hidden_marker-layer"); + this.activeEditor.renderer.$markerBack.element.classList.remove("ace_hidden_marker-layer"); + this.removeBracketHighlight(this.otherEditor); } else { this.activeEditor.selection.clearSelection(); this.activeEditor.textInput.setHost(this.otherEditor); @@ -152,8 +172,22 @@ class InlineDiffView extends BaseDiffView { if (this.showSideA) { this.sessionA.removeMarker(this.syncSelectionMarkerA.id); } + this.markerLayer.element.classList.remove("ace_hidden_marker-layer"); + this.activeEditor.renderer.$markerBack.element.classList.add("ace_hidden_marker-layer"); + this.removeBracketHighlight(this.activeEditor); } } + + removeBracketHighlight(editor) { + var session = editor.session; + if (session.$bracketHighlight) { + session.$bracketHighlight.markerIds.forEach(function(id) { + session.removeMarker(id); + }); + session.$bracketHighlight = null; + } + } + initMouse() { this.otherEditor.renderer.$loop = this.activeEditor.renderer.$loop; @@ -310,6 +344,7 @@ class InlineDiffView extends BaseDiffView { this.otherEditor.setSession(null); this.otherEditor.renderer.$loop = null; this.initTextInput(true); + this.initRenderer(true); this.otherEditor.destroy(); } diff --git a/src/ext/diff/styles-css.js b/src/ext/diff/styles-css.js index 466de654367..a1ba7cad901 100644 --- a/src/ext/diff/styles-css.js +++ b/src/ext/diff/styles-css.js @@ -13,10 +13,10 @@ exports.cssText = ` * Light Colors */ .ace_diff.insert { - background-color: #eaffea; /*rgb(74 251 74 / 12%); */ + background-color: #EFFFF1; } .ace_diff.delete { - background-color: #ffecec; /*rgb(251 74 74 / 12%);*/ + background-color: #FFF1F1; } .ace_diff.aligned_diff { background: rgba(206, 194, 191, 0.26); @@ -24,8 +24,8 @@ exports.cssText = ` 45deg, rgba(122, 111, 108, 0.26), rgba(122, 111, 108, 0.26) 5px, - #FFFFFF 5px, - #FFFFFF 10px + rgba(0, 0, 0, 0) 5px, + rgba(0, 0, 0, 0) 10px ); } @@ -37,36 +37,27 @@ exports.cssText = ` } .ace_diff.delete.inline.empty { - background-color: rgba(255, 128, 79, 0.8); + background-color: rgba(255, 128, 79, 0.7); width: 2px !important; } .ace_diff.insert.inline.empty { - background-color: rgba(49, 230, 96, 0.8); + background-color: rgba(49, 230, 96, 0.7); width: 2px !important; } -.ace_diff.selection { - border-bottom: 1px solid black; - border-top: 1px solid black; +.ace_diff-active-line { + border-bottom: 1px solid; + border-top: 1px solid; background: transparent; + position: absolute; + box-sizing: border-box; + border-color: #9191ac; } -/* - * Dark Colors - */ - -.ace_dark .ace_diff.insert.inline { - background-color: rgba(0, 130, 58, 0.45); -} -.ace_dark .ace_diff.delete.inline { - background-color: rgba(169, 46, 33, 0.55); -} - -.ace_dark .ace_diff.selection { - border-bottom: 1px solid white; - border-top: 1px solid white; +.ace_dark .ace_diff-active-line { background: transparent; + border-color: #75777a; } @@ -87,15 +78,15 @@ exports.cssText = ` .ace_mini-diff_gutter-enabled > .mini-diff-added { - background-color: #eaffea; - border-left: 3px solid #00FF00; + background-color: #EFFFF1; + border-left: 3px solid #2BB534; padding-left: 16px; display: block; } .ace_mini-diff_gutter-enabled > .mini-diff-deleted { - background-color: #ffecec; - border-left: 3px solid #FF0000; + background-color: #FFF1F1; + border-left: 3px solid #EA7158; padding-left: 16px; display: block; } @@ -116,10 +107,8 @@ exports.cssText = ` color: darkgray; background-color: inherit; } -.ace_fade-fold-widgets:hover .mini-diff-added:after { - display: none; -} -.ace_fade-fold-widgets:hover .mini-diff-deleted:after { +.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-added:after, +.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-deleted:after { display: none; } @@ -127,4 +116,31 @@ exports.cssText = ` filter: drop-shadow(1px 2px 3px darkgray); } +.ace_hidden_marker-layer .ace_bracket { + display: none; +} + + + +/* + * Dark Colors + */ + +.ace_dark .ace_diff.insert { + background-color: #212E25; +} +.ace_dark .ace_diff.delete { + background-color: #3F2222; +} + +.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-added { + background-color: #212E25; + border-left-color:#00802F; +} + +.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-deleted { + background-color: #3F2222; + border-left-color: #9C3838; +} + `; diff --git a/src/ext/options.js b/src/ext/options.js index f30f83f2af9..bb37028b917 100644 --- a/src/ext/options.js +++ b/src/ext/options.js @@ -401,3 +401,4 @@ class OptionPanel { oop.implement(OptionPanel.prototype, EventEmitter); exports.OptionPanel = OptionPanel; +exports.optionGroups = optionGroups; diff --git a/src/theme/cloud_editor-css.js b/src/theme/cloud_editor-css.js index b445e68492d..d93e1d9d6c2 100644 --- a/src/theme/cloud_editor-css.js +++ b/src/theme/cloud_editor-css.js @@ -60,6 +60,7 @@ module.exports = ` width: 100%; left: 0; z-index: 1; + pointer-events: none; } .ace-cloud_editor .ace_marker-layer .ace_selected-word { diff --git a/src/theme/cloud_editor_dark-css.js b/src/theme/cloud_editor_dark-css.js index ac05e7a016e..9ff17345bfe 100644 --- a/src/theme/cloud_editor_dark-css.js +++ b/src/theme/cloud_editor_dark-css.js @@ -60,6 +60,7 @@ module.exports = ` width: 100%; left: 0; z-index: 1; + pointer-events: none; } .ace-cloud_editor_dark .ace_marker-layer .ace_selected-word { diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index de7e029170c..5e276e5b611 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -1162,6 +1162,11 @@ class VirtualRenderer { firstRowHeight; offset = this.scrollTop - firstRowScreen * lineHeight; + // adjust firstRowScreen and offset in case there is a line widget above the first row + if (offset < 0 && firstRowScreen > 0) { + firstRowScreen = Math.max(0, firstRowScreen + Math.floor(offset / lineHeight)); + offset = this.scrollTop - firstRowScreen * lineHeight; + } var changes = 0; if (this.layerConfig.width != longestLine || hScrollChanged) From 35e1be52fd8172405cf0f219bab1ef7571b3363f Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Tue, 3 Jun 2025 17:17:47 +0200 Subject: [PATCH 1260/1293] release v1.42.0 --- CHANGELOG.md | 13 +++++++++++++ ace.d.ts | 2 +- build | 2 +- package.json | 2 +- src/config.js | 2 +- types/ace-modules.d.ts | 2 +- 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35a8e9ef0bf..6f66541cce4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.42.0](https://github.com/ajaxorg/ace/compare/v1.41.0...v1.42.0) (2025-06-03) + + +### Features + +* update mouse selection at user's refresh rate ([#5717](https://github.com/ajaxorg/ace/issues/5717)) ([90d72fc](https://github.com/ajaxorg/ace/commit/90d72fc95ed2a3e35725a39fa2b88c2fe6d0a44c)), closes [#5716](https://github.com/ajaxorg/ace/issues/5716) + + +### Bug Fixes + +* editor.completer would init on `enableBasicAutocompletion` option `true` ([#5756](https://github.com/ajaxorg/ace/issues/5756)) ([25a471a](https://github.com/ajaxorg/ace/commit/25a471a3ec0a7c657646a54d034709f0d3283f19)) +* missing type aliases and MarkerGroup in `ace-builds` ([#5782](https://github.com/ajaxorg/ace/issues/5782)) ([b20be1a](https://github.com/ajaxorg/ace/commit/b20be1a4591e1c566fdb0e205a75fa580885e7c6)) + ### [1.40.2](https://github.com/ajaxorg/ace/compare/v1.40.1...v1.40.2) (2025-05-02) ### [1.40.1](https://github.com/ajaxorg/ace/compare/v1.40.0...v1.40.1) (2025-04-23) diff --git a/ace.d.ts b/ace.d.ts index dddfe9a5ac3..ac416abc0a3 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1044,6 +1044,6 @@ declare module "ace-code" { import { Range } from "ace-code/src/range"; import { UndoManager } from "ace-code/src/undomanager"; import { VirtualRenderer as Renderer } from "ace-code/src/virtual_renderer"; - export var version: "1.41.0"; + export var version: "1.42.0"; export { Range, Editor, EditSession, UndoManager, Renderer as VirtualRenderer }; } diff --git a/build b/build index 939251942ec..4e0cab7c327 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 939251942ecab0d269dd5f9ff0dc824103346198 +Subproject commit 4e0cab7c3277baa41466f197490df540f758d1f8 diff --git a/package.json b/package.json index 5398385ae20..0d8cc32bfde 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.41.0", + "version": "1.42.0", "homepage": "https://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 82bfeffd088..f65056fa41e 100644 --- a/src/config.js +++ b/src/config.js @@ -197,6 +197,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.41.0"; +exports.version = "1.42.0"; diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index 5e5f10eab8b..7af10ee1a25 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -375,7 +375,7 @@ declare module "ace-code/src/config" { string ], onLoad: (module: any) => void) => void; setModuleLoader: (moduleName: any, onLoad: any) => void; - version: "1.41.0"; + version: "1.42.0"; }; export = _exports; } From b45e94cb92d757b5f09ee0966a764ed0d245ed70 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Wed, 4 Jun 2025 15:04:09 +0400 Subject: [PATCH 1261/1293] Feat: Add scroll diff decorators (#5807) * add diff decorators for split view * better offset calculation for decorators; separate ScrollDiffDecorator * improve diff scroll decorators placement * determine scroll decorator zone width by diff editor type * add tests for scroll diff decorators * fix: decorators initialization * fix: return decorators state on dispose * fix: make sure decorators restored after dispose * fix tests after merge conflicts --- src/ext/diff/base_diff_view.js | 111 ++++++++++++- src/ext/diff/diff_test.js | 80 +++++++++- src/ext/diff/providers/default.js | 1 + src/ext/diff/scroll_diff_decorator.js | 146 +++++++++++++++++ src/layer/decorators.js | 143 +++++++++-------- src/test/mockdom.js | 2 +- src/virtual_renderer.js | 12 +- types/ace-ext.d.ts | 218 +++++++++++++++++++++++++- types/ace-modules.d.ts | 21 +-- 9 files changed, 631 insertions(+), 103 deletions(-) create mode 100644 src/ext/diff/scroll_diff_decorator.js diff --git a/src/ext/diff/base_diff_view.js b/src/ext/diff/base_diff_view.js index 339b7b7a4e9..b86abc50f3e 100644 --- a/src/ext/diff/base_diff_view.js +++ b/src/ext/diff/base_diff_view.js @@ -5,6 +5,7 @@ var Range = require("../../range").Range; var dom = require("../../lib/dom"); var config = require("../../config"); var LineWidgets = require("../../line_widgets").LineWidgets; +var ScrollDiffDecorator = require("./scroll_diff_decorator").ScrollDiffDecorator; // @ts-ignore var css = require("./styles-css.js").cssText; @@ -12,6 +13,8 @@ var css = require("./styles-css.js").cssText; var Editor = require("../../editor").Editor; var Renderer = require("../../virtual_renderer").VirtualRenderer; var UndoManager = require("../../undomanager").UndoManager; +var Decorator = require("../../layer/decorators").Decorator; + require("../../theme/textmate"); // enable multiselect require("../../multi_select"); @@ -125,6 +128,8 @@ class BaseDiffView { diffModel.valueB || "")), chunks: [] }); + + this.setupScrollbars(); } addGutterDecorators() { @@ -141,7 +146,6 @@ class BaseDiffView { $setupModel(session, value) { var editor = new Editor(new Renderer(), session); editor.session.setUndoManager(new UndoManager()); - // editor.renderer.setOption("decoratorType", "diff"); if (value) { editor.setValue(value, -1); } @@ -290,13 +294,100 @@ class BaseDiffView { this.editorA && this.editorA.renderer.updateBackMarkers(); this.editorB && this.editorB.renderer.updateBackMarkers(); - //this.updateScrollBarDecorators(); + setTimeout(() => { + this.updateScrollBarDecorators(); + }, 0); if (this.$foldUnchangedOnInput) { this.foldUnchanged(); } } + setupScrollbars() { + /** + * @param {Renderer & {$scrollDecorator: ScrollDiffDecorator}} renderer + */ + const setupScrollBar = (renderer) => { + setTimeout(() => { + this.$setScrollBarDecorators(renderer); + this.updateScrollBarDecorators(); + }, 0); + }; + + if (this.inlineDiffEditor) { + setupScrollBar(this.activeEditor.renderer); + } + else { + setupScrollBar(this.editorA.renderer); + setupScrollBar(this.editorB.renderer); + } + + } + + $setScrollBarDecorators(renderer) { + if (renderer.$scrollDecorator) { + renderer.$scrollDecorator.destroy(); + } + renderer.$scrollDecorator = new ScrollDiffDecorator(renderer.scrollBarV, renderer, this.inlineDiffEditor); + renderer.$scrollDecorator.setSessions(this.sessionA, this.sessionB); + renderer.scrollBarV.setVisible(true); + renderer.scrollBarV.element.style.bottom = renderer.scrollBarH.getHeight() + "px"; + } + + $resetDecorators(renderer) { + if (renderer.$scrollDecorator) { + renderer.$scrollDecorator.destroy(); + } + renderer.$scrollDecorator = new Decorator(renderer.scrollBarV, renderer); + } + + updateScrollBarDecorators() { + if (this.inlineDiffEditor) { + if (!this.activeEditor) { + return; + } + this.activeEditor.renderer.$scrollDecorator.zones = []; + } + else { + if (!this.editorA || !this.editorB) { + return; + } + this.editorA.renderer.$scrollDecorator.zones = []; + this.editorB.renderer.$scrollDecorator.zones = []; + } + + /** + * @param {DiffChunk} change + */ + const updateDecorators = (editor, change) => { + if (!editor) { + return; + } + if (change.old.start.row != change.old.end.row) { + editor.renderer.$scrollDecorator.addZone(change.old.start.row, change.old.end.row - 1, "delete"); + } + if (change.new.start.row != change.new.end.row) { + editor.renderer.$scrollDecorator.addZone(change.new.start.row, change.new.end.row - 1, "insert"); + } + }; + + if (this.inlineDiffEditor) { + this.chunks && this.chunks.forEach((lineChange) => { + updateDecorators(this.activeEditor, lineChange); + }); + this.activeEditor.renderer.$scrollDecorator.$updateDecorators(this.activeEditor.renderer.layerConfig); + } + else { + this.chunks && this.chunks.forEach((lineChange) => { + updateDecorators(this.editorA, lineChange); + updateDecorators(this.editorB, lineChange); + }); + + this.editorA.renderer.$scrollDecorator.$updateDecorators(this.editorA.renderer.layerConfig); + this.editorB.renderer.$scrollDecorator.$updateDecorators(this.editorB.renderer.layerConfig); + } + } + /** * * @param {string[]} val1 @@ -366,7 +457,7 @@ class BaseDiffView { return row; } - /** + /** * scroll locking * @abstract **/ @@ -468,8 +559,8 @@ class BaseDiffView { } } } - - scheduleRealign() { + + scheduleRealign() { if (!this.realignPending) { this.realignPending = true; this.editorA.renderer.on("beforeRender", this.realign); @@ -500,6 +591,14 @@ class BaseDiffView { this.gutterDecoratorB && this.gutterDecoratorB.dispose(); this.sessionA.selection.clearSelection(); this.sessionB.selection.clearSelection(); + + if (this.savedOptionsA && this.savedOptionsA.customScrollbar) { + this.$resetDecorators(this.editorA.renderer); + } + if (this.savedOptionsB &&this.savedOptionsB.customScrollbar) { + this.$resetDecorators(this.editorB.renderer); + } + this.editorA = this.editorB = null; } @@ -771,7 +870,7 @@ config.defineOptions(BaseDiffView.prototype, "DiffView", { return this.editorA.getTheme(); } }, -}); +}); var emptyGutterRenderer = { getText: function name(params) { diff --git a/src/ext/diff/diff_test.js b/src/ext/diff/diff_test.js index ec37791bc4d..dfce31f916d 100644 --- a/src/ext/diff/diff_test.js +++ b/src/ext/diff/diff_test.js @@ -10,6 +10,9 @@ var {DiffProvider} = require("./providers/default"); var ace = require("../../ace"); var Range = require("../../range").Range; var editorA, editorB, diffView; +const {Decorator} = require("../../layer/decorators"); +const {ScrollDiffDecorator} = require("./scroll_diff_decorator"); + var DEBUG = false; @@ -28,14 +31,14 @@ function setEditorPosition(editor) { function getValueA(lines) { return lines.map(function(v) { - return v[0]; + return v[0]; }).filter(function(x) { return x != null; }).join("\n"); } function getValueB(lines) { return lines.map(function(v) { - return v.length == 2 ? v[1] : v[0]; + return v.length == 2 ? v[1] : v[0]; }).filter(function(x) { return x != null; }).join("\n"); @@ -191,7 +194,7 @@ module.exports = { diffView.setTheme("ace/theme/cloud_editor"); assert.equal(diffView.editorA.getTheme(), "ace/theme/cloud_editor"); - assert.equal(diffView.editorB.getTheme(), "ace/theme/cloud_editor"); + assert.equal(diffView.editorB.getTheme(), "ace/theme/cloud_editor"); diffView.editorB.setTheme("ace/theme/textmate"); assert.equal(diffView.editorA.getTheme(), "ace/theme/textmate"); @@ -212,7 +215,7 @@ module.exports = { diffView.detach(); checkEventRegistry(); - + }, "test: diff at ends": function() { var diffProvider = new DiffProvider(); @@ -353,6 +356,7 @@ module.exports = { editorA.session.setValue(getValueA(simpleDiff)); editorB.session.setValue(getValueB(simpleDiff)); + editorA.setOption("customScrollbar", true); diffView = new InlineDiffView({ editorA, editorB, @@ -378,6 +382,8 @@ module.exports = { assert.ok(!!diffView.editorB.renderer.$gutterLayer.$renderer); + assert.ok(editorA.renderer.$scrollDecorator instanceof ScrollDiffDecorator); + diffView.detach(); assert.equal(editorA.getOption("wrap"), "free"); @@ -388,9 +394,75 @@ module.exports = { assert.equal(editorB.getOption("fadeFoldWidgets"), false); assert.equal(editorB.getOption("showFoldWidgets"), true); assert.ok(!editorB.renderer.$gutterLayer.$renderer); + + assert.ok(editorA.renderer.$scrollDecorator instanceof Decorator); }, + "test split diff scroll decorators": function(done) { + editorA.session.setValue(["a", "b", "c"].join("\n")); + editorB.session.setValue(["a", "c", "X"].join("\n")); + + diffView = new DiffView({ editorA, editorB }); + diffView.setProvider(new DiffProvider()); + diffView.onInput(); + + + editorA.renderer.$loop._flush(); + editorB.renderer.$loop._flush(); + + setTimeout(() => { + assertDecoratorsPlacement(editorA, false); + done(); + }, 0); + }, + "test inline diff scroll decorators": function(done) { + editorA.session.setValue(["a", "b", "c"].join("\n")); + editorB.session.setValue(["a", "c", "X"].join("\n")); + + diffView = new InlineDiffView({ editorA, editorB, showSideA: true }); + diffView.setProvider(new DiffProvider()); + diffView.onInput(); + + editorA.renderer.$loop._flush(); + + setTimeout(() => { + assertDecoratorsPlacement(editorA, true); + done(); + }, 0); + } }; +function findPointFillStyle(imageData, y) { + const data = imageData.slice(4 * y, 4 * (y + 1)); + const a = Math.round(data[3] / 256 * 100); + if (a === 100) return "rgb(" + data.slice(0, 3).join(",") + ")"; + return "rgba(" + data.slice(0, 3).join(",") + "," + (a / 100) + ")"; +} + +function assertDecoratorsPlacement(editor, inlineDiff) { + const decoA = editor.renderer.$scrollDecorator; + const ctxA = decoA.canvas.getContext("2d"); + const delRow = 1; + const offA = decoA.sessionA.documentToScreenRow(delRow, 0) * decoA.lineHeight; + const centerA = offA + decoA.lineHeight / 2; + const yA = Math.round(decoA.heightRatio * centerA); + let imgA = ctxA.getImageData(decoA.oneZoneWidth, 0, 1, decoA.canvasHeight).data; + assert.equal(findPointFillStyle(imgA, yA), decoA.colors.light.delete); + + if (inlineDiff) { + //make sure that in inline diff, markers fills the whole line (except error decorators part) + imgA = ctxA.getImageData(decoA.canvasWidth - 1, 0, 1, decoA.canvasHeight).data; + assert.equal(findPointFillStyle(imgA, yA), decoA.colors.light.delete); + } + + const xB = decoA.oneZoneWidth * 2; + const imgB = ctxA.getImageData(xB, 0, 1, decoA.canvasHeight).data; + + const insRow = 2; + const offB = decoA.sessionB.documentToScreenRow(insRow, 0) * decoA.lineHeight; + const centerB = offB + decoA.lineHeight / 2; + const yB = Math.round(decoA.heightRatio * centerB); + assert.equal(findPointFillStyle(imgB, yB), decoA.colors.light.insert); +} if (typeof module !== "undefined" && module === require.main) { require("asyncjs").test.testcase(module.exports).exec(); diff --git a/src/ext/diff/providers/default.js b/src/ext/diff/providers/default.js index 27ff9d09f97..cf5465ede7d 100644 --- a/src/ext/diff/providers/default.js +++ b/src/ext/diff/providers/default.js @@ -2462,6 +2462,7 @@ var {DiffChunk} = require("../base_diff_view"); /** * VSCode’s computeDiff provider */ + class DiffProvider { compute(originalLines, modifiedLines, opts) { if (!opts) opts = {}; diff --git a/src/ext/diff/scroll_diff_decorator.js b/src/ext/diff/scroll_diff_decorator.js new file mode 100644 index 00000000000..6120f2d29ff --- /dev/null +++ b/src/ext/diff/scroll_diff_decorator.js @@ -0,0 +1,146 @@ +var Decorator = require("../../layer/decorators").Decorator; + +class ScrollDiffDecorator extends Decorator { + /** + * @param {import("../../../ace-internal").Ace.VScrollbar} scrollbarV + * @param {import("../../virtual_renderer").VirtualRenderer} renderer + * @param {boolean} [forInlineDiff] + */ + constructor(scrollbarV, renderer, forInlineDiff) { + super(scrollbarV, renderer); + + this.colors.dark["delete"] = "rgba(255, 18, 18, 1)"; + this.colors.dark["insert"] = "rgba(18, 136, 18, 1)"; + this.colors.light["delete"] = "rgb(255,51,51)"; + this.colors.light["insert"] = "rgb(32,133,72)"; + + this.$zones = []; + this.$forInlineDiff = forInlineDiff; + } + + /** + * @param {number} startRow + * @param {number} endRow + * @param {"delete"|"insert"} type + */ + addZone(startRow, endRow, type) { + this.$zones.push({ + startRow, + endRow, + type + }); + } + + /** + * @param {import("../../edit_session").EditSession} sessionA + * @param {import("../../edit_session").EditSession} sessionB + */ + setSessions(sessionA, sessionB) { + this.sessionA = sessionA; + this.sessionB = sessionB; + } + + $updateDecorators(config) { + super.$updateDecorators(config); + if (this.$zones.length > 0) { + var colors = (this.renderer.theme.isDark === true) ? this.colors.dark : this.colors.light; + var ctx = this.canvas.getContext("2d"); + this.$setDiffDecorators(ctx, colors); + } + } + + /** + * @param {number} row + * @param {string} type + */ + $transformPosition(row, type) { + if (type == "delete") { + return this.sessionA.documentToScreenRow(row, 0); + } else { + return this.sessionB.documentToScreenRow(row, 0); + } + } + + $setDiffDecorators(ctx, colors) { + function compare(a, b) { + if (a.from === b.from) { + return a.to - b.to; + } + return a.from - b.from; + } + + var zones = this.$zones; + if (zones) { + var resolvedZones = []; + + const deleteZones = zones.filter(z => z.type === "delete"); + const insertZones = zones.filter(z => z.type === "insert"); + + [deleteZones, insertZones].forEach((typeZones) => { + typeZones.forEach((zone, i) => { + const offset1 = this.$transformPosition(zone.startRow, zone.type) * this.lineHeight; + let offset2 = this.$transformPosition(zone.endRow, zone.type) * this.lineHeight + this.lineHeight; + + const y1 = Math.round(this.heightRatio * offset1); + const y2 = Math.round(this.heightRatio * offset2); + + const padding = 1; + + let ycenter = Math.round((y1 + y2) / 2); + let halfHeight = (y2 - ycenter); + + if (halfHeight < this.halfMinDecorationHeight) { + halfHeight = this.halfMinDecorationHeight; + } + + const previousZone = resolvedZones[resolvedZones.length - 1]; + + if (i > 0 && previousZone && previousZone.type === zone.type && ycenter - halfHeight < previousZone.to + padding) { + ycenter = resolvedZones[resolvedZones.length - 1].to + padding + halfHeight; + } + + if (ycenter - halfHeight < 0) { + ycenter = halfHeight; + } + if (ycenter + halfHeight > this.canvasHeight) { + ycenter = this.canvasHeight - halfHeight; + } + + resolvedZones.push({ + type: zone.type, + from: ycenter - halfHeight, + to: ycenter + halfHeight, + color: colors[zone.type] || null + }); + }); + }); + + resolvedZones = resolvedZones.sort(compare); + + for (const zone of resolvedZones) { + ctx.fillStyle = zone.color || null; + + const zoneFrom = zone.from; + const zoneTo = zone.to; + const zoneHeight = zoneTo - zoneFrom; + if (this.$forInlineDiff) { + ctx.fillRect(this.oneZoneWidth, zoneFrom, 2 * this.oneZoneWidth, zoneHeight); + } else { + if (zone.type == "delete") { + ctx.fillRect(this.oneZoneWidth, zoneFrom, this.oneZoneWidth, zoneHeight); + } + else { + ctx.fillRect(2 * this.oneZoneWidth, zoneFrom, this.oneZoneWidth, zoneHeight); + } + } + } + + } + } + + setZoneWidth() { + this.oneZoneWidth = Math.round(this.canvasWidth / 3); + } +} + +exports.ScrollDiffDecorator = ScrollDiffDecorator; \ No newline at end of file diff --git a/src/layer/decorators.js b/src/layer/decorators.js index c803df5916e..9fb5c71797f 100644 --- a/src/layer/decorators.js +++ b/src/layer/decorators.js @@ -4,35 +4,47 @@ var oop = require("../lib/oop"); var EventEmitter = require("../lib/event_emitter").EventEmitter; class Decorator { - constructor(parent, renderer) { - this.parentEl = parent; - this.canvas = dom.createElement("canvas"); + /** + * @param {import("../../ace-internal").Ace.VScrollbar} scrollbarV + * @param {import("../virtual_renderer").VirtualRenderer} renderer + */ + constructor(scrollbarV, renderer) { this.renderer = renderer; + this.pixelRatio = 1; this.maxHeight = renderer.layerConfig.maxHeight; this.lineHeight = renderer.layerConfig.lineHeight; this.minDecorationHeight = (2 * this.pixelRatio) | 0; this.halfMinDecorationHeight = (this.minDecorationHeight / 2) | 0; - this.canvas.style.top = 0 + "px"; - this.canvas.style.right = 0 + "px"; - this.canvas.style.zIndex = 7 + "px"; - this.canvas.style.position = "absolute"; this.colors = {}; this.colors.dark = { "error": "rgba(255, 18, 18, 1)", "warning": "rgba(18, 136, 18, 1)", - "info": "rgba(18, 18, 136, 1)" + "info": "rgba(18, 18, 136, 1)", }; this.colors.light = { "error": "rgb(255,51,51)", "warning": "rgb(32,133,72)", - "info": "rgb(35,68,138)" + "info": "rgb(35,68,138)", }; - this.setDimensions(); + this.setScrollBarV(scrollbarV); + } - parent.element.appendChild(this.canvas); + $createCanvas() { + this.canvas = dom.createElement("canvas"); + this.canvas.style.top = 0 + "px"; + this.canvas.style.right = 0 + "px"; + this.canvas.style.zIndex = "7"; + this.canvas.style.position = "absolute"; + } + + setScrollBarV(scrollbarV) { + this.$createCanvas(); + this.scrollbarV = scrollbarV; + scrollbarV.element.appendChild(this.canvas); + this.setDimensions(); } $updateDecorators(config) { @@ -56,95 +68,80 @@ class Decorator { "error": 3 }; annotations.forEach(function (item) { - item.priority = priorities[item.type] || null; + item["priority"] = priorities[item.type] || null; }); annotations = annotations.sort(compare); for (let i = 0; i < annotations.length; i++) { let row = annotations[i].row; - let compensateFold = this.compensateFoldRows(row); - let currentY = Math.round((row - compensateFold) * this.lineHeight * this.heightRatio); - let y1 = Math.round(((row - compensateFold) * this.lineHeight * this.heightRatio)); - let y2 = Math.round((((row - compensateFold) * this.lineHeight + this.lineHeight) * this.heightRatio)); - const height = y2 - y1; - if (height < this.minDecorationHeight) { - let yCenter = ((y1 + y2) / 2) | 0; - if (yCenter < this.halfMinDecorationHeight) { - yCenter = this.halfMinDecorationHeight; - } - else if (yCenter + this.halfMinDecorationHeight > this.canvasHeight) { - yCenter = this.canvasHeight - this.halfMinDecorationHeight; - } - y1 = Math.round(yCenter - this.halfMinDecorationHeight); - y2 = Math.round(yCenter + this.halfMinDecorationHeight); + const offset1 = this.getVerticalOffsetForRow(row); + const offset2 = offset1 + this.lineHeight; + + const y1 = Math.round(this.heightRatio * offset1); + const y2 = Math.round(this.heightRatio * offset2); + let ycenter = Math.round((y1 + y2) / 2); + let halfHeight = (y2 - ycenter); + + if (halfHeight < this.halfMinDecorationHeight) { + halfHeight = this.halfMinDecorationHeight; + } + if (ycenter - halfHeight < 0) { + ycenter = halfHeight; } + if (ycenter + halfHeight > this.canvasHeight) { + ycenter = this.canvasHeight - halfHeight; + } + + const from = ycenter - halfHeight; + const to = ycenter + halfHeight; + const zoneHeight = to - from; ctx.fillStyle = colors[annotations[i].type] || null; - ctx.fillRect(0, currentY, this.canvasWidth, y2 - y1); + ctx.fillRect(0, from, Math.round(this.oneZoneWidth - 1), zoneHeight); } } var cursor = this.renderer.session.selection.getCursor(); if (cursor) { - let compensateFold = this.compensateFoldRows(cursor.row); - let currentY = Math.round((cursor.row - compensateFold) * this.lineHeight * this.heightRatio); + let currentY = Math.round(this.getVerticalOffsetForRow(cursor.row) * this.heightRatio); ctx.fillStyle = "rgba(0, 0, 0, 0.5)"; ctx.fillRect(0, currentY, this.canvasWidth, 2); } } - compensateFoldRows(row) { - let foldData = this.renderer.session.$foldData; - let compensateFold = 0; - if (foldData && foldData.length > 0) { - for (let j = 0; j < foldData.length; j++) { - if (row > foldData[j].start.row && row < foldData[j].end.row) { - compensateFold += row - foldData[j].start.row; - } - else if (row >= foldData[j].end.row) { - compensateFold += foldData[j].end.row - foldData[j].start.row; - } - } - } - return compensateFold; - } - - compensateLineWidgets(row) { - const widgetManager = this.renderer.session.widgetManager; - if (widgetManager) { - let delta = 0; - widgetManager.lineWidgets.forEach((el, index) => { - if (row > index) { - delta += el.rowCount || 0; - } - }); - return delta - 1; - } - return 0; + getVerticalOffsetForRow(row) { + row = row | 0; + const offset = this.renderer.session.documentToScreenRow(row, 0) * this.lineHeight; + return offset; } setDimensions(config) { - if (config) { - this.maxHeight = config.maxHeight; - this.lineHeight = config.lineHeight; - this.canvasHeight = config.height; + config = config || this.renderer.layerConfig; + this.maxHeight = config.maxHeight; + this.lineHeight = config.lineHeight; + this.canvasHeight = config.height; + this.canvasWidth = this.scrollbarV.width || this.canvasWidth; - if (this.maxHeight < this.canvasHeight) { - this.heightRatio = 1; - } - else { - this.heightRatio = this.canvasHeight / this.maxHeight; - } + this.setZoneWidth(); + + this.canvas.width = this.canvasWidth; + this.canvas.height = this.canvasHeight; + + if (this.maxHeight < this.canvasHeight) { + this.heightRatio = 1; } else { - this.canvasHeight = this.parentEl.parent.scrollHeight || this.canvasHeight; - this.canvasWidth = this.parentEl.width || this.canvasWidth; this.heightRatio = this.canvasHeight / this.maxHeight; - - this.canvas.width = this.canvasWidth; - this.canvas.height = this.canvasHeight; } } + + setZoneWidth() { + this.oneZoneWidth = this.canvasWidth; + } + + destroy() { + this.canvas.parentNode.removeChild(this.canvas); + } } oop.implement(Decorator.prototype, EventEmitter); diff --git a/src/test/mockdom.js b/src/test/mockdom.js index 569e831eda7..25c2f02a34f 100644 --- a/src/test/mockdom.js +++ b/src/test/mockdom.js @@ -136,7 +136,7 @@ function Context2d(w, h) { this.getImageData = function(sx, sy, sw, sh) { var data = new Uint8ClampedArray(sw * sh * 4); var newIndex = 0; - for (var i = sx; i < sw + sy; i++) { + for (var i = sx; i < sw + sx; i++) { for (var j = sy; j < sh + sy; j++) { var index = (this.width * j + i) * 4; for (var k = 0; k < 4; k++) diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 5e276e5b611..4184510ae74 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -2108,9 +2108,6 @@ class VirtualRenderer { this.$horizScroll = this.$vScroll = null; this.scrollBarV.element.remove(); this.scrollBarH.element.remove(); - if (this.$scrollDecorator) { - delete this.$scrollDecorator; - } if (val === true) { /**@type {import("../ace-internal").Ace.VScrollbar}*/ this.scrollBarV = new VScrollBarCustom(this.container, this); @@ -2125,8 +2122,13 @@ class VirtualRenderer { this.scrollBarH.addEventListener("scroll", function (e) { if (!_self.$scrollAnimation) _self.session.setScrollLeft(e.data - _self.scrollMargin.left); }); - this.$scrollDecorator = new Decorator(this.scrollBarV, this); - this.$scrollDecorator.$updateDecorators(); + if (!this.$scrollDecorator) { + this.$scrollDecorator = new Decorator(this.scrollBarV, this); + this.$scrollDecorator.$updateDecorators(); + } else { + this.$scrollDecorator.setScrollBarV(this.scrollBarV); + this.$scrollDecorator.$updateDecorators(); + } } else { this.scrollBarV = new VScrollBar(this.container, this); diff --git a/types/ace-ext.d.ts b/types/ace-ext.d.ts index c190183b2f1..ca82e2434d1 100644 --- a/types/ace-ext.d.ts +++ b/types/ace-ext.d.ts @@ -450,6 +450,195 @@ declare module "ace-code/src/ext/options" { getOption(option: any): any; } export type Editor = import("ace-code/src/editor").Editor; + export namespace optionGroups { + let Main: { + Mode: { + path: string; + type: string; + items: { + caption: string; + value: string; + }[]; + }; + Theme: { + path: string; + type: string; + items: { + Bright: any[]; + Dark: any[]; + }; + }; + Keybinding: { + type: string; + path: string; + items: { + caption: string; + value: string; + }[]; + }; + "Font Size": { + path: string; + type: string; + defaultValue: number; + defaults: { + caption: string; + value: number; + }[]; + }; + "Soft Wrap": { + type: string; + path: string; + items: { + caption: string; + value: string; + }[]; + }; + "Cursor Style": { + path: string; + items: { + caption: string; + value: string; + }[]; + }; + Folding: { + path: string; + items: { + caption: string; + value: string; + }[]; + }; + "Soft Tabs": ({ + path: string; + ariaLabel?: undefined; + type?: undefined; + values?: undefined; + } | { + ariaLabel: string; + path: string; + type: string; + values: number[]; + })[]; + Overscroll: { + type: string; + path: string; + items: { + caption: string; + value: number; + }[]; + }; + }; + let More: { + "Atomic soft tabs": { + path: string; + }; + "Enable Behaviours": { + path: string; + }; + "Wrap with quotes": { + path: string; + }; + "Enable Auto Indent": { + path: string; + }; + "Full Line Selection": { + type: string; + values: string; + path: string; + }; + "Highlight Active Line": { + path: string; + }; + "Show Invisibles": { + path: string; + }; + "Show Indent Guides": { + path: string; + }; + "Highlight Indent Guides": { + path: string; + }; + "Persistent HScrollbar": { + path: string; + }; + "Persistent VScrollbar": { + path: string; + }; + "Animate scrolling": { + path: string; + }; + "Show Gutter": { + path: string; + }; + "Show Line Numbers": { + path: string; + }; + "Relative Line Numbers": { + path: string; + }; + "Fixed Gutter Width": { + path: string; + }; + "Show Print Margin": ({ + path: string; + ariaLabel?: undefined; + type?: undefined; + } | { + ariaLabel: string; + type: string; + path: string; + })[]; + "Indented Soft Wrap": { + path: string; + }; + "Highlight selected word": { + path: string; + }; + "Fade Fold Widgets": { + path: string; + }; + "Use textarea for IME": { + path: string; + }; + "Merge Undo Deltas": { + path: string; + items: { + caption: string; + value: string; + }[]; + }; + "Elastic Tabstops": { + path: string; + }; + "Incremental Search": { + path: string; + }; + "Read-only": { + path: string; + }; + "Copy without selection": { + path: string; + }; + "Live Autocompletion": { + path: string; + }; + "Custom scrollbar": { + path: string; + }; + "Use SVG gutter icons": { + path: string; + }; + "Annotations for folded lines": { + path: string; + }; + "Keyboard Accessibility Mode": { + path: string; + }; + "Gutter tooltip follows mouse": { + path: string; + defaultValue: boolean; + }; + }; + } namespace Ace { type EventEmitter any; @@ -644,8 +833,18 @@ declare module "ace-code/src/ext/whitespace" { }[]; export type EditSession = import("ace-code/src/edit_session").EditSession; } +declare module "ace-code/src/ext/diff/scroll_diff_decorator" { + export class ScrollDiffDecorator extends Decorator { + constructor(scrollbarV: import("ace-code").Ace.VScrollbar, renderer: import("ace-code/src/virtual_renderer").VirtualRenderer, forInlineDiff?: boolean); + addZone(startRow: number, endRow: number, type: "delete" | "insert"): void; + setSessions(sessionA: import("ace-code/src/edit_session").EditSession, sessionB: import("ace-code/src/edit_session").EditSession): void; + sessionA: import("ace-code/src/edit_session").EditSession; + sessionB: import("ace-code/src/edit_session").EditSession; + } + import { Decorator } from "ace-code/src/layer/decorators"; +} declare module "ace-code/src/ext/diff/styles-css" { - export const cssText: "\n/*\n * Line Markers\n */\n.ace_diff {\n position: absolute;\n z-index: 0;\n}\n.ace_diff.inline {\n z-index: 20;\n}\n/*\n * Light Colors \n */\n.ace_diff.insert {\n background-color: #eaffea; /*rgb(74 251 74 / 12%); */\n}\n.ace_diff.delete {\n background-color: #ffecec; /*rgb(251 74 74 / 12%);*/\n}\n.ace_diff.aligned_diff {\n background: rgba(206, 194, 191, 0.26);\n background: repeating-linear-gradient(\n 45deg,\n rgba(122, 111, 108, 0.26),\n rgba(122, 111, 108, 0.26) 5px,\n #FFFFFF 5px,\n #FFFFFF 10px \n );\n}\n\n.ace_diff.insert.inline {\n background-color: rgb(74 251 74 / 18%); \n}\n.ace_diff.delete.inline {\n background-color: rgb(251 74 74 / 15%);\n}\n\n.ace_diff.delete.inline.empty {\n background-color: rgba(255, 128, 79, 0.8);\n width: 2px !important;\n}\n\n.ace_diff.insert.inline.empty {\n background-color: rgba(49, 230, 96, 0.8);\n width: 2px !important;\n}\n\n.ace_diff.selection {\n border-bottom: 1px solid black;\n border-top: 1px solid black;\n background: transparent;\n}\n\n/*\n * Dark Colors \n */\n\n.ace_dark .ace_diff.insert.inline {\n background-color: rgba(0, 130, 58, 0.45);\n}\n.ace_dark .ace_diff.delete.inline {\n background-color: rgba(169, 46, 33, 0.55);\n}\n\n.ace_dark .ace_diff.selection {\n border-bottom: 1px solid white;\n border-top: 1px solid white;\n background: transparent;\n}\n \n\n/* gutter changes */\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell {\n background-color: #f0f0f0;\n padding-right: 13px;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #eaffea;\n border-left: 3px solid #00FF00;\n padding-left: 0;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #ffecec;\n border-left: 3px solid #FF0000;\n padding-left: 0;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added:after {\n position: absolute;\n right: 2px;\n content: \"+\";\n color: darkgray;\n background-color: inherit;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted:after {\n position: absolute;\n right: 2px;\n content: \"-\";\n color: darkgray;\n background-color: inherit;\n}\n.ace_fade-fold-widgets:hover .mini-diff-added:after {\n display: none;\n}\n.ace_fade-fold-widgets:hover .mini-diff-deleted:after {\n display: none;\n}\n\n.ace_diff_other .ace_selection {\n filter: drop-shadow(1px 2px 3px darkgray);\n}\n\n"; + export const cssText: "\n/*\n * Line Markers\n */\n.ace_diff {\n position: absolute;\n z-index: 0;\n}\n.ace_diff.inline {\n z-index: 20;\n}\n/*\n * Light Colors \n */\n.ace_diff.insert {\n background-color: #EFFFF1;\n}\n.ace_diff.delete {\n background-color: #FFF1F1;\n}\n.ace_diff.aligned_diff {\n background: rgba(206, 194, 191, 0.26);\n background: repeating-linear-gradient(\n 45deg,\n rgba(122, 111, 108, 0.26),\n rgba(122, 111, 108, 0.26) 5px,\n rgba(0, 0, 0, 0) 5px,\n rgba(0, 0, 0, 0) 10px \n );\n}\n\n.ace_diff.insert.inline {\n background-color: rgb(74 251 74 / 18%); \n}\n.ace_diff.delete.inline {\n background-color: rgb(251 74 74 / 15%);\n}\n\n.ace_diff.delete.inline.empty {\n background-color: rgba(255, 128, 79, 0.7);\n width: 2px !important;\n}\n\n.ace_diff.insert.inline.empty {\n background-color: rgba(49, 230, 96, 0.7);\n width: 2px !important;\n}\n\n.ace_diff-active-line {\n border-bottom: 1px solid;\n border-top: 1px solid;\n background: transparent;\n position: absolute;\n box-sizing: border-box;\n border-color: #9191ac;\n}\n\n.ace_dark .ace_diff-active-line {\n background: transparent;\n border-color: #75777a;\n}\n \n\n/* gutter changes */\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell,\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell_svg-icons {\n padding-right: 13px;\n}\n\n.ace_mini-diff_gutter_other > .ace_gutter-cell,\n.ace_mini-diff_gutter_other > .ace_gutter-cell_svg-icons {\n display: none;\n}\n\n.ace_mini-diff_gutter_other {\n pointer-events: none;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #EFFFF1;\n border-left: 3px solid #2BB534;\n padding-left: 16px;\n display: block;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #FFF1F1;\n border-left: 3px solid #EA7158;\n padding-left: 16px;\n display: block;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added:after {\n position: absolute;\n right: 2px;\n content: \"+\";\n color: darkgray;\n background-color: inherit;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted:after {\n position: absolute;\n right: 2px;\n content: \"-\";\n color: darkgray;\n background-color: inherit;\n}\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-added:after,\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-deleted:after {\n display: none;\n}\n\n.ace_diff_other .ace_selection {\n filter: drop-shadow(1px 2px 3px darkgray);\n}\n\n.ace_hidden_marker-layer .ace_bracket {\n display: none;\n}\n\n\n\n/*\n * Dark Colors \n */\n\n.ace_dark .ace_diff.insert {\n background-color: #212E25;\n}\n.ace_dark .ace_diff.delete {\n background-color: #3F2222;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #212E25;\n border-left-color:#00802F;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #3F2222;\n border-left-color: #9C3838;\n}\n\n"; } declare module "ace-code/src/ext/diff/gutter_decorator" { export class MinimalGutterDiffDecorator { @@ -681,11 +880,12 @@ declare module "ace-code/src/ext/diff/base_diff_view" { * @param {HTMLElement} [container] - optional container element for the DiffView. */ constructor(inlineDiffEditor?: boolean, container?: HTMLElement); - onChangeTheme(): void; + onChangeTheme(e: any): void; onInput(): void; onChangeFold(ev: any, session: EditSession): void; realign(): void; onSelect(e: any, selection: any): void; + onChangeWrapLimit(e: any, session: any): void; realignPending: boolean; diffSession: { sessionA: EditSession; @@ -712,7 +912,9 @@ declare module "ace-code/src/ext/diff/base_diff_view" { addGutterDecorators(): void; gutterDecoratorA: MinimalGutterDiffDecorator; gutterDecoratorB: MinimalGutterDiffDecorator; - foldUnchanged(): void; + foldUnchanged(): boolean; + unfoldUnchanged(): void; + toggleFoldUnchanged(): void; setDiffSession(session: { sessionA: any; sessionB: EditSession; @@ -731,8 +933,11 @@ declare module "ace-code/src/ext/diff/base_diff_view" { scheduleOnInput(): void; selectionRangeA: any; selectionRangeB: any; + setupScrollbars(): void; + updateScrollBarDecorators(): void; setProvider(provider: import("ace-code/src/ext/diff/providers/default").DiffProvider): void; - /** scroll locking + /** + * scroll locking * @abstract **/ align(): void; @@ -818,6 +1023,7 @@ declare module "ace-code/src/ext/diff/diff_view" { init(diffModel: any): void; onMouseWheel(ev: any): any; onScroll(e: any, session: any): void; + onChangeWrapLimit(): void; syncScroll(renderer: import("ace-code/src/virtual_renderer").VirtualRenderer): void; scrollA: any; scrollB: any; @@ -851,18 +1057,20 @@ declare module "ace-code/src/ext/diff/inline_diff_view" { }, container?: HTMLElement); init(diffModel: any): void; onAfterRender(changes: number, renderer: import("ace-code").VirtualRenderer): void; - onChangeWrapLimit(): void; textLayer: any; markerLayer: any; gutterLayer: any; cursorLayer: any; + initRenderer(restore: any): void; initTextLayer(): void; initTextInput(restore: any): void; othertextInput: any; otherEditorContainer: any; selectEditor(editor: any): void; + removeBracketHighlight(editor: any): void; initMouse(): void; onMouseDetach: () => void; + onChangeWrapLimit(): void; } import { BaseDiffView } from "ace-code/src/ext/diff/base_diff_view"; } diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index 7af10ee1a25..9db069c52f7 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -817,22 +817,25 @@ declare module "ace-code/src/css/editor-css" { } declare module "ace-code/src/layer/decorators" { export class Decorator { - constructor(parent: any, renderer: any); - parentEl: any; - canvas: HTMLCanvasElement; - renderer: any; + constructor(scrollbarV: import("ace-code").Ace.VScrollbar, renderer: import("ace-code/src/virtual_renderer").VirtualRenderer); + renderer: import("ace-code/src/virtual_renderer").VirtualRenderer; pixelRatio: number; - maxHeight: any; - lineHeight: any; + maxHeight: number; + lineHeight: number; minDecorationHeight: number; halfMinDecorationHeight: number; colors: {}; - compensateFoldRows(row: any): number; - compensateLineWidgets(row: any): number; + canvas: HTMLCanvasElement; + setScrollBarV(scrollbarV: any): void; + scrollbarV: any; + getVerticalOffsetForRow(row: any): number; setDimensions(config: any): void; canvasHeight: any; - heightRatio: number; canvasWidth: any; + heightRatio: number; + setZoneWidth(): void; + oneZoneWidth: any; + destroy(): void; } } declare module "ace-code/src/virtual_renderer" { From dd9fdf5a9b5e69a2502c7ee4fd4ea2fcb8e6092f Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Thu, 5 Jun 2025 13:27:52 +0400 Subject: [PATCH 1262/1293] Transform TextInput to es6 class (#5805) * transform to es6 class * generate types after merge * rename AriaOptions to TextInputAriaOptions for clarity --- ace-internal.d.ts | 14 +- ace.d.ts | 15 +- src/editor.js | 2 +- src/keyboard/textinput.js | 1463 +++++++++++++++++++------------------ types/ace-modules.d.ts | 76 +- 5 files changed, 848 insertions(+), 722 deletions(-) diff --git a/ace-internal.d.ts b/ace-internal.d.ts index febda4711f1..f5432c940c2 100644 --- a/ace-internal.d.ts +++ b/ace-internal.d.ts @@ -32,6 +32,7 @@ export namespace Ace { type HoverTooltip = import("ace-code/src/tooltip").HoverTooltip; type Tooltip = import("ace-code/src/tooltip").Tooltip; type PopupManager = import("ace-code/src/tooltip").PopupManager; + type TextInput = import("ace-code/src/keyboard/textinput").TextInput; type AfterLoadCallback = (err: Error | null, module: unknown) => void; type LoaderFunction = (moduleName: string, afterLoad: AfterLoadCallback) => void; @@ -967,12 +968,6 @@ export namespace Ace { new(session: EditSession): Selection; } - interface TextInput { - resetSelection(): void; - - setAriaOption(options?: { activeDescendant: string, role: string, setLabel: any }): void; - } - type CompleterCallback = (error: any, completions: Completion[]) => void; interface Completer { @@ -1292,6 +1287,13 @@ export namespace Ace { export interface ScrollbarEvents { "scroll": (e: { data: number }) => void; } + + export interface TextInputAriaOptions { + activeDescendant?: string; + role?: string; + setLabel?: boolean; + inline?: boolean; + } } diff --git a/ace.d.ts b/ace.d.ts index ac416abc0a3..74063873db7 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -41,6 +41,7 @@ declare module "ace-code" { type HoverTooltip = import("ace-code/src/tooltip").HoverTooltip; type Tooltip = import("ace-code/src/tooltip").Tooltip; type PopupManager = import("ace-code/src/tooltip").PopupManager; + type TextInput = import("ace-code/src/keyboard/textinput").TextInput; type AfterLoadCallback = (err: Error | null, module: unknown) => void; type LoaderFunction = (moduleName: string, afterLoad: AfterLoadCallback) => void; export interface ConfigOptions { @@ -775,14 +776,6 @@ declare module "ace-code" { var Selection: { new(session: EditSession): Selection; }; - interface TextInput { - resetSelection(): void; - setAriaOption(options?: { - activeDescendant: string; - role: string; - setLabel: any; - }): void; - } type CompleterCallback = (error: any, completions: Completion[]) => void; interface Completer { identifierRegexps?: Array; @@ -1032,6 +1025,12 @@ declare module "ace-code" { data: number; }) => void; } + export interface TextInputAriaOptions { + activeDescendant?: string; + role?: string; + setLabel?: boolean; + inline?: boolean; + } } export const config: typeof import("ace-code/src/config"); export function edit(el?: string | (HTMLElement & { diff --git a/src/editor.js b/src/editor.js index f9394b66d20..9f162c18c9a 100644 --- a/src/editor.js +++ b/src/editor.js @@ -906,7 +906,7 @@ class Editor { /** * - * @param {string | string[]} command + * @param {string | string[] | import("../ace-internal").Ace.Command} command * @param [args] * @return {boolean} */ diff --git a/src/keyboard/textinput.js b/src/keyboard/textinput.js index e118443245a..7de343a520d 100644 --- a/src/keyboard/textinput.js +++ b/src/keyboard/textinput.js @@ -12,7 +12,7 @@ var HAS_FOCUS_ARGS = useragent.isChrome > 63; var MAX_LINE_LENGTH = 400; /** - * + * * @type {{[key: string]: any}} */ var KEYS = require("../lib/keys"); @@ -21,273 +21,647 @@ var isIOS = useragent.isIOS; var valueResetRegex = isIOS ? /\s/ : /\n/; var isMobile = useragent.isMobile; -var TextInput; -TextInput= function(/**@type{HTMLTextAreaElement} */parentNode, /**@type{import("../editor").Editor} */host) { - /**@type {HTMLTextAreaElement & {msGetInputContext?: () => {compositionStartOffset: number}, getInputContext?: () => {compositionStartOffset: number}}}*/ - var text = dom.createElement("textarea"); - text.className = "ace_text-input"; - - text.setAttribute("wrap", "off"); - text.setAttribute("autocorrect", "off"); - text.setAttribute("autocapitalize", "off"); - text.setAttribute("spellcheck", "false"); - - text.style.opacity = "0"; - parentNode.insertBefore(text, parentNode.firstChild); - - this.setHost = function(newHost) { - host = newHost; - }; - - /**@type{boolean|string}*/var copied = false; - var pasted = false; - /**@type {(boolean|Object) & {context?: any, useTextareaForIME?: boolean, selectionStart?: number, markerRange?: any}}} */ - var inComposition = false; - var sendingText = false; - var tempStyle = ''; - - if (!isMobile) - text.style.fontSize = "1px"; - - var commandMode = false; - var ignoreFocusEvents = false; - - var lastValue = ""; - var lastSelectionStart = 0; - var lastSelectionEnd = 0; - var lastRestoreEnd = 0; - var rowStart = Number.MAX_SAFE_INTEGER; - var rowEnd = Number.MIN_SAFE_INTEGER; - var numberOfExtraLines = 0; - - // FOCUS - // ie9 throws error if document.activeElement is accessed too soon - try { var isFocused = document.activeElement === text; } catch(e) {} - - // Set number of extra lines in textarea, some screenreaders - // perform better with extra lines above and below in the textarea. - this.setNumberOfExtraLines = function(/**@type{number}*/number) { - rowStart = Number.MAX_SAFE_INTEGER; - rowEnd = Number.MIN_SAFE_INTEGER; +class TextInput { + /** + * @param {HTMLElement} parentNode + * @param {import("../editor").Editor} host + */ + constructor(parentNode, host) { + this.host = host; + /**@type {HTMLTextAreaElement & {msGetInputContext?: () => {compositionStartOffset: number}, getInputContext?: () => {compositionStartOffset: number}}}*/ + this.text = dom.createElement("textarea"); + this.text.className = "ace_text-input"; + + this.text.setAttribute("wrap", "off"); + this.text.setAttribute("autocorrect", "off"); + this.text.setAttribute("autocapitalize", "off"); + this.text.setAttribute("spellcheck", "false"); + + this.text.style.opacity = "0"; + parentNode.insertBefore(this.text, parentNode.firstChild); + + /**@type{boolean|string}*/this.copied = false; + this.pasted = false; + /**@type {(boolean|Object) & {context?: any, useTextareaForIME?: boolean, selectionStart?: number, markerRange?: any}}} */ + this.inComposition = false; + this.sendingText = false; + this.tempStyle = ''; + + if (!isMobile) this.text.style.fontSize = "1px"; + + this.commandMode = false; + this.ignoreFocusEvents = false; + + this.lastValue = ""; + this.lastSelectionStart = 0; + this.lastSelectionEnd = 0; + this.lastRestoreEnd = 0; + this.rowStart = Number.MAX_SAFE_INTEGER; + this.rowEnd = Number.MIN_SAFE_INTEGER; + this.numberOfExtraLines = 0; + + // FOCUS + // ie9 throws error if document.activeElement is accessed too soon + try { + this.$isFocused = document.activeElement === this.text; + } catch (e) { + } - if (number < 0) { - numberOfExtraLines = 0; - return; + this.cancelComposition = this.cancelComposition.bind(this); + + this.setAriaOptions({role: "textbox"}); + + event.addListener(this.text, "blur", (e) => { + if (this.ignoreFocusEvents) return; + host.onBlur(e); + this.$isFocused = false; + }, host); + event.addListener(this.text, "focus", (e) => { + if (this.ignoreFocusEvents) return; + this.$isFocused = true; + if (useragent.isEdge) { + // on edge focus event is fired even if document itself is not focused + try { + if (!document.hasFocus()) return; + } catch (e) { + } + } + host.onFocus(e); + if (useragent.isEdge) setTimeout(this.resetSelection.bind(this)); else this.resetSelection(); + }, host); + + /**@type {boolean | string}*/this.$focusScroll = false; + + host.on("beforeEndOperation", () => { + var curOp = host.curOp; + var commandName = curOp && curOp.command && curOp.command.name; + if (commandName == "insertstring") return; + var isUserAction = commandName && (curOp.docChanged || curOp.selectionChanged); + if (this.inComposition && isUserAction) { + // exit composition from commands other than insertstring + this.lastValue = this.text.value = ""; + this.onCompositionEnd(); + } + // sync value of textarea + this.resetSelection(); + }); + + // if cursor changes position, we need to update the label with the correct row + host.on("changeSelection", this.setAriaLabel.bind(this)); + + this.resetSelection = isIOS ? this.$resetSelectionIOS : this.$resetSelection; + + if (this.$isFocused) host.onFocus(); + + this.inputHandler = null; + this.afterContextMenu = false; + + event.addCommandKeyListener(this.text, (e, hashId, keyCode) => { + // ignore command events during composition as they will + // either be handled by ime itself or fired again after ime end + if (this.inComposition) return; + return host.onCommandKey(e, hashId, keyCode); + }, host); + + event.addListener(this.text, "select", this.onSelect.bind(this), host); + event.addListener(this.text, "input", this.onInput.bind(this), host); + + event.addListener(this.text, "cut", this.onCut.bind(this), host); + event.addListener(this.text, "copy", this.onCopy.bind(this), host); + event.addListener(this.text, "paste", this.onPaste.bind(this), host); + + + // Opera has no clipboard events + if (!('oncut' in this.text) || !('oncopy' in this.text) || !('onpaste' in this.text)) { + event.addListener(parentNode, "keydown", (e) => { + if ((useragent.isMac && !e.metaKey) || !e.ctrlKey) return; + + switch (e.keyCode) { + case 67: + this.onCopy(e); + break; + case 86: + this.onPaste(e); + break; + case 88: + this.onCut(e); + break; + } + }, host); } - - numberOfExtraLines = number; - }; - this.setAriaLabel = function() { - var ariaLabel = ""; - if (host.$textInputAriaLabel) { - ariaLabel += `${host.$textInputAriaLabel}, `; + this.syncComposition = lang.delayedCall(this.onCompositionUpdate.bind(this), 50).schedule.bind(null, null); //TODO: check this + + event.addListener(this.text, "compositionstart", this.onCompositionStart.bind(this), host); + event.addListener(this.text, "compositionupdate", this.onCompositionUpdate.bind(this), host); + event.addListener(this.text, "keyup", this.onKeyup.bind(this), host); + event.addListener(this.text, "keydown", this.syncComposition.bind(this), host); + event.addListener(this.text, "compositionend", this.onCompositionEnd.bind(this), host); + + this.closeTimeout; + + event.addListener(this.text, "mouseup", this.$onContextMenu.bind(this), host); + event.addListener(this.text, "mousedown", (e) => { + e.preventDefault(); + this.onContextMenuClose(); + }, host); + event.addListener(host.renderer.scroller, "contextmenu", this.$onContextMenu.bind(this), host); + event.addListener(this.text, "contextmenu", this.$onContextMenu.bind(this), host); + + if (isIOS) this.addIosSelectionHandler(parentNode, host, this.text); + } + + /** + * @internal + * @param {HTMLElement} parentNode + * @param {import("../editor").Editor} host + * @param {HTMLTextAreaElement} text + */ + addIosSelectionHandler(parentNode, host, text) { + var typingResetTimeout = null; + var typing = false; + + text.addEventListener("keydown", function (e) { + if (typingResetTimeout) clearTimeout(typingResetTimeout); + typing = true; + }, true); + + text.addEventListener("keyup", function (e) { + typingResetTimeout = setTimeout(function () { + typing = false; + }, 100); + }, true); + + // IOS doesn't fire events for arrow keys, but this unique hack changes everything! + var detectArrowKeys = (e) => { + if (document.activeElement !== text) return; + if (typing || this.inComposition || host.$mouseHandler.isMousePressed) return; + + if (this.copied) { + return; + } + var selectionStart = text.selectionStart; + var selectionEnd = text.selectionEnd; + + var key = null; + var modifier = 0; + // console.log(selectionStart, selectionEnd); + if (selectionStart == 0) { + key = KEYS.up; + } + else if (selectionStart == 1) { + key = KEYS.home; + } + else if (selectionEnd > this.lastSelectionEnd && this.lastValue[selectionEnd] == "\n") { + key = KEYS.end; + } + else if (selectionStart < this.lastSelectionStart && this.lastValue[selectionStart - 1] == " ") { + key = KEYS.left; + modifier = MODS.option; + } + else if (selectionStart < this.lastSelectionStart || (selectionStart == this.lastSelectionStart + && this.lastSelectionEnd != this.lastSelectionStart && selectionStart == selectionEnd)) { + key = KEYS.left; + } + else if (selectionEnd > this.lastSelectionEnd && this.lastValue.slice(0, selectionEnd).split( + "\n").length > 2) { + key = KEYS.down; + } + else if (selectionEnd > this.lastSelectionEnd && this.lastValue[selectionEnd - 1] == " ") { + key = KEYS.right; + modifier = MODS.option; + } + else if (selectionEnd > this.lastSelectionEnd || (selectionEnd == this.lastSelectionEnd + && this.lastSelectionEnd != this.lastSelectionStart && selectionStart == selectionEnd)) { + key = KEYS.right; + } + + if (selectionStart !== selectionEnd) modifier |= MODS.shift; + + if (key) { + var result = host.onCommandKey({}, modifier, key); + if (!result && host.commands) { + key = KEYS.keyCodeToString(key); + var command = host.commands.findKeyCommand(modifier, key); + if (command) host.execCommand(command); + } + this.lastSelectionStart = selectionStart; + this.lastSelectionEnd = selectionEnd; + this.resetSelection(""); + } + }; + // On iOS, "selectionchange" can only be attached to the document object... + document.addEventListener("selectionchange", detectArrowKeys); + host.on("destroy", function () { + document.removeEventListener("selectionchange", detectArrowKeys); + }); + } + + onContextMenuClose() { + clearTimeout(this.closeTimeout); + this.closeTimeout = setTimeout(() => { + if (this.tempStyle) { + this.text.style.cssText = this.tempStyle; + this.tempStyle = ''; + } + this.host.renderer.$isMousePressed = false; + if (this.host.renderer.$keepTextAreaAtCursor) this.host.renderer.$moveTextAreaToCursor(); + }, 0); + } + + $onContextMenu(e) { + this.host.textInput.onContextMenu(e); + this.onContextMenuClose(); + } + + /** + * @internal + * @param e + */ + onKeyup(e) { + // workaround for a bug in ie where pressing esc silently moves selection out of textarea + if (e.keyCode == 27 && this.text.value.length < this.text.selectionStart) { + if (!this.inComposition) this.lastValue = this.text.value; + this.lastSelectionStart = this.lastSelectionEnd = -1; + this.resetSelection(); } - if(host.session) { - var row = host.session.selection.cursor.row; - ariaLabel += nls("text-input.aria-label", "Cursor at row $0", [row + 1]); + this.syncComposition(); + } + + // COMPOSITION + + /** + * @internal + */ + cancelComposition() { + // force end composition + this.ignoreFocusEvents = true; + this.text.blur(); + this.text.focus(); + this.ignoreFocusEvents = false; + } + + /** + * @internal + */ + onCompositionStart(e) { + if (this.inComposition || !this.host.onCompositionStart || this.host.$readOnly) return; + + this.inComposition = {}; + + if (this.commandMode) return; + + if (e.data) this.inComposition.useTextareaForIME = false; + + setTimeout(this.onCompositionUpdate.bind(this), 0); + this.host._signal("compositionStart"); + this.host.on("mousedown", this.cancelComposition); //TODO: + + var range = this.host.getSelectionRange(); + range.end.row = range.start.row; + range.end.column = range.start.column; + this.inComposition.markerRange = range; + this.inComposition.selectionStart = this.lastSelectionStart; + this.host.onCompositionStart(this.inComposition); + + if (this.inComposition.useTextareaForIME) { + this.lastValue = this.text.value = ""; + this.lastSelectionStart = 0; + this.lastSelectionEnd = 0; + } + else { + if (this.text.msGetInputContext) this.inComposition.context = this.text.msGetInputContext(); + if (this.text.getInputContext) this.inComposition.context = this.text.getInputContext(); } - text.setAttribute("aria-label", ariaLabel); - }; + } - this.setAriaOptions = function(options) { - if (options.activeDescendant) { - text.setAttribute("aria-haspopup", "true"); - text.setAttribute("aria-autocomplete", options.inline ? "both" : "list"); - text.setAttribute("aria-activedescendant", options.activeDescendant); - } else { - text.setAttribute("aria-haspopup", "false"); - text.setAttribute("aria-autocomplete", "both"); - text.removeAttribute("aria-activedescendant"); + /** + * @internal + */ + onCompositionUpdate() { + if (!this.inComposition || !this.host.onCompositionUpdate || this.host.$readOnly) return; + if (this.commandMode) return this.cancelComposition(); + + if (this.inComposition.useTextareaForIME) { + this.host.onCompositionUpdate(this.text.value); } - if (options.role) { - text.setAttribute("role", options.role); - } - if (options.setLabel) { - text.setAttribute("aria-roledescription", nls("text-input.aria-roledescription", "editor")); - this.setAriaLabel(); + else { + var data = this.text.value; + this.sendText(data); + if (this.inComposition.markerRange) { + if (this.inComposition.context) { + this.inComposition.markerRange.start.column = this.inComposition.selectionStart = this.inComposition.context.compositionStartOffset; + } + this.inComposition.markerRange.end.column = this.inComposition.markerRange.start.column + + this.lastSelectionEnd - this.inComposition.selectionStart + this.lastRestoreEnd; + } } - }; + } - this.setAriaOptions({role: "textbox"}); + /** + * @internal + */ + onCompositionEnd(e) { + if (!this.host.onCompositionEnd || this.host.$readOnly) return; + this.inComposition = false; + this.host.onCompositionEnd(); + this.host.off("mousedown", this.cancelComposition); + // note that resetting value of textarea at this point doesn't always work + // because textarea value can be silently restored + if (e) this.onInput(); + } - event.addListener(text, "blur", function(e) { - if (ignoreFocusEvents) return; - host.onBlur(e); - isFocused = false; - }, host); - event.addListener(text, "focus", function(e) { - if (ignoreFocusEvents) return; - isFocused = true; - if (useragent.isEdge) { - // on edge focus event is fired even if document itself is not focused - try { - if (!document.hasFocus()) - return; - } catch(e) {} - } - host.onFocus(e); - if (useragent.isEdge) - setTimeout(resetSelection); - else - resetSelection(); - }, host); /** - * - * @type {boolean | string} + * @internal */ - this.$focusScroll = false; - this.focus = function() { - // On focusing on the textarea, read active row number to assistive tech. - this.setAriaOptions({ - setLabel: host.renderer.enableKeyboardAccessibility - }); + onCut(e) { + this.doCopy(e, true); + } - if (tempStyle || HAS_FOCUS_ARGS || this.$focusScroll == "browser") - return text.focus({ preventScroll: true }); + /** + * @internal + */ + onCopy(e) { + this.doCopy(e, false); + } - var top = text.style.top; - text.style.position = "fixed"; - text.style.top = "0px"; - try { - var isTransformed = text.getBoundingClientRect().top != 0; - } catch(e) { - // getBoundingClientRect on IE throws error if element is not in the dom tree - return; + /** + * @internal + */ + onPaste(e) { + var data = this.handleClipboardData(e); + if (clipboard.pasteCancelled()) return; + if (typeof data == "string") { + if (data) this.host.onPaste(data, e); + if (useragent.isIE) setTimeout(this.resetSelection); + event.preventDefault(e); } - var ancestors = []; - if (isTransformed) { - var t = text.parentElement; - while (t && t.nodeType == 1) { - ancestors.push(t); - t.setAttribute("ace_nocontext", "true"); - if (!t.parentElement && t.getRootNode) - t = t.getRootNode()["host"]; - else - t = t.parentElement; + else { + this.text.value = ""; + this.pasted = true; + } + } + + /** + * @internal + * @param {ClipboardEvent} e + * @param {boolean} isCut + */ + doCopy(e, isCut) { + var data = this.host.getCopyText(); + if (!data) return event.preventDefault(e); + + if (this.handleClipboardData(e, data)) { + if (isIOS) { + this.resetSelection(data); + this.copied = data; + setTimeout(() => { + this.copied = false; + }, 10); } + isCut ? this.host.onCut() : this.host.onCopy(); + event.preventDefault(e); } - text.focus({ preventScroll: true }); - if (isTransformed) { - ancestors.forEach(function(p) { - p.removeAttribute("ace_nocontext"); + else { + this.copied = true; + this.text.value = data; + this.text.select(); + setTimeout(() => { + this.copied = false; + this.resetSelection(); + isCut ? this.host.onCut() : this.host.onCopy(); }); } - setTimeout(function() { - text.style.position = ""; - if (text.style.top == "0px") - text.style.top = top; - }, 0); - }; - this.blur = function() { - text.blur(); - }; - this.isFocused = function() { - return isFocused; - }; - - host.on("beforeEndOperation", function() { - var curOp = host.curOp; - var commandName = curOp && curOp.command && curOp.command.name; - if (commandName == "insertstring") - return; - var isUserAction = commandName && (curOp.docChanged || curOp.selectionChanged); - if (inComposition && isUserAction) { - // exit composition from commands other than insertstring - lastValue = text.value = ""; - onCompositionEnd(); - } - // sync value of textarea - resetSelection(); - }); - - // if cursor changes position, we need to update the label with the correct row - host.on("changeSelection", this.setAriaLabel); - - // Convert from row,column position to the linear position with respect to the current - // block of lines in the textarea. - var positionToSelection = function(row, column) { - var selection = column; - - for (var i = 1; i <= row - rowStart && i < 2*numberOfExtraLines + 1; i++) { - selection += host.session.getLine(row - i).length + 1; - } - return selection; - }; - - var resetSelection = isIOS - ? function(value) { - if (!isFocused || (copied && !value) || sendingText) return; - if (!value) - value = ""; + } + + /** + * + * @internal + * @param {ClipboardEvent} e + * @param {string} [data] + * @param {boolean} [forceIEMime] + */ + handleClipboardData(e, data, forceIEMime) { + var clipboardData = e.clipboardData || window["clipboardData"]; + if (!clipboardData || BROKEN_SETDATA) return; + // using "Text" doesn't work on old webkit but ie needs it + var mime = USE_IE_MIME_TYPE || forceIEMime ? "Text" : "text/plain"; + try { + if (data) { + // Safari 5 has clipboardData object, but does not handle setData() + return clipboardData.setData(mime, data) !== false; + } + else { + return clipboardData.getData(mime); + } + } catch (e) { + if (!forceIEMime) return this.handleClipboardData(e, data, true); + } + } + + /** + * @internal + * @param e + */ + onInput(e) { + if (this.inComposition) return this.onCompositionUpdate(); + if (e && e.inputType) { + if (e.inputType == "historyUndo") return this.host.execCommand("undo"); + if (e.inputType == "historyRedo") return this.host.execCommand("redo"); + } + var data = this.text.value; + var inserted = this.sendText(data, true); + if (data.length > MAX_LINE_LENGTH + 100 || valueResetRegex.test(inserted) || isMobile && this.lastSelectionStart + < 1 && this.lastSelectionStart == this.lastSelectionEnd) { + this.resetSelection(); + } + } + + /** + * @internal + * @param {string} value + * @param {boolean} [fromInput] + * @return {string} + */ + sendText(value, fromInput) { + if (this.afterContextMenu) this.afterContextMenu = false; + if (this.pasted) { + this.resetSelection(); + if (value) this.host.onPaste(value); + this.pasted = false; + return ""; + } + else { + var selectionStart = this.text.selectionStart; + var selectionEnd = this.text.selectionEnd; + + var extendLeft = this.lastSelectionStart; + var extendRight = this.lastValue.length - this.lastSelectionEnd; + + var inserted = value; + var restoreStart = value.length - selectionStart; + var restoreEnd = value.length - selectionEnd; + + var i = 0; + while (extendLeft > 0 && this.lastValue[i] == value[i]) { + i++; + extendLeft--; + } + inserted = inserted.slice(i); + i = 1; + while (extendRight > 0 && this.lastValue.length - i > this.lastSelectionStart - 1 + && this.lastValue[this.lastValue.length - i] == value[value.length - i]) { + i++; + extendRight--; + } + restoreStart -= i - 1; + restoreEnd -= i - 1; + var endIndex = inserted.length - i + 1; + if (endIndex < 0) { + extendLeft = -endIndex; + endIndex = 0; + } + inserted = inserted.slice(0, endIndex); + + // composition update can be called without any change + if (!fromInput && !inserted && !restoreStart && !extendLeft && !extendRight && !restoreEnd) return ""; + this.sendingText = true; + + // some android keyboards converts two spaces into sentence end, which is not useful for code + var shouldReset = false; + if (useragent.isAndroid && inserted == ". ") { + inserted = " "; + shouldReset = true; + } + + if (inserted && !extendLeft && !extendRight && !restoreStart && !restoreEnd || this.commandMode) { + this.host.onTextInput(inserted); + } + else { + this.host.onTextInput(inserted, { + extendLeft: extendLeft, + extendRight: extendRight, + restoreStart: restoreStart, + restoreEnd: restoreEnd + }); + } + this.sendingText = false; + + this.lastValue = value; + this.lastSelectionStart = selectionStart; + this.lastSelectionEnd = selectionEnd; + this.lastRestoreEnd = restoreEnd; + return shouldReset ? "\n" : inserted; + } + } + + /** + * @internal + * @param e + */ + onSelect(e) { + if (this.inComposition) return; + + var isAllSelected = (text) => { + return text.selectionStart === 0 && text.selectionEnd >= this.lastValue.length && text.value + === this.lastValue && this.lastValue && text.selectionEnd !== this.lastSelectionEnd; + }; + + if (this.copied) { + this.copied = false; + } + else if (isAllSelected(this.text)) { + this.host.selectAll(); + this.resetSelection(); + } + else if (isMobile && this.text.selectionStart != this.lastSelectionStart) { + this.resetSelection(); + } + } + + $resetSelectionIOS(value) { + if (!this.$isFocused || (this.copied && !value) || this.sendingText) return; + if (!value) value = ""; var newValue = "\n ab" + value + "cde fg\n"; - if (newValue != text.value) - text.value = lastValue = newValue; - + if (newValue != this.text.value) this.text.value = this.lastValue = newValue; + var selectionStart = 4; - var selectionEnd = 4 + (value.length || (host.selection.isEmpty() ? 0 : 1)); + var selectionEnd = 4 + (value.length || (this.host.selection.isEmpty() ? 0 : 1)); - if (lastSelectionStart != selectionStart || lastSelectionEnd != selectionEnd) { - text.setSelectionRange(selectionStart, selectionEnd); + if (this.lastSelectionStart != selectionStart || this.lastSelectionEnd != selectionEnd) { + this.text.setSelectionRange(selectionStart, selectionEnd); } - lastSelectionStart = selectionStart; - lastSelectionEnd = selectionEnd; + this.lastSelectionStart = selectionStart; + this.lastSelectionEnd = selectionEnd; } - : function() { - if (inComposition || sendingText) - return; + + $resetSelection() { + if (this.inComposition || this.sendingText) return; // modifying selection of blured textarea can focus it (chrome mac/linux) - if (!isFocused && !afterContextMenu) - return; + if (!this.$isFocused && !this.afterContextMenu) return; // see https://github.com/ajaxorg/ace/issues/2114 // this prevents infinite recursion on safari 8 - inComposition = true; - + this.inComposition = true; + var selectionStart = 0; var selectionEnd = 0; var line = ""; - if (host.session) { - var selection = host.selection; + // Convert from row,column position to the linear position with respect to the current + // block of lines in the textarea. + var positionToSelection = (row, column) => { + var selection = column; + + for (var i = 1; i <= row - this.rowStart && i < 2 * this.numberOfExtraLines + 1; i++) { + selection += this.host.session.getLine(row - i).length + 1; + } + return selection; + }; + + if (this.host.session) { + var selection = this.host.selection; var range = selection.getRange(); var row = selection.cursor.row; // We keep 2*numberOfExtraLines + 1 lines in the textarea, if the new active row // is within the current block of lines in the textarea we do nothing. If the new row // is one row above or below the current block, move up or down to the next block of lines. - // If the new row is further than 1 row away from the current block grab a new block centered + // If the new row is further than 1 row away from the current block grab a new block centered // around the new row. - if (row === rowEnd + 1) { - rowStart = rowEnd + 1; - rowEnd = rowStart + 2*numberOfExtraLines; - } else if (row === rowStart - 1) { - rowEnd = rowStart - 1; - rowStart = rowEnd - 2*numberOfExtraLines; - } else if (row < rowStart - 1 || row > rowEnd + 1) { - rowStart = row > numberOfExtraLines ? row - numberOfExtraLines : 0; - rowEnd = row > numberOfExtraLines ? row + numberOfExtraLines : 2*numberOfExtraLines; - } - + if (row === this.rowEnd + 1) { + this.rowStart = this.rowEnd + 1; + this.rowEnd = this.rowStart + 2 * this.numberOfExtraLines; + } + else if (row === this.rowStart - 1) { + this.rowEnd = this.rowStart - 1; + this.rowStart = this.rowEnd - 2 * this.numberOfExtraLines; + } + else if (row < this.rowStart - 1 || row > this.rowEnd + 1) { + this.rowStart = row > this.numberOfExtraLines ? row - this.numberOfExtraLines : 0; + this.rowEnd = row > this.numberOfExtraLines ? row + this.numberOfExtraLines : 2 + * this.numberOfExtraLines; + } + var lines = []; - for (var i = rowStart; i <= rowEnd; i++) { - lines.push(host.session.getLine(i)); + for (var i = this.rowStart; i <= this.rowEnd; i++) { + lines.push(this.host.session.getLine(i)); } - + line = lines.join('\n'); selectionStart = positionToSelection(range.start.row, range.start.column); selectionEnd = positionToSelection(range.end.row, range.end.column); - - if (range.start.row < rowStart) { - var prevLine = host.session.getLine(rowStart - 1); - selectionStart = range.start.row < rowStart - 1 ? 0 : selectionStart; + + if (range.start.row < this.rowStart) { + var prevLine = this.host.session.getLine(this.rowStart - 1); + selectionStart = range.start.row < this.rowStart - 1 ? 0 : selectionStart; selectionEnd += prevLine.length + 1; line = prevLine + "\n" + line; } - else if (range.end.row > rowEnd) { - var nextLine = host.session.getLine(rowEnd + 1); - selectionEnd = range.end.row > rowEnd + 1 ? nextLine.length : range.end.column; + else if (range.end.row > this.rowEnd) { + var nextLine = this.host.session.getLine(this.rowEnd + 1); + selectionEnd = range.end.row > this.rowEnd + 1 ? nextLine.length : range.end.column; selectionEnd += line.length + 1; line = line + "\n" + nextLine; } @@ -300,7 +674,8 @@ TextInput= function(/**@type{HTMLTextAreaElement} */parentNode, /**@type{import( if (line.length > MAX_LINE_LENGTH) { if (selectionStart < MAX_LINE_LENGTH && selectionEnd < MAX_LINE_LENGTH) { line = line.slice(0, MAX_LINE_LENGTH); - } else { + } + else { line = "\n"; if (selectionStart == selectionEnd) { selectionStart = selectionEnd = 0; @@ -311,536 +686,216 @@ TextInput= function(/**@type{HTMLTextAreaElement} */parentNode, /**@type{import( } } } - + var newValue = line + "\n\n"; - if (newValue != lastValue) { - text.value = lastValue = newValue; - lastSelectionStart = lastSelectionEnd = newValue.length; + if (newValue != this.lastValue) { + this.text.value = this.lastValue = newValue; + this.lastSelectionStart = this.lastSelectionEnd = newValue.length; } } - + // contextmenu on mac may change the selection - if (afterContextMenu) { - lastSelectionStart = text.selectionStart; - lastSelectionEnd = text.selectionEnd; + if (this.afterContextMenu) { + this.lastSelectionStart = this.text.selectionStart; + this.lastSelectionEnd = this.text.selectionEnd; } // on firefox this throws if textarea is hidden - if ( - lastSelectionEnd != selectionEnd - || lastSelectionStart != selectionStart - || text.selectionEnd != lastSelectionEnd // on ie edge selectionEnd changes silently after the initialization + if (this.lastSelectionEnd != selectionEnd || this.lastSelectionStart != selectionStart || this.text.selectionEnd + != this.lastSelectionEnd // on ie edge selectionEnd changes silently after the initialization ) { try { - text.setSelectionRange(selectionStart, selectionEnd); - lastSelectionStart = selectionStart; - lastSelectionEnd = selectionEnd; - } catch(e){} + this.text.setSelectionRange(selectionStart, selectionEnd); + this.lastSelectionStart = selectionStart; + this.lastSelectionEnd = selectionEnd; + } catch (e) { + } } - inComposition = false; - }; - this.resetSelection = resetSelection; - - if (isFocused) - host.onFocus(); + this.inComposition = false; + } + /** + * @param {import("../editor").Editor} newHost + */ + setHost(newHost) { + this.host = newHost; + } - var isAllSelected = function(text) { - return text.selectionStart === 0 && text.selectionEnd >= lastValue.length - && text.value === lastValue && lastValue - && text.selectionEnd !== lastSelectionEnd; - }; + /** + * Sets the number of extra lines in the textarea to improve screen reader compatibility. + * Extra lines can help screen readers perform better when reading text. + * + * @param {number} number - The number of extra lines to add. Must be non-negative. + */ + setNumberOfExtraLines(number) { + this.rowStart = Number.MAX_SAFE_INTEGER; + this.rowEnd = Number.MIN_SAFE_INTEGER; - var onSelect = function(e) { - if (inComposition) - return; - if (copied) { - copied = false; - } else if (isAllSelected(text)) { - host.selectAll(); - resetSelection(); - } else if (isMobile && text.selectionStart != lastSelectionStart) { - resetSelection(); - } - }; - - - var inputHandler = null; - this.setInputHandler = function(cb) {inputHandler = cb;}; - this.getInputHandler = function() {return inputHandler;}; - var afterContextMenu = false; - - var sendText = function(value, fromInput) { - if (afterContextMenu) - afterContextMenu = false; - if (pasted) { - resetSelection(); - if (value) - host.onPaste(value); - pasted = false; - return ""; - } else { - var selectionStart = text.selectionStart; - var selectionEnd = text.selectionEnd; - - var extendLeft = lastSelectionStart; - var extendRight = lastValue.length - lastSelectionEnd; - - var inserted = value; - var restoreStart = value.length - selectionStart; - var restoreEnd = value.length - selectionEnd; - - var i = 0; - while (extendLeft > 0 && lastValue[i] == value[i]) { - i++; - extendLeft--; - } - inserted = inserted.slice(i); - i = 1; - while (extendRight > 0 && lastValue.length - i > lastSelectionStart - 1 && lastValue[lastValue.length - i] == value[value.length - i]) { - i++; - extendRight--; - } - restoreStart -= i-1; - restoreEnd -= i-1; - var endIndex = inserted.length - i + 1; - if (endIndex < 0) { - extendLeft = -endIndex; - endIndex = 0; - } - inserted = inserted.slice(0, endIndex); - - // composition update can be called without any change - if (!fromInput && !inserted && !restoreStart && !extendLeft && !extendRight && !restoreEnd) - return ""; - sendingText = true; - - // some android keyboards converts two spaces into sentence end, which is not useful for code - var shouldReset = false; - if (useragent.isAndroid && inserted == ". ") { - inserted = " "; - shouldReset = true; - } - - if (inserted && !extendLeft && !extendRight && !restoreStart && !restoreEnd || commandMode) { - host.onTextInput(inserted); - } else { - host.onTextInput(inserted, { - extendLeft: extendLeft, - extendRight: extendRight, - restoreStart: restoreStart, - restoreEnd: restoreEnd - }); - } - sendingText = false; - - lastValue = value; - lastSelectionStart = selectionStart; - lastSelectionEnd = selectionEnd; - lastRestoreEnd = restoreEnd; - return shouldReset ? "\n" : inserted; - } - }; - var onInput = function(e) { - if (inComposition) - return onCompositionUpdate(); - if (e && e.inputType) { - if (e.inputType == "historyUndo") return host.execCommand("undo"); - if (e.inputType == "historyRedo") return host.execCommand("redo"); - } - var data = text.value; - var inserted = sendText(data, true); - if ( - data.length > MAX_LINE_LENGTH + 100 - || valueResetRegex.test(inserted) - || isMobile && lastSelectionStart < 1 && lastSelectionStart == lastSelectionEnd - ) { - resetSelection(); - } - }; - - var handleClipboardData = function(e, data, forceIEMime) { - var clipboardData = e.clipboardData || window["clipboardData"]; - if (!clipboardData || BROKEN_SETDATA) + if (number < 0) { + this.numberOfExtraLines = 0; return; - // using "Text" doesn't work on old webkit but ie needs it - var mime = USE_IE_MIME_TYPE || forceIEMime ? "Text" : "text/plain"; - try { - if (data) { - // Safari 5 has clipboardData object, but does not handle setData() - return clipboardData.setData(mime, data) !== false; - } else { - return clipboardData.getData(mime); - } - } catch(e) { - if (!forceIEMime) - return handleClipboardData(e, data, true); } - }; - var doCopy = function(e, isCut) { - var data = host.getCopyText(); - if (!data) - return event.preventDefault(e); + this.numberOfExtraLines = number; + } - if (handleClipboardData(e, data)) { - if (isIOS) { - resetSelection(data); - copied = data; - setTimeout(function () { - copied = false; - }, 10); - } - isCut ? host.onCut() : host.onCopy(); - event.preventDefault(e); - } else { - copied = true; - text.value = data; - text.select(); - setTimeout(function(){ - copied = false; - resetSelection(); - isCut ? host.onCut() : host.onCopy(); - }); + + setAriaLabel() { + var ariaLabel = ""; + if (this.host.$textInputAriaLabel) { + ariaLabel += `${this.host.$textInputAriaLabel}, `; } - }; - - var onCut = function(e) { - doCopy(e, true); - }; - - var onCopy = function(e) { - doCopy(e, false); - }; - - var onPaste = function(e) { - var data = handleClipboardData(e); - if (clipboard.pasteCancelled()) - return; - if (typeof data == "string") { - if (data) - host.onPaste(data, e); - if (useragent.isIE) - setTimeout(resetSelection); - event.preventDefault(e); + if (this.host.session) { + var row = this.host.session.selection.cursor.row; + ariaLabel += nls("text-input.aria-label", "Cursor at row $0", [row + 1]); + } + this.text.setAttribute("aria-label", ariaLabel); + } + + /** + * @param {import("../../ace-internal").Ace.TextInputAriaOptions} options + */ + setAriaOptions(options) { + if (options.activeDescendant) { + this.text.setAttribute("aria-haspopup", "true"); + this.text.setAttribute("aria-autocomplete", options.inline ? "both" : "list"); + this.text.setAttribute("aria-activedescendant", options.activeDescendant); } else { - text.value = ""; - pasted = true; + this.text.setAttribute("aria-haspopup", "false"); + this.text.setAttribute("aria-autocomplete", "both"); + this.text.removeAttribute("aria-activedescendant"); } - }; - - event.addCommandKeyListener(text, function(e, hashId, keyCode) { - // ignore command events during composition as they will - // either be handled by ime itself or fired again after ime end - if (inComposition) return; - return host.onCommandKey(e, hashId, keyCode); - }, host); + if (options.role) { + this.text.setAttribute("role", options.role); + } + if (options.setLabel) { + this.text.setAttribute("aria-roledescription", nls("text-input.aria-roledescription", "editor")); + this.setAriaLabel(); + } + } - event.addListener(text, "select", onSelect, host); - event.addListener(text, "input", onInput, host); + focus() { + // On focusing on the textarea, read active row number to assistive tech. + this.setAriaOptions({ + setLabel: this.host.renderer.enableKeyboardAccessibility + }); - event.addListener(text, "cut", onCut, host); - event.addListener(text, "copy", onCopy, host); - event.addListener(text, "paste", onPaste, host); + if (this.tempStyle || HAS_FOCUS_ARGS || this.$focusScroll == "browser") return this.text.focus( + {preventScroll: true}); + var top = this.text.style.top; + this.text.style.position = "fixed"; + this.text.style.top = "0px"; + try { + var isTransformed = this.text.getBoundingClientRect().top != 0; + } catch (e) { + // getBoundingClientRect on IE throws error if element is not in the dom tree + return; + } + var ancestors = []; + if (isTransformed) { + var t = this.text.parentElement; + while (t && t.nodeType == 1) { + ancestors.push(t); + t.setAttribute("ace_nocontext", "true"); + if (!t.parentElement && t.getRootNode) t = t.getRootNode()["host"]; else t = t.parentElement; + } + } + this.text.focus({preventScroll: true}); + if (isTransformed) { + ancestors.forEach(function (p) { + p.removeAttribute("ace_nocontext"); + }); + } + setTimeout(() => { + this.text.style.position = ""; + if (this.text.style.top == "0px") this.text.style.top = top; + }, 0); + } - // Opera has no clipboard events - if (!('oncut' in text) || !('oncopy' in text) || !('onpaste' in text)) { - event.addListener(parentNode, "keydown", function(e) { - if ((useragent.isMac && !e.metaKey) || !e.ctrlKey) - return; + blur() { + this.text.blur(); + } - switch (e.keyCode) { - case 67: - onCopy(e); - break; - case 86: - onPaste(e); - break; - case 88: - onCut(e); - break; - } - }, host); + isFocused() { + return this.$isFocused; } + setInputHandler(cb) { + this.inputHandler = cb; + } - // COMPOSITION - var onCompositionStart = function(e) { - if (inComposition || !host.onCompositionStart || host.$readOnly) - return; - - inComposition = {}; + getInputHandler() { + return this.inputHandler; + } - if (commandMode) - return; - - if (e.data) - inComposition.useTextareaForIME = false; - - setTimeout(onCompositionUpdate, 0); - host._signal("compositionStart"); - host.on("mousedown", cancelComposition); - - var range = host.getSelectionRange(); - range.end.row = range.start.row; - range.end.column = range.start.column; - inComposition.markerRange = range; - inComposition.selectionStart = lastSelectionStart; - host.onCompositionStart(inComposition); - - if (inComposition.useTextareaForIME) { - lastValue = text.value = ""; - lastSelectionStart = 0; - lastSelectionEnd = 0; - } - else { - if (text.msGetInputContext) - inComposition.context = text.msGetInputContext(); - if (text.getInputContext) - inComposition.context = text.getInputContext(); - } - }; + getElement() { + return this.text; + } - var onCompositionUpdate = function() { - if (!inComposition || !host.onCompositionUpdate || host.$readOnly) - return; - if (commandMode) - return cancelComposition(); - - if (inComposition.useTextareaForIME) { - host.onCompositionUpdate(text.value); - } - else { - var data = text.value; - sendText(data); - if (inComposition.markerRange) { - if (inComposition.context) { - inComposition.markerRange.start.column = inComposition.selectionStart - = inComposition.context.compositionStartOffset; - } - inComposition.markerRange.end.column = inComposition.markerRange.start.column - + lastSelectionEnd - inComposition.selectionStart + lastRestoreEnd; - } - } - }; + /** + * allows to ignore composition (used by vim keyboard handler in the normal mode) + * this is useful on mac, where with some keyboard layouts (e.g swedish) ^ starts composition + * @param {boolean} value + */ + setCommandMode(value) { + this.commandMode = value; + this.text.readOnly = false; + } - var onCompositionEnd = function(e) { - if (!host.onCompositionEnd || host.$readOnly) return; - inComposition = false; - host.onCompositionEnd(); - host.off("mousedown", cancelComposition); - // note that resetting value of textarea at this point doesn't always work - // because textarea value can be silently restored - if (e) onInput(); - }; - + setReadOnly(readOnly) { + if (!this.commandMode) this.text.readOnly = readOnly; + } - function cancelComposition() { - // force end composition - ignoreFocusEvents = true; - text.blur(); - text.focus(); - ignoreFocusEvents = false; + setCopyWithEmptySelection(value) { } - var syncComposition = lang.delayedCall(onCompositionUpdate, 50).schedule.bind(null, null); - - function onKeyup(e) { - // workaround for a bug in ie where pressing esc silently moves selection out of textarea - if (e.keyCode == 27 && text.value.length < text.selectionStart) { - if (!inComposition) - lastValue = text.value; - lastSelectionStart = lastSelectionEnd = -1; - resetSelection(); - } - syncComposition(); - } - - event.addListener(text, "compositionstart", onCompositionStart, host); - event.addListener(text, "compositionupdate", onCompositionUpdate, host); - event.addListener(text, "keyup", onKeyup, host); - event.addListener(text, "keydown", syncComposition, host); - event.addListener(text, "compositionend", onCompositionEnd, host); - - this.getElement = function() { - return text; - }; - - // allows to ignore composition (used by vim keyboard handler in the normal mode) - // this is useful on mac, where with some keyboard layouts (e.g swedish) ^ starts composition - this.setCommandMode = function(value) { - commandMode = value; - text.readOnly = false; - }; - - this.setReadOnly = function(readOnly) { - if (!commandMode) - text.readOnly = readOnly; - }; - - this.setCopyWithEmptySelection = function(value) { - }; - - this.onContextMenu = function(e) { - afterContextMenu = true; - resetSelection(); - host._emit("nativecontextmenu", {target: host, domEvent: e}); + onContextMenu(e) { + this.afterContextMenu = true; + this.resetSelection(); + this.host._emit("nativecontextmenu", { + target: this.host, + domEvent: e + }); this.moveToMouse(e, true); - }; - - this.moveToMouse = function(e, bringToFront) { - if (!tempStyle) - tempStyle = text.style.cssText; - text.style.cssText = (bringToFront ? "z-index:100000;" : "") - + (useragent.isIE ? "opacity:0.1;" : "") - + "text-indent: -" + (lastSelectionStart + lastSelectionEnd) * host.renderer.characterWidth * 0.5 + "px;"; - - var rect = host.container.getBoundingClientRect(); - var style = dom.computedStyle(host.container); + } + + /** + * @param e + * @param {boolean} bringToFront + */ + moveToMouse(e, bringToFront) { + if (!this.tempStyle) this.tempStyle = this.text.style.cssText; + this.text.style.cssText = (bringToFront ? "z-index:100000;" : "") + (useragent.isIE ? "opacity:0.1;" : "") + + "text-indent: -" + (this.lastSelectionStart + this.lastSelectionEnd) * this.host.renderer.characterWidth + * 0.5 + "px;"; + + var rect = this.host.container.getBoundingClientRect(); + var style = dom.computedStyle(this.host.container); var top = rect.top + (parseInt(style.borderTopWidth) || 0); var left = rect.left + (parseInt(style.borderLeftWidth) || 0); - var maxTop = rect.bottom - top - text.clientHeight -2; - var move = function(e) { - dom.translate(text, e.clientX - left - 2, Math.min(e.clientY - top - 2, maxTop)); - }; + var maxTop = rect.bottom - top - this.text.clientHeight - 2; + var move = (e) => { + dom.translate(this.text, e.clientX - left - 2, Math.min(e.clientY - top - 2, maxTop)); + }; move(e); - if (e.type != "mousedown") - return; + if (e.type != "mousedown") return; - host.renderer.$isMousePressed = true; + this.host.renderer.$isMousePressed = true; - clearTimeout(closeTimeout); + clearTimeout(this.closeTimeout); // on windows context menu is opened after mouseup - if (useragent.isWin) - event.capture(host.container, move, onContextMenuClose); - }; - - this.onContextMenuClose = onContextMenuClose; - var closeTimeout; - function onContextMenuClose() { - clearTimeout(closeTimeout); - closeTimeout = setTimeout(function () { - if (tempStyle) { - text.style.cssText = tempStyle; - tempStyle = ''; - } - host.renderer.$isMousePressed = false; - if (host.renderer.$keepTextAreaAtCursor) - host.renderer.$moveTextAreaToCursor(); - }, 0); + if (useragent.isWin) event.capture(this.host.container, move, this.onContextMenuClose.bind(this)); } - var onContextMenu = function(e) { - host.textInput.onContextMenu(e); - onContextMenuClose(); - }; - event.addListener(text, "mouseup", onContextMenu, host); - event.addListener(text, "mousedown", function(e) { - e.preventDefault(); - onContextMenuClose(); - }, host); - event.addListener(host.renderer.scroller, "contextmenu", onContextMenu, host); - event.addListener(text, "contextmenu", onContextMenu, host); - - if (isIOS) - addIosSelectionHandler(parentNode, host, text); - - function addIosSelectionHandler(parentNode, host, text) { - var typingResetTimeout = null; - var typing = false; - - text.addEventListener("keydown", function (e) { - if (typingResetTimeout) clearTimeout(typingResetTimeout); - typing = true; - }, true); - - text.addEventListener("keyup", function (e) { - typingResetTimeout = setTimeout(function () { - typing = false; - }, 100); - }, true); - - // IOS doesn't fire events for arrow keys, but this unique hack changes everything! - var detectArrowKeys = function(e) { - if (document.activeElement !== text) return; - if (typing || inComposition || host.$mouseHandler.isMousePressed) return; - - if (copied) { - return; - } - var selectionStart = text.selectionStart; - var selectionEnd = text.selectionEnd; - - var key = null; - var modifier = 0; - // console.log(selectionStart, selectionEnd); - if (selectionStart == 0) { - key = KEYS.up; - } else if (selectionStart == 1) { - key = KEYS.home; - } else if (selectionEnd > lastSelectionEnd && lastValue[selectionEnd] == "\n") { - key = KEYS.end; - } else if (selectionStart < lastSelectionStart && lastValue[selectionStart - 1] == " ") { - key = KEYS.left; - modifier = MODS.option; - } else if ( - selectionStart < lastSelectionStart - || ( - selectionStart == lastSelectionStart - && lastSelectionEnd != lastSelectionStart - && selectionStart == selectionEnd - ) - ) { - key = KEYS.left; - } else if (selectionEnd > lastSelectionEnd && lastValue.slice(0, selectionEnd).split("\n").length > 2) { - key = KEYS.down; - } else if (selectionEnd > lastSelectionEnd && lastValue[selectionEnd - 1] == " ") { - key = KEYS.right; - modifier = MODS.option; - } else if ( - selectionEnd > lastSelectionEnd - || ( - selectionEnd == lastSelectionEnd - && lastSelectionEnd != lastSelectionStart - && selectionStart == selectionEnd - ) - ) { - key = KEYS.right; - } - - if (selectionStart !== selectionEnd) - modifier |= MODS.shift; - - if (key) { - var result = host.onCommandKey({}, modifier, key); - if (!result && host.commands) { - key = KEYS.keyCodeToString(key); - var command = host.commands.findKeyCommand(modifier, key); - if (command) - host.execCommand(command); - } - lastSelectionStart = selectionStart; - lastSelectionEnd = selectionEnd; - resetSelection(""); - } - }; - // On iOS, "selectionchange" can only be attached to the document object... - document.addEventListener("selectionchange", detectArrowKeys); - host.on("destroy", function() { - document.removeEventListener("selectionchange", detectArrowKeys); - }); + destroy() { + if (this.text.parentElement) this.text.parentElement.removeChild(this.text); } - - this.destroy = function() { - if (text.parentElement) - text.parentElement.removeChild(text); - }; -}; +} exports.TextInput = TextInput; -exports.$setUserAgentForTests = function(_isMobile, _isIOS) { +exports.$setUserAgentForTests = function (_isMobile, _isIOS) { isMobile = _isMobile; isIOS = _isIOS; }; diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index 9db069c52f7..a20909cfef3 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -1563,7 +1563,76 @@ declare module "ace-code/src/clipboard" { } declare module "ace-code/src/keyboard/textinput" { export function $setUserAgentForTests(_isMobile: any, _isIOS: any): void; - export var TextInput: any; + export class TextInput { + constructor(parentNode: HTMLElement, host: import("ace-code/src/editor").Editor); + host: import("ace-code/src/editor").Editor; + text: HTMLTextAreaElement & { + msGetInputContext?: () => { + compositionStartOffset: number; + }; + getInputContext?: () => { + compositionStartOffset: number; + }; + }; + copied: boolean | string; + pasted: boolean; + inComposition: (boolean | any) & { + context?: any; + useTextareaForIME?: boolean; + selectionStart?: number; + markerRange?: any; + }; + sendingText: boolean; + tempStyle: string; + commandMode: boolean; + ignoreFocusEvents: boolean; + lastValue: string; + lastSelectionStart: number; + lastSelectionEnd: number; + lastRestoreEnd: number; + rowStart: number; + rowEnd: number; + numberOfExtraLines: number; + resetSelection: (value: any) => void; + inputHandler: any; + afterContextMenu: boolean; + syncComposition: any; + onContextMenuClose(): void; + closeTimeout: number; + setHost(newHost: import("ace-code/src/editor").Editor): void; + /** + * Sets the number of extra lines in the textarea to improve screen reader compatibility. + * Extra lines can help screen readers perform better when reading text. + * + * @param {number} number - The number of extra lines to add. Must be non-negative. + */ + setNumberOfExtraLines(number: number): void; + setAriaLabel(): void; + setAriaOptions(options: import("ace-code").Ace.TextInputAriaOptions): void; + focus(): void; + blur(): void; + isFocused(): boolean; + setInputHandler(cb: any): void; + getInputHandler(): any; + getElement(): HTMLTextAreaElement & { + msGetInputContext?: () => { + compositionStartOffset: number; + }; + getInputContext?: () => { + compositionStartOffset: number; + }; + }; + /** + * allows to ignore composition (used by vim keyboard handler in the normal mode) + * this is useful on mac, where with some keyboard layouts (e.g swedish) ^ starts composition + */ + setCommandMode(value: boolean): void; + setReadOnly(readOnly: any): void; + setCopyWithEmptySelection(value: any): void; + onContextMenu(e: any): void; + moveToMouse(e: any, bringToFront: boolean): void; + destroy(): void; + } } declare module "ace-code/src/mouse/mouse_event" { export class MouseEvent { @@ -2050,7 +2119,7 @@ declare module "ace-code/src/editor" { }; renderer: VirtualRenderer; commands: CommandManager; - textInput: any; + textInput: TextInput; keyBinding: KeyBinding; startOperation(commandEvent: any): void; /** @@ -2165,7 +2234,7 @@ declare module "ace-code/src/editor" { * Returns the string of text currently highlighted. **/ getCopyText(): string; - execCommand(command: string | string[], args?: any): boolean; + execCommand(command: string | string[] | import("ace-code").Ace.Command, args?: any): boolean; /** * Inserts `text` into wherever the cursor is pointing. * @param {String} text The new text to add @@ -2709,6 +2778,7 @@ declare module "ace-code/src/editor" { export type SearchOptions = import("ace-code").Ace.SearchOptions; import { EditSession } from "ace-code/src/edit_session"; import { CommandManager } from "ace-code/src/commands/command_manager"; + import { TextInput } from "ace-code/src/keyboard/textinput"; import { MouseHandler } from "ace-code/src/mouse/mouse_handler"; import { KeyBinding } from "ace-code/src/keyboard/keybinding"; import { Search } from "ace-code/src/search"; From 469dc2b4d4546c80ac2bacdf9dfbc2c29130a855 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Thu, 5 Jun 2025 15:33:17 +0400 Subject: [PATCH 1263/1293] Add folding support for Nunjucks templates and related tests (#5824) * add folding support for Nunjucks templates and related tests * add nunjucks folding --- ace-modes.d.ts | 4 + src/mode/folding/nunjucks.js | 173 ++++++++++++++++++++++++++++++ src/mode/folding/nunjucks_test.js | 63 +++++++++++ src/mode/nunjucks.js | 16 ++- 4 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 src/mode/folding/nunjucks.js create mode 100644 src/mode/folding/nunjucks_test.js diff --git a/ace-modes.d.ts b/ace-modes.d.ts index d7eee30ec94..fa7692936f8 100644 --- a/ace-modes.d.ts +++ b/ace-modes.d.ts @@ -508,6 +508,10 @@ declare module "ace-code/src/mode/folding/mixed" { export const FoldMode: new () => import("ace-code").Ace.Folding; } +declare module "ace-code/src/mode/folding/nunjucks" { + export const FoldMode: new () => import("ace-code").Ace.Folding; +} + declare module "ace-code/src/mode/folding/php" { export const FoldMode: new () => import("ace-code").Ace.Folding; } diff --git a/src/mode/folding/nunjucks.js b/src/mode/folding/nunjucks.js new file mode 100644 index 00000000000..0bd234b7437 --- /dev/null +++ b/src/mode/folding/nunjucks.js @@ -0,0 +1,173 @@ +"use strict"; + +var oop = require("../../lib/oop"); +const {FoldMode: MixedFoldMode} = require("./mixed"); +var HtmlFoldMode = require("./html").FoldMode; +var Range = require("../../range").Range; +var TokenIterator = require("../../token_iterator").TokenIterator; + + +var FoldMode = exports.FoldMode = function (voidElements, optionalTags) { + HtmlFoldMode.call(this, voidElements, optionalTags); +}; + +oop.inherits(FoldMode, HtmlFoldMode); + +(function () {//TODO: set|endset + this.getFoldWidgetRangeBase = this.getFoldWidgetRange; + this.getFoldWidgetBase = this.getFoldWidget; + + this.indentKeywords = { + "block": 1, + "if": 1, + "for": 1, + "asyncEach": 1, + "asyncAll": 1, + "macro": 1, + "filter": 1, + "call": 1, + "else": 0, + "elif": 0, + "set": 1, + "endblock": -1, + "endif": -1, + "endfor": -1, + "endeach": -1, + "endall": -1, + "endmacro": -1, + "endfilter": -1, + "endcall": -1, + "endset": -1 + }; + + this.foldingStartMarkerNunjucks = /(?:\{%-?\s*)(?:(block|if|else|elif|for|asyncEach|asyncAll|macro|filter|call)\b.*)|(?:\bset(?:[^=]*))(?=%})/i; + this.foldingStopMarkerNunjucks = /(?:\{%-?\s*)(endblock|endif|endfor|endeach|endall|endmacro|endfilter|endcall|endset)\b.*(?=%})/i; + + this.getFoldWidgetRange = function (session, foldStyle, row) { + var line = session.doc.getLine(row); + let offset = calculateOffset(this.foldingStartMarkerNunjucks, line); + if (offset) { + return this.nunjucksBlock(session, row, offset); + } + + offset = calculateOffset(this.foldingStopMarkerNunjucks, line); + if (offset) { + return this.nunjucksBlock(session, row, offset); + } + return this.getFoldWidgetRangeBase(session, foldStyle, row); + }; + + /** + * + * @param {RegExp} regExp + * @param line + * @return {*} + */ + function calculateOffset(regExp, line) { + var match = regExp.exec(line); + if (match) { + var keyword = match[0].includes("set") ? "set" : match[1].toLowerCase(); + if (keyword) { + var offsetInMatch = match[0].toLowerCase().indexOf(keyword); + return match.index + offsetInMatch + 1; + } + } + } + + // must return "" if there's no fold, to enable caching + this.getFoldWidget = function (session, foldStyle, row) { + var line = session.getLine(row); + var isStart = this.foldingStartMarkerNunjucks.test(line); + var isEnd = this.foldingStopMarkerNunjucks.test(line); + if (isStart && !isEnd) { + var offset = calculateOffset(this.foldingStartMarkerNunjucks, line); + if (offset) { + var type = session.getTokenAt(row, offset).type; + if (type === "keyword.control") { + return "start"; + } + } + } + if (isEnd && !isStart && foldStyle === "markbeginend") { + var offset = calculateOffset(this.foldingStopMarkerNunjucks, line); + if (offset) { + var type = session.getTokenAt(row, offset).type; + if (type === "keyword.control") { + return "end"; + } + } + } + return this.getFoldWidgetBase(session, foldStyle, row); + }; + + /** + * + * @param {TokenIterator} stream + */ + function getTokenPosition(stream, findStart) { + let token; + const currentIndex = stream.$tokenIndex; + const type = findStart ? "punctuation.begin" : "punctuation.end"; + stream.step = findStart ? stream.stepBackward : stream.stepForward; + while (token = stream.step()) { + if (token.type !== type) continue; + break; + } + if (!token) return; + let pos = stream.getCurrentTokenPosition(); + if (!findStart) { + pos.column = pos.column + token.value.length; + } + stream.$tokenIndex = currentIndex; + return pos; + } + + this.nunjucksBlock = function (session, row, column) { + var stream = new TokenIterator(session, row, column); + + var token = stream.getCurrentToken(); + if (!token || token.type != "keyword.control") return; + + var val = token.value; + var stack = [val]; + var dir = this.indentKeywords[val]; + + if (val === "else" || val === "elif") { + dir = 1; + } + + if (!dir) return; + + var start = getTokenPosition(stream, dir === -1); + + if (!token) return; + + stream.step = dir === -1 ? stream.stepBackward : stream.stepForward; + while (token = stream.step()) { + if (token.type !== "keyword.control") continue; + var level = dir * this.indentKeywords[token.value]; + + if (token.value === "set") { + var tokenPos = stream.getCurrentTokenPosition(); + var line = session.getLine(tokenPos.row).substring(tokenPos.column); + if (!/^[^=]*%}/.test(line)) { + continue; + } + } + if (level > 0) { + stack.unshift(token.value); + } + else if (level <= 0) { + stack.shift(); + if (!stack.length) break; + if (level === 0) stack.unshift(token.value); + } + } + + if (!token) return null; + + var end = getTokenPosition(stream, dir === 1); + return dir === 1 ? Range.fromPoints(start, end) : Range.fromPoints(end, start); + }; + +}).call(FoldMode.prototype); diff --git a/src/mode/folding/nunjucks_test.js b/src/mode/folding/nunjucks_test.js new file mode 100644 index 00000000000..14e44359bc7 --- /dev/null +++ b/src/mode/folding/nunjucks_test.js @@ -0,0 +1,63 @@ +"use strict"; + +var NunjucksMode = require("../nunjucks").Mode; +var EditSession = require("../../edit_session").EditSession; +var assert = require("../../test/assertions"); + +module.exports = { + setUp : function() { + this.mode = new NunjucksMode(); + }, + + "test: nunjucks folding": function() { + var session = new EditSession([ + '{% block header %}', + '
    ', + ' {% block left %}{% endblock %}', + ' {% set standardModal %}', + ' {% include "standardModalData.html" %}', + ' {% set cls = cycler("odd", "even") %}', + ' {% endset %}', + ' {% if hungry %}', + ' I am hungry', + ' {% elif tired %}', + ' I am tired', + ' {% else %}', + ' I am good!', + ' {% endif %}', + '
    ', + '{% endblock %}' + ]); + + session.setFoldStyle("markbeginend"); + session.setMode(this.mode); + + assert.equal(session.getFoldWidget(0), "start"); + assert.equal(session.getFoldWidget(1), "start"); + assert.equal(session.getFoldWidget(2), ""); + assert.equal(session.getFoldWidget(3), "start"); + assert.equal(session.getFoldWidget(4), ""); + assert.equal(session.getFoldWidget(5), ""); // set with = + assert.equal(session.getFoldWidget(6), "end"); + assert.equal(session.getFoldWidget(7), "start"); + assert.equal(session.getFoldWidget(8), ""); + assert.equal(session.getFoldWidget(9), "start"); + assert.equal(session.getFoldWidget(10), ""); + assert.equal(session.getFoldWidget(11), "start"); + assert.equal(session.getFoldWidget(12), ""); + assert.equal(session.getFoldWidget(13), "end"); + assert.equal(session.getFoldWidget(14), "end"); + assert.equal(session.getFoldWidget(15), "end"); + + assert.range(session.getFoldWidgetRange(0), 0, 18, 15, 0); + assert.range(session.getFoldWidgetRange(1), 1, 24, 14, 2); + assert.range(session.getFoldWidgetRange(3), 3, 27, 6, 4); + assert.range(session.getFoldWidgetRange(6), 3, 27, 6, 4); + assert.range(session.getFoldWidgetRange(7), 7, 19, 9, 4); + assert.range(session.getFoldWidgetRange(11), 11, 14, 13, 4); + } +}; + + +if (typeof module !== "undefined" && module === require.main) + require("asyncjs").test.testcase(module.exports).exec(); \ No newline at end of file diff --git a/src/mode/nunjucks.js b/src/mode/nunjucks.js index 995bc2b3575..d2b45312323 100644 --- a/src/mode/nunjucks.js +++ b/src/mode/nunjucks.js @@ -1,17 +1,29 @@ "use strict"; var oop = require("../lib/oop"); +var NunjucksFoldMode = require("./folding/nunjucks").FoldMode; +var lang = require("../lib/lang"); var HtmlMode = require("./html").Mode; var NunjucksHighlightRules = require("./nunjucks_highlight_rules").NunjucksHighlightRules; -var Mode = function() { +// http://www.w3.org/TR/html5/syntax.html#void-elements +var voidElements = [ + "area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "meta", "menuitem", "param", "source", + "track", "wbr" +]; +var optionalEndTags = ["li", "dt", "dd", "p", "rt", "rp", "optgroup", "option", "colgroup", "td", "th"]; + +var Mode = function () { this.HighlightRules = NunjucksHighlightRules; + this.foldingRules = new NunjucksFoldMode(this.voidElements, lang.arrayToMap(optionalEndTags)); }; oop.inherits(Mode, HtmlMode); -(function() { +(function () { this.$id = "ace/mode/nunjucks"; + this.voidElements = lang.arrayToMap(voidElements); + }).call(Mode.prototype); exports.Mode = Mode; From b4748041d889274acc52e10a601729917b3fb10a Mon Sep 17 00:00:00 2001 From: Markos-Th09 <87304130+Markos-Th09@users.noreply.github.com> Date: Fri, 6 Jun 2025 11:41:09 +0400 Subject: [PATCH 1264/1293] Add support for the Clue language (#5823) --- ace-modes.d.ts | 8 + demo/kitchen-sink/docs/clue.clue | 356 +++++++++++++++++++++++++++++++ src/ext/modelist.js | 3 +- src/mode/clue.js | 60 ++++++ src/mode/clue_highlight_rules.js | 201 +++++++++++++++++ 5 files changed, 627 insertions(+), 1 deletion(-) create mode 100644 demo/kitchen-sink/docs/clue.clue create mode 100644 src/mode/clue.js create mode 100644 src/mode/clue_highlight_rules.js diff --git a/ace-modes.d.ts b/ace-modes.d.ts index fa7692936f8..8bf991f2bb8 100644 --- a/ace-modes.d.ts +++ b/ace-modes.d.ts @@ -207,6 +207,14 @@ declare module "ace-code/src/mode/clojure" { export const Mode: new () => import("ace-code").Ace.SyntaxMode; } +declare module "ace-code/src/mode/clue_highlight_rules" { + export const ClueHighlightRules: new () => import("ace-code").Ace.HighlightRules; +} + +declare module "ace-code/src/mode/clue" { + export const Mode: new () => import("ace-code").Ace.SyntaxMode; +} + declare module "ace-code/src/mode/cobol_highlight_rules" { export const CobolHighlightRules: new () => import("ace-code").Ace.HighlightRules; } diff --git a/demo/kitchen-sink/docs/clue.clue b/demo/kitchen-sink/docs/clue.clue new file mode 100644 index 00000000000..a3fa865edd7 --- /dev/null +++ b/demo/kitchen-sink/docs/clue.clue @@ -0,0 +1,356 @@ +@iflua jit { + local fn pack(...) { + return love.data.pack("string", ...) + } + local fn unpack(...) { + return love.data.unpack(...) + } + local fn mtype(x) { + if type(x) != "number" { + return + } elseif x == math.floor(x) { + return "integer" + } else { + return "float" + } + } + local utf8len = require("utf8").len + local tconcat, tunpack = table.concat, _G.unpack + local ssub = string.sub + local type, pcall, pairs, select = type, pcall, pairs, select +} @else { + @if all(not(lua(5.4)), not(lua(5.3))) { + @print "Warning: Lua version not specified, defaulting to Lua5.4" + } + local {pack, unpack} = string + local mtype, utf8len = math.type, utf8.len + local tconcat, tunpack = table.concat, table.unpack + local ssub = string.sub + local type, pcall, pairs, select = type, pcall, pairs, select +} + +//ENCODER +local encode_value //forward declaration + +local fn is_an_array(value) { + local expected = 1 + for k of value { + if k != expected { + return false + } + expected += 1 + } + return true +} + +local encoder_functions = { + ["nil"] = fn { + return pack("B", 0xc0) + }, + ["boolean"] = fn(value) { + if value { + return pack("B", 0xc3) + } else { + return pack("B", 0xc2) + } + }, + ["number"] = fn(value) { + if mtype(value) == "integer" { + if value >= 0 { + if value < 128 { + return pack("B", value) + } elseif value <= 0xff { + return pack("BB", 0xcc, value) + } elseif value <= 0xffff { + return pack(">BI2", 0xcd, value) + } elseif value <= 0xffffffff { + return pack(">BI4", 0xce, value) + } else { + return pack(">BI8", 0xcf, value) + } + } else { + if value >= -32 { + return pack("B", 0xe0 + (value + 32)) + } elseif value >= -128 { + return pack("Bb", 0xd0, value) + } elseif value >= -32768 { + return pack(">Bi2", 0xd1, value) + } elseif value >= -2147483648 { + return pack(">Bi4", 0xd2, value) + } else { + return pack(">Bi8", 0xd3, value) + } + } + } else { + local test = unpack("f", pack("f", value)) + if test == value { //check if we can use float + return pack(">Bf", 0xca, value) + } else { + return pack(">Bd", 0xcb, value) + } + } + }, + ["string"] = fn(value) { + local len = #value + if utf8len(value) { //check if it is a real utf8 string or just byte junk + if len < 32 { + return pack("B", 0xa0 + len) .. value + } elseif len < 256 { + return pack(">Bs1", 0xd9, value) + } elseif len < 65536 { + return pack(">Bs2", 0xda, value) + } else { + return pack(">Bs4", 0xdb, value) + } + } else { //encode it as byte-junk :) + if len < 256 { + return pack(">Bs1", 0xc4, value) + } elseif len < 65536 { + return pack(">Bs2", 0xc5, value) + } else { + return pack(">Bs4", 0xc6, value) + } + } + }, + ["table"] = fn(value) { + if is_an_array(value) { //it seems to be a proper Lua array + local elements = {} + for i, v of value { + elements[i] = encode_value(v) + } + + local length = #elements + if length < 16 { + return pack(">B", 0x90 + length) .. tconcat(elements) + } elseif length < 65536 { + return pack(">BI2", 0xdc, length) .. tconcat(elements) + } else { + return pack(">BI4", 0xdd, length) .. tconcat(elements) + } + } else { //encode as a map + local elements = {} + for k, v of value { + if type(v) != "function" { + elements[#elements + 1] = encode_value(k) + elements[#elements + 1] = encode_value(v) + } + } + + local length = #elements /_ 2 + if length < 16 { + return pack(">B", 0x80 + length) .. tconcat(elements) + } elseif length < 65536 { + return pack(">BI2", 0xde, length) .. tconcat(elements) + } else { + return pack(">BI4", 0xdf, length) .. tconcat(elements) + } + } + }, + ["function"] = fn { + return pack("B", 0xc0) + } +} + +encode_value = fn(value) { + return encoder_functions[type(value)](value) +} + +local fn encode(...) { + local data = {} + for i = 1, select("#", ...) { + data[#data + 1] = encode_value(select(i, ...)) + } + return tconcat(data) +} + + +//DECODER +local decode_value //forward declaration + +local fn decode_array(data, position, length) { + local elements, value = {} + for i = 1, length { + value, position = decode_value(data, position) + elements[i] = value + } + return elements, position +} + +local fn decode_map(data, position, length) { + local elements, key, value = {} + for i = 1, length { + key, position = decode_value(data, position) + value, position = decode_value(data, position) + elements[key] = value + } + return elements, position +} + +local decoder_functions = { + [0xc0] = fn(data, position) { + return nil, position + }, + [0xc2] = fn(data, position) { + return false, position + }, + [0xc3] = fn(data, position) { + return true, position + }, + [0xc4] = fn(data, position) { + return unpack(">s1", data, position) + }, + [0xc5] = fn(data, position) { + return unpack(">s2", data, position) + }, + [0xc6] = fn(data, position) { + return unpack(">s4", data, position) + }, + [0xca] = fn(data, position) { + return unpack(">f", data, position) + }, + [0xcb] = fn(data, position) { + return unpack(">d", data, position) + }, + [0xcc] = fn(data, position) { + return unpack(">B", data, position) + }, + [0xcd] = fn(data, position) { + return unpack(">I2", data, position) + }, + [0xce] = fn(data, position) { + return unpack(">I4", data, position) + }, + [0xcf] = fn(data, position) { + return unpack(">I8", data, position) + }, + [0xd0] = fn(data, position) { + return unpack(">b", data, position) + }, + [0xd1] = fn(data, position) { + return unpack(">i2", data, position) + }, + [0xd2] = fn(data, position) { + return unpack(">i4", data, position) + }, + [0xd3] = fn(data, position) { + return unpack(">i8", data, position) + }, + [0xd9] = fn(data, position) { + return unpack(">s1", data, position) + }, + [0xda] = fn(data, position) { + return unpack(">s2", data, position) + }, + [0xdb] = fn(data, position) { + return unpack(">s4", data, position) + }, + [0xdc] = fn(data, position) { + local length + length, position = unpack(">I2", data, position) + return decode_array(data, position, length) + }, + [0xdd] = fn(data, position) { + local length + length, position = unpack(">I4", data, position) + return decode_array(data, position, length) + }, + [0xde] = fn(data, position) { + local length + length, position = unpack(">I2", data, position) + return decode_map(data, position, length) + }, + [0xdf] = fn(data, position) { + local length + length, position = unpack(">I4", data, position) + return decode_map(data, position, length) + }, +} + +//add fix-array, fix-map, fix-string, fix-int stuff +for i = 0x00, 0x7f { + decoder_functions[i] = fn(data, position) { + return i, position + } +} +for i = 0x80, 0x8f { + decoder_functions[i] = fn(data, position) { + return decode_map(data, position, i - 0x80) + } +} +for i = 0x90, 0x9f { + decoder_functions[i] = fn(data, position) { + return decode_array(data, position, i - 0x90) + } +} +for i = 0xa0, 0xbf { + decoder_functions[i] = fn(data, position) { + local length = i - 0xa0 + return ssub(data, position, position + length - 1), position + length + } +} +for i = 0xe0, 0xff { + decoder_functions[i] = fn(data, position) { + return -32 + (i - 0xe0), position + } +} + +decode_value = fn(data, position) { + local byte, value + byte, position = unpack("B", data, position) + value, position = decoder_functions[byte](data, position) + return value, position +} + +//INTERFACE +return { + _AUTHOR = "Felice D'Angelo ", + _VERSION = "0.2.1", + + //primary encode function + encode = fn(...) { + local data, ok = {} + for i = 1, select("#", ...) { + ok, data[i] = pcall(encode_value, select(i, ...)) + if !ok { + return nil, "cannot encode MessagePack" + } + } + return tconcat(data) + }, + + //encode just one value + encode_one = fn(value) { + local ok, data = pcall(encode_value, value) + if ok { + return data + } else { + return nil, "cannot encode MessagePack" + } + }, + + //primary decode function + decode = fn(data, position) { + local values, value, ok = {} + position ||= 1 + while position <= #data { + ok, value, position = pcall(decode_value, data, position) + if ok { + values[#values + 1] = value + } else { + return nil, "cannot decode MessagePack" + } + } + return tunpack(values) + }, + + //decode just one value + decode_one = fn(data, position) { + local value, ok + ok, value, position = pcall(decode_value, data, position || 1) + if ok { + return value, position + } else { + return nil, "cannot decode MessagePack" + } + }, +} diff --git a/src/ext/modelist.js b/src/ext/modelist.js index 5d874e67e00..964f4b2265e 100644 --- a/src/ext/modelist.js +++ b/src/ext/modelist.js @@ -71,13 +71,14 @@ var supportedModes = { Assembly_x86:["asm|a"], Astro: ["astro"], AutoHotKey: ["ahk"], - BatchFile: ["bat|cmd"], Basic: ["bas|bak"], + BatchFile: ["bat|cmd"], BibTeX: ["bib"], C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp|ino"], C9Search: ["c9search_results"], Cirru: ["cirru|cr"], Clojure: ["clj|cljs"], + Clue: ["clue"], Cobol: ["CBL|COB"], coffee: ["coffee|cf|cson|^Cakefile"], ColdFusion: ["cfm|cfc"], diff --git a/src/mode/clue.js b/src/mode/clue.js new file mode 100644 index 00000000000..457cef5367e --- /dev/null +++ b/src/mode/clue.js @@ -0,0 +1,60 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js +*/ + +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var ClueHighlightRules = require("./clue_highlight_rules").ClueHighlightRules; +var FoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function () { + this.HighlightRules = ClueHighlightRules; + this.foldingRules = new FoldMode(); + this.$behaviour = this.$defaultBehaviour; +}; +oop.inherits(Mode, TextMode); + +(function () { + this.lineCommentStart = "//"; + this.blockComment = { start: "/*", end: "*/" }; + this.$quotes = { '"': '"', "'": "'", "`": "`" }; + this.$pairQuotesAfter = { + "`": /\w/ + }; + + this.$id = "ace/mode/clue"; +}).call(Mode.prototype); + +exports.Mode = Mode; diff --git a/src/mode/clue_highlight_rules.js b/src/mode/clue_highlight_rules.js new file mode 100644 index 00000000000..e87e994199b --- /dev/null +++ b/src/mode/clue_highlight_rules.js @@ -0,0 +1,201 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +/* This file was autogenerated from clue.json (uuid: ) */ +/**************************************************************************************** + * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. * + * fileTypes * + ****************************************************************************************/ + +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var ClueHighlightRules = function () { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + start: [{ + token: [ + "keyword.control.directive.clue", + "text", + "text" + ], + regex: /(@version)( )(.+?(?=\n))/ + }, { + token: ["keyword.control.macro.clue", "text", "text"], + regex: /(@macro)( )([A-Za-z_][0-9A-Za-z_]*)/ + }, { + token: [ + "keyword.control.import.clue", + "text", + "string" + ], + regex: /(@import)( )(".*")/ + }, { + token: "meta.preprocessor.macro.invocation.clue", + regex: /\$[A-Za-z_][0-9A-Za-z_]*!/ + }, { + token: "keyword.control.directive.clue", + regex: /@(?:(?:else_)?(?:ifos|iflua|ifdef|ifndef|ifcmp|ifos|iflua|ifdef|ifcmp|if)|else|define|macro|error|print)/ + }, { + token: "constant.numeric.integer.hexadecimal.clue", + regex: /\b0[xX][0-9A-Fa-f]+(?![pPeE.0-9])\b/ + + }, { + token: "constant.numeric.float.hexadecimal.clue", + regex: /\b0[xX][0-9A-Fa-f]+(?:\.[0-9A-Fa-f]+)?(?:[eE]-?\d*)?(?:[pP][-+]\d+)?\b/ + }, { + token: "constant.numeric.integer.clue", + regex: /\b\d+(?![pPeE.0-9])/ + }, { + token: "constant.numeric.float.clue", + regex: /\b\d+(?:\.\d+)?(?:[eE]-?\d*)?/ + }, { + token: "punctuation.definition.string.multilined.begin.clue", + regex: /'/, + push: [{ + token: "punctuation.definition.string.multilined.end.clue", + regex: /'/, + next: "pop" + }, { + include: "#escaped_char" + }, { + defaultToken: "string.quoted.single.clue" + }] + }, { + token: "punctuation.definition.string.multilined.begin.clue", + regex: /"/, + push: [{ + token: "punctuation.definition.string.multilined.end.clue", + regex: /"/, + next: "pop" + }, { + include: "#escaped_char" + }, { + defaultToken: "string.quoted.double.clue" + }] + }, { + token: "punctuation.definition.string.multilined.begin.clue", + regex: /`/, + push: [{ + token: "punctuation.definition.string.multilined.end.clue", + regex: /`/, + next: "pop" + }, { + include: "#escaped_char" + }, { + defaultToken: "string.multiline.clue" + }] + }, { + token: "comment.line.double-dash.clue", + regex: /\/\/.*/ + }, { + token: "punctuation.definition.comment.begin.clue", + regex: /\/\*/, + push: [{ + token: "punctuation.definition.comment.end.clue", + regex: /\*\//, + next: "pop" + }, { + include: "#escaped_char" + }, { + defaultToken: "comment.block.clue" + }] + }, { + token: "keyword.control.clue", + regex: /\b(?:if|elseif|else|for|of|in|with|while|meta|until|fn|method|return|loop|enum|goto|continue|break|try|catch|match|default|macro)\b/ + }, { + token: "keyword.scope.clue", + regex: /\b(?:local|global|static)\b/ + }, { + token: "constant.language.clue", + regex: /\b(?:false|nil|true|_G|_VERSION|math\.(?:pi|huge))\b/ + }, { + token: "constant.language.ellipsis.clue", + regex: /\.{3}(?!\.)/ + }, { + token: "keyword.operator.property.clue", + regex: /\.|::/, + next: "property_identifier" + }, { + token: "keyword.operator.clue", + regex: /\/_|\&|\||\!|\~|\?|\$|@|\+|-|%|#|\*|\/|\^|==?|<=?|>=?|\.{2}|\?\?=?|(?:&&|\|\|)=?/ + }, { + token: "variable.language.self.clue", + regex: /\bself\b/ + }, { + token: "support.function.any-method.clue", + regex: /\b[a-zA-Z_][a-zA-Z0-9_]*\b(?=\(\s*)/ + }, { + token: "variable.other.clue", + regex: /[A-Za-z_][0-9A-Za-z_]*/ + }], + "#escaped_char": [{ + token: "constant.character.escape.clue", + regex: /\\[abfnrtvz\\"'$]/ + }, { + token: "constant.character.escape.byte.clue", + regex: /\\\d{1,3}/ + }, { + token: "constant.character.escape.byte.clue", + regex: /\\x[0-9A-Fa-f][0-9A-Fa-f]/ + }, { + token: "constant.character.escape.unicode.clue", + regex: /\\u\{[0-9A-Fa-f]+\}/ + }, { + token: "invalid.illegal.character.escape.clue", + regex: /\\./ + }], + property_identifier: [{ + token: "variable.other.property.clue", + regex: /[A-Za-z_][0-9A-Za-z_]*/, + next: "start" + }, { + token: "", + regex: "", + next: "start" + }], + }; + + this.normalizeRules(); +}; + +ClueHighlightRules.metaData = { + name: "Clue", + scopeName: "source.clue" +}; + + +oop.inherits(ClueHighlightRules, TextHighlightRules); + +exports.ClueHighlightRules = ClueHighlightRules; From 017341f8260d734fbdab116266c6f1b5a51ac72e Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Tue, 10 Jun 2025 14:01:07 +0400 Subject: [PATCH 1265/1293] fix search box initialization for multi-line selection (#5826) --- src/ext/searchbox.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ext/searchbox.js b/src/ext/searchbox.js index 6b5b67e78cb..145439a58be 100644 --- a/src/ext/searchbox.js +++ b/src/ext/searchbox.js @@ -314,7 +314,7 @@ class SearchBox { if (this.editor.$search.$options.regExp) value = lang.escapeRegExp(value); - if (value) + if (value != undefined) this.searchInput.value = value; this.searchInput.focus(); @@ -434,7 +434,9 @@ exports.SearchBox = SearchBox; */ exports.Search = function(editor, isReplace) { var sb = editor.searchBox || new SearchBox(editor); - sb.show(editor.session.getTextRange(), isReplace); + var range = editor.session.selection.getRange(); + var value = range.isMultiLine() ? "" : editor.session.getTextRange(range); + sb.show(value, isReplace); }; From 896c9da9ce1eff2ec444b5384e90ce6898418551 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Tue, 17 Jun 2025 13:22:46 +0400 Subject: [PATCH 1266/1293] fix wrong `zones` property, causing correct `$zones` array accumulation (#5828) --- src/ext/diff/base_diff_view.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ext/diff/base_diff_view.js b/src/ext/diff/base_diff_view.js index b86abc50f3e..019ad027bd5 100644 --- a/src/ext/diff/base_diff_view.js +++ b/src/ext/diff/base_diff_view.js @@ -346,14 +346,14 @@ class BaseDiffView { if (!this.activeEditor) { return; } - this.activeEditor.renderer.$scrollDecorator.zones = []; + this.activeEditor.renderer.$scrollDecorator.$zones = []; } else { if (!this.editorA || !this.editorB) { return; } - this.editorA.renderer.$scrollDecorator.zones = []; - this.editorB.renderer.$scrollDecorator.zones = []; + this.editorA.renderer.$scrollDecorator.$zones = []; + this.editorB.renderer.$scrollDecorator.$zones = []; } /** From eb75438cd8017c3a29bf76bea267c1eff0e8440d Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Thu, 19 Jun 2025 16:16:01 +0400 Subject: [PATCH 1267/1293] add canvas context check in $updateDecorators method (#5833) --- src/ext/diff/scroll_diff_decorator.js | 3 +++ src/layer/decorators.js | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/ext/diff/scroll_diff_decorator.js b/src/ext/diff/scroll_diff_decorator.js index 6120f2d29ff..ffb7c57b456 100644 --- a/src/ext/diff/scroll_diff_decorator.js +++ b/src/ext/diff/scroll_diff_decorator.js @@ -41,6 +41,9 @@ class ScrollDiffDecorator extends Decorator { } $updateDecorators(config) { + if (typeof this.canvas.getContext !== "function") { + return; + } super.$updateDecorators(config); if (this.$zones.length > 0) { var colors = (this.renderer.theme.isDark === true) ? this.colors.dark : this.colors.light; diff --git a/src/layer/decorators.js b/src/layer/decorators.js index 9fb5c71797f..bfe209ec67d 100644 --- a/src/layer/decorators.js +++ b/src/layer/decorators.js @@ -48,6 +48,9 @@ class Decorator { } $updateDecorators(config) { + if (typeof this.canvas.getContext !== "function") { + return; + } var colors = (this.renderer.theme.isDark === true) ? this.colors.dark : this.colors.light; this.setDimensions(config); From 7e53851d0864b4ebb85cab911ae332fba60219e8 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Thu, 19 Jun 2025 16:24:48 +0400 Subject: [PATCH 1268/1293] improve typings and add module documentation for extensions (#5827) --- ace-internal.d.ts | 41 ++++++++++ ace.d.ts | 39 +++++++++ src/ext/beautify.js | 49 ++++++++++-- src/ext/code_lens.js | 8 ++ src/ext/command_bar.js | 11 +++ src/ext/elastic_tabstops_lite.js | 12 +++ src/ext/emmet.js | 50 ++++++++++-- src/ext/error_marker.js | 18 ++++- src/ext/hardwrap.js | 24 +++++- src/ext/inline_autocomplete.js | 11 +++ src/ext/keybinding_menu.js | 23 ++++-- src/ext/language_tools.js | 38 ++++++++- src/ext/linking.js | 11 +++ .../get_editor_keyboard_shortcuts.js | 31 +++++--- src/ext/menu_tools/overlay_page.js | 36 ++++++--- src/ext/modelist.js | 26 ++++-- src/ext/options.js | 29 +++++++ src/ext/prompt.js | 47 +++++++++-- src/ext/rtl.js | 28 +++++++ src/ext/searchbox.js | 33 +++++++- src/ext/settings_menu.js | 27 +++++-- src/ext/simple_tokenizer.js | 21 +++++ src/ext/spellcheck.js | 20 +++++ src/ext/split.js | 18 +++++ src/ext/static_highlight.js | 25 +++++- src/ext/statusbar.js | 17 ++++ src/ext/textarea.js | 37 ++++++++- src/ext/themelist.js | 13 +++ src/ext/whitespace.js | 18 ++++- types/ace-ext.d.ts | 79 ++++++++++++++++--- 30 files changed, 751 insertions(+), 89 deletions(-) diff --git a/ace-internal.d.ts b/ace-internal.d.ts index f5432c940c2..0ec5700a2f1 100644 --- a/ace-internal.d.ts +++ b/ace-internal.d.ts @@ -88,9 +88,13 @@ export namespace Ace { } interface HardWrapOptions { + /** First row of the range to process */ startRow: number; + /** Last row of the range to process */ endRow: number; + /** Whether to merge short adjacent lines that fit within the limit */ allowMerge?: boolean; + /** Maximum column width for line wrapping (defaults to editor's print margin) */ column?: number; } @@ -971,24 +975,34 @@ export namespace Ace { type CompleterCallback = (error: any, completions: Completion[]) => void; interface Completer { + /** Regular expressions defining valid identifier characters for completion triggers */ identifierRegexps?: Array, + /** Main completion method that provides suggestions for the given context */ getCompletions(editor: Editor, session: EditSession, position: Point, prefix: string, callback: CompleterCallback): void; + /** Returns documentation tooltip for a completion item */ getDocTooltip?(item: Completion): void | string | Completion; + /** Called when a completion item becomes visible */ onSeen?: (editor: Ace.Editor, completion: Completion) => void; + /** Called when a completion item is inserted */ onInsert?: (editor: Ace.Editor, completion: Completion) => void; + /** Cleanup method called when completion is cancelled */ cancel?(): void; + /** Unique identifier for this completer */ id?: string; + /** Characters that trigger autocompletion when typed */ triggerCharacters?: string[]; + /** Whether to hide inline preview text */ hideInlinePreview?: boolean; + /** Custom insertion handler for completion items */ insertMatch?: (editor: Editor, data: Completion) => void; } @@ -1252,10 +1266,15 @@ export namespace Ace { }>> export interface StaticHighlightOptions { + /** Syntax mode (e.g., 'ace/mode/javascript'). Auto-detected from CSS class if not provided */ mode?: string | SyntaxMode, + /** Color theme (e.g., 'ace/theme/textmate'). Defaults to 'ace/theme/textmate' */ theme?: string | Theme, + /** Whether to trim whitespace from code content */ trim?: boolean, + /** Starting line number for display */ firstLineNumber?: number, + /** Whether to show line numbers gutter */ showGutter?: boolean } @@ -1294,6 +1313,28 @@ export namespace Ace { setLabel?: boolean; inline?: boolean; } + + export interface TextAreaOptions { + /** Programming language mode for syntax highlighting (e.g., "javascript", "html", "css") */ + mode?: string; + /** Visual theme for the editor appearance (e.g., "textmate", "monokai", "eclipse") */ + theme?: string; + /** Line wrapping behavior - "off", "free", or specific column number like "40", "80" */ + wrap?: string | number; + /** Font size in CSS units (e.g., "12px", "14px", "16px") */ + fontSize?: string; + /** Whether to display the line number gutter on the left side */ + showGutter?: boolean | string; + /** Keyboard handler/bindings to use - "ace", "vim", or "emacs" */ + keybindings?: string; + /** Whether to show the print margin indicator line */ + showPrintMargin?: boolean | string; + /** Whether to use soft tabs (spaces) instead of hard tabs */ + useSoftTabs?: boolean | string; + /** Whether to show invisible characters like spaces and tabs */ + showInvisibles?: boolean | string; + } + } diff --git a/ace.d.ts b/ace.d.ts index 74063873db7..0feecde7175 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -86,9 +86,13 @@ declare module "ace-code" { gutterOffset: number; } interface HardWrapOptions { + /** First row of the range to process */ startRow: number; + /** Last row of the range to process */ endRow: number; + /** Whether to merge short adjacent lines that fit within the limit */ allowMerge?: boolean; + /** Maximum column width for line wrapping (defaults to editor's print margin) */ column?: number; } interface CommandBarOptions { @@ -778,15 +782,25 @@ declare module "ace-code" { }; type CompleterCallback = (error: any, completions: Completion[]) => void; interface Completer { + /** Regular expressions defining valid identifier characters for completion triggers */ identifierRegexps?: Array; + /** Main completion method that provides suggestions for the given context */ getCompletions(editor: Editor, session: EditSession, position: Point, prefix: string, callback: CompleterCallback): void; + /** Returns documentation tooltip for a completion item */ getDocTooltip?(item: Completion): void | string | Completion; + /** Called when a completion item becomes visible */ onSeen?: (editor: Ace.Editor, completion: Completion) => void; + /** Called when a completion item is inserted */ onInsert?: (editor: Ace.Editor, completion: Completion) => void; + /** Cleanup method called when completion is cancelled */ cancel?(): void; + /** Unique identifier for this completer */ id?: string; + /** Characters that trigger autocompletion when typed */ triggerCharacters?: string[]; + /** Whether to hide inline preview text */ hideInlinePreview?: boolean; + /** Custom insertion handler for completion items */ insertMatch?: (editor: Editor, data: Completion) => void; } interface CompletionOptions { @@ -985,10 +999,15 @@ declare module "ace-code" { value: string; }>>; export interface StaticHighlightOptions { + /** Syntax mode (e.g., 'ace/mode/javascript'). Auto-detected from CSS class if not provided */ mode?: string | SyntaxMode; + /** Color theme (e.g., 'ace/theme/textmate'). Defaults to 'ace/theme/textmate' */ theme?: string | Theme; + /** Whether to trim whitespace from code content */ trim?: boolean; + /** Starting line number for display */ firstLineNumber?: number; + /** Whether to show line numbers gutter */ showGutter?: boolean; } export interface Operation { @@ -1031,6 +1050,26 @@ declare module "ace-code" { setLabel?: boolean; inline?: boolean; } + export interface TextAreaOptions { + /** Programming language mode for syntax highlighting (e.g., "javascript", "html", "css") */ + mode?: string; + /** Visual theme for the editor appearance (e.g., "textmate", "monokai", "eclipse") */ + theme?: string; + /** Line wrapping behavior - "off", "free", or specific column number like "40", "80" */ + wrap?: string | number; + /** Font size in CSS units (e.g., "12px", "14px", "16px") */ + fontSize?: string; + /** Whether to display the line number gutter on the left side */ + showGutter?: boolean | string; + /** Keyboard handler/bindings to use - "ace", "vim", or "emacs" */ + keybindings?: string; + /** Whether to show the print margin indicator line */ + showPrintMargin?: boolean | string; + /** Whether to use soft tabs (spaces) instead of hard tabs */ + useSoftTabs?: boolean | string; + /** Whether to show invisible characters like spaces and tabs */ + showInvisibles?: boolean | string; + } } export const config: typeof import("ace-code/src/config"); export function edit(el?: string | (HTMLElement & { diff --git a/src/ext/beautify.js b/src/ext/beautify.js index be367fb4e21..ea0b01990a6 100644 --- a/src/ext/beautify.js +++ b/src/ext/beautify.js @@ -1,20 +1,48 @@ -// [WIP] +/** + * ## Code beautification and formatting extension. + * + * **This extension is considered outdated.** For better formatting support with modern language servers + * and advanced formatting capabilities, consider using [ace-linters](https://github.com/mkslanc/ace-linters) + * which provides comprehensive language support including formatting, linting, and IntelliSense features. + * + * This legacy extension provides basic formatting for HTML, CSS, JavaScript, and PHP code with support for + * proper indentation, whitespace management, line breaks, and bracket alignment. It handles various language + * constructs including HTML tags, CSS selectors, JavaScript operators, control structures, and maintains + * consistent code style throughout the document. + * + * @module + */ + "use strict"; + var TokenIterator = require("../token_iterator").TokenIterator; function is(token, type) { return token.type.lastIndexOf(type + ".xml") > -1; } -// do not indent after singleton tags or +/** + * List of HTML singleton (self-closing) tags that do not require additional indentation. + * These tags are typically void elements that cannot have child content and are closed within themselves. + * + * @type {string[]} + * @exports + */ exports.singletonTags = ["area", "base", "br", "col", "command", "embed", "hr", "html", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"]; -// insert a line break after block level tags +/** + * List of HTML block-level tags that typically require line breaks after their opening and closing tags. + * These tags represent structural elements that usually contain other content and are rendered as block-level elements. + * + * @type {string[]} + */ exports.blockTags = ["article", "aside", "blockquote", "body", "div", "dl", "fieldset", "footer", "form", "head", "header", "html", "nav", "ol", "p", "script", "section", "style", "table", "tbody", "tfoot", "thead", "ul"]; /** - * + * Configuration options for code formatting behavior. + * Controls various formatting rules such as line break placement and spacing preferences. + * * @type {{lineBreaksAfterCommasInCurlyBlock?: boolean}} */ exports.formatOptions = { @@ -22,9 +50,12 @@ exports.formatOptions = { }; /** - * - * @param {import("../edit_session").EditSession} session + * Formats and beautifies code in the editor session with intelligent indentation, whitespace management, and bracket alignment. + * Supports HTML, CSS, JavaScript, and PHP with configurable formatting options and language-specific rules. + * + * @param {import("../edit_session").EditSession} session - The editor session containing the code to format */ + exports.beautify = function(session) { var iterator = new TokenIterator(session, 0, 0); var token = iterator.getCurrentToken(); @@ -398,6 +429,12 @@ exports.beautify = function(session) { session.doc.setValue(code); }; +/** + * Array of command definitions for the beautify extension. + * Contains the main beautify command with keyboard shortcut and execution handler. + * + * @type {import("../../ace-internal").Ace.Command[]} + */ exports.commands = [{ name: "beautify", description: "Format selection (Beautify)", diff --git a/src/ext/code_lens.js b/src/ext/code_lens.js index 0d64791ed8c..2f610833697 100644 --- a/src/ext/code_lens.js +++ b/src/ext/code_lens.js @@ -1,3 +1,11 @@ +/** + * ## Code Lens extension. + * + * Displaying contextual information and clickable commands above code lines. Supports registering custom providers, + * rendering lens widgets with proper positioning and styling, and handling user interactions with lens commands. + * @module + */ + "use strict"; /** * @typedef {import("../edit_session").EditSession} EditSession diff --git a/src/ext/command_bar.js b/src/ext/command_bar.js index 4ee68c31e07..6123d736f19 100644 --- a/src/ext/command_bar.js +++ b/src/ext/command_bar.js @@ -1,3 +1,14 @@ +/** + * ## Command Bar extension. + * + * Provides an interactive command bar tooltip that displays above the editor's active line. The extension enables + * clickable commands with keyboard shortcuts, icons, and various button types including standard buttons, checkboxes, + * and text elements. Supports overflow handling with a secondary tooltip for additional commands when space is limited. + * The tooltip can be configured to always show or display only on mouse hover over the active line. + * + * @module + */ + /** * @typedef {import("../editor").Editor} Editor * @typedef {import("../../ace-internal").Ace.TooltipCommand} TooltipCommand diff --git a/src/ext/elastic_tabstops_lite.js b/src/ext/elastic_tabstops_lite.js index 66ce76e8c03..9d9bbab9858 100644 --- a/src/ext/elastic_tabstops_lite.js +++ b/src/ext/elastic_tabstops_lite.js @@ -1,3 +1,15 @@ +/** + * ## Elastic Tabstops Lite extension. + * + * Automatically adjusts tab spacing to align content in tabular format by calculating optimal column widths + * and maintaining consistent vertical alignment across multiple lines. Tracks content changes and dynamically + * reprocesses affected rows to ensure proper formatting without manual intervention. + * + * **Enable:** `editor.setOption("useElasticTabstops", true)` + * or configure it during editor initialization in the options object. + * @module + */ + "use strict"; class ElasticTabstopsLite { /** diff --git a/src/ext/emmet.js b/src/ext/emmet.js index 5f5a1e3907a..7e166125066 100644 --- a/src/ext/emmet.js +++ b/src/ext/emmet.js @@ -1,3 +1,13 @@ +/** + * ## Emmet extension + * + * Providing HTML/CSS abbreviation expansion, code navigation, and text editing utilities with configurable options and + * keyboard shortcuts for rapid web development workflow. + * + * **Enable:** `editor.setOption("enableEmmet", true)` + * or configure it during editor initialization in the options object. + * @module + */ "use strict"; var HashHandler = require("../keyboard/hash_handler").HashHandler; var Editor = require("../editor").Editor; @@ -322,9 +332,12 @@ var keymap = { var editorProxy = new AceEmmetEditor(); exports.commands = new HashHandler(); + /** - * @param {Editor} editor - * @return {ReturnType | boolean} + * Runs an Emmet command on the given editor. + * + * @param {Editor} editor - The Ace editor instance to run the Emmet command on + * @return {ReturnType | boolean} The result of the Emmet command execution */ exports.runEmmetCommand = function runEmmetCommand(editor) { if (this.action == "expand_abbreviation_with_tab") { @@ -372,8 +385,10 @@ for (var command in keymap) { } /** - * @param {Editor} editor - * @param {boolean} [enabled] + * Updates the keyboard handler for Emmet commands in the editor. + * + * @param {Editor} editor - The Ace editor instance + * @param {boolean} [enabled] - Whether Emmet commands should be enabled */ exports.updateCommands = function(editor, enabled) { if (enabled) { @@ -383,6 +398,12 @@ exports.updateCommands = function(editor, enabled) { } }; +/** + * Determines if a given editor mode is supported by Emmet. + * + * @param {Object|string} mode - The editor mode to check for Emmet support + * @returns {boolean} Whether the mode is supported by Emmet + */ exports.isSupportedMode = function(mode) { if (!mode) return false; if (mode.emmetConfig) return true; @@ -391,9 +412,11 @@ exports.isSupportedMode = function(mode) { }; /** - * @param {Editor} editor - * @param {string} command - * @return {boolean} + * Checks if an Emmet command is available for the current editor context. + * + * @param {Editor} editor - The current Ace editor instance + * @param {string} command - The Emmet command to check availability for + * @return {boolean} Whether the command is available in the current editor mode */ exports.isAvailable = function(editor, command) { if (/(evaluate_math_expression|expand_abbreviation)$/.test(command)) @@ -423,6 +446,12 @@ var onChangeMode = function(e, target) { exports.updateCommands(editor, enabled); }; +/** + * Loads the Emmet core module dynamically. + * + * @param {Function} [cb] - Optional callback function to be executed after module loading + * @return {boolean} Whether the Emmet core module loading was initiated successfully + */ exports.load = function(cb) { if (typeof emmetPath !== "string") { config.warn("script for emmet-core is not loaded"); @@ -446,6 +475,13 @@ config.defineOptions(Editor.prototype, "editor", { } }); +/** + * Sets the Emmet core module or path. + * + * @param {string|Object} e - Either the path to the Emmet core script or the Emmet core module itself + * If a string is provided, it sets the path to load the Emmet core script. + * If an object is provided, it directly sets the Emmet core module. + */ exports.setCore = function(e) { if (typeof e == "string") emmetPath = e; diff --git a/src/ext/error_marker.js b/src/ext/error_marker.js index 2da3838a7ca..6cea3202064 100644 --- a/src/ext/error_marker.js +++ b/src/ext/error_marker.js @@ -1,3 +1,13 @@ +/** + * ## Error Marker extension + * + * Provides inline error display functionality for Ace editor. Creates visual error markers that appear as tooltips + * below editor lines containing annotations (errors, warnings, info). Enables navigation between error locations with + * keyboard shortcuts and displays context-sensitive messages with proper styling based on annotation severity. + * + * @module + */ + "use strict"; var dom = require("../lib/dom"); var Range = require("../range").Range; @@ -45,7 +55,7 @@ function findAnnotations(session, row, dir) { if (!annotation || !dir) return; - if (annotation.row === row) { + if (annotation.row === row) { do { annotation = annotations[i += dir]; } while (annotation && annotation.row === row); @@ -64,8 +74,10 @@ function findAnnotations(session, row, dir) { } /** - * @param {import("../editor").Editor} editor - * @param {number} dir + * Displays an error marker widget in the editor for annotations at the current cursor position. + * + * @param {import("../editor").Editor} editor - The Ace editor instance + * @param {number} dir - The direction of navigation through annotations (-1 or 1) */ exports.showErrorMarker = function(editor, dir) { var session = editor.session; diff --git a/src/ext/hardwrap.js b/src/ext/hardwrap.js index cc545ac98be..26d2df61b94 100644 --- a/src/ext/hardwrap.js +++ b/src/ext/hardwrap.js @@ -1,11 +1,31 @@ +/** + * ## Text hard wrapping extension for automatic line breaking and text formatting. + * + * Provides intelligent line wrapping functionality that breaks long lines at configurable column limits while + * preserving indentation and optionally merging short adjacent lines. Supports both automatic wrapping during text + * input and manual formatting of selected text ranges. + * + * **Enable:** `editor.setOption("hardWrap", true)` + * or configure it during editor initialization in the options object. + * @module + */ + "use strict"; var Range = require("../range").Range; /** - * @param {import("../editor").Editor} editor - * @param {import("../../ace-internal").Ace.HardWrapOptions} options + * Wraps lines at specified column limits and optionally merges short adjacent lines. + * + * Processes text within the specified row range, breaking lines that exceed the maximum column + * width at appropriate word boundaries while preserving indentation. When merge is enabled, + * combines short consecutive lines that can fit within the column limit. Automatically adjusts + * the end row when new line breaks are inserted to ensure all affected content is processed. + * + * @param {import("../editor").Editor} editor - The editor instance containing the text to wrap + * @param {import("../../ace-internal").Ace.HardWrapOptions} options - Configuration options for wrapping behavior */ + function hardWrap(editor, options) { var max = options.column || editor.getOption("printMarginColumn"); var allowMerge = options.allowMerge != false; diff --git a/src/ext/inline_autocomplete.js b/src/ext/inline_autocomplete.js index 67edac3c7fd..45d832da05b 100644 --- a/src/ext/inline_autocomplete.js +++ b/src/ext/inline_autocomplete.js @@ -1,3 +1,14 @@ +/** + * ## Inline Autocomplete extension + * + * Provides lightweight, prefix-based autocompletion with inline ghost text rendering and an optional command bar tooltip. + * Displays completion suggestions as ghost text directly in the editor with keyboard navigation and interactive controls. + * + * **Enable:** `editor.setOption("enableInlineAutocompletion", true)` + * or configure it during editor initialization in the options object. + * @module + */ + "use strict"; var HashHandler = require("../keyboard/hash_handler").HashHandler; diff --git a/src/ext/keybinding_menu.js b/src/ext/keybinding_menu.js index 26ebbefa601..656ee3477da 100644 --- a/src/ext/keybinding_menu.js +++ b/src/ext/keybinding_menu.js @@ -1,15 +1,18 @@ -/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ -/*global define, require */ - /** - * Show Keyboard Shortcuts - * @fileOverview Show Keyboard Shortcuts
    - * Generates a menu which displays the keyboard shortcuts. + * ## Show Keyboard Shortcuts extension + * + * Provides a keyboard shortcuts display overlay for the Ace editor. Creates an interactive menu that shows all available + * keyboard shortcuts with their corresponding commands, organized in a searchable and navigable format. The menu + * appears as an overlay page and can be triggered via keyboard shortcut (Ctrl-Alt-H/Cmd-Alt-H) or programmatically. + * * @author * Matthew Christopher Kastor-Inare III
    - * ☭ Hial Atropa!! ☭ + * @module */ +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ +/*global define, require */ + "use strict"; var Editor = require("../editor").Editor; @@ -41,7 +44,11 @@ function showKeyboardShortcuts(editor) { } /** - * @param {Editor} editor + * Initializes keyboard shortcut functionality for the editor. + * Adds a method to show keyboard shortcuts and registers a command + * to trigger the keyboard shortcuts display. + * + * @param {Editor} editor The Ace editor instance to initialize */ module.exports.init = function (editor) { Editor.prototype.showKeyboardShortcuts = function () { diff --git a/src/ext/language_tools.js b/src/ext/language_tools.js index 7628f280647..cc04a46c7b8 100644 --- a/src/ext/language_tools.js +++ b/src/ext/language_tools.js @@ -1,3 +1,29 @@ +/** + * ## Language Tools extension for Ace Editor + * + * Provides autocompletion, snippets, and language intelligence features for the Ace code editor. + * This extension integrates multiple completion providers including keyword completion, snippet expansion, + * and text-based completion to enhance the coding experience with contextual suggestions and automated code generation. + * + * **Configuration Options:** + * - `enableBasicAutocompletion`: Enable/disable basic completion functionality + * - `enableLiveAutocompletion`: Enable/disable real-time completion suggestions + * - `enableSnippets`: Enable/disable snippet expansion with Tab key + * - `liveAutocompletionDelay`: Delay before showing live completion popup + * - `liveAutocompletionThreshold`: Minimum prefix length to trigger completion + * + * **Usage:** + * ```javascript + * editor.setOptions({ + * enableBasicAutocompletion: true, + * enableLiveAutocompletion: true, + * enableSnippets: true + * }); + * ``` + * + * @module + */ + "use strict"; /**@type{import("../snippets").snippetManager & {files?: {[key: string]: any}}}*/ var snippetManager = require("../snippets").snippetManager; @@ -77,11 +103,21 @@ var snippetCompleter = { }; var completers = [snippetCompleter, textCompleter, keyWordCompleter]; -// Modifies list of default completers +/** + * Replaces the default list of completers with a new set of completers. + * + * @param {import("../../ace-internal").Ace.Completer[]} [val] + * + */ exports.setCompleters = function(val) { completers.length = 0; if (val) completers.push.apply(completers, val); }; +/** + * Adds a new completer to the list of available completers. + * + * @param {import("../../ace-internal").Ace.Completer} completer - The completer object to be added to the completers array. + */ exports.addCompleter = function(completer) { completers.push(completer); }; diff --git a/src/ext/linking.js b/src/ext/linking.js index 806c965c296..c0388b4bcee 100644 --- a/src/ext/linking.js +++ b/src/ext/linking.js @@ -1,3 +1,14 @@ +/** + * ## Interactive Linking Extension + * + * Enables clickable links and hover interactions in the editor when the Control key is pressed. Provides + * keyboard-accelerated navigation by detecting tokens under the cursor and emitting custom events that can be handled + * by external code to implement go-to-definition, symbol navigation, or other link-based functionality. + * + * **Enable:** `editor.setOption("enableLinking", true)` + * @module + */ + var Editor = require("../editor").Editor; require("../config").defineOptions(Editor.prototype, "editor", { diff --git a/src/ext/menu_tools/get_editor_keyboard_shortcuts.js b/src/ext/menu_tools/get_editor_keyboard_shortcuts.js index c87320e61fc..d090866d427 100644 --- a/src/ext/menu_tools/get_editor_keyboard_shortcuts.js +++ b/src/ext/menu_tools/get_editor_keyboard_shortcuts.js @@ -1,15 +1,28 @@ -/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ -/*global define, require */ - /** - * Get Editor Keyboard Shortcuts - * @fileOverview Get Editor Keyboard Shortcuts
    - * Gets a map of keyboard shortcuts to command names for the current platform. - * @author - * Matthew Christopher Kastor-Inare III
    - * ☭ Hial Atropa!! ☭ + * ## Editor Keyboard Shortcuts Utility + * + * Provides functionality to extract and format keyboard shortcuts from an Ace editor instance. Analyzes all registered + * command handlers and their key bindings to generate a list of available keyboard shortcuts for the + * current platform. Returns formatted key combinations with proper modifier key representations and handles multiple + * bindings per command with pipe-separated notation. + * + * **Usage:** + * ```javascript + * var getKbShortcuts = require('ace/ext/menu_tools/get_editor_keyboard_shortcuts'); + * var shortcuts = getKbShortcuts.getEditorKeybordShortcuts(editor); + * console.log(shortcuts); + * // [ + * // {'command': 'selectall', 'key': 'Ctrl-A'}, + * // {'command': 'copy', 'key': 'Ctrl-C|Ctrl-Insert'} + * // ] + * ``` + * + * @module */ +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ +/*global define, require */ + "use strict"; /** @type{any} */var keys = require("../../lib/keys"); diff --git a/src/ext/menu_tools/overlay_page.js b/src/ext/menu_tools/overlay_page.js index d1cb87e6c3e..fe554441c35 100644 --- a/src/ext/menu_tools/overlay_page.js +++ b/src/ext/menu_tools/overlay_page.js @@ -1,16 +1,28 @@ -/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ -/*global define, require */ - /** - * Overlay Page - * @fileOverview Overlay Page
    - * Generates an overlay for displaying menus. The overlay is an absolutely - * positioned div. - * @author - * Matthew Christopher Kastor-Inare III
    - * ☭ Hial Atropa!! ☭ + * ## Overlay Page utility + * + * Provides modal overlay functionality for displaying editor extension interfaces. Creates a full-screen overlay with + * configurable backdrop behavior, keyboard navigation (ESC to close), and focus management. Used by various extensions + * to display menus, settings panels, and other interactive content over the editor interface. + * + * **Usage:** + * ```javascript + * var overlayPage = require('./overlay_page').overlayPage; + * var contentElement = document.createElement('div'); + * contentElement.innerHTML = '

    Settings

    '; + * + * var overlay = overlayPage(editor, contentElement, function() { + * console.log('Overlay closed'); + * }); + * ``` + * + * @module */ + +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ +/*global define, require */ + 'use strict'; var dom = require("../../lib/dom"); var cssText = require("./settings_menu.css"); @@ -22,10 +34,10 @@ dom.importCssString(cssText, "settings_menu.css", false); * @author * Matthew Christopher Kastor-Inare III
    * ☭ Hial Atropa!! ☭ - * @param editor + * @param {import("../../editor").Editor} editor * @param {HTMLElement} contentElement Any element which may be presented inside * a div. - * @param [callback] + * @param {() => void} [callback] */ module.exports.overlayPage = function overlayPage(editor, contentElement, callback) { var closer = document.createElement('div'); diff --git a/src/ext/modelist.js b/src/ext/modelist.js index 964f4b2265e..8b62a3c8208 100644 --- a/src/ext/modelist.js +++ b/src/ext/modelist.js @@ -1,6 +1,19 @@ +/** + * ## File mode detection utility + * + * Provides automatic detection of editor syntax modes based on file paths and extensions. Maps file extensions to + * appropriate Ace Editor syntax highlighting modes for over 100 programming languages and file formats including + * JavaScript, TypeScript, HTML, CSS, Python, Java, C++, and many others. Supports complex extension patterns and + * provides fallback mechanisms for unknown file types. + * + * @module + */ + "use strict"; /** + * Represents an array to store various syntax modes. + * * @type {Mode[]} */ var modes = []; @@ -269,6 +282,11 @@ var nameOverrides = { }; /** + * An object that serves as a mapping of mode names to their corresponding mode data. + * The keys of this object are mode names (as strings), and the values are expected + * to represent data associated with each mode. + * + * This structure can be used for quick lookups of mode information by name. * @type {Record} */ var modesByName = {}; @@ -281,8 +299,6 @@ for (var name in supportedModes) { modes.push(mode); } -module.exports = { - getModeForPath: getModeForPath, - modes: modes, - modesByName: modesByName -}; +exports.getModeForPath = getModeForPath; +exports.modes = modes; +exports.modesByName = modesByName; \ No newline at end of file diff --git a/src/ext/options.js b/src/ext/options.js index bb37028b917..6457003f45d 100644 --- a/src/ext/options.js +++ b/src/ext/options.js @@ -1,3 +1,22 @@ +/** + * ## Settings Menu extension + * + * Provides a settings panel for configuring editor options through an interactive UI. + * Creates a tabular interface with grouped configuration options including themes, modes, keybindings, + * font settings, display preferences, and advanced editor behaviors. Supports dynamic option rendering + * with various input types (dropdowns, checkboxes, number inputs, button bars) and real-time updates. + * + * **Usage:** + * ```javascript + * var OptionPanel = require("ace/ext/settings_menu").OptionPanel; + * var panel = new OptionPanel(editor); + * panel.render(); + * ``` + * + * @module + */ + + "use strict"; /** * @typedef {import("../editor").Editor} Editor @@ -24,6 +43,12 @@ var modes = modelist.modes.map(function(x){ }); +/** + * Configuration object for grouping various options/settings into categorized groups. + * + * Organizes settings into two main categories: "Main" and "More", + * each containing settings for configurable features of an application. + */ var optionGroups = { Main: { Mode: { @@ -214,6 +239,10 @@ var optionGroups = { } }; +/** + * Option panel component for configuring settings or options. + * The panel is designed to integrate with an editor and render various UI controls based on provided configuration. + */ class OptionPanel { /** * diff --git a/src/ext/prompt.js b/src/ext/prompt.js index 9dc7e46e36f..74ada3ad8e7 100644 --- a/src/ext/prompt.js +++ b/src/ext/prompt.js @@ -1,7 +1,35 @@ /** - * @typedef {import("../editor").Editor} Editor + * ## User Input Prompt extension + * + * Provides customizable modal prompts for gathering user input with support for autocompletion, validation, and + * specialized input types. Includes built-in prompt types for navigation (goto line), command palette, and mode + * selection, with extensible architecture for custom prompt implementations. + * + * **Built-in Prompt Types:** + * - `gotoLine`: Navigate to specific line numbers with selection support + * - `commands`: Command palette with searchable editor commands and shortcuts + * - `modes`: Language mode selector with filtering capabilities + * + * **Usage:** + * ```javascript + * // Basic prompt + * prompt(editor, "Default value", { + * placeholder: "Enter text...", + * onAccept: (data) => console.log(data.value) + * }); + * + * // Built-in prompts + * prompt.gotoLine(editor); + * prompt.commands(editor); + * prompt.modes(editor); + * ``` + * + * @module */ +/** + * @typedef {import("../editor").Editor} Editor + */ "use strict"; @@ -208,8 +236,9 @@ function prompt(editor, message, options, callback) { } /** - * - * @param {Editor} editor + * Displays a "Go to Line" prompt for navigating to specific line and column positions with selection support. + * + * @param {Editor} editor - The editor instance to navigate within * @param {Function} [callback] */ prompt.gotoLine = function(editor, callback) { @@ -320,8 +349,9 @@ prompt.gotoLine = function(editor, callback) { }; /** - * - * @param {Editor} editor + * Displays a searchable command palette for executing editor commands with keyboard shortcuts and history. + * + * @param {Editor} editor - The editor instance to execute commands on * @param {Function} [callback] */ prompt.commands = function(editor, callback) { @@ -455,10 +485,15 @@ prompt.commands = function(editor, callback) { }; /** + * Shows an interactive prompt containing all available syntax highlighting modes + * that can be applied to the editor session. Users can type to filter through the modes list + * and select one to change the editor's syntax highlighting mode. The prompt includes real-time + * filtering based on mode names and captions. * - * @param {Editor} editor + * @param {Editor} editor - The editor instance to change the language mode for * @param {Function} [callback] */ + prompt.modes = function(editor, callback) { /**@type {any[]}*/ var modesArray = modelist.modes; diff --git a/src/ext/rtl.js b/src/ext/rtl.js index 7c8e1f60edb..6de5a01a3d8 100644 --- a/src/ext/rtl.js +++ b/src/ext/rtl.js @@ -1,3 +1,31 @@ +/** + * ## Right-to-Left (RTL) text support extension + * + * Provides bidirectional text support enabling proper rendering and editing of RTL languages such as Arabic, Hebrew, + * and Persian. Handles text direction detection, cursor positioning, and ensures correct visual behavior for mixed + * LTR/RTL content. Includes keyboard shortcuts for manual text direction control and automatic + * RLE (Right-to-Left Embedding) marker management. + * + * **Configuration Options:** + * - `rtlText`: Enable automatic RTL text detection and handling + * - `rtl`: Force RTL direction for the entire editor + * + * **Keyboard Shortcuts:** + * - `Ctrl-Alt-Shift-L` (Win) / `Cmd-Alt-Shift-L` (Mac): Force left-to-right direction + * - `Ctrl-Alt-Shift-R` (Win) / `Cmd-Alt-Shift-R` (Mac): Force right-to-left direction + * + * **Usage:** + * ```javascript + * editor.setOptions({ + * rtlText: true, // Enable automatic RTL detection + * rtl: false // Or force RTL direction + * }); + * ``` + * + * @module + */ + + "use strict"; var commands = [{ diff --git a/src/ext/searchbox.js b/src/ext/searchbox.js index 145439a58be..3345d6f5829 100644 --- a/src/ext/searchbox.js +++ b/src/ext/searchbox.js @@ -1,3 +1,31 @@ +/** + * ## Interactive search and replace UI extension for text editing + * + * Provides a floating search box interface with find/replace functionality including live search results, regex + * support, case sensitivity options, whole word matching, and scoped selection searching. Features keyboard shortcuts + * for quick access and navigation, with visual feedback for search matches and a counter showing current position + * in results. + * + * **Key Features:** + * - Real-time search with highlighted matches + * - Find and replace with individual or bulk operations + * - Advanced options: regex, case sensitivity, whole words, search in selection + * - Keyboard navigation and shortcuts + * - Visual match counter and no-match indicators + * + * **Usage:** + * ```javascript + * // Show search box + * require("ace/ext/searchbox").Search(editor); + * + * // Show with replace functionality + * require("ace/ext/searchbox").Search(editor, true); + * ``` + * + * @module + */ + + "use strict"; /** * @typedef {import("../editor").Editor} Editor @@ -428,9 +456,10 @@ SearchBox.prototype.$closeSearchBarKb = $closeSearchBarKb; exports.SearchBox = SearchBox; /** + * Shows the search box for the editor with optional replace functionality. * - * @param {Editor} editor - * @param {boolean} [isReplace] + * @param {Editor} editor - The editor instance + * @param {boolean} [isReplace] - Whether to show replace options */ exports.Search = function(editor, isReplace) { var sb = editor.searchBox || new SearchBox(editor); diff --git a/src/ext/settings_menu.js b/src/ext/settings_menu.js index f6e600f551f..ad5dda4ed73 100644 --- a/src/ext/settings_menu.js +++ b/src/ext/settings_menu.js @@ -1,16 +1,27 @@ -/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ -/*global define, require */ - /** - * Show Settings Menu - * @fileOverview Show Settings Menu
    - * Displays an interactive settings menu mostly generated on the fly based on - * the current state of the editor. + * ## Interactive Settings Menu Extension + * + * Provides settings interface for the Ace editor that displays dynamically generated configuration options based on + * the current editor state. The menu appears as an overlay panel allowing users to modify editor options, themes, + * modes, and other settings through an intuitive graphical interface. + * + * **Usage:** + * ```javascript + * editor.showSettingsMenu(); + * ``` + * + * The extension automatically registers the `showSettingsMenu` command and method + * on the editor instance when initialized. + * * @author * Matthew Christopher Kastor-Inare III
    - * ☭ Hial Atropa!! ☭ + * + * @module */ +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ +/*global define, require */ + "use strict"; var OptionPanel = require("./options").OptionPanel; var overlayPage = require('./menu_tools/overlay_page').overlayPage; diff --git a/src/ext/simple_tokenizer.js b/src/ext/simple_tokenizer.js index 51d42701fa0..52612fd4866 100644 --- a/src/ext/simple_tokenizer.js +++ b/src/ext/simple_tokenizer.js @@ -1,3 +1,24 @@ +/** + * ## Simple tokenizer extension + * + * Provides standalone tokenization functionality that can parse code content using Ace's highlight rules without + * requiring a full editor instance. This is useful for generating syntax-highlighted tokens for external rendering, + * static code generation, or testing tokenization rules. The tokenizer processes text line by line and returns + * structured token data with CSS class names compatible with Ace themes. + * + * **Usage:** + * ```javascript + * const { tokenize } = require("ace/ext/simple_tokenizer"); + * const { JsonHighlightRules } = require("ace/mode/json_highlight_rules"); + * + * const content = '{"name": "value"}'; + * const tokens = tokenize(content, new JsonHighlightRules()); + * // Returns: [[{className: "ace_paren ace_lparen", value: "{"}, ...]] + * ``` + * + * @module + */ + "use strict"; const { Tokenizer } = require("../tokenizer"); const isTextToken = require("../layer/text_util").isTextToken; diff --git a/src/ext/spellcheck.js b/src/ext/spellcheck.js index badf12f4d71..31fa7debbf4 100644 --- a/src/ext/spellcheck.js +++ b/src/ext/spellcheck.js @@ -1,6 +1,26 @@ +/** + * ## Browser spellcheck integration extension for native spelling correction + * + * Provides seamless integration with browser's native spellcheck functionality through context menu interactions. + * Enables right-click spelling suggestions on misspelled words while preserving editor functionality and text input + * handling. The extension bridges browser spellcheck capabilities with the editor's text manipulation system. + * + * **Enable:** `editor.setOption("spellcheck", true)` (enabled by default) + * or configure it during editor initialization in the options object. + * + * @module + */ + + "use strict"; var event = require("../lib/event"); +/** + * Handles context menu events for spellcheck integration by setting up a hidden input field + * with the word at cursor position to trigger browser spellcheck suggestions. + * @param {any} e - The context menu event + */ + exports.contextMenuHandler = function(e){ var host = e.target; var text = host.textInput.getElement(); diff --git a/src/ext/split.js b/src/ext/split.js index 240a19b88ac..3137cecf9be 100644 --- a/src/ext/split.js +++ b/src/ext/split.js @@ -1,3 +1,21 @@ +/** + * ## Split editor container extension for multiple editor instances + * + * Provides functionality to create and manage multiple editor instances within a single container, + * arranged either horizontally (beside) or vertically (below). Enables synchronized editing sessions + * with shared configurations while maintaining independent cursor positions and selections. + * + * **Usage:** + * ```javascript + * var Split = require("ace/ext/split").Split; + * var split = new Split(container, theme, numberOfSplits); + * split.setOrientation(split.BESIDE); // or split.BELOW + * ``` + * + * @experimental + * @module + */ + "use strict"; /** diff --git a/src/ext/static_highlight.js b/src/ext/static_highlight.js index ada36bfc023..f5f9c951b6e 100644 --- a/src/ext/static_highlight.js +++ b/src/ext/static_highlight.js @@ -1,3 +1,15 @@ +/** + * ## Static syntax highlighting extension for code-to-HTML conversion + * + * Transforms code snippets into syntax-highlighted HTML with CSS styling without requiring a live editor instance. + * Uses a simplified DOM implementation to generate standalone HTML output suitable for static content generation, + * documentation, code export, and embedding highlighted code in web pages. Supports automatic language detection + * from CSS classes and custom modes/themes. + * + * @module + */ + + "use strict"; /** * @typedef {import("../../ace-internal").Ace.SyntaxMode} SyntaxMode @@ -80,11 +92,16 @@ var SimpleTextLayer = function() { SimpleTextLayer.prototype = TextLayer.prototype; /** + * Applies syntax highlighting to an HTML element containing code. + * + * Automatically detects the language from CSS class names (e.g., 'lang-javascript') or uses + * the specified mode. Transforms the element's content into syntax-highlighted HTML with + * CSS styling and preserves any existing child elements by repositioning them after highlighting. * - * @param {HTMLElement} el - * @param {import("../../ace-internal").Ace.StaticHighlightOptions} opts - * @param [callback] - * @returns {boolean} + * @param {HTMLElement} el - The HTML element containing code to highlight + * @param {import("../../ace-internal").Ace.StaticHighlightOptions} opts - Highlighting options + * @param {function} [callback] - Optional callback executed after highlighting is complete + * @returns {boolean} Returns false if no valid mode is found, otherwise true */ var highlight = function(el, opts, callback) { var m = el.className.match(/lang-(\w+)/); diff --git a/src/ext/statusbar.js b/src/ext/statusbar.js index a9e649b018a..cd8d6b776be 100644 --- a/src/ext/statusbar.js +++ b/src/ext/statusbar.js @@ -1,3 +1,20 @@ +/** + * ## Status bar extension for displaying editor state information + * + * Provides a lightweight status indicator that displays real-time information about the editor state including + * cursor position, selection details, recording status, and keyboard binding information. The status bar + * automatically updates on editor events and renders as an inline element that can be embedded in any parent container. + * + * **Usage:** + * ```javascript + * var StatusBar = require("ace/ext/statusbar").StatusBar; + * var statusBar = new StatusBar(editor, parentElement); + * ``` + * + * @module + */ + + "use strict"; /** * diff --git a/src/ext/textarea.js b/src/ext/textarea.js index 29dca121c32..2b5fc359a5c 100644 --- a/src/ext/textarea.js +++ b/src/ext/textarea.js @@ -1,3 +1,24 @@ +/** + * ## Textarea transformation extension + * + * Transforms HTML textarea elements into fully-featured Ace editor instances while maintaining form compatibility + * and providing an interactive settings panel. Handles automatic resizing, form submission integration, and + * preserves the original textarea's styling properties. Includes a visual settings interface for configuring + * editor options like themes, modes, keybindings, and display preferences through an overlay panel. + * + * **Usage:** + * ```javascript + * var ace = require("ace/ext/textarea"); + * var editor = ace.transformTextarea(textareaElement, { + * mode: "javascript", + * theme: "monokai", + * wrap: true + * }); + * ``` + * + * @module + */ + "use strict"; var event = require("../lib/event"); @@ -129,6 +150,17 @@ function setupContainer(element, getValue) { return container; } +/** + * Transforms a textarea element into an Ace editor instance. + * + * This function replaces the original textarea with an Ace editor, + * preserving the textarea's initial value and focus state. It creates + * a container with settings panel and provides full editor functionality. + * + * @param {HTMLTextAreaElement} element - The textarea element to transform + * @param {import("../../ace-internal").Ace.TextAreaOptions} [options] - Optional configuration options for the editor + * @returns {import("../editor").Editor} The created Ace editor instance + */ exports.transformTextarea = function(element, options) { var isFocused = element.autofocus || document.activeElement == element; var session; @@ -470,7 +502,10 @@ function setupSettingPanel(settingDiv, settingOpener, editor) { settingDiv.hideButton = button; } -// Default startup options. +/** + * Default startup options. + * @type {import("../../ace-internal").Ace.TextAreaOptions} + */ exports.defaultOptions = { mode: "javascript", theme: "textmate", diff --git a/src/ext/themelist.js b/src/ext/themelist.js index 7c81f89dba8..c2f6df3a3ee 100644 --- a/src/ext/themelist.js +++ b/src/ext/themelist.js @@ -1,3 +1,16 @@ +/** + * ## Theme enumeration utility + * + * Provides theme management for the Ace Editor by generating and organizing available themes into + * categorized collections. Automatically maps theme data into structured objects containing theme metadata including + * display captions, theme paths, brightness classification (dark/light), and normalized names. Exports both an + * indexed theme collection and a complete themes array for easy integration with theme selection components + * and configuration systems. + * + * @author + * Matthew Christopher Kastor-Inare III
    + * @module + */ /** * Generates a list of themes available when ace was built. * @fileOverview Generates a list of themes available when ace was built. diff --git a/src/ext/whitespace.js b/src/ext/whitespace.js index 3a42fcde289..a0b08dbaac7 100644 --- a/src/ext/whitespace.js +++ b/src/ext/whitespace.js @@ -1,3 +1,13 @@ +/** + * ## Whitespace management and indentation utilities extension + * + * Provides whitespace handling capabilities including automatic indentation detection, trailing whitespace trimming, + * and indentation format conversion. Analyzes code patterns to determine optimal tab settings and offers commands for + * maintaining consistent code formatting across different indentation styles (spaces vs. tabs) and sizes. + * + * @module + */ + "use strict"; /** @@ -86,8 +96,10 @@ exports.$detectIndentation = function(lines, fallback) { }; /** - * @param {EditSession} session - * @returns {{ch?: string, length?: number}|{}} + * Detects the indentation style of a document and configures the session accordingly. + * + * @param {EditSession} session The editing session to analyze and configure + * @returns {{ch?: string, length?: number}|{}} An object containing detected indentation details (character and length) */ exports.detectIndentation = function(session) { var lines = session.getLines(0, 1000); @@ -102,6 +114,7 @@ exports.detectIndentation = function(session) { }; /** + * Removes trailing whitespace from all lines in the session. * @param {EditSession} session * @param {Object} options * @param {boolean} [options.trimEmpty] trim empty lines too @@ -145,6 +158,7 @@ exports.trimTrailingSpace = function(session, options) { }; /** + * Converts indentation format throughout the session to use specified character and size. * @param {EditSession} session * @param {string} ch * @param {number} len diff --git a/types/ace-ext.d.ts b/types/ace-ext.d.ts index ca82e2434d1..3496a7d7da6 100644 --- a/types/ace-ext.d.ts +++ b/types/ace-ext.d.ts @@ -80,8 +80,8 @@ declare module "ace-code/src/ext/command_bar" { } } declare module "ace-code/src/ext/language_tools" { - export function setCompleters(val: any): void; - export function addCompleter(completer: any): void; + export function setCompleters(val?: import("ace-code").Ace.Completer[]): void; + export function addCompleter(completer: import("ace-code").Ace.Completer): void; import textCompleter = require("ace-code/src/autocomplete/text_completer"); export var keyWordCompleter: import("ace-code").Ace.Completer; export var snippetCompleter: import("ace-code").Ace.Completer; @@ -237,12 +237,7 @@ declare module "ace-code/src/ext/beautify" { lineBreaksAfterCommasInCurlyBlock?: boolean; }; export function beautify(session: import("ace-code/src/edit_session").EditSession): void; - export const commands: { - name: string; - description: string; - exec: (editor: any) => void; - bindKey: string; - }[]; + export const commands: import("ace-code").Ace.Command[]; } declare module "ace-code/src/ext/code_lens" { export function setLenses(session: EditSession, lenses: import("ace-code").Ace.CodeLense[]): number; @@ -259,10 +254,10 @@ declare module "ace-code/src/ext/emmet" { export const commands: HashHandler; export function runEmmetCommand(editor: Editor): ReturnType | boolean; export function updateCommands(editor: Editor, enabled?: boolean): void; - export function isSupportedMode(mode: any): boolean; + export function isSupportedMode(mode: any | string): boolean; export function isAvailable(editor: Editor, command: string): boolean; - export function load(cb: any): boolean; - export function setCore(e: any): void; + export function load(cb?: Function): boolean; + export function setCore(e: string | any): void; import { HashHandler } from "ace-code/src/keyboard/hash_handler"; import { Editor } from "ace-code/src/editor"; /** @@ -367,6 +362,17 @@ declare module "ace-code/src/ext/emmet" { } } declare module "ace-code/src/ext/hardwrap" { + /** + * Wraps lines at specified column limits and optionally merges short adjacent lines. + * + * Processes text within the specified row range, breaking lines that exceed the maximum column + * width at appropriate word boundaries while preserving indentation. When merge is enabled, + * combines short consecutive lines that can fit within the column limit. Automatically adjusts + * the end row when new line breaks are inserted to ensure all affected content is processed. + * + * @param {import("ace-code/src/editor").Editor} editor - The editor instance containing the text to wrap + * @param {import("ace-code").Ace.HardWrapOptions} options - Configuration options for wrapping behavior + */ export function hardWrap(editor: import("ace-code/src/editor").Editor, options: import("ace-code").Ace.HardWrapOptions): void; import { Editor } from "ace-code/src/editor"; } @@ -375,7 +381,7 @@ declare module "ace-code/src/ext/menu_tools/settings_menu.css" { export = _exports; } declare module "ace-code/src/ext/menu_tools/overlay_page" { - export function overlayPage(editor: any, contentElement: HTMLElement, callback?: any): { + export function overlayPage(editor: import("ace-code/src/editor").Editor, contentElement: HTMLElement, callback?: () => void): { close: () => void; setIgnoreFocusOut: (ignore: boolean) => void; }; @@ -396,7 +402,20 @@ declare module "ace-code/src/ext/modelist" { * suggested mode. */ export function getModeForPath(path: string): Mode; + /** + * Represents an array to store various syntax modes. + * + * + */ export var modes: Mode[]; + /** + * An object that serves as a mapping of mode names to their corresponding mode data. + * The keys of this object are mode names (as strings), and the values are expected + * to represent data associated with each mode. + * + * This structure can be used for quick lookups of mode information by name. + * + */ export var modesByName: Record; class Mode { constructor(name: string, caption: string, extensions: string); @@ -433,6 +452,10 @@ declare module "ace-code/src/ext/themelist" { }; } declare module "ace-code/src/ext/options" { + /** + * Option panel component for configuring settings or options. + * The panel is designed to integrate with an editor and render various UI controls based on provided configuration. + */ export class OptionPanel { constructor(editor: Editor, element?: HTMLElement); editor: import("ace-code/src/editor").Editor; @@ -733,8 +756,26 @@ declare module "ace-code/src/ext/prompt" { * */ export function prompt(editor: Editor, message: string | Partial, options: Partial, callback?: Function): any; export namespace prompt { + /** + * Displays a "Go to Line" prompt for navigating to specific line and column positions with selection support. + * + * @param {Editor} editor - The editor instance to navigate within + */ function gotoLine(editor: Editor, callback?: Function): void; + /** + * Displays a searchable command palette for executing editor commands with keyboard shortcuts and history. + * + * @param {Editor} editor - The editor instance to execute commands on + */ function commands(editor: Editor, callback?: Function): void; + /** + * Shows an interactive prompt containing all available syntax highlighting modes + * that can be applied to the editor session. Users can type to filter through the modes list + * and select one to change the editor's syntax highlighting mode. The prompt includes real-time + * filtering based on mode names and captions. + * + * @param {Editor} editor - The editor instance to change the language mode for + */ function modes(editor: Editor, callback?: Function): void; } } @@ -767,7 +808,19 @@ declare module "ace-code/src/ext/static-css" { export = _exports; } declare module "ace-code/src/ext/static_highlight" { - function highlight(el: HTMLElement, opts: import("ace-code").Ace.StaticHighlightOptions, callback?: any): boolean; + /** + * Applies syntax highlighting to an HTML element containing code. + * + * Automatically detects the language from CSS class names (e.g., 'lang-javascript') or uses + * the specified mode. Transforms the element's content into syntax-highlighted HTML with + * CSS styling and preserves any existing child elements by repositioning them after highlighting. + * + * @param {HTMLElement} el - The HTML element containing code to highlight + * @param {import("ace-code").Ace.StaticHighlightOptions} opts - Highlighting options + * @param {function} [callback] - Optional callback executed after highlighting is complete + * @returns {boolean} Returns false if no valid mode is found, otherwise true + */ + function highlight(el: HTMLElement, opts: import("ace-code").Ace.StaticHighlightOptions, callback?: Function): boolean; export namespace highlight { export { render, renderSync, highlight, SyntaxMode, Theme }; } From 431006693ced1dfd08d6bfdb38cb995c685a19c8 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:33:03 +0400 Subject: [PATCH 1269/1293] Add `createDiffView` wrapper (#5825) * add `createDiffView` wrapper * refactor diff handling: introduce `DiffViewOptions`, streamline API, and update tests * refactor: rename `DiffView` to `SplitDiffView`, enhance typings, and update usage across modules; add diff ext package tests * fix: update references to `SplitDiffView` after module rename * fix: ensure proper cleanup of editors in `InlineDiffView` and detach functionality; add destroy calls for `diffView` --- ace-internal.d.ts | 35 +- ace.d.ts | 22 +- demo/diff/index.html | 12 +- demo/kitchen-sink/demo.js | 36 ++ demo/test_ace_builds/index.ts | 21 +- demo/test_package/index.ts | 17 +- src/ext/diff.js | 86 +++ src/ext/diff/base_diff_view.js | 32 +- src/ext/diff/diff_test.js | 32 +- src/ext/diff/inline_diff_view.js | 15 +- .../diff/{diff_view.js => split_diff_view.js} | 14 +- src/ext/diff_test.js | 38 ++ src/ext/textarea.js | 17 +- types/ace-ext.d.ts | 568 ++++++++++-------- types/ace-modules.d.ts | 36 +- 15 files changed, 612 insertions(+), 369 deletions(-) create mode 100644 src/ext/diff.js rename src/ext/diff/{diff_view.js => split_diff_view.js} (90%) create mode 100644 src/ext/diff_test.js diff --git a/ace-internal.d.ts b/ace-internal.d.ts index 0ec5700a2f1..ebb8184c245 100644 --- a/ace-internal.d.ts +++ b/ace-internal.d.ts @@ -29,10 +29,10 @@ export namespace Ace { type Config = typeof import("./src/config"); type GutterTooltip = import( "./src/mouse/default_gutter_handler").GutterTooltip; type GutterKeyboardEvent = import( "./src/keyboard/gutter_handler").GutterKeyboardEvent; - type HoverTooltip = import("ace-code/src/tooltip").HoverTooltip; - type Tooltip = import("ace-code/src/tooltip").Tooltip; - type PopupManager = import("ace-code/src/tooltip").PopupManager; - type TextInput = import("ace-code/src/keyboard/textinput").TextInput; + type HoverTooltip = import("./src/tooltip").HoverTooltip; + type Tooltip = import("./src/tooltip").Tooltip; + type TextInput = import("./src/keyboard/textinput").TextInput; + type DiffChunk = import("./src/ext/diff/base_diff_view").DiffChunk; type AfterLoadCallback = (err: Error | null, module: unknown) => void; type LoaderFunction = (moduleName: string, afterLoad: AfterLoadCallback) => void; @@ -1313,28 +1313,6 @@ export namespace Ace { setLabel?: boolean; inline?: boolean; } - - export interface TextAreaOptions { - /** Programming language mode for syntax highlighting (e.g., "javascript", "html", "css") */ - mode?: string; - /** Visual theme for the editor appearance (e.g., "textmate", "monokai", "eclipse") */ - theme?: string; - /** Line wrapping behavior - "off", "free", or specific column number like "40", "80" */ - wrap?: string | number; - /** Font size in CSS units (e.g., "12px", "14px", "16px") */ - fontSize?: string; - /** Whether to display the line number gutter on the left side */ - showGutter?: boolean | string; - /** Keyboard handler/bindings to use - "ace", "vim", or "emacs" */ - keybindings?: string; - /** Whether to show the print margin indicator line */ - showPrintMargin?: boolean | string; - /** Whether to use soft tabs (spaces) instead of hard tabs */ - useSoftTabs?: boolean | string; - /** Whether to show invisible characters like spaces and tabs */ - showInvisibles?: boolean | string; - } - } @@ -1671,3 +1649,8 @@ declare module "./src/mouse/default_gutter_handler" { } } +declare module "./src/ext/diff/base_diff_view" { + export interface BaseDiffView extends Ace.OptionsProvider { + } +} + diff --git a/ace.d.ts b/ace.d.ts index 0feecde7175..3115a5d132f 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -40,8 +40,8 @@ declare module "ace-code" { type GutterKeyboardEvent = import("ace-code/src/keyboard/gutter_handler").GutterKeyboardEvent; type HoverTooltip = import("ace-code/src/tooltip").HoverTooltip; type Tooltip = import("ace-code/src/tooltip").Tooltip; - type PopupManager = import("ace-code/src/tooltip").PopupManager; type TextInput = import("ace-code/src/keyboard/textinput").TextInput; + type DiffChunk = import("ace-code/src/ext/diff/base_diff_view").DiffChunk; type AfterLoadCallback = (err: Error | null, module: unknown) => void; type LoaderFunction = (moduleName: string, afterLoad: AfterLoadCallback) => void; export interface ConfigOptions { @@ -1050,26 +1050,6 @@ declare module "ace-code" { setLabel?: boolean; inline?: boolean; } - export interface TextAreaOptions { - /** Programming language mode for syntax highlighting (e.g., "javascript", "html", "css") */ - mode?: string; - /** Visual theme for the editor appearance (e.g., "textmate", "monokai", "eclipse") */ - theme?: string; - /** Line wrapping behavior - "off", "free", or specific column number like "40", "80" */ - wrap?: string | number; - /** Font size in CSS units (e.g., "12px", "14px", "16px") */ - fontSize?: string; - /** Whether to display the line number gutter on the left side */ - showGutter?: boolean | string; - /** Keyboard handler/bindings to use - "ace", "vim", or "emacs" */ - keybindings?: string; - /** Whether to show the print margin indicator line */ - showPrintMargin?: boolean | string; - /** Whether to use soft tabs (spaces) instead of hard tabs */ - useSoftTabs?: boolean | string; - /** Whether to show invisible characters like spaces and tabs */ - showInvisibles?: boolean | string; - } } export const config: typeof import("ace-code/src/config"); export function edit(el?: string | (HTMLElement & { diff --git a/demo/diff/index.html b/demo/diff/index.html index f3ff2f7b0e8..d582a713c6e 100644 --- a/demo/diff/index.html +++ b/demo/diff/index.html @@ -65,8 +65,8 @@ }); require([ - "ace/ext/diff/diff_view", - "ace/ext/diff/inline_diff_view", + "ace/ext/diff/split_diff_view", + "ace/ext/diff/inline_diff_view", "demo/kitchen-sink/util", "demo/kitchen-sink/layout", "ace/ext/diff/providers/default", @@ -74,7 +74,7 @@ "ace/ext/menu_tools/overlay_page", ], function () { var {InlineDiffView} = require("ace/ext/diff/inline_diff_view"); - var {DiffView} = require("ace/ext/diff/diff_view"); + var {SplitDiffView} = require("ace/ext/diff/split_diff_view"); var {DiffProvider} = require("ace/ext/diff/providers/default"); var {OptionPanel, optionGroups} = require("ace/ext/options") var {buildDom} = require("ace/lib/dom"); @@ -121,7 +121,6 @@ case "inlineA": diffView = new InlineDiffView({ editorA, editorB, - showSideA: true }); if (!debugInline) editorB.container.style.display = "none"; editorA.container.style.display = ""; @@ -129,18 +128,17 @@ case "inlineB": diffView = new InlineDiffView({ editorA, editorB, - showSideA: false + inline: "b" }); editorB.container.style.display = ""; if (!debugInline) editorA.container.style.display = "none"; break; case "split": - diffView = new DiffView({editorA, editorB}); + diffView = new SplitDiffView({editorA, editorB}); editorA.container.style.display = ""; editorB.container.style.display = ""; break; case "off": - diffView.detach("off"); diffView = undefined; editorA.container.style.display = ""; editorB.container.style.display = ""; diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 5a75ecb07ff..6081a2512ab 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -33,6 +33,7 @@ var Range = require("ace/range").Range; var whitespace = require("ace/ext/whitespace"); +var createDiffView = require("../../src/ext/diff").createDiffView; var doclist = require("./doclist"); @@ -323,6 +324,7 @@ window.onresize = onResize; onResize(); /*********** options panel ***************************/ +var diffView; doclist.history = doclist.docs.map(function(doc) { return doc.name; }); @@ -355,6 +357,14 @@ doclist.pickDocument = function(name) { whitespace.detectIndentation(session); optionsPanel.render(); env.editor.focus(); + if (diffView) { + diffView.detach() + diffView = createDiffView({ + inline: "b", + editorB: editor, + valueA: editor.getValue() + }); + } }); }; @@ -365,6 +375,7 @@ var optionsPanel = env.optionsPanel = new OptionPanel(env.editor); var originalAutocompleteCommand = null; + optionsPanel.add({ Main: { Document: { @@ -406,6 +417,31 @@ optionsPanel.add({ ? "Below" : "Beside"; } + }, + "Show diffs": { + position: 0, + type: "buttonBar", + path: "diffView", + values: ["None", "Inline"], + onchange: function (value) { + if (value === "Inline" && !diffView) { + diffView = createDiffView({ + inline: "b", + editorB: editor, + valueA: editor.getValue() + }); + } + else if (value === "None") { + if (diffView) { + diffView.detach(); + diffView = null; + } + } + }, + getValue: function() { + return !diffView ? "None" + : "Inline"; + } } }, More: { diff --git a/demo/test_ace_builds/index.ts b/demo/test_ace_builds/index.ts index 1fa7f5cadb3..063e625ce14 100644 --- a/demo/test_ace_builds/index.ts +++ b/demo/test_ace_builds/index.ts @@ -6,11 +6,14 @@ import "../../src/test/mockdom.js"; var HoverTooltip = ace.require("ace/tooltip").HoverTooltip; import "ace-builds/src-noconflict/mode-javascript"; import "ace-builds/src-noconflict/theme-monokai"; +import {DiffViewOptions } from "ace-builds/src-noconflict/ext-diff"; +import "ace-builds/src-noconflict/ext-diff"; +const diff = ace.require("ace/ext/diff"); const MarkerGroup = ace.require("ace/marker_group").MarkerGroup; const MouseEvent = ace.require("ace/mouse/mouse_event").MouseEvent; var Tooltip = ace.require("ace/tooltip").Tooltip; -var popupManager: Ace.PopupManager = ace.require("ace/tooltip").popupManager; +var popupManager = ace.require("ace/tooltip").popupManager; const editor = ace.edit(null); // should not be an error editor.setTheme("ace/theme/monokai"); @@ -63,4 +66,18 @@ tooltip.show('hello'); popupManager.addPopup(tooltip); -editor.destroy && editor.destroy(); \ No newline at end of file +editor.destroy && editor.destroy(); + +const diffViewOptions: DiffViewOptions = { + maxDiffs: 1000, + folding: true +} + +var diffView = diff.createDiffView({ + valueB: "test", + inline: "b" +}, diffViewOptions); + +diffView.setProvider(new diff.DiffProvider()); + +diffView.destroy(); \ No newline at end of file diff --git a/demo/test_package/index.ts b/demo/test_package/index.ts index e732f66791b..055c48d5966 100644 --- a/demo/test_package/index.ts +++ b/demo/test_package/index.ts @@ -16,6 +16,7 @@ import "../../src/test/mockdom.js"; import {tokenize} from "ace-code/src/ext/simple_tokenizer"; import {JavaScriptHighlightRules} from "ace-code/src/mode/javascript_highlight_rules"; import {highlight} from "ace-code/src/ext/static_highlight"; +import {createDiffView, DiffProvider, DiffViewOptions} from "ace-code/src/ext/diff"; // TODO this does not work in node // import "ace-code/esm-resolver"; @@ -155,4 +156,18 @@ editor.commands.on('afterExec', ({editor, command}) => { editor.commands.on('exec', ({editor, command}) => { console.log(editor.getValue(), command.name); -}); \ No newline at end of file +}); + +const diffViewOptions: DiffViewOptions = { + maxDiffs: 1000, + folding: true +} + +var diffView = createDiffView({ + valueB: "test", + inline: "b" +}, diffViewOptions); + +diffView.setProvider(new DiffProvider()); + +diffView.destroy(); \ No newline at end of file diff --git a/src/ext/diff.js b/src/ext/diff.js new file mode 100644 index 00000000000..fe597d5dba7 --- /dev/null +++ b/src/ext/diff.js @@ -0,0 +1,86 @@ +/** + * ## Diff extension + * + * Provides side-by-side and inline diff view capabilities for comparing code differences between two versions. + * Supports visual highlighting of additions, deletions, and modifications with customizable diff providers + * and rendering options. Includes features for synchronized scrolling, line number alignment, and + * various diff computation algorithms. + * + * **Components:** + * - `InlineDiffView`: Single editor view showing changes inline with markers + * - `SplitDiffView`: Side-by-side comparison view with two synchronized editors + * - `DiffProvider`: Configurable algorithms for computing differences + * + * **Usage:** + * ```javascript + * const diffView = createDiffView({ + * valueA: originalContent, + * valueB: modifiedContent, + * inline: false // or 'a'/'b' for inline view + * }); + * ``` + * + * @module + */ + +var InlineDiffView = require("./diff/inline_diff_view").InlineDiffView; +var SplitDiffView = require("./diff/split_diff_view").SplitDiffView; +var DiffProvider = require("./diff/providers/default").DiffProvider; + +/** + * Interface representing a model for handling differences between two views or states. + * @typedef {Object} DiffModel + * @property {import("../editor").Editor} [editorA] - The editor for the original view. + * @property {import("../editor").Editor} [editorB] - The editor for the edited view. + * @property {import("../edit_session").EditSession} [sessionA] - The edit session for the original view. + * @property {import("../edit_session").EditSession} [sessionB] - The edit session for the edited view. + * @property {string} [valueA] - The original content. + * @property {string} [valueB] - The modified content. + * @property {"a"|"b"} [inline] - Whether to show the original view("a") or modified view("b") for inline diff view + * @property {IDiffProvider} [diffProvider] - Provider for computing differences between original and modified content. + */ + +/** + * @typedef {Object} DiffViewOptions + * @property {boolean} [showOtherLineNumbers=true] - Whether to show line numbers in the other editor's gutter + * @property {boolean} [folding] - Whether to enable code folding widgets + * @property {boolean} [syncSelections] - Whether to synchronize selections between both editors + * @property {boolean} [ignoreTrimWhitespace] - Whether to ignore trimmed whitespace when computing diffs + * @property {boolean} [wrap] - Whether to enable word wrapping in both editors + * @property {number} [maxDiffs=5000] - Maximum number of diffs to compute before failing silently + * @property {string|import("../../ace-internal").Ace.Theme} [theme] - Theme to apply to both editors + */ + +/** + * @typedef {Object} IDiffProvider + * @property {(originalLines: string[], modifiedLines: string[], opts?: any) => import("./diff/base_diff_view").DiffChunk[]} compute - Computes differences between original and modified lines + */ + + +/** + * Creates a diff view for comparing code. + * @param {DiffModel} [diffModel] model for the diff view + * @param {DiffViewOptions} [options] options for the diff view + * @returns {InlineDiffView|SplitDiffView} Configured diff view instance + */ +function createDiffView(diffModel, options) { + diffModel = diffModel || {}; + diffModel.diffProvider = diffModel.diffProvider || new DiffProvider(); //use default diff provider; + let diffView; + if (diffModel.inline) { + diffView = new InlineDiffView(diffModel); + } + else { + diffView = new SplitDiffView(diffModel); + } + if (options) { + diffView.setOptions(options); + } + + return diffView; +} + +exports.InlineDiffView = InlineDiffView; +exports.SplitDiffView = SplitDiffView; +exports.DiffProvider = DiffProvider; +exports.createDiffView = createDiffView; diff --git a/src/ext/diff/base_diff_view.js b/src/ext/diff/base_diff_view.js index 019ad027bd5..9bad56162da 100644 --- a/src/ext/diff/base_diff_view.js +++ b/src/ext/diff/base_diff_view.js @@ -66,21 +66,13 @@ class BaseDiffView { } /** - * @param {Object} [diffModel] - The model for the diff view. - * @param {Editor} [diffModel.editorA] - The editor for the original view. - * @param {Editor} [diffModel.editorB] - The editor for the edited view. - * @param {EditSession} [diffModel.sessionA] - The edit session for the original view. - * @param {EditSession} [diffModel.sessionB] - The edit session for the edited view. - * @param {string} [diffModel.valueA] - The original content. - * @param {string} [diffModel.valueB] - The modified content. - * @param {boolean} [diffModel.showSideA] - Whether to show the original view or modified view. - * @param {import("./providers/default").DiffProvider} [diffModel.diffProvider] - The diff provider to use. + * @param {import("../diff").DiffModel} [diffModel] - The model for the diff view. */ $setupModels(diffModel) { if (diffModel.diffProvider) { this.setProvider(diffModel.diffProvider); } - this.showSideA = diffModel.showSideA == undefined ? true : diffModel.showSideA; + this.showSideA = diffModel.inline == undefined ? true : diffModel.inline === "a"; var diffEditorOptions = /**@type {Partial}*/({ scrollPastEnd: 0.5, highlightActiveLine: false, @@ -96,25 +88,25 @@ class BaseDiffView { this.savedOptionsA = diffModel.editorA && diffModel.editorA.getOptions(diffEditorOptions); this.savedOptionsB = diffModel.editorB && diffModel.editorB.getOptions(diffEditorOptions); - if (!this.inlineDiffEditor || diffModel.showSideA) { + if (!this.inlineDiffEditor || diffModel.inline === "a") { this.editorA = diffModel.editorA || this.$setupModel(diffModel.sessionA, diffModel.valueA); this.container && this.container.appendChild(this.editorA.container); this.editorA.setOptions(diffEditorOptions); } - if (!this.inlineDiffEditor || !diffModel.showSideA) { + if (!this.inlineDiffEditor || diffModel.inline === "b") { this.editorB = diffModel.editorB || this.$setupModel(diffModel.sessionB, diffModel.valueB); this.container && this.container.appendChild(this.editorB.container); this.editorB.setOptions(diffEditorOptions); } if (this.inlineDiffEditor) { - this.activeEditor = diffModel.showSideA ? this.editorA : this.editorB; - this.otherSession = diffModel.showSideA ? this.sessionB : this.sessionA; + this.activeEditor = this.showSideA ? this.editorA : this.editorB; + this.otherSession = this.showSideA ? this.sessionB : this.sessionA; var cloneOptions = this.activeEditor.getOptions(); cloneOptions.readOnly = true; delete cloneOptions.mode; this.otherEditor = new Editor(new Renderer(null), undefined, cloneOptions); - if (diffModel.showSideA) { + if (this.showSideA) { this.editorB = this.otherEditor; } else { this.editorA = this.otherEditor; @@ -146,7 +138,7 @@ class BaseDiffView { $setupModel(session, value) { var editor = new Editor(new Renderer(), session); editor.session.setUndoManager(new UndoManager()); - if (value) { + if (value != undefined) { editor.setValue(value, -1); } return editor; @@ -210,7 +202,7 @@ class BaseDiffView { this.diffSession = session; this.sessionA = this.sessionB = null; if (this.diffSession) { - this.chunks = this.diffSession.chunks; + this.chunks = this.diffSession.chunks || []; this.editorA && this.editorA.setSession(session.sessionA); this.editorB && this.editorB.setSession(session.sessionB); this.sessionA = this.diffSession.sessionA; @@ -363,6 +355,9 @@ class BaseDiffView { if (!editor) { return; } + if (typeof editor.renderer.$scrollDecorator.addZone !== "function") { + return; + } if (change.old.start.row != change.old.end.row) { editor.renderer.$scrollDecorator.addZone(change.old.start.row, change.old.end.row - 1, "delete"); } @@ -598,8 +593,6 @@ class BaseDiffView { if (this.savedOptionsB &&this.savedOptionsB.customScrollbar) { this.$resetDecorators(this.editorB.renderer); } - - this.editorA = this.editorB = null; } @@ -622,6 +615,7 @@ class BaseDiffView { this.detach(); this.editorA && this.editorA.destroy(); this.editorB && this.editorB.destroy(); + this.editorA = this.editorB = null; } gotoNext(dir) { diff --git a/src/ext/diff/diff_test.js b/src/ext/diff/diff_test.js index dfce31f916d..026d12e223c 100644 --- a/src/ext/diff/diff_test.js +++ b/src/ext/diff/diff_test.js @@ -4,7 +4,7 @@ var assert = require("../../test/assertions"); require("../../test/mockdom"); var {InlineDiffView} = require("./inline_diff_view"); -var {DiffView} = require("./diff_view"); +var {SplitDiffView} = require("./split_diff_view"); var {DiffProvider} = require("./providers/default"); var ace = require("../../ace"); @@ -167,7 +167,7 @@ module.exports = { var diffView = new InlineDiffView({ editorA, editorB, - showSideA: true, + inline: "a", diffProvider, }); editorA.session.addFold("---", new Range(0, 0, 2, 0)); @@ -182,7 +182,7 @@ module.exports = { sessionB.widgetManager.attach(editorB); checkEventRegistry(); - diffView = new DiffView({editorA, editorB, diffProvider}); + diffView = new SplitDiffView({editorA, editorB, diffProvider}); editorB.session.addFold("---", new Range(5, 0, 7, 0)); editorB.renderer.$loop._flush(); editorA.renderer.$loop._flush(); @@ -206,7 +206,7 @@ module.exports = { var diffView = new InlineDiffView({ editorB, valueA: editorA.getValue(), - showSideB: true, + inline: "b", diffProvider, }); @@ -226,7 +226,7 @@ module.exports = { diffView = new InlineDiffView({ valueA, valueB, - showSideA: true, + inline: "a", diffProvider, }, document.body); setEditorPosition(diffView.editorA); @@ -241,7 +241,7 @@ module.exports = { assert.equal(diffView.editorA.renderer.layerConfig.offset, 0.5 * lineHeight); diffView.detach(); - diffView = new DiffView({ + diffView = new SplitDiffView({ valueA, valueB, diffProvider, @@ -257,7 +257,7 @@ module.exports = { diffView = new InlineDiffView({ valueA, valueB, - showSideA: false, + inline: "b", }, document.body); setEditorPosition(diffView.editorB); diffView.onInput(); @@ -274,7 +274,7 @@ module.exports = { editorA.session.setValue(valueA); editorB.session.setValue(valueB); - diffView = new DiffView({ + diffView = new SplitDiffView({ editorA, editorB, diffProvider, }); @@ -316,7 +316,7 @@ module.exports = { editorA.session.setValue("a\n"); editorB.session.setValue("\n\na\n\n"); - diffView = new DiffView({ + diffView = new SplitDiffView({ editorA, editorB, diffProvider, }); @@ -334,7 +334,7 @@ module.exports = { editorA.session.setValue(getValueA(longLinesDiff)); editorB.session.setValue(getValueB(longLinesDiff)); - diffView = new DiffView({ + diffView = new SplitDiffView({ editorA, editorB, diffProvider, }); @@ -360,7 +360,7 @@ module.exports = { diffView = new InlineDiffView({ editorA, editorB, - showSideA: true, + inline: "a", diffProvider, }); diffView.onInput(); @@ -401,7 +401,7 @@ module.exports = { editorA.session.setValue(["a", "b", "c"].join("\n")); editorB.session.setValue(["a", "c", "X"].join("\n")); - diffView = new DiffView({ editorA, editorB }); + diffView = new SplitDiffView({ editorA, editorB }); diffView.setProvider(new DiffProvider()); diffView.onInput(); @@ -418,7 +418,7 @@ module.exports = { editorA.session.setValue(["a", "b", "c"].join("\n")); editorB.session.setValue(["a", "c", "X"].join("\n")); - diffView = new InlineDiffView({ editorA, editorB, showSideA: true }); + diffView = new InlineDiffView({ editorA, editorB, inline: "a" }); diffView.setProvider(new DiffProvider()); diffView.onInput(); @@ -428,6 +428,12 @@ module.exports = { assertDecoratorsPlacement(editorA, true); done(); }, 0); + }, + "test: second editor destroyed on detach in inline diff view": function() { + diffView = new InlineDiffView({ editorA, inline: "a" }); + assert.ok(Array.isArray(diffView.otherEditor.$toDestroy)); + diffView.detach(); + assert.ok(diffView.otherEditor.$toDestroy == undefined); } }; diff --git a/src/ext/diff/inline_diff_view.js b/src/ext/diff/inline_diff_view.js index 22270c81503..4704ab15419 100644 --- a/src/ext/diff/inline_diff_view.js +++ b/src/ext/diff/inline_diff_view.js @@ -8,18 +8,12 @@ const config = require("../../config"); class InlineDiffView extends BaseDiffView { /** * Constructs a new inline DiffView instance. - * @param {Object} [diffModel] - The model for the diff view. - * @param {import("ace-code").Editor} [diffModel.editorA] - The editor for the original view. - * @param {import("ace-code").Editor} [diffModel.editorB] - The editor for the edited view. - * @param {import("ace-code").EditSession} [diffModel.sessionA] - The edit session for the original view. - * @param {import("ace-code").EditSession} [diffModel.sessionB] - The edit session for the edited view. - * @param {string} [diffModel.valueA] - The original content. - * @param {string} [diffModel.valueB] - The modified content. - * @param {boolean} [diffModel.showSideA] - Whether to show the original view or modified view. + * @param {import("../diff").DiffModel} [diffModel] - The model for the diff view. * @param {HTMLElement} [container] - optional container element for the DiffView. */ constructor(diffModel, container) { diffModel = diffModel || {}; + diffModel.inline = diffModel.inline || "a"; super( true, container); this.init(diffModel); } @@ -398,6 +392,11 @@ class InlineDiffView extends BaseDiffView { this.markerLayer.setMarkers(this.otherSession.getMarkers()); this.markerLayer.update(newConfig); } + + detach() { + super.detach(); + this.otherEditor && this.otherEditor.destroy(); + } } exports.InlineDiffView = InlineDiffView; diff --git a/src/ext/diff/diff_view.js b/src/ext/diff/split_diff_view.js similarity index 90% rename from src/ext/diff/diff_view.js rename to src/ext/diff/split_diff_view.js index fe030d1bc74..f6a321c3092 100644 --- a/src/ext/diff/diff_view.js +++ b/src/ext/diff/split_diff_view.js @@ -1,21 +1,13 @@ "use strict"; -var LineWidgets = require("../../line_widgets").LineWidgets; - var BaseDiffView = require("./base_diff_view").BaseDiffView; var config = require("../../config"); -class DiffView extends BaseDiffView { +class SplitDiffView extends BaseDiffView { /** * Constructs a new side by side DiffView instance. * - * @param {Object} [diffModel] - The model for the diff view. - * @param {import("../../editor").Editor} [diffModel.editorA] - The editor for the original view. - * @param {import("../../editor").Editor} [diffModel.editorB] - The editor for the edited view. - * @param {import("../../edit_session").EditSession} [diffModel.sessionA] - The edit session for the original view. - * @param {import("../../edit_session").EditSession} [diffModel.sessionB] - The edit session for the edited view. - * @param {string} [diffModel.valueA] - The original content. - * @param {string} [diffModel.valueB] - The modified content. + * @param {import("../diff").DiffModel} [diffModel] - The model for the diff view. */ constructor(diffModel) { diffModel = diffModel || {}; @@ -220,4 +212,4 @@ class DiffView extends BaseDiffView { } -exports.DiffView = DiffView; +exports.SplitDiffView = SplitDiffView; diff --git a/src/ext/diff_test.js b/src/ext/diff_test.js new file mode 100644 index 00000000000..51d4627b3e2 --- /dev/null +++ b/src/ext/diff_test.js @@ -0,0 +1,38 @@ +"use strict"; + +var assert = require("../test/assertions"); +require("../test/mockdom"); + +var {InlineDiffView} = require("./diff/inline_diff_view"); +var {SplitDiffView} = require("./diff/split_diff_view"); +const {createDiffView} = require("./diff"); + +var diffView; + +module.exports = { + tearDown: function () { + if (diffView) { + diffView.destroy(); + diffView = null; + } + }, + "test: diff wrapper test": function () { + diffView = createDiffView({inline: "a"}); + assert.ok(diffView instanceof InlineDiffView); + diffView.destroy(); + diffView = createDiffView({}); + assert.ok(diffView instanceof SplitDiffView); + }, + "test: diff setOptions": function () { + diffView = createDiffView({}, { + maxDiffs: 1000, + ignoreTrimWhitespace: true + }); + assert.ok(diffView.getOption("maxDiffs"), 1000); + assert.ok(diffView.getOption("ignoreTrimWhitespace"), true); + } +}; + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/src/ext/textarea.js b/src/ext/textarea.js index 2b5fc359a5c..8895fe60350 100644 --- a/src/ext/textarea.js +++ b/src/ext/textarea.js @@ -27,6 +27,19 @@ var ace = require("../ace"); module.exports = exports = ace; +/** + * @typedef {Object} TextAreaOptions + * @property {string} [mode] - Programming language mode for syntax highlighting (e.g., "javascript", "html", "css") + * @property {string} [theme] - Visual theme for the editor appearance (e.g., "textmate", "monokai", "eclipse") + * @property {string|number} [wrap] - Line wrapping behavior - "off", "free", or specific column number like "40", "80" + * @property {string} [fontSize] - Font size in CSS units (e.g., "12px", "14px", "16px") + * @property {boolean|string} [showGutter] - Whether to display the line number gutter on the left side + * @property {string} [keybindings] - Keyboard handler/bindings to use - "ace", "vim", or "emacs" + * @property {boolean|string} [showPrintMargin] - Whether to show the print margin indicator line + * @property {boolean|string} [useSoftTabs] - Whether to use soft tabs (spaces) instead of hard tabs + * @property {boolean|string} [showInvisibles] - Whether to show invisible characters like spaces and tabs + */ + /** * Returns the CSS property of element. * 1) If the CSS property is on the style object of the element, use it, OR @@ -158,7 +171,7 @@ function setupContainer(element, getValue) { * a container with settings panel and provides full editor functionality. * * @param {HTMLTextAreaElement} element - The textarea element to transform - * @param {import("../../ace-internal").Ace.TextAreaOptions} [options] - Optional configuration options for the editor + * @param {TextAreaOptions} [options] - Optional configuration options for the editor * @returns {import("../editor").Editor} The created Ace editor instance */ exports.transformTextarea = function(element, options) { @@ -504,7 +517,7 @@ function setupSettingPanel(settingDiv, settingOpener, editor) { /** * Default startup options. - * @type {import("../../ace-internal").Ace.TextAreaOptions} + * @type {TextAreaOptions} */ exports.defaultOptions = { mode: "javascript", diff --git a/types/ace-ext.d.ts b/types/ace-ext.d.ts index 3496a7d7da6..68e7aeac24c 100644 --- a/types/ace-ext.d.ts +++ b/types/ace-ext.d.ts @@ -217,6 +217,333 @@ declare module "ace-code/src/ext/searchbox" { } import { HashHandler } from "ace-code/src/keyboard/hash_handler"; } +declare module "ace-code/src/ext/diff/scroll_diff_decorator" { + export class ScrollDiffDecorator extends Decorator { + constructor(scrollbarV: import("ace-code").Ace.VScrollbar, renderer: import("ace-code/src/virtual_renderer").VirtualRenderer, forInlineDiff?: boolean); + addZone(startRow: number, endRow: number, type: "delete" | "insert"): void; + setSessions(sessionA: import("ace-code/src/edit_session").EditSession, sessionB: import("ace-code/src/edit_session").EditSession): void; + sessionA: import("ace-code/src/edit_session").EditSession; + sessionB: import("ace-code/src/edit_session").EditSession; + } + import { Decorator } from "ace-code/src/layer/decorators"; +} +declare module "ace-code/src/ext/diff/styles-css" { + export const cssText: "\n/*\n * Line Markers\n */\n.ace_diff {\n position: absolute;\n z-index: 0;\n}\n.ace_diff.inline {\n z-index: 20;\n}\n/*\n * Light Colors \n */\n.ace_diff.insert {\n background-color: #EFFFF1;\n}\n.ace_diff.delete {\n background-color: #FFF1F1;\n}\n.ace_diff.aligned_diff {\n background: rgba(206, 194, 191, 0.26);\n background: repeating-linear-gradient(\n 45deg,\n rgba(122, 111, 108, 0.26),\n rgba(122, 111, 108, 0.26) 5px,\n rgba(0, 0, 0, 0) 5px,\n rgba(0, 0, 0, 0) 10px \n );\n}\n\n.ace_diff.insert.inline {\n background-color: rgb(74 251 74 / 18%); \n}\n.ace_diff.delete.inline {\n background-color: rgb(251 74 74 / 15%);\n}\n\n.ace_diff.delete.inline.empty {\n background-color: rgba(255, 128, 79, 0.7);\n width: 2px !important;\n}\n\n.ace_diff.insert.inline.empty {\n background-color: rgba(49, 230, 96, 0.7);\n width: 2px !important;\n}\n\n.ace_diff-active-line {\n border-bottom: 1px solid;\n border-top: 1px solid;\n background: transparent;\n position: absolute;\n box-sizing: border-box;\n border-color: #9191ac;\n}\n\n.ace_dark .ace_diff-active-line {\n background: transparent;\n border-color: #75777a;\n}\n \n\n/* gutter changes */\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell,\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell_svg-icons {\n padding-right: 13px;\n}\n\n.ace_mini-diff_gutter_other > .ace_gutter-cell,\n.ace_mini-diff_gutter_other > .ace_gutter-cell_svg-icons {\n display: none;\n}\n\n.ace_mini-diff_gutter_other {\n pointer-events: none;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #EFFFF1;\n border-left: 3px solid #2BB534;\n padding-left: 16px;\n display: block;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #FFF1F1;\n border-left: 3px solid #EA7158;\n padding-left: 16px;\n display: block;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added:after {\n position: absolute;\n right: 2px;\n content: \"+\";\n color: darkgray;\n background-color: inherit;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted:after {\n position: absolute;\n right: 2px;\n content: \"-\";\n color: darkgray;\n background-color: inherit;\n}\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-added:after,\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-deleted:after {\n display: none;\n}\n\n.ace_diff_other .ace_selection {\n filter: drop-shadow(1px 2px 3px darkgray);\n}\n\n.ace_hidden_marker-layer .ace_bracket {\n display: none;\n}\n\n\n\n/*\n * Dark Colors \n */\n\n.ace_dark .ace_diff.insert {\n background-color: #212E25;\n}\n.ace_dark .ace_diff.delete {\n background-color: #3F2222;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #212E25;\n border-left-color:#00802F;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #3F2222;\n border-left-color: #9C3838;\n}\n\n"; +} +declare module "ace-code/src/ext/diff/gutter_decorator" { + export class MinimalGutterDiffDecorator { + constructor(editor: import("ace-code/src/editor").Editor, type: number); + gutterClass: string; + gutterCellsClasses: { + add: string; + delete: string; + }; + editor: import("ace-code/src/editor").Editor; + type: number; + chunks: any[]; + attachToEditor(): void; + renderGutters(e: any, gutterLayer: any): void; + setDecorations(changes: any): void; + dispose(): void; + } +} +declare module "ace-code/src/ext/diff/inline_diff_view" { + export class InlineDiffView extends BaseDiffView { + /** + * Constructs a new inline DiffView instance. + * @param {import("ace-code/src/diff").DiffModel} [diffModel] - The model for the diff view. + * @param {HTMLElement} [container] - optional container element for the DiffView. + */ + constructor(diffModel?: import("ace-code/src/ext/diff").DiffModel, container?: HTMLElement); + init(diffModel: any): void; + onAfterRender(changes: number, renderer: import("ace-code").VirtualRenderer): void; + textLayer: any; + markerLayer: any; + gutterLayer: any; + cursorLayer: any; + initRenderer(restore: any): void; + initTextLayer(): void; + initTextInput(restore: any): void; + othertextInput: any; + otherEditorContainer: any; + selectEditor(editor: any): void; + removeBracketHighlight(editor: any): void; + initMouse(): void; + onMouseDetach: () => void; + onChangeWrapLimit(): void; + } + import { BaseDiffView } from "ace-code/src/ext/diff/base_diff_view"; +} +declare module "ace-code/src/ext/diff/split_diff_view" { + export class SplitDiffView extends BaseDiffView { + /** + * Constructs a new side by side DiffView instance. + * + * @param {import("ace-code/src/diff").DiffModel} [diffModel] - The model for the diff view. + */ + constructor(diffModel?: import("ace-code/src/ext/diff").DiffModel); + init(diffModel: any): void; + onMouseWheel(ev: any): any; + onScroll(e: any, session: any): void; + onChangeWrapLimit(): void; + syncScroll(renderer: import("ace-code/src/virtual_renderer").VirtualRenderer): void; + scrollA: any; + scrollB: any; + scrollSetBy: any; + scrollSetAt: number; + } + import { BaseDiffView } from "ace-code/src/ext/diff/base_diff_view"; +} +declare module "ace-code/src/ext/diff/providers/default" { + export function computeDiff(originalLines: any, modifiedLines: any, options: any): any; + /** + * VSCode’s computeDiff provider + */ + export class DiffProvider { + compute(originalLines: any, modifiedLines: any, opts: any): any; + } +} +declare module "ace-code/src/ext/diff" { + /** + * Interface representing a model for handling differences between two views or states. + */ + export type DiffModel = { + /** + * - The editor for the original view. + */ + editorA?: import("ace-code/src/editor").Editor; + /** + * - The editor for the edited view. + */ + editorB?: import("ace-code/src/editor").Editor; + /** + * - The edit session for the original view. + */ + sessionA?: import("ace-code/src/edit_session").EditSession; + /** + * - The edit session for the edited view. + */ + sessionB?: import("ace-code/src/edit_session").EditSession; + /** + * - The original content. + */ + valueA?: string; + /** + * - The modified content. + */ + valueB?: string; + /** + * - Whether to show the original view("a") or modified view("b") for inline diff view + */ + inline?: "a" | "b"; + /** + * - Provider for computing differences between original and modified content. + */ + diffProvider?: IDiffProvider; + }; + export type DiffViewOptions = { + /** + * - Whether to show line numbers in the other editor's gutter + */ + showOtherLineNumbers?: boolean; + /** + * - Whether to enable code folding widgets + */ + folding?: boolean; + /** + * - Whether to synchronize selections between both editors + */ + syncSelections?: boolean; + /** + * - Whether to ignore trimmed whitespace when computing diffs + */ + ignoreTrimWhitespace?: boolean; + /** + * - Whether to enable word wrapping in both editors + */ + wrap?: boolean; + /** + * - Maximum number of diffs to compute before failing silently + */ + maxDiffs?: number; + /** + * - Theme to apply to both editors + */ + theme?: string | import("ace-code").Ace.Theme; + }; + export type IDiffProvider = { + /** + * - Computes differences between original and modified lines + */ + compute: (originalLines: string[], modifiedLines: string[], opts?: any) => import("ace-code/src/ext/diff/base_diff_view").DiffChunk[]; + }; + import { InlineDiffView } from "ace-code/src/ext/diff/inline_diff_view"; + import { SplitDiffView } from "ace-code/src/ext/diff/split_diff_view"; + import { DiffProvider } from "ace-code/src/ext/diff/providers/default"; + /** + * Interface representing a model for handling differences between two views or states. + * @property {import("ace-code/src/editor").Editor} [editorA] - The editor for the original view. + * @property {import("ace-code/src/editor").Editor} [editorB] - The editor for the edited view. + * @property {import("ace-code/src/edit_session").EditSession} [sessionA] - The edit session for the original view. + * @property {import("ace-code/src/edit_session").EditSession} [sessionB] - The edit session for the edited view. + * @property {string} [valueA] - The original content. + * @property {string} [valueB] - The modified content. + * @property {"a"|"b"} [inline] - Whether to show the original view("a") or modified view("b") for inline diff view + * @property {IDiffProvider} [diffProvider] - Provider for computing differences between original and modified content. + */ + /** + * @property {boolean} [showOtherLineNumbers=true] - Whether to show line numbers in the other editor's gutter + * @property {boolean} [folding] - Whether to enable code folding widgets + * @property {boolean} [syncSelections] - Whether to synchronize selections between both editors + * @property {boolean} [ignoreTrimWhitespace] - Whether to ignore trimmed whitespace when computing diffs + * @property {boolean} [wrap] - Whether to enable word wrapping in both editors + * @property {number} [maxDiffs=5000] - Maximum number of diffs to compute before failing silently + * @property {string|import("ace-code").Ace.Theme} [theme] - Theme to apply to both editors + */ + /** + * @property {(originalLines: string[], modifiedLines: string[], opts?: any) => import("ace-code/src/diff/base_diff_view").DiffChunk[]} compute - Computes differences between original and modified lines + */ + /** + * Creates a diff view for comparing code. + * @param {DiffModel} [diffModel] model for the diff view + * @param {DiffViewOptions} [options] options for the diff view + * @returns {InlineDiffView|SplitDiffView} Configured diff view instance + */ + export function createDiffView(diffModel?: DiffModel, options?: DiffViewOptions): InlineDiffView | SplitDiffView; + export { InlineDiffView, SplitDiffView, DiffProvider }; +} +declare module "ace-code/src/ext/diff/base_diff_view" { + export class BaseDiffView { + /** + * Constructs a new base DiffView instance. + * @param {boolean} [inlineDiffEditor] - Whether to use an inline diff editor. + * @param {HTMLElement} [container] - optional container element for the DiffView. + */ + constructor(inlineDiffEditor?: boolean, container?: HTMLElement); + onChangeTheme(e: any): void; + onInput(): void; + onChangeFold(ev: any, session: EditSession): void; + realign(): void; + onSelect(e: any, selection: any): void; + onChangeWrapLimit(e: any, session: any): void; + realignPending: boolean; + diffSession: { + sessionA: EditSession; + sessionB: EditSession; + chunks: DiffChunk[]; + }; + /**@type DiffChunk[]*/ chunks: DiffChunk[]; + inlineDiffEditor: boolean; + currentDiffIndex: number; + diffProvider: { + compute: (val1: any, val2: any, options: any) => any[]; + }; + container: HTMLElement; + markerB: DiffHighlight; + markerA: DiffHighlight; + showSideA: boolean; + savedOptionsA: Partial; + savedOptionsB: Partial; + editorA: any; + editorB: any; + activeEditor: any; + otherSession: EditSession; + otherEditor: any; + addGutterDecorators(): void; + gutterDecoratorA: MinimalGutterDiffDecorator; + gutterDecoratorB: MinimalGutterDiffDecorator; + foldUnchanged(): boolean; + unfoldUnchanged(): void; + toggleFoldUnchanged(): void; + setDiffSession(session: { + sessionA: any; + sessionB: EditSession; + chunks: DiffChunk[]; + }): void; + sessionA: EditSession; + sessionB: EditSession; + getDiffSession(): { + sessionA: EditSession; + sessionB: EditSession; + chunks: DiffChunk[]; + }; + setTheme(theme: any): void; + getTheme(): any; + resize(force: any): void; + scheduleOnInput(): void; + selectionRangeA: any; + selectionRangeB: any; + setupScrollbars(): void; + updateScrollBarDecorators(): void; + setProvider(provider: import("ace-code/src/ext/diff").DiffProvider): void; + /** + * scroll locking + * @abstract + **/ + align(): void; + syncSelect(selection: any): void; + updateSelectionMarker(marker: any, session: any, range: any): void; + scheduleRealign(): void; + detach(): void; + destroy(): void; + gotoNext(dir: any): void; + firstDiffSelected(): boolean; + lastDiffSelected(): boolean; + transformRange(range: Range, isOriginal: boolean): Range; + transformPosition(pos: import("ace-code").Ace.Point, isOriginal: boolean): import("ace-code").Ace.Point; + printDiffs(): void; + findChunkIndex(chunks: DiffChunk[], row: number, isOriginal: boolean): number; + searchHighlight(selection: any): void; + initSelectionMarkers(): void; + syncSelectionMarkerA: SyncSelectionMarker; + syncSelectionMarkerB: SyncSelectionMarker; + clearSelectionMarkers(): void; + } + import { EditSession } from "ace-code/src/edit_session"; + export class DiffChunk { + /** + * @param {{originalStartLineNumber: number, originalStartColumn: number, + * originalEndLineNumber: number, originalEndColumn: number, modifiedStartLineNumber: number, + * modifiedStartColumn: number, modifiedEndLineNumber: number, modifiedEndColumn: number}[]} [charChanges] + */ + constructor(originalRange: Range, modifiedRange: Range, charChanges?: { + originalStartLineNumber: number; + originalStartColumn: number; + originalEndLineNumber: number; + originalEndColumn: number; + modifiedStartLineNumber: number; + modifiedStartColumn: number; + modifiedEndLineNumber: number; + modifiedEndColumn: number; + }[]); + old: Range; + new: Range; + charChanges: DiffChunk[]; + } + export class DiffHighlight { + constructor(diffView: import("ace-code/src/ext/diff/base_diff_view").BaseDiffView, type: any); + id: number; + diffView: BaseDiffView; + type: any; + update(html: any, markerLayer: any, session: any, config: any): void; + } + import { MinimalGutterDiffDecorator } from "ace-code/src/ext/diff/gutter_decorator"; + import { Editor } from "ace-code/src/editor"; + import { Range } from "ace-code/src/range"; + class SyncSelectionMarker { + id: number; + type: string; + clazz: string; + update(html: any, markerLayer: any, session: any, config: any): void; + setRange(range: Range): void; + range: Range; + } + namespace Ace { + type OptionsProvider = import("ace-code").Ace.OptionsProvider; + } + export interface BaseDiffView extends Ace.OptionsProvider { + } +} declare module "ace-code/src/ext/elastic_tabstops_lite" { export class ElasticTabstopsLite { constructor(editor: Editor); @@ -886,244 +1213,3 @@ declare module "ace-code/src/ext/whitespace" { }[]; export type EditSession = import("ace-code/src/edit_session").EditSession; } -declare module "ace-code/src/ext/diff/scroll_diff_decorator" { - export class ScrollDiffDecorator extends Decorator { - constructor(scrollbarV: import("ace-code").Ace.VScrollbar, renderer: import("ace-code/src/virtual_renderer").VirtualRenderer, forInlineDiff?: boolean); - addZone(startRow: number, endRow: number, type: "delete" | "insert"): void; - setSessions(sessionA: import("ace-code/src/edit_session").EditSession, sessionB: import("ace-code/src/edit_session").EditSession): void; - sessionA: import("ace-code/src/edit_session").EditSession; - sessionB: import("ace-code/src/edit_session").EditSession; - } - import { Decorator } from "ace-code/src/layer/decorators"; -} -declare module "ace-code/src/ext/diff/styles-css" { - export const cssText: "\n/*\n * Line Markers\n */\n.ace_diff {\n position: absolute;\n z-index: 0;\n}\n.ace_diff.inline {\n z-index: 20;\n}\n/*\n * Light Colors \n */\n.ace_diff.insert {\n background-color: #EFFFF1;\n}\n.ace_diff.delete {\n background-color: #FFF1F1;\n}\n.ace_diff.aligned_diff {\n background: rgba(206, 194, 191, 0.26);\n background: repeating-linear-gradient(\n 45deg,\n rgba(122, 111, 108, 0.26),\n rgba(122, 111, 108, 0.26) 5px,\n rgba(0, 0, 0, 0) 5px,\n rgba(0, 0, 0, 0) 10px \n );\n}\n\n.ace_diff.insert.inline {\n background-color: rgb(74 251 74 / 18%); \n}\n.ace_diff.delete.inline {\n background-color: rgb(251 74 74 / 15%);\n}\n\n.ace_diff.delete.inline.empty {\n background-color: rgba(255, 128, 79, 0.7);\n width: 2px !important;\n}\n\n.ace_diff.insert.inline.empty {\n background-color: rgba(49, 230, 96, 0.7);\n width: 2px !important;\n}\n\n.ace_diff-active-line {\n border-bottom: 1px solid;\n border-top: 1px solid;\n background: transparent;\n position: absolute;\n box-sizing: border-box;\n border-color: #9191ac;\n}\n\n.ace_dark .ace_diff-active-line {\n background: transparent;\n border-color: #75777a;\n}\n \n\n/* gutter changes */\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell,\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell_svg-icons {\n padding-right: 13px;\n}\n\n.ace_mini-diff_gutter_other > .ace_gutter-cell,\n.ace_mini-diff_gutter_other > .ace_gutter-cell_svg-icons {\n display: none;\n}\n\n.ace_mini-diff_gutter_other {\n pointer-events: none;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #EFFFF1;\n border-left: 3px solid #2BB534;\n padding-left: 16px;\n display: block;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #FFF1F1;\n border-left: 3px solid #EA7158;\n padding-left: 16px;\n display: block;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added:after {\n position: absolute;\n right: 2px;\n content: \"+\";\n color: darkgray;\n background-color: inherit;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted:after {\n position: absolute;\n right: 2px;\n content: \"-\";\n color: darkgray;\n background-color: inherit;\n}\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-added:after,\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-deleted:after {\n display: none;\n}\n\n.ace_diff_other .ace_selection {\n filter: drop-shadow(1px 2px 3px darkgray);\n}\n\n.ace_hidden_marker-layer .ace_bracket {\n display: none;\n}\n\n\n\n/*\n * Dark Colors \n */\n\n.ace_dark .ace_diff.insert {\n background-color: #212E25;\n}\n.ace_dark .ace_diff.delete {\n background-color: #3F2222;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #212E25;\n border-left-color:#00802F;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #3F2222;\n border-left-color: #9C3838;\n}\n\n"; -} -declare module "ace-code/src/ext/diff/gutter_decorator" { - export class MinimalGutterDiffDecorator { - constructor(editor: import("ace-code/src/editor").Editor, type: number); - gutterClass: string; - gutterCellsClasses: { - add: string; - delete: string; - }; - editor: import("ace-code/src/editor").Editor; - type: number; - chunks: any[]; - attachToEditor(): void; - renderGutters(e: any, gutterLayer: any): void; - setDecorations(changes: any): void; - dispose(): void; - } -} -declare module "ace-code/src/ext/diff/providers/default" { - export function computeDiff(originalLines: any, modifiedLines: any, options: any): any; - /** - * VSCode’s computeDiff provider - */ - export class DiffProvider { - compute(originalLines: any, modifiedLines: any, opts: any): any; - } -} -declare module "ace-code/src/ext/diff/base_diff_view" { - export class BaseDiffView { - /** - * Constructs a new base DiffView instance. - * @param {boolean} [inlineDiffEditor] - Whether to use an inline diff editor. - * @param {HTMLElement} [container] - optional container element for the DiffView. - */ - constructor(inlineDiffEditor?: boolean, container?: HTMLElement); - onChangeTheme(e: any): void; - onInput(): void; - onChangeFold(ev: any, session: EditSession): void; - realign(): void; - onSelect(e: any, selection: any): void; - onChangeWrapLimit(e: any, session: any): void; - realignPending: boolean; - diffSession: { - sessionA: EditSession; - sessionB: EditSession; - chunks: DiffChunk[]; - }; - /**@type DiffChunk[]*/ chunks: DiffChunk[]; - inlineDiffEditor: boolean; - currentDiffIndex: number; - diffProvider: { - compute: (val1: any, val2: any, options: any) => any[]; - }; - container: HTMLElement; - markerB: DiffHighlight; - markerA: DiffHighlight; - showSideA: boolean; - savedOptionsA: Partial; - savedOptionsB: Partial; - editorA: any; - editorB: any; - activeEditor: any; - otherSession: EditSession; - otherEditor: any; - addGutterDecorators(): void; - gutterDecoratorA: MinimalGutterDiffDecorator; - gutterDecoratorB: MinimalGutterDiffDecorator; - foldUnchanged(): boolean; - unfoldUnchanged(): void; - toggleFoldUnchanged(): void; - setDiffSession(session: { - sessionA: any; - sessionB: EditSession; - chunks: DiffChunk[]; - }): void; - sessionA: EditSession; - sessionB: EditSession; - getDiffSession(): { - sessionA: EditSession; - sessionB: EditSession; - chunks: DiffChunk[]; - }; - setTheme(theme: any): void; - getTheme(): any; - resize(force: any): void; - scheduleOnInput(): void; - selectionRangeA: any; - selectionRangeB: any; - setupScrollbars(): void; - updateScrollBarDecorators(): void; - setProvider(provider: import("ace-code/src/ext/diff/providers/default").DiffProvider): void; - /** - * scroll locking - * @abstract - **/ - align(): void; - syncSelect(selection: any): void; - updateSelectionMarker(marker: any, session: any, range: any): void; - scheduleRealign(): void; - detach(): void; - destroy(): void; - gotoNext(dir: any): void; - firstDiffSelected(): boolean; - lastDiffSelected(): boolean; - transformRange(range: Range, isOriginal: boolean): Range; - transformPosition(pos: import("ace-code").Ace.Point, isOriginal: boolean): import("ace-code").Ace.Point; - printDiffs(): void; - findChunkIndex(chunks: DiffChunk[], row: number, isOriginal: boolean): number; - searchHighlight(selection: any): void; - initSelectionMarkers(): void; - syncSelectionMarkerA: SyncSelectionMarker; - syncSelectionMarkerB: SyncSelectionMarker; - clearSelectionMarkers(): void; - } - export class DiffChunk { - /** - * @param {{originalStartLineNumber: number, originalStartColumn: number, - * originalEndLineNumber: number, originalEndColumn: number, modifiedStartLineNumber: number, - * modifiedStartColumn: number, modifiedEndLineNumber: number, modifiedEndColumn: number}[]} [charChanges] - */ - constructor(originalRange: Range, modifiedRange: Range, charChanges?: { - originalStartLineNumber: number; - originalStartColumn: number; - originalEndLineNumber: number; - originalEndColumn: number; - modifiedStartLineNumber: number; - modifiedStartColumn: number; - modifiedEndLineNumber: number; - modifiedEndColumn: number; - }[]); - old: Range; - new: Range; - charChanges: DiffChunk[]; - } - export class DiffHighlight { - constructor(diffView: import("ace-code/src/ext/diff/base_diff_view").BaseDiffView, type: any); - id: number; - diffView: BaseDiffView; - type: any; - update(html: any, markerLayer: any, session: any, config: any): void; - } - import { EditSession } from "ace-code/src/edit_session"; - import { Editor } from "ace-code/src/editor"; - import { MinimalGutterDiffDecorator } from "ace-code/src/ext/diff/gutter_decorator"; - import { Range } from "ace-code/src/range"; - class SyncSelectionMarker { - id: number; - type: string; - clazz: string; - update(html: any, markerLayer: any, session: any, config: any): void; - setRange(range: Range): void; - range: Range; - } -} -declare module "ace-code/src/ext/diff/diff_view" { - export class DiffView extends BaseDiffView { - /** - * Constructs a new side by side DiffView instance. - * - * @param {Object} [diffModel] - The model for the diff view. - * @param {import("ace-code/src/editor").Editor} [diffModel.editorA] - The editor for the original view. - * @param {import("ace-code/src/editor").Editor} [diffModel.editorB] - The editor for the edited view. - * @param {import("ace-code/src/edit_session").EditSession} [diffModel.sessionA] - The edit session for the original view. - * @param {import("ace-code/src/edit_session").EditSession} [diffModel.sessionB] - The edit session for the edited view. - * @param {string} [diffModel.valueA] - The original content. - * @param {string} [diffModel.valueB] - The modified content. - */ - constructor(diffModel?: { - editorA?: import("ace-code/src/editor").Editor; - editorB?: import("ace-code/src/editor").Editor; - sessionA?: import("ace-code/src/edit_session").EditSession; - sessionB?: import("ace-code/src/edit_session").EditSession; - valueA?: string; - valueB?: string; - }); - init(diffModel: any): void; - onMouseWheel(ev: any): any; - onScroll(e: any, session: any): void; - onChangeWrapLimit(): void; - syncScroll(renderer: import("ace-code/src/virtual_renderer").VirtualRenderer): void; - scrollA: any; - scrollB: any; - scrollSetBy: any; - scrollSetAt: number; - } - import { BaseDiffView } from "ace-code/src/ext/diff/base_diff_view"; -} -declare module "ace-code/src/ext/diff/inline_diff_view" { - export class InlineDiffView extends BaseDiffView { - /** - * Constructs a new inline DiffView instance. - * @param {Object} [diffModel] - The model for the diff view. - * @param {import("ace-code").Editor} [diffModel.editorA] - The editor for the original view. - * @param {import("ace-code").Editor} [diffModel.editorB] - The editor for the edited view. - * @param {import("ace-code").EditSession} [diffModel.sessionA] - The edit session for the original view. - * @param {import("ace-code").EditSession} [diffModel.sessionB] - The edit session for the edited view. - * @param {string} [diffModel.valueA] - The original content. - * @param {string} [diffModel.valueB] - The modified content. - * @param {boolean} [diffModel.showSideA] - Whether to show the original view or modified view. - * @param {HTMLElement} [container] - optional container element for the DiffView. - */ - constructor(diffModel?: { - editorA?: import("ace-code").Editor; - editorB?: import("ace-code").Editor; - sessionA?: import("ace-code").EditSession; - sessionB?: import("ace-code").EditSession; - valueA?: string; - valueB?: string; - showSideA?: boolean; - }, container?: HTMLElement); - init(diffModel: any): void; - onAfterRender(changes: number, renderer: import("ace-code").VirtualRenderer): void; - textLayer: any; - markerLayer: any; - gutterLayer: any; - cursorLayer: any; - initRenderer(restore: any): void; - initTextLayer(): void; - initTextInput(restore: any): void; - othertextInput: any; - otherEditorContainer: any; - selectEditor(editor: any): void; - removeBracketHighlight(editor: any): void; - initMouse(): void; - onMouseDetach: () => void; - onChangeWrapLimit(): void; - } - import { BaseDiffView } from "ace-code/src/ext/diff/base_diff_view"; -} diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index a20909cfef3..28c6d6762c7 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -3537,6 +3537,24 @@ declare module "ace-code/src/occur" { import { Search } from "ace-code/src/search"; import { EditSession } from "ace-code/src/edit_session"; } +declare module "ace-code/src/mouse/multi_select_handler" { + export function onMouseDown(e: any): any; +} +declare module "ace-code/src/commands/multi_select_commands" { + export const defaultCommands: import("ace-code").Ace.Command[]; + export const multiSelectCommands: import("ace-code").Ace.Command[]; + export const keyboardHandler: HashHandler; + import { HashHandler } from "ace-code/src/keyboard/hash_handler"; +} +declare module "ace-code/src/multi_select" { + export const commands: import("ace-code").Ace.Command[]; + export const onSessionChange: (e: any) => void; + export type Anchor = import("ace-code/src/anchor").Anchor; + export type Point = import("ace-code").Ace.Point; + export type ScreenCoordinates = import("ace-code").Ace.ScreenCoordinates; + export function MultiSelect(editor: Editor): void; + import { Editor } from "ace-code/src/editor"; +} declare module "ace-code/src/edit_session/fold" { export class Fold extends RangeList { constructor(range: Range, placeholder: any); @@ -4789,24 +4807,6 @@ declare module "ace-code/src/placeholder" { export interface PlaceHolder extends Ace.EventEmitter { } } -declare module "ace-code/src/mouse/multi_select_handler" { - export function onMouseDown(e: any): any; -} -declare module "ace-code/src/commands/multi_select_commands" { - export const defaultCommands: import("ace-code").Ace.Command[]; - export const multiSelectCommands: import("ace-code").Ace.Command[]; - export const keyboardHandler: HashHandler; - import { HashHandler } from "ace-code/src/keyboard/hash_handler"; -} -declare module "ace-code/src/multi_select" { - export const commands: import("ace-code").Ace.Command[]; - export const onSessionChange: (e: any) => void; - export type Anchor = import("ace-code/src/anchor").Anchor; - export type Point = import("ace-code").Ace.Point; - export type ScreenCoordinates = import("ace-code").Ace.ScreenCoordinates; - export function MultiSelect(editor: Editor): void; - import { Editor } from "ace-code/src/editor"; -} declare module "ace-code/src/commands/occur_commands" { export namespace occurStartCommand { let name: string; From 0207e6ddc9f00387a0e4ae6c16fd1e59b4124205 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Fri, 20 Jun 2025 16:36:39 +0200 Subject: [PATCH 1270/1293] release v1.43.0 --- CHANGELOG.md | 7 +++++++ ace.d.ts | 2 +- build | 2 +- package.json | 2 +- src/config.js | 2 +- types/ace-modules.d.ts | 2 +- 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f66541cce4..a1936456597 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.42.1](https://github.com/ajaxorg/ace/compare/v1.42.0...v1.42.1) (2025-06-20) + + +### Features + +* Add scroll diff decorators ([#5807](https://github.com/ajaxorg/ace/issues/5807)) ([b45e94c](https://github.com/ajaxorg/ace/commit/b45e94cb92d757b5f09ee0966a764ed0d245ed70)) + ## [1.42.0](https://github.com/ajaxorg/ace/compare/v1.41.0...v1.42.0) (2025-06-03) diff --git a/ace.d.ts b/ace.d.ts index 3115a5d132f..41cfd990513 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1062,6 +1062,6 @@ declare module "ace-code" { import { Range } from "ace-code/src/range"; import { UndoManager } from "ace-code/src/undomanager"; import { VirtualRenderer as Renderer } from "ace-code/src/virtual_renderer"; - export var version: "1.42.0"; + export var version: "1.43.0"; export { Range, Editor, EditSession, UndoManager, Renderer as VirtualRenderer }; } diff --git a/build b/build index 4e0cab7c327..bf883aff064 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 4e0cab7c3277baa41466f197490df540f758d1f8 +Subproject commit bf883aff0642dc313c62b0aea2aca1f58a7ea2f9 diff --git a/package.json b/package.json index 0d8cc32bfde..6743d189fa7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.42.0", + "version": "1.43.0", "homepage": "https://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index f65056fa41e..e9ea8a44b3c 100644 --- a/src/config.js +++ b/src/config.js @@ -197,6 +197,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.42.0"; +exports.version = "1.43.0"; diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index 28c6d6762c7..c7834a76a4c 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -375,7 +375,7 @@ declare module "ace-code/src/config" { string ], onLoad: (module: any) => void) => void; setModuleLoader: (moduleName: any, onLoad: any) => void; - version: "1.42.0"; + version: "1.43.0"; }; export = _exports; } From bf27c151685ac486a991a61d67fa04adf8891c76 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Tue, 1 Jul 2025 11:59:58 +0400 Subject: [PATCH 1271/1293] fix(a11y): aria-describedby to gutter elements (#5838) --- src/mouse/default_gutter_handler.js | 31 ++++++++++++++++++++ src/mouse/default_gutter_handler_test.js | 36 ++++++++++++++++++++++++ types/ace-modules.d.ts | 4 +++ 3 files changed, 71 insertions(+) diff --git a/src/mouse/default_gutter_handler.js b/src/mouse/default_gutter_handler.js index 3b68d5f5b0f..0c1735d6d97 100644 --- a/src/mouse/default_gutter_handler.js +++ b/src/mouse/default_gutter_handler.js @@ -142,11 +142,13 @@ exports.GutterHandler = GutterHandler; class GutterTooltip extends Tooltip { constructor(editor, isHover = false) { super(editor.container); + this.id = "gt" + (++GutterTooltip.$uid); this.editor = editor; /**@type {Number | Undefined}*/ this.visibleTooltipRow; var el = this.getElement(); el.setAttribute("role", "tooltip"); + el.setAttribute("id", this.id); el.style.pointerEvents = "auto"; if (isHover) { this.onMouseOut = this.onMouseOut.bind(this); @@ -295,17 +297,44 @@ class GutterTooltip extends Tooltip { this.setClassName("ace_gutter-tooltip"); } + const annotationNode = this.$findLinkedAnnotationNode(row); + if (annotationNode) { + annotationNode.setAttribute("aria-describedby", this.id); + } + this.show(); this.visibleTooltipRow = row; this.editor._signal("showGutterTooltip", this); } + $findLinkedAnnotationNode(row) { + const cell = this.$findCellByRow(row); + if (cell) { + const element = cell.element; + if (element.childNodes.length > 2) { + return element.childNodes[2]; + } + } + } + + $findCellByRow(row) { + return this.editor.renderer.$gutterLayer.$lines.cells.find((el) => el.row === row); + } + hideTooltip() { if(!this.isOpen){ return; } this.$element.removeAttribute("aria-live"); this.hide(); + + if (this.visibleTooltipRow != undefined) { + const annotationNode = this.$findLinkedAnnotationNode(this.visibleTooltipRow); + if (annotationNode) { + annotationNode.removeAttribute("aria-describedby"); + } + } + this.visibleTooltipRow = undefined; this.editor._signal("hideGutterTooltip", this); } @@ -322,4 +351,6 @@ class GutterTooltip extends Tooltip { } } +GutterTooltip.$uid = 0; + exports.GutterTooltip = GutterTooltip; diff --git a/src/mouse/default_gutter_handler_test.js b/src/mouse/default_gutter_handler_test.js index 7214f2dea8e..e3a0b3af6b4 100644 --- a/src/mouse/default_gutter_handler_test.js +++ b/src/mouse/default_gutter_handler_test.js @@ -467,6 +467,42 @@ module.exports = { done(); }, 100); }, + "test: gutter tooltip aria-describedby attribute": function(done) { + var editor = this.editor; + var value = ""; + + editor.session.setMode(new Mode()); + editor.setValue(value, -1); + editor.session.setAnnotations([{row: 0, column: 0, text: "error test", type: "error"}]); + editor.renderer.$loop._flush(); + + var lines = editor.renderer.$gutterLayer.$lines; + var element = lines.cells[0].element; + var annotation = element.childNodes[2]; + assert.ok(/ace_error/.test(element.className)); + + var rect = element.getBoundingClientRect(); + element.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + + // Wait for the tooltip to appear after its timeout. + setTimeout(function() { + editor.renderer.$loop._flush(); + var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + assert.ok(/error test/.test(tooltip.textContent)); + + var ariaDescribedBy = annotation.getAttribute("aria-describedby"); + assert.ok(ariaDescribedBy, "aria-describedby should be set when tooltip is shown"); + assert.equal(ariaDescribedBy, tooltip.id, "aria-describedby should match tooltip id"); + + editor.container.dispatchEvent(new MouseEvent("wheel", {})); + + setTimeout(function() { + editor.renderer.$loop._flush(); + assert.equal(annotation.getAttribute("aria-describedby"), "", "aria-describedby should be removed when tooltip is hidden"); + done(); + }, 100); + }, 100); + }, tearDown : function() { this.editor.destroy(); diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index c7834a76a4c..0a6f48ee0ce 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -1788,6 +1788,7 @@ declare module "ace-code/src/mouse/default_gutter_handler" { }; static annotationsToSummaryString(annotations: any): string; constructor(editor: any, isHover?: boolean); + id: string; editor: any; visibleTooltipRow: number | undefined; onMouseOut(e: any): void; @@ -1795,6 +1796,9 @@ declare module "ace-code/src/mouse/default_gutter_handler" { showTooltip(row: any): void; hideTooltip(): void; } + export namespace GutterTooltip { + let $uid: number; + } import { Tooltip } from "ace-code/src/tooltip"; export interface GutterHandler { } From a165c1664562b5e2e4717d223d9d5d232026ff56 Mon Sep 17 00:00:00 2001 From: Marin Sokol Date: Wed, 2 Jul 2025 11:50:35 +0200 Subject: [PATCH 1272/1293] release v1.43.1 --- CHANGELOG.md | 7 +++++++ ace.d.ts | 2 +- build | 2 +- package.json | 2 +- src/config.js | 2 +- types/ace-modules.d.ts | 2 +- 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1936456597..9f1d77a268a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.43.1](https://github.com/ajaxorg/ace/compare/v1.43.0...v1.43.1) (2025-07-02) + + +### Bug Fixes + +* **a11y:** aria-describedby to gutter elements ([#5838](https://github.com/ajaxorg/ace/issues/5838)) ([bf27c15](https://github.com/ajaxorg/ace/commit/bf27c151685ac486a991a61d67fa04adf8891c76)) + ### [1.42.1](https://github.com/ajaxorg/ace/compare/v1.42.0...v1.42.1) (2025-06-20) diff --git a/ace.d.ts b/ace.d.ts index 41cfd990513..f3e156cfbd2 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1062,6 +1062,6 @@ declare module "ace-code" { import { Range } from "ace-code/src/range"; import { UndoManager } from "ace-code/src/undomanager"; import { VirtualRenderer as Renderer } from "ace-code/src/virtual_renderer"; - export var version: "1.43.0"; + export var version: "1.43.1"; export { Range, Editor, EditSession, UndoManager, Renderer as VirtualRenderer }; } diff --git a/build b/build index bf883aff064..742b25c1cb9 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit bf883aff0642dc313c62b0aea2aca1f58a7ea2f9 +Subproject commit 742b25c1cb94b10a158e1efffad742188dda2c22 diff --git a/package.json b/package.json index 6743d189fa7..9f9182177c8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.43.0", + "version": "1.43.1", "homepage": "https://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index e9ea8a44b3c..86c7e35f628 100644 --- a/src/config.js +++ b/src/config.js @@ -197,6 +197,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.43.0"; +exports.version = "1.43.1"; diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index 0a6f48ee0ce..a4343a3c781 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -375,7 +375,7 @@ declare module "ace-code/src/config" { string ], onLoad: (module: any) => void) => void; setModuleLoader: (moduleName: any, onLoad: any) => void; - version: "1.43.0"; + version: "1.43.1"; }; export = _exports; } From 020e0c44ccda5c177ef0aed718d081b618fbfe70 Mon Sep 17 00:00:00 2001 From: AiSofto Date: Fri, 4 Jul 2025 17:30:28 +0530 Subject: [PATCH 1273/1293] Add project Aisofto (#5818) --- index.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/index.html b/index.html index 071fe5f27ea..3b12a0faa0a 100644 --- a/index.html +++ b/index.html @@ -1214,6 +1214,11 @@

    Projects Using Ace

    Contao
  • +
  • + + AiSofto +
  • +
  • +

    Your Site Here From 0e0571a3f39915796b835e4d22c4124c183e6538 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Thu, 10 Jul 2025 14:33:03 +0400 Subject: [PATCH 1274/1293] add editor.destroyed property (#5785) * add editor.destroyed property * fix demo * fix test --- demo/kitchen-sink/demo.js | 3 ++- demo/test_package/index.ts | 6 +++++- src/autocomplete/inline_test.js | 2 +- src/editor.js | 11 ++++++++--- src/ext/diff/diff_test.js | 4 ++-- src/ext/searchbox.js | 1 + static.js | 3 ++- types/ace-modules.d.ts | 8 ++++++-- 8 files changed, 27 insertions(+), 11 deletions(-) diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 6081a2512ab..8f0b011c5d2 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -33,7 +33,7 @@ var Range = require("ace/range").Range; var whitespace = require("ace/ext/whitespace"); -var createDiffView = require("../../src/ext/diff").createDiffView; +var createDiffView = require("ace/ext/diff").createDiffView; var doclist = require("./doclist"); @@ -504,6 +504,7 @@ function updateUIEditorOptions() { env.editor.on("changeSession", function() { for (var i in env.editor.session.$options) { + if (i == "mode") continue; var value = util.getOption(i); if (value != undefined) { env.editor.setOption(i, value); diff --git a/demo/test_package/index.ts b/demo/test_package/index.ts index 055c48d5966..3d05770ecb8 100644 --- a/demo/test_package/index.ts +++ b/demo/test_package/index.ts @@ -170,4 +170,8 @@ var diffView = createDiffView({ diffView.setProvider(new DiffProvider()); -diffView.destroy(); \ No newline at end of file +diffView.destroy(); +editor.setSession(null); +console.log(editor.destroyed); +editor.destroy(); +console.log(editor.destroyed); diff --git a/src/autocomplete/inline_test.js b/src/autocomplete/inline_test.js index c1cc1b07020..0618423b2d2 100644 --- a/src/autocomplete/inline_test.js +++ b/src/autocomplete/inline_test.js @@ -59,7 +59,7 @@ var completions = [ var getAllLines = function(editorOverride) { editorOverride = editorOverride || editor; - return editorOverride.renderer.$textLayer.element.childNodes.map(function (node) { + return Array.from(editorOverride.renderer.$textLayer.element.childNodes).map(function (node) { return node.textContent; }).join("\n"); }; diff --git a/src/editor.js b/src/editor.js index 9f162c18c9a..f97042468d4 100644 --- a/src/editor.js +++ b/src/editor.js @@ -242,7 +242,7 @@ class Editor { /** * Sets a new editsession to use. This method also emits the `'changeSession'` event. - * @param {EditSession} [session] The new session to use + * @param {EditSession|null} [session] The new session to use **/ setSession(session) { if (this.session == session) @@ -2690,11 +2690,12 @@ class Editor { * Cleans up the entire editor. **/ destroy() { + this.destroyed = true; if (this.$toDestroy) { this.$toDestroy.forEach(function(el) { el.destroy(); }); - this.$toDestroy = null; + this.$toDestroy = []; } if (this.$mouseHandler) this.$mouseHandler.destroy(); @@ -2841,12 +2842,16 @@ config.defineOptions(Editor.prototype, "editor", { readOnly: { set: function(/**@type{boolean}*/readOnly) { this.textInput.setReadOnly(readOnly); + if (this.destroyed) return; this.$resetCursorStyle(); if (!this.$readOnlyCallback) { this.$readOnlyCallback = (e) => { var shouldShow = false; if (e && e.type == "keydown") { - shouldShow = e && e.key && e.key.length == 1 && !e.ctrlKey && !e.metaKey; + if (e && e.key && !e.ctrlKey && !e.metaKey) { + if (e.key == " ") e.preventDefault(); + shouldShow = e.key.length == 1; + } if (!shouldShow) return; } else if (e && e.type !== "exec") { shouldShow = true; diff --git a/src/ext/diff/diff_test.js b/src/ext/diff/diff_test.js index 026d12e223c..c0b86416053 100644 --- a/src/ext/diff/diff_test.js +++ b/src/ext/diff/diff_test.js @@ -431,9 +431,9 @@ module.exports = { }, "test: second editor destroyed on detach in inline diff view": function() { diffView = new InlineDiffView({ editorA, inline: "a" }); - assert.ok(Array.isArray(diffView.otherEditor.$toDestroy)); + assert.ok(!diffView.otherEditor.destroyed); diffView.detach(); - assert.ok(diffView.otherEditor.$toDestroy == undefined); + assert.ok(diffView.otherEditor.destroyed); } }; diff --git a/src/ext/searchbox.js b/src/ext/searchbox.js index 3345d6f5829..0b5cf0b6468 100644 --- a/src/ext/searchbox.js +++ b/src/ext/searchbox.js @@ -224,6 +224,7 @@ class SearchBox { * @param {any} [preventScroll] */ find(skipCurrent, backwards, preventScroll) { + if (!this.editor.session) return; var range = this.editor.find(this.searchInput.value, { skipCurrent: skipCurrent, backwards: backwards, diff --git a/static.js b/static.js index 19e491cfa22..617140c3028 100755 --- a/static.js +++ b/static.js @@ -117,7 +117,8 @@ function serveDirectory(filename, uri, req, res) { html = "" + html + "
    "; var baseUri = uri.replace(/\/?$/, "/"); - html = "" + html; + html = "" + + "" + html; res._hasBody && res.write(html); res.end(); } diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index a4343a3c781..3afe6ca6575 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -2151,9 +2151,9 @@ declare module "ace-code/src/editor" { getKeyboardHandler(): any; /** * Sets a new editsession to use. This method also emits the `'changeSession'` event. - * @param {EditSession} [session] The new session to use + * @param {EditSession|null} [session] The new session to use **/ - setSession(session?: EditSession): void; + setSession(session?: EditSession | null): void; selection: import("ace-code/src/selection").Selection; /** * Returns the current session being used. @@ -2756,6 +2756,10 @@ declare module "ace-code/src/editor" { * Cleans up the entire editor. **/ destroy(): void; + /** + * true if editor is destroyed + */ + destroyed: boolean; /** * Enables automatic scrolling of the cursor into view when editor itself is inside scrollable element * @param {Boolean} enable default true From eaa9deccd08afb2aa2526b0426e54826d34c332d Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Fri, 11 Jul 2025 16:33:00 +0400 Subject: [PATCH 1275/1293] include diff view css in build (#5842) --- src/ext/diff/base_diff_view.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ext/diff/base_diff_view.js b/src/ext/diff/base_diff_view.js index 9bad56162da..7355ae00e76 100644 --- a/src/ext/diff/base_diff_view.js +++ b/src/ext/diff/base_diff_view.js @@ -29,6 +29,8 @@ var dummyDiffProvider = { } }; +dom.importCssString(css, "diffview.css"); + class BaseDiffView { /** * Constructs a new base DiffView instance. @@ -54,7 +56,6 @@ class BaseDiffView { this.container = container; } - dom.importCssString(css, "diffview.css"); this.$ignoreTrimWhitespace = false; this.$maxDiffs = 5000; this.$maxComputationTimeMs = 150; From 07ee8fb45ac0a22362cb8efedbd83c6fc8b7806e Mon Sep 17 00:00:00 2001 From: Agent Smith <67276662+AgentSmith0@users.noreply.github.com> Date: Sun, 13 Jul 2025 16:48:22 +0200 Subject: [PATCH 1276/1293] Update php_highlight_rules.js (#5819) --- src/mode/php_highlight_rules.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mode/php_highlight_rules.js b/src/mode/php_highlight_rules.js index b097790d48e..15a532f250c 100644 --- a/src/mode/php_highlight_rules.js +++ b/src/mode/php_highlight_rules.js @@ -814,7 +814,8 @@ ziparchive_deletename|ziparchive_extractto|ziparchive_getarchivecomment|ziparchi ziparchive_getfromindex|ziparchive_getfromname|ziparchive_getnameindex|ziparchive_getstatusstring|ziparchive_getstream|\ ziparchive_locatename|ziparchive_open|ziparchive_renameindex|ziparchive_renamename|ziparchive_setCommentName|ziparchive_setarchivecomment|\ ziparchive_setcommentindex|ziparchive_statindex|ziparchive_statname|ziparchive_unchangeall|ziparchive_unchangearchive|\ -ziparchive_unchangeindex|ziparchive_unchangename|zlib_get_coding_type'.split('|') +ziparchive_unchangeindex|ziparchive_unchangename|zlib_get_coding_type|array_is_list|fdatasync|fdiv|fsync|get_debug_type|get_resource_id|\ +json_validate|mb_str_pad|mysqli_execute_query|preg_last_error_msg|stream_context_set_options|str_contains|str_ends_with|str_starts_with'.split('|') ); // http://php.net/manual/en/reserved.keywords.php From 085730fff987ec88c2350146f18b42b17532d47f Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:23:54 +0400 Subject: [PATCH 1277/1293] Feat: Implement text markers (#5835) * wip: change color of selected text * use afterRender event; fix wrapped lines serving * separate text markers as extension * add text markers to demo; make implementation more robust; add schedule to remove outdated text markers * add tests for text markers; improve marker rendering logic * resolve merge conflicts * remove markers from demo --- ace-internal.d.ts | 12 +- demo/kitchen-sink/demo.js | 2 +- src/editor.js | 16 +- src/layer/text.js | 8 +- src/layer/text_markers.js | 279 +++++++++++++++++++++++++++++++++ src/layer/text_markers_test.js | 194 +++++++++++++++++++++++ src/test/mockdom.js | 3 + types/ace-modules.d.ts | 56 ++++++- 8 files changed, 555 insertions(+), 15 deletions(-) create mode 100644 src/layer/text_markers.js create mode 100644 src/layer/text_markers_test.js diff --git a/ace-internal.d.ts b/ace-internal.d.ts index ebb8184c245..086a0930d87 100644 --- a/ace-internal.d.ts +++ b/ace-internal.d.ts @@ -1417,9 +1417,16 @@ declare module "./src/editor" { } declare module "./src/edit_session" { + type TextMarker = import("./src/layer/text_markers").TextMarker; + type TextMarkers = typeof import("./src/layer/text_markers").editSessionTextMarkerMixin & { + $textMarkers: TextMarker[]; + $textMarkerId: number; + $scheduleForRemove: Set; + }; + export interface EditSession extends Ace.EventEmitter, Ace.OptionsProvider, - Ace.Folding, Ace.BracketMatch { + Ace.Folding, Ace.BracketMatch, TextMarkers { doc: Ace.Document, $highlightLineMarker?: { start: Ace.Point, @@ -1597,7 +1604,8 @@ declare module "./src/layer/gutter" { } declare module "./src/layer/text" { - export interface Text extends Ace.EventEmitter { + type TextMarkersMixin = typeof import("./src/layer/text_markers").textMarkerMixin; + export interface Text extends Ace.EventEmitter, TextMarkersMixin { config: Ace.LayerConfig } } diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 8f0b011c5d2..8958b6750ba 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -712,4 +712,4 @@ function moveFocus() { env.editor.cmdLine.focus(); else env.editor.focus(); -} +} \ No newline at end of file diff --git a/src/editor.js b/src/editor.js index f97042468d4..2e9060ef37d 100644 --- a/src/editor.js +++ b/src/editor.js @@ -141,7 +141,7 @@ class Editor { switch (scrollIntoView) { case "center-animate": scrollIntoView = "animate"; - /* fall through */ + /* fall through */ case "center": this.renderer.scrollCursorIntoView(null, 0.5); break; @@ -467,7 +467,7 @@ class Editor { */ getFontSize() { return this.getOption("fontSize") || - dom.computedStyle(this.container).fontSize; + dom.computedStyle(this.container).fontSize; } /** @@ -974,13 +974,13 @@ class Editor { if (transform.selection.length == 2) { // Transform relative to the current column this.selection.setSelectionRange( new Range(cursor.row, start + transform.selection[0], - cursor.row, start + transform.selection[1])); + cursor.row, start + transform.selection[1])); } else { // Transform relative to the current row. this.selection.setSelectionRange( new Range(cursor.row + transform.selection[0], - transform.selection[1], - cursor.row + transform.selection[2], - transform.selection[3])); + transform.selection[1], + cursor.row + transform.selection[2], + transform.selection[3])); } } if (this.$enableAutoIndent) { @@ -1883,7 +1883,7 @@ class Editor { * Copies all the selected lines up one row. * **/ - copyLinesUp() { + copyLinesUp() { this.$moveLines(-1, true); } @@ -2081,7 +2081,7 @@ class Editor { * Shifts the document to wherever "page down" is, as well as moving the cursor position. **/ gotoPageDown() { - this.$moveByPage(1, false); + this.$moveByPage(1, false); } /** diff --git a/src/layer/text.js b/src/layer/text.js index 9667fcddcc2..016c49314eb 100644 --- a/src/layer/text.js +++ b/src/layer/text.js @@ -376,7 +376,9 @@ class Text { if (tab) { var tabSize = self.session.getScreenTabSize(screenColumn + m.index); - valueFragment.appendChild(self.$tabStrings[tabSize].cloneNode(true)); + var text = self.$tabStrings[tabSize].cloneNode(true); + text["charCount"] = 1; + valueFragment.appendChild(text); screenColumn += tabSize - 1; } else if (simpleSpace) { if (self.showSpaces) { @@ -609,7 +611,9 @@ class Text { lineEl = this.$createLineElement(); parent.appendChild(lineEl); - lineEl.appendChild(this.dom.createTextNode(lang.stringRepeat("\xa0", splits.indent), this.element)); + var text = this.dom.createTextNode(lang.stringRepeat("\xa0", splits.indent), this.element); + text["charCount"] = 0; // not to take into account when we are counting columns + lineEl.appendChild(text); split ++; screenColumn = 0; diff --git a/src/layer/text_markers.js b/src/layer/text_markers.js new file mode 100644 index 00000000000..2a233a48cd3 --- /dev/null +++ b/src/layer/text_markers.js @@ -0,0 +1,279 @@ +const Text = require("./text").Text; + +/** + * @typedef TextMarker + * @property {import("../../ace-internal").Ace.IRange} range + * @property {number} id + * @property {string} className + */ + +const textMarkerMixin = { + /** + * @param {string} className + * @this {Text} + */ + $removeClass(className) { + if (!this.element) return; + const selectedElements = this.element.querySelectorAll('.' + className); + for (let i = 0; i < selectedElements.length; i++) { + selectedElements[i].classList.remove(className); + } + }, + /** + * @this {Text} + */ + $applyTextMarkers() { + if (this.session.$scheduleForRemove) { + this.session.$scheduleForRemove.forEach(className => { + this.$removeClass(className); + }); + + this.session.$scheduleForRemove = new Set(); + } + + const textMarkers = this.session.getTextMarkers(); + + if (textMarkers.length === 0) { + return; + } + + const classNameGroups = new Set(); + textMarkers.forEach(marker => { + classNameGroups.add(marker.className); + }); + + classNameGroups.forEach(className => { + this.$removeClass(className); + }); + + textMarkers.forEach((marker) => { + for (let row = marker.range.start.row; row <= marker.range.end.row; row++) { + const cell = this.$lines.cells.find((el) => el.row === row); + + if (cell) { + this.$modifyDomForMarkers(cell.element, row, marker); + } + } + }); + }, + /** + * @param {HTMLElement} lineElement + * @param {number} row + * @param {TextMarker} marker + * @this {Text} + */ + $modifyDomForMarkers(lineElement, row, marker) { + const lineLength = this.session.getLine(row).length; + let startCol = row > marker.range.start.row ? 0 : marker.range.start.column; + let endCol = row < marker.range.end.row ? lineLength : marker.range.end.column; + + var lineElements = []; + if (lineElement.classList.contains('ace_line_group')) { + lineElements = Array.from(lineElement.childNodes); + } + else { + lineElements = [lineElement]; + } + + var currentColumn = 0; + lineElements.forEach((lineElement) => { + const childNodes = Array.from(lineElement.childNodes); + for (let i = 0; i < childNodes.length; i++) { + let subChildNodes = [childNodes[i]]; + let parentNode = lineElement; + if (childNodes[i].childNodes && childNodes[i].childNodes.length > 0) { + subChildNodes = Array.from(childNodes[i].childNodes); + parentNode = childNodes[i]; + } + for (let j = 0; j < subChildNodes.length; j++) { + const node = subChildNodes[j]; + const nodeText = node.textContent || ''; + const contentLength = node["charCount"] || node.parentNode["charCount"] || nodeText.length; + const nodeStart = currentColumn; + const nodeEnd = currentColumn + contentLength; + + if (node["charCount"] === 0 || contentLength === 0) { + continue; + } + + if (nodeStart < endCol && nodeEnd > startCol) { + if (node.nodeType === 3) { //text node + const beforeSelection = Math.max(0, startCol - nodeStart); + const afterSelection = Math.max(0, nodeEnd - endCol); + const selectionLength = contentLength - beforeSelection - afterSelection; + + if (beforeSelection > 0 || afterSelection > 0) { + const fragment = this.dom.createFragment(this.element); + + if (beforeSelection > 0) { + fragment.appendChild( + this.dom.createTextNode(nodeText.substring(0, beforeSelection), this.element)); + } + + if (selectionLength > 0) { + const selectedSpan = this.dom.createElement('span'); + selectedSpan.classList.add(marker.className); + selectedSpan.textContent = nodeText.substring( + beforeSelection, + beforeSelection + selectionLength + ); + fragment.appendChild(selectedSpan); + } + + if (afterSelection > 0) { + fragment.appendChild( + this.dom.createTextNode( + nodeText.substring(beforeSelection + selectionLength), + this.element + )); + } + + parentNode.replaceChild(fragment, node); + } + else { + const selectedSpan = this.dom.createElement('span'); + selectedSpan.classList.add(marker.className); + selectedSpan.textContent = nodeText; + selectedSpan["charCount"] = node["charCount"]; + parentNode.replaceChild(selectedSpan, node); + } + } + else if (node.nodeType === 1) { //element node + if (nodeStart >= startCol && nodeEnd <= endCol) { + // @ts-ignore + node.classList.add(marker.className); + } + else { + const beforeSelection = Math.max(0, startCol - nodeStart); + const afterSelection = Math.max(0, nodeEnd - endCol); + const selectionLength = contentLength - beforeSelection - afterSelection; + + if (beforeSelection > 0 || afterSelection > 0) { + // @ts-ignore + const nodeClasses = node.className; + const fragment = this.dom.createFragment(this.element); + + if (beforeSelection > 0) { + const beforeSpan = this.dom.createElement('span'); + beforeSpan.className = nodeClasses; + beforeSpan.textContent = nodeText.substring(0, beforeSelection); + fragment.appendChild(beforeSpan); + } + + if (selectionLength > 0) { + const selectedSpan = this.dom.createElement('span'); + selectedSpan.className = nodeClasses + ' ' + marker.className; + selectedSpan.textContent = nodeText.substring( + beforeSelection, + beforeSelection + selectionLength + ); + fragment.appendChild(selectedSpan); + } + + if (afterSelection > 0) { + const afterSpan = this.dom.createElement('span'); + afterSpan.className = nodeClasses; + afterSpan.textContent = nodeText.substring(beforeSelection + selectionLength); + fragment.appendChild(afterSpan); + } + + parentNode.replaceChild(fragment, node); + } + } + } + } + currentColumn = nodeEnd; + } + } + }); + } +}; +Object.assign(Text.prototype, textMarkerMixin); + +var EditSession = require("../edit_session").EditSession; +const editSessionTextMarkerMixin = { + /** + * Adds a text marker to the current edit session. + * + * @param {import("../../ace-internal").Ace.IRange} range - The range to mark in the document + * @param {string} className - The CSS class name to apply to the marked text + * @returns {number} The unique identifier for the added text marker + * + * @this {EditSession} + */ + addTextMarker(range, className) { + /**@type{number}*/ + this.$textMarkerId = this.$textMarkerId || 0; + this.$textMarkerId++; + var marker = { + range: range, + id: this.$textMarkerId, + className: className + }; + if (!this.$textMarkers) { + this.$textMarkers = []; + } + this.$textMarkers[marker.id] = marker; + return marker.id; + }, + /** + * Removes a text marker from the current edit session. + * + * @param {number} markerId - The unique identifier of the text marker to remove + * + * @this {EditSession} + */ + removeTextMarker(markerId) { + if (!this.$textMarkers) { + return; + } + + const marker = this.$textMarkers[markerId]; + if (!marker) { + return; + } + if (!this.$scheduleForRemove) { + this.$scheduleForRemove = new Set(); + } + this.$scheduleForRemove.add(marker.className); + delete this.$textMarkers[markerId]; + }, + /** + * Retrieves the text markers associated with the current edit session. + * + * @returns {TextMarker[]} An array of text markers, or an empty array if no markers exist + * + * @this {EditSession} + */ + getTextMarkers() { + return this.$textMarkers || []; + } +}; +Object.assign(EditSession.prototype, editSessionTextMarkerMixin); + + +const onAfterRender = (e, renderer) => { + renderer.$textLayer.$applyTextMarkers(); +}; + +const Editor = require("../editor").Editor; +require("../config").defineOptions(Editor.prototype, "editor", { + enableTextMarkers: { + /** + * @param {boolean} val + * @this {Editor} + */ + set: function (val) { + if (val) { + this.renderer.on("afterRender", onAfterRender); + } + else { + this.renderer.off("afterRender", onAfterRender); + } + }, + value: true + } +}); + +exports.textMarkerMixin = textMarkerMixin; +exports.editSessionTextMarkerMixin = editSessionTextMarkerMixin; \ No newline at end of file diff --git a/src/layer/text_markers_test.js b/src/layer/text_markers_test.js new file mode 100644 index 00000000000..3ed0d2c5979 --- /dev/null +++ b/src/layer/text_markers_test.js @@ -0,0 +1,194 @@ +if (typeof process !== "undefined") { + require("amd-loader"); + require("../test/mockdom"); +} + +"use strict"; + +var assert = require("../test/assertions"); +var EditSession = require("../edit_session").EditSession; +var TextLayer = require("./text").Text; +var JavaScriptMode = require("../mode/javascript").Mode; +var dom = require("../lib/dom"); +var Range = require("../range").Range; + +require("./text_markers"); + +function normalize(str) { + return str.replace(/\s/gm, ""); +} + +function getText(nodes) { + var markedContent = ""; + nodes.forEach(node => { + markedContent += node.textContent; + }); + + return markedContent; +} + +module.exports = { + setUp: function (next) { + this.session = new EditSession(""); + this.session.setMode(new JavaScriptMode()); + + this.container = document.createElement("div"); + this.textLayer = new TextLayer(this.container); + this.textLayer.setSession(this.session); + this.textLayer.config = { + characterWidth: 10, + lineHeight: 20, + firstRow: 0, + lastRow: 10, + firstRowScreen: 0, + padding: 0, + offset: 0 + }; + + next(); + }, + + "test: marker splits single token into multiple DOM nodes": function () { + this.session.setValue('var functionName = "test";'); + + this.textLayer.update(this.textLayer.config); + + this.session.addTextMarker(new Range(0, 6, 0, 10), "split-token-marker"); + + this.textLayer.$applyTextMarkers(); + + var markerSpans = this.textLayer.element.querySelectorAll('.split-token-marker'); + assert.equal(markerSpans.length, 1); + assert.equal(getText(markerSpans), "ncti"); + + const result = normalize(`var + functionName = "test";`); + const actual = normalize(this.textLayer.element.childNodes[0].innerHTML); + assert.equal(actual, result); + }, + + "test: marker partially overlaps multiple tokens": function () { + this.session.setValue('var test = 123;'); + + this.textLayer.update(this.textLayer.config); + + this.session.addTextMarker(new Range(0, 6, 0, 12), "overlap-marker"); + + this.textLayer.$applyTextMarkers(); + + var markerSpans = this.textLayer.element.querySelectorAll('.overlap-marker'); + assert.equal(getText(markerSpans), "st = 1"); + + const result = normalize(`var te + st + + = + 123;`); + const actual = normalize(this.textLayer.element.childNodes[0].innerHTML); + assert.equal(actual, result); + }, + + "test: multiple overlapping markers split tokens differently": function () { + this.session.setValue('var longVariableName = 42;'); + + this.textLayer.update(this.textLayer.config); + + this.session.addTextMarker(new Range(0, 4, 0, 12), "marker-1"); + this.session.addTextMarker(new Range(0, 8, 0, 16), "marker-2"); + this.session.addTextMarker(new Range(0, 6, 0, 14), "marker-3"); + + this.textLayer.$applyTextMarkers(); + + const line = this.textLayer.element.childNodes[0]; + + // Verify all markers are applied + assert.ok(line.querySelectorAll('.marker-1').length > 0); + assert.ok(line.querySelectorAll('.marker-2').length > 0); + assert.ok(line.querySelectorAll('.marker-3').length > 0); + + assert.equal(line.textContent, 'var longVariableName = 42;'); + + const result = normalize(`var + long + Variab + leName = + 42;`); + const actual = normalize(this.textLayer.element.childNodes[0].innerHTML); + assert.equal(actual, result); + }, + + "test: marker with tab characters and invisible rendering": function () { + this.session.setValue("func\t\ttest"); + this.textLayer.setShowInvisibles("tab"); + this.textLayer.$computeTabString(); + + this.textLayer.update(this.textLayer.config); + + this.session.addTextMarker(new Range(0, 3, 0, 7), "tab-marker"); + + this.textLayer.$applyTextMarkers(); + + //preserve whitespaces + const result = `func test`; + const actual = this.textLayer.element.childNodes[0].innerHTML; + assert.equal(actual, result); + }, + + "test: marker with CJK characters and proper width calculation": function () { + this.session.setValue("测试function测试"); + + this.textLayer.update(this.textLayer.config); + + this.session.addTextMarker(new Range(0, 1, 0, 11), "cjk-marker"); + + this.textLayer.$applyTextMarkers(); + + const line = this.textLayer.element.childNodes[0]; + var cjkMarkers = line.querySelectorAll('.cjk-marker'); + assert.ok(cjkMarkers.length > 0, "CJK marker should be present"); + + var markedText = ""; + cjkMarkers.forEach(span => { + markedText += span.textContent; + }); + assert.equal(markedText, "试function测"); + + const result = normalize(` + function + + `); + const actual = normalize(this.textLayer.element.childNodes[0].innerHTML); + assert.equal(actual, result); + }, + + "test: marker removal properly cleans up split tokens": function() { + this.session.setValue('var functionName = "test";'); + + this.textLayer.update(this.textLayer.config); + + var markerId = this.session.addTextMarker(new Range(0, 6, 0, 10), "temp-marker"); + + this.textLayer.$applyTextMarkers(); + + const line = this.textLayer.element.childNodes[0]; + + var markerSpans = line.querySelectorAll('.temp-marker'); + assert.ok(markerSpans.length > 0, "Marker should be present"); + + this.session.removeTextMarker(markerId); + + this.textLayer.update(this.textLayer.config); + this.textLayer.$applyTextMarkers(); + + const newLine = this.textLayer.element.childNodes[0]; + + markerSpans = newLine.querySelectorAll('.temp-marker'); + assert.equal(markerSpans.length, 0, "Marker should be removed"); + }, +}; + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} \ No newline at end of file diff --git a/src/test/mockdom.js b/src/test/mockdom.js index 25c2f02a34f..2c586ae2be8 100644 --- a/src/test/mockdom.js +++ b/src/test/mockdom.js @@ -757,6 +757,9 @@ function TextNode(value) { this.__defineGetter__("nodeValue", function() { return this.data; }); + this.__defineGetter__("textContent", function() { + return this.data; + }); }).call(TextNode.prototype); var window = { diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index 3afe6ca6575..a8a6ec0e04c 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -506,6 +506,8 @@ declare module "ace-code/src/layer/text" { } export type LayerConfig = import("ace-code").Ace.LayerConfig; export type EditSession = import("ace-code/src/edit_session").EditSession; + type TextMarkersMixin = { + }; import dom = require("ace-code/src/lib/dom"); import { Lines } from "ace-code/src/layer/lines"; namespace Ace { @@ -515,7 +517,7 @@ declare module "ace-code/src/layer/text" { type TextEvents = import("ace-code").Ace.TextEvents; type LayerConfig = import("ace-code").Ace.LayerConfig; } - export interface Text extends Ace.EventEmitter { + export interface Text extends Ace.EventEmitter, TextMarkersMixin { config: Ace.LayerConfig; } } @@ -3563,6 +3565,45 @@ declare module "ace-code/src/multi_select" { export function MultiSelect(editor: Editor): void; import { Editor } from "ace-code/src/editor"; } +declare module "ace-code/src/layer/text_markers" { + export type TextMarker = { + range: import("ace-code").Ace.IRange; + id: number; + className: string; + }; + export namespace textMarkerMixin { + function $removeClass(this: Text, className: string): void; + function $applyTextMarkers(this: Text): void; + function $modifyDomForMarkers(this: Text, lineElement: HTMLElement, row: number, marker: TextMarker): void; + } + export namespace editSessionTextMarkerMixin { + /** + * Adds a text marker to the current edit session. + * + * @param {import("ace-code").Ace.IRange} range - The range to mark in the document + * @param {string} className - The CSS class name to apply to the marked text + * @returns {number} The unique identifier for the added text marker + * + */ + function addTextMarker(this: EditSession, range: import("ace-code").Ace.IRange, className: string): number; + /** + * Removes a text marker from the current edit session. + * + * @param {number} markerId - The unique identifier of the text marker to remove + * + */ + function removeTextMarker(this: EditSession, markerId: number): void; + /** + * Retrieves the text markers associated with the current edit session. + * + * @returns {TextMarker[]} An array of text markers, or an empty array if no markers exist + * + */ + function getTextMarkers(this: EditSession): TextMarker[]; + } + import { Text } from "ace-code/src/layer/text"; + import { EditSession } from "ace-code/src/edit_session"; +} declare module "ace-code/src/edit_session/fold" { export class Fold extends RangeList { constructor(range: Range, placeholder: any); @@ -4486,6 +4527,17 @@ declare module "ace-code/src/edit_session" { export type SyntaxMode = import("ace-code").Ace.SyntaxMode; export type LineWidget = import("ace-code").Ace.LineWidget; export type TextMode = SyntaxMode; + type TextMarker = { + range: IRange; + id: number; + className: string; + }; + type TextMarkers = { + addTextMarker(this: EditSession, range: IRange, className: string): number; + removeTextMarker(this: EditSession, markerId: number): void; + getTextMarkers(this: EditSession): TextMarker[]; + } & { + }; import { Document } from "ace-code/src/document"; import { BackgroundTokenizer } from "ace-code/src/background_tokenizer"; import { Selection } from "ace-code/src/selection"; @@ -4510,7 +4562,7 @@ declare module "ace-code/src/edit_session" { type Operation = import("ace-code").Ace.Operation; } export interface EditSession extends Ace.EventEmitter, Ace.OptionsProvider, Ace.Folding, Ace. - BracketMatch { + BracketMatch, TextMarkers { doc: Ace.Document; lineWidgetsWidth?: number; gutterRenderer?: any; From 282be0ca27649a10ca1ba9442006e20a48d1ac79 Mon Sep 17 00:00:00 2001 From: Marin Sokol Date: Tue, 15 Jul 2025 10:53:00 +0200 Subject: [PATCH 1278/1293] release v1.43.2 --- CHANGELOG.md | 7 +++++++ ace.d.ts | 2 +- build | 2 +- package.json | 2 +- src/config.js | 2 +- types/ace-modules.d.ts | 2 +- 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f1d77a268a..b4160b9fed0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.43.2](https://github.com/ajaxorg/ace/compare/v1.43.1...v1.43.2) (2025-07-15) + + +### Features + +* Implement text markers ([#5835](https://github.com/ajaxorg/ace/issues/5835)) ([085730f](https://github.com/ajaxorg/ace/commit/085730fff987ec88c2350146f18b42b17532d47f)) + ### [1.43.1](https://github.com/ajaxorg/ace/compare/v1.43.0...v1.43.1) (2025-07-02) diff --git a/ace.d.ts b/ace.d.ts index f3e156cfbd2..d084674c6a2 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1062,6 +1062,6 @@ declare module "ace-code" { import { Range } from "ace-code/src/range"; import { UndoManager } from "ace-code/src/undomanager"; import { VirtualRenderer as Renderer } from "ace-code/src/virtual_renderer"; - export var version: "1.43.1"; + export var version: "1.43.2"; export { Range, Editor, EditSession, UndoManager, Renderer as VirtualRenderer }; } diff --git a/build b/build index 742b25c1cb9..ed87eff0725 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 742b25c1cb94b10a158e1efffad742188dda2c22 +Subproject commit ed87eff0725307ff0b2370dba44bd69b8140e485 diff --git a/package.json b/package.json index 9f9182177c8..2673e7a9ed6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.43.1", + "version": "1.43.2", "homepage": "https://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 86c7e35f628..11ed209f09b 100644 --- a/src/config.js +++ b/src/config.js @@ -197,6 +197,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.43.1"; +exports.version = "1.43.2"; diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index a8a6ec0e04c..f05d25965c2 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -375,7 +375,7 @@ declare module "ace-code/src/config" { string ], onLoad: (module: any) => void) => void; setModuleLoader: (moduleName: any, onLoad: any) => void; - version: "1.43.1"; + version: "1.43.2"; }; export = _exports; } From 1ae394314348120cbc2cee76cb5783b07b2c00ee Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Sun, 27 Jul 2025 23:58:16 +0400 Subject: [PATCH 1279/1293] Improve typings for editor options (#5846) * improve typings for editor options * describe `destroyed` property --- ace.d.ts | 2 +- src/ace.js | 2 +- src/editor.js | 1 + types/ace-modules.d.ts | 4 +--- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ace.d.ts b/ace.d.ts index d084674c6a2..23d0956cdd6 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1055,7 +1055,7 @@ declare module "ace-code" { export function edit(el?: string | (HTMLElement & { env?: any; value?: any; - }) | null, options?: any): Editor; + }) | null, options?: Partial): Editor; export function createEditSession(text: import("ace-code/src/document").Document | string, mode?: import("ace-code").Ace.SyntaxMode): EditSession; import { Editor } from "ace-code/src/editor"; import { EditSession } from "ace-code/src/edit_session"; diff --git a/src/ace.js b/src/ace.js index 2e2180fdd5a..b7ed7e4bbb8 100644 --- a/src/ace.js +++ b/src/ace.js @@ -29,7 +29,7 @@ exports.config = require("./config"); /** * Embeds the Ace editor into the DOM, at the element provided by `el`. * @param {String | HTMLElement & {env?: any, value?: any} | null} [el] Either the id of an element, or the element itself - * @param {Object } [options] Options for the editor + * @param {Partial } [options] Options for the editor * @returns {Editor} **/ exports.edit = function(el, options) { diff --git a/src/editor.js b/src/editor.js index 2e9060ef37d..528f440ec36 100644 --- a/src/editor.js +++ b/src/editor.js @@ -2690,6 +2690,7 @@ class Editor { * Cleans up the entire editor. **/ destroy() { + /** true if editor is destroyed */ this.destroyed = true; if (this.$toDestroy) { this.$toDestroy.forEach(function(el) { diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index f05d25965c2..d789703e026 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -2758,9 +2758,7 @@ declare module "ace-code/src/editor" { * Cleans up the entire editor. **/ destroy(): void; - /** - * true if editor is destroyed - */ + /** true if editor is destroyed */ destroyed: boolean; /** * Enables automatic scrolling of the cursor into view when editor itself is inside scrollable element From 29a55573a772e23e516fed30ca4015a56b1fabd1 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Wed, 30 Jul 2025 15:57:28 +0400 Subject: [PATCH 1280/1293] tweak diff view styles (#5850) --- src/ext/diff/styles-css.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ext/diff/styles-css.js b/src/ext/diff/styles-css.js index a1ba7cad901..017162db634 100644 --- a/src/ext/diff/styles-css.js +++ b/src/ext/diff/styles-css.js @@ -96,7 +96,6 @@ exports.cssText = ` position: absolute; right: 2px; content: "+"; - color: darkgray; background-color: inherit; } @@ -104,7 +103,6 @@ exports.cssText = ` position: absolute; right: 2px; content: "-"; - color: darkgray; background-color: inherit; } .ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-added:after, @@ -116,7 +114,8 @@ exports.cssText = ` filter: drop-shadow(1px 2px 3px darkgray); } -.ace_hidden_marker-layer .ace_bracket { +.ace_hidden_marker-layer .ace_bracket, +.ace_hidden_marker-layer .ace_error_bracket { display: none; } From 6afb0480c3c58b04b5bd9a1585fdda73c904e6f3 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Mon, 4 Aug 2025 13:23:16 +0400 Subject: [PATCH 1281/1293] fix tooltip position when editor is placed in new stacking context (#5853) * fix tooltip position when editor is placed in new stacking context * pin typescript version until we update types --- demo/kitchen-sink/demo.js | 7 ++++++- package.json | 2 +- src/autocomplete/popup.js | 13 ++++++++----- src/css/editor-css.js | 2 +- src/tooltip.js | 6 ++++-- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 8958b6750ba..a492ff4a667 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -597,10 +597,15 @@ function openTestDialog(animateHeight) { window.dialogEditor.destroy(); var editor = ace.edit(null, { value: "test editor", - mode: "ace/mode/javascript" + mode: "ace/mode/javascript", + enableBasicAutocompletion: true }); window.dialogEditor = editor; + editor.completer.parentNode = editor.container; + if (window.languageProvider) + window.languageProvider.registerEditor(editor); + var dialog = dom.buildDom(["div", { style: "transition: all 1s; position: fixed; z-index: 100000;" + "background: darkblue; border: solid 1px black; display: flex; flex-direction: column" diff --git a/package.json b/package.json index 2673e7a9ed6..72be9dce36f 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "eslint": "^8.20.0", "istanbul": "^0.4.5", "standard-version": "^9.3.2", - "typescript": "^5.6.3" + "typescript": "5.8.3" }, "mappings": { "ace": "." diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js index 2ca9683bc41..bb6ec7fe5f0 100644 --- a/src/autocomplete/popup.js +++ b/src/autocomplete/popup.js @@ -370,24 +370,27 @@ class AcePopup { renderer.$maxPixelHeight = null; } + el.style.display = ""; + var rootRect = el.offsetParent && el.offsetParent.getBoundingClientRect(); + if (anchor === "top") { el.style.top = ""; - el.style.bottom = (screenHeight + scrollBarSize - dims.bottom) + "px"; + el.style.bottom = (screenHeight + scrollBarSize - dims.bottom) + - (rootRect ? screenHeight + scrollBarSize - rootRect.bottom : 0)+ "px"; popup.isTopdown = false; } else { - el.style.top = dims.top + "px"; + el.style.top = (dims.top - (rootRect ? rootRect.top : 0)) + "px"; el.style.bottom = ""; popup.isTopdown = true; } - el.style.display = ""; var left = pos.left; if (left + el.offsetWidth > screenWidth) left = screenWidth - el.offsetWidth; - el.style.left = left + "px"; + el.style.left = (left - (rootRect ? rootRect.left : 0)) + "px"; el.style.right = ""; if (!popup.isOpen) { @@ -469,7 +472,7 @@ dom.importCssString(` width: 300px; z-index: 200000; border: 1px lightgray solid; - position: fixed; + position: absolute; box-shadow: 2px 3px 5px rgba(0,0,0,.2); line-height: 1.4; background: #fefefe; diff --git a/src/css/editor-css.js b/src/css/editor-css.js index cf7768f4a7b..48b62ee2743 100644 --- a/src/css/editor-css.js +++ b/src/css/editor-css.js @@ -460,7 +460,7 @@ module.exports = ` box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); color: black; padding: 3px 4px; - position: fixed; + position: absolute; z-index: 999999; box-sizing: border-box; cursor: default; diff --git a/src/tooltip.js b/src/tooltip.js index a83fce5ab00..6454863bd37 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -56,8 +56,10 @@ class Tooltip { * @param {Number} y **/ setPosition(x, y) { - this.getElement().style.left = x + "px"; - this.getElement().style.top = y + "px"; + var el = this.getElement(); + var rootRect = el.offsetParent && el.offsetParent.getBoundingClientRect(); + el.style.left = x - (rootRect ? rootRect.left : 0) + "px"; + el.style.top = y - (rootRect ? rootRect.top : 0) + "px"; } /** From 23ac02f7602b84cc4ea30f6ed4f889d3802affde Mon Sep 17 00:00:00 2001 From: yurenchen000 Date: Mon, 25 Aug 2025 16:11:33 +0800 Subject: [PATCH 1282/1293] fix: firefox textarea autocomplete corruption (#5860) --- src/keyboard/textinput.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keyboard/textinput.js b/src/keyboard/textinput.js index 7de343a520d..ccde43c0953 100644 --- a/src/keyboard/textinput.js +++ b/src/keyboard/textinput.js @@ -33,6 +33,7 @@ class TextInput { this.text.className = "ace_text-input"; this.text.setAttribute("wrap", "off"); + this.text.setAttribute("autocomplete", "off"); this.text.setAttribute("autocorrect", "off"); this.text.setAttribute("autocapitalize", "off"); this.text.setAttribute("spellcheck", "false"); From e9c0810b8375009863ad651a0a946a19f8c9fb55 Mon Sep 17 00:00:00 2001 From: Marin Sokol Date: Tue, 2 Sep 2025 16:14:10 +0200 Subject: [PATCH 1283/1293] release v1.43.3 --- CHANGELOG.md | 7 +++++++ ace.d.ts | 2 +- build | 2 +- package.json | 2 +- src/config.js | 2 +- types/ace-modules.d.ts | 2 +- 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4160b9fed0..43c00df358f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.43.3](https://github.com/ajaxorg/ace/compare/v1.43.2...v1.43.3) (2025-09-02) + + +### Bug Fixes + +* firefox textarea autocomplete corruption ([#5860](https://github.com/ajaxorg/ace/issues/5860)) ([23ac02f](https://github.com/ajaxorg/ace/commit/23ac02f7602b84cc4ea30f6ed4f889d3802affde)) + ### [1.43.2](https://github.com/ajaxorg/ace/compare/v1.43.1...v1.43.2) (2025-07-15) diff --git a/ace.d.ts b/ace.d.ts index 23d0956cdd6..c1940248f4c 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1062,6 +1062,6 @@ declare module "ace-code" { import { Range } from "ace-code/src/range"; import { UndoManager } from "ace-code/src/undomanager"; import { VirtualRenderer as Renderer } from "ace-code/src/virtual_renderer"; - export var version: "1.43.2"; + export var version: "1.43.3"; export { Range, Editor, EditSession, UndoManager, Renderer as VirtualRenderer }; } diff --git a/build b/build index ed87eff0725..933d5765d4c 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit ed87eff0725307ff0b2370dba44bd69b8140e485 +Subproject commit 933d5765d4cd9e80a8aa7073df39b80dd04671f7 diff --git a/package.json b/package.json index 72be9dce36f..881457158ed 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.43.2", + "version": "1.43.3", "homepage": "https://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 11ed209f09b..8c02d2c102f 100644 --- a/src/config.js +++ b/src/config.js @@ -197,6 +197,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.43.2"; +exports.version = "1.43.3"; diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index d789703e026..203254f67a4 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -375,7 +375,7 @@ declare module "ace-code/src/config" { string ], onLoad: (module: any) => void) => void; setModuleLoader: (moduleName: any, onLoad: any) => void; - version: "1.43.2"; + version: "1.43.3"; }; export = _exports; } From a7d4b4b2a8c9ef1dae6a1621712abf38c4f6b7d3 Mon Sep 17 00:00:00 2001 From: "Razvan (Raz)" Date: Wed, 10 Sep 2025 17:45:51 +0700 Subject: [PATCH 1284/1293] updated index.html to add Chartbrew to the list of users (#5870) --- index.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.html b/index.html index 3b12a0faa0a..a7733c1e4a0 100644 --- a/index.html +++ b/index.html @@ -1218,6 +1218,10 @@

    Projects Using Ace

    AiSofto
  • +
  • + + Chartbrew +
  • +

    From b195c5895d29fd4be5b5c96883bde5f1339a0209 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Wed, 10 Sep 2025 14:46:24 +0400 Subject: [PATCH 1285/1293] sync wrap option at start to keep diff alignment (#5868) --- src/ext/diff/base_diff_view.js | 4 ++++ src/ext/diff/diff_test.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/ext/diff/base_diff_view.js b/src/ext/diff/base_diff_view.js index 7355ae00e76..d86e07d159b 100644 --- a/src/ext/diff/base_diff_view.js +++ b/src/ext/diff/base_diff_view.js @@ -121,6 +121,10 @@ class BaseDiffView { diffModel.valueB || "")), chunks: [] }); + + if (this.otherEditor && this.activeEditor) { + this.otherSession.setOption("wrap", this.activeEditor.getOption("wrap")); + } this.setupScrollbars(); } diff --git a/src/ext/diff/diff_test.js b/src/ext/diff/diff_test.js index c0b86416053..760832588be 100644 --- a/src/ext/diff/diff_test.js +++ b/src/ext/diff/diff_test.js @@ -430,7 +430,11 @@ module.exports = { }, 0); }, "test: second editor destroyed on detach in inline diff view": function() { + editorA.setOption("wrap", "free"); diffView = new InlineDiffView({ editorA, inline: "a" }); + + assert.equal(diffView.editorB.getOption("wrap"), "free"); + assert.ok(!diffView.otherEditor.destroyed); diffView.detach(); assert.ok(diffView.otherEditor.destroyed); From 900cffc0c51315b50174347ec8b2c5bbe0af6b8f Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Wed, 10 Sep 2025 14:47:07 +0400 Subject: [PATCH 1286/1293] fix gutter click on wrapped line moving cursor to the next line (#5867) --- src/mouse/default_handlers.js | 8 ++++---- src/mouse/mouse_handler_test.js | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/mouse/default_handlers.js b/src/mouse/default_handlers.js index d04954df8a9..6b7590f9001 100644 --- a/src/mouse/default_handlers.js +++ b/src/mouse/default_handlers.js @@ -112,7 +112,7 @@ class DefaultHandlers { } else if (cmp == 1) { anchor = this.$clickSelection.start; } else { - var orientedRange = calcRangeOrientation(this.$clickSelection, cursor); + var orientedRange = calcRangeOrientation(this.$clickSelection, cursor, editor.session); cursor = orientedRange.cursor; anchor = orientedRange.anchor; } @@ -146,7 +146,7 @@ class DefaultHandlers { cursor = range.end; anchor = range.start; } else { - var orientedRange = calcRangeOrientation(this.$clickSelection, cursor); + var orientedRange = calcRangeOrientation(this.$clickSelection, cursor, editor.session); cursor = orientedRange.cursor; anchor = orientedRange.anchor; } @@ -305,11 +305,11 @@ function calcDistance(ax, ay, bx, by) { return Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2)); } -function calcRangeOrientation(range, cursor) { +function calcRangeOrientation(range, cursor, session) { if (range.start.row == range.end.row) var cmp = 2 * cursor.column - range.start.column - range.end.column; else if (range.start.row == range.end.row - 1 && !range.start.column && !range.end.column) - var cmp = cursor.column - 4; + var cmp = 3 * cursor.column - 2 * session.getLine(range.start.row).length; else var cmp = 2 * cursor.row - range.start.row - range.end.row; diff --git a/src/mouse/mouse_handler_test.js b/src/mouse/mouse_handler_test.js index 07ff2c9ba54..09a7c8af5e7 100644 --- a/src/mouse/mouse_handler_test.js +++ b/src/mouse/mouse_handler_test.js @@ -10,6 +10,7 @@ require("../theme/textmate"); var Editor = require("../editor").Editor; var Mode = require("../mode/java").Mode; var VirtualRenderer = require("../virtual_renderer").VirtualRenderer; +const { test } = require("asyncjs"); var assert = require("../test/assertions"); var MouseEvent = function(type, opts){ var e = document.createEvent("MouseEvents"); @@ -148,6 +149,29 @@ module.exports = { editor.renderer.$loop._flush(); assert.ok(parseInt(lines.cells[0].element.textContent) > 1); }, + "test: gutter click on wrapped line" : function() { + var editor = this.editor; + var value = "x {\n" + " abc".repeat(100) + "\n}"; + value = value.repeat(10); + editor.setValue(value, -1); + editor.setOption("wrap", 40); + editor.renderer.$loop._flush(); + var lines = editor.renderer.$gutterLayer.$lines; + var toggler = lines.cells[1].element; + var rect = toggler.getBoundingClientRect(); + editor.isFocused = () => true; + editor.focus(); + + assert.position(editor.getCursorPosition(), 0, 0); + + toggler.dispatchEvent(MouseEvent("down", {x: rect.left, y: rect.top + rect.height / 2})); + editor.renderer.$loop._flush(); + assert.position(editor.getCursorPosition(), 1, 0); + + toggler.dispatchEvent(MouseEvent("up", {x: rect.left, y: rect.top + rect.height})); + editor.renderer.$loop._flush(); + assert.position(editor.getCursorPosition(), 2, 0); + }, "test: wheel" : function() { var editor = this.editor; var lines = editor.renderer.$gutterLayer.$lines; From 6e110b0061b56b72db7478762036a1ba39251102 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:59:18 +0400 Subject: [PATCH 1287/1293] Fix: Update for compliance with typescript 5.9.2 (#5855) * update for compliance with typescript 5.9.2 * add non-optional emitter to all event types; misc type fixes * update known unknown types * fix EmitParameters type --- ace-internal.d.ts | 179 +++++++++++---------- ace.d.ts | 178 +++++++++++---------- demo/test_package/index.ts | 11 +- package.json | 2 +- src/layer/gutter.js | 13 +- types/ace-ext.d.ts | 316 ++++++++++++++++++------------------- types/ace-modules.d.ts | 289 +++++++++++++++++---------------- 7 files changed, 519 insertions(+), 469 deletions(-) diff --git a/ace-internal.d.ts b/ace-internal.d.ts index 086a0930d87..c0417ec25cd 100644 --- a/ace-internal.d.ts +++ b/ace-internal.d.ts @@ -423,133 +423,133 @@ export namespace Ace { * Emitted when the document changes. * @param delta */ - "change": (delta: Delta) => void; + "change": (delta: Delta, emitter: EditSession) => void; /** * Emitted when the tab size changes, via [[EditSession.setTabSize]]. */ - "changeTabSize": () => void; + "changeTabSize": (e: undefined, emitter: EditSession) => void; /** * Emitted when the ability to overwrite text changes, via [[EditSession.setOverwrite]]. * @param overwrite */ - "changeOverwrite": (overwrite: boolean) => void; + "changeOverwrite": (overwrite: boolean, emitter: EditSession) => void; /** * Emitted when the gutter changes, either by setting or removing breakpoints, or when the gutter decorations change. * @param e */ - "changeBreakpoint": (e?: { row?: number, breakpoint?: boolean }) => void; + "changeBreakpoint": (e: { row?: number, breakpoint?: boolean }, emitter: EditSession) => void; /** * Emitted when a front marker changes. */ - "changeFrontMarker": () => void; + "changeFrontMarker": (e: undefined, emitter: EditSession) => void; /** * Emitted when a back marker changes. */ - "changeBackMarker": () => void; + "changeBackMarker": (e: undefined, emitter: EditSession) => void; /** * Emitted when an annotation changes, like through [[EditSession.setAnnotations]]. */ - "changeAnnotation": (e: {}) => void; + "changeAnnotation": (e: {}, emitter: EditSession) => void; /** * Emitted when a background tokenizer asynchronously processes new rows. */ - "tokenizerUpdate": (e: { data: { first: number, last: number } }) => void; + "tokenizerUpdate": (e: { data: { first: number, last: number } }, emitter: EditSession) => void; /** * Emitted when the current mode changes. * @param e */ - "changeMode": (e: any) => void; + "changeMode": (e: any, emitter: EditSession) => void; /** * Emitted when the wrap mode changes. * @param e */ - "changeWrapMode": (e: any) => void; + "changeWrapMode": (e: any, emitter: EditSession) => void; /** * Emitted when the wrapping limit changes. * @param e */ - "changeWrapLimit": (e: any) => void; + "changeWrapLimit": (e: any, emitter: EditSession) => void; /** * Emitted when a code fold is added or removed. * @param e */ - "changeFold": (e: any, session?: EditSession) => void; + "changeFold": (e: any, emitter: EditSession) => void; /** * Emitted when the scroll top changes. * @param scrollTop The new scroll top value **/ - "changeScrollTop": (scrollTop: number) => void; + "changeScrollTop": (scrollTop: number, emitter: EditSession) => void; /** * Emitted when the scroll left changes. * @param scrollLeft The new scroll left value **/ - "changeScrollLeft": (scrollLeft: number) => void; - "changeEditor": (e: { editor?: Editor, oldEditor?: Editor }) => void; - "changeSelection": () => void; - "startOperation": (op?: { command?: { name?: string }, args?: any }) => void; - "endOperation": (op?: any) => void; - "beforeEndOperation": () => void; + "changeScrollLeft": (scrollLeft: number, emitter: EditSession) => void; + "changeEditor": (e: { editor?: Editor, oldEditor?: Editor }, emitter: EditSession) => void; + "changeSelection": (e: undefined, emitter: EditSession) => void; + "startOperation": (op: { command?: { name?: string }, args?: any }, emitter: EditSession) => void; + "endOperation": (op: any, emitter: EditSession) => void; + "beforeEndOperation": (e: undefined, emitter: EditSession) => void; } interface EditorEvents { - "change": (delta: Delta) => void; - "changeSelection": () => void; - "input": () => void; + "change": (delta: Delta, emitter: Editor) => void; + "changeSelection": (e: undefined, emitter: Editor) => void; + "input": (e: undefined, emitter: Editor) => void; /** * Emitted whenever the [[EditSession]] changes. * @param e An object with two properties, `oldSession` and `session`, that represent the old and new [[EditSession]]s. **/ - "changeSession": (e: { oldSession: EditSession, session: EditSession }) => void; - "blur": (e: any) => void; - "mousedown": (e: MouseEvent) => void; - "mousemove": (e: MouseEvent & { scrollTop?: any }, editor?: Editor) => void; - "changeStatus": (e: any) => void; - "keyboardActivity": (e: any) => void; - "mousewheel": (e: MouseEvent) => void; - "mouseup": (e: MouseEvent) => void; - "beforeEndOperation": (e: any) => void; - "nativecontextmenu": (e: any) => void; - "destroy": (e: any) => void; - "focus": (e?: any) => void; + "changeSession": (e: { oldSession: EditSession, session: EditSession }, emitter: Editor) => void; + "blur": (e: any, emitter: Editor) => void; + "mousedown": (e: MouseEvent, emitter: Editor) => void; + "mousemove": (e: MouseEvent & { scrollTop?: any }, emitter: Editor) => void; + "changeStatus": (e: any, emitter: Editor) => void; + "keyboardActivity": (e: any, emitter: Editor) => void; + "mousewheel": (e: MouseEvent, emitter: Editor) => void; + "mouseup": (e: MouseEvent, emitter: Editor) => void; + "beforeEndOperation": (e: any, emitter: Editor) => void; + "nativecontextmenu": (e: any, emitter: Editor) => void; + "destroy": (e: any, emitter: Editor) => void; + "focus": (e: any, emitter: Editor) => void; /** * Emitted when text is copied. * @param text The copied text **/ - "copy": (e: { text: string }) => void; + "copy": (e: { text: string }, emitter: Editor) => void; /** * Emitted when text is pasted. **/ - "paste": (e: { text: string, event?: ClipboardEvent }) => void; + "paste": (e: { text: string, event?: ClipboardEvent }, emitter: Editor) => void; /** * Emitted when the selection style changes, via [[Editor.setSelectionStyle]]. * @param data Contains one property, `data`, which indicates the new selection style **/ - "changeSelectionStyle": (data: "fullLine" | "screenLine" | "text" | "line") => void; - "changeMode": (e: { mode?: Ace.SyntaxMode, oldMode?: Ace.SyntaxMode }) => void; + "changeSelectionStyle": (data: "fullLine" | "screenLine" | "text" | "line", emitter: Editor) => void; + "changeMode": (e: { mode?: Ace.SyntaxMode, oldMode?: Ace.SyntaxMode }, emitter: Editor) => void; //from searchbox extension - "findSearchBox": (e: { match: boolean }) => void; + "findSearchBox": (e: { match: boolean }, emitter: Editor) => void; //from code_lens extension - "codeLensClick": (e: any) => void; + "codeLensClick": (e: any, emitter: Editor) => void; - "select": () => void; - "gutterkeydown": (e: GutterKeyboardEvent) => void; - "gutterclick": (e: MouseEvent) => void; - "showGutterTooltip": (e: GutterTooltip) => void; - "hideGutterTooltip": (e: GutterTooltip) => void; - "compositionStart": () => void; + "select": (e: undefined, emitter: Editor) => void; + "gutterkeydown": (e: GutterKeyboardEvent, emitter: Editor) => void; + "gutterclick": (e: MouseEvent, emitter: Editor) => void; + "showGutterTooltip": (e: GutterTooltip, emitter: Editor) => void; + "hideGutterTooltip": (e: GutterTooltip, emitter: Editor) => void; + "compositionStart": (e: undefined, emitter: Editor) => void; } interface AcePopupEvents { - "click": (e: MouseEvent) => void; - "dblclick": (e: MouseEvent) => void; - "tripleclick": (e: MouseEvent) => void; - "quadclick": (e: MouseEvent) => void; - "show": () => void; - "hide": () => void; - "select": (hide: boolean) => void; - "changeHoverMarker": (e: any) => void; + "click": (e: MouseEvent, emitter: AcePopup) => void; + "dblclick": (e: MouseEvent, emitter: AcePopup) => void; + "tripleclick": (e: MouseEvent, emitter: AcePopup) => void; + "quadclick": (e: MouseEvent, emitter: AcePopup) => void; + "show": (e: undefined, emitter: AcePopup) => void; + "hide": (e: undefined, emitter: AcePopup) => void; + "select": (hide: boolean, emitter: AcePopup) => void; + "changeHoverMarker": (e: any, emitter: AcePopup) => void; } interface DocumentEvents { @@ -564,8 +564,8 @@ export namespace Ace { * * `lines`: the lines being removed * **/ - "change": (e: Delta) => void; - "changeNewLineMode": () => void; + "change": (e: Delta, emitter: Document) => void; + "changeNewLineMode": (e: undefined, emitter: Document) => void; } interface AnchorEvents { @@ -577,7 +577,7 @@ export namespace Ace { * - `old`: An object describing the old Anchor position * - `value`: An object describing the new Anchor position **/ - "change": (e: { old: Point, value: Point }) => void; + "change": (e: { old: Point, value: Point }, emitter: Anchor) => void; } interface BackgroundTokenizerEvents { @@ -587,52 +587,57 @@ export namespace Ace { **/ "update": (e: { data: { first: number, last: number } - }) => void; + }, emitter: import("./src/background_tokenizer").BackgroundTokenizer) => void; } interface SelectionEvents { /** * Emitted when the cursor position changes. **/ - "changeCursor": () => void; + "changeCursor": (e: undefined, emitter: Selection) => void; /** * Emitted when the cursor selection changes. **/ - "changeSelection": () => void; + "changeSelection": (e: undefined, emitter: Selection) => void; } interface MultiSelectionEvents extends SelectionEvents { - "multiSelect": () => void; - "addRange": (e: { range: Range }) => void; - "removeRange": (e: { ranges: Range[] }) => void; - "singleSelect": () => void; + "multiSelect": (e: undefined, emitter: Selection) => void; + "addRange": (e: { range: Range }, emitter: Selection) => void; + "removeRange": (e: { ranges: Range[] }, emitter: Selection) => void; + "singleSelect": (e: undefined, emitter: Selection) => void; } interface PlaceHolderEvents { - "cursorEnter": (e: any) => void; - "cursorLeave": (e: any) => void; + "cursorEnter": (e: any, emitter: import("./src/placeholder").PlaceHolder) => void; + "cursorLeave": (e: any, emitter: import("./src/placeholder").PlaceHolder) => void; } interface GutterEvents { - "changeGutterWidth": (width: number) => void; - "afterRender": () => void; + "changeGutterWidth": (width: number, emitter: import("./src/layer/gutter").Gutter) => void; + "afterRender": (e: undefined, emitter: import("./src/layer/gutter").Gutter) => void; } interface TextEvents { - "changeCharacterSize": (e: any) => void; + "changeCharacterSize": (e: any, emitter: import("./src/layer/text").Text) => void; } interface VirtualRendererEvents { - "afterRender": (e?: any, renderer?: VirtualRenderer) => void; - "beforeRender": (e: any, renderer?: VirtualRenderer) => void; - "themeLoaded": (e: { theme: string | Theme }) => void; - "themeChange": (e: { theme: string | Theme }) => void; - "scrollbarVisibilityChanged": () => void; - "changeCharacterSize": (e: any) => void; - "resize": (e?: any) => void; - "autosize": () => void; + "afterRender": (e: any, emitter: VirtualRenderer) => void; + "beforeRender": (e: any, emitter: VirtualRenderer) => void; + "themeLoaded": (e: { theme: string | Theme }, emitter: VirtualRenderer) => void; + "themeChange": (e: { theme: string | Theme }, emitter: VirtualRenderer) => void; + "scrollbarVisibilityChanged": (e: undefined, emitter: VirtualRenderer) => void; + "changeCharacterSize": (e: any, emitter: VirtualRenderer) => void; + "resize": (e: any, emitter: VirtualRenderer) => void; + "autosize": (e: undefined, emitter: VirtualRenderer) => void; } + type EmitParameters any> = + T extends (first: infer First, ...rest: any[]) => any + ? [First] + : []; + export class EventEmitter any }> { once(name: K, callback: T[K]): void; @@ -652,11 +657,11 @@ export namespace Ace { removeAllListeners(name?: string): void; - _signal(eventName: K, ...args: Parameters): void; + _signal(eventName: K, ...args: EmitParameters): void; - _emit(eventName: K, ...args: Parameters): void; + _emit(eventName: K, ...args: EmitParameters): void; - _dispatchEvent(eventName: K, ...args: Parameters): void; + _dispatchEvent(eventName: K, ...args: EmitParameters): void; } interface SearchOptions { @@ -951,7 +956,7 @@ export namespace Ace { editor: Editor, command: Command, args: any[] - }) => void; + }, emitter: CommandManager) => void; interface CommandManagerEvents { "exec": execEventHandler @@ -1290,21 +1295,21 @@ export namespace Ace { } export interface CommandBarEvents { - "hide": () => void; - "show": () => void; - "alwaysShow": (e: boolean) => void; + "hide": (e: undefined, emitter: import("./src/ext/command_bar").CommandBarTooltip) => void; + "show": (e: undefined, emitter: import("./src/ext/command_bar").CommandBarTooltip) => void; + "alwaysShow": (e: boolean, emitter: import("./src/ext/command_bar").CommandBarTooltip) => void; } export interface FontMetricsEvents { - "changeCharacterSize": (e: { data: { height: number, width: number } }) => void; + "changeCharacterSize": (e: { data: { height: number, width: number } }, emitter: import("./src/layer/font_metrics").FontMetrics) => void; } export interface OptionPanelEvents { - "setOption": (e: { name: string, value: any }) => void; + "setOption": (e: { name: string, value: any }, emitter: import("./src/ext/options").OptionPanel) => void; } export interface ScrollbarEvents { - "scroll": (e: { data: number }) => void; + "scroll": (e: { data: number }, emitter: ScrollBar) => void; } export interface TextInputAriaOptions { diff --git a/ace.d.ts b/ace.d.ts index c1940248f4c..04dadcec71a 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -318,34 +318,34 @@ declare module "ace-code" { /** * Emitted when the document changes. */ - "change": (delta: Delta) => void; + "change": (delta: Delta, emitter: EditSession) => void; /** * Emitted when the tab size changes, via [[EditSession.setTabSize]]. */ - "changeTabSize": () => void; + "changeTabSize": (e: undefined, emitter: EditSession) => void; /** * Emitted when the ability to overwrite text changes, via [[EditSession.setOverwrite]]. */ - "changeOverwrite": (overwrite: boolean) => void; + "changeOverwrite": (overwrite: boolean, emitter: EditSession) => void; /** * Emitted when the gutter changes, either by setting or removing breakpoints, or when the gutter decorations change. */ - "changeBreakpoint": (e?: { + "changeBreakpoint": (e: { row?: number; breakpoint?: boolean; - }) => void; + }, emitter: EditSession) => void; /** * Emitted when a front marker changes. */ - "changeFrontMarker": () => void; + "changeFrontMarker": (e: undefined, emitter: EditSession) => void; /** * Emitted when a back marker changes. */ - "changeBackMarker": () => void; + "changeBackMarker": (e: undefined, emitter: EditSession) => void; /** * Emitted when an annotation changes, like through [[EditSession.setAnnotations]]. */ - "changeAnnotation": (e: {}) => void; + "changeAnnotation": (e: {}, emitter: EditSession) => void; /** * Emitted when a background tokenizer asynchronously processes new rows. */ @@ -354,51 +354,51 @@ declare module "ace-code" { first: number; last: number; }; - }) => void; + }, emitter: EditSession) => void; /** * Emitted when the current mode changes. */ - "changeMode": (e: any) => void; + "changeMode": (e: any, emitter: EditSession) => void; /** * Emitted when the wrap mode changes. */ - "changeWrapMode": (e: any) => void; + "changeWrapMode": (e: any, emitter: EditSession) => void; /** * Emitted when the wrapping limit changes. */ - "changeWrapLimit": (e: any) => void; + "changeWrapLimit": (e: any, emitter: EditSession) => void; /** * Emitted when a code fold is added or removed. */ - "changeFold": (e: any, session?: EditSession) => void; + "changeFold": (e: any, emitter: EditSession) => void; /** * Emitted when the scroll top changes. * @param scrollTop The new scroll top value **/ - "changeScrollTop": (scrollTop: number) => void; + "changeScrollTop": (scrollTop: number, emitter: EditSession) => void; /** * Emitted when the scroll left changes. * @param scrollLeft The new scroll left value **/ - "changeScrollLeft": (scrollLeft: number) => void; + "changeScrollLeft": (scrollLeft: number, emitter: EditSession) => void; "changeEditor": (e: { editor?: Editor; oldEditor?: Editor; - }) => void; - "changeSelection": () => void; - "startOperation": (op?: { + }, emitter: EditSession) => void; + "changeSelection": (e: undefined, emitter: EditSession) => void; + "startOperation": (op: { command?: { name?: string; }; args?: any; - }) => void; - "endOperation": (op?: any) => void; - "beforeEndOperation": () => void; + }, emitter: EditSession) => void; + "endOperation": (op: any, emitter: EditSession) => void; + "beforeEndOperation": (e: undefined, emitter: EditSession) => void; } interface EditorEvents { - "change": (delta: Delta) => void; - "changeSelection": () => void; - "input": () => void; + "change": (delta: Delta, emitter: Editor) => void; + "changeSelection": (e: undefined, emitter: Editor) => void; + "input": (e: undefined, emitter: Editor) => void; /** * Emitted whenever the [[EditSession]] changes. * @param e An object with two properties, `oldSession` and `session`, that represent the old and new [[EditSession]]s. @@ -406,65 +406,65 @@ declare module "ace-code" { "changeSession": (e: { oldSession: EditSession; session: EditSession; - }) => void; - "blur": (e: any) => void; - "mousedown": (e: MouseEvent) => void; + }, emitter: Editor) => void; + "blur": (e: any, emitter: Editor) => void; + "mousedown": (e: MouseEvent, emitter: Editor) => void; "mousemove": (e: MouseEvent & { scrollTop?: any; - }, editor?: Editor) => void; - "changeStatus": (e: any) => void; - "keyboardActivity": (e: any) => void; - "mousewheel": (e: MouseEvent) => void; - "mouseup": (e: MouseEvent) => void; - "beforeEndOperation": (e: any) => void; - "nativecontextmenu": (e: any) => void; - "destroy": (e: any) => void; - "focus": (e?: any) => void; + }, emitter: Editor) => void; + "changeStatus": (e: any, emitter: Editor) => void; + "keyboardActivity": (e: any, emitter: Editor) => void; + "mousewheel": (e: MouseEvent, emitter: Editor) => void; + "mouseup": (e: MouseEvent, emitter: Editor) => void; + "beforeEndOperation": (e: any, emitter: Editor) => void; + "nativecontextmenu": (e: any, emitter: Editor) => void; + "destroy": (e: any, emitter: Editor) => void; + "focus": (e: any, emitter: Editor) => void; /** * Emitted when text is copied. * @param text The copied text **/ "copy": (e: { text: string; - }) => void; + }, emitter: Editor) => void; /** * Emitted when text is pasted. **/ "paste": (e: { text: string; event?: ClipboardEvent; - }) => void; + }, emitter: Editor) => void; /** * Emitted when the selection style changes, via [[Editor.setSelectionStyle]]. * @param data Contains one property, `data`, which indicates the new selection style **/ - "changeSelectionStyle": (data: "fullLine" | "screenLine" | "text" | "line") => void; + "changeSelectionStyle": (data: "fullLine" | "screenLine" | "text" | "line", emitter: Editor) => void; "changeMode": (e: { mode?: Ace.SyntaxMode; oldMode?: Ace.SyntaxMode; - }) => void; + }, emitter: Editor) => void; //from searchbox extension "findSearchBox": (e: { match: boolean; - }) => void; + }, emitter: Editor) => void; //from code_lens extension - "codeLensClick": (e: any) => void; - "select": () => void; - "gutterkeydown": (e: GutterKeyboardEvent) => void; - "gutterclick": (e: MouseEvent) => void; - "showGutterTooltip": (e: GutterTooltip) => void; - "hideGutterTooltip": (e: GutterTooltip) => void; - "compositionStart": () => void; + "codeLensClick": (e: any, emitter: Editor) => void; + "select": (e: undefined, emitter: Editor) => void; + "gutterkeydown": (e: GutterKeyboardEvent, emitter: Editor) => void; + "gutterclick": (e: MouseEvent, emitter: Editor) => void; + "showGutterTooltip": (e: GutterTooltip, emitter: Editor) => void; + "hideGutterTooltip": (e: GutterTooltip, emitter: Editor) => void; + "compositionStart": (e: undefined, emitter: Editor) => void; } interface AcePopupEvents { - "click": (e: MouseEvent) => void; - "dblclick": (e: MouseEvent) => void; - "tripleclick": (e: MouseEvent) => void; - "quadclick": (e: MouseEvent) => void; - "show": () => void; - "hide": () => void; - "select": (hide: boolean) => void; - "changeHoverMarker": (e: any) => void; + "click": (e: MouseEvent, emitter: AcePopup) => void; + "dblclick": (e: MouseEvent, emitter: AcePopup) => void; + "tripleclick": (e: MouseEvent, emitter: AcePopup) => void; + "quadclick": (e: MouseEvent, emitter: AcePopup) => void; + "show": (e: undefined, emitter: AcePopup) => void; + "hide": (e: undefined, emitter: AcePopup) => void; + "select": (hide: boolean, emitter: AcePopup) => void; + "changeHoverMarker": (e: any, emitter: AcePopup) => void; } interface DocumentEvents { /** @@ -478,8 +478,8 @@ declare module "ace-code" { * * `lines`: the lines being removed * **/ - "change": (e: Delta) => void; - "changeNewLineMode": () => void; + "change": (e: Delta, emitter: Document) => void; + "changeNewLineMode": (e: undefined, emitter: Document) => void; } interface AnchorEvents { /** @@ -493,7 +493,7 @@ declare module "ace-code" { "change": (e: { old: Point; value: Point; - }) => void; + }, emitter: Anchor) => void; } interface BackgroundTokenizerEvents { /** @@ -505,53 +505,57 @@ declare module "ace-code" { first: number; last: number; }; - }) => void; + }, emitter: import("ace-code/src/background_tokenizer").BackgroundTokenizer) => void; } interface SelectionEvents { /** * Emitted when the cursor position changes. **/ - "changeCursor": () => void; + "changeCursor": (e: undefined, emitter: Selection) => void; /** * Emitted when the cursor selection changes. **/ - "changeSelection": () => void; + "changeSelection": (e: undefined, emitter: Selection) => void; } interface MultiSelectionEvents extends SelectionEvents { - "multiSelect": () => void; + "multiSelect": (e: undefined, emitter: Selection) => void; "addRange": (e: { range: Range; - }) => void; + }, emitter: Selection) => void; "removeRange": (e: { ranges: Range[]; - }) => void; - "singleSelect": () => void; + }, emitter: Selection) => void; + "singleSelect": (e: undefined, emitter: Selection) => void; } interface PlaceHolderEvents { - "cursorEnter": (e: any) => void; - "cursorLeave": (e: any) => void; + "cursorEnter": (e: any, emitter: import("ace-code/src/placeholder").PlaceHolder) => void; + "cursorLeave": (e: any, emitter: import("ace-code/src/placeholder").PlaceHolder) => void; } interface GutterEvents { - "changeGutterWidth": (width: number) => void; - "afterRender": () => void; + "changeGutterWidth": (width: number, emitter: import("ace-code/src/layer/gutter").Gutter) => void; + "afterRender": (e: undefined, emitter: import("ace-code/src/layer/gutter").Gutter) => void; } interface TextEvents { - "changeCharacterSize": (e: any) => void; + "changeCharacterSize": (e: any, emitter: import("ace-code/src/layer/text").Text) => void; } interface VirtualRendererEvents { - "afterRender": (e?: any, renderer?: VirtualRenderer) => void; - "beforeRender": (e: any, renderer?: VirtualRenderer) => void; + "afterRender": (e: any, emitter: VirtualRenderer) => void; + "beforeRender": (e: any, emitter: VirtualRenderer) => void; "themeLoaded": (e: { theme: string | Theme; - }) => void; + }, emitter: VirtualRenderer) => void; "themeChange": (e: { theme: string | Theme; - }) => void; - "scrollbarVisibilityChanged": () => void; - "changeCharacterSize": (e: any) => void; - "resize": (e?: any) => void; - "autosize": () => void; - } + }, emitter: VirtualRenderer) => void; + "scrollbarVisibilityChanged": (e: undefined, emitter: VirtualRenderer) => void; + "changeCharacterSize": (e: any, emitter: VirtualRenderer) => void; + "resize": (e: any, emitter: VirtualRenderer) => void; + "autosize": (e: undefined, emitter: VirtualRenderer) => void; + } + type EmitParameters any> = T extends (first: infer First, ...rest: any[]) => any ? [ + First + ] : [ + ]; export class EventEmitter any; }> { @@ -765,7 +769,7 @@ declare module "ace-code" { editor: Editor; command: Command; args: any[]; - }) => void; + }, emitter: CommandManager) => void; interface CommandManagerEvents { "exec": execEventHandler; "afterExec": execEventHandler; @@ -1021,9 +1025,9 @@ declare module "ace-code" { selectionChanged?: boolean; } export interface CommandBarEvents { - "hide": () => void; - "show": () => void; - "alwaysShow": (e: boolean) => void; + "hide": (e: undefined, emitter: import("ace-code/src/ext/command_bar").CommandBarTooltip) => void; + "show": (e: undefined, emitter: import("ace-code/src/ext/command_bar").CommandBarTooltip) => void; + "alwaysShow": (e: boolean, emitter: import("ace-code/src/ext/command_bar").CommandBarTooltip) => void; } export interface FontMetricsEvents { "changeCharacterSize": (e: { @@ -1031,18 +1035,18 @@ declare module "ace-code" { height: number; width: number; }; - }) => void; + }, emitter: import("ace-code/src/layer/font_metrics").FontMetrics) => void; } export interface OptionPanelEvents { "setOption": (e: { name: string; value: any; - }) => void; + }, emitter: import("ace-code/src/ext/options").OptionPanel) => void; } export interface ScrollbarEvents { "scroll": (e: { data: number; - }) => void; + }, emitter: ScrollBar) => void; } export interface TextInputAriaOptions { activeDescendant?: string; diff --git a/demo/test_package/index.ts b/demo/test_package/index.ts index 3d05770ecb8..3895061ec26 100644 --- a/demo/test_package/index.ts +++ b/demo/test_package/index.ts @@ -1,5 +1,5 @@ import * as ace from "ace-code"; -import {Range} from "ace-code"; +import {EditSession, Range} from "ace-code"; import {Autocomplete, FilteredList} from "ace-code/src/autocomplete"; import {beautify} from "ace-code/src/ext/beautify"; import {registerCodeLensProvider, setLenses} from "ace-code/src/ext/code_lens"; @@ -138,15 +138,22 @@ filter.setFilter("test"); editor.session.startOperation(); editor.session.endOperation(); -editor.on("paste", (e) => { +editor.on("paste", (e, emitter) => { if (e.event && e.event.clipboardData) { var htmlString = e.event.clipboardData.getData("text/html") if (htmlString) { e.text = htmlString } + if (emitter.session) { + console.log("no error"); + } } }) +editor.session.on("changeMode", (e, emitter) => { + return e && emitter instanceof EditSession +}) + if (themesByName.textmate) console.log(themesByName.textmate.theme); diff --git a/package.json b/package.json index 881457158ed..740a51c21f4 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "eslint": "^8.20.0", "istanbul": "^0.4.5", "standard-version": "^9.3.2", - "typescript": "5.8.3" + "typescript": "5.9.2" }, "mappings": { "ace": "." diff --git a/src/layer/gutter.js b/src/layer/gutter.js index abc8619ee7e..143d9dbadde 100644 --- a/src/layer/gutter.js +++ b/src/layer/gutter.js @@ -1,8 +1,18 @@ "use strict"; /** * @typedef {import("../edit_session").EditSession} EditSession + * @typedef {import("../editor").Editor} Editor * @typedef {import("../../ace-internal").Ace.LayerConfig} LayerConfig */ +/** + * @typedef {Object} GutterRenderer + * @property {(session: EditSession, row: number) => string} getText - Gets the text to display for a given row + * @property {(session: EditSession, lastLineNumber: number, config: Object) => number} getWidth - Calculates the width needed for the gutter + * @property {(e: undefined, editor: Editor) => void} [update] - Updates the gutter display + * @property {(editor: Editor) => void} [attach] - Attaches the renderer to an editor + * @property {(editor: Editor) => void} [detach] - Detaches the renderer from an editor + */ + var dom = require("../lib/dom"); var oop = require("../lib/oop"); var lang = require("../lib/lang"); @@ -572,6 +582,7 @@ class Gutter{ * @param {boolean} show */ setShowLineNumbers(show) { + /**@type{GutterRenderer}*/ this.$renderer = !show && { getWidth: function() {return 0;}, getText: function() {return "";} @@ -739,7 +750,7 @@ class Gutter{ Gutter.prototype.$fixedWidth = false; Gutter.prototype.$highlightGutterLine = true; -Gutter.prototype.$renderer = ""; +Gutter.prototype.$renderer = undefined; Gutter.prototype.$showLineNumbers = true; Gutter.prototype.$showFoldWidgets = true; diff --git a/types/ace-ext.d.ts b/types/ace-ext.d.ts index 68e7aeac24c..e87d48c3a82 100644 --- a/types/ace-ext.d.ts +++ b/types/ace-ext.d.ts @@ -228,7 +228,7 @@ declare module "ace-code/src/ext/diff/scroll_diff_decorator" { import { Decorator } from "ace-code/src/layer/decorators"; } declare module "ace-code/src/ext/diff/styles-css" { - export const cssText: "\n/*\n * Line Markers\n */\n.ace_diff {\n position: absolute;\n z-index: 0;\n}\n.ace_diff.inline {\n z-index: 20;\n}\n/*\n * Light Colors \n */\n.ace_diff.insert {\n background-color: #EFFFF1;\n}\n.ace_diff.delete {\n background-color: #FFF1F1;\n}\n.ace_diff.aligned_diff {\n background: rgba(206, 194, 191, 0.26);\n background: repeating-linear-gradient(\n 45deg,\n rgba(122, 111, 108, 0.26),\n rgba(122, 111, 108, 0.26) 5px,\n rgba(0, 0, 0, 0) 5px,\n rgba(0, 0, 0, 0) 10px \n );\n}\n\n.ace_diff.insert.inline {\n background-color: rgb(74 251 74 / 18%); \n}\n.ace_diff.delete.inline {\n background-color: rgb(251 74 74 / 15%);\n}\n\n.ace_diff.delete.inline.empty {\n background-color: rgba(255, 128, 79, 0.7);\n width: 2px !important;\n}\n\n.ace_diff.insert.inline.empty {\n background-color: rgba(49, 230, 96, 0.7);\n width: 2px !important;\n}\n\n.ace_diff-active-line {\n border-bottom: 1px solid;\n border-top: 1px solid;\n background: transparent;\n position: absolute;\n box-sizing: border-box;\n border-color: #9191ac;\n}\n\n.ace_dark .ace_diff-active-line {\n background: transparent;\n border-color: #75777a;\n}\n \n\n/* gutter changes */\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell,\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell_svg-icons {\n padding-right: 13px;\n}\n\n.ace_mini-diff_gutter_other > .ace_gutter-cell,\n.ace_mini-diff_gutter_other > .ace_gutter-cell_svg-icons {\n display: none;\n}\n\n.ace_mini-diff_gutter_other {\n pointer-events: none;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #EFFFF1;\n border-left: 3px solid #2BB534;\n padding-left: 16px;\n display: block;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #FFF1F1;\n border-left: 3px solid #EA7158;\n padding-left: 16px;\n display: block;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added:after {\n position: absolute;\n right: 2px;\n content: \"+\";\n color: darkgray;\n background-color: inherit;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted:after {\n position: absolute;\n right: 2px;\n content: \"-\";\n color: darkgray;\n background-color: inherit;\n}\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-added:after,\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-deleted:after {\n display: none;\n}\n\n.ace_diff_other .ace_selection {\n filter: drop-shadow(1px 2px 3px darkgray);\n}\n\n.ace_hidden_marker-layer .ace_bracket {\n display: none;\n}\n\n\n\n/*\n * Dark Colors \n */\n\n.ace_dark .ace_diff.insert {\n background-color: #212E25;\n}\n.ace_dark .ace_diff.delete {\n background-color: #3F2222;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #212E25;\n border-left-color:#00802F;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #3F2222;\n border-left-color: #9C3838;\n}\n\n"; + export const cssText: "\n/*\n * Line Markers\n */\n.ace_diff {\n position: absolute;\n z-index: 0;\n}\n.ace_diff.inline {\n z-index: 20;\n}\n/*\n * Light Colors \n */\n.ace_diff.insert {\n background-color: #EFFFF1;\n}\n.ace_diff.delete {\n background-color: #FFF1F1;\n}\n.ace_diff.aligned_diff {\n background: rgba(206, 194, 191, 0.26);\n background: repeating-linear-gradient(\n 45deg,\n rgba(122, 111, 108, 0.26),\n rgba(122, 111, 108, 0.26) 5px,\n rgba(0, 0, 0, 0) 5px,\n rgba(0, 0, 0, 0) 10px \n );\n}\n\n.ace_diff.insert.inline {\n background-color: rgb(74 251 74 / 18%); \n}\n.ace_diff.delete.inline {\n background-color: rgb(251 74 74 / 15%);\n}\n\n.ace_diff.delete.inline.empty {\n background-color: rgba(255, 128, 79, 0.7);\n width: 2px !important;\n}\n\n.ace_diff.insert.inline.empty {\n background-color: rgba(49, 230, 96, 0.7);\n width: 2px !important;\n}\n\n.ace_diff-active-line {\n border-bottom: 1px solid;\n border-top: 1px solid;\n background: transparent;\n position: absolute;\n box-sizing: border-box;\n border-color: #9191ac;\n}\n\n.ace_dark .ace_diff-active-line {\n background: transparent;\n border-color: #75777a;\n}\n \n\n/* gutter changes */\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell,\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell_svg-icons {\n padding-right: 13px;\n}\n\n.ace_mini-diff_gutter_other > .ace_gutter-cell,\n.ace_mini-diff_gutter_other > .ace_gutter-cell_svg-icons {\n display: none;\n}\n\n.ace_mini-diff_gutter_other {\n pointer-events: none;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #EFFFF1;\n border-left: 3px solid #2BB534;\n padding-left: 16px;\n display: block;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #FFF1F1;\n border-left: 3px solid #EA7158;\n padding-left: 16px;\n display: block;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added:after {\n position: absolute;\n right: 2px;\n content: \"+\";\n background-color: inherit;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted:after {\n position: absolute;\n right: 2px;\n content: \"-\";\n background-color: inherit;\n}\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-added:after,\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-deleted:after {\n display: none;\n}\n\n.ace_diff_other .ace_selection {\n filter: drop-shadow(1px 2px 3px darkgray);\n}\n\n.ace_hidden_marker-layer .ace_bracket,\n.ace_hidden_marker-layer .ace_error_bracket {\n display: none;\n}\n\n\n\n/*\n * Dark Colors \n */\n\n.ace_dark .ace_diff.insert {\n background-color: #212E25;\n}\n.ace_dark .ace_diff.delete {\n background-color: #3F2222;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #212E25;\n border-left-color:#00802F;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #3F2222;\n border-left-color: #9C3838;\n}\n\n"; } declare module "ace-code/src/ext/diff/gutter_decorator" { export class MinimalGutterDiffDecorator { @@ -554,155 +554,6 @@ declare module "ace-code/src/ext/elastic_tabstops_lite" { } import { Editor } from "ace-code/src/editor"; } -declare module "ace-code/src/ext/error_marker" { - export function showErrorMarker(editor: import("ace-code/src/editor").Editor, dir: number): void; -} -declare module "ace-code/src/ext/beautify" { - export const singletonTags: string[]; - export const blockTags: string[]; - export const formatOptions: { - lineBreaksAfterCommasInCurlyBlock?: boolean; - }; - export function beautify(session: import("ace-code/src/edit_session").EditSession): void; - export const commands: import("ace-code").Ace.Command[]; -} -declare module "ace-code/src/ext/code_lens" { - export function setLenses(session: EditSession, lenses: import("ace-code").Ace.CodeLense[]): number; - export function registerCodeLensProvider(editor: import("ace-code/src/editor").Editor, codeLensProvider: import("ace-code").Ace.CodeLenseProvider): void; - export function clear(session: EditSession): void; - export type EditSession = import("ace-code/src/edit_session").EditSession; - export type VirtualRenderer = import("ace-code/src/virtual_renderer").VirtualRenderer & { - }; - export type CodeLenseCommand = import("ace-code").Ace.CodeLenseCommand; - export type CodeLense = import("ace-code").Ace.CodeLense; - import { Editor } from "ace-code/src/editor"; -} -declare module "ace-code/src/ext/emmet" { - export const commands: HashHandler; - export function runEmmetCommand(editor: Editor): ReturnType | boolean; - export function updateCommands(editor: Editor, enabled?: boolean): void; - export function isSupportedMode(mode: any | string): boolean; - export function isAvailable(editor: Editor, command: string): boolean; - export function load(cb?: Function): boolean; - export function setCore(e: string | any): void; - import { HashHandler } from "ace-code/src/keyboard/hash_handler"; - import { Editor } from "ace-code/src/editor"; - /** - * Implementation of {@link IEmmetEditor} interface for Ace - */ - export class AceEmmetEditor { - setupContext(editor: Editor): void; - ace: Editor; - indentation: string; - /** - * Returns character indexes of selected text: object with start - * and end properties. If there's no selection, should return - * object with start and end properties referring - * to current caret position - * @example - * var selection = editor.getSelectionRange(); - * alert(selection.start + ', ' + selection.end); - */ - getSelectionRange(): any; - /** - * Creates selection from start to end character - * indexes. If end is ommited, this method should place caret - * and start index - * @example - * editor.createSelection(10, 40); - * - * //move caret to 15th character - * editor.createSelection(15); - */ - createSelection(start: number, end?: number): void; - /** - * Returns current line's start and end indexes as object with start - * and end properties - * @example - * var range = editor.getCurrentLineRange(); - * alert(range.start + ', ' + range.end); - */ - getCurrentLineRange(): any; - /** - * Returns current caret position - */ - getCaretPos(): number | null; - /** - * Set new caret position - * @param {Number} index Caret position - */ - setCaretPos(index: number): void; - /** - * Returns content of current line - */ - getCurrentLine(): string; - /** - * Replace editor's content or it's part (from start to - * end index). If value contains - * caret_placeholder, the editor will put caret into - * this position. If you skip start and end - * arguments, the whole target's content will be replaced with - * value. - * - * If you pass start argument only, - * the value will be placed at start string - * index of current content. - * - * If you pass start and end arguments, - * the corresponding substring of current target's content will be - * replaced with value. - * @param {String} value Content you want to paste - * @param {Number} [start] Start index of editor's content - * @param {Number} [end] End index of editor's content - * @param {Boolean} [noIndent] Do not auto indent value - */ - replaceContent(value: string, start?: number, end?: number, noIndent?: boolean): void; - /** - * Returns editor's content - */ - getContent(): string; - /** - * Returns current editor's syntax mode - */ - getSyntax(): string; - /** - * Returns current output profile name (@see emmet#setupProfile) - */ - getProfileName(): string; - /** - * Ask user to enter something - * @param {String} title Dialog title - * @return {String} Entered data - * @since 0.65 - */ - prompt(title: string): string; - /** - * Returns current selection - * @since 0.65 - */ - getSelection(): string; - /** - * Returns current editor's file path - * @since 0.65 - */ - getFilePath(): string; - } -} -declare module "ace-code/src/ext/hardwrap" { - /** - * Wraps lines at specified column limits and optionally merges short adjacent lines. - * - * Processes text within the specified row range, breaking lines that exceed the maximum column - * width at appropriate word boundaries while preserving indentation. When merge is enabled, - * combines short consecutive lines that can fit within the column limit. Automatically adjusts - * the end row when new line breaks are inserted to ensure all affected content is processed. - * - * @param {import("ace-code/src/editor").Editor} editor - The editor instance containing the text to wrap - * @param {import("ace-code").Ace.HardWrapOptions} options - Configuration options for wrapping behavior - */ - export function hardWrap(editor: import("ace-code/src/editor").Editor, options: import("ace-code").Ace.HardWrapOptions): void; - import { Editor } from "ace-code/src/editor"; -} declare module "ace-code/src/ext/menu_tools/settings_menu.css" { const _exports: string; export = _exports; @@ -713,14 +564,6 @@ declare module "ace-code/src/ext/menu_tools/overlay_page" { setIgnoreFocusOut: (ignore: boolean) => void; }; } -declare module "ace-code/src/ext/menu_tools/get_editor_keyboard_shortcuts" { - export function getEditorKeybordShortcuts(editor: import("ace-code/src/editor").Editor): any[]; -} -declare module "ace-code/src/ext/keybinding_menu" { - export function init(editor: Editor): void; - import { Editor } from "ace-code/src/editor"; -} -declare module "ace-code/src/ext/linking" { } declare module "ace-code/src/ext/modelist" { /** * Suggests a mode based on the file extension present in the given path @@ -998,6 +841,163 @@ declare module "ace-code/src/ext/options" { export interface OptionPanel extends Ace.EventEmitter { } } +declare module "ace-code/src/ext/error_marker" { + export function showErrorMarker(editor: import("ace-code/src/editor").Editor, dir: number): void; +} +declare module "ace-code/src/ext/beautify" { + export const singletonTags: string[]; + export const blockTags: string[]; + export const formatOptions: { + lineBreaksAfterCommasInCurlyBlock?: boolean; + }; + export function beautify(session: import("ace-code/src/edit_session").EditSession): void; + export const commands: import("ace-code").Ace.Command[]; +} +declare module "ace-code/src/ext/code_lens" { + export function setLenses(session: EditSession, lenses: import("ace-code").Ace.CodeLense[]): number; + export function registerCodeLensProvider(editor: import("ace-code/src/editor").Editor, codeLensProvider: import("ace-code").Ace.CodeLenseProvider): void; + export function clear(session: EditSession): void; + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type VirtualRenderer = import("ace-code/src/virtual_renderer").VirtualRenderer & { + }; + export type CodeLenseCommand = import("ace-code").Ace.CodeLenseCommand; + export type CodeLense = import("ace-code").Ace.CodeLense; + import { Editor } from "ace-code/src/editor"; +} +declare module "ace-code/src/ext/emmet" { + export const commands: HashHandler; + export function runEmmetCommand(editor: Editor): ReturnType | boolean; + export function updateCommands(editor: Editor, enabled?: boolean): void; + export function isSupportedMode(mode: any | string): boolean; + export function isAvailable(editor: Editor, command: string): boolean; + export function load(cb?: Function): boolean; + export function setCore(e: string | any): void; + import { HashHandler } from "ace-code/src/keyboard/hash_handler"; + import { Editor } from "ace-code/src/editor"; + /** + * Implementation of {@link IEmmetEditor} interface for Ace + */ + export class AceEmmetEditor { + setupContext(editor: Editor): void; + ace: Editor; + indentation: string; + /** + * Returns character indexes of selected text: object with start + * and end properties. If there's no selection, should return + * object with start and end properties referring + * to current caret position + * @example + * var selection = editor.getSelectionRange(); + * alert(selection.start + ', ' + selection.end); + */ + getSelectionRange(): any; + /** + * Creates selection from start to end character + * indexes. If end is ommited, this method should place caret + * and start index + * @example + * editor.createSelection(10, 40); + * + * //move caret to 15th character + * editor.createSelection(15); + */ + createSelection(start: number, end?: number): void; + /** + * Returns current line's start and end indexes as object with start + * and end properties + * @example + * var range = editor.getCurrentLineRange(); + * alert(range.start + ', ' + range.end); + */ + getCurrentLineRange(): any; + /** + * Returns current caret position + */ + getCaretPos(): number | null; + /** + * Set new caret position + * @param {Number} index Caret position + */ + setCaretPos(index: number): void; + /** + * Returns content of current line + */ + getCurrentLine(): string; + /** + * Replace editor's content or it's part (from start to + * end index). If value contains + * caret_placeholder, the editor will put caret into + * this position. If you skip start and end + * arguments, the whole target's content will be replaced with + * value. + * + * If you pass start argument only, + * the value will be placed at start string + * index of current content. + * + * If you pass start and end arguments, + * the corresponding substring of current target's content will be + * replaced with value. + * @param {String} value Content you want to paste + * @param {Number} [start] Start index of editor's content + * @param {Number} [end] End index of editor's content + * @param {Boolean} [noIndent] Do not auto indent value + */ + replaceContent(value: string, start?: number, end?: number, noIndent?: boolean): void; + /** + * Returns editor's content + */ + getContent(): string; + /** + * Returns current editor's syntax mode + */ + getSyntax(): string; + /** + * Returns current output profile name (@see emmet#setupProfile) + */ + getProfileName(): string; + /** + * Ask user to enter something + * @param {String} title Dialog title + * @return {String} Entered data + * @since 0.65 + */ + prompt(title: string): string; + /** + * Returns current selection + * @since 0.65 + */ + getSelection(): string; + /** + * Returns current editor's file path + * @since 0.65 + */ + getFilePath(): string; + } +} +declare module "ace-code/src/ext/hardwrap" { + /** + * Wraps lines at specified column limits and optionally merges short adjacent lines. + * + * Processes text within the specified row range, breaking lines that exceed the maximum column + * width at appropriate word boundaries while preserving indentation. When merge is enabled, + * combines short consecutive lines that can fit within the column limit. Automatically adjusts + * the end row when new line breaks are inserted to ensure all affected content is processed. + * + * @param {import("ace-code/src/editor").Editor} editor - The editor instance containing the text to wrap + * @param {import("ace-code").Ace.HardWrapOptions} options - Configuration options for wrapping behavior + */ + export function hardWrap(editor: import("ace-code/src/editor").Editor, options: import("ace-code").Ace.HardWrapOptions): void; + import { Editor } from "ace-code/src/editor"; +} +declare module "ace-code/src/ext/menu_tools/get_editor_keyboard_shortcuts" { + export function getEditorKeybordShortcuts(editor: import("ace-code/src/editor").Editor): any[]; +} +declare module "ace-code/src/ext/keybinding_menu" { + export function init(editor: Editor): void; + import { Editor } from "ace-code/src/editor"; +} +declare module "ace-code/src/ext/linking" { } declare module "ace-code/src/ext/prompt" { export type PromptOptions = { /** diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index 203254f67a4..4bfc1caa28e 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -427,7 +427,30 @@ declare module "ace-code/src/layer/gutter" { }): "markers" | "foldWidgets"; } export type EditSession = import("ace-code/src/edit_session").EditSession; + export type Editor = import("ace-code/src/editor").Editor; export type LayerConfig = import("ace-code").Ace.LayerConfig; + export type GutterRenderer = { + /** + * - Gets the text to display for a given row + */ + getText: (session: EditSession, row: number) => string; + /** + * - Calculates the width needed for the gutter + */ + getWidth: (session: EditSession, lastLineNumber: number, config: any) => number; + /** + * - Updates the gutter display + */ + update?: (e: undefined, editor: Editor) => void; + /** + * - Attaches the renderer to an editor + */ + attach?: (editor: Editor) => void; + /** + * - Detaches the renderer from an editor + */ + detach?: (editor: Editor) => void; + }; import { Lines } from "ace-code/src/layer/lines"; namespace Ace { type EventEmitter; + lines: any[]; + states: string[] | string[][]; + currentLine: number; + tokenizer: import("ace-code/src/tokenizer").Tokenizer; + /** + * Sets a new tokenizer for this object. + * @param {Tokenizer} tokenizer The new tokenizer to use + **/ + setTokenizer(tokenizer: Tokenizer): void; + /** + * Sets a new document to associate with this object. + * @param {Document} doc The new document to associate with + **/ + setDocument(doc: Document): void; + doc: import("ace-code/src/document").Document; + /** + * Emits the `'update'` event. `firstRow` and `lastRow` are used to define the boundaries of the region to be updated. + * @param {Number} firstRow The starting row region + * @param {Number} lastRow The final row region + **/ + fireUpdateEvent(firstRow: number, lastRow: number): void; + /** + * Starts tokenizing at the row indicated. + * @param {Number} startRow The row to start at + **/ + start(startRow: number): void; + /** + * Sets pretty long delay to prevent the tokenizer from interfering with the user + */ + scheduleStart(): void; + /** + * Stops tokenizing. + **/ + stop(): void; + /** + * Gives list of [[Token]]'s of the row. (tokens are cached) + * @param {Number} row The row to get tokens at + **/ + getTokens(row: number): import("ace-code").Ace.Token[]; + /** + * Returns the state of tokenization at the end of a row. + * @param {Number} row The row to get state at + **/ + getState(row: number): string | string[]; + cleanup(): void; + } + export type Document = import("ace-code/src/document").Document; + export type EditSession = import("ace-code/src/edit_session").EditSession; + export type Tokenizer = import("ace-code/src/tokenizer").Tokenizer; + namespace Ace { + type EventEmitter any; + }> = import("ace-code").Ace.EventEmitter; + type BackgroundTokenizerEvents = import("ace-code").Ace.BackgroundTokenizerEvents; + } + export interface BackgroundTokenizer extends Ace.EventEmitter { + } +} +declare module "ace-code/src/placeholder" { + export class PlaceHolder { + constructor(session: EditSession, length: number, pos: import("ace-code").Ace.Point, others: any[], mainClass: string, othersClass: string); + length: number; + session: import("ace-code/src/edit_session").EditSession; + doc: import("ace-code/src/document").Document; + mainClass: string; + othersClass: string; + /** + * PlaceHolder.setup() + * + * TODO + * + **/ + setup(): void; + selectionBefore: Range | Range[]; + pos: import("ace-code/src/anchor").Anchor; + others: any[]; + /** + * PlaceHolder.showOtherMarkers() + * + * TODO + * + **/ + showOtherMarkers(): void; + othersActive: boolean; + /** + * PlaceHolder.hideOtherMarkers() + * + * Hides all over markers in the [[EditSession `EditSession`]] that are not the currently selected one. + * + **/ + hideOtherMarkers(): void; + updateAnchors(delta: import("ace-code").Ace.Delta): void; + updateMarkers(): void; + /** + * PlaceHolder.detach() + * + * TODO + * + **/ + detach(): void; + /** + * PlaceHolder.cancel() + * + * TODO + * + **/ + cancel(): void; + } + export type EditSession = import("ace-code/src/edit_session").EditSession; + import { Range } from "ace-code/src/range"; + namespace Ace { + type EventEmitter any; + }> = import("ace-code").Ace.EventEmitter; + type PlaceHolderEvents = import("ace-code").Ace.PlaceHolderEvents; + } + export interface PlaceHolder extends Ace.EventEmitter { + } +} declare module "ace-code/src/layer/text_markers" { export type TextMarker = { range: import("ace-code").Ace.IRange; @@ -3742,78 +3898,6 @@ declare module "ace-code/src/bidihandler" { } import bidiUtil = require("ace-code/src/lib/bidiutil"); } -declare module "ace-code/src/background_tokenizer" { - /** - * Tokenizes the current [[Document `Document`]] in the background, and caches the tokenized rows for future use. - * - * If a certain row is changed, everything below that row is re-tokenized. - **/ - export class BackgroundTokenizer { - /** - * Creates a new `BackgroundTokenizer` object. - * @param {Tokenizer} tokenizer The tokenizer to use - * @param {EditSession} [session] The editor session to associate with - **/ - constructor(tokenizer: Tokenizer, session?: EditSession); - running: false | ReturnType; - lines: any[]; - states: string[] | string[][]; - currentLine: number; - tokenizer: import("ace-code/src/tokenizer").Tokenizer; - /** - * Sets a new tokenizer for this object. - * @param {Tokenizer} tokenizer The new tokenizer to use - **/ - setTokenizer(tokenizer: Tokenizer): void; - /** - * Sets a new document to associate with this object. - * @param {Document} doc The new document to associate with - **/ - setDocument(doc: Document): void; - doc: import("ace-code/src/document").Document; - /** - * Emits the `'update'` event. `firstRow` and `lastRow` are used to define the boundaries of the region to be updated. - * @param {Number} firstRow The starting row region - * @param {Number} lastRow The final row region - **/ - fireUpdateEvent(firstRow: number, lastRow: number): void; - /** - * Starts tokenizing at the row indicated. - * @param {Number} startRow The row to start at - **/ - start(startRow: number): void; - /** - * Sets pretty long delay to prevent the tokenizer from interfering with the user - */ - scheduleStart(): void; - /** - * Stops tokenizing. - **/ - stop(): void; - /** - * Gives list of [[Token]]'s of the row. (tokens are cached) - * @param {Number} row The row to get tokens at - **/ - getTokens(row: number): import("ace-code").Ace.Token[]; - /** - * Returns the state of tokenization at the end of a row. - * @param {Number} row The row to get state at - **/ - getState(row: number): string | string[]; - cleanup(): void; - } - export type Document = import("ace-code/src/document").Document; - export type EditSession = import("ace-code/src/edit_session").EditSession; - export type Tokenizer = import("ace-code/src/tokenizer").Tokenizer; - namespace Ace { - type EventEmitter any; - }> = import("ace-code").Ace.EventEmitter; - type BackgroundTokenizerEvents = import("ace-code").Ace.BackgroundTokenizerEvents; - } - export interface BackgroundTokenizer extends Ace.EventEmitter { - } -} declare module "ace-code/src/edit_session/folding" { export type IFolding = import("ace-code/src/edit_session").EditSession & import("ace-code").Ace.Folding; export type Delta = import("ace-code").Ace.Delta; @@ -4804,67 +4888,6 @@ declare module "ace-code/src/range" { declare module "ace-code/src/worker/worker_client" { export var WorkerClient: any; } -declare module "ace-code/src/placeholder" { - export class PlaceHolder { - constructor(session: EditSession, length: number, pos: import("ace-code").Ace.Point, others: any[], mainClass: string, othersClass: string); - length: number; - session: import("ace-code/src/edit_session").EditSession; - doc: import("ace-code/src/document").Document; - mainClass: string; - othersClass: string; - /** - * PlaceHolder.setup() - * - * TODO - * - **/ - setup(): void; - selectionBefore: Range | Range[]; - pos: import("ace-code/src/anchor").Anchor; - others: any[]; - /** - * PlaceHolder.showOtherMarkers() - * - * TODO - * - **/ - showOtherMarkers(): void; - othersActive: boolean; - /** - * PlaceHolder.hideOtherMarkers() - * - * Hides all over markers in the [[EditSession `EditSession`]] that are not the currently selected one. - * - **/ - hideOtherMarkers(): void; - updateAnchors(delta: import("ace-code").Ace.Delta): void; - updateMarkers(): void; - /** - * PlaceHolder.detach() - * - * TODO - * - **/ - detach(): void; - /** - * PlaceHolder.cancel() - * - * TODO - * - **/ - cancel(): void; - } - export type EditSession = import("ace-code/src/edit_session").EditSession; - import { Range } from "ace-code/src/range"; - namespace Ace { - type EventEmitter any; - }> = import("ace-code").Ace.EventEmitter; - type PlaceHolderEvents = import("ace-code").Ace.PlaceHolderEvents; - } - export interface PlaceHolder extends Ace.EventEmitter { - } -} declare module "ace-code/src/commands/occur_commands" { export namespace occurStartCommand { let name: string; From 8f32aabe3caf737421b27f7420535440dbb37d5f Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Wed, 17 Sep 2025 21:31:21 +0400 Subject: [PATCH 1288/1293] fix gutter custom widget modifying wrong rows (#5869) --- src/keyboard/gutter_handler_test.js | 37 ++++++++++++++++++++++++++--- src/layer/gutter.js | 26 +++++++++++++++----- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/keyboard/gutter_handler_test.js b/src/keyboard/gutter_handler_test.js index 9124f2dfb3d..c59d46738f5 100644 --- a/src/keyboard/gutter_handler_test.js +++ b/src/keyboard/gutter_handler_test.js @@ -296,7 +296,8 @@ module.exports = { assert.equal(toggler.getAttribute("aria-label"), "Toggle code folding, row 1"); assert.equal(toggler.getAttribute("aria-expanded"), "true"); assert.equal(toggler.getAttribute("title"), "Fold code"); - },"test: should signal keyboard event" : function(done) { + }, + "test: should signal keyboard event" : function(done) { var editor = this.editor; var value = "x {" + "\n".repeat(50) + "}\n"; value = value.repeat(50); @@ -391,7 +392,8 @@ module.exports = { done(); }, 20); }, 20); - }, "test: moving up and down to custom widget and checking onclick callback as well" : function(done) { + }, + "test: moving up and down to custom widget and checking onclick callback as well" : function(done) { var editor = this.editor; var value = "\n x {" + "\n".repeat(5) + "}\n"; value = value.repeat(50); @@ -441,7 +443,36 @@ module.exports = { assert.equal(document.activeElement, lines.cells[1].element.childNodes[1]); done(); }, 20); - }, + }, + "test: add several custom widgets" : function() { + var editor = this.editor; + var value = "x {" + "\n".repeat(5) + "}\n"; + value = value.repeat(50); + editor.session.setMode(new Mode()); + editor.setValue(value, -1); + editor.execCommand("toggleFoldWidget"); + editor.renderer.$loop._flush(); + + + editor.renderer.$gutterLayer.$addCustomWidget(100, { + className: "widget1", + }); + editor.renderer.$gutterLayer.$addCustomWidget(4, { + className: "widget2", + }); + editor.renderer.$loop._flush(); + + assert.ok(!editor.container.querySelector(".widget1")); + assert.ok(editor.container.querySelector(".widget2")); + + editor.navigateTo(100, 0); + editor.renderer.scrollCursorIntoView(); + + editor.renderer.$loop._flush(); + assert.ok(editor.container.querySelector(".widget1")); + assert.ok(!editor.container.querySelector(".widget2")); + + }, tearDown : function() { this.editor.destroy(); diff --git a/src/layer/gutter.js b/src/layer/gutter.js index 143d9dbadde..7f41e375e1e 100644 --- a/src/layer/gutter.js +++ b/src/layer/gutter.js @@ -645,15 +645,29 @@ class Gutter{ /** * Retrieves the gutter cell element at the specified cursor row position. * @param {number} row - The row number in the editor where the gutter cell is located starts from 0 - * @returns {HTMLElement|null} The gutter cell element at the specified row, or null if not found + * @returns {HTMLElement|undefined} The gutter cell element at the specified row, or undefined if not found * @experimental */ $getGutterCell(row) { - // contains only visible rows - const cells = this.$lines.cells; - const visibileRow= this.session.documentToScreenRow(row,0); - // subtracting the first visible screen row index and folded rows from the row number. - return cells[row - this.config.firstRowScreen - (row-visibileRow)]; + var cells = this.$lines.cells; + var min = 0; + var max = cells.length - 1; + + if (row < cells[0].row || row > cells[max].row) + return; + + while (min <= max) { + var mid = Math.floor((min + max) / 2); + var cell = cells[mid]; + if (cell.row > row) { + max = mid - 1; + } else if (cell.row < row) { + min = mid + 1; + } else { + return cell; + } + } + return cell; } /** From 063e683953a517e9e84f114ac84c6d0584b6c6bd Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Thu, 2 Oct 2025 16:05:48 +0400 Subject: [PATCH 1289/1293] add internal gutter cursor marker feature for cloud-editor themes (#5873) --- src/layer/gutter.js | 29 +++++++++++++++++++++++++++++ src/theme/cloud_editor-css.js | 9 ++------- src/theme/cloud_editor.js | 2 ++ src/theme/cloud_editor_dark-css.js | 9 ++------- src/theme/cloud_editor_dark.js | 2 ++ src/virtual_renderer.js | 9 +++++++++ 6 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/layer/gutter.js b/src/layer/gutter.js index 7f41e375e1e..a4ff890b224 100644 --- a/src/layer/gutter.js +++ b/src/layer/gutter.js @@ -25,6 +25,7 @@ class Gutter{ * @param {HTMLElement} parentEl */ constructor(parentEl) { + this.$showCursorMarker = null; this.element = dom.createElement("div"); this.element.className = "ace_layer ace_gutter-layer"; parentEl.appendChild(this.element); @@ -182,6 +183,9 @@ class Gutter{ this._signal("afterRender"); this.$updateGutterWidth(config); + + if (this.$showCursorMarker) + this.$updateCursorMarker(); } /** @@ -224,6 +228,9 @@ class Gutter{ } updateLineHighlight() { + if (this.$showCursorMarker) + this.$updateCursorMarker(); + if (!this.$highlightGutterLine) return; var row = this.session.selection.cursor.row; @@ -252,6 +259,28 @@ class Gutter{ } } + $updateCursorMarker() { + if (!this.session) + return; + var session = this.session; + if (!this.$highlightElement) { + this.$highlightElement = dom.createElement("div"); + this.$highlightElement.className = "ace_gutter-cursor"; + this.element.appendChild(this.$highlightElement); + } + var pos = session.selection.cursor; + var config = this.config; + var lines = this.$lines; + + var screenTop = config.firstRowScreen * config.lineHeight; + var screenPage = Math.floor(screenTop / lines.canvasHeight); + var lineTop = session.documentToScreenRow(pos) * config.lineHeight; + var top = lineTop - (screenPage * lines.canvasHeight); + + dom.setStyle(this.$highlightElement.style, "height", config.lineHeight + "px"); + dom.setStyle(this.$highlightElement.style, "top", top + "px"); + } + /** * @param {LayerConfig} config */ diff --git a/src/theme/cloud_editor-css.js b/src/theme/cloud_editor-css.js index d93e1d9d6c2..a6cc1eb93cc 100644 --- a/src/theme/cloud_editor-css.js +++ b/src/theme/cloud_editor-css.js @@ -46,21 +46,16 @@ module.exports = ` border: 1px solid #697077; } -.ace-cloud_editor .ace_gutter-active-line::before, +.ace-cloud_editor .ace_gutter-cursor, .ace-cloud_editor .ace_marker-layer .ace_active-line { box-sizing: border-box; border-top: 1px solid #9191ac; border-bottom: 1px solid #9191ac; } -.ace-cloud_editor .ace_gutter-active-line::before { - content: ""; +.ace-cloud_editor .ace_gutter-cursor { position: absolute; - height: 100%; width: 100%; - left: 0; - z-index: 1; - pointer-events: none; } .ace-cloud_editor .ace_marker-layer .ace_selected-word { diff --git a/src/theme/cloud_editor.js b/src/theme/cloud_editor.js index 23a5eb5a835..ee8c1beeb09 100644 --- a/src/theme/cloud_editor.js +++ b/src/theme/cloud_editor.js @@ -1,6 +1,8 @@ exports.isDark = false; exports.cssClass = "ace-cloud_editor"; exports.cssText = require("./cloud_editor-css"); +/**@internal */ +exports.$showGutterCursorMarker = true; var dom = require("../lib/dom"); dom.importCssString(exports.cssText, exports.cssClass, false); diff --git a/src/theme/cloud_editor_dark-css.js b/src/theme/cloud_editor_dark-css.js index 9ff17345bfe..3ac9ddd6930 100644 --- a/src/theme/cloud_editor_dark-css.js +++ b/src/theme/cloud_editor_dark-css.js @@ -46,21 +46,16 @@ module.exports = ` border: 1px solid #e8e8e8; } -.ace-cloud_editor_dark .ace_gutter-active-line::before, +.ace-cloud_editor_dark .ace_gutter-cursor, .ace-cloud_editor_dark .ace_marker-layer .ace_active-line { box-sizing: border-box; border-top: 1px solid #75777a; border-bottom: 1px solid #75777a; } -.ace-cloud_editor_dark .ace_gutter-active-line::before { - content: ""; +.ace-cloud_editor_dark .ace_gutter-cursor { position: absolute; - height: 100%; width: 100%; - left: 0; - z-index: 1; - pointer-events: none; } .ace-cloud_editor_dark .ace_marker-layer .ace_selected-word { diff --git a/src/theme/cloud_editor_dark.js b/src/theme/cloud_editor_dark.js index 9aa93b85cd3..ae45daf3b88 100644 --- a/src/theme/cloud_editor_dark.js +++ b/src/theme/cloud_editor_dark.js @@ -1,6 +1,8 @@ exports.isDark = true; exports.cssClass = "ace-cloud_editor_dark"; exports.cssText = require("./cloud_editor_dark-css"); +/**@internal */ +exports.$showGutterCursorMarker = true; var dom = require("../lib/dom"); dom.importCssString(exports.cssText, exports.cssClass, false); diff --git a/src/virtual_renderer.js b/src/virtual_renderer.js index 4184510ae74..2aea1ec6805 100644 --- a/src/virtual_renderer.js +++ b/src/virtual_renderer.js @@ -2013,6 +2013,15 @@ class VirtualRenderer { if (_self.$padding && padding != _self.$padding) _self.setPadding(padding); + if (_self.$gutterLayer) { + var showGutterCursor = module["$showGutterCursorMarker"]; + if (showGutterCursor && !_self.$gutterLayer.$showCursorMarker) { + _self.$gutterLayer.$showCursorMarker = "theme"; + } else if (!showGutterCursor && _self.$gutterLayer.$showCursorMarker == "theme") { + _self.$gutterLayer.$showCursorMarker = null; + } + } + // this is kept only for backwards compatibility _self.$theme = module.cssClass; From c5b2f82ff2ab18ffc4f0be81a73c2510288d0a14 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Tue, 7 Oct 2025 17:18:36 +0400 Subject: [PATCH 1290/1293] allow changing diff view wrap option from editor too (#5875) --- src/ext/diff/diff_test.js | 30 ++++++++++++++++++++++++++++++ src/ext/diff/inline_diff_view.js | 15 +++++++++------ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/ext/diff/diff_test.js b/src/ext/diff/diff_test.js index 760832588be..db6d3d1c757 100644 --- a/src/ext/diff/diff_test.js +++ b/src/ext/diff/diff_test.js @@ -438,6 +438,36 @@ module.exports = { assert.ok(!diffView.otherEditor.destroyed); diffView.detach(); assert.ok(diffView.otherEditor.destroyed); + }, + "test: wrap stays in sync": function() { + editorA.setOption("wrap", "off"); + diffView = new InlineDiffView({ editorA, inline: "a" }); + + assert.equal(diffView.editorB.getOption("wrap"), "off"); + assert.equal(diffView.editorA.getOption("wrap"), "off"); + + editorA.setOption("wrap", "free"); + assert.equal(diffView.editorB.getOption("wrap"), "free"); + assert.equal(diffView.editorA.getOption("wrap"), "free"); + + diffView.detach(); + + + editorB.setOption("wrap", 40); + diffView = new InlineDiffView({ editorB, inline: "b" }); + + assert.equal(diffView.editorB.getOption("wrap"), 40); + assert.equal(diffView.editorA.getOption("wrap"), 40); + + editorB.setOption("wrap", "free"); + assert.equal(diffView.editorB.getOption("wrap"), "free"); + assert.equal(diffView.editorA.getOption("wrap"), "free"); + + editorB.setOption("wrap", 50); + assert.equal(diffView.editorB.getOption("wrap"), 50); + assert.equal(diffView.editorA.getOption("wrap"), 50); + + diffView.detach(); } }; diff --git a/src/ext/diff/inline_diff_view.js b/src/ext/diff/inline_diff_view.js index 4704ab15419..94383bfedc7 100644 --- a/src/ext/diff/inline_diff_view.js +++ b/src/ext/diff/inline_diff_view.js @@ -278,16 +278,18 @@ class InlineDiffView extends BaseDiffView { diffView.sessionB["_emit"]("changeFold", {data: {start: {row: 0}}}); } - onChangeWrapLimit() { - this.sessionB.adjustWrapLimit(this.sessionA.$wrapLimit); + onChangeWrapLimit(e, session) { + this.otherSession.setOption("wrap", session.getOption("wrap")); + this.otherSession.adjustWrapLimit(session.$wrapLimit); this.scheduleRealign(); } $attachSessionsEventHandlers() { this.$attachSessionEventHandlers(this.editorA, this.markerA); this.$attachSessionEventHandlers(this.editorB, this.markerB); - this.sessionA.on("changeWrapLimit", this.onChangeWrapLimit); - this.sessionA.on("changeWrapMode", this.onChangeWrapLimit); + var session = this.activeEditor.session; + session.on("changeWrapLimit", this.onChangeWrapLimit); + session.on("changeWrapMode", this.onChangeWrapLimit); } $attachSessionEventHandlers(editor, marker) { @@ -301,8 +303,9 @@ class InlineDiffView extends BaseDiffView { this.$detachSessionHandlers(this.editorA, this.markerA); this.$detachSessionHandlers(this.editorB, this.markerB); this.otherSession.bgTokenizer.lines.fill(undefined); - this.sessionA.off("changeWrapLimit", this.onChangeWrapLimit); - this.sessionA.off("changeWrapMode", this.onChangeWrapLimit); + var session = this.activeEditor.session; + session.off("changeWrapLimit", this.onChangeWrapLimit); + session.off("changeWrapMode", this.onChangeWrapLimit); } $detachSessionHandlers(editor, marker) { From 0e72f76d26ec2c496d67767e537bd3f014043c02 Mon Sep 17 00:00:00 2001 From: Harutyun Amirjanyan Date: Thu, 9 Oct 2025 19:44:05 +0400 Subject: [PATCH 1291/1293] fixes for Line Wrapping (#5879) Co-authored-by: Harutyun Amirjanyan --- src/ext/diff/inline_diff_view.js | 3 +++ src/layer/gutter.js | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ext/diff/inline_diff_view.js b/src/ext/diff/inline_diff_view.js index 94383bfedc7..9548fc9a903 100644 --- a/src/ext/diff/inline_diff_view.js +++ b/src/ext/diff/inline_diff_view.js @@ -282,6 +282,9 @@ class InlineDiffView extends BaseDiffView { this.otherSession.setOption("wrap", session.getOption("wrap")); this.otherSession.adjustWrapLimit(session.$wrapLimit); this.scheduleRealign(); + // todo, this is needed because editor.onChangeWrapMode + // calls resize(true) instead of waiting for the renderloop + this.activeEditor.renderer.updateFull(); } $attachSessionsEventHandlers() { diff --git a/src/layer/gutter.js b/src/layer/gutter.js index a4ff890b224..b44f76ee82d 100644 --- a/src/layer/gutter.js +++ b/src/layer/gutter.js @@ -184,7 +184,7 @@ class Gutter{ this._signal("afterRender"); this.$updateGutterWidth(config); - if (this.$showCursorMarker) + if (this.$showCursorMarker && this.$highlightGutterLine) this.$updateCursorMarker(); } @@ -266,6 +266,7 @@ class Gutter{ if (!this.$highlightElement) { this.$highlightElement = dom.createElement("div"); this.$highlightElement.className = "ace_gutter-cursor"; + this.$highlightElement.style.pointerEvents = "none"; this.element.appendChild(this.$highlightElement); } var pos = session.selection.cursor; @@ -605,6 +606,10 @@ class Gutter{ */ setHighlightGutterLine(highlightGutterLine) { this.$highlightGutterLine = highlightGutterLine; + if (!highlightGutterLine && this.$highlightElement) { + this.$highlightElement.remove(); + this.$highlightElement = null; + } } /** From d1a93fcf4dce3f9a7987b711d405ffd4b55743e6 Mon Sep 17 00:00:00 2001 From: Azat Alimov <32402726+mkslanc@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:19:52 +0400 Subject: [PATCH 1292/1293] Gutter Hover tooltip (#5872) * WIP: gutter hover tooltip based on hover tooltip * Refactor gutter tooltip to reuse hover tooltip functionality and align position logic. * Adjust gutter tooltip offsets and ensure absolute positioning. * refactor gutter tooltip handling: unify hide method, remove unused code, and improve positioning logic. * remove tooltipFollowsMouse option in default gutter handler (for now) * remove `tooltipFollowsMouse` option and refactor gutter tooltip logic to improve handling and positioning. * fix tests * refactor gutter tooltip constructor and positioning logic for improved alignment and consistency. * fix tooltip positioning logic * refactor gutter tooltip positioning logic to enhance alignment, reuse anchor metrics, and improve code clarity. * fix more tests * refactor gutter tooltip: improve type definitions, remove unused constants, replace `const` with `var` for consistency, and adjust destroy logic. * refactor tooltip logic: improve $setPosition method, update handling of markers, and enhance code readability. * refactor tooltip references: rename `tooltip` to `$tooltip`, update type definitions, and adjust related logic for consistency and clarity. * cleanup * Use position fixed to prevent tooltip being cropped to parent node reverts https://github.com/ajaxorg/ace/pull/5853 --------- Co-authored-by: nightwing --- ace-internal.d.ts | 3 +- ace.d.ts | 1 - src/autocomplete/popup.js | 15 +- src/css/editor-css.js | 2 +- src/editor.js | 1 - src/ext/options.js | 4 - src/keyboard/gutter_handler.js | 15 +- src/keyboard/gutter_handler_test.js | 106 +++++----- src/lib/dom.js | 37 ++++ src/mouse/default_gutter_handler.js | 247 +++++++++-------------- src/mouse/default_gutter_handler_test.js | 101 ++++----- src/mouse/mouse_handler.js | 2 +- src/test/mockdom.js | 64 ++++-- src/tooltip.js | 109 +++++++--- types/ace-ext.d.ts | 4 - types/ace-modules.d.ts | 31 +-- 16 files changed, 390 insertions(+), 352 deletions(-) diff --git a/ace-internal.d.ts b/ace-internal.d.ts index c0417ec25cd..926b3b4a959 100644 --- a/ace-internal.d.ts +++ b/ace-internal.d.ts @@ -380,7 +380,6 @@ export namespace Ace { dragDelay: number; dragEnabled: boolean; focusTimeout: number; - tooltipFollowsMouse: boolean; } interface EditorOptions extends EditSessionOptions, @@ -1629,7 +1628,6 @@ declare module "./src/mouse/mouse_event" { declare module "./src/mouse/mouse_handler" { export interface MouseHandler { - $tooltipFollowsMouse?: boolean, cancelDrag?: boolean //from DefaultHandlers $clickSelection?: Ace.Range, @@ -1638,6 +1636,7 @@ declare module "./src/mouse/mouse_handler" { select?: () => void $lastScroll?: { t: number, vx: number, vy: number, allowed: number } selectEnd?: () => void + $tooltip?: Ace.GutterTooltip } } diff --git a/ace.d.ts b/ace.d.ts index 04dadcec71a..8f5e42c3a8f 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -281,7 +281,6 @@ declare module "ace-code" { dragDelay: number; dragEnabled: boolean; focusTimeout: number; - tooltipFollowsMouse: boolean; } interface EditorOptions extends EditSessionOptions, MouseHandlerOptions, VirtualRendererOptions { selectionStyle: "fullLine" | "screenLine" | "text" | "line"; diff --git a/src/autocomplete/popup.js b/src/autocomplete/popup.js index bb6ec7fe5f0..b5e33ac7538 100644 --- a/src/autocomplete/popup.js +++ b/src/autocomplete/popup.js @@ -370,27 +370,24 @@ class AcePopup { renderer.$maxPixelHeight = null; } - el.style.display = ""; - var rootRect = el.offsetParent && el.offsetParent.getBoundingClientRect(); - if (anchor === "top") { el.style.top = ""; - el.style.bottom = (screenHeight + scrollBarSize - dims.bottom) - - (rootRect ? screenHeight + scrollBarSize - rootRect.bottom : 0)+ "px"; + el.style.bottom = (screenHeight + scrollBarSize - dims.bottom) + "px"; popup.isTopdown = false; } else { - el.style.top = (dims.top - (rootRect ? rootRect.top : 0)) + "px"; + el.style.top = dims.top + "px"; el.style.bottom = ""; popup.isTopdown = true; } + el.style.display = ""; var left = pos.left; if (left + el.offsetWidth > screenWidth) left = screenWidth - el.offsetWidth; - el.style.left = (left - (rootRect ? rootRect.left : 0)) + "px"; + el.style.left = left + "px"; el.style.right = ""; if (!popup.isOpen) { @@ -401,6 +398,8 @@ class AcePopup { popup.anchorPos = pos; popup.anchor = anchor; + + dom.$fixPositionBug(el); return true; }; @@ -472,7 +471,7 @@ dom.importCssString(` width: 300px; z-index: 200000; border: 1px lightgray solid; - position: absolute; + position: fixed; box-shadow: 2px 3px 5px rgba(0,0,0,.2); line-height: 1.4; background: #fefefe; diff --git a/src/css/editor-css.js b/src/css/editor-css.js index 48b62ee2743..cf7768f4a7b 100644 --- a/src/css/editor-css.js +++ b/src/css/editor-css.js @@ -460,7 +460,7 @@ module.exports = ` box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); color: black; padding: 3px 4px; - position: absolute; + position: fixed; z-index: 999999; box-sizing: border-box; cursor: default; diff --git a/src/editor.js b/src/editor.js index 528f440ec36..3b5f5445f19 100644 --- a/src/editor.js +++ b/src/editor.js @@ -3121,7 +3121,6 @@ config.defineOptions(Editor.prototype, "editor", { dragDelay: "$mouseHandler", dragEnabled: "$mouseHandler", focusTimeout: "$mouseHandler", - tooltipFollowsMouse: "$mouseHandler", firstLineNumber: "session", overwrite: "session", diff --git a/src/ext/options.js b/src/ext/options.js index 6457003f45d..47a1685e49c 100644 --- a/src/ext/options.js +++ b/src/ext/options.js @@ -231,10 +231,6 @@ var optionGroups = { }, "Keyboard Accessibility Mode": { path: "enableKeyboardAccessibility" - }, - "Gutter tooltip follows mouse": { - path: "tooltipFollowsMouse", - defaultValue: true } } }; diff --git a/src/keyboard/gutter_handler.js b/src/keyboard/gutter_handler.js index d8f99dd07b6..e2726e01b9a 100644 --- a/src/keyboard/gutter_handler.js +++ b/src/keyboard/gutter_handler.js @@ -1,7 +1,6 @@ "use strict"; var keys = require('../lib/keys'); -var GutterTooltip = require("../mouse/default_gutter_handler").GutterTooltip; class GutterKeyboardHandler { constructor(editor) { @@ -13,7 +12,7 @@ class GutterKeyboardHandler { this.activeRowIndex = null; this.activeLane = null; - this.annotationTooltip = new GutterTooltip(this.editor); + this.annotationTooltip = this.editor.$mouseHandler.$tooltip; } addListener() { @@ -34,7 +33,7 @@ class GutterKeyboardHandler { e.preventDefault(); if (e.keyCode === keys["escape"]) - this.annotationTooltip.hideTooltip(); + this.annotationTooltip.hide(); return; } @@ -186,12 +185,8 @@ class GutterKeyboardHandler { return; case "annotation": - var gutterElement = this.lines.cells[this.activeRowIndex].element.childNodes[2]; - var rect = gutterElement.getBoundingClientRect(); - var style = this.annotationTooltip.getElement().style; - style.left = rect.right + "px"; - style.top = rect.bottom + "px"; - this.annotationTooltip.showTooltip(this.$rowIndexToRow(this.activeRowIndex)); + this.annotationTooltip.showTooltip(this.$rowIndexToRow(this.activeRowIndex)); + this.annotationTooltip.$fromKeyboard = true; break; } return; @@ -213,7 +208,7 @@ class GutterKeyboardHandler { } if (this.annotationTooltip.isOpen) - this.annotationTooltip.hideTooltip(); + this.annotationTooltip.hide(); return; } diff --git a/src/keyboard/gutter_handler_test.js b/src/keyboard/gutter_handler_test.js index c59d46738f5..3c641fe07ea 100644 --- a/src/keyboard/gutter_handler_test.js +++ b/src/keyboard/gutter_handler_test.js @@ -3,23 +3,24 @@ if (typeof process !== "undefined") { require("../test/mockdom"); } -var keys = require('../lib/keys'); - "use strict"; - + require("../multi_select"); require("../theme/textmate"); +var user = require("../test/user"); var Editor = require("../editor").Editor; var Mode = require("../mode/java").Mode; var VirtualRenderer = require("../virtual_renderer").VirtualRenderer; var assert = require("../test/assertions"); -function emit(keyCode) { - var data = {bubbles: true, keyCode}; - var event = new KeyboardEvent("keydown", data); - - var el = document.activeElement; - el.dispatchEvent(event); +function findVisibleTooltip() { + const tooltips = document.body.querySelectorAll(".ace_gutter-tooltip"); + for (let i = 0; i < tooltips.length; i++) { + if (window.getComputedStyle(tooltips[i]).display === "block") { + return tooltips[i]; + } + } + return null; } module.exports = { @@ -43,20 +44,20 @@ module.exports = { editor.renderer.$loop._flush(); var lines = editor.renderer.$gutterLayer.$lines; - var toggler = lines.cells[0].element.children[1]; + var toggler = lines.cells[0].element.querySelector(".ace_fold-widget"); // Set focus to the gutter div. editor.renderer.$gutter.focus(); assert.equal(document.activeElement, editor.renderer.$gutter); // Focus on the fold widget. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { assert.equal(document.activeElement, lines.cells[0].element.childNodes[1]); // Click the fold widget. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { // Check that code is folded. @@ -65,7 +66,7 @@ module.exports = { assert.equal(lines.cells[1].element.textContent, "52"); // After escape focus should be back to the gutter. - emit(keys["escape"]); + user.type("Escape"); assert.equal(document.activeElement, editor.renderer.$gutter); done(); @@ -90,13 +91,13 @@ module.exports = { assert.equal(lines.cells[2].element.textContent, "3"); // Focus on the fold widgets. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { assert.equal(document.activeElement, lines.cells[1].element.childNodes[1]); // Click the first fold widget. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { // Check that code is folded. @@ -104,19 +105,19 @@ module.exports = { assert.equal(lines.cells[2].element.textContent, "8"); // Move to the next fold widget. - emit(keys["down"]); + user.type("Down"); assert.equal(document.activeElement, lines.cells[3].element.childNodes[1]); assert.equal(lines.cells[4].element.textContent, "10"); // Click the fold widget. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { // Check that code is folded. assert.equal(lines.cells[4].element.textContent, "15"); // Move back up one fold widget. - emit(keys["up"]); + user.type("Up"); assert.equal(document.activeElement, lines.cells[1].element.childNodes[1]); done(); @@ -141,26 +142,26 @@ module.exports = { assert.equal(document.activeElement, editor.renderer.$gutter); // Focus on the annotation. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { - emit(keys["left"]); + user.type("Left"); assert.equal(document.activeElement, lines.cells[0].element.childNodes[2]); // Click annotation. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { // Check annotation is rendered. editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/error test/.test(tooltip.textContent)); // Press escape to dismiss the tooltip. - emit(keys["escape"]); + user.type("Escape"); // After escape again focus should be back to the gutter. - emit(keys["escape"]); + user.type("Escape"); assert.equal(document.activeElement, editor.renderer.$gutter); done(); @@ -186,46 +187,46 @@ module.exports = { assert.equal(document.activeElement, editor.renderer.$gutter); // Focus on the annotation. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { - emit(keys["left"]); + user.type("Left"); assert.equal(document.activeElement, lines.cells[1].element.childNodes[2]); // Click annotation. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { // Check annotation is rendered. editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/error test/.test(tooltip.textContent)); // Press escape to dismiss the tooltip. - emit(keys["escape"]); + user.type("Escape"); // Press down to move to next annotation. - emit(keys["down"]); + user.type("Down"); assert.equal(document.activeElement, lines.cells[2].element.childNodes[2]); // Click annotation. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { // Check annotation is rendered. editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/warning test/.test(tooltip.textContent)); // Press escape to dismiss the tooltip. - emit(keys["escape"]); + user.type("Escape"); // Move back up one annotation. - emit(keys["up"]); + user.type("Up"); assert.equal(document.activeElement, lines.cells[1].element.childNodes[2]); // Move back to the folds, focus should be on the fold on line 1. - emit(keys["right"]); + user.type("Right"); assert.equal(document.activeElement, lines.cells[0].element.childNodes[1]); done(); @@ -249,14 +250,15 @@ module.exports = { assert.equal(document.activeElement, editor.renderer.$gutter); // Focus on gutter interaction. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { // Focus should be on the annotation directly. assert.equal(document.activeElement, lines.cells[1].element.childNodes[2]); done(); }, 20); - },"test: aria attributes mode with getFoldWidgetRange" : function() { + }, + "test: aria attributes mode with getFoldWidgetRange" : function() { var editor = this.editor; var value = "x {" + "\n".repeat(5) + "}"; editor.session.setMode(new Mode()); @@ -265,7 +267,7 @@ module.exports = { editor.renderer.$loop._flush(); var lines = editor.renderer.$gutterLayer.$lines; - var toggler = lines.cells[0].element.children[1]; + var toggler = lines.cells[0].element.querySelector(".ace_fold-widget"); assert.equal(toggler.getAttribute("aria-label"), "Toggle code folding, rows 1 through 6"); assert.equal(toggler.getAttribute("aria-expanded"), "true"); @@ -291,7 +293,7 @@ module.exports = { editor.renderer.$loop._flush(); var lines = editor.renderer.$gutterLayer.$lines; - var toggler = lines.cells[0].element.children[1]; + var toggler = lines.cells[0].element.querySelector(".ace_fold-widget"); assert.equal(toggler.getAttribute("aria-label"), "Toggle code folding, row 1"); assert.equal(toggler.getAttribute("aria-expanded"), "true"); @@ -323,10 +325,10 @@ module.exports = { assert.equal(document.activeElement, editor.renderer.$gutter); // Focus on the annotation. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { - emit(keys["left"]); + user.type("Left"); assert.equal(document.activeElement, lines.cells[0].element.childNodes[2]); setTimeout(function() { @@ -364,30 +366,30 @@ module.exports = { }); // Focus on the annotation. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { - emit(keys["left"]); + user.type("Left"); assert.equal(document.activeElement, lines.cells[1].element.childNodes[2]); // Click annotation. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { // Check annotation is rendered. editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/error test/.test(tooltip.textContent)); // Press escape to dismiss the tooltip. - emit(keys["escape"]); + user.type("Escape"); // Switch lane move to custom widget - emit(keys["right"]); + user.type("Right"); assert.equal(document.activeElement, lines.cells[1].element.childNodes[3]); // Move back to the annotations, focus should be on the annotation on line 1. - emit(keys["left"]); + user.type("Left"); assert.equal(document.activeElement, lines.cells[1].element.childNodes[2]); done(); }, 20); @@ -426,20 +428,20 @@ module.exports = { }); // Focus on the fold widgets. - emit(keys["enter"]); + user.type("Enter"); setTimeout(function() { assert.equal(document.activeElement, lines.cells[1].element.childNodes[1]); // Move down to the custom widget. - emit(keys["down"]); + user.type("Down"); assert.equal(document.activeElement, lines.cells[2].element.childNodes[3]); - emit(keys["enter"]); + user.type("Enter"); assert.equal(firstCallbackCalledCount,1); // Move up to the previous fold widget. - emit(keys["up"]); + user.type("Up"); assert.equal(document.activeElement, lines.cells[1].element.childNodes[1]); done(); }, 20); diff --git a/src/lib/dom.js b/src/lib/dom.js index a83b0a6f3bf..79a72c52e77 100644 --- a/src/lib/dom.js +++ b/src/lib/dom.js @@ -290,6 +290,43 @@ exports.importCssStylsheet = function(uri, doc) { exports.buildDom(["link", {rel: "stylesheet", href: uri}], exports.getDocumentHead(doc)); }; +/** + * Due to bug in html specification fixed position elements are placed relative to + * ancestor with transform instead of screen, so we attempt to detect and compensate for that + * @param {HTMLElement} el with position: fixed + */ +exports.$fixPositionBug = function(el) { + var rect = el.getBoundingClientRect(); + if (el.style.left) { + var target = parseFloat(el.style.left); + var result = +rect.left; + if (Math.abs(target - result) > 1) { + el.style.left = 2 * target - result + "px"; + } + } + if (el.style.right) { + var target = parseFloat(el.style.right); + var result = window.innerWidth - rect.right; + if (Math.abs(target - result) > 1) { + el.style.right = 2 * target - result + "px"; + } + } + if (el.style.top) { + var target = parseFloat(el.style.top); + var result = +rect.top; + if (Math.abs(target - result) > 1) { + el.style.top = 2 * target - result + "px"; + } + } + if (el.style.bottom) { + var target = parseFloat(el.style.bottom); + var result = window.innerHeight - rect.bottom; + if (Math.abs(target - result) > 1) { + el.style.bottom = 2 * target - result + "px"; + } + } +}; + /** * @param {Document} [doc] * @returns {number} diff --git a/src/mouse/default_gutter_handler.js b/src/mouse/default_gutter_handler.js index 0c1735d6d97..eb992bde974 100644 --- a/src/mouse/default_gutter_handler.js +++ b/src/mouse/default_gutter_handler.js @@ -3,15 +3,10 @@ * @typedef {import("./mouse_handler").MouseHandler} MouseHandler */ var dom = require("../lib/dom"); -var event = require("../lib/event"); -var Tooltip = require("../tooltip").Tooltip; +var MouseEvent = require("./mouse_event").MouseEvent; +var HoverTooltip = require("../tooltip").HoverTooltip; var nls = require("../config").nls; - -const GUTTER_TOOLTIP_LEFT_OFFSET = 5; -const GUTTER_TOOLTIP_TOP_OFFSET = 3; -exports.GUTTER_TOOLTIP_LEFT_OFFSET = GUTTER_TOOLTIP_LEFT_OFFSET; -exports.GUTTER_TOOLTIP_TOP_OFFSET = GUTTER_TOOLTIP_TOP_OFFSET; - +var Range = require("../range").Range; /** * @param {MouseHandler} mouseHandler @@ -20,7 +15,13 @@ exports.GUTTER_TOOLTIP_TOP_OFFSET = GUTTER_TOOLTIP_TOP_OFFSET; function GutterHandler(mouseHandler) { var editor = mouseHandler.editor; var gutter = editor.renderer.$gutterLayer; - var tooltip = new GutterTooltip(editor, true); + mouseHandler.$tooltip = new GutterTooltip(editor); + mouseHandler.$tooltip.addToEditor(editor); + + mouseHandler.$tooltip.setDataProvider(function(e, editor) { + var row = e.getDocumentPosition().row; + mouseHandler.$tooltip.showTooltip(row); + }); mouseHandler.editor.setDefaultHandler("guttermousedown", function(e) { if (!editor.isFocused() || e.getButton() != 0) @@ -46,101 +47,16 @@ function GutterHandler(mouseHandler) { mouseHandler.captureMouse(e); return e.preventDefault(); }); - - var tooltipTimeout, mouseEvent; - - function showTooltip() { - var row = mouseEvent.getDocumentPosition().row; - - var maxRow = editor.session.getLength(); - if (row == maxRow) { - var screenRow = editor.renderer.pixelToScreenCoordinates(0, mouseEvent.y).row; - var pos = mouseEvent.$pos; - if (screenRow > editor.session.documentToScreenRow(pos.row, pos.column)) - return hideTooltip(); - } - - tooltip.showTooltip(row); - - if (!tooltip.isOpen) - return; - - editor.on("mousewheel", hideTooltip); - editor.on("changeSession", hideTooltip); - window.addEventListener("keydown", hideTooltip, true); - - if (mouseHandler.$tooltipFollowsMouse) { - moveTooltip(mouseEvent); - } else { - var gutterRow = mouseEvent.getGutterRow(); - var gutterCell = gutter.$lines.get(gutterRow); - if (gutterCell) { - var gutterElement = gutterCell.element.querySelector(".ace_gutter_annotation"); - var rect = gutterElement.getBoundingClientRect(); - var style = tooltip.getElement().style; - style.left = (rect.right - GUTTER_TOOLTIP_LEFT_OFFSET) + "px"; - style.top = (rect.bottom - GUTTER_TOOLTIP_TOP_OFFSET) + "px"; - } else { - moveTooltip(mouseEvent); - } - } - } - - function hideTooltip(e) { - // dont close tooltip in case the user wants to copy text from it (Ctrl/Meta + C) - if (e && e.type === "keydown" && (e.ctrlKey || e.metaKey)) - return; - // in case mouse moved but is still on the tooltip, dont close it - if (e && e.type === "mouseout" && (!e.relatedTarget || tooltip.getElement().contains(e.relatedTarget))) - return; - if (tooltipTimeout) - tooltipTimeout = clearTimeout(tooltipTimeout); - if (tooltip.isOpen) { - tooltip.hideTooltip(); - editor.off("mousewheel", hideTooltip); - editor.off("changeSession", hideTooltip); - window.removeEventListener("keydown", hideTooltip, true); - } - } - - function moveTooltip(e) { - tooltip.setPosition(e.x, e.y); - } - - mouseHandler.editor.setDefaultHandler("guttermousemove", function(e) { - var target = e.domEvent.target || e.domEvent.srcElement; - if (dom.hasCssClass(target, "ace_fold-widget") || dom.hasCssClass(target, "ace_custom-widget")) - return hideTooltip(); - - if (tooltip.isOpen && mouseHandler.$tooltipFollowsMouse) - moveTooltip(e); - - mouseEvent = e; - if (tooltipTimeout) - return; - tooltipTimeout = setTimeout(function() { - tooltipTimeout = null; - if (mouseEvent && !mouseHandler.isMousePressed) - showTooltip(); - }, 50); - }); - - event.addListener(editor.renderer.$gutter, "mouseout", function(e) { - mouseEvent = null; - if (!tooltip.isOpen) - return; - - tooltipTimeout = setTimeout(function() { - tooltipTimeout = null; - hideTooltip(e); - }, 50); - }, editor); } exports.GutterHandler = GutterHandler; -class GutterTooltip extends Tooltip { - constructor(editor, isHover = false) { + +class GutterTooltip extends HoverTooltip { + /** + * @param {import("../editor").Editor} editor + */ + constructor(editor) { super(editor.container); this.id = "gt" + (++GutterTooltip.$uid); this.editor = editor; @@ -150,38 +66,45 @@ class GutterTooltip extends Tooltip { el.setAttribute("role", "tooltip"); el.setAttribute("id", this.id); el.style.pointerEvents = "auto"; - if (isHover) { - this.onMouseOut = this.onMouseOut.bind(this); - el.addEventListener("mouseout", this.onMouseOut); - } - } + this.idleTime = 50; - // handler needed to hide tooltip after mouse hovers from tooltip to editor - onMouseOut(e) { - if (!this.isOpen) return; + this.onDomMouseMove = this.onDomMouseMove.bind(this); + this.onDomMouseOut = this.onDomMouseOut.bind(this); - if (!e.relatedTarget || this.getElement().contains(e.relatedTarget)) return; + this.setClassName("ace_gutter-tooltip"); + } + + onDomMouseMove(domEvent) { + var aceEvent = new MouseEvent(domEvent, this.editor); + this.onMouseMove(aceEvent, this.editor); + } + + onDomMouseOut(domEvent) { + var aceEvent = new MouseEvent(domEvent, this.editor); + this.onMouseOut(aceEvent); + } - if (e && e.currentTarget.contains(e.relatedTarget)) return; - this.hideTooltip(); + addToEditor(editor) { + var gutter = editor.renderer.$gutter; + gutter.addEventListener("mousemove", this.onDomMouseMove); + gutter.addEventListener("mouseout", this.onDomMouseOut); + super.addToEditor(editor); } - setPosition(x, y) { - var windowWidth = window.innerWidth || document.documentElement.clientWidth; - var windowHeight = window.innerHeight || document.documentElement.clientHeight; - var width = this.getWidth(); - var height = this.getHeight(); - x += 15; - y += 15; - if (x + width > windowWidth) { - x -= (x + width) - windowWidth; - } - if (y + height > windowHeight) { - y -= 20 + height; + removeFromEditor(editor) { + var gutter = editor.renderer.$gutter; + gutter.removeEventListener("mousemove", this.onDomMouseMove); + gutter.removeEventListener("mouseout", this.onDomMouseOut); + super.removeFromEditor(editor); + } + + destroy() { + if (this.editor) { + this.removeFromEditor(this.editor); } - Tooltip.prototype.setPosition.call(this, x, y); + super.destroy(); } - + static get annotationLabels() { return { error: { @@ -207,6 +130,9 @@ class GutterTooltip extends Tooltip { }; } + /** + * @param {number} row + */ showTooltip(row) { var gutter = this.editor.renderer.$gutterLayer; var annotationsInRow = gutter.$annotations[row]; @@ -227,7 +153,7 @@ class GutterTooltip extends Tooltip { var severityRank = {error: 1, security: 2, warning: 3, info: 4, hint: 5}; var mostSevereAnnotationTypeInFold; - for (let i = row + 1; i <= fold.end.row; i++) { + for (var i = row + 1; i <= fold.end.row; i++) { if (!gutter.$annotations[i]) continue; for (var j = 0; j < gutter.$annotations[i].text.length; j++) { @@ -253,13 +179,13 @@ class GutterTooltip extends Tooltip { } } - if (annotation.displayText.length === 0) return this.hideTooltip(); + if (annotation.displayText.length === 0) return this.hide(); var annotationMessages = {error: [], security: [], warning: [], info: [], hint: []}; var iconClassName = gutter.$useSvgGutterIcons ? "ace_icon_svg" : "ace_icon"; // Construct the contents of the tooltip. - for (let i = 0; i < annotation.displayText.length; i++) { + for (var i = 0; i < annotation.displayText.length; i++) { var lineElement = dom.createElement("span"); var iconElement = dom.createElement("span"); @@ -279,9 +205,7 @@ class GutterTooltip extends Tooltip { annotationMessages[annotation.type[i].replace("_fold", "")].push(lineElement); } - // Clear the current tooltip content - var tooltipElement = this.getElement(); - dom.removeChildren(tooltipElement); + var tooltipElement = dom.createElement("span"); // Update the tooltip content annotationMessages.error.forEach((el) => tooltipElement.appendChild(el)); @@ -292,25 +216,41 @@ class GutterTooltip extends Tooltip { tooltipElement.setAttribute("aria-live", "polite"); - if (!this.isOpen) { - this.setTheme(this.editor.renderer.theme); - this.setClassName("ace_gutter-tooltip"); - } - - const annotationNode = this.$findLinkedAnnotationNode(row); + var annotationNode = this.$findLinkedAnnotationNode(row); if (annotationNode) { annotationNode.setAttribute("aria-describedby", this.id); } - this.show(); + var range = Range.fromPoints({row, column: 0}, {row, column: 0}); + this.showForRange(this.editor, range, tooltipElement); this.visibleTooltipRow = row; this.editor._signal("showGutterTooltip", this); } + $setPosition(editor, _ignoredPosition, _withMarker, range) { + var gutterCell = this.$findCellByRow(range.start.row); + if (!gutterCell) return; + var el = gutterCell && gutterCell.element; + var anchorEl = el && (el.querySelector(".ace_gutter_annotation")); + if (!anchorEl) return; + var r = anchorEl.getBoundingClientRect(); + if (!r) return; + var position = { + pageX: r.right, + pageY: r.top + }; + //we don't need marker for gutter + return super.$setPosition(editor, position, false, range); + } + + $shouldPlaceAbove(labelHeight, anchorTop, spaceBelow) { + return spaceBelow < labelHeight; + } + $findLinkedAnnotationNode(row) { - const cell = this.$findCellByRow(row); + var cell = this.$findCellByRow(row); if (cell) { - const element = cell.element; + var element = cell.element; if (element.childNodes.length > 2) { return element.childNodes[2]; } @@ -321,34 +261,45 @@ class GutterTooltip extends Tooltip { return this.editor.renderer.$gutterLayer.$lines.cells.find((el) => el.row === row); } - hideTooltip() { + hide(e) { if(!this.isOpen){ return; } this.$element.removeAttribute("aria-live"); - this.hide(); if (this.visibleTooltipRow != undefined) { - const annotationNode = this.$findLinkedAnnotationNode(this.visibleTooltipRow); + var annotationNode = this.$findLinkedAnnotationNode(this.visibleTooltipRow); if (annotationNode) { annotationNode.removeAttribute("aria-describedby"); } } - this.visibleTooltipRow = undefined; this.editor._signal("hideGutterTooltip", this); + super.hide(e); } static annotationsToSummaryString(annotations) { - const summary = []; - const annotationTypes = ["error", "security", "warning", "info", "hint"]; - for (const annotationType of annotationTypes) { + var summary = []; + var annotationTypes = ["error", "security", "warning", "info", "hint"]; + for (var annotationType of annotationTypes) { if (!annotations[annotationType].length) continue; - const label = annotations[annotationType].length === 1 ? GutterTooltip.annotationLabels[annotationType].singular : GutterTooltip.annotationLabels[annotationType].plural; + var label = annotations[annotationType].length === 1 ? GutterTooltip.annotationLabels[annotationType].singular : GutterTooltip.annotationLabels[annotationType].plural; summary.push(`${annotations[annotationType].length} ${label}`); } return summary.join(", "); } + + /** + * Check if cursor is outside gutter + * @param e + * @return {boolean} + */ + isOutsideOfText(e) { + var editor = e.editor; + var rect = editor.renderer.$gutter.getBoundingClientRect(); + return !(e.clientX >= rect.left && e.clientX <= rect.right && + e.clientY >= rect.top && e.clientY <= rect.bottom); + } } GutterTooltip.$uid = 0; diff --git a/src/mouse/default_gutter_handler_test.js b/src/mouse/default_gutter_handler_test.js index e3a0b3af6b4..f52dc2078a4 100644 --- a/src/mouse/default_gutter_handler_test.js +++ b/src/mouse/default_gutter_handler_test.js @@ -12,7 +12,7 @@ var Mode = require("../mode/java").Mode; var VirtualRenderer = require("../virtual_renderer").VirtualRenderer; var assert = require("../test/assertions"); var user = require("../test/user"); -const {GUTTER_TOOLTIP_LEFT_OFFSET, GUTTER_TOOLTIP_TOP_OFFSET} = require("./default_gutter_handler"); + var MouseEvent = function(type, opts){ var e = document.createEvent("MouseEvents"); e.initMouseEvent(/click|wheel/.test(type) ? type : "mouse" + type, @@ -26,6 +26,16 @@ var MouseEvent = function(type, opts){ var editor; +function findVisibleTooltip() { + const tooltips = document.body.querySelectorAll(".ace_gutter-tooltip"); + for (let i = 0; i < tooltips.length; i++) { + if (window.getComputedStyle(tooltips[i]).display === "block") { + return tooltips[i]; + } + } + return null; +} + module.exports = { setUp : function(next) { this.editor = new Editor(new VirtualRenderer()); @@ -52,13 +62,15 @@ module.exports = { assert.ok(/ace_error/.test(annotation.className)); var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + annotation.dispatchEvent(new MouseEvent("move", {x: rect.left + rect.width/2, y: rect.top + rect.height/2})); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); + assert.ok(/error test/.test(tooltip.textContent)); + annotation.dispatchEvent(new MouseEvent("move", {x: 0, y: 0})); done(); }, 100); }, @@ -76,12 +88,12 @@ module.exports = { assert.ok(/ace_security/.test(annotation.className)); var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + annotation.dispatchEvent(new MouseEvent("move", {x: rect.left + rect.width/2, y: rect.top + rect.height/2})); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/security finding test/.test(tooltip.textContent)); done(); }, 100); @@ -100,12 +112,12 @@ module.exports = { assert.ok(/ace_warning/.test(annotation.className)); var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + annotation.dispatchEvent(new MouseEvent("move", {x: rect.left + rect.width/2, y: rect.top + rect.height/2})); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/warning test/.test(tooltip.textContent)); done(); }, 100); @@ -124,12 +136,12 @@ module.exports = { assert.ok(/ace_info/.test(annotation.className)); var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + annotation.dispatchEvent(new MouseEvent("move", {x: rect.left + rect.width/2, y: rect.top + rect.height/2})); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/info test/.test(tooltip.textContent)); done(); }, 100); @@ -148,12 +160,12 @@ module.exports = { assert.ok(/ace_hint/.test(annotation.className)); var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + annotation.dispatchEvent(new MouseEvent("move", {x: rect.left + rect.width/2, y: rect.top + rect.height/2})); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/suggestion test/.test(tooltip.textContent)); done(); }, 100); @@ -200,16 +212,16 @@ module.exports = { var annotation = lines.cells[0].element.children[2].firstChild; assert.ok(/ace_error_fold/.test(annotation.className)); - var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + var row = lines.cells[0].row; + editor.$mouseHandler.$tooltip.showTooltip(row); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/error in folded/.test(tooltip.textContent)); done(); - }, 50); + }, 100); }, "test: security show up in fold" : function(done) { var editor = this.editor; @@ -236,13 +248,13 @@ module.exports = { var annotation = lines.cells[0].element.children[2].firstChild; assert.ok(/ace_security_fold/.test(annotation.className)); - var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + var row = lines.cells[0].row; + editor.$mouseHandler.$tooltip.showTooltip(row); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/security finding in folded/.test(tooltip.textContent)); done(); }, 100); @@ -272,13 +284,13 @@ module.exports = { var annotation = lines.cells[0].element.children[2].firstChild; assert.ok(/ace_warning_fold/.test(annotation.className)); - var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + var row = lines.cells[0].row; + editor.$mouseHandler.$tooltip.showTooltip(row); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/warning in folded/.test(tooltip.textContent)); done(); }, 100); @@ -384,34 +396,6 @@ module.exports = { assert.notOk(/ace_security_fold/.test(firstLineGutterElement.className)); assert.ok(/ace_warning_fold/.test(firstLineGutterElement.className)); }, - "test: sets position correctly when tooltipFollowsMouse false" : function(done) { - var editor = this.editor; - var value = ""; - - editor.session.setMode(new Mode()); - editor.setValue(value, -1); - editor.session.setAnnotations([{row: 0, column: 0, text: "error test", type: "error"}]); - editor.setOption("tooltipFollowsMouse", false); - editor.setOption("useSvgGutterIcons", true); - editor.renderer.$loop._flush(); - - var lines = editor.renderer.$gutterLayer.$lines; - var annotation = lines.cells[0].element.childNodes[2].firstChild; - assert.ok(/ace_error/.test(annotation.className)); - - var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); - - // Wait for the tooltip to appear after its timeout. - setTimeout(function() { - editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); - assert.ok(/error test/.test(tooltip.textContent)); - assert.equal(tooltip.style.left, `${rect.right - GUTTER_TOOLTIP_LEFT_OFFSET}px`); - assert.equal(tooltip.style.top, `${rect.bottom - GUTTER_TOOLTIP_TOP_OFFSET}px`); - done(); - }, 100); - }, "test: gutter tooltip should properly display special characters (\" ' & <)" : function(done) { var editor = this.editor; var value = ""; @@ -426,12 +410,12 @@ module.exports = { assert.ok(/ace_error/.test(annotation.className)); var rect = annotation.getBoundingClientRect(); - annotation.dispatchEvent(new MouseEvent("move", {x: rect.left, y: rect.top})); + annotation.dispatchEvent(new MouseEvent("move", {x: rect.left + rect.width/2, y: rect.top + rect.height/2})); // Wait for the tooltip to appear after its timeout. setTimeout(function() { editor.renderer.$loop._flush(); - var tooltip = editor.container.querySelector(".ace_gutter-tooltip"); + var tooltip = findVisibleTooltip(); assert.ok(/special characters " ' & = 0; i--) { + var node = parents[i]; + if (call(node, true)) return; + } + e.eventPhase = 2; + if (call(this, true)) return; + if (call(this, false)) return; + e.eventPhase = 3; + for (var i = 0; i < parents.length; i++) { + var node = parents[i]; + if (call(node, false)) return; + } + + function call(node, capturing) { + e.currentTarget = node; + if (!capturing && node["on" + e.type]) + node["on" + e.type](e); + var id = capturing ? "__c__:" + e.type : e.type; + var events = node._events && node._events[id]; + events && events.slice().forEach(function(listener) { + listener.call(node, e); + }); + if (e.stopped) return true; + if (!capturing && !e.bubbles) return true; + } }; this.contains = function(node) { while (node) { diff --git a/src/tooltip.js b/src/tooltip.js index 6454863bd37..4df4a42a365 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -56,10 +56,8 @@ class Tooltip { * @param {Number} y **/ setPosition(x, y) { - var el = this.getElement(); - var rootRect = el.offsetParent && el.offsetParent.getBoundingClientRect(); - el.style.left = x - (rootRect ? rootRect.left : 0) + "px"; - el.style.top = y - (rootRect ? rootRect.top : 0) + "px"; + this.getElement().style.left = x + "px"; + this.getElement().style.top = y + "px"; } /** @@ -73,8 +71,20 @@ class Tooltip { * @param {import("../ace-internal").Ace.Theme} theme */ setTheme(theme) { - this.$element.className = CLASSNAME + " " + - (theme.isDark? "ace_dark " : "") + (theme.cssClass || ""); + if (this.theme) { + this.theme.isDark && dom.removeCssClass(this.getElement(), "ace_dark"); + this.theme.cssClass && dom.removeCssClass(this.getElement(), this.theme.cssClass); + } + if (theme.isDark) { + dom.addCssClass(this.getElement(), "ace_dark"); + } + if (theme.cssClass) { + dom.addCssClass(this.getElement(), theme.cssClass); + } + this.theme = { + isDark: theme.isDark, + cssClass: theme.cssClass + }; } /** @@ -142,7 +152,7 @@ class PopupManager { * @param {Tooltip} popup */ removePopup(popup) { - const index = this.popups.indexOf(popup); + var index = this.popups.indexOf(popup); if (index !== -1) { this.popups.splice(index, 1); this.updatePopups(); @@ -176,9 +186,9 @@ class PopupManager { * @param {Tooltip} popupB * @return {boolean} */ - doPopupsOverlap (popupA, popupB) { - const rectA = popupA.getElement().getBoundingClientRect(); - const rectB = popupB.getElement().getBoundingClientRect(); + doPopupsOverlap(popupA, popupB) { + var rectA = popupA.getElement().getBoundingClientRect(); + var rectB = popupB.getElement().getBoundingClientRect(); return (rectA.left < rectB.right && rectA.right > rectB.left && rectA.top < rectB.bottom && rectA.bottom > rectB.top); @@ -225,7 +235,11 @@ class HoverTooltip extends Tooltip { addToEditor(editor) { editor.on("mousemove", this.onMouseMove); editor.on("mousedown", this.hide); - editor.renderer.getMouseEventTarget().addEventListener("mouseout", this.onMouseOut, true); + var target = editor.renderer.getMouseEventTarget(); + if (target && typeof target.removeEventListener === "function") { + target.addEventListener("mouseout", this.onMouseOut, true); + } + } /** @@ -234,7 +248,10 @@ class HoverTooltip extends Tooltip { removeFromEditor(editor) { editor.off("mousemove", this.onMouseMove); editor.off("mousedown", this.hide); - editor.renderer.getMouseEventTarget().removeEventListener("mouseout", this.onMouseOut, true); + var target = editor.renderer.getMouseEventTarget(); + if (target && typeof target.removeEventListener === "function") { + target.removeEventListener("mouseout", this.onMouseOut, true); + } if (this.timeout) { clearTimeout(this.timeout); this.timeout = null; @@ -313,7 +330,6 @@ class HoverTooltip extends Tooltip { * @param {MouseEvent} [startingEvent] */ showForRange(editor, range, domNode, startingEvent) { - var MARGIN = 10; if (startingEvent && startingEvent != this.lastEvent) return; if (this.isOpen && document.activeElement == this.getElement()) return; @@ -325,14 +341,12 @@ class HoverTooltip extends Tooltip { } this.isOpen = true; - this.addMarker(range, editor.session); this.range = Range.fromPoints(range.start, range.end); var position = renderer.textToScreenCoordinates(range.start.row, range.start.column); var rect = renderer.scroller.getBoundingClientRect(); // clip position to visible area of the editor - if (position.pageX < rect.left) - position.pageX = rect.left; + if (position.pageX < rect.left) position.pageX = rect.left; var element = this.getElement(); element.innerHTML = ""; @@ -341,23 +355,50 @@ class HoverTooltip extends Tooltip { element.style.maxHeight = ""; element.style.display = "block"; + this.$setPosition(editor, position, true, range); + + dom.$fixPositionBug(element); + } + + /** + * @param {Editor} editor + * @param {{pageX: number;pageY: number;}} position + * @param {boolean} withMarker + * @param {Range} [range] + */ + $setPosition(editor, position, withMarker, range) { + var MARGIN = 10; + + withMarker && this.addMarker(range, editor.session); + + var renderer = editor.renderer; + var element = this.getElement(); + // measure the size of tooltip, without constraints on its height - var labelHeight = element.clientHeight; - var labelWidth = element.clientWidth; - var spaceBelow = window.innerHeight - position.pageY - renderer.lineHeight; + var labelHeight = element.offsetHeight; + var labelWidth = element.offsetWidth; + var anchorTop = position.pageY; + var anchorLeft = position.pageX; + var spaceBelow = window.innerHeight - anchorTop - renderer.lineHeight; // if tooltip fits above the line, or space below the line is smaller, show tooltip above - let isAbove = true; - if (position.pageY - labelHeight < 0 && position.pageY < spaceBelow) { - isAbove = false; - } + var isAbove = this.$shouldPlaceAbove(labelHeight, anchorTop, spaceBelow - MARGIN); - element.style.maxHeight = (isAbove ? position.pageY : spaceBelow) - MARGIN + "px"; - element.style.top = isAbove ? "" : position.pageY + renderer.lineHeight + "px"; - element.style.bottom = isAbove ? window.innerHeight - position.pageY + "px" : ""; + element.style.maxHeight = (isAbove ? anchorTop : spaceBelow) - MARGIN + "px"; + element.style.top = isAbove ? "" : anchorTop + renderer.lineHeight + "px"; + element.style.bottom = isAbove ? window.innerHeight - anchorTop + "px" : ""; // try to align tooltip left with the range, but keep it on screen - element.style.left = Math.min(position.pageX, window.innerWidth - labelWidth - MARGIN) + "px"; + element.style.left = Math.min(anchorLeft, window.innerWidth - labelWidth - MARGIN) + "px"; + } + + /** + * @param {number} labelHeight + * @param {number} anchorTop + * @param {number} spaceBelow + */ + $shouldPlaceAbove(labelHeight, anchorTop, spaceBelow) { + return !(anchorTop - labelHeight < 0 && anchorTop < spaceBelow); } /** @@ -373,15 +414,21 @@ class HoverTooltip extends Tooltip { } hide(e) { - if (!e && document.activeElement == this.getElement()) - return; - if (e && e.target && (e.type != "keydown" || e.ctrlKey || e.metaKey) && this.$element.contains(e.target)) - return; + if (e && this.$fromKeyboard && e.type == "keydown") { + if (e.code == "Escape") { + return; + } + } + + if (!e && document.activeElement == this.getElement()) return; + if (e && e.target && (e.type != "keydown" || e.ctrlKey || e.metaKey) && this.$element.contains( + e.target)) return; this.lastEvent = null; if (this.timeout) clearTimeout(this.timeout); this.timeout = null; this.addMarker(null); if (this.isOpen) { + this.$fromKeyboard = false; this.$removeCloseEvents(); this.getElement().style.display = "none"; this.isOpen = false; diff --git a/types/ace-ext.d.ts b/types/ace-ext.d.ts index e87d48c3a82..55bc6de1be6 100644 --- a/types/ace-ext.d.ts +++ b/types/ace-ext.d.ts @@ -826,10 +826,6 @@ declare module "ace-code/src/ext/options" { "Keyboard Accessibility Mode": { path: string; }; - "Gutter tooltip follows mouse": { - path: string; - defaultValue: boolean; - }; }; } namespace Ace { diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index 4bfc1caa28e..07bd4f4cbda 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -1763,6 +1763,10 @@ declare module "ace-code/src/tooltip" { setPosition(x: number, y: number): void; setClassName(className: string): void; setTheme(theme: import("ace-code").Ace.Theme): void; + theme: { + isDark: boolean; + cssClass: string; + }; show(text?: string, x?: number, y?: number): void; hide(e: any): void; getHeight(): number; @@ -1786,9 +1790,7 @@ declare module "ace-code/src/mouse/default_gutter_handler" { export interface GutterHandler { } export type MouseHandler = import("ace-code/src/mouse/mouse_handler").MouseHandler; - export const GUTTER_TOOLTIP_LEFT_OFFSET: 5; - export const GUTTER_TOOLTIP_TOP_OFFSET: 3; - export class GutterTooltip extends Tooltip { + export class GutterTooltip extends HoverTooltip { static get annotationLabels(): { error: { singular: any; @@ -1812,19 +1814,24 @@ declare module "ace-code/src/mouse/default_gutter_handler" { }; }; static annotationsToSummaryString(annotations: any): string; - constructor(editor: any, isHover?: boolean); + constructor(editor: import("ace-code/src/editor").Editor); id: string; - editor: any; + editor: import("ace-code/src/editor").Editor; visibleTooltipRow: number | undefined; - onMouseOut(e: any): void; - setPosition(x: any, y: any): void; - showTooltip(row: any): void; - hideTooltip(): void; + onDomMouseMove(domEvent: any): void; + onDomMouseOut(domEvent: any): void; + addToEditor(editor: any): void; + removeFromEditor(editor: any): void; + showTooltip(row: number): void; + /** + * Check if cursor is outside gutter + */ + isOutsideOfText(e: any): boolean; } export namespace GutterTooltip { let $uid: number; } - import { Tooltip } from "ace-code/src/tooltip"; + import { HoverTooltip } from "ace-code/src/tooltip"; export interface GutterHandler { } } @@ -1876,6 +1883,7 @@ declare module "ace-code/src/mouse/mouse_handler" { type Range = import("ace-code").Ace.Range; type MouseEvent = import("ace-code").Ace.MouseEvent; type Point = import("ace-code").Ace.Point; + type GutterTooltip = import("ace-code").Ace.GutterTooltip; } export interface MouseHandler { cancelDrag?: boolean; @@ -2087,7 +2095,7 @@ declare module "ace-code/src/keyboard/gutter_handler" { lines: any; activeRowIndex: any; activeLane: string; - annotationTooltip: GutterTooltip; + annotationTooltip: any; addListener(): void; removeListener(): void; lane: any; @@ -2121,7 +2129,6 @@ declare module "ace-code/src/keyboard/gutter_handler" { */ isInFoldLane(): boolean; } - import { GutterTooltip } from "ace-code/src/mouse/default_gutter_handler"; } declare module "ace-code/src/editor" { /** From 82eab6674ff58002fa2879349d8c802fad3d1aad Mon Sep 17 00:00:00 2001 From: maria-raluca-st Date: Fri, 17 Oct 2025 11:24:17 +0200 Subject: [PATCH 1293/1293] release v1.43.4 --- CHANGELOG.md | 7 +++++++ ace.d.ts | 2 +- build | 2 +- package.json | 2 +- src/config.js | 2 +- types/ace-modules.d.ts | 2 +- 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43c00df358f..7b0ad15be9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.43.4](https://github.com/ajaxorg/ace/compare/v1.43.3...v1.43.4) (2025-10-17) + + +### Bug Fixes + +* Update for compliance with typescript 5.9.2 ([#5855](https://github.com/ajaxorg/ace/issues/5855)) ([6e110b0](https://github.com/ajaxorg/ace/commit/6e110b0061b56b72db7478762036a1ba39251102)) + ### [1.43.3](https://github.com/ajaxorg/ace/compare/v1.43.2...v1.43.3) (2025-09-02) diff --git a/ace.d.ts b/ace.d.ts index 8f5e42c3a8f..276d900f33c 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1065,6 +1065,6 @@ declare module "ace-code" { import { Range } from "ace-code/src/range"; import { UndoManager } from "ace-code/src/undomanager"; import { VirtualRenderer as Renderer } from "ace-code/src/virtual_renderer"; - export var version: "1.43.3"; + export var version: "1.43.4"; export { Range, Editor, EditSession, UndoManager, Renderer as VirtualRenderer }; } diff --git a/build b/build index 933d5765d4c..56a46777e92 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 933d5765d4cd9e80a8aa7073df39b80dd04671f7 +Subproject commit 56a46777e92abd648dce1c29069c13a74480f9a5 diff --git a/package.json b/package.json index 740a51c21f4..beb161752b2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.43.3", + "version": "1.43.4", "homepage": "https://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/config.js b/src/config.js index 8c02d2c102f..9f13c446cb8 100644 --- a/src/config.js +++ b/src/config.js @@ -197,6 +197,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.43.3"; +exports.version = "1.43.4"; diff --git a/types/ace-modules.d.ts b/types/ace-modules.d.ts index 07bd4f4cbda..e4df339ce01 100644 --- a/types/ace-modules.d.ts +++ b/types/ace-modules.d.ts @@ -375,7 +375,7 @@ declare module "ace-code/src/config" { string ], onLoad: (module: any) => void) => void; setModuleLoader: (moduleName: any, onLoad: any) => void; - version: "1.43.3"; + version: "1.43.4"; }; export = _exports; }