Dont remove leading and trailing spaces when wrapping

Without this we lose some spaces and also there was a case where the
line could end up longer than the specified width.
This commit is contained in:
Kovid Goyal 2023-03-29 20:41:05 +05:30
parent 7169a89591
commit cb99fbd83c
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 27 additions and 50 deletions

View File

@ -262,23 +262,12 @@ func (self hyperlink_state) as_escape_codes(for_close bool) string {
type line_builder struct { type line_builder struct {
buf []byte buf []byte
last_text_pos, cursor_pos int cursor_pos int
} }
func (self *line_builder) reset() string { func (self *line_builder) reset() string {
ans := string(self.buf) ans := string(self.buf)
if len(ans) > self.last_text_pos {
prefix := ans[:self.last_text_pos]
suffix := ans[self.last_text_pos:]
prefix = strings.TrimRightFunc(prefix, unicode.IsSpace)
if len(prefix) != self.last_text_pos {
ans = prefix + suffix
}
} else {
ans = strings.TrimRightFunc(ans, unicode.IsSpace)
}
self.buf = self.buf[:0] self.buf = self.buf[:0]
self.last_text_pos = 0
self.cursor_pos = 0 self.cursor_pos = 0
return ans return ans
} }
@ -289,13 +278,11 @@ func (self *line_builder) has_space_for_width(w, max_width int) bool {
func (self *line_builder) add_char(ch rune) { func (self *line_builder) add_char(ch rune) {
self.buf = utf8.AppendRune(self.buf, ch) self.buf = utf8.AppendRune(self.buf, ch)
self.last_text_pos = len(self.buf)
self.cursor_pos += wcswidth.Runewidth(ch) self.cursor_pos += wcswidth.Runewidth(ch)
} }
func (self *line_builder) add_word(word []byte, width int) { func (self *line_builder) add_word(word []byte, width int) {
self.buf = append(self.buf, word...) self.buf = append(self.buf, word...)
self.last_text_pos = len(self.buf)
self.cursor_pos += width self.cursor_pos += width
} }
@ -351,27 +338,6 @@ func (self *word_builder) recalculate_width() {
self.wcswidth.Parse(self.buf) self.wcswidth.Parse(self.buf)
} }
func (self *word_builder) trim_leading_spaces() {
if self.is_empty() {
return
}
s := utils.UnsafeBytesToString(self.buf)
var before, after string
if self.text_start_position != 0 {
before, after = s[:self.text_start_position-1], s[self.text_start_position-1:]
} else {
after = s
}
q := strings.TrimLeftFunc(after, unicode.IsSpace)
if q != after {
self.buf = make([]byte, 0, len(s))
self.buf = append(self.buf, before...)
self.buf = append(self.buf, q...)
self.text_start_position = len(before) + 1
self.recalculate_width()
}
}
func (self *word_builder) add_rune(ch rune) (num_bytes_written int) { func (self *word_builder) add_rune(ch rune) (num_bytes_written int) {
before := len(self.buf) before := len(self.buf)
self.buf = utf8.AppendRune(self.buf, ch) self.buf = utf8.AppendRune(self.buf, ch)
@ -433,7 +399,6 @@ func (self *wrapper) print_word() {
w := self.current_word.width() w := self.current_word.width()
if !self.current_line.has_space_for_width(w, self.width) { if !self.current_line.has_space_for_width(w, self.width) {
self.end_current_line() self.end_current_line()
self.current_word.trim_leading_spaces()
w = self.current_word.width() w = self.current_word.width()
} }
for _, e := range self.current_word.escape_codes { for _, e := range self.current_word.escape_codes {
@ -454,6 +419,9 @@ func (self *wrapper) handle_rune(ch rune) error {
self.end_current_line() self.end_current_line()
} else if self.current_word.has_text() && ch != 0xa0 && unicode.IsSpace(ch) { } else if self.current_word.has_text() && ch != 0xa0 && unicode.IsSpace(ch) {
self.print_word() self.print_word()
if self.current_line.cursor_pos >= self.width {
self.end_current_line()
}
self.current_line.add_char(ch) self.current_line.add_char(ch)
} else { } else {
num_of_bytes_written := self.current_word.add_rune(ch) num_of_bytes_written := self.current_word.add_rune(ch)

View File

@ -8,29 +8,38 @@ import (
) )
func TestFormatWithIndent(t *testing.T) { func TestFormatWithIndent(t *testing.T) {
indent := "__"
screen_width := 11 screen_width, indent := 0, ""
tx := func(text string, expected ...string) { tx := func(text string, expected ...string) {
q := indent + strings.Join(expected, "") q := indent + strings.Join(expected, "")
actual := WrapText(text, indent, screen_width) actual := WrapText(text, indent, screen_width)
if actual != q { if actual != q {
t.Fatalf("%#v\nexpected: %#v\nactual: %#v", text, q, actual) t.Fatalf("\nFailed for: %#v\nexpected: %#v\nactual: %#v", text, q, actual)
} }
} }
indent = ""
screen_width = 4
tx("one two", "one \ntwo")
tx("a b", "a b")
screen_width = 3
tx("one tw", "one\n tw")
indent = "__"
screen_width = 11
tx("testing\n\ntwo", "testing\n\n__two") tx("testing\n\ntwo", "testing\n\n__two")
tx("testing\n \ntwo", "testing\n\n__two") tx("testing\n \ntwo", "testing\n__ \n__two")
a := strings.Repeat("a", screen_width-len(indent)-1) a := strings.Repeat("a", screen_width-len(indent)-1)
tx(a+" b", a+"\n__b") tx(a+" b", a+" \n__b")
tx("123456 \x1b[31m789a", "123456\n__\x1b[31m789a") tx("123456 \x1b[31m789a", "123456 \n__\x1b[31m789a")
tx("12 \x1b[31m789 abcd", "12 \x1b[31m789\n\x1b[39m__\x1b[31mabcd") tx("12 \x1b[31m789 abcd", "12 \x1b[31m789 \n\x1b[39m__\x1b[31mabcd")
tx("bb \x1b]8;;http://xyz.com\x1b\\text\x1b]8;;\x1b\\ two", "bb \x1b]8;;http://xyz.com\x1b\\text\x1b]8;;\x1b\\\n__two") tx("bb \x1b]8;;http://xyz.com\x1b\\text\x1b]8;;\x1b\\ two", "bb \x1b]8;;http://xyz.com\x1b\\text\x1b]8;;\x1b\\ \n__two")
tx("\x1b[31maaaaaa \x1b[39mbbbbbb", "\x1b[31maaaaaa\n\x1b[39m__\x1b[31m\x1b[39mbbbbbb") tx("\x1b[31maaaaaa \x1b[39mbbbbbb", "\x1b[31maaaaaa \n\x1b[39m__\x1b[31m\x1b[39mbbbbbb")
tx( tx(
"\x1b[31;4:3m\x1b]8;;XXX\x1b\\combined using\x1b]8;;\x1b\\ operators", "\x1b[31;4:3m\x1b]8;;XXX\x1b\\combined using\x1b]8;;\x1b\\ operators",
"\x1b[31;4:3m\x1b]8;;XXX\x1b\\combined\n\x1b[4:0;39m\x1b]8;;\x1b\\__\x1b[4:3;31m\x1b]8;;XXX\x1b\\using\x1b]8;;\x1b\\\n\x1b[4:0;39m__\x1b[4:3;31moperators") "\x1b[31;4:3m\x1b]8;;XXX\x1b\\combined \n\x1b[4:0;39m\x1b]8;;\x1b\\__\x1b[4:3;31m\x1b]8;;XXX\x1b\\using\x1b]8;;\x1b\\ \n\x1b[4:0;39m__\x1b[4:3;31moperators")
indent = "" indent = ""
screen_width = 3 screen_width = 3
tx("one", "one") tx("one", "one")
@ -41,6 +50,6 @@ func TestFormatWithIndent(t *testing.T) {
screen_width = 8 screen_width = 8
tx( tx(
"\x1b[1mbold\x1b[221m no more bold", "\x1b[1mbold\x1b[221m no more bold",
"\x1b[1mbold\x1b[221m no\nmore\nbold", "\x1b[1mbold\x1b[221m no \nmore \nbold",
) )
} }