From 5e5cae83914c792e29f332322c49212381617a9c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 6 Oct 2022 13:54:18 +0530 Subject: [PATCH] Code to move cursor right --- tools/tui/readline/actions.go | 40 ++++++++++++++++++++++++++++++ tools/tui/readline/actions_test.go | 28 +++++++++++++++++++-- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/tools/tui/readline/actions.go b/tools/tui/readline/actions.go index 3d782af94..9f155291c 100644 --- a/tools/tui/readline/actions.go +++ b/tools/tui/readline/actions.go @@ -120,3 +120,43 @@ func (self *Readline) move_cursor_left(amt uint, traverse_line_breaks bool) uint } return amt_moved } + +func (self *Readline) move_cursor_right(amt uint, traverse_line_breaks bool) uint { + var amt_moved uint + for ; amt > 0; amt -= 1 { + line := self.lines[self.cursor_line] + if self.cursor_pos_in_line >= len(line) { + if !traverse_line_breaks || self.cursor_line == len(self.lines)-1 { + return amt_moved + } + self.cursor_line += 1 + self.cursor_pos_in_line = 0 + amt_moved += 1 + continue + } + // This is an extremely inefficient algorithm but it does not matter since + // lines are not large. + before_runes := []rune(line[:self.cursor_pos_in_line]) + after_runes := []rune(line[self.cursor_pos_in_line:]) + orig_width := wcswidth.Stringwidth(line[:self.cursor_pos_in_line]) + current_width := orig_width + for current_width == orig_width && len(after_runes) > 0 { + before_runes = append(before_runes, after_runes[0]) + current_width = wcswidth.Stringwidth(string(before_runes)) + after_runes = after_runes[1:] + } + // soak up any more runes that dont affect width + for len(after_runes) > 0 { + q := append(before_runes, after_runes[0]) + w := wcswidth.Stringwidth(string(q)) + if w != current_width { + break + } + after_runes = after_runes[1:] + before_runes = q + } + self.cursor_pos_in_line = len(string(before_runes)) + amt_moved += 1 + } + return amt_moved +} diff --git a/tools/tui/readline/actions_test.go b/tools/tui/readline/actions_test.go index a1b250f66..2bbeed1cc 100644 --- a/tools/tui/readline/actions_test.go +++ b/tools/tui/readline/actions_test.go @@ -83,7 +83,31 @@ func TestCursorMovement(t *testing.T) { dt("one😀", func(rl *Readline) { left(rl, 1, 1, false) }, "one", "😀") - dt("oneä", func(rl *Readline) { + dt("oneà", func(rl *Readline) { left(rl, 1, 1, false) - }, "one", "ä") + }, "one", "à") + + right := func(rl *Readline, amt uint, moved_amt uint, traverse_line_breaks bool) { + rl.cursor_line = 0 + rl.cursor_pos_in_line = 0 + actual := rl.move_cursor_right(amt, traverse_line_breaks) + if actual != moved_amt { + t.Fatalf("Failed to move cursor by %#v\nactual != expected: %#v != %#v", amt, actual, moved_amt) + } + } + dt("one\ntwo", func(rl *Readline) { + right(rl, 2, 2, false) + }, "on", "e\ntwo") + dt("one\ntwo", func(rl *Readline) { + right(rl, 4, 3, false) + }, "one", "\ntwo") + dt("one\ntwo", func(rl *Readline) { + right(rl, 4, 4, true) + }, "one\n", "two") + dt("😀one", func(rl *Readline) { + right(rl, 1, 1, false) + }, "😀", "one") + dt("àb", func(rl *Readline) { + right(rl, 1, 1, false) + }, "à", "b") }