diff options
| author | Maxime Coste <mawww@kakoune.org> | 2021-07-14 20:37:18 +1000 |
|---|---|---|
| committer | Maxime Coste <mawww@kakoune.org> | 2021-07-14 20:51:25 +1000 |
| commit | c643cd446712a9f9db05081786b5bc0daf2a96d7 (patch) | |
| tree | 3e8bf0f219b59a211e48529774deed3e0a737019 /src | |
| parent | ac6420ee8d3a1395d358aa6f6b860e2405906c07 (diff) | |
Fix blitting of windows halfway through double-width codepoint
Display a whitespace in place of the uncovered half of the codepoint.
(I know this is incorrect and we should be considering grapheme clusters
instead of codepoints, but this is a far bigger refactoring and another
can of worms to handle with terminal emulators).
Fixes #4262
Diffstat (limited to 'src')
| -rw-r--r-- | src/terminal_ui.cc | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/src/terminal_ui.cc b/src/terminal_ui.cc index fe1da35d..ee451c82 100644 --- a/src/terminal_ui.cc +++ b/src/terminal_ui.cc @@ -51,14 +51,19 @@ struct TerminalUI::Window::Line ColumnCount length() const { return text.column_length() + skip; } void resize(ColumnCount size) { - auto text_len = text.column_length(); - if (size < text_len) + auto it = text.begin(), end = text.end(); + while (it != end and size > 0) + size -= codepoint_width(utf8::read_codepoint(it, end)); + + if (size < 0) // possible if resizing to the middle of a double-width codepoint { - text.resize(text.byte_count_to(size), 0); - skip = 0; + kak_assert(size == -1); + utf8::to_previous(it, text.begin()); + skip = 1; } else - skip = size - text_len; + skip = size; + text.resize(it - text.begin(), 0); } friend bool operator==(const Atom& lhs, const Atom& rhs) { return lhs.text == rhs.text and lhs.skip == rhs.skip and lhs.face == rhs.face; } @@ -111,10 +116,16 @@ struct TerminalUI::Window::Line Pos end = find_col(pos+len); auto make_tail = [](const Atom& atom, ColumnCount from) { - if (atom.text.column_length() > from) - return Atom{atom.text.substr(atom.text.byte_count_to(from)).str(), atom.skip, atom.face}; - else - return Atom{{}, atom.length() - from, atom.face}; + auto it = atom.text.begin(), end = atom.text.end(); + while (it != end and from > 0) + from -= codepoint_width(utf8::read_codepoint(it, end)); + + if (from < 0) // can happen if tail starts in the middle of a double-width codepoint + { + kak_assert(from == -1); + return Atom{" " + StringView{it, end}, atom.skip, atom.face}; + } + return Atom{{it, end}, atom.skip - from, atom.face}; }; if (begin.it == end.it) |
