diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c09936..931f5e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to the Vz Keymap extension will be documented in this file. +### [Unreleased] +- 新規: + - 「次の論理行頭へのカーソル移動」コマンドを追加しました。[#43](https://github.com/tshino/vscode-vz-like-keymap/issues/43) + - キー割り当てはありません。 + - このコマンドはVZエディタの上書きモード時のENTERキーに近い動作を提供します。 + - コマンドIDは`vz.cursorNextLineStart`です。補助コマンド`vz.findStartCursorNextLineStart`もあります。 +- New: + - Added new command that moves the cursor to the beginning of the next line. [#43](https://github.com/tshino/vscode-vz-like-keymap/issues/43) + - It has no keybinding. + - It provides a similar behavior to that of the Enter key in overwrite mode of VZ Editor. + - The command ID is `vz.cursorNextLineStart`. Supplementary command `vz.findStartCursorNextLineStart` is also available. + ### [0.18.1] - 2022-01-15 - 修正: - vscode上の一部の操作(Gitなど)によりVz Keymapのエラーが表示される問題を修正しました。 [#41](https://github.com/tshino/vscode-vz-like-keymap/issues/41) diff --git a/src/cursor_commands.js b/src/cursor_commands.js index ecbe8d0..860d816 100644 --- a/src/cursor_commands.js +++ b/src/cursor_commands.js @@ -345,6 +345,18 @@ const CursorHandler = function(modeHandler) { let col = textEditor.document.lineAt(line).range.end.character; await moveCursorTo(textEditor, line, col, true); }; + const cursorNextLineStart = async function(textEditor, _edit) { + mode.sync(textEditor); + mode.resetBoxSelection(); + const lineCount = textEditor.document.lineCount; + const line = textEditor.selection.active.line + 1; + if (line < lineCount) { + await moveCursorTo(textEditor, line, 0, mode.inSelection()); + } else { + const col = textEditor.document.lineAt(lineCount - 1).text.length; + await moveCursorTo(textEditor, lineCount - 1, col, mode.inSelection()); + } + }; const cursorLeft = makeCursorCommand('cursorLeft', 'cursorLeftSelect', 'cursorColumnSelectLeft'); const cursorRight = makeCursorCommand('cursorRight', 'cursorRightSelect', 'cursorColumnSelectRight'); const cursorUp = makeCursorCommand('cursorUp', 'cursorUpSelect', 'cursorColumnSelectUp'); @@ -619,6 +631,7 @@ const CursorHandler = function(modeHandler) { registerTextEditorCommand(context, 'cursorEnd', cursorEnd); registerTextEditorCommand(context, 'cursorTop', cursorTop); registerTextEditorCommand(context, 'cursorBottom', cursorBottom); + registerTextEditorCommand(context, 'cursorNextLineStart', cursorNextLineStart); registerCursorCommand(context, 'cursorLeftSelect', 'cursorLeftSelect'); registerCursorCommand(context, 'cursorRightSelect', 'cursorRightSelect'); registerCursorCommand(context, 'cursorUpSelect', 'cursorUpSelect'); @@ -665,6 +678,7 @@ const CursorHandler = function(modeHandler) { cursorEnd, cursorTop, cursorBottom, + cursorNextLineStart, scrollLineUp, scrollLineDown, stopBoxSelection, diff --git a/src/search_commands.js b/src/search_commands.js index 0fa2131..1fdb096 100644 --- a/src/search_commands.js +++ b/src/search_commands.js @@ -221,6 +221,10 @@ const SearchHandler = function(modeHandler) { 'findStartCursorViewBottom', makeFindStartCursorImpl(cursorHandler.cursorViewBottom) ); + const findStartCursorNextLineStart = makeGuardedCommand( + 'findStartCursorNextLineStart', + makeFindStartCursorImpl(cursorHandler.cursorNextLineStart) + ); const findStartScrollLineUp = makeGuardedCommand( 'findStartScrollLineUp', makeFindStartCursorImpl(cursorHandler.scrollLineUp) @@ -294,6 +298,7 @@ const SearchHandler = function(modeHandler) { registerTextEditorCommand(context, 'findStartCursorBottom', findStartCursorBottom); registerTextEditorCommand(context, 'findStartCursorViewTop', findStartCursorViewTop); registerTextEditorCommand(context, 'findStartCursorViewBottom', findStartCursorViewBottom); + registerTextEditorCommand(context, 'findStartCursorNextLineStart', findStartCursorNextLineStart); registerTextEditorCommand(context, 'findStartScrollLineUp', findStartScrollLineUp); registerTextEditorCommand(context, 'findStartScrollLineDown', findStartScrollLineDown); registerTextEditorCommand(context, 'findStartCancelSelection', findStartCancelSelection); @@ -326,6 +331,7 @@ const SearchHandler = function(modeHandler) { findStartCursorBottom, findStartCursorViewTop, findStartCursorViewBottom, + findStartCursorNextLineStart, findStartScrollLineUp, findStartScrollLineDown, findStartCancelSelection, diff --git a/test_with_vscode/suite/cursor_commands.test.js b/test_with_vscode/suite/cursor_commands.test.js index a7ec538..59c6f0c 100644 --- a/test_with_vscode/suite/cursor_commands.test.js +++ b/test_with_vscode/suite/cursor_commands.test.js @@ -950,6 +950,57 @@ describe('CursorHandler', () => { assert.deepStrictEqual(selectionsAsArray(), [[3, 3, 10, 0]]); }); }); + describe('cursorNextLineStart', () => { + before(async () => { + await testUtils.resetDocument( + textEditor, + '0123456789\n'.repeat(9) + + '0123456789' + ); + }); + it('should move cursor to the beginning of the next line', async () => { + await resetCursor(5, 5); + + await cursorHandler.cursorNextLineStart(textEditor); + + assert.strictEqual(mode.inSelection(), false); + assert.deepStrictEqual(selectionsAsArray(), [[6, 0]]); + }); + it('should move cursor to the end of the line if it is in the last line of the document', async () => { + await resetCursor(9, 5); + + await cursorHandler.cursorNextLineStart(textEditor); + + assert.strictEqual(mode.inSelection(), false); + assert.deepStrictEqual(selectionsAsArray(), [[9, 10]]); + }); + it('should do nothing if the cursor is at the end of the last line of the document', async () => { + await resetCursor(9, 10); + + await cursorHandler.cursorNextLineStart(textEditor); + + assert.strictEqual(mode.inSelection(), false); + assert.deepStrictEqual(selectionsAsArray(), [[9, 10]]); + }); + it('should extend selection', async () => { + await selectRange(5, 5, 5, 8); + + await cursorHandler.cursorNextLineStart(textEditor); + + assert.strictEqual(mode.inSelection(), true); + assert.strictEqual(mode.inBoxSelection(), false); + assert.deepStrictEqual(selectionsAsArray(), [[5, 5, 6, 0]]); + }); + it('should cancel box-selection mode', async () => { + await selectRanges([[6, 6, 6, 8]]); + + await cursorHandler.cursorNextLineStart(textEditor); + + assert.strictEqual(mode.inSelection(), true); + assert.strictEqual(mode.inBoxSelection(), false); + assert.deepStrictEqual(selectionsAsArray(), [[6, 6, 7, 0]]); + }); + }); describe('scrollLineUp', () => { before(async () => { await testUtils.resetDocument(textEditor, '0123456789\n'.repeat(1000)); diff --git a/test_with_vscode/suite/keyboard_macro.test.js b/test_with_vscode/suite/keyboard_macro.test.js index 8f63712..9f62dcf 100644 --- a/test_with_vscode/suite/keyboard_macro.test.js +++ b/test_with_vscode/suite/keyboard_macro.test.js @@ -274,6 +274,17 @@ describe('KeyboardMacro', () => { assert.strictEqual(mode.inSelection(), false); assert.deepStrictEqual(selectionsAsArray(), [[10, 0]]); }); + it('should move cursor to beginning of the next line', async () => { + await resetCursor(3, 3); + const commands = ['vz.cursorNextLineStart']; + await recordThroughExecution(commands); + assert.deepStrictEqual(kb_macro.getRecordedCommandNames(), commands); + + await resetCursor(5, 5); + await kb_macro.replay(textEditor); + assert.strictEqual(mode.inSelection(), false); + assert.deepStrictEqual(selectionsAsArray(), [[6, 0]]); + }); it('should make selection range while moving cursor (*arrow-select)', async () => { await resetCursor(3, 3); const commands = [ @@ -861,6 +872,21 @@ describe('KeyboardMacro', () => { assert.strictEqual(mode.inSelection(), true); assert.deepStrictEqual(selectionsAsArray(), [[0, 0, 10, 0]]); }); + it('should make a selection range (nextLineStart -> toggle -> nextLineStart)', async () => { + await resetCursor(1, 1); + const commands = [ + 'vz.cursorNextLineStart', + 'vz.toggleSelection', + 'vz.cursorNextLineStart' + ]; + await recordThroughExecution(commands); + assert.deepStrictEqual(kb_macro.getRecordedCommandNames(), commands); + + await resetCursor(5, 5); + await kb_macro.replay(textEditor); + assert.strictEqual(mode.inSelection(), true); + assert.deepStrictEqual(selectionsAsArray(), [[6, 0, 7, 0]]); + }); it('should make a selection range (right-select -> toggle -> left-select)', async () => { await resetCursor(1, 1); const commands = [ @@ -1032,6 +1058,22 @@ describe('KeyboardMacro', () => { assert.strictEqual(mode.inSelection(), false); assert.deepStrictEqual(selectionsAsArray(), [[10, 0]]); }); + it('should make a selection range and cancel it then move cursor (nextLineStart)', async () => { + await resetCursor(1, 1); + const commands = [ + 'vz.toggleSelection', + 'vz.cursorNextLineStart', + 'vz.toggleSelection', + 'vz.cursorNextLineStart' + ]; + await recordThroughExecution(commands); + assert.deepStrictEqual(kb_macro.getRecordedCommandNames(), commands); + + await resetCursor(5, 5); + await kb_macro.replay(textEditor); + assert.strictEqual(mode.inSelection(), false); + assert.deepStrictEqual(selectionsAsArray(), [[7, 0]]); + }); it('should make and cancel a selection range then make another one (left/right-select)', async () => { await resetCursor(1, 1); const commands = [ @@ -5234,6 +5276,13 @@ describe('KeyboardMacro', () => { await selectRange(2, 2, 2, 7); await testReplayFindStartCursorXXX([[10, 0]]); }); + it('should cancel selection and move cursor to beginning of next line (findStartCursorNextLineStart)', async () => { + await selectRange(7, 2, 7, 5); + await testRecordingFindStartCursorXXX(['vz.findStartCursorNextLineStart'], [[8, 0]]); + + await selectRange(2, 2, 2, 7); + await testReplayFindStartCursorXXX([[3, 0]]); + }); }); describe('findStartCursorTop, findStartCursorBottom', () => { beforeEach(async () => { diff --git a/test_with_vscode/suite/search_commands.test.js b/test_with_vscode/suite/search_commands.test.js index a87309f..2dca429 100644 --- a/test_with_vscode/suite/search_commands.test.js +++ b/test_with_vscode/suite/search_commands.test.js @@ -505,6 +505,10 @@ describe('SearchHandler', () => { await selectRange(7, 3, 7, 8); await testWithMatch(searchHandler.findStartCursorViewBottom, [[10, 0]]); }); + it('should cancel selection and move cursor to beginning of the next line (findStartCursorNextLineStart)', async () => { + await selectRange(7, 7, 7, 10); + await testWithMatch(searchHandler.findStartCursorNextLineStart, [[8, 0]]); + }); it('should not cancel selection if it is not a match (findStartCursorLeft)', async () => { await selectRange(5, 2, 5, 5); @@ -562,6 +566,10 @@ describe('SearchHandler', () => { await selectRange(5, 2, 5, 7); await testWithoutMatch(searchHandler.findStartCursorViewBottom, [[5, 2, 10, 0]]); }); + it('should not cancel selection if it is not a match (findStartCursorNextLineStart)', async () => { + await selectRange(5, 2, 5, 7); + await testWithoutMatch(searchHandler.findStartCursorNextLineStart, [[5, 2, 6, 0]]); + }); }); describe('findStartScrollLineXXX', () => { before(async () => {