diff --git a/src/vim.js b/src/vim.js index d266502..5538772 100644 --- a/src/vim.js +++ b/src/vim.js @@ -138,6 +138,7 @@ export function initVim(CM) { { keys: "g$", type: "motion", motion: "moveToEndOfDisplayLine" }, { keys: "g^", type: "motion", motion: "moveToStartOfDisplayLine" }, { keys: "g0", type: "motion", motion: "moveToStartOfDisplayLine" }, + { keys: "g_", type: "motion", motion: "moveToLastNonWhiteSpaceCharacter", motionArgs: { inclusive: true }}, { keys: '0', type: 'motion', motion: 'moveToStartOfLine' }, { keys: '^', type: 'motion', motion: 'moveToFirstNonWhiteSpaceCharacter' }, { keys: '+', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true }}, @@ -2537,6 +2538,12 @@ export function initVim(CM) { return new Pos(cursor.line, findFirstNonWhiteSpaceCharacter(cm.getLine(cursor.line))); }, + moveToLastNonWhiteSpaceCharacter: function(cm, head, motionArgs) { + var line = head.line + motionArgs.repeat - 1; + var lineText = cm.getLine(line); + var lastNonWS = findLastNonWhiteSpaceCharacter(lineText); + return new Pos(line, Math.max(0, lastNonWS)); + }, moveToMatchedSymbol: function(cm, head) { var cursor = head; var line = cursor.line; @@ -4018,6 +4025,15 @@ export function initVim(CM) { return firstNonWS == -1 ? text.length : firstNonWS; } + /** @arg {string} [text] */ + function findLastNonWhiteSpaceCharacter(text) { + if (!text) { + return 0; + } + var index = text.search(/\s+$/); + return index == -1 ? text.length - 1 : index - 1; + } + /** * @arg {CodeMirror} cm * @arg {{inclusive?: boolean, innerWord?: boolean, bigWord?: boolean, noSymbol?: boolean, multiline?: boolean}} options diff --git a/test/vim_test.js b/test/vim_test.js index 789fc06..8e1adeb 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -541,6 +541,24 @@ testVim('g0_g$', function(cm, vim, helpers) { is(!/\.$/.test(cm.getValue())); },{ lineNumbers: false, lineWrapping:true, value: 'This line is long to test movement of g$ and g0 over wrapped lines.' }); +testVim('g_', function(cm, vim, helpers) { + // Test basic g_ on line with trailing spaces + cm.setCursor(0, 0); + helpers.doKeys('g', '_'); + helpers.assertCursorAt(0, 2); + // Test g_ on line without trailing spaces + cm.setCursor(1, 0); + helpers.doKeys('g', '_'); + helpers.assertCursorAt(1, 2); + // Test g_ with count (2g_ goes to last non-whitespace of next line) + cm.setCursor(0, 0); + helpers.doKeys('2', 'g', '_'); + helpers.assertCursorAt(1, 2); + // Test dg_ deletes to last non-whitespace (preserving trailing spaces) + cm.setCursor(0, 0); + helpers.doKeys('d', 'g', '_'); + eq(' \nfoo', cm.getValue()); +}, { value: 'foo \nfoo' }); testVim('}', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('}');