diff --git a/CHANGELOG.md b/CHANGELOG.md
index f300262eba..14864e433c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -46,6 +46,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- BREAKING: `AppFocus` and `AppBlur` are now posted when the terminal window gains or loses focus, if the terminal supports this https://github.com/Textualize/textual/pull/4265
- When the terminal window loses focus, the currently-focused widget will also lose focus.
- When the terminal window regains focus, the previously-focused widget will regain focus.
+- TextArea binding for ctrl+k will now delete the line if the line is empty https://github.com/Textualize/textual/issues/4277
## [0.52.1] - 2024-02-20
diff --git a/src/textual/widgets/_text_area.py b/src/textual/widgets/_text_area.py
index 61042474fd..dc2ea49d44 100644
--- a/src/textual/widgets/_text_area.py
+++ b/src/textual/widgets/_text_area.py
@@ -219,7 +219,12 @@ class TextArea(ScrollView):
Binding(
"ctrl+u", "delete_to_start_of_line", "delete to line start", show=False
),
- Binding("ctrl+k", "delete_to_end_of_line", "delete to line end", show=False),
+ Binding(
+ "ctrl+k",
+ "delete_to_end_of_line_or_delete_line",
+ "delete to line end",
+ show=False,
+ ),
Binding("ctrl+z", "undo", "Undo", show=False),
Binding("ctrl+y", "redo", "Redo", show=False),
]
@@ -2112,6 +2117,26 @@ def action_delete_to_end_of_line(self) -> None:
to_location = self.get_cursor_line_end_location()
self._delete_via_keyboard(from_location, to_location)
+ async def action_delete_to_end_of_line_or_delete_line(self) -> None:
+ """Deletes from the cursor location to the end of the line, or deletes the line.
+
+ The line will be deleted if the line is empty.
+ """
+ # Assume we're just going to delete to the end of the line.
+ action = "delete_to_end_of_line"
+ if self.get_cursor_line_start_location() == self.get_cursor_line_end_location():
+ # The line is empty, so we'll simply remove the line itself.
+ action = "delete_line"
+ elif (
+ self.selection.start
+ == self.selection.end
+ == self.get_cursor_line_end_location()
+ ):
+ # We're at the end of the line, so the kill delete operation
+ # should join the next line to this.
+ action = "delete_right"
+ await self.run_action(action)
+
def action_delete_word_left(self) -> None:
"""Deletes the word to the left of the cursor and updates the cursor location."""
if self.cursor_at_start_of_text: