diff --git a/src/cm_adapter.ts b/src/cm_adapter.ts index 391f784..62cf1be 100644 --- a/src/cm_adapter.ts +++ b/src/cm_adapter.ts @@ -5,6 +5,7 @@ import { RegExpCursor, setSearchQuery, SearchQuery } from "@codemirror/search" import { insertNewlineAndIndent, indentMore, indentLess, indentSelection, cursorCharLeft, undo, redo, cursorLineBoundaryBackward, cursorLineBoundaryForward, cursorCharBackward, + toggleLineComment } from "@codemirror/commands" import {vimState, CM5RangeInterface} from "./types" @@ -135,6 +136,7 @@ export class CodeMirror { static Pos = Pos; static StringStream = StringStream as unknown as StringStream & { new(_: string): StringStream } static commands = { + toggleLineComment: function (cm: CodeMirror) { toggleLineComment(cm.cm6) }, cursorCharLeft: function (cm: CodeMirror) { cursorCharLeft(cm.cm6); }, redo: function (cm: CodeMirror) { runHistoryCommand(cm, false); }, undo: function (cm: CodeMirror) { runHistoryCommand(cm, true); }, @@ -427,7 +429,7 @@ export class CodeMirror { }; execCommand(name: string) { - if (name == "indentAuto") CodeMirror.commands.indentAuto(this); + if (CodeMirror.commands.hasOwnProperty(name)) CodeMirror.commands[name](this); else if (name == "goLineLeft") cursorLineBoundaryBackward(this.cm6); else if (name == "goLineRight") { cursorLineBoundaryForward(this.cm6); diff --git a/src/vim.js b/src/vim.js index 237858b..99fc4c8 100644 --- a/src/vim.js +++ b/src/vim.js @@ -175,6 +175,7 @@ export function initVim(CM) { { 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: 'gc', type: 'operator', operator: 'toggleComment', isEdit: true }, { keys: 'n', type: 'motion', motion: 'findNext', motionArgs: { forward: true, toJumplist: true }}, { keys: 'N', type: 'motion', motion: 'findNext', motionArgs: { forward: false, toJumplist: true }}, { keys: 'gn', type: 'motion', motion: 'findAndSelectNextInclusive', motionArgs: { forward: true }}, @@ -297,6 +298,7 @@ export function initVim(CM) { { name: 'startinsert', shortName: 'start' }, { name: 'nohlsearch', shortName: 'noh' }, { name: 'yank', shortName: 'y' }, + { name: 'put', shortName: 'pu' }, { name: 'delmarks', shortName: 'delm' }, { name: 'marks', excludeFromCommandHistory: true }, { name: 'registers', shortName: 'reg', excludeFromCommandHistory: true }, @@ -1983,6 +1985,12 @@ export function initVim(CM) { if (vim.visualMode) { promptOptions.value = '\'<,\'>'; promptOptions.selectValueOnOpen = false; + } else { + var repeat = vim.inputState.getRepeat(); + if (repeat > 1) { + promptOptions.value = '.,.+' + (repeat - 1); + promptOptions.selectValueOnOpen = false; + } } showPrompt(cm, promptOptions); } @@ -2861,6 +2869,10 @@ export function initVim(CM) { if (endRow > from && operatorArgs.linewise) endRow--; return operatorArgs.keepCursor ? oldAnchor : new Pos(endRow, 0); }, + toggleComment: function(cm, _args, ranges, oldAnchor, newHead) { + cm.execCommand("toggleLineComment"); + return newHead; + }, changeCase: function(cm, args, ranges, oldAnchor, newHead) { var selections = cm.getSelections(); var swapped = []; @@ -2901,6 +2913,9 @@ export function initVim(CM) { vimGlobalState.registerController.pushText( args.registerName, 'yank', text, args.linewise, vim.visualBlock); + + var lineCount = Math.abs(cm.getCursor("end").line - cm.getCursor("start").line) || 1; + showConfirm(cm, lineCount + ' lines yanked', false, 1500); return endPos; }, rot13: function(cm, args, ranges, oldAnchor, newHead) { @@ -3291,7 +3306,7 @@ export function initVim(CM) { if (actionArgs.repeat > 1) { text = Array(actionArgs.repeat + 1).join(text); } - var linewise = register.linewise; + var linewise = actionArgs.linewise == undefined ? register.linewise : actionArgs.linewise; var blockwise = register.blockwise; var textLines = blockwise ? text.split('\n') : undefined; if (textLines) { @@ -5288,8 +5303,8 @@ export function initVim(CM) { return n; } - /** @arg {CodeMirror} cm @arg {any} template @arg {boolean} [long]*/ - function showConfirm(cm, template, long) { + /** @arg {CodeMirror} cm @arg {any} template @arg {boolean} [long] @arg {number} [duration]*/ + function showConfirm(cm, template, long, duration) { var pre = dom('div', {$color: 'red', $whiteSpace: 'pre', class: 'cm-vim-message'}, template); if (cm.openNotification) { if (long) { @@ -5299,9 +5314,9 @@ export function initVim(CM) { } cm.state.closeVimNotification = cm.openNotification(pre, {bottom: true, duration: 0}); } else { - cm.openNotification(pre, {bottom: true, duration: 15000}); + cm.openNotification(pre, {bottom: true, duration: duration || 15000}); } - } else { + } else if (!duration) { alert(pre.innerText); } } @@ -5708,6 +5723,7 @@ export function initVim(CM) { result.selectionLineEnd = result.lineEnd; } + inputStream.eatSpace(); // Parse command name. var commandMatch = inputStream.match(/^(\w+|!!|@@|[!#&*<=>@~])/); if (commandMatch) { @@ -6365,13 +6381,39 @@ export function initVim(CM) { nohlsearch: function(cm) { clearSearchHighlight(cm); }, - /** @arg {CodeMirrorV} cm */ - yank: function (cm) { - var cur = copyCursor(cm.getCursor()); - var line = cur.line; - var lineText = cm.getLine(line); + /** @arg {CodeMirrorV} cm @arg {ExParams} params */ + yank: function (cm, params) { + var line = params.selectionLine; + var lineEnd = isNaN(params.selectionLineEnd) ? line : params.selectionLineEnd; + if (lineEnd < line) { + var tmp = lineEnd; + lineEnd = line; + line = tmp; + } + var text = cm.getRange(new Pos(line, 0), new Pos(lineEnd + 1, 0)); vimGlobalState.registerController.pushText( - '0', 'yank', lineText, true, true); + '0', 'yank', text, true, false); + showConfirm(cm, (lineEnd + 1 - line) + ' lines yanked', false, 1500); + }, + /** @arg {CodeMirrorV} cm @arg {ExParams} params @arg {boolean} [matchIndent]*/ + put: function(cm, params, matchIndent) { + var actionArgs = { after: true, isEdit: true, matchIndent: !!matchIndent, repeat: 1, lineWise: true, registerName: '' }; + var args = params.args || []; + if (args[0] == "!") { + actionArgs.after = false; + args.shift(); + } + if (args[0]) { + actionArgs.registerName = args[0]; + } + var line = params.selectionLine; + if (line != undefined) + cm.setCursor(new Pos(line, 0)); + actions.paste(cm, actionArgs, cm.state.vim); + }, + /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ + iput: function(cm, params) { + this.put(cm, params, true); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ delete: function(cm, params) {