UNPKG

ts-playground-plugin-vim

Version:

Provides Vim keybindings for TypeScript Playground editor.

1,117 lines (1,115 loc) 292 kB
define(function () { 'use strict'; /** * An adapter to make CodeMirror's vim bindings work with monaco */ // import { TypeOperations } from 'monaco-editor/esm/vs/editor/common/controller/cursorTypeOperations'; var _a = globalThis.monaco, monacoEditor = _a.editor, KeyCode = _a.KeyCode, KeyMod = _a.KeyMod, Range = _a.Range, Position = _a.Position, Selection = _a.Selection, SelectionDirection = _a.SelectionDirection; var VerticalRevealType = { Bottom: 4, }; // for monaco 0.19.x where x < 3 var EditorOptConstants = { readOnly: 65, cursorWidth: 20, fontInfo: 32, }; var _b = window.navigator, userAgent = _b.userAgent, platform = _b.platform; var edge = /Edge\/(\d+)/.exec(userAgent); var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent); var mac = ios || /Mac/.test(platform); var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; function isWordCharBasic(ch) { return /\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); } function Pos(line, column) { if (!(this instanceof Pos)) { return new Pos(line, column); } this.line = line; this.ch = column; } function signal(cm, signal, args) { cm.dispatch(signal, args); } function dummy(key) { return function () { // console.log(key, 'dummy function called with', Array.prototype.slice.call(arguments)); }; } var StringStream = function (string, tabSize) { this.pos = this.start = 0; this.string = string; this.tabSize = tabSize || 8; this.lastColumnPos = this.lastColumnValue = 0; this.lineStart = 0; }; StringStream.prototype = { eol: function () { return this.pos >= this.string.length; }, sol: function () { return this.pos == this.lineStart; }, peek: function () { return this.string.charAt(this.pos) || undefined; }, next: function () { if (this.pos < this.string.length) return this.string.charAt(this.pos++); }, eat: function (match) { var ch = this.string.charAt(this.pos); if (typeof match == "string") var ok = ch == match; else var ok = ch && (match.test ? match.test(ch) : match(ch)); if (ok) { ++this.pos; return ch; } }, eatWhile: function (match) { var start = this.pos; while (this.eat(match)) { } return this.pos > start; }, eatSpace: function () { var start = this.pos; while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; return this.pos > start; }, skipToEnd: function () { this.pos = this.string.length; }, skipTo: function (ch) { var found = this.string.indexOf(ch, this.pos); if (found > -1) { this.pos = found; return true; } }, backUp: function (n) { this.pos -= n; }, column: function () { throw "not implemented"; }, indentation: function () { throw "not implemented"; }, match: function (pattern, consume, caseInsensitive) { if (typeof pattern == "string") { var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; }; var substr = this.string.substr(this.pos, pattern.length); if (cased(substr) == cased(pattern)) { if (consume !== false) this.pos += pattern.length; return true; } } else { var match = this.string.slice(this.pos).match(pattern); if (match && match.index > 0) return null; if (match && consume !== false) this.pos += match[0].length; return match; } }, current: function () { return this.string.slice(this.start, this.pos); }, hideFirstChars: function (n, inner) { this.lineStart += n; try { return inner(); } finally { this.lineStart -= n; } } }; function toCmPos(pos) { return new Pos(pos.lineNumber - 1, pos.column - 1); } function toMonacoPos(pos) { return new Position(pos.line + 1, pos.ch + 1); } var Marker = /** @class */ (function () { function Marker(cm, id, line, ch) { this.cm = cm; this.id = id; this.lineNumber = line + 1; this.column = ch + 1; cm.marks[this.id] = this; } Marker.prototype.clear = function () { delete this.cm.marks[this.id]; }; Marker.prototype.find = function () { return toCmPos(this); }; return Marker; }()); function monacoToCmKey(e, skip) { if (skip === void 0) { skip = false; } var addQuotes = true; var keyName = monaco.KeyCode[e.keyCode]; if (e.key) { keyName = e.key; addQuotes = false; } var key = keyName; var skipOnlyShiftCheck = skip; switch (e.keyCode) { case KeyCode.Shift: case KeyCode.Meta: case KeyCode.Alt: case KeyCode.Ctrl: return key; case KeyCode.Escape: skipOnlyShiftCheck = true; key = 'Esc'; break; } if (keyName.startsWith('KEY_')) { key = keyName[keyName.length - 1].toLowerCase(); } else if (keyName.endsWith('Arrow')) { skipOnlyShiftCheck = true; key = keyName.substr(0, keyName.length - 5); } else if (keyName.startsWith('US_')) { key = e.browserEvent.key; } if (!skipOnlyShiftCheck && !e.altKey && !e.ctrlKey && !e.metaKey) { key = e.key || e.browserEvent.key; } else { if (e.altKey) { key = "Alt-" + key; } if (e.ctrlKey) { key = "Ctrl-" + key; } if (e.metaKey) { key = "Meta-" + key; } if (e.shiftKey) { key = "Shift-" + key; } } if (key.length === 1 && addQuotes) { key = "'" + key + "'"; } return key; } var CMAdapter = /** @class */ (function () { function CMAdapter(editor) { var _this = this; this.editor = editor; this.handleKeyDown = function (e) { // Allow previously registered keydown listeners to handle the event and // prevent this extension from also handling it. if (e.browserEvent.defaultPrevented & e.keyCode !== KeyCode.Escape) { return; } if (!_this.attached) { return; } var key = monacoToCmKey(e); if (_this.replaceMode) { _this.handleReplaceMode(key, e); } if (!key) { return; } if (CMAdapter.keyMap.vim && CMAdapter.keyMap.vim.call) { var cmd = CMAdapter.keyMap.vim.call(key, _this); if (cmd) { e.preventDefault(); e.stopPropagation(); try { cmd(); } catch (err) { console.error(err); } } } }; this.handleCursorChange = function (e) { var position = e.position, source = e.source; var editor = _this.editor; var selection = editor.getSelection(); if (!_this.ctxInsert.get() && e.source === 'mouse' && selection.isEmpty()) { var maxCol = editor.getModel().getLineMaxColumn(position.lineNumber); if (e.position.column === maxCol) { editor.setPosition(new Position(e.position.lineNumber, maxCol - 1)); return; } } _this.dispatch('cursorActivity', _this, e); }; this.handleChange = function (e) { var changes = e.changes; var change = { text: changes.reduce(function (acc, change) { acc.push(change.text); return acc; }, []), origin: '+input' }; var curOp = _this.curOp = _this.curOp || {}; if (!curOp.changeHandlers) { curOp.changeHandlers = _this.listeners['change'] && _this.listeners['change'].slice(); } if (_this.virtualSelectionMode()) { return; } if (!curOp.lastChange) { curOp.lastChange = curOp.change = change; } else { curOp.lastChange.next = curOp.lastChange = change; } _this.dispatch('change', _this, change); }; this.editor = editor; this.state = {}; this.marks = {}; this.$uid = 0; this.disposables = []; this.listeners = {}; this.curOp = {}; this.attached = false; this.statusBar = null; this.addLocalListeners(); this.ctxInsert = this.editor.createContextKey('insertMode', true); } CMAdapter.prototype.attach = function () { CMAdapter.keyMap.vim.attach(this); }; CMAdapter.prototype.addLocalListeners = function () { this.disposables.push(this.editor.onDidChangeCursorPosition(this.handleCursorChange), this.editor.onDidChangeModelContent(this.handleChange), this.editor.onKeyDown(this.handleKeyDown)); }; CMAdapter.prototype.handleReplaceMode = function (key, e) { var fromReplace = false; var char = key; var pos = this.editor.getPosition(); var range = new Range(pos.lineNumber, pos.column, pos.lineNumber, pos.column + 1); var forceMoveMarkers = true; if (key.startsWith('\'')) { char = key[1]; } else if (char === 'Enter') { char = '\n'; } else if (char === 'Backspace') { var lastItem = this.replaceStack.pop(); if (!lastItem) { return; } fromReplace = true; char = lastItem; range = new Range(pos.lineNumber, pos.column, pos.lineNumber, pos.column - 1); } else { return; } e.preventDefault(); e.stopPropagation(); if (!this.replaceStack) { this.replaceStack = []; } if (!fromReplace) { this.replaceStack.push(this.editor.getModel().getValueInRange(range)); } this.editor.executeEdits('vim', [{ text: char, range: range, forceMoveMarkers: forceMoveMarkers, }]); if (fromReplace) { this.editor.setPosition(range.getStartPosition()); } }; CMAdapter.prototype.setOption = function (key, value) { this.state[key] = value; if (key === 'theme') { monacoEditor.setTheme(value); } }; CMAdapter.prototype.getConfiguration = function () { var editor = this.editor; var opts = EditorOptConstants; if (typeof editor.getConfiguration === 'function') { return editor.getConfiguration(); } else if ('EditorOption' in monacoEditor) { // for monaco 0.19.3 onwards opts = monacoEditor.EditorOption; } return { readOnly: editor.getOption(opts.readOnly), viewInfo: { cursorWidth: editor.getOption(opts.cursorWidth), }, fontInfo: editor.getOption(opts.fontInfo), }; }; CMAdapter.prototype.getOption = function (key) { if (key === 'readOnly') { return this.getConfiguration().readOnly; } else if (key === 'firstLineNumber') { return this.firstLine() + 1; } else if (key === 'indentWithTabs') { return !this.editor.getModel().getOptions().insertSpaces; } else { if (typeof this.editor.getConfiguration === 'function') { return this.editor.getRawConfiguration()[key]; } return this.editor.getRawOptions()[key]; } }; CMAdapter.prototype.dispatch = function (signal) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var listeners = this.listeners[signal]; if (!listeners) { return; } listeners.forEach(function (handler) { return handler.apply(void 0, args); }); }; CMAdapter.prototype.on = function (event, handler) { if (!this.listeners[event]) { this.listeners[event] = []; } this.listeners[event].push(handler); }; CMAdapter.prototype.off = function (event, handler) { var listeners = this.listeners[event]; if (!listeners) { return; } this.listeners[event] = listeners.filter(function (l) { return l !== handler; }); }; CMAdapter.prototype.firstLine = function () { return 0; }; CMAdapter.prototype.lastLine = function () { return this.lineCount() - 1; }; CMAdapter.prototype.lineCount = function () { return this.editor.getModel().getLineCount(); }; CMAdapter.prototype.defaultTextHeight = function () { return 1; }; CMAdapter.prototype.getLine = function (line) { if (line < 0) { return ''; } var model = this.editor.getModel(); var maxLines = model.getLineCount(); if (line + 1 > maxLines) { line = maxLines - 1; } return this.editor.getModel().getLineContent(line + 1); }; CMAdapter.prototype.getAnchorForSelection = function (selection) { if (selection.isEmpty()) { return selection.getPosition(); } var selDir = selection.getDirection(); return (selDir === SelectionDirection.LTR) ? selection.getStartPosition() : selection.getEndPosition(); }; CMAdapter.prototype.getHeadForSelection = function (selection) { if (selection.isEmpty()) { return selection.getPosition(); } var selDir = selection.getDirection(); return (selDir === SelectionDirection.LTR) ? selection.getEndPosition() : selection.getStartPosition(); }; CMAdapter.prototype.getCursor = function (type) { if (type === void 0) { type = null; } if (!type) { return toCmPos(this.editor.getPosition()); } var sel = this.editor.getSelection(); var pos; if (sel.isEmpty()) { pos = sel.getPosition(); } else if (type === 'anchor') { pos = this.getAnchorForSelection(sel); } else { pos = this.getHeadForSelection(sel); } return toCmPos(pos); }; CMAdapter.prototype.getRange = function (start, end) { var p1 = toMonacoPos(start); var p2 = toMonacoPos(end); return this.editor.getModel().getValueInRange(Range.fromPositions(p1, p2)); }; CMAdapter.prototype.getSelection = function () { return this.editor.getModel().getValueInRange(this.editor.getSelection()); }; CMAdapter.prototype.replaceRange = function (text, start, end) { var p1 = toMonacoPos(start); var p2 = !end ? p1 : toMonacoPos(end); this.editor.executeEdits('vim', [{ text: text, range: Range.fromPositions(p1, p2), }]); // @TODO - Check if this breaks any other expectation this.pushUndoStop(); }; CMAdapter.prototype.pushUndoStop = function () { this.editor.pushUndoStop(); }; CMAdapter.prototype.setCursor = function (line, ch) { var pos = line; if (typeof line !== 'object') { pos = {}; pos.line = line; pos.ch = ch; } var monacoPos = this.editor.getModel().validatePosition(toMonacoPos(pos)); this.editor.setPosition(toMonacoPos(pos)); this.editor.revealPosition(monacoPos); }; CMAdapter.prototype.somethingSelected = function () { return !this.editor.getSelection().isEmpty(); }; CMAdapter.prototype.operation = function (fn, force) { return fn(); }; CMAdapter.prototype.listSelections = function () { var _this = this; var selections = this.editor.getSelections(); if (!selections.length || this.inVirtualSelectionMode) { return [{ anchor: this.getCursor('anchor'), head: this.getCursor('head'), }]; } return selections.map(function (sel) { var pos = sel.getPosition(); var start = sel.getStartPosition(); var end = sel.getEndPosition(); return { anchor: _this.clipPos(toCmPos(_this.getAnchorForSelection(sel))), head: _this.clipPos(toCmPos(_this.getHeadForSelection(sel))), }; }); }; CMAdapter.prototype.focus = function () { this.editor.focus(); }; CMAdapter.prototype.setSelections = function (selections, primIndex) { var hasSel = !!this.editor.getSelections().length; var sels = selections.map(function (sel, index) { var anchor = sel.anchor, head = sel.head; if (hasSel) { return Selection.fromPositions(toMonacoPos(anchor), toMonacoPos(head)); } else { return Selection.fromPositions(toMonacoPos(head), toMonacoPos(anchor)); } }); if (!primIndex) { sels.reverse(); } else if (sels[primIndex]) { sels.push(sels.splice(primIndex, 1)[0]); } if (!sels.length) { return; } var sel = sels[0]; var posToReveal; if (sel.getDirection() === SelectionDirection.LTR) { posToReveal = sel.getEndPosition(); } else { posToReveal = sel.getStartPosition(); } this.editor.setSelections(sels); this.editor.revealPosition(posToReveal); }; CMAdapter.prototype.setSelection = function (frm, to) { var range = Range.fromPositions(toMonacoPos(frm), toMonacoPos(to)); this.editor.setSelection(range); }; CMAdapter.prototype.getSelections = function () { var editor = this.editor; return editor.getSelections().map(function (sel) { return editor.getModel().getValueInRange(sel); }); }; CMAdapter.prototype.replaceSelections = function (texts) { var editor = this.editor; editor.getSelections().forEach(function (sel, index) { editor.executeEdits('vim', [{ range: sel, text: texts[index], forceMoveMarkers: false, }]); }); }; CMAdapter.prototype.toggleOverwrite = function (toggle) { if (toggle) { this.enterVimMode(); this.replaceMode = true; } else { this.leaveVimMode(); this.replaceMode = false; this.replaceStack = []; } }; CMAdapter.prototype.charCoords = function (pos, mode) { return { top: pos.line, left: pos.ch, }; }; CMAdapter.prototype.coordsChar = function (pos, mode) { }; CMAdapter.prototype.clipPos = function (p) { var pos = this.editor.getModel().validatePosition(toMonacoPos(p)); return toCmPos(pos); }; CMAdapter.prototype.setBookmark = function (cursor, options) { var bm = new Marker(this, this.$uid++, cursor.line, cursor.ch); if (!options || !options.insertLeft) { bm.$insertRight = true; } this.marks[bm.id] = bm; return bm; }; CMAdapter.prototype.getScrollInfo = function () { var editor = this.editor; var range = editor.getVisibleRanges()[0]; return { left: 0, top: range.startLineNumber - 1, height: editor.getModel().getLineCount(), clientHeight: range.endLineNumber - range.startLineNumber + 1, }; }; CMAdapter.prototype.triggerEditorAction = function (action) { this.editor.trigger('vim', action); }; CMAdapter.prototype.dispose = function () { this.dispatch('dispose'); this.removeOverlay(); if (CMAdapter.keyMap.vim) { CMAdapter.keyMap.vim.detach(this); } this.disposables.forEach(function (d) { return d.dispose(); }); }; CMAdapter.prototype.getInputField = function () { }; CMAdapter.prototype.getWrapperElement = function () { }; CMAdapter.prototype.enterVimMode = function (toVim) { this.ctxInsert.set(false); var config = this.getConfiguration(); this.initialCursorWidth = config.viewInfo.cursorWidth || 0; this.editor.updateOptions({ cursorWidth: config.fontInfo.typicalFullwidthCharacterWidth, cursorBlinking: 'solid', }); }; CMAdapter.prototype.leaveVimMode = function () { this.ctxInsert.set(true); this.editor.updateOptions({ cursorWidth: this.initialCursorWidth || 0, cursorBlinking: 'blink', }); }; CMAdapter.prototype.virtualSelectionMode = function () { return this.inVirtualSelectionMode; }; CMAdapter.prototype.markText = function () { // only used for fat-cursor, not needed return { clear: function () { }, find: function () { } }; }; CMAdapter.prototype.getUserVisibleLines = function () { var ranges = this.editor.getVisibleRanges(); if (!ranges.length) { return { top: 0, bottom: 0, }; } var res = { top: Infinity, bottom: 0, }; ranges.reduce(function (acc, range) { if (range.startLineNumber < acc.top) { acc.top = range.startLineNumber; } if (range.endLineNumber > acc.bottom) { acc.bottom = range.endLineNumber; } return acc; }, res); res.top -= 1; res.bottom -= 1; return res; }; CMAdapter.prototype.findPosV = function (startPos, amount, unit) { var editor = this.editor; var finalAmount = amount; var pos = toMonacoPos(startPos); if (unit === 'page') { var editorHeight = editor.getLayoutInfo().height; var lineHeight = this.getConfiguration().fontInfo.lineHeight; finalAmount = finalAmount * Math.floor(editorHeight / lineHeight); } if (unit === 'line') { pos.lineNumber += finalAmount; } return toCmPos(pos); }; CMAdapter.prototype.findMatchingBracket = function (pos) { var mPos = toMonacoPos(pos); var res = this.editor.getModel().matchBracket(mPos); if (!res || !(res.length === 2)) { return { to: null, }; } return { to: toCmPos(res[1].getStartPosition()), }; }; CMAdapter.prototype.findFirstNonWhiteSpaceCharacter = function (line) { return this.editor.getModel().getLineFirstNonWhitespaceColumn(line + 1) - 1; }; CMAdapter.prototype.scrollTo = function (x, y) { if (!x && !y) { return; } if (!x) { if (y < 0) { y = this.editor.getPosition().lineNumber - y; } this.editor.setScrollTop(this.editor.getTopForLineNumber(y + 1)); } }; CMAdapter.prototype.moveCurrentLineTo = function (viewPosition) { var editor = this.editor; var pos = editor.getPosition(); var range = Range.fromPositions(pos, pos); switch (viewPosition) { case 'top': editor.revealRangeAtTop(range); return; case 'center': editor.revealRangeInCenter(range); return; case 'bottom': // private api. no other way editor._revealRange(range, VerticalRevealType.Bottom); return; } }; CMAdapter.prototype.getSearchCursor = function (query, pos, caseFold) { var matchCase = false; var isRegex = false; if (query instanceof RegExp && !query.global) { matchCase = !query.ignoreCase; query = query.source; isRegex = true; } if (pos.ch == undefined) pos.ch = Number.MAX_VALUE; var monacoPos = toMonacoPos(pos); var context = this; var editor = this.editor; var lastSearch = null; var model = editor.getModel(); var matches = model.findMatches(query, false, isRegex, matchCase) || []; return { getMatches: function () { return matches; }, findNext: function () { return this.find(false); }, findPrevious: function () { return this.find(true); }, jumpTo: function (index) { if (!matches || !matches.length) { return false; } var match = matches[index]; lastSearch = match.range; context.highlightRanges([lastSearch], 'currentFindMatch'); context.highlightRanges(matches.map(function (m) { return m.range; }).filter(function (r) { return !r.equalsRange(lastSearch); })); return lastSearch; }, find: function (back) { if (!matches || !matches.length) { return false; } var match; if (back) { var pos_1 = lastSearch ? lastSearch.getStartPosition() : monacoPos; match = model.findPreviousMatch(query, pos_1, isRegex, matchCase); if (!match || !match.range.getStartPosition().isBeforeOrEqual(pos_1)) { return false; } } else { var pos_2 = lastSearch ? lastSearch.getEndPosition() : monacoPos; match = model.findNextMatch(query, pos_2, isRegex, matchCase); if (!match || !pos_2.isBeforeOrEqual(match.range.getStartPosition())) { return false; } } lastSearch = match.range; context.highlightRanges([lastSearch], 'currentFindMatch'); context.highlightRanges(matches.map(function (m) { return m.range; }).filter(function (r) { return !r.equalsRange(lastSearch); })); return lastSearch; }, from: function () { return lastSearch && toCmPos(lastSearch.getStartPosition()); }, to: function () { return lastSearch && toCmPos(lastSearch.getEndPosition()); }, replace: function (text) { if (lastSearch) { editor.executeEdits('vim', [{ range: lastSearch, text: text, forceMoveMarkers: true, }]); lastSearch.setEndPosition(editor.getPosition()); editor.setPosition(lastSearch.getStartPosition()); } } }; }; CMAdapter.prototype.highlightRanges = function (ranges, className) { if (className === void 0) { className = 'findMatch'; } var decorationKey = "decoration" + className; this[decorationKey] = this.editor.deltaDecorations(this[decorationKey] || [], ranges.map(function (range) { return ({ range: range, options: { stickiness: monacoEditor.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, zIndex: 13, className: className, showIfCollapsed: true, }, }); })); return this[decorationKey]; }; CMAdapter.prototype.addOverlay = function (_a, hasBoundary, style) { var query = _a.query; var matchCase = false; var isRegex = false; if (query && query instanceof RegExp && !query.global) { isRegex = true; matchCase = !query.ignoreCase; query = query.source; } var match = this.editor.getModel().findNextMatch(query, this.editor.getPosition(), isRegex, matchCase); if (!match || !match.range) { return; } this.highlightRanges([match.range]); }; CMAdapter.prototype.removeOverlay = function () { var _this = this; ['currentFindMatch', 'findMatch'].forEach(function (key) { _this.editor.deltaDecorations(_this["decoration" + key] || [], []); }); }; CMAdapter.prototype.scrollIntoView = function (pos) { if (!pos) { return; } this.editor.revealPosition(toMonacoPos(pos)); }; CMAdapter.prototype.moveH = function (units, type) { if (type !== 'char') { return; } var pos = this.editor.getPosition(); this.editor.setPosition(new Position(pos.lineNumber, pos.column + units)); }; /** * Uses internal apis which not sure why is internal */ CMAdapter.prototype.scanForBracket = function (pos, dir, dd, config) { var mPos = toMonacoPos(pos); var model = this.editor.getModel(); var range = model.matchBracket(mPos); if (!range || range.length !== 2) { var bracket = '{(['; for (var i = 0; i < bracket.length; i++) { var bracketRange = model.findMatchingBracketUp(bracket[i], mPos); if (bracketRange) { range = model.matchBracket(bracketRange.getEndPosition()); break; } } } if (!range || range.length !== 2) { return null; } var res; if (dir === -1) { res = range[1].getStartPosition(); } else { res = range[0].getStartPosition(); } return { pos: toCmPos(res), ch: model.getValueInRange(dir === -1 ? range[0] : range[1]), }; }; CMAdapter.prototype.indexFromPos = function (pos) { return this.editor.getModel().getOffsetAt(toMonacoPos(pos)); }; CMAdapter.prototype.posFromIndex = function (offset) { return toCmPos(this.editor.getModel().getPositionAt(offset)); }; CMAdapter.prototype.indentLine = function (line, indentRight) { var editor = this.editor; var cursors = editor._getCursors(); var pos = new Position(line + 1, 1); var sel = Selection.fromPositions(pos, pos); // no other way than to use internal apis to preserve the undoStack for a batch of indents // editor.executeCommands( // `editor.action.${indentRight ? 'indent' : 'outdent'}Lines`, // TypeOperations[indentRight ? 'indent' : 'outdent'](cursors.context.config, this.editor.getModel(), [sel]), // ); }; CMAdapter.prototype.setStatusBar = function (statusBar) { this.statusBar = statusBar; }; CMAdapter.prototype.openDialog = function (html, callback, options) { if (!this.statusBar) { return; } return this.statusBar.setSec(html, callback, options); }; CMAdapter.prototype.openNotification = function (html) { if (!this.statusBar) { return; } this.statusBar.showNotification(html); }; CMAdapter.Pos = Pos; CMAdapter.signal = signal; CMAdapter.on = dummy(); CMAdapter.off = dummy(); CMAdapter.addClass = dummy(); CMAdapter.rmClass = dummy(); CMAdapter.defineOption = dummy(); CMAdapter.keyMap = { 'default': function (key) { return function (cm) { return true; }; } }; CMAdapter.isWordChar = isWordCharBasic; CMAdapter.keyName = monacoToCmKey; CMAdapter.StringStream = StringStream; CMAdapter.e_stop = function (e) { if (e.stopPropagation) { e.stopPropagation(); } else { e.cancelBubble = true; } CMAdapter.e_preventDefault(e); return false; }; CMAdapter.e_preventDefault = function (e) { if (e.preventDefault) { e.preventDefault(); if (e.browserEvent) { e.browserEvent.preventDefault(); } } else { e.returnValue = false; } return false; }; CMAdapter.commands = { redo: function (cm) { cm.triggerEditorAction('redo'); }, undo: function (cm) { cm.triggerEditorAction('undo'); }, newlineAndIndent: function (cm) { cm.triggerEditorAction('editor.action.insertLineAfter'); } }; CMAdapter.lookupKey = function lookupKey(key, map, handle) { if (typeof map === 'string') { map = CMAdapter.keyMap[map]; } var found = typeof map == "function" ? map(key) : map[key]; if (found === false) return "nothing"; if (found === "...") return "multi"; if (found != null && handle(found)) return "handled"; if (map.fallthrough) { if (!Array.isArray(map.fallthrough)) return lookupKey(key, map.fallthrough, handle); for (var i = 0; i < map.fallthrough.length; i++) { var result = lookupKey(key, map.fallthrough[i], handle); if (result) return result; } } }; CMAdapter.defineExtension = function (name, fn) { CMAdapter.prototype[name] = fn; }; return CMAdapter; }()); /* eslint-disable */ var defaultKeymap = [ // Key to key mapping. This goes first to make it possible to override // existing mappings. { keys: '<Left>', type: 'keyToKey', toKeys: 'h' }, { keys: '<Right>', type: 'keyToKey', toKeys: 'l' }, { keys: '<Up>', type: 'keyToKey', toKeys: 'k' }, { keys: '<Down>', type: 'keyToKey', toKeys: 'j' }, { keys: '<Space>', type: 'keyToKey', toKeys: 'l' }, { keys: '<BS>', type: 'keyToKey', toKeys: 'h', context: 'normal' }, { keys: '<C-Space>', type: 'keyToKey', toKeys: 'W' }, { keys: '<C-BS>', type: 'keyToKey', toKeys: 'B', context: 'normal' }, { keys: '<S-Space>', type: 'keyToKey', toKeys: 'w' }, { keys: '<S-BS>', type: 'keyToKey', toKeys: 'b', context: 'normal' }, { keys: '<C-n>', type: 'keyToKey', toKeys: 'j' }, { keys: '<C-p>', type: 'keyToKey', toKeys: 'k' }, { keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>' }, { keys: '<C-c>', type: 'keyToKey', toKeys: '<Esc>' }, { keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>', context: 'insert' }, { keys: '<C-c>', type: 'keyToKey', toKeys: '<Esc>', context: 'insert' }, { keys: 's', type: 'keyToKey', toKeys: 'cl', context: 'normal' }, { keys: 's', type: 'keyToKey', toKeys: 'c', context: 'visual' }, { keys: 'S', type: 'keyToKey', toKeys: 'cc', context: 'normal' }, { keys: 'S', type: 'keyToKey', toKeys: 'VdO', context: 'visual' }, { keys: '<Home>', type: 'keyToKey', toKeys: '0' }, { keys: '<End>', type: 'keyToKey', toKeys: '$' }, { keys: '<PageUp>', type: 'keyToKey', toKeys: '<C-b>' }, { keys: '<PageDown>', type: 'keyToKey', toKeys: '<C-f>' }, { keys: '<CR>', type: 'keyToKey', toKeys: 'j^', context: 'normal' }, { keys: '<CR>', type: 'keyToKey', toKeys: 'j^', context: 'visual' }, { keys: '<Ins>', type: 'action', action: 'toggleOverwrite', context: 'insert' }, // Motions { keys: 'H', type: 'motion', motion: 'moveToTopLine', motionArgs: { linewise: true, toJumplist: true } }, { keys: 'M', type: 'motion', motion: 'moveToMiddleLine', motionArgs: { linewise: true, toJumplist: true } }, { keys: 'L', type: 'motion', motion: 'moveToBottomLine', motionArgs: { linewise: true, toJumplist: true } }, { keys: 'h', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: false } }, { keys: 'l', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: true } }, { keys: 'j', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, linewise: true } }, { keys: 'k', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, linewise: true } }, { keys: 'gj', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: true } }, { keys: 'gk', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: false } }, { keys: 'w', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false } }, { keys: 'W', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false, bigWord: true } }, { keys: 'e', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, inclusive: true } }, { keys: 'E', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, bigWord: true, inclusive: true } }, { keys: 'b', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false } }, { keys: 'B', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false, bigWord: true } }, { keys: 'ge', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, inclusive: true } }, { 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: '<C-f>', type: 'motion', motion: 'moveByPage', motionArgs: { forward: true } }, { keys: '<C-b>', type: 'motion', motion: 'moveByPage', motionArgs: { forward: false } }, { keys: '<C-d>', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: true, explicitRepeat: true } }, { keys: '<C-u>', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: false, explicitRepeat: true } }, { keys: 'gg', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true } }, { keys: 'G', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true } }, { keys: '0', type: 'motion', motion: 'moveToStartOfLine' }, { keys: '^', type: 'motion', motion: 'moveToFirstNonWhiteSpaceCharacter' }, { keys: '+', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar: true } }, { keys: '-', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, toFirstChar: true } }, { keys: '_', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar: true, repeatOffset: -1 } }, { keys: '$', type: 'motion', motion: 'moveToEol', motionArgs: { inclusive: true } }, { keys: '%', type: 'motion', motion: 'moveToMatchedSymbol', motionArgs: { inclusive: true, toJumplist: true } }, { keys: 'f<character>', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: true, inclusive: true } }, { keys: 'F<character>', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: false } }, { keys: 't<character>', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: true, inclusive: true } }, { keys: 'T<character>', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: false } }, { keys: ';', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: true } }, { keys: ',', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: false } }, { keys: '\'<character>', type: 'motion', motion: 'goToMark', motionArgs: { toJumplist: true, linewise: true } }, { keys: '`<character>', type: 'motion', motion: 'goToMark', motionArgs: { toJumplist: true } }, { keys: ']`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } }, { keys: '[`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } }, { keys: ']\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } }, { keys: '[\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } }, // the next two aren't motions but must come before more general motion declarations { keys: ']p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true, matchIndent: true } }, { keys: '[p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true, matchIndent: true } }, { keys: ']<character>', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: true, toJumplist: true } }, { keys: '[<character>', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: false, toJumplist: true } }, { keys: '|', type: 'motion', motion: 'moveToColumn' }, { keys: 'o', type: 'motion', motion: 'moveToOtherHighlightedEnd', context: 'visual' }, { keys: 'O', type: 'motion', motion: 'moveToOtherHighlightedEnd', motionArgs: { sameLine: true }, context: 'visual' }, // Operators { keys: 'd', type: 'operator', operator: 'delete' }, { keys: 'y', type: 'operator', operator: 'yank' }, { keys: 'c', type: 'operator', operator: 'change' }, { keys: '>', type: 'operator', operator: 'indent', operatorArgs: { indentRight: true } }, { keys: '<', type: 'operator', operator: 'indent', operatorArgs: { indentRight: false } }, { keys: 'g~', type: 'operator', operator: 'changeCase' }, { keys: 'gu', type: 'operator', operator: 'changeCase', operatorArgs: { toLower: true }, isEdit: true }, { keys: 'gU', type: 'operator', operator: 'changeCase', operatorArgs: { toLower: false }, isEdit: true }, { keys: 'n', type: 'motion', motion: 'findNext', motionArgs: { forward: true, toJumplist: true } }, { keys: 'N', type: 'motion', motion: 'findNext', motionArgs: { forward: false, toJumplist: true } }, // Operator-Motion dual commands { keys: 'x', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorMotionArgs: { visualLine: false } }, { 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: '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: '<C-w>', type: 'operatorMotion', operator: 'delete', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }, context: 'insert' }, // Actions { keys: '<C-i>', type: 'action', action: 'jumpListWalk', actionArgs: { forward: true } }, { keys: '<C-o>', type: 'action', action: 'jumpListWalk', actionArgs: { forward: false } }, { keys: '<C-e>', type: 'action', action: 'scroll', actionArgs: { forward: true, linewise: true } }, { keys: '<C-y>', type: 'action', action: 'scroll', actionArgs: { forward: false, linewise: true } }, { keys: 'a', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'charAfter' }, context: 'normal' }, { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'eol' }, context: 'normal' }, { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'endOfSelectedArea' }, context: 'visual' }, { keys: 'i', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'inplace' }, context: 'normal' }, { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'firstNonBlank' }, context: 'normal' }, { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'startOfSelectedArea' }, context: 'visual' }, { keys: 'o', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: true }, context: 'normal' }, { keys: 'O', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: false }, context: 'normal' }, { keys: 'v', type: 'action', action: 'toggleVisualMode' }, { keys: 'V', type: 'action', action: 'toggleVisualMode', actionArgs: { linewise: true } }, { keys: '<C-v>', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true } }, { keys: '<C-q>', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true } }, { keys: 'gv', type: 'action', action: 'reselectLastSelection' }, { keys: 'J', type: 'action', action: 'joinLines', isEdit: true }, { keys: 'p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true } }, { keys: 'P', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true } }, { keys: 'r<character>', type: 'action', action: 'replace', isEdit: true }, { keys: '@<character>', type: 'action', action: 'replayMacro' }, { keys: 'q<character>', type: 'action', action: 'enterMacroRecordMode' }, // Handle Replace-mode as a special case of insert mode. { keys: 'R', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { replace: true } }, { keys: 'u', type: 'action', action: 'undo', context: 'normal' }, { keys: 'u', type: 'operator', operator: 'changeCase', operatorArgs: { toLower: true }, context: 'visual', isEdit: true }, { keys: 'U', type: 'operator', operator: 'changeCase', operatorArgs: { toLower: false }, context: 'visual', isEdit: true }, { keys: '<C-r>', type: 'action', action: 'redo' }, { keys: 'm<character>', type: 'action', action: 'setMark' }, { keys