From efef0ef5b2d12e11d0edcc839babe28670300208 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 14 Dec 2023 18:20:24 +0000 Subject: [PATCH] Experimental ^K change of behaviour. If you press ^K to delete to end of line and you're in mid-paragraph, I think not a bad answer is to _insert_ a paragraph break, so that the text on the next line doesn't unexpectedly wrap. This is intuitively as close as possible to the behaviour in the non-auto-wrapping 'me'. The only thing I don't like about it is that pasting the text back in again with ^Y doesn't delete the line break, but I haven't thought of a less astonishing answer to that yet. --- cursesclient.py | 51 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/cursesclient.py b/cursesclient.py index 7c7d45b..87f64de 100644 --- a/cursesclient.py +++ b/cursesclient.py @@ -880,19 +880,6 @@ class EditorCommon: self.point += 1 if self.word_boundary(self.point): break - elif ch in {ctrl('k')}: - if self.point < len(self.text): - if self.text[self.point] == '\n': - self.text = (self.text[:self.point] + - self.text[self.point+1:]) - else: - try: - endpos = self.text.index('\n', self.point) - except ValueError: - endpos = len(self.text) - self.ctrl_k_paste_buffer = self.text[self.point:endpos] - self.text = (self.text[:self.point] + - self.text[endpos:]) elif ch in {ctrl('y')}: self.text = ( self.text[:self.point] + self.ctrl_k_paste_buffer + @@ -936,6 +923,10 @@ class BottomLinePrompt(Activity, EditorCommon): self.move_to(0) elif ch in {ctrl('e'), curses.KEY_END}: self.move_to(len(self.text)) + elif ch in {ctrl('k')}: + if self.point < len(self.text): + self.ctrl_k_paste_buffer = self.text[self.point:] + self.text = (self.text[:self.point]) elif ch in {'\r', '\n'}: self.callback(self.text) self.chain_to(self.parent_activity) @@ -1201,6 +1192,26 @@ class Composer(Activity, EditorCommon): self.point) if yx[0] == self.cy) self.move_to(new_point) + elif ch in {ctrl('k')}: + if self.point < len(self.text): + line_end = util.last( + i for i, yx in enumerate(self.dtext.yx[self.point:], + self.point) + if yx[0] == self.cy) + end_of_para = self.text[line_end:line_end+1] in {'', '\n'} + if not end_of_para and line_end < len(self.text): + line_end += 1 + + if line_end == self.point: + if end_of_para: + self.text = (self.text[:self.point] + + self.text[self.point+1:]) + else: + self.ctrl_k_paste_buffer = self.text[ + self.point:line_end] + self.text = (self.text[:self.point] + + ("\n" if not end_of_para else "") + + self.text[line_end:]) elif ch in {'\r', '\n'}: self.text = (self.text[:self.point] + '\n' + self.text[self.point:]) @@ -1397,6 +1408,20 @@ class testComposerLayout(unittest.TestCase): t.handle_key(ctrl('k')) self.assertEqual(t.text, "abc def ghi jklmno pqr stu vwx") + # On a non-final line of a paragraph: delete up to the next + # line break, and _insert_ a newline. (Logically weird but + # intuitive in use, given that 'me' would leave a miswrapped + # paragraph) + t = setup(4) + t.handle_key(ctrl('k')) + self.assertEqual(t.text, "abc \nghi jkl\nmno pqr stu vwx") + + # If you're at the very end of the non-final line, this + # translates to _just_ replacing a space with a newline. + t = setup(7) + t.handle_key(ctrl('k')) + self.assertEqual(t.text, "abc def\nghi jkl\nmno pqr stu vwx") + # At the very end of the buffer: do nothing, including not # crashing t = setup(31) -- 2.30.2