diff --git a/tools/tui/readline/actions_test.go b/tools/tui/readline/actions_test.go index 29e260c8a..e77f79e2d 100644 --- a/tools/tui/readline/actions_test.go +++ b/tools/tui/readline/actions_test.go @@ -90,52 +90,52 @@ func TestGetScreenLines(t *testing.T) { t.Fatalf("Did not get expected screen lines for: %#v and cursor: %+v\n%s", rl.AllText(), rl.input_state.cursor, diff) } } - tsl(ScreenLine{Prompt: p(true), CursorCell: 3}) + tsl(ScreenLine{Prompt: p(true), CursorCell: 3, AfterLineBreak: true}) rl.add_text("123") - tsl(ScreenLine{Prompt: p(true), CursorCell: 6, Text: "123", CursorTextPos: 3, TextLengthInCells: 3}) + tsl(ScreenLine{Prompt: p(true), CursorCell: 6, Text: "123", CursorTextPos: 3, TextLengthInCells: 3, AfterLineBreak: true}) rl.add_text("456") - tsl(ScreenLine{Prompt: p(true), CursorCell: 9, Text: "123456", CursorTextPos: 6, TextLengthInCells: 6}) + tsl(ScreenLine{Prompt: p(true), CursorCell: 9, Text: "123456", CursorTextPos: 6, TextLengthInCells: 6, AfterLineBreak: true}) rl.add_text("7") tsl( - ScreenLine{Prompt: p(true), CursorCell: -1, Text: "1234567", CursorTextPos: -1, TextLengthInCells: 7}, + ScreenLine{Prompt: p(true), CursorCell: -1, Text: "1234567", CursorTextPos: -1, TextLengthInCells: 7, AfterLineBreak: true}, ScreenLine{OffsetInParentLine: 7}, ) rl.add_text("89") tsl( - ScreenLine{Prompt: p(true), CursorCell: -1, Text: "1234567", CursorTextPos: -1, TextLengthInCells: 7}, + ScreenLine{Prompt: p(true), CursorCell: -1, Text: "1234567", CursorTextPos: -1, TextLengthInCells: 7, AfterLineBreak: true}, ScreenLine{OffsetInParentLine: 7, Text: "89", CursorCell: 2, TextLengthInCells: 2, CursorTextPos: 2}, ) rl.ResetText() rl.add_text("123\n456abcdeXYZ") tsl( - ScreenLine{Prompt: p(true), CursorCell: -1, Text: "123", CursorTextPos: -1, TextLengthInCells: 3}, - ScreenLine{ParentLineNumber: 1, Prompt: p(false), Text: "456abcde", TextLengthInCells: 8, CursorCell: -1, CursorTextPos: -1}, + ScreenLine{Prompt: p(true), CursorCell: -1, Text: "123", CursorTextPos: -1, TextLengthInCells: 3, AfterLineBreak: true}, + ScreenLine{ParentLineNumber: 1, Prompt: p(false), Text: "456abcde", TextLengthInCells: 8, CursorCell: -1, CursorTextPos: -1, AfterLineBreak: true}, ScreenLine{OffsetInParentLine: 8, ParentLineNumber: 1, TextLengthInCells: 3, CursorCell: 3, CursorTextPos: 3, Text: "XYZ"}, ) rl.input_state.cursor = Position{X: 2} tsl( - ScreenLine{Prompt: p(true), CursorCell: 5, Text: "123", CursorTextPos: 2, TextLengthInCells: 3}, - ScreenLine{ParentLineNumber: 1, Prompt: p(false), Text: "456abcde", TextLengthInCells: 8, CursorCell: -1, CursorTextPos: -1}, + ScreenLine{Prompt: p(true), CursorCell: 5, Text: "123", CursorTextPos: 2, TextLengthInCells: 3, AfterLineBreak: true}, + ScreenLine{ParentLineNumber: 1, Prompt: p(false), Text: "456abcde", TextLengthInCells: 8, CursorCell: -1, CursorTextPos: -1, AfterLineBreak: true}, ScreenLine{OffsetInParentLine: 8, ParentLineNumber: 1, TextLengthInCells: 3, CursorCell: -1, CursorTextPos: -1, Text: "XYZ"}, ) rl.input_state.cursor = Position{X: 2, Y: 1} tsl( - ScreenLine{Prompt: p(true), CursorCell: -1, Text: "123", CursorTextPos: -1, TextLengthInCells: 3}, - ScreenLine{ParentLineNumber: 1, Prompt: p(false), Text: "456abcde", TextLengthInCells: 8, CursorCell: 4, CursorTextPos: 2}, + ScreenLine{Prompt: p(true), CursorCell: -1, Text: "123", CursorTextPos: -1, TextLengthInCells: 3, AfterLineBreak: true}, + ScreenLine{ParentLineNumber: 1, Prompt: p(false), Text: "456abcde", TextLengthInCells: 8, CursorCell: 4, CursorTextPos: 2, AfterLineBreak: true}, ScreenLine{OffsetInParentLine: 8, ParentLineNumber: 1, TextLengthInCells: 3, CursorCell: -1, CursorTextPos: -1, Text: "XYZ"}, ) rl.input_state.cursor = Position{X: 8, Y: 1} tsl( - ScreenLine{Prompt: p(true), CursorCell: -1, Text: "123", CursorTextPos: -1, TextLengthInCells: 3}, - ScreenLine{ParentLineNumber: 1, Prompt: p(false), Text: "456abcde", TextLengthInCells: 8, CursorCell: -1, CursorTextPos: -1}, + ScreenLine{Prompt: p(true), CursorCell: -1, Text: "123", CursorTextPos: -1, TextLengthInCells: 3, AfterLineBreak: true}, + ScreenLine{ParentLineNumber: 1, Prompt: p(false), Text: "456abcde", TextLengthInCells: 8, CursorCell: -1, CursorTextPos: -1, AfterLineBreak: true}, ScreenLine{OffsetInParentLine: 8, ParentLineNumber: 1, TextLengthInCells: 3, CursorCell: 0, CursorTextPos: 0, Text: "XYZ"}, ) rl.ResetText() rl.add_text("1234567\nabc") rl.input_state.cursor = Position{X: 7} tsl( - ScreenLine{Prompt: p(true), CursorCell: -1, Text: "1234567", CursorTextPos: -1, TextLengthInCells: 7}, - ScreenLine{ParentLineNumber: 1, Prompt: p(false), Text: "abc", CursorCell: 2, TextLengthInCells: 3, CursorTextPos: 0}, + ScreenLine{Prompt: p(true), CursorCell: -1, Text: "1234567", CursorTextPos: -1, TextLengthInCells: 7, AfterLineBreak: true}, + ScreenLine{ParentLineNumber: 1, Prompt: p(false), Text: "abc", CursorCell: 2, TextLengthInCells: 3, CursorTextPos: 0, AfterLineBreak: true}, ) } diff --git a/tools/tui/readline/draw.go b/tools/tui/readline/draw.go index 66c334f5d..47accc89d 100644 --- a/tools/tui/readline/draw.go +++ b/tools/tui/readline/draw.go @@ -34,6 +34,7 @@ type ScreenLine struct { Prompt Prompt TextLengthInCells, CursorCell, CursorTextPos int Text string + AfterLineBreak bool } func (self *Readline) format_arg_prompt(cna string) string { @@ -101,7 +102,7 @@ func (self *Readline) get_screen_lines() []*ScreenLine { sl := ScreenLine{ ParentLineNumber: i, OffsetInParentLine: offset, Prompt: prompt, TextLengthInCells: width, - CursorCell: -1, Text: l, CursorTextPos: -1, + CursorCell: -1, Text: l, CursorTextPos: -1, AfterLineBreak: is_first, } if cursor_at_start_of_next_line { cursor_at_start_of_next_line = false @@ -148,7 +149,7 @@ func (self *Readline) redraw() { csl, csl_cached := self.completion_screen_lines() render_completion_above := len(csl)+len(prompt_lines) > self.screen_height completion_needs_render := len(csl) > 0 && (!render_completion_above || !self.completions.current.last_rendered_above || !csl_cached) - cursor_x := -1 + final_cursor_x := -1 cursor_y := 0 move_cursor_up_by := 0 @@ -175,32 +176,53 @@ func (self *Readline) redraw() { if render_completion_above { render_completion_lines() } + self.loop.AllowLineWrapping(true) + self.loop.QueueWriteString("\r") + text_length := 0 + for i, sl := range prompt_lines { - self.loop.QueueWriteString("\r") - if i > 0 { - self.loop.QueueWriteString("\n") + cursor_moved_down := false + if i > 0 && sl.AfterLineBreak { + self.loop.QueueWriteString("\r\n") + cursor_moved_down = true + text_length = 0 } if sl.Prompt.Length > 0 { - self.loop.QueueWriteString(self.prompt_for_line_number(i).Text) + p := self.prompt_for_line_number(i) + self.loop.QueueWriteString(p.Text) + text_length += p.Length } self.loop.QueueWriteString(sl.Text) - if sl.CursorCell > -1 { - cursor_x = sl.CursorCell - } else if cursor_x > -1 { - move_cursor_up_by++ + text_length += sl.TextLengthInCells + if text_length == self.screen_width && sl.Text == "" && i == len(prompt_lines)-1 { + self.loop.QueueWriteString("\r\n") + cursor_moved_down = true + text_length = 0 + } + if text_length > self.screen_width { + cursor_moved_down = true + text_length -= self.screen_width + } + if sl.CursorCell > -1 { + final_cursor_x = sl.CursorCell + } else if final_cursor_x > -1 { + if cursor_moved_down { + move_cursor_up_by++ + } + } + if cursor_moved_down { + cursor_y++ } - cursor_y++ } if !render_completion_above { move_cursor_up_by += render_completion_lines() } - self.loop.AllowLineWrapping(true) self.loop.MoveCursorVertically(-move_cursor_up_by) self.loop.QueueWriteString("\r") - self.loop.MoveCursorHorizontally(cursor_x) + self.loop.MoveCursorHorizontally(final_cursor_x) self.cursor_y = 0 cursor_y -= move_cursor_up_by if cursor_y > 0 { - self.cursor_y = cursor_y - 1 + self.cursor_y = cursor_y } }