diff --git a/changelog.d/20231026_201819_GitHub_Actions_add-yank-commands.rst b/changelog.d/20231026_201819_GitHub_Actions_add-yank-commands.rst new file mode 100644 index 000000000..8869a28b8 --- /dev/null +++ b/changelog.d/20231026_201819_GitHub_Actions_add-yank-commands.rst @@ -0,0 +1,7 @@ +.. _#1905: https://github.com/fox0430/moe/pull/1905 + +Added +..... + +- `#1905`_ feat: Add y0 and y$ commands to Normal mode + diff --git a/src/moepkg/editor.nim b/src/moepkg/editor.nim index 745e5a809..f55a67b98 100644 --- a/src/moepkg/editor.nim +++ b/src/moepkg/editor.nim @@ -1381,15 +1381,15 @@ proc yankLines*( name: string, settings: EditorSettings) = - const IsDelete = false - bufStatus.yankLines( - registers, - commandLine, - notificationSettings, - first, last, - name, - IsDelete, - settings) + const IsDelete = false + bufStatus.yankLines( + registers, + commandLine, + notificationSettings, + first, last, + name, + IsDelete, + settings) proc yankLines*( bufStatus: BufferStatus, @@ -1411,7 +1411,6 @@ proc yankLines*( IsDelete, settings) -# name is the register name proc yankCharacters*( bufStatus: BufferStatus, registers: var Registers, @@ -1419,7 +1418,7 @@ proc yankCharacters*( commandLine: var CommandLine, settings: EditorSettings, length: int, - name: string, + registerName: string, isDelete: bool) = var yankedBuffer: Runes @@ -1431,8 +1430,8 @@ proc yankCharacters*( line = windowNode.currentLine yankedBuffer.add bufStatus.buffer[line][col] - if name.len > 0: - registers.addRegister(yankedBuffer, name, settings) + if registerName.len > 0: + registers.addRegister(yankedBuffer, registerName, settings) else: registers.addRegister(yankedBuffer, settings) diff --git a/src/moepkg/normalmode.nim b/src/moepkg/normalmode.nim index 8bf3b9859..3c4915b52 100644 --- a/src/moepkg/normalmode.nim +++ b/src/moepkg/normalmode.nim @@ -668,6 +668,47 @@ proc yankCharactersToCharacter( registerName, IsDelete) +proc yankCharactersFromBeginOfLine( + status: var EditorStatus, + registerName: string = "") = + ## y0 command + + if currentMainWindowNode.currentColumn > 0: + let currentColumn = currentMainWindowNode.currentColumn + currentMainWindowNode.currentColumn = 0 + + const IsDelete = false + currentBufStatus.yankCharacters( + status.registers, + currentMainWindowNode, + status.commandLine, + status.settings, + currentColumn, + registerName, + IsDelete) + + currentMainWindowNode.currentColumn = currentColumn + +proc yankCharactersToEndOfLine( + status: var EditorStatus, + registerName: string = "") = + ## y$ command + + if currentBufStatus.buffer[currentMainWindowNode.currentLine].len > 0: + + const IsDelete = false + let length = + currentBufStatus.buffer[currentMainWindowNode.currentLine].len - + currentMainWindowNode.currentColumn + currentBufStatus.yankCharacters( + status.registers, + currentMainWindowNode, + status.commandLine, + status.settings, + length, + registerName, + IsDelete) + proc deleteCharacters(status: var EditorStatus, registerName: string) = if currentBufStatus.isReadonly: status.commandLine.writeReadonlyModeWarning @@ -1167,6 +1208,10 @@ proc addRegister(status: var EditorStatus, command, registerName: string) = status.yankToPreviousBlankLine(registerName) elif command == "y}": status.yankToNextBlankLine(registerName) + elif command == "y0": + status.yankCharactersFromBeginOfLine(registerName) + elif command == "y$": + status.yankCharactersToEndOfLine elif command == "dd": status.deleteLines(registerName) elif command == "dw": @@ -1245,6 +1290,8 @@ proc registerCommand(status: var EditorStatus, command: Runes) = cmd == "yl" or cmd == "y{" or cmd == "y}" or + cmd == "y0" or + cmd == "y$" or cmd == "dd" or cmd == "dw" or cmd == "d$" or (cmd.len == 1 and isEndKey(command[0])) or @@ -1508,6 +1555,10 @@ proc normalCommand(status: var EditorStatus, commands: Runes): Option[Rune] = status.yankToNextBlankLine elif secondKey == ord('l'): status.yankCharacters + elif secondKey == ord('0'): + status.yankCharactersFromBeginOfLine + elif secondKey == ord('$'): + status.yankCharactersToEndOfLine elif secondKey == ord('t'): let thirdKey = commands[2] status.yankCharactersToCharacter(thirdKey) @@ -1795,8 +1846,10 @@ proc isNormalModeCommand*( command[1] == ord('w') or command[1] == ord('{') or command[1] == ord('}') or - command[1] == ord('l'): - result = InputState.Valid + command[1] == ord('l') or + command[1] == ord('0') or + command[1] == ord('$'): + result = InputState.Valid elif command == "yt".ru: result = InputState.Continue elif command.len == 3: @@ -1890,6 +1943,8 @@ proc isNormalModeCommand*( cmd == "yl" or cmd == "y{" or cmd == "y}" or + cmd == "y0" or + cmd == "y$" or cmd == "dd" or cmd == "dw" or cmd == "d$" or (cmd.len == 1 and isEndKey(cmd[0].toRune)) or diff --git a/tests/tnormalmode.nim b/tests/tnormalmode.nim index be093b396..df9ed8be0 100644 --- a/tests/tnormalmode.nim +++ b/tests/tnormalmode.nim @@ -1285,7 +1285,7 @@ suite "Normal mode: delete from the beginning of the line to current column": check status.registers.noNameRegisters.buffer[0] == ru"abcde" -suite "Normal mode: Yank string": +suite "Normal mode: Yank characters": test "yank character (yl command)": var status = initEditorStatus() discard status.addNewBufferInCurrentWin.get @@ -1327,6 +1327,98 @@ suite "Normal mode: Yank string": check status.registers.noNameRegisters.buffer[0] == ru"abcde" +suite "Normal mode: yank characters from the begin of the line": + test "y0 command": + var status = initEditorStatus() + discard status.addNewBufferInCurrentWin.get + currentBufStatus.buffer = initGapBuffer(@[ru"abcde"]) + currentMainWindowNode.currentColumn = 2 + + const Command = ru"y0" + check isNormalModeCommand(Command, none(Rune)) == InputState.Valid + check status.normalCommand(Command).isNone + + check status.registers.noNameRegisters.buffer[0] == ru"ab" + + test "Basic 1": + var status = initEditorStatus() + discard status.addNewBufferInCurrentWin.get + currentBufStatus.buffer = initGapBuffer(@[ru"abcde"]) + currentMainWindowNode.currentColumn = 1 + + status.yankCharactersFromBeginOfLine + + check status.registers.noNameRegisters.buffer[0] == ru"a" + + test "Basic 2": + var status = initEditorStatus() + discard status.addNewBufferInCurrentWin.get + currentBufStatus.buffer = initGapBuffer(@[ru"abcde"]) + currentMainWindowNode.currentColumn = 4 + + status.yankCharactersFromBeginOfLine + + check status.registers.noNameRegisters.buffer[0] == ru"abcd" + + test "currentColumn == 0": + var status = initEditorStatus() + discard status.addNewBufferInCurrentWin.get + currentBufStatus.buffer = initGapBuffer(@[ru"abcde"]) + + status.yankCharactersFromBeginOfLine + + check status.registers.noNameRegisters.buffer.len == 0 + + test "Empty line": + var status = initEditorStatus() + discard status.addNewBufferInCurrentWin.get + currentBufStatus.buffer = initGapBuffer(@[ru""]) + + status.yankCharactersFromBeginOfLine + + check status.registers.noNameRegisters.buffer.len == 0 + +suite "Normal mode: yank characters to the end of the line": + test "y$ command": + var status = initEditorStatus() + discard status.addNewBufferInCurrentWin.get + currentBufStatus.buffer = initGapBuffer(@[ru"abcde"]) + currentMainWindowNode.currentColumn = 2 + + const Command = ru"y$" + check isNormalModeCommand(Command, none(Rune)) == InputState.Valid + check status.normalCommand(Command).isNone + + check status.registers.noNameRegisters.buffer[0] == ru"cde" + + test "Basic 1": + var status = initEditorStatus() + discard status.addNewBufferInCurrentWin.get + currentBufStatus.buffer = initGapBuffer(@[ru"abcde"]) + + status.yankCharactersToEndOfLine + + check status.registers.noNameRegisters.buffer[0] == ru"abcde" + + test "Basic 2": + var status = initEditorStatus() + discard status.addNewBufferInCurrentWin.get + currentBufStatus.buffer = initGapBuffer(@[ru"abcde"]) + currentMainWindowNode.currentColumn = 4 + + status.yankCharactersToEndOfLine + + check status.registers.noNameRegisters.buffer[0] == ru"e" + + test "Empty line": + var status = initEditorStatus() + discard status.addNewBufferInCurrentWin.get + currentBufStatus.buffer = initGapBuffer(@[ru""]) + + status.yankCharactersToEndOfLine + + check status.registers.noNameRegisters.buffer.len == 0 + suite "Normal mode: Cut character before cursor": test "Cut character before cursor (X command)": var status = initEditorStatus()