diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index e272582..afd40db 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -34,24 +34,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -156,7 +142,7 @@
1764457173148
-
+
diff --git a/Command.cc b/Command.cc
index 3c59460..8eb47e8 100644
--- a/Command.cc
+++ b/Command.cc
@@ -720,6 +720,80 @@ cmd_delete_char(CommandContext &ctx)
}
+static bool
+cmd_kill_to_eol(CommandContext &ctx)
+{
+ Buffer *buf = ctx.editor.CurrentBuffer();
+ if (!buf) {
+ ctx.editor.SetStatus("No buffer to edit");
+ return false;
+ }
+ ensure_at_least_one_line(*buf);
+ auto &rows = buf->Rows();
+ std::size_t y = buf->Cury();
+ std::size_t x = buf->Curx();
+ int repeat = ctx.count > 0 ? ctx.count : 1;
+ for (int i = 0; i < repeat; ++i) {
+ if (y >= rows.size())
+ break;
+ if (x < rows[y].size()) {
+ // delete from cursor to end of line
+ rows[y].erase(x);
+ } else if (y + 1 < rows.size()) {
+ // at EOL: delete the newline (join with next line)
+ rows[y] += rows[y + 1];
+ rows.erase(rows.begin() + static_cast(y + 1));
+ } else {
+ // nothing to delete
+ break;
+ }
+ }
+ buf->SetDirty(true);
+ ensure_cursor_visible(ctx.editor, *buf);
+ return true;
+}
+
+
+static bool
+cmd_kill_line(CommandContext &ctx)
+{
+ Buffer *buf = ctx.editor.CurrentBuffer();
+ if (!buf) {
+ ctx.editor.SetStatus("No buffer to edit");
+ return false;
+ }
+ ensure_at_least_one_line(*buf);
+ auto &rows = buf->Rows();
+ std::size_t y = buf->Cury();
+ std::size_t x = buf->Curx();
+ (void)x; // cursor x will be reset to 0
+ int repeat = ctx.count > 0 ? ctx.count : 1;
+ for (int i = 0; i < repeat; ++i) {
+ if (rows.empty())
+ break;
+ if (rows.size() == 1) {
+ // last remaining line: clear its contents
+ rows[0].clear();
+ y = 0;
+ } else if (y < rows.size()) {
+ // erase current line; keep y pointing at the next line
+ rows.erase(rows.begin() + static_cast(y));
+ if (y >= rows.size()) {
+ // deleted last line; move to previous
+ y = rows.size() - 1;
+ }
+ } else {
+ // out of range
+ y = rows.empty() ? 0 : rows.size() - 1;
+ }
+ }
+ buf->SetCursor(0, y);
+ buf->SetDirty(true);
+ ensure_cursor_visible(ctx.editor, *buf);
+ return true;
+}
+
+
// --- Navigation ---
// (helper removed)
@@ -1208,6 +1282,8 @@ InstallDefaultCommands()
CommandRegistry::Register({CommandId::Newline, "newline", "Insert newline at cursor", cmd_newline});
CommandRegistry::Register({CommandId::Backspace, "backspace", "Delete char before cursor", cmd_backspace});
CommandRegistry::Register({CommandId::DeleteChar, "delete-char", "Delete char at cursor", cmd_delete_char});
+ CommandRegistry::Register({CommandId::KillToEOL, "kill-to-eol", "Delete to end of line", cmd_kill_to_eol});
+ CommandRegistry::Register({CommandId::KillLine, "kill-line", "Delete entire line", cmd_kill_line});
// Navigation
CommandRegistry::Register({CommandId::MoveLeft, "left", "Move cursor left", cmd_move_left});
CommandRegistry::Register({CommandId::MoveRight, "right", "Move cursor right", cmd_move_right});
diff --git a/Command.h b/Command.h
index 6d37725..0e796c7 100644
--- a/Command.h
+++ b/Command.h
@@ -29,6 +29,8 @@ enum class CommandId {
Newline, // insert a newline at cursor
Backspace, // delete char before cursor (may join lines)
DeleteChar, // delete char at cursor (may join lines)
+ KillToEOL, // delete from cursor to end of line; if at EOL, delete newline
+ KillLine, // delete the entire current line (including newline)
// Navigation (basic)
MoveLeft,
MoveRight,
diff --git a/GUIInputHandler.cc b/GUIInputHandler.cc
index e46532b..3871f1c 100644
--- a/GUIInputHandler.cc
+++ b/GUIInputHandler.cc
@@ -62,6 +62,33 @@ map_key(const SDL_Keycode key, const SDL_Keymod mod, bool &k_prefix, MappedInput
break;
}
+ // If we are in k-prefix, the very next key must be interpreted via the
+ // C-k keymap first, even if Control is held (e.g., C-k C-d).
+ if (k_prefix) {
+ k_prefix = false;
+ // Normalize SDL key to ASCII where possible
+ int ascii_key = 0;
+ if (key >= SDLK_SPACE && key <= SDLK_z) {
+ ascii_key = static_cast(key);
+ }
+ bool ctrl2 = (mod & KMOD_CTRL) != 0;
+ if (ascii_key != 0) {
+ ascii_key = KLowerAscii(ascii_key);
+ CommandId id;
+ if (KLookupKCommand(ascii_key, ctrl2, id)) {
+ out = {true, id, "", 0};
+ return true;
+ }
+ // Unknown k-command: report the typed character
+ char c = (ascii_key >= 0x20 && ascii_key <= 0x7e) ? static_cast(ascii_key) : '?';
+ std::string arg(1, c);
+ out = {true, CommandId::UnknownKCommand, arg, 0};
+ return true;
+ }
+ out.hasCommand = false;
+ return true;
+ }
+
if (is_ctrl) {
if (key == SDLK_k || key == SDLK_KP_EQUALS) {
k_prefix = true;
@@ -91,30 +118,7 @@ map_key(const SDL_Keycode key, const SDL_Keymod mod, bool &k_prefix, MappedInput
}
}
- if (k_prefix) {
- k_prefix = false;
- // Normalize SDL key to ASCII where possible
- int ascii_key = 0;
- if (key >= SDLK_SPACE && key <= SDLK_z) {
- ascii_key = static_cast(key);
- }
- bool ctrl2 = (mod & KMOD_CTRL) != 0;
- if (ascii_key != 0) {
- ascii_key = KLowerAscii(ascii_key);
- CommandId id;
- if (KLookupKCommand(ascii_key, ctrl2, id)) {
- out = {true, id, "", 0};
- return true;
- }
- // Unknown k-command: report the typed character
- char c = (ascii_key >= 0x20 && ascii_key <= 0x7e) ? static_cast(ascii_key) : '?';
- std::string arg(1, c);
- out = {true, CommandId::UnknownKCommand, arg, 0};
- return true;
- }
- out.hasCommand = false;
- return true;
- }
+ // k_prefix handled earlier
return false;
}
diff --git a/KKeymap.cc b/KKeymap.cc
index adc820d..a623de3 100644
--- a/KKeymap.cc
+++ b/KKeymap.cc
@@ -9,6 +9,9 @@ KLookupKCommand(const int ascii_key, const bool ctrl, CommandId &out) -> bool
if (ctrl) {
switch (k) {
+ case 'd':
+ out = CommandId::KillLine;
+ return true; // C-k C-d
case 'x':
out = CommandId::SaveAndQuit;
return true; // C-k C-x
@@ -20,6 +23,9 @@ KLookupKCommand(const int ascii_key, const bool ctrl, CommandId &out) -> bool
}
} else {
switch (k) {
+ case 'd':
+ out = CommandId::KillToEOL;
+ return true; // C-k d
case 's':
out = CommandId::Save;
return true; // C-k s
@@ -45,6 +51,9 @@ KLookupCtrlCommand(const int ascii_key, CommandId &out) -> bool
{
const int k = KLowerAscii(ascii_key);
switch (k) {
+ case 'd':
+ out = CommandId::DeleteChar; // C-d
+ return true;
case 'n':
out = CommandId::MoveDown;
return true;
diff --git a/TerminalInputHandler.cc b/TerminalInputHandler.cc
index 3033476..e501f0d 100644
--- a/TerminalInputHandler.cc
+++ b/TerminalInputHandler.cc
@@ -105,6 +105,28 @@ map_key_to_command(const int ch, bool &k_prefix, bool &esc_meta, MappedInput &ou
return true;
}
// Generic Control-chord lookup (after handling special prefixes/cancel)
+ // IMPORTANT: if we're in k-prefix, the very next key must be interpreted
+ // via the C-k keymap first, even if it's a Control chord like C-d.
+ if (k_prefix) {
+ k_prefix = false; // consume the prefix for this one key
+ bool ctrl = false;
+ int ascii_key = ch;
+ if (ch >= 1 && ch <= 26) {
+ ctrl = true;
+ ascii_key = 'a' + (ch - 1);
+ }
+ ascii_key = KLowerAscii(ascii_key);
+ CommandId id;
+ if (KLookupKCommand(ascii_key, ctrl, id)) {
+ out = {true, id, "", 0};
+ } else {
+ char c = (ascii_key >= 0x20 && ascii_key <= 0x7e) ? static_cast(ascii_key) : '?';
+ std::string arg(1, c);
+ out = {true, CommandId::UnknownKCommand, arg, 0};
+ }
+ return true;
+ }
+
if (ch >= 1 && ch <= 26) {
int ascii_key = 'a' + (ch - 1);
CommandId id;
@@ -143,29 +165,7 @@ map_key_to_command(const int ch, bool &k_prefix, bool &esc_meta, MappedInput &ou
return true;
}
- if (k_prefix) {
- k_prefix = false; // single next key only
- // Determine if this is a control chord (e.g., C-x) and normalize
- bool ctrl = false;
- int ascii_key = ch;
- if (ch >= 1 && ch <= 26) {
- ctrl = true;
- ascii_key = 'a' + (ch - 1);
- }
- // For letters, normalize to lowercase ASCII
- ascii_key = KLowerAscii(ascii_key);
-
- CommandId id;
- if (KLookupKCommand(ascii_key, ctrl, id)) {
- out = {true, id, "", 0};
- } else {
- // Show unknown k-command message with the typed character
- char c = (ascii_key >= 0x20 && ascii_key <= 0x7e) ? static_cast(ascii_key) : '?';
- std::string arg(1, c);
- out = {true, CommandId::UnknownKCommand, arg, 0};
- }
- return true;
- }
+ // k_prefix handled earlier
// Printable ASCII
if (ch >= 0x20 && ch <= 0x7E) {