From 35559b65ddf107fea2a4dda92fcbd664986976d9 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 22 Sep 2016 20:36:26 +0100 Subject: [PATCH] Support codepoints of variable width Add a ColumnCount type and use it in place of CharCount whenever more appropriate, take column size of codepoints into account for vertical movements and docstring wrapping. Fixes #811 --- src/buffer.cc | 56 ++--- src/buffer.hh | 54 ++--- src/buffer.inl.hh | 20 +- src/buffer_utils.cc | 12 +- src/buffer_utils.hh | 31 ++- src/client.cc | 8 +- src/client.hh | 14 +- src/command_manager.cc | 6 +- src/command_manager.hh | 8 +- src/commands.cc | 4 +- src/coord.hh | 22 +- src/display_buffer.cc | 50 ++-- src/display_buffer.hh | 28 +-- src/highlighters.cc | 60 ++--- src/input_handler.cc | 51 ++-- src/insert_completer.cc | 18 +- src/insert_completer.hh | 4 +- src/json_ui.cc | 10 +- src/json_ui.hh | 8 +- src/keys.cc | 4 +- src/keys.hh | 16 +- src/main.cc | 14 +- src/ncurses_ui.cc | 88 +++---- src/ncurses_ui.hh | 20 +- src/normal.cc | 58 ++--- src/remote.cc | 24 +- src/selection.cc | 38 +-- src/selection.hh | 24 +- src/selectors.cc | 20 +- src/selectors.hh | 10 +- src/string.cc | 19 +- src/string.hh | 33 ++- src/unicode.hh | 5 + src/units.hh | 12 + src/user_interface.hh | 8 +- src/utf8.hh | 224 +++++++++++------- src/window.cc | 64 ++--- src/window.hh | 30 +-- .../811-double-width-codepoints/cmd | 1 + .../regression/811-double-width-codepoints/in | 2 + .../811-double-width-codepoints/selections | 1 + 41 files changed, 639 insertions(+), 540 deletions(-) create mode 100644 test/regression/811-double-width-codepoints/cmd create mode 100644 test/regression/811-double-width-codepoints/in create mode 100644 test/regression/811-double-width-codepoints/selections diff --git a/src/buffer.cc b/src/buffer.cc index 8747ec94..a0a66fd8 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -161,12 +161,12 @@ void Buffer::update_display_name() m_display_name = compact_path(m_name); } -BufferIterator Buffer::iterator_at(ByteCoord coord) const +BufferIterator Buffer::iterator_at(BufferCoord coord) const { return is_end(coord) ? end() : BufferIterator(*this, clamp(coord)); } -ByteCoord Buffer::clamp(ByteCoord coord) const +BufferCoord Buffer::clamp(BufferCoord coord) const { coord.line = Kakoune::clamp(coord.line, 0_line, line_count() - 1); ByteCount max_col = std::max(0_byte, m_lines[coord.line].length() - 1); @@ -174,24 +174,24 @@ ByteCoord Buffer::clamp(ByteCoord coord) const return coord; } -ByteCoord Buffer::offset_coord(ByteCoord coord, CharCount offset) +BufferCoord Buffer::offset_coord(BufferCoord coord, CharCount offset) { StringView line = m_lines[coord.line]; auto target = utf8::advance(&line[coord.column], offset < 0 ? line.begin() : line.end()-1, offset); return {coord.line, (int)(target - line.begin())}; } -ByteCoordAndTarget Buffer::offset_coord(ByteCoordAndTarget coord, LineCount offset) +BufferCoordAndTarget Buffer::offset_coord(BufferCoordAndTarget coord, LineCount offset) { - auto character = coord.target == -1 ? m_lines[coord.line].char_count_to(coord.column) : coord.target; + auto column = coord.target == -1 ? m_lines[coord.line].column_count_to(coord.column) : coord.target; auto line = Kakoune::clamp(coord.line + offset, 0_line, line_count()-1); StringView content = m_lines[line]; - character = std::max(0_char, std::min(character, content.char_length() - 2)); - return {line, content.byte_count_to(character), character}; + column = std::max(0_col, std::min(column, content.column_length() - 2)); + return {line, content.byte_count_to(column), column}; } -String Buffer::string(ByteCoord begin, ByteCoord end) const +String Buffer::string(BufferCoord begin, BufferCoord end) const { String res; for (auto line = begin.line; line <= end.line and line < line_count(); ++line) @@ -213,10 +213,10 @@ struct Buffer::Modification enum Type { Insert, Erase }; Type type; - ByteCoord coord; + BufferCoord coord; StringDataPtr content; - Modification(Type type, ByteCoord coord, StringDataPtr content) + Modification(Type type, BufferCoord coord, StringDataPtr content) : type(type), coord(coord), content(std::move(content)) {} Modification inverse() const @@ -441,7 +441,7 @@ void Buffer::check_invariant() const #endif } -ByteCoord Buffer::do_insert(ByteCoord pos, StringView content) +BufferCoord Buffer::do_insert(BufferCoord pos, StringView content) { kak_assert(is_valid(pos)); @@ -484,13 +484,13 @@ ByteCoord Buffer::do_insert(ByteCoord pos, StringView content) std::make_move_iterator(new_lines.end())); const LineCount last_line = pos.line + new_lines.size() - 1; - const ByteCoord end = ByteCoord{ last_line, m_lines[last_line].length() - suffix.length() }; + const BufferCoord end = BufferCoord{ last_line, m_lines[last_line].length() - suffix.length() }; m_changes.push_back({ Change::Insert, at_end, pos, end }); return pos; } -ByteCoord Buffer::do_erase(ByteCoord begin, ByteCoord end) +BufferCoord Buffer::do_erase(BufferCoord begin, BufferCoord end) { kak_assert(is_valid(begin)); kak_assert(is_valid(end)); @@ -498,7 +498,7 @@ ByteCoord Buffer::do_erase(ByteCoord begin, ByteCoord end) StringView suffix = m_lines[end.line].substr(end.column); String new_line = prefix + suffix; - ByteCoord next; + BufferCoord next; if (new_line.length() != 0) { m_lines.erase(m_lines.begin() + (int)begin.line, m_lines.begin() + (int)end.line); @@ -508,7 +508,7 @@ ByteCoord Buffer::do_erase(ByteCoord begin, ByteCoord end) else { m_lines.erase(m_lines.begin() + (int)begin.line, m_lines.begin() + (int)end.line + 1); - next = is_end(begin) ? end_coord() : ByteCoord{begin.line, 0}; + next = is_end(begin) ? end_coord() : BufferCoord{begin.line, 0}; } m_changes.push_back({ Change::Erase, is_end(begin), begin, end }); @@ -518,7 +518,7 @@ ByteCoord Buffer::do_erase(ByteCoord begin, ByteCoord end) void Buffer::apply_modification(const Modification& modification) { StringView content = modification.content->strview(); - ByteCoord coord = modification.coord; + BufferCoord coord = modification.coord; kak_assert(is_valid(coord)); switch (modification.type) @@ -538,7 +538,7 @@ void Buffer::apply_modification(const Modification& modification) } } -ByteCoord Buffer::insert(ByteCoord pos, StringView content) +BufferCoord Buffer::insert(BufferCoord pos, StringView content) { kak_assert(is_valid(pos)); if (content.empty()) @@ -558,13 +558,13 @@ ByteCoord Buffer::insert(ByteCoord pos, StringView content) return do_insert(pos, real_content->strview()); } -ByteCoord Buffer::erase(ByteCoord begin, ByteCoord end) +BufferCoord Buffer::erase(BufferCoord begin, BufferCoord end) { kak_assert(is_valid(begin) and is_valid(end)); // do not erase last \n except if we erase from the start of a line, and normalize // end coord if (is_end(end)) - end = (begin.column != 0 or begin == ByteCoord{0,0}) ? prev(end) : end_coord(); + end = (begin.column != 0 or begin == BufferCoord{0,0}) ? prev(end) : end_coord(); if (begin >= end) // use >= to handle case where begin is {line_count} return begin; @@ -575,7 +575,7 @@ ByteCoord Buffer::erase(ByteCoord begin, ByteCoord end) return do_erase(begin, end); } -ByteCoord Buffer::replace(ByteCoord begin, ByteCoord end, StringView content) +BufferCoord Buffer::replace(BufferCoord begin, BufferCoord end, StringView content) { if (not (m_flags & Flags::NoUndo)) m_current_undo_group.emplace_back(Modification::Erase, begin, @@ -613,7 +613,7 @@ void Buffer::notify_saved() m_fs_timestamp = get_fs_timestamp(m_name); } -ByteCoord Buffer::advance(ByteCoord coord, ByteCount count) const +BufferCoord Buffer::advance(BufferCoord coord, ByteCount count) const { if (count > 0) { @@ -642,7 +642,7 @@ ByteCoord Buffer::advance(ByteCoord coord, ByteCount count) const return coord; } -ByteCoord Buffer::char_next(ByteCoord coord) const +BufferCoord Buffer::char_next(BufferCoord coord) const { if (coord.column < m_lines[coord.line].length() - 1) { @@ -665,7 +665,7 @@ ByteCoord Buffer::char_next(ByteCoord coord) const return coord; } -ByteCoord Buffer::char_prev(ByteCoord coord) const +BufferCoord Buffer::char_prev(BufferCoord coord) const { kak_assert(is_valid(coord)); if (is_end(coord)) @@ -714,7 +714,7 @@ void Buffer::run_hook_in_own_context(StringView hook_name, StringView param) hooks().run_hook(hook_name, param, hook_handler.context()); } -ByteCoord Buffer::last_modification_coord() const +BufferCoord Buffer::last_modification_coord() const { if (m_history_cursor.get() == &m_history) return {}; @@ -788,13 +788,13 @@ UnitTest test_buffer{[]() BufferIterator pos = buffer.begin(); kak_assert(*pos == 'a'); pos += 6; - kak_assert(pos.coord() == ByteCoord{0, 6}); + kak_assert(pos.coord() == BufferCoord{0, 6}); ++pos; - kak_assert(pos.coord() == ByteCoord{1, 0}); + kak_assert(pos.coord() == BufferCoord{1, 0}); --pos; - kak_assert(pos.coord() == ByteCoord{0, 6}); + kak_assert(pos.coord() == BufferCoord{0, 6}); pos += 1; - kak_assert(pos.coord() == ByteCoord{1, 0}); + kak_assert(pos.coord() == BufferCoord{1, 0}); buffer.insert(pos.coord(), "tchou kanaky\n"); kak_assert(buffer.line_count() == 5); BufferIterator pos2 = buffer.end(); diff --git a/src/buffer.hh b/src/buffer.hh index 447089dd..d95d41bc 100644 --- a/src/buffer.hh +++ b/src/buffer.hh @@ -58,7 +58,7 @@ public: using iterator_category = std::random_access_iterator_tag; BufferIterator() : m_buffer(nullptr) {} - BufferIterator(const Buffer& buffer, ByteCoord coord); + BufferIterator(const Buffer& buffer, BufferCoord coord); bool operator== (const BufferIterator& iterator) const; bool operator!= (const BufferIterator& iterator) const; @@ -83,12 +83,12 @@ public: BufferIterator operator++ (int); BufferIterator operator-- (int); - const ByteCoord& coord() const { return m_coord; } + const BufferCoord& coord() const { return m_coord; } private: SafePtr m_buffer; StringView m_line; - ByteCoord m_coord; + BufferCoord m_coord; LineCount m_last_line; }; @@ -125,9 +125,9 @@ public: bool set_name(String name); void update_display_name(); - ByteCoord insert(ByteCoord pos, StringView content); - ByteCoord erase(ByteCoord begin, ByteCoord end); - ByteCoord replace(ByteCoord begin, ByteCoord end, StringView content); + BufferCoord insert(BufferCoord pos, StringView content); + BufferCoord erase(BufferCoord begin, BufferCoord end); + BufferCoord replace(BufferCoord begin, BufferCoord end, StringView content); size_t timestamp() const; timespec fs_timestamp() const; @@ -139,24 +139,24 @@ public: bool move_to(size_t history_id) noexcept; size_t current_history_id() const noexcept; - String string(ByteCoord begin, ByteCoord end) const; + String string(BufferCoord begin, BufferCoord end) const; - const char& byte_at(ByteCoord c) const; - ByteCount distance(ByteCoord begin, ByteCoord end) const; - ByteCoord advance(ByteCoord coord, ByteCount count) const; - ByteCoord next(ByteCoord coord) const; - ByteCoord prev(ByteCoord coord) const; + const char& byte_at(BufferCoord c) const; + ByteCount distance(BufferCoord begin, BufferCoord end) const; + BufferCoord advance(BufferCoord coord, ByteCount count) const; + BufferCoord next(BufferCoord coord) const; + BufferCoord prev(BufferCoord coord) const; - ByteCoord char_next(ByteCoord coord) const; - ByteCoord char_prev(ByteCoord coord) const; + BufferCoord char_next(BufferCoord coord) const; + BufferCoord char_prev(BufferCoord coord) const; - ByteCoord back_coord() const; - ByteCoord end_coord() const; + BufferCoord back_coord() const; + BufferCoord end_coord() const; - bool is_valid(ByteCoord c) const; - bool is_end(ByteCoord c) const; + bool is_valid(BufferCoord c) const; + bool is_end(BufferCoord c) const; - ByteCoord last_modification_coord() const; + BufferCoord last_modification_coord() const; BufferIterator begin() const; BufferIterator end() const; @@ -169,13 +169,13 @@ public: { return m_lines.get_storage(line); } // returns an iterator at given coordinates. clamp line_and_column - BufferIterator iterator_at(ByteCoord coord) const; + BufferIterator iterator_at(BufferCoord coord) const; // returns nearest valid coordinates from given ones - ByteCoord clamp(ByteCoord coord) const; + BufferCoord clamp(BufferCoord coord) const; - ByteCoord offset_coord(ByteCoord coord, CharCount offset); - ByteCoordAndTarget offset_coord(ByteCoordAndTarget coord, LineCount offset); + BufferCoord offset_coord(BufferCoord coord, CharCount offset); + BufferCoordAndTarget offset_coord(BufferCoordAndTarget coord, LineCount offset); const String& name() const { return m_name; } const String& display_name() const { return m_display_name; } @@ -200,8 +200,8 @@ public: enum Type : char { Insert, Erase }; Type type; bool at_end; - ByteCoord begin; - ByteCoord end; + BufferCoord begin; + BufferCoord end; }; ConstArrayView changes_since(size_t timestamp) const; @@ -214,8 +214,8 @@ private: void on_option_changed(const Option& option) override; - ByteCoord do_insert(ByteCoord pos, StringView content); - ByteCoord do_erase(ByteCoord begin, ByteCoord end); + BufferCoord do_insert(BufferCoord pos, StringView content); + BufferCoord do_erase(BufferCoord begin, BufferCoord end); struct Modification; diff --git a/src/buffer.inl.hh b/src/buffer.inl.hh index 9abaf01b..1880450d 100644 --- a/src/buffer.inl.hh +++ b/src/buffer.inl.hh @@ -7,13 +7,13 @@ namespace Kakoune { [[gnu::always_inline]] -inline const char& Buffer::byte_at(ByteCoord c) const +inline const char& Buffer::byte_at(BufferCoord c) const { kak_assert(c.line < line_count() and c.column < m_lines[c.line].length()); return m_lines[c.line][c.column]; } -inline ByteCoord Buffer::next(ByteCoord coord) const +inline BufferCoord Buffer::next(BufferCoord coord) const { if (coord.column < m_lines[coord.line].length() - 1) ++coord.column; @@ -27,7 +27,7 @@ inline ByteCoord Buffer::next(ByteCoord coord) const return coord; } -inline ByteCoord Buffer::prev(ByteCoord coord) const +inline BufferCoord Buffer::prev(BufferCoord coord) const { if (coord.column == 0) { @@ -39,7 +39,7 @@ inline ByteCoord Buffer::prev(ByteCoord coord) const return coord; } -inline ByteCount Buffer::distance(ByteCoord begin, ByteCoord end) const +inline ByteCount Buffer::distance(BufferCoord begin, BufferCoord end) const { if (begin > end) return -distance(end, begin); @@ -53,7 +53,7 @@ inline ByteCount Buffer::distance(ByteCoord begin, ByteCoord end) const return res; } -inline bool Buffer::is_valid(ByteCoord c) const +inline bool Buffer::is_valid(BufferCoord c) const { if (c.line < 0 or c.column < 0) return false; @@ -63,7 +63,7 @@ inline bool Buffer::is_valid(ByteCoord c) const (c.line == line_count() and c.column == 0); } -inline bool Buffer::is_end(ByteCoord c) const +inline bool Buffer::is_end(BufferCoord c) const { return c >= end_coord(); } @@ -97,18 +97,18 @@ inline ConstArrayView Buffer::changes_since(size_t timestamp) co return {}; } -inline ByteCoord Buffer::back_coord() const +inline BufferCoord Buffer::back_coord() const { return { line_count() - 1, m_lines.back().length() - 1 }; } -inline ByteCoord Buffer::end_coord() const +inline BufferCoord Buffer::end_coord() const { return m_lines.empty() ? - ByteCoord{0,0} : ByteCoord{ line_count() - 1, m_lines.back().length() }; + BufferCoord{0,0} : BufferCoord{ line_count() - 1, m_lines.back().length() }; } -inline BufferIterator::BufferIterator(const Buffer& buffer, ByteCoord coord) +inline BufferIterator::BufferIterator(const Buffer& buffer, BufferCoord coord) : m_buffer(&buffer), m_coord(coord), m_line((*m_buffer)[coord.line]), m_last_line(buffer.line_count()-1) diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index 09a65952..20d24118 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -12,11 +12,11 @@ namespace Kakoune { -CharCount get_column(const Buffer& buffer, - CharCount tabstop, ByteCoord coord) +ColumnCount get_column(const Buffer& buffer, + ColumnCount tabstop, BufferCoord coord) { auto line = buffer[coord.line]; - auto col = 0_char; + auto col = 0_col; for (auto it = line.begin(); it != line.end() and coord.column > (int)(it - line.begin()); it = utf8::next(it, line.end())) @@ -29,10 +29,10 @@ CharCount get_column(const Buffer& buffer, return col; } -ByteCount get_byte_to_column(const Buffer& buffer, CharCount tabstop, CharCoord coord) +ByteCount get_byte_to_column(const Buffer& buffer, ColumnCount tabstop, DisplayCoord coord) { auto line = buffer[coord.line]; - auto col = 0_char; + auto col = 0_col; auto it = line.begin(); while (it != line.end() and coord.column > col) { @@ -123,7 +123,7 @@ Buffer* create_fifo_buffer(String name, int fd, bool scroll) count = read(fifo, data, buffer_size); auto pos = buffer->back_coord(); - const bool prevent_scrolling = pos == ByteCoord{0,0} and not scroll; + const bool prevent_scrolling = pos == BufferCoord{0,0} and not scroll; if (prevent_scrolling) pos = buffer->next(pos); diff --git a/src/buffer_utils.hh b/src/buffer_utils.hh index 58192f31..7e3f8ac3 100644 --- a/src/buffer_utils.hh +++ b/src/buffer_utils.hh @@ -15,12 +15,12 @@ inline String content(const Buffer& buffer, const Selection& range) return buffer.string(range.min(), buffer.char_next(range.max())); } -inline ByteCoord erase(Buffer& buffer, const Selection& range) +inline BufferCoord erase(Buffer& buffer, const Selection& range) { return buffer.erase(range.min(), buffer.char_next(range.max())); } -inline ByteCoord replace(Buffer& buffer, const Selection& range, StringView content) +inline BufferCoord replace(Buffer& buffer, const Selection& range, StringView content) { return buffer.replace(range.min(), buffer.char_next(range.max()), content); } @@ -31,44 +31,49 @@ inline CharCount char_length(const Buffer& buffer, const Selection& range) buffer.iterator_at(buffer.char_next(range.max()))); } -inline CharCount char_length(const Buffer& buffer, const ByteCoord& begin, const ByteCoord& end) +inline CharCount char_length(const Buffer& buffer, const BufferCoord& begin, const BufferCoord& end) { return utf8::distance(buffer.iterator_at(begin), buffer.iterator_at(end)); } -inline bool is_bol(ByteCoord coord) +inline ColumnCount column_length(const Buffer& buffer, const BufferCoord& begin, const BufferCoord& end) +{ + return utf8::column_distance(buffer.iterator_at(begin), buffer.iterator_at(end)); +} + +inline bool is_bol(BufferCoord coord) { return coord.column == 0; } -inline bool is_eol(const Buffer& buffer, ByteCoord coord) +inline bool is_eol(const Buffer& buffer, BufferCoord coord) { return buffer.is_end(coord) or buffer[coord.line].length() == coord.column+1; } -inline bool is_bow(const Buffer& buffer, ByteCoord coord) +inline bool is_bow(const Buffer& buffer, BufferCoord coord) { auto it = utf8::iterator(buffer.iterator_at(coord), buffer); - if (coord == ByteCoord{0,0}) + if (coord == BufferCoord{0,0}) return is_word(*it); return not is_word(*(it-1)) and is_word(*it); } -inline bool is_eow(const Buffer& buffer, ByteCoord coord) +inline bool is_eow(const Buffer& buffer, BufferCoord coord) { - if (buffer.is_end(coord) or coord == ByteCoord{0,0}) + if (buffer.is_end(coord) or coord == BufferCoord{0,0}) return true; auto it = utf8::iterator(buffer.iterator_at(coord), buffer); return is_word(*(it-1)) and not is_word(*it); } -CharCount get_column(const Buffer& buffer, - CharCount tabstop, ByteCoord coord); +ColumnCount get_column(const Buffer& buffer, + ColumnCount tabstop, BufferCoord coord); -ByteCount get_byte_to_column(const Buffer& buffer, CharCount tabstop, - CharCoord coord); +ByteCount get_byte_to_column(const Buffer& buffer, ColumnCount tabstop, + DisplayCoord coord); Buffer* create_fifo_buffer(String name, int fd, bool scroll = false); Buffer* open_file_buffer(StringView filename); diff --git a/src/client.cc b/src/client.cc index e62aaa5d..a2d06cf0 100644 --- a/src/client.cc +++ b/src/client.cc @@ -205,7 +205,7 @@ void Client::redraw_ifn() if (m_ui_pending & MenuShow) { m_menu.ui_anchor = m_menu.style == MenuStyle::Inline ? - window.display_position(m_menu.anchor) : CharCoord{}; + window.display_position(m_menu.anchor) : DisplayCoord{}; m_ui->menu_show(m_menu.items, m_menu.ui_anchor, get_face("MenuForeground"), get_face("MenuBackground"), m_menu.style); @@ -218,7 +218,7 @@ void Client::redraw_ifn() if (m_ui_pending & InfoShow) { m_info.ui_anchor = is_inline(m_info.style) ? - window.display_position(m_info.anchor) : CharCoord{}; + window.display_position(m_info.anchor) : DisplayCoord{}; m_ui->info_show(m_info.title, m_info.content, m_info.ui_anchor, get_face("Information"), m_info.style); } @@ -330,7 +330,7 @@ void Client::on_option_changed(const Option& option) } } -void Client::menu_show(Vector choices, ByteCoord anchor, MenuStyle style) +void Client::menu_show(Vector choices, BufferCoord anchor, MenuStyle style) { m_menu = Menu{ std::move(choices), anchor, {}, style, -1 }; m_ui_pending |= MenuShow; @@ -351,7 +351,7 @@ void Client::menu_hide() m_ui_pending &= ~(MenuShow | MenuSelect); } -void Client::info_show(String title, String content, ByteCoord anchor, InfoStyle style) +void Client::info_show(String title, String content, BufferCoord anchor, InfoStyle style) { m_info = Info{ std::move(title), std::move(content), anchor, {}, style }; m_ui_pending |= InfoShow; diff --git a/src/client.hh b/src/client.hh index fcedd7bb..1eb845b1 100644 --- a/src/client.hh +++ b/src/client.hh @@ -34,16 +34,16 @@ public: // handle all the keys currently available in the user interface void handle_available_input(EventMode mode); - void menu_show(Vector choices, ByteCoord anchor, MenuStyle style); + void menu_show(Vector choices, BufferCoord anchor, MenuStyle style); void menu_select(int selected); void menu_hide(); - void info_show(String title, String content, ByteCoord anchor, InfoStyle style); + void info_show(String title, String content, BufferCoord anchor, InfoStyle style); void info_hide(); void print_status(DisplayLine status_line); - CharCoord dimensions() const { return m_ui->dimensions(); } + DisplayCoord dimensions() const { return m_ui->dimensions(); } void force_redraw(); void redraw_ifn(); @@ -100,8 +100,8 @@ private: struct Menu { Vector items; - ByteCoord anchor; - CharCoord ui_anchor; + BufferCoord anchor; + DisplayCoord ui_anchor; MenuStyle style; int selected; } m_menu; @@ -110,8 +110,8 @@ private: { String title; String content; - ByteCoord anchor; - CharCoord ui_anchor; + BufferCoord anchor; + DisplayCoord ui_anchor; InfoStyle style; } m_info; diff --git a/src/command_manager.cc b/src/command_manager.cc index 250a5fe4..6f78f686 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -80,7 +80,7 @@ public: StringView str; ByteCount pos; - CharCoord coord; + DisplayCoord coord; }; bool is_command_separator(char c) @@ -399,7 +399,7 @@ CommandManager::find_command(const Context& context, const String& name) const void CommandManager::execute_single_command(CommandParameters params, Context& context, const ShellContext& shell_context, - CharCoord pos) const + DisplayCoord pos) const { if (params.empty()) return; @@ -429,7 +429,7 @@ void CommandManager::execute(StringView command_line, if (tokens.empty()) return; - CharCoord command_coord; + DisplayCoord command_coord; Vector params; for (auto it = tokens.begin(); it != tokens.end(); ++it) { diff --git a/src/command_manager.hh b/src/command_manager.hh index e9f5c5fc..563d5431 100644 --- a/src/command_manager.hh +++ b/src/command_manager.hh @@ -56,20 +56,20 @@ struct Token }; Token() : m_type(Type::Raw) {} - Token(Type type, ByteCount b, ByteCount e, CharCoord coord, String str = "") + Token(Type type, ByteCount b, ByteCount e, DisplayCoord coord, String str = "") : m_type(type), m_begin(b), m_end(e), m_coord(coord), m_content(std::move(str)) {} Type type() const { return m_type; } ByteCount begin() const { return m_begin; } ByteCount end() const { return m_end; } - CharCoord coord() const { return m_coord; } + DisplayCoord coord() const { return m_coord; } const String& content() const { return m_content; } private: Type m_type; ByteCount m_begin; ByteCount m_end; - CharCoord m_coord; + DisplayCoord m_coord; String m_content; }; @@ -111,7 +111,7 @@ private: void execute_single_command(CommandParameters params, Context& context, const ShellContext& shell_context, - CharCoord pos) const; + DisplayCoord pos) const; struct CommandDescriptor { diff --git a/src/commands.cc b/src/commands.cc index 45f3cacd..74d9eb1e 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -1812,14 +1812,14 @@ const CommandDesc info_cmd = { if (parser.positional_count() > 0) { InfoStyle style = InfoStyle::Prompt; - ByteCoord pos; + BufferCoord pos; if (auto anchor = parser.get_switch("anchor")) { auto dot = find(*anchor, '.'); if (dot == anchor->end()) throw runtime_error("expected . for anchor"); - pos = ByteCoord{str_to_int({anchor->begin(), dot})-1, + pos = BufferCoord{str_to_int({anchor->begin(), dot})-1, str_to_int({dot+1, anchor->end()})-1}; style = InfoStyle::Inline; diff --git a/src/coord.hh b/src/coord.hh index 2a55695a..aa2f0e54 100644 --- a/src/coord.hh +++ b/src/coord.hh @@ -91,36 +91,36 @@ struct LineAndColumn } }; -struct ByteCoord : LineAndColumn +struct BufferCoord : LineAndColumn { [[gnu::always_inline]] - constexpr ByteCoord(LineCount line = 0, ByteCount column = 0) + constexpr BufferCoord(LineCount line = 0, ByteCount column = 0) : LineAndColumn(line, column) {} }; -struct CharCoord : LineAndColumn +struct DisplayCoord : LineAndColumn { [[gnu::always_inline]] - constexpr CharCoord(LineCount line = 0, CharCount column = 0) + constexpr DisplayCoord(LineCount line = 0, ColumnCount column = 0) : LineAndColumn(line, column) {} static constexpr const char* option_type_name = "coord"; }; -struct ByteCoordAndTarget : ByteCoord +struct BufferCoordAndTarget : BufferCoord { [[gnu::always_inline]] - constexpr ByteCoordAndTarget(LineCount line = 0, ByteCount column = 0, CharCount target = -1) - : ByteCoord(line, column), target(target) {} + constexpr BufferCoordAndTarget(LineCount line = 0, ByteCount column = 0, ColumnCount target = -1) + : BufferCoord(line, column), target(target) {} [[gnu::always_inline]] - constexpr ByteCoordAndTarget(ByteCoord coord, CharCount target = -1) - : ByteCoord(coord), target(target) {} + constexpr BufferCoordAndTarget(BufferCoord coord, ColumnCount target = -1) + : BufferCoord(coord), target(target) {} - CharCount target; + ColumnCount target; }; -inline size_t hash_value(const ByteCoordAndTarget& val) +inline size_t hash_value(const BufferCoordAndTarget& val) { return hash_values(val.line, val.column, val.target); } diff --git a/src/display_buffer.cc b/src/display_buffer.cc index c26ca8da..b8a1d43f 100644 --- a/src/display_buffer.cc +++ b/src/display_buffer.cc @@ -26,10 +26,10 @@ void option_from_string(StringView str, BufferRange& opt) if (comma == str.end() or dot_begin == comma or dot_end == str.end()) throw runtime_error(format("'{}' does not follow .,. format", str)); - ByteCoord begin{str_to_int({str.begin(), dot_begin}) - 1, + BufferCoord begin{str_to_int({str.begin(), dot_begin}) - 1, str_to_int({dot_begin+1, comma}) - 1}; - ByteCoord end{str_to_int({comma+1, dot_end}) - 1, + BufferCoord end{str_to_int({comma+1, dot_end}) - 1, str_to_int({dot_end+1, str.end()}) - 1}; opt.begin = begin; @@ -58,37 +58,39 @@ StringView DisplayAtom::content() const return {}; } -CharCount DisplayAtom::length() const +ColumnCount DisplayAtom::length() const { switch (m_type) { case BufferRange: - return char_length(*m_buffer, m_range.begin, m_range.end); + return (int)column_length(*m_buffer, m_range.begin, m_range.end); case Text: case ReplacedBufferRange: - return m_text.char_length(); + return (int)m_text.column_length(); } kak_assert(false); return 0; } -void DisplayAtom::trim_begin(CharCount count) +void DisplayAtom::trim_begin(ColumnCount count) { if (m_type == BufferRange) m_range.begin = utf8::advance(m_buffer->iterator_at(m_range.begin), - m_buffer->iterator_at(m_range.end), count).coord(); + m_buffer->iterator_at(m_range.end), + count).coord(); else m_text = m_text.substr(count).str(); check_invariant(); } -void DisplayAtom::trim_end(CharCount count) +void DisplayAtom::trim_end(ColumnCount count) { if (m_type == BufferRange) m_range.end = utf8::advance(m_buffer->iterator_at(m_range.end), - m_buffer->iterator_at(m_range.begin), -count).coord(); + m_buffer->iterator_at(m_range.begin), + -count).coord(); else - m_text = m_text.substr(0, m_text.char_length() - count).str(); + m_text = m_text.substr(0, m_text.column_length() - count).str(); check_invariant(); } @@ -109,7 +111,7 @@ DisplayLine::DisplayLine(AtomList atoms) compute_range(); } -DisplayLine::iterator DisplayLine::split(iterator it, ByteCoord pos) +DisplayLine::iterator DisplayLine::split(iterator it, BufferCoord pos) { kak_assert(it->type() == DisplayAtom::BufferRange); kak_assert(it->begin() < pos); @@ -123,7 +125,7 @@ DisplayLine::iterator DisplayLine::split(iterator it, ByteCoord pos) return m_atoms.insert(it, std::move(atom)); } -DisplayLine::iterator DisplayLine::split(iterator it, CharCount pos) +DisplayLine::iterator DisplayLine::split(iterator it, ColumnCount pos) { kak_assert(it->type() == DisplayAtom::Text); kak_assert(pos > 0); @@ -203,17 +205,17 @@ void DisplayLine::optimize() } } -CharCount DisplayLine::length() const +ColumnCount DisplayLine::length() const { - CharCount len = 0; + ColumnCount len = 0; for (auto& atom : m_atoms) len += atom.length(); return len; } -void DisplayLine::trim(CharCount first_char, CharCount char_count, bool only_buffer) +void DisplayLine::trim(ColumnCount first_col, ColumnCount col_count, bool only_buffer) { - for (auto it = begin(); first_char > 0 and it != end(); ) + for (auto it = begin(); first_col > 0 and it != end(); ) { if (only_buffer and not it->has_buffer_range()) { @@ -222,23 +224,23 @@ void DisplayLine::trim(CharCount first_char, CharCount char_count, bool only_buf } auto len = it->length(); - if (len <= first_char) + if (len <= first_col) { m_atoms.erase(it); - first_char -= len; + first_col -= len; } else { - it->trim_begin(first_char); - first_char = 0; + it->trim_begin(first_col); + first_col = 0; } } auto it = begin(); - for (; it != end() and char_count > 0; ++it) - char_count -= it->length(); + for (; it != end() and col_count > 0; ++it) + col_count -= it->length(); - if (char_count < 0) - (it-1)->trim_end(-char_count); + if (col_count < 0) + (it-1)->trim_end(-col_count); m_atoms.erase(it, end()); compute_range(); diff --git a/src/display_buffer.hh b/src/display_buffer.hh index 14e7044e..f83586d4 100644 --- a/src/display_buffer.hh +++ b/src/display_buffer.hh @@ -11,7 +11,7 @@ namespace Kakoune { class Buffer; -struct BufferRange{ ByteCoord begin, end; }; +struct BufferRange{ BufferCoord begin, end; }; String option_to_string(BufferRange range); void option_from_string(StringView str, BufferRange& opt); @@ -32,7 +32,7 @@ struct DisplayAtom : public UseMemoryDomain public: enum Type { BufferRange, ReplacedBufferRange, Text }; - DisplayAtom(const Buffer& buffer, ByteCoord begin, ByteCoord end) + DisplayAtom(const Buffer& buffer, BufferCoord begin, BufferCoord end) : m_type(BufferRange), m_buffer(&buffer), m_range{begin, end} { check_invariant(); } @@ -41,15 +41,15 @@ public: { check_invariant(); } StringView content() const; - CharCount length() const; + ColumnCount length() const; - const ByteCoord& begin() const + const BufferCoord& begin() const { kak_assert(has_buffer_range()); return m_range.begin; } - const ByteCoord& end() const + const BufferCoord& end() const { kak_assert(has_buffer_range()); return m_range.end; @@ -71,8 +71,8 @@ public: Type type() const { return m_type; } - void trim_begin(CharCount count); - void trim_end(CharCount count); + void trim_begin(ColumnCount count); + void trim_end(ColumnCount count); void check_invariant() const; @@ -117,24 +117,24 @@ public: const AtomList& atoms() const { return m_atoms; } - CharCount length() const; + ColumnCount length() const; const BufferRange& range() const { return m_range; } // Split atom pointed by it at buffer coord pos, // returns an iterator to the first atom - iterator split(iterator it, ByteCoord pos); + iterator split(iterator it, BufferCoord pos); - // Split atom pointed by it at its pos character, + // Split atom pointed by it at its pos column, // returns an iterator to the first atom - iterator split(iterator it, CharCount pos); + iterator split(iterator it, ColumnCount pos); iterator insert(iterator it, DisplayAtom atom); iterator erase(iterator beg, iterator end); void push_back(DisplayAtom atom); - // remove first_char from the begining of the line, and make sure - // the line is less that char_count character - void trim(CharCount first_char, CharCount char_count, bool only_buffer); + // remove first_col from the begining of the line, and make sure + // the line is less that col_count character + void trim(ColumnCount first_col, ColumnCount col_count, bool only_buffer); void optimize(); private: diff --git a/src/highlighters.cc b/src/highlighters.cc index a8758458..2ee019a4 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -26,7 +26,7 @@ namespace Kakoune template void highlight_range(DisplayBuffer& display_buffer, - ByteCoord begin, ByteCoord end, + BufferCoord begin, BufferCoord end, bool skip_replaced, T func) { if (begin == end or end <= display_buffer.range().begin @@ -68,7 +68,7 @@ void highlight_range(DisplayBuffer& display_buffer, void apply_highlighter(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer, - ByteCoord begin, ByteCoord end, + BufferCoord begin, BufferCoord end, Highlighter& highlighter) { if (begin == end) @@ -335,8 +335,8 @@ private: cache.m_regex_version = m_regex_version; } const LineCount line_offset = 3; - BufferRange range{std::max(buffer_range.begin, display_range.begin.line - line_offset), - std::min(buffer_range.end, display_range.end.line + line_offset)}; + BufferRange range{std::max(buffer_range.begin, display_range.begin.line - line_offset), + std::min(buffer_range.end, display_range.end.line + line_offset)}; auto it = std::upper_bound(matches.begin(), matches.end(), range, [](const BufferRange& lhs, const Cache::RangeAndMatches& rhs) @@ -514,7 +514,7 @@ HighlighterAndId create_line_highlighter(HighlighterParameters params) return; auto face = get_face(facespec); - CharCount column = 0; + ColumnCount column = 0; for (auto atom_it = it->begin(); atom_it != it->end(); ++atom_it) { column += atom_it->length(); @@ -524,7 +524,7 @@ HighlighterAndId create_line_highlighter(HighlighterParameters params) kak_assert(atom_it->begin().line == line); apply_face(face)(*atom_it); } - const CharCount remaining = context.window().dimensions().column - column; + const ColumnCount remaining = context.window().dimensions().column - column; if (remaining > 0) it->push_back({ String{' ', remaining}, face }); }; @@ -545,7 +545,7 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params) auto func = [=](const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer, BufferRange) { - CharCount column = -1; + ColumnCount column = -1; try { column = str_to_int_ifp(expand(col_expr, context)).value_or(0) - 1; @@ -566,7 +566,7 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params) { const LineCount buf_line = line.range().begin.line; const ByteCount byte_col = get_byte_to_column(buffer, tabstop, {buf_line, column}); - const ByteCoord coord{buf_line, byte_col}; + const BufferCoord coord{buf_line, byte_col}; bool found = false; if (buffer.is_valid(coord) and not buffer.is_end(coord)) { @@ -591,8 +591,8 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params) } if (not found) { - CharCount first_buffer_col = -1; - CharCount first_display_col = 0; + ColumnCount first_buffer_col = -1; + ColumnCount first_display_col = 0; for (auto& atom : line) { if (atom.has_buffer_range()) @@ -606,8 +606,8 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params) if (first_buffer_col == -1) continue; - CharCount eol_col = line.length(); - CharCount count = column + first_display_col - first_buffer_col - eol_col; + ColumnCount eol_col = line.length(); + ColumnCount count = column + first_display_col - first_buffer_col - eol_col; if (count >= 0) { if (count > 0) @@ -620,11 +620,11 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params) { DisplayAtom& atom = *(atom_it-1); - const CharCount len = atom.length(); + const ColumnCount len = atom.length(); if (atom.type() == DisplayAtom::Text and -count <= len) { auto it = atom_it - 1; - CharCount pos = len + count; + ColumnCount pos = len + count; if (pos > 0) { it = ++line.split(it, pos); @@ -709,7 +709,7 @@ void show_whitespaces(const Context& context, HighlightFlags flags, DisplayBuffe { int column = (int)get_column(buffer, tabstop, it.coord()); int count = tabstop - (column % tabstop); - atom_it->replace("→" + String(' ', count-1)); + atom_it->replace("→" + String(' ', CharCount{count-1})); } else if (c == ' ') atom_it->replace("·"); @@ -855,8 +855,8 @@ void highlight_selections(const Context& context, HighlightFlags flags, DisplayB { auto& sel = selections[i]; const bool forward = sel.anchor() <= sel.cursor(); - ByteCoord begin = forward ? sel.anchor() : buffer.char_next(sel.cursor()); - ByteCoord end = forward ? (ByteCoord)sel.cursor() : buffer.char_next(sel.anchor()); + BufferCoord begin = forward ? sel.anchor() : buffer.char_next(sel.cursor()); + BufferCoord end = forward ? (BufferCoord)sel.cursor() : buffer.char_next(sel.anchor()); const bool primary = (i == selections.main_index()); highlight_range(display_buffer, begin, end, false, @@ -961,7 +961,7 @@ HighlighterAndId create_flag_lines_highlighter(HighlighterParameters params) atom.face = merge_faces(def_face, atom.face); } - CharCount width = 0; + ColumnCount width = 0; for (auto& l : display_lines) width = std::max(width, l.length()); const DisplayAtom empty{String{' ', width}, def_face}; @@ -1070,8 +1070,8 @@ struct RegexMatch ByteCount begin; ByteCount end; - ByteCoord begin_coord() const { return { line, begin }; } - ByteCoord end_coord() const { return { line, end }; } + BufferCoord begin_coord() const { return { line, begin }; } + BufferCoord end_coord() const { return { line, end }; } }; using RegexMatchList = Vector; @@ -1147,18 +1147,18 @@ struct RegionMatches RegexMatchList end_matches; RegexMatchList recurse_matches; - static bool compare_to_begin(const RegexMatch& lhs, ByteCoord rhs) + static bool compare_to_begin(const RegexMatch& lhs, BufferCoord rhs) { return lhs.begin_coord() < rhs; } - RegexMatchList::const_iterator find_next_begin(ByteCoord pos) const + RegexMatchList::const_iterator find_next_begin(BufferCoord pos) const { return std::lower_bound(begin_matches.begin(), begin_matches.end(), pos, compare_to_begin); } - RegexMatchList::const_iterator find_matching_end(ByteCoord beg_pos) const + RegexMatchList::const_iterator find_matching_end(BufferCoord beg_pos) const { auto end_it = end_matches.begin(); auto rec_it = recurse_matches.begin(); @@ -1247,10 +1247,10 @@ public: auto& regions = get_regions_for_range(buffer, range); auto begin = std::lower_bound(regions.begin(), regions.end(), display_range.begin, - [](const Region& r, ByteCoord c) { return r.end < c; }); + [](const Region& r, BufferCoord c) { return r.end < c; }); auto end = std::lower_bound(begin, regions.end(), display_range.end, - [](const Region& r, ByteCoord c) { return r.begin < c; }); - auto correct = [&](ByteCoord c) -> ByteCoord { + [](const Region& r, BufferCoord c) { return r.begin < c; }); + auto correct = [&](BufferCoord c) -> BufferCoord { if (not buffer.is_end(c) and buffer[c.line].length() == c.column) return {c.line+1, 0}; return c; @@ -1260,7 +1260,7 @@ public: const bool apply_default = default_group_it != m_groups.end(); auto last_begin = (begin == regions.begin()) ? - ByteCoord{0,0} : (begin-1)->end; + BufferCoord{0,0} : (begin-1)->end; kak_assert(begin <= end); for (; begin != end; ++begin) { @@ -1350,8 +1350,8 @@ private: struct Region { - ByteCoord begin; - ByteCoord end; + BufferCoord begin; + BufferCoord end; StringView group; }; using RegionList = Vector; @@ -1367,7 +1367,7 @@ private: using RegionAndMatch = std::pair; // find the begin closest to pos in all matches - RegionAndMatch find_next_begin(const Cache& cache, ByteCoord pos) const + RegionAndMatch find_next_begin(const Cache& cache, BufferCoord pos) const { RegionAndMatch res{0, cache.matches[0].find_next_begin(pos)}; for (size_t i = 1; i < cache.matches.size(); ++i) diff --git a/src/input_handler.cc b/src/input_handler.cc index c7675a1a..28921066 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -74,7 +74,7 @@ struct MouseHandler return false; Buffer& buffer = context.buffer(); - ByteCoord cursor; + BufferCoord cursor; switch (key.modifiers) { case Key::Modifiers::MousePress: @@ -117,7 +117,7 @@ struct MouseHandler private: bool m_dragging = false; - ByteCoord m_anchor; + BufferCoord m_anchor; }; constexpr StringView register_doc = @@ -371,7 +371,7 @@ public: { if (m_cursor_pos != 0) { - m_line = m_line.substr(0, m_cursor_pos - 1) + m_line = m_line.substr(0_char, m_cursor_pos - 1) + m_line.substr(m_cursor_pos); --m_cursor_pos; @@ -429,7 +429,7 @@ public: const String& line() const { return m_line; } CharCount cursor_pos() const { return m_cursor_pos; } - DisplayLine build_display_line(CharCount width) + DisplayLine build_display_line(ColumnCount in_width) { auto cleanup = [](StringView str) { String res; @@ -448,6 +448,7 @@ public: return res; }; + CharCount width = (int)in_width; // Todo: proper handling of char/column kak_assert(m_cursor_pos <= m_line.char_length()); if (m_cursor_pos < m_display_pos) m_display_pos = m_cursor_pos; @@ -463,10 +464,10 @@ public: { cleanup(m_line.substr(m_cursor_pos+1, width - m_cursor_pos + m_display_pos - 1)), get_face("StatusLine") } }); } private: - CharCount m_cursor_pos = 0; - CharCount m_display_pos = 0; + CharCount m_cursor_pos = 0; + CharCount m_display_pos = 0; - String m_line; + String m_line; }; class Menu : public InputMode @@ -560,7 +561,7 @@ public: if (m_edit_filter and context().has_client()) { auto prompt = "filter:"_str; - auto width = context().client().dimensions().column - prompt.char_length(); + auto width = context().client().dimensions().column - prompt.column_length(); auto display_line = m_filter_editor.build_display_line(width); display_line.insert(display_line.begin(), { prompt, get_face("Prompt") }); context().print_status(display_line); @@ -858,7 +859,7 @@ private: if (not context().has_client()) return; - auto width = context().client().dimensions().column - m_prompt.char_length(); + auto width = context().client().dimensions().column - m_prompt.column_length(); DisplayLine display_line; if (not (m_flags & PromptFlags::Password)) display_line = m_line_editor.build_display_line(width); @@ -998,7 +999,7 @@ public: Vector sels; for (auto& sel : context().selections()) { - if (sel.cursor() == ByteCoord{0,0}) + if (sel.cursor() == BufferCoord{0,0}) continue; auto pos = sel.cursor(); sels.push_back({ buffer.char_prev(pos) }); @@ -1037,7 +1038,7 @@ public: { auto& selections = context().selections(); for (auto& sel : selections) - sel.anchor() = sel.cursor() = ByteCoord{sel.cursor().line, 0}; + sel.anchor() = sel.cursor() = BufferCoord{sel.cursor().line, 0}; selections.sort_and_merge_overlapping(); } else if (key == Key::End) @@ -1186,19 +1187,19 @@ private: break; case InsertMode::AppendAtLineEnd: for (auto& sel : selections) - sel = ByteCoord{sel.max().line, buffer[sel.max().line].length() - 1}; + sel = BufferCoord{sel.max().line, buffer[sel.max().line].length() - 1}; break; case InsertMode::OpenLineBelow: for (auto& sel : selections) - sel = ByteCoord{sel.max().line, buffer[sel.max().line].length() - 1}; + sel = BufferCoord{sel.max().line, buffer[sel.max().line].length() - 1}; insert('\n'); break; case InsertMode::OpenLineAbove: for (auto& sel : selections) { auto line = sel.min().line; - sel = line > 0 ? ByteCoord{line - 1, buffer[line-1].length() - 1} - : ByteCoord{0, 0}; + sel = line > 0 ? BufferCoord{line - 1, buffer[line-1].length() - 1} + : BufferCoord{0, 0}; } insert('\n'); // fix case where we inserted at begining @@ -1211,7 +1212,7 @@ private: case InsertMode::InsertAtLineBegin: for (auto& sel : selections) { - ByteCoord pos = sel.min().line; + BufferCoord pos = sel.min().line; auto pos_non_blank = buffer.iterator_at(pos); while (*pos_non_blank == ' ' or *pos_non_blank == '\t') ++pos_non_blank; @@ -1446,22 +1447,24 @@ void scroll_window(Context& context, LineCount offset) Window& window = context.window(); Buffer& buffer = context.buffer(); - CharCoord win_pos = window.position(); - CharCoord win_dim = window.dimensions(); + DisplayCoord win_pos = window.position(); + DisplayCoord win_dim = window.dimensions(); - const CharCoord max_offset{(win_dim.line - 1)/2, (win_dim.column - 1)/2}; - const CharCoord scrolloff = - std::min(context.options()["scrolloff"].get(), max_offset); + const DisplayCoord max_offset{(win_dim.line - 1)/2, (win_dim.column - 1)/2}; + const DisplayCoord scrolloff = + std::min(context.options()["scrolloff"].get(), max_offset); const LineCount line_count = buffer.line_count(); win_pos.line = clamp(win_pos.line + offset, 0_line, line_count-1); SelectionList& selections = context.selections(); - const ByteCoord cursor = selections.main().cursor(); + const BufferCoord cursor = selections.main().cursor(); auto clamp_line = [&](LineCount line) { return clamp(line, 0_line, line_count-1); }; - auto min_coord = buffer.offset_coord(clamp_line(win_pos.line + scrolloff.line), win_pos.column); - auto max_coord = buffer.offset_coord(clamp_line(win_pos.line + win_dim.line - 1 - scrolloff.line), win_pos.column); + auto min_line = clamp_line(win_pos.line + scrolloff.line); + auto max_line = clamp_line(win_pos.line + win_dim.line - 1 - scrolloff.line); + BufferCoord min_coord{min_line, buffer[min_line].byte_count_to(win_pos.column)}; + BufferCoord max_coord{max_line, buffer[max_line].byte_count_to(win_pos.column)}; selections = SelectionList{buffer, clamp(cursor, min_coord, max_coord)}; diff --git a/src/insert_completer.cc b/src/insert_completer.cc index 1cad959d..b7de3567 100644 --- a/src/insert_completer.cc +++ b/src/insert_completer.cc @@ -80,14 +80,14 @@ InsertCompletion complete_word(const SelectionList& sels, const OptionManager& o auto is_word_pred = [extra_word_char](Codepoint c) { return is_word(c) or contains(extra_word_char, c); }; const Buffer& buffer = sels.buffer(); - ByteCoord cursor_pos = sels.main().cursor(); + BufferCoord cursor_pos = sels.main().cursor(); using Utf8It = utf8::iterator; Utf8It pos{buffer.iterator_at(cursor_pos), buffer}; if (pos == buffer.begin() or not is_word_pred(*(pos-1))) return {}; - ByteCoord word_begin; + BufferCoord word_begin; String prefix; IdMap sel_word_counts; for (int i = 0; i < sels.size(); ++i) @@ -242,7 +242,7 @@ InsertCompletion complete_option(const SelectionList& sels, StringView option_name) { const Buffer& buffer = sels.buffer(); - ByteCoord cursor_pos = sels.main().cursor(); + BufferCoord cursor_pos = sels.main().cursor(); const CompletionList& opt = options[option_name].get(); if (opt.list.empty()) @@ -253,7 +253,7 @@ InsertCompletion complete_option(const SelectionList& sels, MatchResults match; if (regex_match(desc.begin(), desc.end(), match, re)) { - ByteCoord coord{ str_to_int({match[1].first, match[1].second}) - 1, + BufferCoord coord{ str_to_int({match[1].first, match[1].second}) - 1, str_to_int({match[2].first, match[2].second}) - 1 }; if (not buffer.is_valid(coord)) return {}; @@ -274,8 +274,8 @@ InsertCompletion complete_option(const SelectionList& sels, StringView query = buffer[coord.line].substr( coord.column, cursor_pos.column - coord.column); - const CharCount tabstop = options["tabstop"].get(); - const CharCount column = get_column(buffer, tabstop, cursor_pos); + const ColumnCount tabstop = options["tabstop"].get(); + const ColumnCount column = get_column(buffer, tabstop, cursor_pos); struct RankedMatchAndInfo : RankedMatch { @@ -318,10 +318,10 @@ InsertCompletion complete_option(const SelectionList& sels, InsertCompletion complete_line(const SelectionList& sels, const OptionManager& options) { const Buffer& buffer = sels.buffer(); - ByteCoord cursor_pos = sels.main().cursor(); + BufferCoord cursor_pos = sels.main().cursor(); - const CharCount tabstop = options["tabstop"].get(); - const CharCount column = get_column(buffer, tabstop, cursor_pos); + const ColumnCount tabstop = options["tabstop"].get(); + const ColumnCount column = get_column(buffer, tabstop, cursor_pos); StringView prefix = buffer[cursor_pos.line].substr(0_byte, cursor_pos.column); InsertCompletion::CandidateList candidates; diff --git a/src/insert_completer.hh b/src/insert_completer.hh index d29af8bd..064047f8 100644 --- a/src/insert_completer.hh +++ b/src/insert_completer.hh @@ -64,8 +64,8 @@ struct InsertCompletion using CandidateList = Vector; - ByteCoord begin; - ByteCoord end; + BufferCoord begin; + BufferCoord end; CandidateList candidates; size_t timestamp; diff --git a/src/json_ui.cc b/src/json_ui.cc index 25fa4513..b74464a0 100644 --- a/src/json_ui.cc +++ b/src/json_ui.cc @@ -112,7 +112,7 @@ String to_json(const DisplayLine& line) return to_json(line.atoms()); } -String to_json(CharCoord coord) +String to_json(DisplayCoord coord) { return format(R"(\{ "line": {}, "column": {} })", coord.line, coord.column); } @@ -197,7 +197,7 @@ Key JsonUI::get_key() } void JsonUI::menu_show(ConstArrayView items, - CharCoord anchor, Face fg, Face bg, + DisplayCoord anchor, Face fg, Face bg, MenuStyle style) { rpc_call("menu_show", items, anchor, fg, bg, style); @@ -214,7 +214,7 @@ void JsonUI::menu_hide() } void JsonUI::info_show(StringView title, StringView content, - CharCoord anchor, Face face, + DisplayCoord anchor, Face face, InfoStyle style) { rpc_call("info_show", title, content, anchor, face, style); @@ -240,7 +240,7 @@ void JsonUI::set_ui_options(const Options& options) // rpc_call("set_ui_options", options); } -CharCoord JsonUI::dimensions() +DisplayCoord JsonUI::dimensions() { return m_dimensions; } @@ -391,7 +391,7 @@ void JsonUI::eval_json(const Value& json) if (params.size() != 2) throw runtime_error("resize expects 2 parameters"); - CharCoord dim{params[0].as(), params[1].as()}; + DisplayCoord dim{params[0].as(), params[1].as()}; m_dimensions = dim; m_pending_keys.push_back(resize(dim)); } diff --git a/src/json_ui.hh b/src/json_ui.hh index e4d278fc..f8b48924 100644 --- a/src/json_ui.hh +++ b/src/json_ui.hh @@ -30,13 +30,13 @@ public: Key get_key() override; void menu_show(ConstArrayView items, - CharCoord anchor, Face fg, Face bg, + DisplayCoord anchor, Face fg, Face bg, MenuStyle style) override; void menu_select(int selected) override; void menu_hide() override; void info_show(StringView title, StringView content, - CharCoord anchor, Face face, + DisplayCoord anchor, Face face, InfoStyle style) override; void info_hide() override; @@ -46,7 +46,7 @@ public: void set_ui_options(const Options& options) override; - CharCoord dimensions() override; + DisplayCoord dimensions() override; private: void parse_requests(EventMode mode); @@ -55,7 +55,7 @@ private: InputCallback m_input_callback; FDWatcher m_stdin_watcher; Vector m_pending_keys; - CharCoord m_dimensions; + DisplayCoord m_dimensions; String m_requests; }; diff --git a/src/keys.cc b/src/keys.cc index 91917ee0..e353ecbc 100644 --- a/src/keys.cc +++ b/src/keys.cc @@ -115,7 +115,7 @@ String key_to_str(Key key) { if (key.modifiers & Key::Modifiers::MouseEvent) { - const auto coord = key.coord() + CharCoord{1,1}; + const auto coord = key.coord() + DisplayCoord{1,1}; switch (key.modifiers) { case Key::Modifiers::MousePos: @@ -133,7 +133,7 @@ String key_to_str(Key key) } else if (key.modifiers == Key::Modifiers::Resize) { - auto size = key.coord() + CharCoord{1,1}; + auto size = key.coord() + DisplayCoord{1,1}; return format("", size.line, size.column); } diff --git a/src/keys.hh b/src/keys.hh index 0e93da8c..1728b17c 100644 --- a/src/keys.hh +++ b/src/keys.hh @@ -79,7 +79,7 @@ struct Key constexpr bool operator!=(Key other) const { return val() != other.val(); } constexpr bool operator<(Key other) const { return val() < other.val(); } - constexpr CharCoord coord() const { return {(int)((key & 0xFFFF0000) >> 16), (int)(key & 0x0000FFFF)}; } + constexpr DisplayCoord coord() const { return {(int)((key & 0xFFFF0000) >> 16), (int)(key & 0x0000FFFF)}; } Optional codepoint() const; }; @@ -98,15 +98,15 @@ constexpr Key alt(Codepoint key) { return { Key::Modifiers::Alt, key }; } constexpr Key ctrl(Codepoint key) { return { Key::Modifiers::Control, key }; } constexpr Key ctrlalt(Codepoint key) { return { Key::Modifiers::ControlAlt, key }; } -constexpr Codepoint encode_coord(CharCoord coord) { return (Codepoint)(((int)coord.line << 16) | ((int)coord.column & 0x0000FFFF)); } +constexpr Codepoint encode_coord(DisplayCoord coord) { return (Codepoint)(((int)coord.line << 16) | ((int)coord.column & 0x0000FFFF)); } -constexpr Key mouse_press(CharCoord pos) { return { Key::Modifiers::MousePress, encode_coord(pos) }; } -constexpr Key mouse_release(CharCoord pos) { return { Key::Modifiers::MouseRelease, encode_coord(pos) }; } -constexpr Key mouse_pos(CharCoord pos) { return { Key::Modifiers::MousePos, encode_coord(pos) }; } -constexpr Key mouse_wheel_down(CharCoord pos) { return { Key::Modifiers::MouseWheelDown, encode_coord(pos) }; } -constexpr Key mouse_wheel_up(CharCoord pos) { return { Key::Modifiers::MouseWheelUp, encode_coord(pos) }; } +constexpr Key mouse_press(DisplayCoord pos) { return { Key::Modifiers::MousePress, encode_coord(pos) }; } +constexpr Key mouse_release(DisplayCoord pos) { return { Key::Modifiers::MouseRelease, encode_coord(pos) }; } +constexpr Key mouse_pos(DisplayCoord pos) { return { Key::Modifiers::MousePos, encode_coord(pos) }; } +constexpr Key mouse_wheel_down(DisplayCoord pos) { return { Key::Modifiers::MouseWheelDown, encode_coord(pos) }; } +constexpr Key mouse_wheel_up(DisplayCoord pos) { return { Key::Modifiers::MouseWheelUp, encode_coord(pos) }; } -constexpr Key resize(CharCoord dim) { return { Key::Modifiers::Resize, encode_coord(dim) }; } +constexpr Key resize(DisplayCoord dim) { return { Key::Modifiers::Resize, encode_coord(dim) }; } inline size_t hash_value(const Key& key) { return hash_values(key.modifiers, key.key); } diff --git a/src/main.cc b/src/main.cc index 3175ac5e..3faf79f7 100644 --- a/src/main.cc +++ b/src/main.cc @@ -198,7 +198,7 @@ static void check_indentwidth(const int& val) if (val < 0) throw runtime_error{"indentwidth should be positive or zero"}; } -static void check_scrolloff(const CharCoord& so) +static void check_scrolloff(const DisplayCoord& so) { if (so.line < 0 or so.column < 0) throw runtime_error{"scroll offset must be positive or zero"}; @@ -216,7 +216,7 @@ void register_options() reg.declare_option("tabstop", "size of a tab character", 8); reg.declare_option("indentwidth", "indentation width", 4); - reg.declare_option( + reg.declare_option( "scrolloff", "number of lines and columns to keep visible main cursor when scrolling", {0,0}); reg.declare_option("eolformat", "end of line format", EolFormat::Lf); @@ -318,17 +318,17 @@ std::unique_ptr make_ui(UIType ui_type) struct DummyUI : UserInterface { DummyUI() { set_signal_handler(SIGINT, SIG_DFL); } - void menu_show(ConstArrayView, CharCoord, + void menu_show(ConstArrayView, DisplayCoord, Face, Face, MenuStyle) override {} void menu_select(int) override {} void menu_hide() override {} - void info_show(StringView, StringView, CharCoord, Face, InfoStyle) override {} + void info_show(StringView, StringView, DisplayCoord, Face, InfoStyle) override {} void info_hide() override {} void draw(const DisplayBuffer&, const Face&, const Face&) override {} void draw_status(const DisplayLine&, const DisplayLine&, const Face&) override {} - CharCoord dimensions() override { return {24,80}; } + DisplayCoord dimensions() override { return {24,80}; } bool is_key_available() override { return false; } Key get_key() override { return Key::Invalid; } void refresh(bool) override {} @@ -477,7 +477,7 @@ int run_client(StringView session, StringView init_command, UIType ui_type) int run_server(StringView session, StringView init_command, bool ignore_kakrc, bool daemon, bool readonly, UIType ui_type, - ConstArrayView files, ByteCoord target_coord) + ConstArrayView files, BufferCoord target_coord) { static bool terminate = false; if (daemon) @@ -839,7 +839,7 @@ int main(int argc, char* argv[]) } else { - ByteCoord target_coord; + BufferCoord target_coord; Vector files; for (auto& name : parser) { diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc index 167f75f6..ea2d025a 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -266,7 +266,7 @@ NCursesUI::~NCursesUI() set_signal_handler(SIGCONT, SIG_DFL); } -void NCursesUI::Window::create(const CharCoord& p, const CharCoord& s) +void NCursesUI::Window::create(const DisplayCoord& p, const DisplayCoord& s) { pos = p; size = s; @@ -277,8 +277,8 @@ void NCursesUI::Window::destroy() { delwin(win); win = nullptr; - pos = CharCoord{}; - size = CharCoord{}; + pos = DisplayCoord{}; + size = DisplayCoord{}; } void NCursesUI::Window::refresh() @@ -286,7 +286,7 @@ void NCursesUI::Window::refresh() if (not win) return; - CharCoord max_pos = pos + size - CharCoord{1,1}; + DisplayCoord max_pos = pos + size - DisplayCoord{1,1}; pnoutrefresh(win, 0, 0, (int)pos.line, (int)pos.column, (int)max_pos.line, (int)max_pos.column); } @@ -316,7 +316,7 @@ void add_str(WINDOW* win, StringView str) } void NCursesUI::draw_line(NCursesWin* window, const DisplayLine& line, - CharCount col_index, CharCount max_column, + ColumnCount col_index, ColumnCount max_column, const Face& default_face) { for (const DisplayAtom& atom : line) @@ -329,16 +329,16 @@ void NCursesUI::draw_line(NCursesWin* window, const DisplayLine& line, const auto remaining_columns = max_column - col_index; if (content.back() == '\n' and - content.char_length() - 1 < remaining_columns) + content.column_length() - 1 < remaining_columns) { add_str(window, content.substr(0, content.length()-1)); waddch(window, ' '); } else { - content = content.substr(0_char, remaining_columns); + content = content.substr(0_col, remaining_columns); add_str(window, content); - col_index += content.char_length(); + col_index += content.column_length(); } } } @@ -391,7 +391,7 @@ void NCursesUI::draw_status(const DisplayLine& status_line, const auto remaining = m_dimensions.column - status_line.length(); if (mode_len < remaining) { - CharCount col = m_dimensions.column - mode_len; + ColumnCount col = m_dimensions.column - mode_len; wmove(m_window, status_line_pos, (int)col); draw_line(m_window, mode_line, col, m_dimensions.column, default_face); } @@ -402,7 +402,7 @@ void NCursesUI::draw_status(const DisplayLine& status_line, trimmed_mode_line.insert(trimmed_mode_line.begin(), { "…" }); kak_assert(trimmed_mode_line.length() == remaining - 1); - CharCount col = m_dimensions.column - remaining + 1; + ColumnCount col = m_dimensions.column - remaining + 1; wmove(m_window, status_line_pos, (int)col); draw_line(m_window, trimmed_mode_line, col, m_dimensions.column, default_face); } @@ -444,7 +444,7 @@ void NCursesUI::check_resize(bool force) intrflush(m_window, false); keypad(m_window, true); - m_dimensions = CharCoord{ws.ws_row-1, ws.ws_col}; + m_dimensions = DisplayCoord{ws.ws_row-1, ws.ws_col}; if (char* csr = tigetstr((char*)"csr")) putp(tparm(csr, 0, ws.ws_row)); @@ -488,7 +488,7 @@ Key NCursesUI::get_key() MEVENT ev; if (getmouse(&ev) == OK) { - CharCoord pos{ ev.y - (m_status_on_top ? 1 : 0), ev.x }; + DisplayCoord pos{ ev.y - (m_status_on_top ? 1 : 0), ev.x }; if (BUTTON_PRESS(ev.bstate, 1)) return mouse_press(pos); if (BUTTON_RELEASE(ev.bstate, 1)) return mouse_release(pos); if (BUTTON_PRESS(ev.bstate, m_wheel_down_button)) return mouse_wheel_down(pos); @@ -596,7 +596,7 @@ void NCursesUI::draw_menu() const LineCount& win_height = m_menu.size.line; kak_assert(win_height <= menu_lines); - const CharCount column_width = (m_menu.size.column - 1) / m_menu.columns; + const ColumnCount column_width = (m_menu.size.column - 1) / m_menu.columns; const LineCount mark_height = min(div_round_up(sq(win_height), menu_lines), win_height); @@ -615,7 +615,7 @@ void NCursesUI::draw_menu() const DisplayLine& item = m_menu.items[item_idx]; draw_line(m_menu.win, item, 0, column_width, item_idx == m_menu.selected_item ? m_menu.fg : m_menu.bg); - const CharCount pad = column_width - item.length(); + const ColumnCount pad = column_width - item.length(); add_str(m_menu.win, String{' ', pad}); } const bool is_mark = line >= mark_line and @@ -629,7 +629,7 @@ void NCursesUI::draw_menu() } void NCursesUI::menu_show(ConstArrayView items, - CharCoord anchor, Face fg, Face bg, + DisplayCoord anchor, Face fg, Face bg, MenuStyle style) { menu_hide(); @@ -640,11 +640,11 @@ void NCursesUI::menu_show(ConstArrayView items, m_menu.anchor = anchor; if (style == MenuStyle::Prompt) - anchor = CharCoord{m_status_on_top ? 0_line : m_dimensions.line, 0}; + anchor = DisplayCoord{m_status_on_top ? 0_line : m_dimensions.line, 0}; else if (m_status_on_top) anchor.line += 1; - CharCoord maxsize = m_dimensions; + DisplayCoord maxsize = m_dimensions; maxsize.column -= anchor.column; if (maxsize.column <= 2) return; @@ -652,14 +652,14 @@ void NCursesUI::menu_show(ConstArrayView items, const int item_count = items.size(); m_menu.items.clear(); // make sure it is empty m_menu.items.reserve(item_count); - CharCount longest = 1; + ColumnCount longest = 1; for (auto& item : items) longest = max(longest, item.length()); const bool is_prompt = style == MenuStyle::Prompt; m_menu.columns = is_prompt ? max((int)((maxsize.column-1) / (longest+1)), 1) : 1; - CharCount maxlen = maxsize.column-1; + ColumnCount maxlen = maxsize.column-1; if (m_menu.columns > 1 and item_count > 1) maxlen = maxlen / m_menu.columns - 1; @@ -720,10 +720,10 @@ void NCursesUI::menu_hide() m_dirty = true; } -static CharCoord compute_needed_size(StringView str) +static DisplayCoord compute_needed_size(StringView str) { - CharCoord res{1,0}; - CharCount line_len = 0; + DisplayCoord res{1,0}; + ColumnCount line_len = 0; for (auto it = str.begin(), end = str.end(); it != end; it = utf8::next(it, end)) { @@ -746,32 +746,32 @@ static CharCoord compute_needed_size(StringView str) return res; } -static CharCoord compute_pos(CharCoord anchor, CharCoord size, +static DisplayCoord compute_pos(DisplayCoord anchor, DisplayCoord size, NCursesUI::Rect rect, NCursesUI::Rect to_avoid, bool prefer_above) { - CharCoord pos; + DisplayCoord pos; if (prefer_above) { - pos = anchor - CharCoord{size.line}; + pos = anchor - DisplayCoord{size.line}; if (pos.line < 0) prefer_above = false; } auto rect_end = rect.pos + rect.size; if (not prefer_above) { - pos = anchor + CharCoord{1_line}; + pos = anchor + DisplayCoord{1_line}; if (pos.line + size.line > rect_end.line) pos.line = max(rect.pos.line, anchor.line - size.line); } if (pos.column + size.column > rect_end.column) pos.column = max(rect.pos.column, rect_end.column - size.column); - if (to_avoid.size != CharCoord{}) + if (to_avoid.size != DisplayCoord{}) { - CharCoord to_avoid_end = to_avoid.pos + to_avoid.size; + DisplayCoord to_avoid_end = to_avoid.pos + to_avoid.size; - CharCoord end = pos + size; + DisplayCoord end = pos + size; // check intersection if (not (end.line < to_avoid.pos.line or end.column < to_avoid.pos.column or @@ -787,24 +787,24 @@ static CharCoord compute_pos(CharCoord anchor, CharCoord size, return pos; } -String make_info_box(StringView title, StringView message, CharCount max_width, +String make_info_box(StringView title, StringView message, ColumnCount max_width, ConstArrayView assistant) { - CharCoord assistant_size; + DisplayCoord assistant_size; if (not assistant.empty()) - assistant_size = { (int)assistant.size(), assistant[0].char_length() }; + assistant_size = { (int)assistant.size(), assistant[0].column_length() }; String result; - const CharCount max_bubble_width = max_width - assistant_size.column - 6; + const ColumnCount max_bubble_width = max_width - assistant_size.column - 6; if (max_bubble_width < 4) return result; Vector lines = wrap_lines(message, max_bubble_width); - CharCount bubble_width = title.char_length() + 2; + ColumnCount bubble_width = title.column_length() + 2; for (auto& line : lines) - bubble_width = max(bubble_width, line.char_length()); + bubble_width = max(bubble_width, line.column_length()); auto line_count = max(assistant_size.line-1, LineCount{(int)lines.size()} + 2); @@ -819,7 +819,7 @@ String make_info_box(StringView title, StringView message, CharCount max_width, result += "╭─" + String{dash, bubble_width} + "─╮"; else { - auto dash_count = bubble_width - title.char_length() - 2; + auto dash_count = bubble_width - title.column_length() - 2; String left{dash, dash_count / 2}; String right{dash, dash_count - dash_count / 2}; result += "╭─" + left + "┤" + title +"├" + right +"─╮"; @@ -828,7 +828,7 @@ String make_info_box(StringView title, StringView message, CharCount max_width, else if (i < lines.size() + 1) { auto& line = lines[(int)i - 1]; - const CharCount padding = bubble_width - line.char_length(); + const ColumnCount padding = bubble_width - line.column_length(); result += "│ " + line + String{' ', padding} + " │"; } else if (i == lines.size() + 1) @@ -840,7 +840,7 @@ String make_info_box(StringView title, StringView message, CharCount max_width, } void NCursesUI::info_show(StringView title, StringView content, - CharCoord anchor, Face face, InfoStyle style) + DisplayCoord anchor, Face face, InfoStyle style) { info_hide(); @@ -855,18 +855,18 @@ void NCursesUI::info_show(StringView title, StringView content, { info_box = make_info_box(m_info.title, m_info.content, m_dimensions.column, m_assistant); - anchor = CharCoord{m_status_on_top ? 0 : m_dimensions.line, + anchor = DisplayCoord{m_status_on_top ? 0 : m_dimensions.line, m_dimensions.column-1}; } else { if (m_status_on_top) anchor.line += 1; - CharCount col = anchor.column; + ColumnCount col = anchor.column; if (style == InfoStyle::MenuDoc and m_menu) col = m_menu.pos.column + m_menu.size.column; - const CharCount max_width = m_dimensions.column - col; + const ColumnCount max_width = m_dimensions.column - col; if (max_width < 4) return; @@ -874,10 +874,10 @@ void NCursesUI::info_show(StringView title, StringView content, info_box += line + "\n"; } - CharCoord size = compute_needed_size(info_box), pos; + DisplayCoord size = compute_needed_size(info_box), pos; const Rect rect = {m_status_on_top ? 1_line : 0_line, m_dimensions}; if (style == InfoStyle::MenuDoc and m_menu) - pos = m_menu.pos + CharCoord{0_line, m_menu.size.column}; + pos = m_menu.pos + DisplayCoord{0_line, m_menu.size.column}; else pos = compute_pos(anchor, size, rect, m_menu, style == InfoStyle::InlineAbove); @@ -916,7 +916,7 @@ void NCursesUI::mark_dirty(const Window& win) wredrawln(m_window, (int)win.pos.line, (int)win.size.line); } -CharCoord NCursesUI::dimensions() +DisplayCoord NCursesUI::dimensions() { return m_dimensions; } diff --git a/src/ncurses_ui.hh b/src/ncurses_ui.hh index 0b0cf08b..1b094c1d 100644 --- a/src/ncurses_ui.hh +++ b/src/ncurses_ui.hh @@ -34,13 +34,13 @@ public: Key get_key() override; void menu_show(ConstArrayView items, - CharCoord anchor, Face fg, Face bg, + DisplayCoord anchor, Face fg, Face bg, MenuStyle style) override; void menu_select(int selected) override; void menu_hide() override; void info_show(StringView title, StringView content, - CharCoord anchor, Face face, + DisplayCoord anchor, Face face, InfoStyle style) override; void info_hide() override; @@ -50,14 +50,14 @@ public: void set_ui_options(const Options& options) override; - CharCoord dimensions() override; + DisplayCoord dimensions() override; static void abort(); struct Rect { - CharCoord pos; - CharCoord size; + DisplayCoord pos; + DisplayCoord size; }; private: void check_resize(bool force = false); @@ -67,12 +67,12 @@ private: int get_color_pair(const Face& face); void set_face(NCursesWin* window, Face face, const Face& default_face); void draw_line(NCursesWin* window, const DisplayLine& line, - CharCount col_index, CharCount max_column, + ColumnCount col_index, ColumnCount max_column, const Face& default_face); NCursesWin* m_window = nullptr; - CharCoord m_dimensions; + DisplayCoord m_dimensions; using ColorPair = std::pair; UnorderedMap m_colors; @@ -81,7 +81,7 @@ private: struct Window : Rect { - void create(const CharCoord& pos, const CharCoord& size); + void create(const DisplayCoord& pos, const DisplayCoord& size); void destroy(); void refresh(); @@ -97,7 +97,7 @@ private: Vector items; Face fg; Face bg; - CharCoord anchor; + DisplayCoord anchor; MenuStyle style; int selected_item = 0; int columns = 1; @@ -111,7 +111,7 @@ private: String title; String content; Face face; - CharCoord anchor; + DisplayCoord anchor; InfoStyle style; } m_info; diff --git a/src/normal.cc b/src/normal.cc index e1564bca..60afe80d 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -71,7 +71,7 @@ void select(Context& context, NormalParams) } template -void select_coord(Buffer& buffer, ByteCoord coord, SelectionList& selections) +void select_coord(Buffer& buffer, BufferCoord coord, SelectionList& selections) { coord = buffer.clamp(coord); if (mode == SelectMode::Replace) @@ -118,7 +118,7 @@ void goto_commands(Context& context, NormalParams params) case 'g': case 'k': context.push_jump(); - select_coord(buffer, ByteCoord{0,0}, context.selections()); + select_coord(buffer, BufferCoord{0,0}, context.selections()); break; case 'l': select>(context, {}); @@ -204,7 +204,7 @@ void goto_commands(Context& context, NormalParams params) if (pos >= buffer.back_coord()) pos = buffer.back_coord(); else if (buffer[pos.line].length() == pos.column + 1) - pos = ByteCoord{ pos.line+1, 0 }; + pos = BufferCoord{ pos.line+1, 0 }; select_coord(buffer, pos, context.selections()); break; } @@ -240,7 +240,7 @@ void view_commands(Context& context, NormalParams params) if (not cp or not context.has_window()) return; - const ByteCoord cursor = context.selections().main().cursor(); + const BufferCoord cursor = context.selections().main().cursor(); Window& window = context.window(); switch (to_lower(*cp)) { @@ -250,7 +250,7 @@ void view_commands(Context& context, NormalParams params) break; case 'm': context.window().center_column( - context.buffer()[cursor.line].char_count_to(cursor.column)); + context.buffer()[cursor.line].column_count_to(cursor.column)); break; case 't': context.window().display_line_at(cursor.line, 0); @@ -259,7 +259,7 @@ void view_commands(Context& context, NormalParams params) context.window().display_line_at(cursor.line, window.dimensions().line-1); break; case 'h': - context.window().scroll(-std::max(1, count)); + context.window().scroll(-std::max(1, count)); break; case 'j': context.window().scroll( std::max(1, count)); @@ -268,7 +268,7 @@ void view_commands(Context& context, NormalParams params) context.window().scroll(-std::max(1, count)); break; case 'l': - context.window().scroll( std::max(1, count)); + context.window().scroll( std::max(1, count)); break; } }, "view", @@ -592,7 +592,7 @@ void paste_all(Context& context, NormalParams params) template void regex_prompt(Context& context, String prompt, T func) { - CharCoord position = context.has_window() ? context.window().position() : CharCoord{}; + DisplayCoord position = context.has_window() ? context.window().position() : DisplayCoord{}; SelectionList selections = context.selections(); context.input_handler().prompt( std::move(prompt), "", get_face("Prompt"), PromptFlags::None, complete_nothing, @@ -875,8 +875,8 @@ void indent(Context& context, NormalParams) template void deindent(Context& context, NormalParams) { - CharCount tabstop = context.options()["tabstop"].get(); - CharCount indent_width = context.options()["indentwidth"].get(); + ColumnCount tabstop = context.options()["tabstop"].get(); + ColumnCount indent_width = context.options()["indentwidth"].get(); if (indent_width == 0) indent_width = tabstop; @@ -888,7 +888,7 @@ void deindent(Context& context, NormalParams) for (auto line = std::max(sel.min().line, last_line); line < sel.max().line+1; ++line) { - CharCount width = 0; + ColumnCount width = 0; auto content = buffer[line]; for (auto column = 0_byte; column < content.length(); ++column) { @@ -900,12 +900,12 @@ void deindent(Context& context, NormalParams) else { if (deindent_incomplete and width != 0) - sels.push_back({ line, ByteCoord{line, column-1} }); + sels.push_back({ line, BufferCoord{line, column-1} }); break; } if (width == indent_width) { - sels.push_back({ line, ByteCoord{line, column} }); + sels.push_back({ line, BufferCoord{line, column} }); break; } } @@ -1048,14 +1048,14 @@ void copy_selections_on_next_lines(Context& context, NormalParams params) { auto& selections = context.selections(); auto& buffer = context.buffer(); - const CharCount tabstop = context.options()["tabstop"].get(); + const ColumnCount tabstop = context.options()["tabstop"].get(); Vector result; for (auto& sel : selections) { auto anchor = sel.anchor(); auto cursor = sel.cursor(); - CharCount cursor_col = get_column(buffer, tabstop, cursor); - CharCount anchor_col = get_column(buffer, tabstop, anchor); + ColumnCount cursor_col = get_column(buffer, tabstop, cursor); + ColumnCount anchor_col = get_column(buffer, tabstop, anchor); result.push_back(std::move(sel)); for (int i = 0; i < std::max(params.count, 1); ++i) { @@ -1073,8 +1073,8 @@ void copy_selections_on_next_lines(Context& context, NormalParams params) if (anchor_byte != buffer[anchor_line].length() and cursor_byte != buffer[cursor_line].length()) - result.emplace_back(ByteCoord{anchor_line, anchor_byte}, - ByteCoordAndTarget{cursor_line, cursor_byte, cursor.target}); + result.emplace_back(BufferCoord{anchor_line, anchor_byte}, + BufferCoordAndTarget{cursor_line, cursor_byte, cursor.target}); } } selections = std::move(result); @@ -1206,7 +1206,7 @@ void align(Context& context, NormalParams) { auto& selections = context.selections(); auto& buffer = context.buffer(); - const CharCount tabstop = context.options()["tabstop"].get(); + const ColumnCount tabstop = context.options()["tabstop"].get(); Vector> columns; LineCount last_line = -1; @@ -1227,7 +1227,7 @@ void align(Context& context, NormalParams) const bool use_tabs = context.options()["aligntab"].get(); for (auto& col : columns) { - CharCount maxcol = 0; + ColumnCount maxcol = 0; for (auto& sel : col) maxcol = std::max(get_column(buffer, tabstop, sel->cursor()), maxcol); for (auto& sel : col) @@ -1292,8 +1292,8 @@ void copy_indent(Context& context, NormalParams params) void tabs_to_spaces(Context& context, NormalParams params) { auto& buffer = context.buffer(); - const CharCount opt_tabstop = context.options()["tabstop"].get(); - const CharCount tabstop = params.count == 0 ? opt_tabstop : params.count; + const ColumnCount opt_tabstop = context.options()["tabstop"].get(); + const ColumnCount tabstop = params.count == 0 ? opt_tabstop : params.count; Vector tabs; Vector spaces; for (auto& sel : context.selections()) @@ -1303,8 +1303,8 @@ void tabs_to_spaces(Context& context, NormalParams params) { if (*it == '\t') { - CharCount col = get_column(buffer, opt_tabstop, it.coord()); - CharCount end_col = (col / tabstop + 1) * tabstop; + ColumnCount col = get_column(buffer, opt_tabstop, it.coord()); + ColumnCount end_col = (col / tabstop + 1) * tabstop; tabs.push_back({ it.coord() }); spaces.push_back(String{ ' ', end_col - col }); } @@ -1317,8 +1317,8 @@ void tabs_to_spaces(Context& context, NormalParams params) void spaces_to_tabs(Context& context, NormalParams params) { auto& buffer = context.buffer(); - const CharCount opt_tabstop = context.options()["tabstop"].get(); - const CharCount tabstop = params.count == 0 ? opt_tabstop : params.count; + const ColumnCount opt_tabstop = context.options()["tabstop"].get(); + const ColumnCount tabstop = params.count == 0 ? opt_tabstop : params.count; Vector spaces; for (auto& sel : context.selections()) { @@ -1329,7 +1329,7 @@ void spaces_to_tabs(Context& context, NormalParams params) { auto spaces_beg = it; auto spaces_end = spaces_beg+1; - CharCount col = get_column(buffer, opt_tabstop, spaces_end.coord()); + ColumnCount col = get_column(buffer, opt_tabstop, spaces_end.coord()); while (spaces_end != end and *spaces_end == ' ' and (col % tabstop) != 0) { @@ -1570,7 +1570,7 @@ void flip_selections(Context& context, NormalParams) { for (auto& sel : context.selections()) { - const ByteCoord tmp = sel.anchor(); + const BufferCoord tmp = sel.anchor(); sel.anchor() = sel.cursor(); sel.cursor() = tmp; } @@ -1581,7 +1581,7 @@ void ensure_forward(Context& context, NormalParams) { for (auto& sel : context.selections()) { - const ByteCoord min = sel.min(), max = sel.max(); + const BufferCoord min = sel.min(), max = sel.max(); sel.anchor() = min; sel.cursor() = max; } diff --git a/src/remote.cc b/src/remote.cc index 7ab6e887..427f52b2 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -291,17 +291,17 @@ DisplayBuffer MsgReader::read() class RemoteUI : public UserInterface { public: - RemoteUI(int socket, CharCoord dimensions); + RemoteUI(int socket, DisplayCoord dimensions); ~RemoteUI(); void menu_show(ConstArrayView choices, - CharCoord anchor, Face fg, Face bg, + DisplayCoord anchor, Face fg, Face bg, MenuStyle style) override; void menu_select(int selected) override; void menu_hide() override; void info_show(StringView title, StringView content, - CharCoord anchor, Face face, + DisplayCoord anchor, Face face, InfoStyle style) override; void info_hide() override; @@ -317,7 +317,7 @@ public: bool is_key_available() override; Key get_key() override; - CharCoord dimensions() override; + DisplayCoord dimensions() override; void set_input_callback(InputCallback callback) override; @@ -329,7 +329,7 @@ public: private: FDWatcher m_socket_watcher; MsgReader m_reader; - CharCoord m_dimensions; + DisplayCoord m_dimensions; InputCallback m_input_callback; SafePtr m_client; @@ -337,7 +337,7 @@ private: }; -RemoteUI::RemoteUI(int socket, CharCoord dimensions) +RemoteUI::RemoteUI(int socket, DisplayCoord dimensions) : m_socket_watcher(socket, [this](FDWatcher& watcher, EventMode mode) { const int sock = watcher.fd(); bool disconnect = false; @@ -380,7 +380,7 @@ RemoteUI::~RemoteUI() } void RemoteUI::menu_show(ConstArrayView choices, - CharCoord anchor, Face fg, Face bg, + DisplayCoord anchor, Face fg, Face bg, MenuStyle style) { MsgWriter msg{m_socket_watcher.fd(), MessageType::MenuShow}; @@ -403,7 +403,7 @@ void RemoteUI::menu_hide() } void RemoteUI::info_show(StringView title, StringView content, - CharCoord anchor, Face face, + DisplayCoord anchor, Face face, InfoStyle style) { MsgWriter msg{m_socket_watcher.fd(), MessageType::InfoShow}; @@ -466,7 +466,7 @@ Key RemoteUI::get_key() return key; } -CharCoord RemoteUI::dimensions() +DisplayCoord RemoteUI::dimensions() { return m_dimensions; } @@ -535,7 +535,7 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr&& case MessageType::MenuShow: { auto choices = reader.read_vector(); - auto anchor = reader.read(); + auto anchor = reader.read(); auto fg = reader.read(); auto bg = reader.read(); auto style = reader.read(); @@ -552,7 +552,7 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr&& { auto title = reader.read(); auto content = reader.read(); - auto anchor = reader.read(); + auto anchor = reader.read(); auto face = reader.read(); auto style = reader.read(); m_ui->info_show(title, content, anchor, face, style); @@ -643,7 +643,7 @@ private: case MessageType::Connect: { auto init_command = m_reader.read(); - auto dimensions = m_reader.read(); + auto dimensions = m_reader.read(); auto env_vars = m_reader.read_idmap(); RemoteUI* ui = new RemoteUI{sock, dimensions}; if (auto* client = ClientManager::instance().create_client( diff --git a/src/selection.cc b/src/selection.cc index 9922e851..7d725c6f 100644 --- a/src/selection.cc +++ b/src/selection.cc @@ -38,7 +38,7 @@ SelectionList::SelectionList(Buffer& buffer, Vector s) namespace { -ByteCoord update_insert(ByteCoord coord, ByteCoord begin, ByteCoord end) +BufferCoord update_insert(BufferCoord coord, BufferCoord begin, BufferCoord end) { if (coord < begin) return coord; @@ -50,7 +50,7 @@ ByteCoord update_insert(ByteCoord coord, ByteCoord begin, ByteCoord end) } /* For reference -ByteCoord update_erase(ByteCoord coord, ByteCoord begin, ByteCoord end) +BufferCoord update_erase(BufferCoord coord, BufferCoord begin, BufferCoord end) { if (coord < begin) return coord; @@ -101,8 +101,8 @@ Iterator merge_overlapping(Iterator begin, Iterator end, size_t& main, OverlapsF // *after* the previous one. struct ForwardChangesTracker { - ByteCoord cur_pos; // last change position at current modification - ByteCoord old_pos; // last change position at start + BufferCoord cur_pos; // last change position at current modification + BufferCoord old_pos; // last change position at start void update(const Buffer::Change& change) { @@ -127,7 +127,7 @@ struct ForwardChangesTracker timestamp = buffer.timestamp(); } - ByteCoord get_old_coord(ByteCoord coord) const + BufferCoord get_old_coord(BufferCoord coord) const { kak_assert(cur_pos <= coord); auto pos_change = cur_pos - old_pos; @@ -141,7 +141,7 @@ struct ForwardChangesTracker return coord; } - ByteCoord get_new_coord(ByteCoord coord) const + BufferCoord get_new_coord(BufferCoord coord) const { kak_assert(old_pos <= coord); auto pos_change = cur_pos - old_pos; @@ -155,14 +155,14 @@ struct ForwardChangesTracker return coord; } - ByteCoord get_new_coord_tolerant(ByteCoord coord) const + BufferCoord get_new_coord_tolerant(BufferCoord coord) const { if (coord < old_pos) return cur_pos; return get_new_coord(coord); } - bool relevant(const Buffer::Change& change, ByteCoord old_coord) const + bool relevant(const Buffer::Change& change, BufferCoord old_coord) const { auto new_coord = get_new_coord_tolerant(old_coord); return change.type == Buffer::Change::Insert ? change.begin <= new_coord @@ -202,7 +202,7 @@ void update_forward(ConstArrayView changes, Vector& s ForwardChangesTracker changes_tracker; auto change_it = changes.begin(); - auto advance_while_relevant = [&](const ByteCoord& pos) mutable { + auto advance_while_relevant = [&](const BufferCoord& pos) mutable { while (change_it != changes.end() and changes_tracker.relevant(*change_it, pos)) changes_tracker.update(*change_it++); }; @@ -227,7 +227,7 @@ void update_backward(ConstArrayView changes, Vector& using ReverseIt = std::reverse_iterator; auto change_it = ReverseIt(changes.end()); auto change_end = ReverseIt(changes.begin()); - auto advance_while_relevant = [&](const ByteCoord& pos) mutable { + auto advance_while_relevant = [&](const BufferCoord& pos) mutable { while (change_it != change_end) { auto change = *change_it; @@ -314,7 +314,7 @@ Vector compute_modified_ranges(Buffer& buffer, size_t timestamp) for (auto& range : ranges) { range.anchor() = std::min(range.anchor(), end_coord); - range.cursor() = std::min(range.cursor(), end_coord); + range.cursor() = std::min(range.cursor(), end_coord); } auto touches = [&](const Selection& lhs, const Selection& rhs) { @@ -401,7 +401,7 @@ void SelectionList::check_invariant() const return; const auto end_coord = buffer.end_coord(); - ByteCoord last_min{0,0}; + BufferCoord last_min{0,0}; for (auto& sel : m_selections) { auto& min = sel.min(); @@ -409,11 +409,11 @@ void SelectionList::check_invariant() const last_min = min; const auto anchor = sel.anchor(); - kak_assert(anchor >= ByteCoord{0,0} and anchor < end_coord); + kak_assert(anchor >= BufferCoord{0,0} and anchor < end_coord); kak_assert(anchor.column < buffer[anchor.line].length()); const auto cursor = sel.cursor(); - kak_assert(cursor >= ByteCoord{0,0} and cursor < end_coord); + kak_assert(cursor >= BufferCoord{0,0} and cursor < end_coord); kak_assert(cursor.column < buffer[cursor.line].length()); } #endif @@ -463,7 +463,7 @@ void SelectionList::sort_and_merge_overlapping() merge_overlapping(); } -static inline void _avoid_eol(const Buffer& buffer, ByteCoord& coord) +static inline void _avoid_eol(const Buffer& buffer, BufferCoord& coord) { auto column = coord.column; auto line = buffer[coord.line]; @@ -481,7 +481,7 @@ void SelectionList::avoid_eol() } } -ByteCoord prepare_insert(Buffer& buffer, const Selection& sel, InsertMode mode) +BufferCoord prepare_insert(Buffer& buffer, const Selection& sel, InsertMode mode) { switch (mode) { @@ -588,7 +588,7 @@ void SelectionList::erase() changes_tracker.update(*m_buffer, m_timestamp); } - ByteCoord back_coord = m_buffer->back_coord(); + BufferCoord back_coord = m_buffer->back_coord(); for (auto& sel : m_selections) { if (sel.anchor() > back_coord) @@ -624,10 +624,10 @@ Selection selection_from_string(StringView desc) if (comma == desc.end() or dot_anchor == comma or dot_cursor == desc.end()) throw runtime_error(format("'{}' does not follow .,. format", desc)); - ByteCoord anchor{str_to_int({desc.begin(), dot_anchor}) - 1, + BufferCoord anchor{str_to_int({desc.begin(), dot_anchor}) - 1, str_to_int({dot_anchor+1, comma}) - 1}; - ByteCoord cursor{str_to_int({comma+1, dot_cursor}) - 1, + BufferCoord cursor{str_to_int({comma+1, dot_cursor}) - 1, str_to_int({dot_cursor+1, desc.end()}) - 1}; return Selection{anchor, cursor}; diff --git a/src/selection.hh b/src/selection.hh index 29c3ffdc..7428fb39 100644 --- a/src/selection.hh +++ b/src/selection.hh @@ -14,19 +14,19 @@ struct Selection static constexpr MemoryDomain Domain = MemoryDomain::Selections; Selection() = default; - Selection(ByteCoord pos) : Selection(pos,pos) {} - Selection(ByteCoord anchor, ByteCoord cursor, + Selection(BufferCoord pos) : Selection(pos,pos) {} + Selection(BufferCoord anchor, BufferCoord cursor, CaptureList captures = {}) : m_anchor{anchor}, m_cursor{cursor}, m_captures(std::move(captures)) {} void merge_with(const Selection& range); - ByteCoord& anchor() { return m_anchor; } - ByteCoordAndTarget& cursor() { return m_cursor; } + BufferCoord& anchor() { return m_anchor; } + BufferCoordAndTarget& cursor() { return m_cursor; } - const ByteCoord& anchor() const { return m_anchor; } - const ByteCoordAndTarget& cursor() const { return m_cursor; } + const BufferCoord& anchor() const { return m_anchor; } + const BufferCoordAndTarget& cursor() const { return m_cursor; } CaptureList& captures() { return m_captures; } const CaptureList& captures() const { return m_captures; } @@ -36,15 +36,15 @@ struct Selection return m_anchor == other.m_anchor and m_cursor == other.m_cursor; } - const ByteCoord& min() const { return m_anchor < m_cursor ? m_anchor : m_cursor; } - const ByteCoord& max() const { return m_anchor < m_cursor ? m_cursor : m_anchor; } + const BufferCoord& min() const { return m_anchor < m_cursor ? m_anchor : m_cursor; } + const BufferCoord& max() const { return m_anchor < m_cursor ? m_cursor : m_anchor; } - ByteCoord& min() { return m_anchor < m_cursor ? m_anchor : m_cursor; } - ByteCoord& max() { return m_anchor < m_cursor ? m_cursor : m_anchor; } + BufferCoord& min() { return m_anchor < m_cursor ? m_anchor : m_cursor; } + BufferCoord& max() { return m_anchor < m_cursor ? m_cursor : m_anchor; } private: - ByteCoord m_anchor; - ByteCoordAndTarget m_cursor; + BufferCoord m_anchor; + BufferCoordAndTarget m_cursor; CaptureList m_captures; }; diff --git a/src/selectors.cc b/src/selectors.cc index 0f519297..3e639ba5 100644 --- a/src/selectors.cc +++ b/src/selectors.cc @@ -341,7 +341,7 @@ Selection select_paragraph(const Buffer& buffer, const Selection& selection, int { BufferIterator first = buffer.iterator_at(selection.cursor()); - if (not (flags & ObjectFlags::ToEnd) and first.coord() > ByteCoord{0,1} and + if (not (flags & ObjectFlags::ToEnd) and first.coord() > BufferCoord{0,1} and *(first-1) == '\n' and *(first-2) == '\n') --first; else if ((flags & ObjectFlags::ToEnd) and @@ -565,10 +565,10 @@ Selection select_argument(const Buffer& buffer, const Selection& selection, Selection select_lines(const Buffer& buffer, const Selection& selection) { - ByteCoord anchor = selection.anchor(); - ByteCoord cursor = selection.cursor(); - ByteCoord& to_line_start = anchor <= cursor ? anchor : cursor; - ByteCoord& to_line_end = anchor <= cursor ? cursor : anchor; + BufferCoord anchor = selection.anchor(); + BufferCoord cursor = selection.cursor(); + BufferCoord& to_line_start = anchor <= cursor ? anchor : cursor; + BufferCoord& to_line_end = anchor <= cursor ? cursor : anchor; to_line_start.column = 0; to_line_end.column = buffer[to_line_end.line].length()-1; @@ -578,10 +578,10 @@ Selection select_lines(const Buffer& buffer, const Selection& selection) Selection trim_partial_lines(const Buffer& buffer, const Selection& selection) { - ByteCoord anchor = selection.anchor(); - ByteCoord cursor = selection.cursor(); - ByteCoord& to_line_start = anchor <= cursor ? anchor : cursor; - ByteCoord& to_line_end = anchor <= cursor ? cursor : anchor; + BufferCoord anchor = selection.anchor(); + BufferCoord cursor = selection.cursor(); + BufferCoord& to_line_start = anchor <= cursor ? anchor : cursor; + BufferCoord& to_line_end = anchor <= cursor ? cursor : anchor; if (to_line_start.column != 0) to_line_start = to_line_start.line+1; @@ -591,7 +591,7 @@ Selection trim_partial_lines(const Buffer& buffer, const Selection& selection) return selection; auto prev_line = to_line_end.line-1; - to_line_end = ByteCoord{ prev_line, buffer[prev_line].length()-1 }; + to_line_end = BufferCoord{ prev_line, buffer[prev_line].length()-1 }; } if (to_line_start > to_line_end) diff --git a/src/selectors.hh b/src/selectors.hh index 3aaf11f1..74f0d198 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -14,7 +14,7 @@ namespace Kakoune inline Selection keep_direction(Selection res, const Selection& ref) { if ((res.cursor() < res.anchor()) != (ref.cursor() < ref.anchor())) - std::swap(res.cursor(), res.anchor()); + std::swap(res.cursor(), res.anchor()); return res; } @@ -117,9 +117,9 @@ Selection select_to_reverse(const Buffer& buffer, const Selection& selection, template Selection select_to_line_end(const Buffer& buffer, const Selection& selection) { - ByteCoord begin = selection.cursor(); + BufferCoord begin = selection.cursor(); LineCount line = begin.line; - ByteCoord end = utf8::previous(buffer.iterator_at({line, buffer[line].length() - 1}), + BufferCoord end = utf8::previous(buffer.iterator_at({line, buffer[line].length() - 1}), buffer.iterator_at(line)).coord(); if (end < begin) // Do not go backward when cursor is on eol end = begin; @@ -129,8 +129,8 @@ Selection select_to_line_end(const Buffer& buffer, const Selection& selection) template Selection select_to_line_begin(const Buffer& buffer, const Selection& selection) { - ByteCoord begin = selection.cursor(); - ByteCoord end = begin.line; + BufferCoord begin = selection.cursor(); + BufferCoord end = begin.line; return {only_move ? end : begin, end}; } diff --git a/src/string.cc b/src/string.cc index d7522bd8..f3166895 100644 --- a/src/string.cc +++ b/src/string.cc @@ -366,7 +366,7 @@ bool subsequence_match(StringView str, StringView subseq) return true; } -String expand_tabs(StringView line, CharCount tabstop, CharCount col) +String expand_tabs(StringView line, ColumnCount tabstop, ColumnCount col) { String res; res.reserve(line.length()); @@ -374,23 +374,23 @@ String expand_tabs(StringView line, CharCount tabstop, CharCount col) { if (*it == '\t') { - CharCount end_col = (col / tabstop + 1) * tabstop; + ColumnCount end_col = (col / tabstop + 1) * tabstop; res += String{' ', end_col - col}; col = end_col; ++it; } else { - auto char_end = utf8::next(it, end); - res += {it, char_end}; - ++col; - it = char_end; + auto char_beg = it; + auto cp = utf8::read_codepoint(it, end); + res += {char_beg, it}; + col += get_width(cp); } } return res; } -Vector wrap_lines(StringView text, CharCount max_width) +Vector wrap_lines(StringView text, ColumnCount max_width) { if (max_width <= 0) throw runtime_error("Invalid max width"); @@ -416,9 +416,10 @@ Vector wrap_lines(StringView text, CharCount max_width) while (word_end != end and categorize(*word_end) == cat) ++word_end; - while (word_end > line_begin and word_end - line_begin >= max_width) + while (word_end > line_begin and + StringView{line_begin.base(), word_end.base()}.column_length() >= max_width) { - auto line_end = last_word_end <= line_begin ? line_begin + max_width + auto line_end = last_word_end <= line_begin ? Utf8It{utf8::advance(line_begin.base(), text.end(), max_width), text} : last_word_end; lines.emplace_back(line_begin.base(), line_end.base()); diff --git a/src/string.hh b/src/string.hh index 3fa08a83..2f3fc787 100644 --- a/src/string.hh +++ b/src/string.hh @@ -65,18 +65,26 @@ public: { return utf8::codepoint(utf8::advance(begin(), end(), pos), end()); } CharCount char_length() const { return utf8::distance(begin(), end()); } + ColumnCount column_length() const { return utf8::column_distance(begin(), end()); } [[gnu::always_inline]] bool empty() const { return type().length() == 0_byte; } ByteCount byte_count_to(CharCount count) const - { return utf8::advance(begin(), end(), (int)count) - begin(); } + { return utf8::advance(begin(), end(), count) - begin(); } + + ByteCount byte_count_to(ColumnCount count) const + { return utf8::advance(begin(), end(), count) - begin(); } CharCount char_count_to(ByteCount count) const { return utf8::distance(begin(), begin() + (int)count); } + ColumnCount column_count_to(ByteCount count) const + { return utf8::column_distance(begin(), begin() + (int)count); } + StringView substr(ByteCount from, ByteCount length = INT_MAX) const; StringView substr(CharCount from, CharCount length = INT_MAX) const; + StringView substr(ColumnCount from, ColumnCount length = INT_MAX) const; private: [[gnu::always_inline]] @@ -103,6 +111,14 @@ public: while (count-- > 0) utf8::dump(std::back_inserter(*this), cp); } + explicit String(Codepoint cp, ColumnCount count) + { + kak_assert(count % get_width(cp) == 0); + int cp_count = (int)count / get_width(cp); + reserve(utf8::codepoint_size(cp) * cp_count); + while (cp_count-- > 0) + utf8::dump(std::back_inserter(*this), cp); + } String(const char* begin, const char* end) : m_data(begin, end-begin) {} [[gnu::always_inline]] @@ -251,7 +267,16 @@ inline StringView StringOps::substr(CharCount from, CharCount le { if (length < 0) length = INT_MAX; - auto beg = utf8::advance(begin(), end(), (int)from); + auto beg = utf8::advance(begin(), end(), from); + return StringView{ beg, utf8::advance(beg, end(), length) }; +} + +template +inline StringView StringOps::substr(ColumnCount from, ColumnCount length) const +{ + if (length < 0) + length = INT_MAX; + auto beg = utf8::advance(begin(), end(), from); return StringView{ beg, utf8::advance(beg, end(), length) }; } @@ -358,9 +383,9 @@ inline bool prefix_match(StringView str, StringView prefix) bool subsequence_match(StringView str, StringView subseq); -String expand_tabs(StringView line, CharCount tabstop, CharCount col = 0); +String expand_tabs(StringView line, ColumnCount tabstop, ColumnCount col = 0); -Vector wrap_lines(StringView text, CharCount max_width); +Vector wrap_lines(StringView text, ColumnCount max_width); namespace detail { diff --git a/src/unicode.hh b/src/unicode.hh index 4ceeac74..12b75002 100644 --- a/src/unicode.hh +++ b/src/unicode.hh @@ -48,6 +48,11 @@ inline bool is_basic_alpha(Codepoint c) return (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z'); } +inline size_t get_width(Codepoint c) +{ + return wcwidth((wchar_t)c); +} + enum class CharCategories { Blank, diff --git a/src/units.hh b/src/units.hh index 255fe9e4..e7f853e6 100644 --- a/src/units.hh +++ b/src/units.hh @@ -158,6 +158,18 @@ inline constexpr CharCount operator"" _char(unsigned long long int value) return CharCount(value); } +struct ColumnCount : public StronglyTypedNumber +{ + [[gnu::always_inline]] + constexpr ColumnCount(int value = 0) : StronglyTypedNumber(value) {} +}; + +[[gnu::always_inline]] +inline constexpr ColumnCount operator"" _col(unsigned long long int value) +{ + return ColumnCount(value); +} + } #endif // units_hh_INCLUDED diff --git a/src/user_interface.hh b/src/user_interface.hh index 26cf9097..19d545d9 100644 --- a/src/user_interface.hh +++ b/src/user_interface.hh @@ -13,7 +13,7 @@ namespace Kakoune class String; class DisplayBuffer; class DisplayLine; -struct CharCoord; +struct DisplayCoord; struct Face; struct Key; @@ -42,13 +42,13 @@ public: virtual ~UserInterface() {} virtual void menu_show(ConstArrayView choices, - CharCoord anchor, Face fg, Face bg, + DisplayCoord anchor, Face fg, Face bg, MenuStyle style) = 0; virtual void menu_select(int selected) = 0; virtual void menu_hide() = 0; virtual void info_show(StringView title, StringView content, - CharCoord anchor, Face face, + DisplayCoord anchor, Face face, InfoStyle style) = 0; virtual void info_hide() = 0; @@ -60,7 +60,7 @@ public: const DisplayLine& mode_line, const Face& default_face) = 0; - virtual CharCoord dimensions() = 0; + virtual DisplayCoord dimensions() = 0; virtual bool is_key_available() = 0; virtual Key get_key() = 0; diff --git a/src/utf8.hh b/src/utf8.hh index 62d9dcbd..9fca5fb0 100644 --- a/src/utf8.hh +++ b/src/utf8.hh @@ -25,97 +25,6 @@ inline bool is_character_start(char c) return (c & 0xC0) != 0x80; } -template -void to_next(Iterator& it, const Iterator& end) -{ - if (it != end and read(it) & 0x80) - while (it != end and (*(it) & 0xC0) == 0x80) - ++it; -} - -// returns an iterator to next character first byte -template -Iterator next(Iterator it, const Iterator& end) -{ - to_next(it, end); - return it; -} - -// returns it's parameter if it points to a character first byte, -// or else returns next character first byte -template -Iterator finish(Iterator it, const Iterator& end) -{ - while (it != end and (*(it) & 0xC0) == 0x80) - ++it; - return it; -} - -template -void to_previous(Iterator& it, const Iterator& begin) -{ - while (it != begin and (*(--it) & 0xC0) == 0x80) - ; -} -// returns an iterator to the previous character first byte -template -Iterator previous(Iterator it, const Iterator& begin) -{ - to_previous(it, begin); - return it; -} - -// returns an iterator pointing to the first byte of the -// dth character after (or before if d < 0) the character -// pointed by it -template -Iterator advance(Iterator it, const Iterator& end, CharCount d) -{ - if (it == end) - return it; - - if (d < 0) - { - while (it != end and d != 0) - { - if (is_character_start(*--it)) - ++d; - } - } - else if (d > 0) - { - while (it != end and d != 0) - { - if (is_character_start(*++it)) - --d; - } - } - return it; -} - -// returns the character count between begin and end -template -CharCount distance(Iterator begin, const Iterator& end) -{ - CharCount dist = 0; - - while (begin != end) - { - if (is_character_start(read(begin))) - ++dist; - } - return dist; -} - -// returns an iterator to the first byte of the character it is into -template -Iterator character_start(Iterator it, const Iterator& begin) -{ - while (it != begin and not is_character_start(*it)) - --it; - return it; -} - namespace InvalidPolicy { @@ -213,6 +122,139 @@ inline ByteCount codepoint_size(Codepoint cp) throw invalid_codepoint{}; } +template +void to_next(Iterator& it, const Iterator& end) +{ + if (it != end and read(it) & 0x80) + while (it != end and (*(it) & 0xC0) == 0x80) + ++it; +} + +// returns an iterator to next character first byte +template +Iterator next(Iterator it, const Iterator& end) +{ + to_next(it, end); + return it; +} + +// returns it's parameter if it points to a character first byte, +// or else returns next character first byte +template +Iterator finish(Iterator it, const Iterator& end) +{ + while (it != end and (*(it) & 0xC0) == 0x80) + ++it; + return it; +} + +template +void to_previous(Iterator& it, const Iterator& begin) +{ + while (it != begin and (*(--it) & 0xC0) == 0x80) + ; +} +// returns an iterator to the previous character first byte +template +Iterator previous(Iterator it, const Iterator& begin) +{ + to_previous(it, begin); + return it; +} + +// returns an iterator pointing to the first byte of the +// dth character after (or before if d < 0) the character +// pointed by it +template +Iterator advance(Iterator it, const Iterator& end, CharCount d) +{ + if (it == end) + return it; + + if (d < 0) + { + while (it != end and d != 0) + { + if (is_character_start(*--it)) + ++d; + } + } + else if (d > 0) + { + while (it != end and d != 0) + { + if (is_character_start(*++it)) + --d; + } + } + return it; +} + +// returns an iterator pointing to the first byte of the +// character at the dth column after (or before if d < 0) +// the character pointed by it +template +Iterator advance(Iterator it, const Iterator& end, ColumnCount d) +{ + if (it == end) + return it; + + if (d < 0) + { + while (it != end and d < 0) + { + auto cur = it; + to_previous(it, end); + d += get_width(codepoint(it, cur)); + } + } + else if (d > 0) + { + auto begin = it; + while (it != end and d > 0) + { + d -= get_width(read_codepoint(it, end)); + if (it != end and d < 0) + to_previous(it, begin); + } + } + return it; +} + +// returns the character count between begin and end +template +CharCount distance(Iterator begin, const Iterator& end) +{ + CharCount dist = 0; + + while (begin != end) + { + if (is_character_start(read(begin))) + ++dist; + } + return dist; +} + +// returns the column count between begin and end +template +ColumnCount column_distance(Iterator begin, const Iterator& end) +{ + ColumnCount dist = 0; + + while (begin != end) + dist += get_width(read_codepoint(begin, end)); + return dist; +} + +// returns an iterator to the first byte of the character it is into +template +Iterator character_start(Iterator it, const Iterator& begin) +{ + while (it != begin and not is_character_start(*it)) + --it; + return it; +} + template void dump(OutputIterator&& it, Codepoint cp) { diff --git a/src/window.cc b/src/window.cc index 487cf927..44238ed6 100644 --- a/src/window.cc +++ b/src/window.cc @@ -58,20 +58,20 @@ void Window::center_line(LineCount buffer_line) display_line_at(buffer_line, m_dimensions.line/2_line); } -void Window::scroll(CharCount offset) +void Window::scroll(ColumnCount offset) { - m_position.column = std::max(0_char, m_position.column + offset); + m_position.column = std::max(0_col, m_position.column + offset); } -void Window::display_column_at(CharCount buffer_column, CharCount display_column) +void Window::display_column_at(ColumnCount buffer_column, ColumnCount display_column) { if (display_column >= 0 or display_column < m_dimensions.column) - m_position.column = std::max(0_char, buffer_column - display_column); + m_position.column = std::max(0_col, buffer_column - display_column); } -void Window::center_column(CharCount buffer_column) +void Window::center_column(ColumnCount buffer_column) { - display_column_at(buffer_column, m_dimensions.column/2_char); + display_column_at(buffer_column, m_dimensions.column/2_col); } Window::Setup Window::build_setup(const Context& context) const @@ -117,7 +117,7 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context) DisplayBuffer::LineList& lines = m_display_buffer.lines(); lines.clear(); - if (m_dimensions == CharCoord{0,0}) + if (m_dimensions == DisplayCoord{0,0}) return m_display_buffer; kak_assert(&buffer() == &context.buffer()); @@ -154,13 +154,13 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context) return m_display_buffer; } -void Window::set_position(CharCoord position) +void Window::set_position(DisplayCoord position) { m_position.line = std::max(0_line, position.line); - m_position.column = std::max(0_char, position.column); + m_position.column = std::max(0_col, position.column); } -void Window::set_dimensions(CharCoord dimensions) +void Window::set_dimensions(DisplayCoord dimensions) { if (m_dimensions != dimensions) { @@ -182,12 +182,12 @@ static LineCount adapt_view_pos(LineCount line, LineCount offset, return view_pos; } -static CharCount adapt_view_pos(const DisplayBuffer& display_buffer, CharCount offset, - ByteCoord pos, CharCount view_pos, CharCount view_size) +static ColumnCount adapt_view_pos(const DisplayBuffer& display_buffer, ColumnCount offset, + BufferCoord pos, ColumnCount view_pos, ColumnCount view_size) { offset = std::min(offset, (view_size + 1) / 2); - CharCount buffer_column = 0; - CharCount non_buffer_column = 0; + ColumnCount buffer_column = 0; + ColumnCount non_buffer_column = 0; for (auto& line : display_buffer.lines()) { for (auto& atom : line) @@ -196,12 +196,12 @@ static CharCount adapt_view_pos(const DisplayBuffer& display_buffer, CharCount o { if (atom.begin() <= pos and atom.end() > pos) { - CharCount pos_beg, pos_end; + ColumnCount pos_beg, pos_end; if (atom.type() == DisplayAtom::BufferRange) { auto& buf = atom.buffer(); pos_beg = buffer_column + - char_length(buf, atom.begin(), pos); + column_length(buf, atom.begin(), pos); pos_end = pos_beg+1; } else @@ -211,7 +211,7 @@ static CharCount adapt_view_pos(const DisplayBuffer& display_buffer, CharCount o } if (pos_beg - offset < view_pos) - return std::max(0_char, pos_beg - offset); + return std::max(0_col, pos_beg - offset); if (pos_end + offset >= view_pos + view_size - non_buffer_column) return pos_end + offset - view_size + non_buffer_column; @@ -231,7 +231,7 @@ void Window::scroll_to_keep_selection_visible_ifn(const Context& context) const auto& anchor = selection.anchor(); const auto& cursor = selection.cursor(); - const CharCoord offset = options()["scrolloff"].get(); + const DisplayCoord offset = options()["scrolloff"].get(); // scroll lines if needed, try to get as much of the selection visible as possible m_position.line = adapt_view_pos(anchor.line, offset.line, m_position.line, @@ -262,17 +262,17 @@ void Window::scroll_to_keep_selection_visible_ifn(const Context& context) namespace { -CharCount find_display_column(const DisplayLine& line, const Buffer& buffer, - ByteCoord coord) +ColumnCount find_display_column(const DisplayLine& line, const Buffer& buffer, + BufferCoord coord) { - CharCount column = 0; + ColumnCount column = 0; for (auto& atom : line) { if (atom.has_buffer_range() and coord >= atom.begin() and coord < atom.end()) { if (atom.type() == DisplayAtom::BufferRange) - column += char_length(buffer, atom.begin(), coord); + column += column_length(buffer, atom.begin(), coord); return column; } column += atom.length(); @@ -280,20 +280,20 @@ CharCount find_display_column(const DisplayLine& line, const Buffer& buffer, return column; } -ByteCoord find_buffer_coord(const DisplayLine& line, const Buffer& buffer, - CharCount column) +BufferCoord find_buffer_coord(const DisplayLine& line, const Buffer& buffer, + ColumnCount column) { auto& range = line.range(); for (auto& atom : line) { - CharCount len = atom.length(); + ColumnCount len = atom.length(); if (atom.has_buffer_range() and column < len) { if (atom.type() == DisplayAtom::BufferRange) return buffer.clamp( utf8::advance(buffer.iterator_at(atom.begin()), buffer.iterator_at(range.end), - std::max(0_char, column)).coord()); + std::max(0_col, column)).coord()); return buffer.clamp(atom.begin()); } column -= len; @@ -302,7 +302,7 @@ ByteCoord find_buffer_coord(const DisplayLine& line, const Buffer& buffer, } } -CharCoord Window::display_position(ByteCoord coord) const +DisplayCoord Window::display_position(BufferCoord coord) const { LineCount l = 0; for (auto& line : m_display_buffer.lines()) @@ -315,25 +315,25 @@ CharCoord Window::display_position(ByteCoord coord) const return { 0, 0 }; } -ByteCoord Window::buffer_coord(CharCoord coord) const +BufferCoord Window::buffer_coord(DisplayCoord coord) const { if (m_display_buffer.lines().empty()) return {0,0}; if (coord <= 0_line) coord = {0,0}; if ((int)coord.line >= m_display_buffer.lines().size()) - coord = CharCoord{(int)m_display_buffer.lines().size()-1, INT_MAX}; + coord = DisplayCoord{(int)m_display_buffer.lines().size()-1, INT_MAX}; return find_buffer_coord(m_display_buffer.lines()[(int)coord.line], buffer(), coord.column); } -ByteCoord Window::offset_coord(ByteCoord coord, CharCount offset) +BufferCoord Window::offset_coord(BufferCoord coord, CharCount offset) { return buffer().offset_coord(coord, offset); } -ByteCoordAndTarget Window::offset_coord(ByteCoordAndTarget coord, LineCount offset) +BufferCoordAndTarget Window::offset_coord(BufferCoordAndTarget coord, LineCount offset) { auto line = clamp(coord.line + offset, 0_line, buffer().line_count()-1); DisplayBuffer display_buffer; @@ -349,7 +349,7 @@ ByteCoordAndTarget Window::offset_coord(ByteCoordAndTarget coord, LineCount offs m_highlighters.highlight(input_handler.context(), HighlightFlags::MoveOnly, display_buffer, range); m_builtin_highlighters.highlight(input_handler.context(), HighlightFlags::MoveOnly, display_buffer, range); - CharCount column = coord.target == -1 ? find_display_column(lines[0], buffer(), coord) : coord.target; + ColumnCount column = coord.target == -1 ? find_display_column(lines[0], buffer(), coord) : coord.target; return { find_buffer_coord(lines[1], buffer(), column), column }; } diff --git a/src/window.hh b/src/window.hh index ef9af667..90e5d58a 100644 --- a/src/window.hh +++ b/src/window.hh @@ -18,24 +18,24 @@ public: Window(Buffer& buffer); ~Window(); - const CharCoord& position() const { return m_position; } - void set_position(CharCoord position); + const DisplayCoord& position() const { return m_position; } + void set_position(DisplayCoord position); - const CharCoord& dimensions() const { return m_dimensions; } - void set_dimensions(CharCoord dimensions); + const DisplayCoord& dimensions() const { return m_dimensions; } + void set_dimensions(DisplayCoord dimensions); void scroll(LineCount offset); void center_line(LineCount buffer_line); void display_line_at(LineCount buffer_line, LineCount display_line); - void scroll(CharCount offset); - void center_column(CharCount buffer_column); - void display_column_at(CharCount buffer_column, CharCount display_column); + void scroll(ColumnCount offset); + void center_column(ColumnCount buffer_column); + void display_column_at(ColumnCount buffer_column, ColumnCount display_column); const DisplayBuffer& update_display_buffer(const Context& context); - CharCoord display_position(ByteCoord coord) const; - ByteCoord buffer_coord(CharCoord coord) const; + DisplayCoord display_position(BufferCoord coord) const; + BufferCoord buffer_coord(DisplayCoord coord) const; Highlighter& highlighters() { return m_highlighters; } @@ -44,8 +44,8 @@ public: bool needs_redraw(const Context& context) const; void force_redraw() { m_last_setup = Setup{}; } - ByteCoord offset_coord(ByteCoord coord, CharCount offset); - ByteCoordAndTarget offset_coord(ByteCoordAndTarget coord, LineCount offset); + BufferCoord offset_coord(BufferCoord coord, CharCount offset); + BufferCoordAndTarget offset_coord(BufferCoordAndTarget coord, LineCount offset); void set_client(Client* client) { m_client = client; } @@ -61,8 +61,8 @@ private: SafePtr m_buffer; SafePtr m_client; - CharCoord m_position; - CharCoord m_dimensions; + DisplayCoord m_position; + DisplayCoord m_dimensions; DisplayBuffer m_display_buffer; HighlighterGroup m_highlighters; @@ -70,8 +70,8 @@ private: struct Setup { - CharCoord position; - CharCoord dimensions; + DisplayCoord position; + DisplayCoord dimensions; size_t timestamp; size_t main_selection; Vector selections; diff --git a/test/regression/811-double-width-codepoints/cmd b/test/regression/811-double-width-codepoints/cmd new file mode 100644 index 00000000..4c559f78 --- /dev/null +++ b/test/regression/811-double-width-codepoints/cmd @@ -0,0 +1 @@ +j diff --git a/test/regression/811-double-width-codepoints/in b/test/regression/811-double-width-codepoints/in new file mode 100644 index 00000000..f054ac6a --- /dev/null +++ b/test/regression/811-double-width-codepoints/in @@ -0,0 +1,2 @@ +1234%(5)67%(8)9012 +一二三四五六 diff --git a/test/regression/811-double-width-codepoints/selections b/test/regression/811-double-width-codepoints/selections new file mode 100644 index 00000000..336acf4a --- /dev/null +++ b/test/regression/811-double-width-codepoints/selections @@ -0,0 +1 @@ +三:四