diff --git a/documents/howtouse.md b/documents/howtouse.md
index 0c1c52de5..e0212bbc4 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 | **y****t**
**Any key**
Yank characters to an any character |
+| **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 | **c****f**
**Any key**
Delete characters to an any character and enter insert mode |
diff --git a/src/moepkg/help.nim b/src/moepkg/help.nim
index b5eada04c..c63b03e35 100644
--- a/src/moepkg/help.nim
+++ b/src/moepkg/help.nim
@@ -72,6 +72,7 @@ ciw - Delete the current word and enter insert mode
ci( or ci) - Delete the inside of round brackets and enter insert mode
ci[ or ci] - Delete the inside of square brackets and enter insert mode
ci{ or ci} - Delete the inside of curly brackets and enter insert mode
+cf any - Delete characters to the any character and enter insert mode
di" - Delete the inside of double quotes
di' - Delete the inside of single quotes
diw - Delete the current word
diff --git a/src/moepkg/normalmode.nim b/src/moepkg/normalmode.nim
index b10654eec..5df835831 100644
--- a/src/moepkg/normalmode.nim
+++ b/src/moepkg/normalmode.nim
@@ -770,6 +770,35 @@ proc deleteCharactersAfterBlankInLine(status: var EditorStatus) =
registerName,
status.settings)
+# cf command
+proc deleteCharactersToCharacterAndEnterInsertMode(status: var EditorStatus,
+ rune: Rune,
+ registerName: string) =
+
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
+ let
+ currentColumn = currentMainWindowNode.currentColumn
+ # Get the position of a character
+ position = currentBufStatus.searchOneCharacterToEndOfLine(
+ currentMainWindowNode,
+ rune)
+
+ if position > currentColumn:
+ currentBufStatus.cmdLoop = position - currentColumn + 1
+ status.deleteCharacters
+
+ status.changeMode(Mode.insert)
+
+# cf command
+proc deleteCharactersToCharacterAndEnterInsertMode(status: var EditorStatus,
+ rune: Rune) =
+
+ const registerName = ""
+ status.deleteCharactersToCharacterAndEnterInsertMode(rune, registerName)
+
proc enterInsertModeAfterCursor(status: var EditorStatus) =
if currentBufStatus.isReadonly:
status.commandLine.writeReadonlyModeWarning
@@ -895,6 +924,10 @@ proc addRegister(status: var EditorStatus, command, registerName: string) =
status.changeInnerCommand(command[2].toRune, registerName)
elif command.len == 3 and command[0 .. 1] == "yt":
status.yankCharactersToCharacter(command[2].toRune, registerName)
+ elif command.len == 3 and command[0 .. 1] == "cf":
+ status.deleteCharactersToCharacterAndEnterInsertMode(
+ command[2].toRune,
+ registerName)
else:
discard
@@ -954,7 +987,8 @@ proc registerCommand(status: var EditorStatus, command: seq[Rune]) =
cmd == "dh" or
cmd == "cl" or cmd == "s" or
(cmd.len == 3 and cmd[0 .. 1] == "ci") or
- (cmd.len == 3 and cmd[0 .. 1] == "yt"):
+ (cmd.len == 3 and cmd[0 .. 1] == "yt") or
+ (cmd.len == 3 and cmd[0 .. 1] == "cf"):
status.addRegister(cmd, $registerName)
proc pasteAfterCursor(status: var EditorStatus) {.inline.} =
@@ -1111,13 +1145,16 @@ proc normalCommand(status: var EditorStatus,
if secondKey == ord('c'):
status.deleteCharactersAfterBlankInLine
status.enterInsertModeAfterCursor
- if secondKey == ord('l'):
+ elif secondKey == ord('l'):
status.deleteCharacterAndEnterInsertMode
elif secondKey == ord('i'):
let thirdKey = commands[2]
if isParen(thirdKey) or
thirdKey == ord('w'):
status.changeInnerCommand(thirdKey)
+ elif secondKey == ord('f'):
+ let thirdKey = commands[2]
+ status.deleteCharactersToCharacterAndEnterInsertMode(thirdKey)
elif key == ord('d'):
let secondKey = commands[1]
if secondKey == ord('d'):
@@ -1371,15 +1408,16 @@ proc isNormalModeCommand(command: seq[Rune]): InputState =
if command.len == 1:
result = InputState.Continue
elif command.len == 2:
- if command[1] == ord('i'):
+ if command[1] == ord('i') or
+ command[1] == ord('f'):
result = InputState.Continue
elif command[1] == ord('c') or command[1] == ('l'):
result = InputState.Valid
elif command.len == 3:
- if command[1] == ord('i'):
- if isParen(command[2]) or
- command[2] == ord('w'):
- result = InputState.Valid
+ if command[1] == ord('f') or
+ (command[1] == ord('i') and
+ (isParen(command[2]) or command[2] == ord('w'))):
+ result = InputState.Valid
elif command[0] == ord('d'):
if command.len == 1:
diff --git a/tests/tnormalmode.nim b/tests/tnormalmode.nim
index f59c76089..3d858209f 100644
--- a/tests/tnormalmode.nim
+++ b/tests/tnormalmode.nim
@@ -1916,3 +1916,39 @@ suite "Normal mode: Yank characters to any character":
check currentBufStatus.buffer[0] == buffer
check status.registers.noNameRegister.buffer.len == 0
+
+suite "Normal mode: Delete characters to any characters and Enter insert mode":
+ test "Case 1: Delete characters to 'd' and enter insert mode (\"cfd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abcd"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "cfd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru ""
+
+ check not status.registers.noNameRegister.isLine
+ check status.registers.noNameRegister.buffer[0] == ru "abcd"
+
+ check currentBufStatus.mode == Mode.insert
+
+ test "Case 1: Do nothing (\"cfz\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abcd"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "cfz"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check status.registers.noNameRegister.buffer.len == 0
+
+ check currentBufStatus.mode == Mode.normal