diff --git a/documents/howtouse.md b/documents/howtouse.md
index 30cc2bce4..0c1c52de5 100644
--- a/documents/howtouse.md
+++ b/documents/howtouse.md
@@ -60,7 +60,7 @@
| **Z** **Z**
Write current file and exit | **Z** **Q**
Same as `:q!` | **Ctrl** **w** **c**
Close current window | **?**
`keyword` Search backwards |
| **/**
`keyword` Search forwards | **\\** **r**
Quick Run | **s** OR **c****u**
Delete current charater and enter insert mode | **y****{**
Yank to the previous blank line |
| **y****}**
Yank to the next blank line | **y****l**
Yank a character| **X** OR **d****h**
Cut a character before cursor | **g****a**
Show current character info |
-| **t****x**
Move to the left of the next ```x``` (any character) on the current line | **T****x**
Move to the right of the back ```x ``` (any character) on the current line |
+| **t****x**
Move to the left of the next ```x``` (any character) on the current line | **T****x**
Move to the right of the back ```x ``` (any character) on the current line | **y****t**
**Any key**
Yank characters to an any character |
diff --git a/src/moepkg/help.nim b/src/moepkg/help.nim
index 89734c1cd..b5eada04c 100644
--- a/src/moepkg/help.nim
+++ b/src/moepkg/help.nim
@@ -52,6 +52,7 @@ yy or Y - Copy a line
y{ - Yank to the previous blank line
y} - Yank to the next blank line
yl - Yank a character
+yt any - Ynak characters to a any character
p - Paste the clipboard
n - Search forwards
: - Start Ex mode
diff --git a/src/moepkg/normalmode.nim b/src/moepkg/normalmode.nim
index 61753a4e3..b10654eec 100644
--- a/src/moepkg/normalmode.nim
+++ b/src/moepkg/normalmode.nim
@@ -464,6 +464,55 @@ proc yankCharacters(status: var Editorstatus, registerName: string) =
registerName,
isDelete)
+# yt command
+proc yankCharactersToCharacter(status: var EditorStatus,
+ rune: Rune) =
+
+ let
+ currentColumn = currentMainWindowNode.currentColumn
+ # Get the position of a character
+ position = currentBufStatus.searchOneCharacterToEndOfLine(
+ currentMainWindowNode,
+ rune)
+
+ if position > currentColumn:
+ const
+ isDelete = false
+ registerName = ""
+ currentBufStatus.yankCharacters(
+ status.registers,
+ currentMainWindowNode,
+ status.commandLine,
+ status.messageLog,
+ status.settings,
+ position,
+ registerName,
+ isDelete)
+
+# yt command
+proc yankCharactersToCharacter(status: var EditorStatus,
+ rune: Rune,
+ registerName: string) =
+
+ let
+ currentColumn = currentMainWindowNode.currentColumn
+ # Get the position of a character
+ position = currentBufStatus.searchOneCharacterToEndOfLine(
+ currentMainWindowNode,
+ rune)
+
+ if position > currentColumn:
+ const isDelete = false
+ currentBufStatus.yankCharacters(
+ status.registers,
+ currentMainWindowNode,
+ status.commandLine,
+ status.messageLog,
+ status.settings,
+ position,
+ registerName,
+ isDelete)
+
proc deleteCharacters(status: var EditorStatus, registerName: string) =
if currentBufStatus.isReadonly:
status.commandLine.writeReadonlyModeWarning
@@ -844,6 +893,8 @@ proc addRegister(status: var EditorStatus, command, registerName: string) =
status.deleteCharacterAndEnterInsertMode(registerName)
elif command.len == 3 and command[0 .. 1] == "ci":
status.changeInnerCommand(command[2].toRune, registerName)
+ elif command.len == 3 and command[0 .. 1] == "yt":
+ status.yankCharactersToCharacter(command[2].toRune, registerName)
else:
discard
@@ -899,10 +950,11 @@ proc registerCommand(status: var EditorStatus, command: seq[Rune]) =
cmd == "dgg" or
cmd == "d{" or
cmd == "d}" or
- cmd.len == 3 and cmd[0 .. 1] == "di" or
+ (cmd.len == 3 and cmd[0 .. 1] == "di") or
cmd == "dh" or
cmd == "cl" or cmd == "s" or
- cmd.len == 3 and cmd[0 .. 1] == "ci":
+ (cmd.len == 3 and cmd[0 .. 1] == "ci") or
+ (cmd.len == 3 and cmd[0 .. 1] == "yt"):
status.addRegister(cmd, $registerName)
proc pasteAfterCursor(status: var EditorStatus) {.inline.} =
@@ -1110,6 +1162,9 @@ proc normalCommand(status: var EditorStatus,
status.yankToNextBlankLine
elif secondKey == ord('l'):
status.yankCharacters
+ elif secondKey == ord('t'):
+ let thirdKey = commands[2]
+ status.yankCharactersToCharacter(thirdKey)
elif key == ord('Y'):
status.yankLines
elif key == ord('p'):
@@ -1358,6 +1413,11 @@ proc isNormalModeCommand(command: seq[Rune]): InputState =
command[1] == ord('}') or
command[1] == ord('l'):
result = InputState.Valid
+ elif command == "yt".ru:
+ result = InputState.Continue
+ elif command.len == 3:
+ if command[0 .. 1] == "yt".ru:
+ result = InputState.Valid
elif command[0] == ord('='):
if command.len == 1:
diff --git a/tests/tnormalmode.nim b/tests/tnormalmode.nim
index 5742f5414..f59c76089 100644
--- a/tests/tnormalmode.nim
+++ b/tests/tnormalmode.nim
@@ -1836,3 +1836,83 @@ suite "Normal mode: Move to the right of the back character":
check currentMainWindowNode.currentLine == 0
check currentMainWindowNode.currentColumn == 0
+
+suite "Normal mode: Yank characters to any character":
+ test "Case 1: Yank characters before 'd' (\"ytd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abcd"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "ytd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check not status.registers.noNameRegister.isLine
+ check status.registers.noNameRegister.buffer[0] == ru "abc"
+
+ test "Case 2: Yank characters before 'd' (\"ytd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "ab c d"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "ytd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check not status.registers.noNameRegister.isLine
+ check status.registers.noNameRegister.buffer[0] == ru "ab c "
+
+ test "Case 1: Do nothing (\"ytd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abc"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "ytd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check status.registers.noNameRegister.buffer.len == 0
+
+ test "Case 2: Do nothing (\"ytd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abcd efg"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+ currentMainWindowNode.currentColumn = 3
+
+ const command = ru "ytd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check status.registers.noNameRegister.buffer.len == 0
+
+ test "Case 3: Do nothing (\"ytd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abcd efg"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+ currentMainWindowNode.currentColumn = buffer.high
+
+ const command = ru "ytd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check status.registers.noNameRegister.buffer.len == 0