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
This commit is contained in:
Maxime Coste 2016-09-22 20:36:26 +01:00
parent 6e17ecfb6e
commit 35559b65dd
41 changed files with 639 additions and 540 deletions

View File

@ -161,12 +161,12 @@ void Buffer::update_display_name()
m_display_name = compact_path(m_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)); 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); coord.line = Kakoune::clamp(coord.line, 0_line, line_count() - 1);
ByteCount max_col = std::max(0_byte, m_lines[coord.line].length() - 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; return coord;
} }
ByteCoord Buffer::offset_coord(ByteCoord coord, CharCount offset) BufferCoord Buffer::offset_coord(BufferCoord coord, CharCount offset)
{ {
StringView line = m_lines[coord.line]; StringView line = m_lines[coord.line];
auto target = utf8::advance(&line[coord.column], offset < 0 ? line.begin() : line.end()-1, offset); auto target = utf8::advance(&line[coord.column], offset < 0 ? line.begin() : line.end()-1, offset);
return {coord.line, (int)(target - line.begin())}; 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); auto line = Kakoune::clamp(coord.line + offset, 0_line, line_count()-1);
StringView content = m_lines[line]; StringView content = m_lines[line];
character = std::max(0_char, std::min(character, content.char_length() - 2)); column = std::max(0_col, std::min(column, content.column_length() - 2));
return {line, content.byte_count_to(character), character}; 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; String res;
for (auto line = begin.line; line <= end.line and line < line_count(); ++line) for (auto line = begin.line; line <= end.line and line < line_count(); ++line)
@ -213,10 +213,10 @@ struct Buffer::Modification
enum Type { Insert, Erase }; enum Type { Insert, Erase };
Type type; Type type;
ByteCoord coord; BufferCoord coord;
StringDataPtr content; StringDataPtr content;
Modification(Type type, ByteCoord coord, StringDataPtr content) Modification(Type type, BufferCoord coord, StringDataPtr content)
: type(type), coord(coord), content(std::move(content)) {} : type(type), coord(coord), content(std::move(content)) {}
Modification inverse() const Modification inverse() const
@ -441,7 +441,7 @@ void Buffer::check_invariant() const
#endif #endif
} }
ByteCoord Buffer::do_insert(ByteCoord pos, StringView content) BufferCoord Buffer::do_insert(BufferCoord pos, StringView content)
{ {
kak_assert(is_valid(pos)); kak_assert(is_valid(pos));
@ -484,13 +484,13 @@ ByteCoord Buffer::do_insert(ByteCoord pos, StringView content)
std::make_move_iterator(new_lines.end())); std::make_move_iterator(new_lines.end()));
const LineCount last_line = pos.line + new_lines.size() - 1; 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 }); m_changes.push_back({ Change::Insert, at_end, pos, end });
return pos; 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(begin));
kak_assert(is_valid(end)); 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); StringView suffix = m_lines[end.line].substr(end.column);
String new_line = prefix + suffix; String new_line = prefix + suffix;
ByteCoord next; BufferCoord next;
if (new_line.length() != 0) if (new_line.length() != 0)
{ {
m_lines.erase(m_lines.begin() + (int)begin.line, m_lines.begin() + (int)end.line); 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 else
{ {
m_lines.erase(m_lines.begin() + (int)begin.line, m_lines.begin() + (int)end.line + 1); 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 }); 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) void Buffer::apply_modification(const Modification& modification)
{ {
StringView content = modification.content->strview(); StringView content = modification.content->strview();
ByteCoord coord = modification.coord; BufferCoord coord = modification.coord;
kak_assert(is_valid(coord)); kak_assert(is_valid(coord));
switch (modification.type) 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)); kak_assert(is_valid(pos));
if (content.empty()) if (content.empty())
@ -558,13 +558,13 @@ ByteCoord Buffer::insert(ByteCoord pos, StringView content)
return do_insert(pos, real_content->strview()); 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)); 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 // do not erase last \n except if we erase from the start of a line, and normalize
// end coord // end coord
if (is_end(end)) 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} if (begin >= end) // use >= to handle case where begin is {line_count}
return begin; return begin;
@ -575,7 +575,7 @@ ByteCoord Buffer::erase(ByteCoord begin, ByteCoord end)
return do_erase(begin, 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)) if (not (m_flags & Flags::NoUndo))
m_current_undo_group.emplace_back(Modification::Erase, begin, 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); 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) if (count > 0)
{ {
@ -642,7 +642,7 @@ ByteCoord Buffer::advance(ByteCoord coord, ByteCount count) const
return coord; 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) if (coord.column < m_lines[coord.line].length() - 1)
{ {
@ -665,7 +665,7 @@ ByteCoord Buffer::char_next(ByteCoord coord) const
return coord; return coord;
} }
ByteCoord Buffer::char_prev(ByteCoord coord) const BufferCoord Buffer::char_prev(BufferCoord coord) const
{ {
kak_assert(is_valid(coord)); kak_assert(is_valid(coord));
if (is_end(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()); 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) if (m_history_cursor.get() == &m_history)
return {}; return {};
@ -788,13 +788,13 @@ UnitTest test_buffer{[]()
BufferIterator pos = buffer.begin(); BufferIterator pos = buffer.begin();
kak_assert(*pos == 'a'); kak_assert(*pos == 'a');
pos += 6; pos += 6;
kak_assert(pos.coord() == ByteCoord{0, 6}); kak_assert(pos.coord() == BufferCoord{0, 6});
++pos; ++pos;
kak_assert(pos.coord() == ByteCoord{1, 0}); kak_assert(pos.coord() == BufferCoord{1, 0});
--pos; --pos;
kak_assert(pos.coord() == ByteCoord{0, 6}); kak_assert(pos.coord() == BufferCoord{0, 6});
pos += 1; pos += 1;
kak_assert(pos.coord() == ByteCoord{1, 0}); kak_assert(pos.coord() == BufferCoord{1, 0});
buffer.insert(pos.coord(), "tchou kanaky\n"); buffer.insert(pos.coord(), "tchou kanaky\n");
kak_assert(buffer.line_count() == 5); kak_assert(buffer.line_count() == 5);
BufferIterator pos2 = buffer.end(); BufferIterator pos2 = buffer.end();

View File

@ -58,7 +58,7 @@ public:
using iterator_category = std::random_access_iterator_tag; using iterator_category = std::random_access_iterator_tag;
BufferIterator() : m_buffer(nullptr) {} 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;
bool operator!= (const BufferIterator& iterator) const; bool operator!= (const BufferIterator& iterator) const;
@ -83,12 +83,12 @@ public:
BufferIterator operator++ (int); BufferIterator operator++ (int);
BufferIterator operator-- (int); BufferIterator operator-- (int);
const ByteCoord& coord() const { return m_coord; } const BufferCoord& coord() const { return m_coord; }
private: private:
SafePtr<const Buffer> m_buffer; SafePtr<const Buffer> m_buffer;
StringView m_line; StringView m_line;
ByteCoord m_coord; BufferCoord m_coord;
LineCount m_last_line; LineCount m_last_line;
}; };
@ -125,9 +125,9 @@ public:
bool set_name(String name); bool set_name(String name);
void update_display_name(); void update_display_name();
ByteCoord insert(ByteCoord pos, StringView content); BufferCoord insert(BufferCoord pos, StringView content);
ByteCoord erase(ByteCoord begin, ByteCoord end); BufferCoord erase(BufferCoord begin, BufferCoord end);
ByteCoord replace(ByteCoord begin, ByteCoord end, StringView content); BufferCoord replace(BufferCoord begin, BufferCoord end, StringView content);
size_t timestamp() const; size_t timestamp() const;
timespec fs_timestamp() const; timespec fs_timestamp() const;
@ -139,24 +139,24 @@ public:
bool move_to(size_t history_id) noexcept; bool move_to(size_t history_id) noexcept;
size_t current_history_id() const 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; const char& byte_at(BufferCoord c) const;
ByteCount distance(ByteCoord begin, ByteCoord end) const; ByteCount distance(BufferCoord begin, BufferCoord end) const;
ByteCoord advance(ByteCoord coord, ByteCount count) const; BufferCoord advance(BufferCoord coord, ByteCount count) const;
ByteCoord next(ByteCoord coord) const; BufferCoord next(BufferCoord coord) const;
ByteCoord prev(ByteCoord coord) const; BufferCoord prev(BufferCoord coord) const;
ByteCoord char_next(ByteCoord coord) const; BufferCoord char_next(BufferCoord coord) const;
ByteCoord char_prev(ByteCoord coord) const; BufferCoord char_prev(BufferCoord coord) const;
ByteCoord back_coord() const; BufferCoord back_coord() const;
ByteCoord end_coord() const; BufferCoord end_coord() const;
bool is_valid(ByteCoord c) const; bool is_valid(BufferCoord c) const;
bool is_end(ByteCoord c) const; bool is_end(BufferCoord c) const;
ByteCoord last_modification_coord() const; BufferCoord last_modification_coord() const;
BufferIterator begin() const; BufferIterator begin() const;
BufferIterator end() const; BufferIterator end() const;
@ -169,13 +169,13 @@ public:
{ return m_lines.get_storage(line); } { return m_lines.get_storage(line); }
// returns an iterator at given coordinates. clamp line_and_column // 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 // returns nearest valid coordinates from given ones
ByteCoord clamp(ByteCoord coord) const; BufferCoord clamp(BufferCoord coord) const;
ByteCoord offset_coord(ByteCoord coord, CharCount offset); BufferCoord offset_coord(BufferCoord coord, CharCount offset);
ByteCoordAndTarget offset_coord(ByteCoordAndTarget coord, LineCount offset); BufferCoordAndTarget offset_coord(BufferCoordAndTarget coord, LineCount offset);
const String& name() const { return m_name; } const String& name() const { return m_name; }
const String& display_name() const { return m_display_name; } const String& display_name() const { return m_display_name; }
@ -200,8 +200,8 @@ public:
enum Type : char { Insert, Erase }; enum Type : char { Insert, Erase };
Type type; Type type;
bool at_end; bool at_end;
ByteCoord begin; BufferCoord begin;
ByteCoord end; BufferCoord end;
}; };
ConstArrayView<Change> changes_since(size_t timestamp) const; ConstArrayView<Change> changes_since(size_t timestamp) const;
@ -214,8 +214,8 @@ private:
void on_option_changed(const Option& option) override; void on_option_changed(const Option& option) override;
ByteCoord do_insert(ByteCoord pos, StringView content); BufferCoord do_insert(BufferCoord pos, StringView content);
ByteCoord do_erase(ByteCoord begin, ByteCoord end); BufferCoord do_erase(BufferCoord begin, BufferCoord end);
struct Modification; struct Modification;

View File

@ -7,13 +7,13 @@ namespace Kakoune
{ {
[[gnu::always_inline]] [[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()); kak_assert(c.line < line_count() and c.column < m_lines[c.line].length());
return m_lines[c.line][c.column]; 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) if (coord.column < m_lines[coord.line].length() - 1)
++coord.column; ++coord.column;
@ -27,7 +27,7 @@ inline ByteCoord Buffer::next(ByteCoord coord) const
return coord; return coord;
} }
inline ByteCoord Buffer::prev(ByteCoord coord) const inline BufferCoord Buffer::prev(BufferCoord coord) const
{ {
if (coord.column == 0) if (coord.column == 0)
{ {
@ -39,7 +39,7 @@ inline ByteCoord Buffer::prev(ByteCoord coord) const
return coord; return coord;
} }
inline ByteCount Buffer::distance(ByteCoord begin, ByteCoord end) const inline ByteCount Buffer::distance(BufferCoord begin, BufferCoord end) const
{ {
if (begin > end) if (begin > end)
return -distance(end, begin); return -distance(end, begin);
@ -53,7 +53,7 @@ inline ByteCount Buffer::distance(ByteCoord begin, ByteCoord end) const
return res; 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) if (c.line < 0 or c.column < 0)
return false; return false;
@ -63,7 +63,7 @@ inline bool Buffer::is_valid(ByteCoord c) const
(c.line == line_count() and c.column == 0); (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(); return c >= end_coord();
} }
@ -97,18 +97,18 @@ inline ConstArrayView<Buffer::Change> Buffer::changes_since(size_t timestamp) co
return {}; return {};
} }
inline ByteCoord Buffer::back_coord() const inline BufferCoord Buffer::back_coord() const
{ {
return { line_count() - 1, m_lines.back().length() - 1 }; 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() ? 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_buffer(&buffer), m_coord(coord),
m_line((*m_buffer)[coord.line]), m_line((*m_buffer)[coord.line]),
m_last_line(buffer.line_count()-1) m_last_line(buffer.line_count()-1)

View File

@ -12,11 +12,11 @@
namespace Kakoune namespace Kakoune
{ {
CharCount get_column(const Buffer& buffer, ColumnCount get_column(const Buffer& buffer,
CharCount tabstop, ByteCoord coord) ColumnCount tabstop, BufferCoord coord)
{ {
auto line = buffer[coord.line]; auto line = buffer[coord.line];
auto col = 0_char; auto col = 0_col;
for (auto it = line.begin(); for (auto it = line.begin();
it != line.end() and coord.column > (int)(it - line.begin()); it != line.end() and coord.column > (int)(it - line.begin());
it = utf8::next(it, line.end())) it = utf8::next(it, line.end()))
@ -29,10 +29,10 @@ CharCount get_column(const Buffer& buffer,
return col; 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 line = buffer[coord.line];
auto col = 0_char; auto col = 0_col;
auto it = line.begin(); auto it = line.begin();
while (it != line.end() and coord.column > col) 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); count = read(fifo, data, buffer_size);
auto pos = buffer->back_coord(); 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) if (prevent_scrolling)
pos = buffer->next(pos); pos = buffer->next(pos);

View File

@ -15,12 +15,12 @@ inline String content(const Buffer& buffer, const Selection& range)
return buffer.string(range.min(), buffer.char_next(range.max())); 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())); 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); 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()))); 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)); 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; 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; 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<BufferIterator>(buffer.iterator_at(coord), buffer); auto it = utf8::iterator<BufferIterator>(buffer.iterator_at(coord), buffer);
if (coord == ByteCoord{0,0}) if (coord == BufferCoord{0,0})
return is_word(*it); return is_word(*it);
return not is_word(*(it-1)) and 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; return true;
auto it = utf8::iterator<BufferIterator>(buffer.iterator_at(coord), buffer); auto it = utf8::iterator<BufferIterator>(buffer.iterator_at(coord), buffer);
return is_word(*(it-1)) and not is_word(*it); return is_word(*(it-1)) and not is_word(*it);
} }
CharCount get_column(const Buffer& buffer, ColumnCount get_column(const Buffer& buffer,
CharCount tabstop, ByteCoord coord); ColumnCount tabstop, BufferCoord coord);
ByteCount get_byte_to_column(const Buffer& buffer, CharCount tabstop, ByteCount get_byte_to_column(const Buffer& buffer, ColumnCount tabstop,
CharCoord coord); DisplayCoord coord);
Buffer* create_fifo_buffer(String name, int fd, bool scroll = false); Buffer* create_fifo_buffer(String name, int fd, bool scroll = false);
Buffer* open_file_buffer(StringView filename); Buffer* open_file_buffer(StringView filename);

View File

@ -205,7 +205,7 @@ void Client::redraw_ifn()
if (m_ui_pending & MenuShow) if (m_ui_pending & MenuShow)
{ {
m_menu.ui_anchor = m_menu.style == MenuStyle::Inline ? 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, m_ui->menu_show(m_menu.items, m_menu.ui_anchor,
get_face("MenuForeground"), get_face("MenuBackground"), get_face("MenuForeground"), get_face("MenuBackground"),
m_menu.style); m_menu.style);
@ -218,7 +218,7 @@ void Client::redraw_ifn()
if (m_ui_pending & InfoShow) if (m_ui_pending & InfoShow)
{ {
m_info.ui_anchor = is_inline(m_info.style) ? 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, m_ui->info_show(m_info.title, m_info.content, m_info.ui_anchor,
get_face("Information"), m_info.style); get_face("Information"), m_info.style);
} }
@ -330,7 +330,7 @@ void Client::on_option_changed(const Option& option)
} }
} }
void Client::menu_show(Vector<DisplayLine> choices, ByteCoord anchor, MenuStyle style) void Client::menu_show(Vector<DisplayLine> choices, BufferCoord anchor, MenuStyle style)
{ {
m_menu = Menu{ std::move(choices), anchor, {}, style, -1 }; m_menu = Menu{ std::move(choices), anchor, {}, style, -1 };
m_ui_pending |= MenuShow; m_ui_pending |= MenuShow;
@ -351,7 +351,7 @@ void Client::menu_hide()
m_ui_pending &= ~(MenuShow | MenuSelect); 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_info = Info{ std::move(title), std::move(content), anchor, {}, style };
m_ui_pending |= InfoShow; m_ui_pending |= InfoShow;

View File

@ -34,16 +34,16 @@ public:
// handle all the keys currently available in the user interface // handle all the keys currently available in the user interface
void handle_available_input(EventMode mode); void handle_available_input(EventMode mode);
void menu_show(Vector<DisplayLine> choices, ByteCoord anchor, MenuStyle style); void menu_show(Vector<DisplayLine> choices, BufferCoord anchor, MenuStyle style);
void menu_select(int selected); void menu_select(int selected);
void menu_hide(); 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 info_hide();
void print_status(DisplayLine status_line); void print_status(DisplayLine status_line);
CharCoord dimensions() const { return m_ui->dimensions(); } DisplayCoord dimensions() const { return m_ui->dimensions(); }
void force_redraw(); void force_redraw();
void redraw_ifn(); void redraw_ifn();
@ -100,8 +100,8 @@ private:
struct Menu struct Menu
{ {
Vector<DisplayLine> items; Vector<DisplayLine> items;
ByteCoord anchor; BufferCoord anchor;
CharCoord ui_anchor; DisplayCoord ui_anchor;
MenuStyle style; MenuStyle style;
int selected; int selected;
} m_menu; } m_menu;
@ -110,8 +110,8 @@ private:
{ {
String title; String title;
String content; String content;
ByteCoord anchor; BufferCoord anchor;
CharCoord ui_anchor; DisplayCoord ui_anchor;
InfoStyle style; InfoStyle style;
} m_info; } m_info;

View File

@ -80,7 +80,7 @@ public:
StringView str; StringView str;
ByteCount pos; ByteCount pos;
CharCoord coord; DisplayCoord coord;
}; };
bool is_command_separator(char c) 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, void CommandManager::execute_single_command(CommandParameters params,
Context& context, Context& context,
const ShellContext& shell_context, const ShellContext& shell_context,
CharCoord pos) const DisplayCoord pos) const
{ {
if (params.empty()) if (params.empty())
return; return;
@ -429,7 +429,7 @@ void CommandManager::execute(StringView command_line,
if (tokens.empty()) if (tokens.empty())
return; return;
CharCoord command_coord; DisplayCoord command_coord;
Vector<String> params; Vector<String> params;
for (auto it = tokens.begin(); it != tokens.end(); ++it) for (auto it = tokens.begin(); it != tokens.end(); ++it)
{ {

View File

@ -56,20 +56,20 @@ struct Token
}; };
Token() : m_type(Type::Raw) {} 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)) {} : m_type(type), m_begin(b), m_end(e), m_coord(coord), m_content(std::move(str)) {}
Type type() const { return m_type; } Type type() const { return m_type; }
ByteCount begin() const { return m_begin; } ByteCount begin() const { return m_begin; }
ByteCount end() const { return m_end; } 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; } const String& content() const { return m_content; }
private: private:
Type m_type; Type m_type;
ByteCount m_begin; ByteCount m_begin;
ByteCount m_end; ByteCount m_end;
CharCoord m_coord; DisplayCoord m_coord;
String m_content; String m_content;
}; };
@ -111,7 +111,7 @@ private:
void execute_single_command(CommandParameters params, void execute_single_command(CommandParameters params,
Context& context, Context& context,
const ShellContext& shell_context, const ShellContext& shell_context,
CharCoord pos) const; DisplayCoord pos) const;
struct CommandDescriptor struct CommandDescriptor
{ {

View File

@ -1812,14 +1812,14 @@ const CommandDesc info_cmd = {
if (parser.positional_count() > 0) if (parser.positional_count() > 0)
{ {
InfoStyle style = InfoStyle::Prompt; InfoStyle style = InfoStyle::Prompt;
ByteCoord pos; BufferCoord pos;
if (auto anchor = parser.get_switch("anchor")) if (auto anchor = parser.get_switch("anchor"))
{ {
auto dot = find(*anchor, '.'); auto dot = find(*anchor, '.');
if (dot == anchor->end()) if (dot == anchor->end())
throw runtime_error("expected <line>.<column> for anchor"); throw runtime_error("expected <line>.<column> 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}; str_to_int({dot+1, anchor->end()})-1};
style = InfoStyle::Inline; style = InfoStyle::Inline;

View File

@ -91,36 +91,36 @@ struct LineAndColumn
} }
}; };
struct ByteCoord : LineAndColumn<ByteCoord, LineCount, ByteCount> struct BufferCoord : LineAndColumn<BufferCoord, LineCount, ByteCount>
{ {
[[gnu::always_inline]] [[gnu::always_inline]]
constexpr ByteCoord(LineCount line = 0, ByteCount column = 0) constexpr BufferCoord(LineCount line = 0, ByteCount column = 0)
: LineAndColumn(line, column) {} : LineAndColumn(line, column) {}
}; };
struct CharCoord : LineAndColumn<CharCoord, LineCount, CharCount> struct DisplayCoord : LineAndColumn<DisplayCoord, LineCount, ColumnCount>
{ {
[[gnu::always_inline]] [[gnu::always_inline]]
constexpr CharCoord(LineCount line = 0, CharCount column = 0) constexpr DisplayCoord(LineCount line = 0, ColumnCount column = 0)
: LineAndColumn(line, column) {} : LineAndColumn(line, column) {}
static constexpr const char* option_type_name = "coord"; static constexpr const char* option_type_name = "coord";
}; };
struct ByteCoordAndTarget : ByteCoord struct BufferCoordAndTarget : BufferCoord
{ {
[[gnu::always_inline]] [[gnu::always_inline]]
constexpr ByteCoordAndTarget(LineCount line = 0, ByteCount column = 0, CharCount target = -1) constexpr BufferCoordAndTarget(LineCount line = 0, ByteCount column = 0, ColumnCount target = -1)
: ByteCoord(line, column), target(target) {} : BufferCoord(line, column), target(target) {}
[[gnu::always_inline]] [[gnu::always_inline]]
constexpr ByteCoordAndTarget(ByteCoord coord, CharCount target = -1) constexpr BufferCoordAndTarget(BufferCoord coord, ColumnCount target = -1)
: ByteCoord(coord), target(target) {} : 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); return hash_values(val.line, val.column, val.target);
} }

View File

@ -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()) if (comma == str.end() or dot_begin == comma or dot_end == str.end())
throw runtime_error(format("'{}' does not follow <line>.<column>,<line>.<column> format", str)); throw runtime_error(format("'{}' does not follow <line>.<column>,<line>.<column> 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}; 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}; str_to_int({dot_end+1, str.end()}) - 1};
opt.begin = begin; opt.begin = begin;
@ -58,37 +58,39 @@ StringView DisplayAtom::content() const
return {}; return {};
} }
CharCount DisplayAtom::length() const ColumnCount DisplayAtom::length() const
{ {
switch (m_type) switch (m_type)
{ {
case BufferRange: 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 Text:
case ReplacedBufferRange: case ReplacedBufferRange:
return m_text.char_length(); return (int)m_text.column_length();
} }
kak_assert(false); kak_assert(false);
return 0; return 0;
} }
void DisplayAtom::trim_begin(CharCount count) void DisplayAtom::trim_begin(ColumnCount count)
{ {
if (m_type == BufferRange) if (m_type == BufferRange)
m_range.begin = utf8::advance(m_buffer->iterator_at(m_range.begin), 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 else
m_text = m_text.substr(count).str(); m_text = m_text.substr(count).str();
check_invariant(); check_invariant();
} }
void DisplayAtom::trim_end(CharCount count) void DisplayAtom::trim_end(ColumnCount count)
{ {
if (m_type == BufferRange) if (m_type == BufferRange)
m_range.end = utf8::advance(m_buffer->iterator_at(m_range.end), 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 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(); check_invariant();
} }
@ -109,7 +111,7 @@ DisplayLine::DisplayLine(AtomList atoms)
compute_range(); 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->type() == DisplayAtom::BufferRange);
kak_assert(it->begin() < pos); 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)); 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(it->type() == DisplayAtom::Text);
kak_assert(pos > 0); 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) for (auto& atom : m_atoms)
len += atom.length(); len += atom.length();
return len; 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()) 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(); auto len = it->length();
if (len <= first_char) if (len <= first_col)
{ {
m_atoms.erase(it); m_atoms.erase(it);
first_char -= len; first_col -= len;
} }
else else
{ {
it->trim_begin(first_char); it->trim_begin(first_col);
first_char = 0; first_col = 0;
} }
} }
auto it = begin(); auto it = begin();
for (; it != end() and char_count > 0; ++it) for (; it != end() and col_count > 0; ++it)
char_count -= it->length(); col_count -= it->length();
if (char_count < 0) if (col_count < 0)
(it-1)->trim_end(-char_count); (it-1)->trim_end(-col_count);
m_atoms.erase(it, end()); m_atoms.erase(it, end());
compute_range(); compute_range();

View File

@ -11,7 +11,7 @@ namespace Kakoune
{ {
class Buffer; class Buffer;
struct BufferRange{ ByteCoord begin, end; }; struct BufferRange{ BufferCoord begin, end; };
String option_to_string(BufferRange range); String option_to_string(BufferRange range);
void option_from_string(StringView str, BufferRange& opt); void option_from_string(StringView str, BufferRange& opt);
@ -32,7 +32,7 @@ struct DisplayAtom : public UseMemoryDomain<MemoryDomain::Display>
public: public:
enum Type { BufferRange, ReplacedBufferRange, Text }; 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} : m_type(BufferRange), m_buffer(&buffer), m_range{begin, end}
{ check_invariant(); } { check_invariant(); }
@ -41,15 +41,15 @@ public:
{ check_invariant(); } { check_invariant(); }
StringView content() const; StringView content() const;
CharCount length() const; ColumnCount length() const;
const ByteCoord& begin() const const BufferCoord& begin() const
{ {
kak_assert(has_buffer_range()); kak_assert(has_buffer_range());
return m_range.begin; return m_range.begin;
} }
const ByteCoord& end() const const BufferCoord& end() const
{ {
kak_assert(has_buffer_range()); kak_assert(has_buffer_range());
return m_range.end; return m_range.end;
@ -71,8 +71,8 @@ public:
Type type() const { return m_type; } Type type() const { return m_type; }
void trim_begin(CharCount count); void trim_begin(ColumnCount count);
void trim_end(CharCount count); void trim_end(ColumnCount count);
void check_invariant() const; void check_invariant() const;
@ -117,24 +117,24 @@ public:
const AtomList& atoms() const { return m_atoms; } const AtomList& atoms() const { return m_atoms; }
CharCount length() const; ColumnCount length() const;
const BufferRange& range() const { return m_range; } const BufferRange& range() const { return m_range; }
// Split atom pointed by it at buffer coord pos, // Split atom pointed by it at buffer coord pos,
// returns an iterator to the first atom // 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 // 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 insert(iterator it, DisplayAtom atom);
iterator erase(iterator beg, iterator end); iterator erase(iterator beg, iterator end);
void push_back(DisplayAtom atom); void push_back(DisplayAtom atom);
// remove first_char from the begining of the line, and make sure // remove first_col from the begining of the line, and make sure
// the line is less that char_count character // the line is less that col_count character
void trim(CharCount first_char, CharCount char_count, bool only_buffer); void trim(ColumnCount first_col, ColumnCount col_count, bool only_buffer);
void optimize(); void optimize();
private: private:

View File

@ -26,7 +26,7 @@ namespace Kakoune
template<typename T> template<typename T>
void highlight_range(DisplayBuffer& display_buffer, void highlight_range(DisplayBuffer& display_buffer,
ByteCoord begin, ByteCoord end, BufferCoord begin, BufferCoord end,
bool skip_replaced, T func) bool skip_replaced, T func)
{ {
if (begin == end or end <= display_buffer.range().begin 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, void apply_highlighter(const Context& context,
HighlightFlags flags, HighlightFlags flags,
DisplayBuffer& display_buffer, DisplayBuffer& display_buffer,
ByteCoord begin, ByteCoord end, BufferCoord begin, BufferCoord end,
Highlighter& highlighter) Highlighter& highlighter)
{ {
if (begin == end) if (begin == end)
@ -335,8 +335,8 @@ private:
cache.m_regex_version = m_regex_version; cache.m_regex_version = m_regex_version;
} }
const LineCount line_offset = 3; const LineCount line_offset = 3;
BufferRange range{std::max<ByteCoord>(buffer_range.begin, display_range.begin.line - line_offset), BufferRange range{std::max<BufferCoord>(buffer_range.begin, display_range.begin.line - line_offset),
std::min<ByteCoord>(buffer_range.end, display_range.end.line + line_offset)}; std::min<BufferCoord>(buffer_range.end, display_range.end.line + line_offset)};
auto it = std::upper_bound(matches.begin(), matches.end(), range, auto it = std::upper_bound(matches.begin(), matches.end(), range,
[](const BufferRange& lhs, const Cache::RangeAndMatches& rhs) [](const BufferRange& lhs, const Cache::RangeAndMatches& rhs)
@ -514,7 +514,7 @@ HighlighterAndId create_line_highlighter(HighlighterParameters params)
return; return;
auto face = get_face(facespec); auto face = get_face(facespec);
CharCount column = 0; ColumnCount column = 0;
for (auto atom_it = it->begin(); atom_it != it->end(); ++atom_it) for (auto atom_it = it->begin(); atom_it != it->end(); ++atom_it)
{ {
column += atom_it->length(); column += atom_it->length();
@ -524,7 +524,7 @@ HighlighterAndId create_line_highlighter(HighlighterParameters params)
kak_assert(atom_it->begin().line == line); kak_assert(atom_it->begin().line == line);
apply_face(face)(*atom_it); apply_face(face)(*atom_it);
} }
const CharCount remaining = context.window().dimensions().column - column; const ColumnCount remaining = context.window().dimensions().column - column;
if (remaining > 0) if (remaining > 0)
it->push_back({ String{' ', remaining}, face }); it->push_back({ String{' ', remaining}, face });
}; };
@ -545,7 +545,7 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params)
auto func = [=](const Context& context, HighlightFlags flags, auto func = [=](const Context& context, HighlightFlags flags,
DisplayBuffer& display_buffer, BufferRange) DisplayBuffer& display_buffer, BufferRange)
{ {
CharCount column = -1; ColumnCount column = -1;
try try
{ {
column = str_to_int_ifp(expand(col_expr, context)).value_or(0) - 1; 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 LineCount buf_line = line.range().begin.line;
const ByteCount byte_col = get_byte_to_column(buffer, tabstop, {buf_line, column}); 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; bool found = false;
if (buffer.is_valid(coord) and not buffer.is_end(coord)) if (buffer.is_valid(coord) and not buffer.is_end(coord))
{ {
@ -591,8 +591,8 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params)
} }
if (not found) if (not found)
{ {
CharCount first_buffer_col = -1; ColumnCount first_buffer_col = -1;
CharCount first_display_col = 0; ColumnCount first_display_col = 0;
for (auto& atom : line) for (auto& atom : line)
{ {
if (atom.has_buffer_range()) if (atom.has_buffer_range())
@ -606,8 +606,8 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params)
if (first_buffer_col == -1) if (first_buffer_col == -1)
continue; continue;
CharCount eol_col = line.length(); ColumnCount eol_col = line.length();
CharCount count = column + first_display_col - first_buffer_col - eol_col; ColumnCount count = column + first_display_col - first_buffer_col - eol_col;
if (count >= 0) if (count >= 0)
{ {
if (count > 0) if (count > 0)
@ -620,11 +620,11 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params)
{ {
DisplayAtom& atom = *(atom_it-1); DisplayAtom& atom = *(atom_it-1);
const CharCount len = atom.length(); const ColumnCount len = atom.length();
if (atom.type() == DisplayAtom::Text and -count <= len) if (atom.type() == DisplayAtom::Text and -count <= len)
{ {
auto it = atom_it - 1; auto it = atom_it - 1;
CharCount pos = len + count; ColumnCount pos = len + count;
if (pos > 0) if (pos > 0)
{ {
it = ++line.split(it, pos); 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 column = (int)get_column(buffer, tabstop, it.coord());
int count = tabstop - (column % tabstop); int count = tabstop - (column % tabstop);
atom_it->replace("" + String(' ', count-1)); atom_it->replace("" + String(' ', CharCount{count-1}));
} }
else if (c == ' ') else if (c == ' ')
atom_it->replace("·"); atom_it->replace("·");
@ -855,8 +855,8 @@ void highlight_selections(const Context& context, HighlightFlags flags, DisplayB
{ {
auto& sel = selections[i]; auto& sel = selections[i];
const bool forward = sel.anchor() <= sel.cursor(); const bool forward = sel.anchor() <= sel.cursor();
ByteCoord begin = forward ? sel.anchor() : buffer.char_next(sel.cursor()); BufferCoord begin = forward ? sel.anchor() : buffer.char_next(sel.cursor());
ByteCoord end = forward ? (ByteCoord)sel.cursor() : buffer.char_next(sel.anchor()); BufferCoord end = forward ? (BufferCoord)sel.cursor() : buffer.char_next(sel.anchor());
const bool primary = (i == selections.main_index()); const bool primary = (i == selections.main_index());
highlight_range(display_buffer, begin, end, false, 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); atom.face = merge_faces(def_face, atom.face);
} }
CharCount width = 0; ColumnCount width = 0;
for (auto& l : display_lines) for (auto& l : display_lines)
width = std::max(width, l.length()); width = std::max(width, l.length());
const DisplayAtom empty{String{' ', width}, def_face}; const DisplayAtom empty{String{' ', width}, def_face};
@ -1070,8 +1070,8 @@ struct RegexMatch
ByteCount begin; ByteCount begin;
ByteCount end; ByteCount end;
ByteCoord begin_coord() const { return { line, begin }; } BufferCoord begin_coord() const { return { line, begin }; }
ByteCoord end_coord() const { return { line, end }; } BufferCoord end_coord() const { return { line, end }; }
}; };
using RegexMatchList = Vector<RegexMatch, MemoryDomain::Highlight>; using RegexMatchList = Vector<RegexMatch, MemoryDomain::Highlight>;
@ -1147,18 +1147,18 @@ struct RegionMatches
RegexMatchList end_matches; RegexMatchList end_matches;
RegexMatchList recurse_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; 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(), return std::lower_bound(begin_matches.begin(), begin_matches.end(),
pos, compare_to_begin); 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 end_it = end_matches.begin();
auto rec_it = recurse_matches.begin(); auto rec_it = recurse_matches.begin();
@ -1247,10 +1247,10 @@ public:
auto& regions = get_regions_for_range(buffer, range); auto& regions = get_regions_for_range(buffer, range);
auto begin = std::lower_bound(regions.begin(), regions.end(), display_range.begin, 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, auto end = std::lower_bound(begin, regions.end(), display_range.end,
[](const Region& r, ByteCoord c) { return r.begin < c; }); [](const Region& r, BufferCoord c) { return r.begin < c; });
auto correct = [&](ByteCoord c) -> ByteCoord { auto correct = [&](BufferCoord c) -> BufferCoord {
if (not buffer.is_end(c) and buffer[c.line].length() == c.column) if (not buffer.is_end(c) and buffer[c.line].length() == c.column)
return {c.line+1, 0}; return {c.line+1, 0};
return c; return c;
@ -1260,7 +1260,7 @@ public:
const bool apply_default = default_group_it != m_groups.end(); const bool apply_default = default_group_it != m_groups.end();
auto last_begin = (begin == regions.begin()) ? auto last_begin = (begin == regions.begin()) ?
ByteCoord{0,0} : (begin-1)->end; BufferCoord{0,0} : (begin-1)->end;
kak_assert(begin <= end); kak_assert(begin <= end);
for (; begin != end; ++begin) for (; begin != end; ++begin)
{ {
@ -1350,8 +1350,8 @@ private:
struct Region struct Region
{ {
ByteCoord begin; BufferCoord begin;
ByteCoord end; BufferCoord end;
StringView group; StringView group;
}; };
using RegionList = Vector<Region, MemoryDomain::Highlight>; using RegionList = Vector<Region, MemoryDomain::Highlight>;
@ -1367,7 +1367,7 @@ private:
using RegionAndMatch = std::pair<size_t, RegexMatchList::const_iterator>; using RegionAndMatch = std::pair<size_t, RegexMatchList::const_iterator>;
// find the begin closest to pos in all matches // 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)}; RegionAndMatch res{0, cache.matches[0].find_next_begin(pos)};
for (size_t i = 1; i < cache.matches.size(); ++i) for (size_t i = 1; i < cache.matches.size(); ++i)

View File

@ -74,7 +74,7 @@ struct MouseHandler
return false; return false;
Buffer& buffer = context.buffer(); Buffer& buffer = context.buffer();
ByteCoord cursor; BufferCoord cursor;
switch (key.modifiers) switch (key.modifiers)
{ {
case Key::Modifiers::MousePress: case Key::Modifiers::MousePress:
@ -117,7 +117,7 @@ struct MouseHandler
private: private:
bool m_dragging = false; bool m_dragging = false;
ByteCoord m_anchor; BufferCoord m_anchor;
}; };
constexpr StringView register_doc = constexpr StringView register_doc =
@ -371,7 +371,7 @@ public:
{ {
if (m_cursor_pos != 0) 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_line.substr(m_cursor_pos);
--m_cursor_pos; --m_cursor_pos;
@ -429,7 +429,7 @@ public:
const String& line() const { return m_line; } const String& line() const { return m_line; }
CharCount cursor_pos() const { return m_cursor_pos; } 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) { auto cleanup = [](StringView str) {
String res; String res;
@ -448,6 +448,7 @@ public:
return res; return res;
}; };
CharCount width = (int)in_width; // Todo: proper handling of char/column
kak_assert(m_cursor_pos <= m_line.char_length()); kak_assert(m_cursor_pos <= m_line.char_length());
if (m_cursor_pos < m_display_pos) if (m_cursor_pos < m_display_pos)
m_display_pos = m_cursor_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") } }); { cleanup(m_line.substr(m_cursor_pos+1, width - m_cursor_pos + m_display_pos - 1)), get_face("StatusLine") } });
} }
private: private:
CharCount m_cursor_pos = 0; CharCount m_cursor_pos = 0;
CharCount m_display_pos = 0; CharCount m_display_pos = 0;
String m_line; String m_line;
}; };
class Menu : public InputMode class Menu : public InputMode
@ -560,7 +561,7 @@ public:
if (m_edit_filter and context().has_client()) if (m_edit_filter and context().has_client())
{ {
auto prompt = "filter:"_str; 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); auto display_line = m_filter_editor.build_display_line(width);
display_line.insert(display_line.begin(), { prompt, get_face("Prompt") }); display_line.insert(display_line.begin(), { prompt, get_face("Prompt") });
context().print_status(display_line); context().print_status(display_line);
@ -858,7 +859,7 @@ private:
if (not context().has_client()) if (not context().has_client())
return; return;
auto width = context().client().dimensions().column - m_prompt.char_length(); auto width = context().client().dimensions().column - m_prompt.column_length();
DisplayLine display_line; DisplayLine display_line;
if (not (m_flags & PromptFlags::Password)) if (not (m_flags & PromptFlags::Password))
display_line = m_line_editor.build_display_line(width); display_line = m_line_editor.build_display_line(width);
@ -998,7 +999,7 @@ public:
Vector<Selection> sels; Vector<Selection> sels;
for (auto& sel : context().selections()) for (auto& sel : context().selections())
{ {
if (sel.cursor() == ByteCoord{0,0}) if (sel.cursor() == BufferCoord{0,0})
continue; continue;
auto pos = sel.cursor(); auto pos = sel.cursor();
sels.push_back({ buffer.char_prev(pos) }); sels.push_back({ buffer.char_prev(pos) });
@ -1037,7 +1038,7 @@ public:
{ {
auto& selections = context().selections(); auto& selections = context().selections();
for (auto& sel : 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(); selections.sort_and_merge_overlapping();
} }
else if (key == Key::End) else if (key == Key::End)
@ -1186,19 +1187,19 @@ private:
break; break;
case InsertMode::AppendAtLineEnd: case InsertMode::AppendAtLineEnd:
for (auto& sel : selections) 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; break;
case InsertMode::OpenLineBelow: case InsertMode::OpenLineBelow:
for (auto& sel : selections) 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'); insert('\n');
break; break;
case InsertMode::OpenLineAbove: case InsertMode::OpenLineAbove:
for (auto& sel : selections) for (auto& sel : selections)
{ {
auto line = sel.min().line; auto line = sel.min().line;
sel = line > 0 ? ByteCoord{line - 1, buffer[line-1].length() - 1} sel = line > 0 ? BufferCoord{line - 1, buffer[line-1].length() - 1}
: ByteCoord{0, 0}; : BufferCoord{0, 0};
} }
insert('\n'); insert('\n');
// fix case where we inserted at begining // fix case where we inserted at begining
@ -1211,7 +1212,7 @@ private:
case InsertMode::InsertAtLineBegin: case InsertMode::InsertAtLineBegin:
for (auto& sel : selections) for (auto& sel : selections)
{ {
ByteCoord pos = sel.min().line; BufferCoord pos = sel.min().line;
auto pos_non_blank = buffer.iterator_at(pos); auto pos_non_blank = buffer.iterator_at(pos);
while (*pos_non_blank == ' ' or *pos_non_blank == '\t') while (*pos_non_blank == ' ' or *pos_non_blank == '\t')
++pos_non_blank; ++pos_non_blank;
@ -1446,22 +1447,24 @@ void scroll_window(Context& context, LineCount offset)
Window& window = context.window(); Window& window = context.window();
Buffer& buffer = context.buffer(); Buffer& buffer = context.buffer();
CharCoord win_pos = window.position(); DisplayCoord win_pos = window.position();
CharCoord win_dim = window.dimensions(); DisplayCoord win_dim = window.dimensions();
const CharCoord max_offset{(win_dim.line - 1)/2, (win_dim.column - 1)/2}; const DisplayCoord max_offset{(win_dim.line - 1)/2, (win_dim.column - 1)/2};
const CharCoord scrolloff = const DisplayCoord scrolloff =
std::min(context.options()["scrolloff"].get<CharCoord>(), max_offset); std::min(context.options()["scrolloff"].get<DisplayCoord>(), max_offset);
const LineCount line_count = buffer.line_count(); const LineCount line_count = buffer.line_count();
win_pos.line = clamp(win_pos.line + offset, 0_line, line_count-1); win_pos.line = clamp(win_pos.line + offset, 0_line, line_count-1);
SelectionList& selections = context.selections(); 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 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 min_line = clamp_line(win_pos.line + scrolloff.line);
auto max_coord = buffer.offset_coord(clamp_line(win_pos.line + win_dim.line - 1 - scrolloff.line), win_pos.column); 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)}; selections = SelectionList{buffer, clamp(cursor, min_coord, max_coord)};

View File

@ -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); }; auto is_word_pred = [extra_word_char](Codepoint c) { return is_word(c) or contains(extra_word_char, c); };
const Buffer& buffer = sels.buffer(); const Buffer& buffer = sels.buffer();
ByteCoord cursor_pos = sels.main().cursor(); BufferCoord cursor_pos = sels.main().cursor();
using Utf8It = utf8::iterator<BufferIterator>; using Utf8It = utf8::iterator<BufferIterator>;
Utf8It pos{buffer.iterator_at(cursor_pos), buffer}; Utf8It pos{buffer.iterator_at(cursor_pos), buffer};
if (pos == buffer.begin() or not is_word_pred(*(pos-1))) if (pos == buffer.begin() or not is_word_pred(*(pos-1)))
return {}; return {};
ByteCoord word_begin; BufferCoord word_begin;
String prefix; String prefix;
IdMap<int> sel_word_counts; IdMap<int> sel_word_counts;
for (int i = 0; i < sels.size(); ++i) for (int i = 0; i < sels.size(); ++i)
@ -242,7 +242,7 @@ InsertCompletion complete_option(const SelectionList& sels,
StringView option_name) StringView option_name)
{ {
const Buffer& buffer = sels.buffer(); const Buffer& buffer = sels.buffer();
ByteCoord cursor_pos = sels.main().cursor(); BufferCoord cursor_pos = sels.main().cursor();
const CompletionList& opt = options[option_name].get<CompletionList>(); const CompletionList& opt = options[option_name].get<CompletionList>();
if (opt.list.empty()) if (opt.list.empty())
@ -253,7 +253,7 @@ InsertCompletion complete_option(const SelectionList& sels,
MatchResults<String::const_iterator> match; MatchResults<String::const_iterator> match;
if (regex_match(desc.begin(), desc.end(), match, re)) 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 }; str_to_int({match[2].first, match[2].second}) - 1 };
if (not buffer.is_valid(coord)) if (not buffer.is_valid(coord))
return {}; return {};
@ -274,8 +274,8 @@ InsertCompletion complete_option(const SelectionList& sels,
StringView query = buffer[coord.line].substr( StringView query = buffer[coord.line].substr(
coord.column, cursor_pos.column - coord.column); coord.column, cursor_pos.column - coord.column);
const CharCount tabstop = options["tabstop"].get<int>(); const ColumnCount tabstop = options["tabstop"].get<int>();
const CharCount column = get_column(buffer, tabstop, cursor_pos); const ColumnCount column = get_column(buffer, tabstop, cursor_pos);
struct RankedMatchAndInfo : RankedMatch struct RankedMatchAndInfo : RankedMatch
{ {
@ -318,10 +318,10 @@ InsertCompletion complete_option(const SelectionList& sels,
InsertCompletion complete_line(const SelectionList& sels, const OptionManager& options) InsertCompletion complete_line(const SelectionList& sels, const OptionManager& options)
{ {
const Buffer& buffer = sels.buffer(); const Buffer& buffer = sels.buffer();
ByteCoord cursor_pos = sels.main().cursor(); BufferCoord cursor_pos = sels.main().cursor();
const CharCount tabstop = options["tabstop"].get<int>(); const ColumnCount tabstop = options["tabstop"].get<int>();
const CharCount column = get_column(buffer, tabstop, cursor_pos); const ColumnCount column = get_column(buffer, tabstop, cursor_pos);
StringView prefix = buffer[cursor_pos.line].substr(0_byte, cursor_pos.column); StringView prefix = buffer[cursor_pos.line].substr(0_byte, cursor_pos.column);
InsertCompletion::CandidateList candidates; InsertCompletion::CandidateList candidates;

View File

@ -64,8 +64,8 @@ struct InsertCompletion
using CandidateList = Vector<Candidate>; using CandidateList = Vector<Candidate>;
ByteCoord begin; BufferCoord begin;
ByteCoord end; BufferCoord end;
CandidateList candidates; CandidateList candidates;
size_t timestamp; size_t timestamp;

View File

@ -112,7 +112,7 @@ String to_json(const DisplayLine& line)
return to_json(line.atoms()); return to_json(line.atoms());
} }
String to_json(CharCoord coord) String to_json(DisplayCoord coord)
{ {
return format(R"(\{ "line": {}, "column": {} })", coord.line, coord.column); return format(R"(\{ "line": {}, "column": {} })", coord.line, coord.column);
} }
@ -197,7 +197,7 @@ Key JsonUI::get_key()
} }
void JsonUI::menu_show(ConstArrayView<DisplayLine> items, void JsonUI::menu_show(ConstArrayView<DisplayLine> items,
CharCoord anchor, Face fg, Face bg, DisplayCoord anchor, Face fg, Face bg,
MenuStyle style) MenuStyle style)
{ {
rpc_call("menu_show", items, anchor, fg, bg, 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, void JsonUI::info_show(StringView title, StringView content,
CharCoord anchor, Face face, DisplayCoord anchor, Face face,
InfoStyle style) InfoStyle style)
{ {
rpc_call("info_show", title, content, anchor, face, 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); // rpc_call("set_ui_options", options);
} }
CharCoord JsonUI::dimensions() DisplayCoord JsonUI::dimensions()
{ {
return m_dimensions; return m_dimensions;
} }
@ -391,7 +391,7 @@ void JsonUI::eval_json(const Value& json)
if (params.size() != 2) if (params.size() != 2)
throw runtime_error("resize expects 2 parameters"); throw runtime_error("resize expects 2 parameters");
CharCoord dim{params[0].as<int>(), params[1].as<int>()}; DisplayCoord dim{params[0].as<int>(), params[1].as<int>()};
m_dimensions = dim; m_dimensions = dim;
m_pending_keys.push_back(resize(dim)); m_pending_keys.push_back(resize(dim));
} }

View File

@ -30,13 +30,13 @@ public:
Key get_key() override; Key get_key() override;
void menu_show(ConstArrayView<DisplayLine> items, void menu_show(ConstArrayView<DisplayLine> items,
CharCoord anchor, Face fg, Face bg, DisplayCoord anchor, Face fg, Face bg,
MenuStyle style) override; MenuStyle style) override;
void menu_select(int selected) override; void menu_select(int selected) override;
void menu_hide() override; void menu_hide() override;
void info_show(StringView title, StringView content, void info_show(StringView title, StringView content,
CharCoord anchor, Face face, DisplayCoord anchor, Face face,
InfoStyle style) override; InfoStyle style) override;
void info_hide() override; void info_hide() override;
@ -46,7 +46,7 @@ public:
void set_ui_options(const Options& options) override; void set_ui_options(const Options& options) override;
CharCoord dimensions() override; DisplayCoord dimensions() override;
private: private:
void parse_requests(EventMode mode); void parse_requests(EventMode mode);
@ -55,7 +55,7 @@ private:
InputCallback m_input_callback; InputCallback m_input_callback;
FDWatcher m_stdin_watcher; FDWatcher m_stdin_watcher;
Vector<Key> m_pending_keys; Vector<Key> m_pending_keys;
CharCoord m_dimensions; DisplayCoord m_dimensions;
String m_requests; String m_requests;
}; };

View File

@ -115,7 +115,7 @@ String key_to_str(Key key)
{ {
if (key.modifiers & Key::Modifiers::MouseEvent) 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) switch (key.modifiers)
{ {
case Key::Modifiers::MousePos: case Key::Modifiers::MousePos:
@ -133,7 +133,7 @@ String key_to_str(Key key)
} }
else if (key.modifiers == Key::Modifiers::Resize) else if (key.modifiers == Key::Modifiers::Resize)
{ {
auto size = key.coord() + CharCoord{1,1}; auto size = key.coord() + DisplayCoord{1,1};
return format("<resize:{}.{}>", size.line, size.column); return format("<resize:{}.{}>", size.line, size.column);
} }

View File

@ -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 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> codepoint() const; Optional<Codepoint> 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 ctrl(Codepoint key) { return { Key::Modifiers::Control, key }; }
constexpr Key ctrlalt(Codepoint key) { return { Key::Modifiers::ControlAlt, 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_press(DisplayCoord pos) { return { Key::Modifiers::MousePress, encode_coord(pos) }; }
constexpr Key mouse_release(CharCoord pos) { return { Key::Modifiers::MouseRelease, encode_coord(pos) }; } constexpr Key mouse_release(DisplayCoord pos) { return { Key::Modifiers::MouseRelease, encode_coord(pos) }; }
constexpr Key mouse_pos(CharCoord pos) { return { Key::Modifiers::MousePos, encode_coord(pos) }; } constexpr Key mouse_pos(DisplayCoord 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_down(DisplayCoord 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_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); } inline size_t hash_value(const Key& key) { return hash_values(key.modifiers, key.key); }

View File

@ -198,7 +198,7 @@ static void check_indentwidth(const int& val)
if (val < 0) throw runtime_error{"indentwidth should be positive or zero"}; 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) if (so.line < 0 or so.column < 0)
throw runtime_error{"scroll offset must be positive or zero"}; throw runtime_error{"scroll offset must be positive or zero"};
@ -216,7 +216,7 @@ void register_options()
reg.declare_option<int, check_tabstop>("tabstop", "size of a tab character", 8); reg.declare_option<int, check_tabstop>("tabstop", "size of a tab character", 8);
reg.declare_option<int, check_indentwidth>("indentwidth", "indentation width", 4); reg.declare_option<int, check_indentwidth>("indentwidth", "indentation width", 4);
reg.declare_option<CharCoord, check_scrolloff>( reg.declare_option<DisplayCoord, check_scrolloff>(
"scrolloff", "number of lines and columns to keep visible main cursor when scrolling", "scrolloff", "number of lines and columns to keep visible main cursor when scrolling",
{0,0}); {0,0});
reg.declare_option("eolformat", "end of line format", EolFormat::Lf); reg.declare_option("eolformat", "end of line format", EolFormat::Lf);
@ -318,17 +318,17 @@ std::unique_ptr<UserInterface> make_ui(UIType ui_type)
struct DummyUI : UserInterface struct DummyUI : UserInterface
{ {
DummyUI() { set_signal_handler(SIGINT, SIG_DFL); } DummyUI() { set_signal_handler(SIGINT, SIG_DFL); }
void menu_show(ConstArrayView<DisplayLine>, CharCoord, void menu_show(ConstArrayView<DisplayLine>, DisplayCoord,
Face, Face, MenuStyle) override {} Face, Face, MenuStyle) override {}
void menu_select(int) override {} void menu_select(int) override {}
void menu_hide() 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 info_hide() override {}
void draw(const DisplayBuffer&, const Face&, const Face&) override {} void draw(const DisplayBuffer&, const Face&, const Face&) override {}
void draw_status(const DisplayLine&, const DisplayLine&, 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; } bool is_key_available() override { return false; }
Key get_key() override { return Key::Invalid; } Key get_key() override { return Key::Invalid; }
void refresh(bool) override {} 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, int run_server(StringView session, StringView init_command,
bool ignore_kakrc, bool daemon, bool readonly, UIType ui_type, bool ignore_kakrc, bool daemon, bool readonly, UIType ui_type,
ConstArrayView<StringView> files, ByteCoord target_coord) ConstArrayView<StringView> files, BufferCoord target_coord)
{ {
static bool terminate = false; static bool terminate = false;
if (daemon) if (daemon)
@ -839,7 +839,7 @@ int main(int argc, char* argv[])
} }
else else
{ {
ByteCoord target_coord; BufferCoord target_coord;
Vector<StringView> files; Vector<StringView> files;
for (auto& name : parser) for (auto& name : parser)
{ {

View File

@ -266,7 +266,7 @@ NCursesUI::~NCursesUI()
set_signal_handler(SIGCONT, SIG_DFL); 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; pos = p;
size = s; size = s;
@ -277,8 +277,8 @@ void NCursesUI::Window::destroy()
{ {
delwin(win); delwin(win);
win = nullptr; win = nullptr;
pos = CharCoord{}; pos = DisplayCoord{};
size = CharCoord{}; size = DisplayCoord{};
} }
void NCursesUI::Window::refresh() void NCursesUI::Window::refresh()
@ -286,7 +286,7 @@ void NCursesUI::Window::refresh()
if (not win) if (not win)
return; 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, pnoutrefresh(win, 0, 0, (int)pos.line, (int)pos.column,
(int)max_pos.line, (int)max_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, 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) const Face& default_face)
{ {
for (const DisplayAtom& atom : line) 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; const auto remaining_columns = max_column - col_index;
if (content.back() == '\n' and 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)); add_str(window, content.substr(0, content.length()-1));
waddch(window, ' '); waddch(window, ' ');
} }
else else
{ {
content = content.substr(0_char, remaining_columns); content = content.substr(0_col, remaining_columns);
add_str(window, content); 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(); const auto remaining = m_dimensions.column - status_line.length();
if (mode_len < remaining) 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); wmove(m_window, status_line_pos, (int)col);
draw_line(m_window, mode_line, col, m_dimensions.column, default_face); 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(), { "" }); trimmed_mode_line.insert(trimmed_mode_line.begin(), { "" });
kak_assert(trimmed_mode_line.length() == remaining - 1); 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); wmove(m_window, status_line_pos, (int)col);
draw_line(m_window, trimmed_mode_line, col, m_dimensions.column, default_face); 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); intrflush(m_window, false);
keypad(m_window, true); 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")) if (char* csr = tigetstr((char*)"csr"))
putp(tparm(csr, 0, ws.ws_row)); putp(tparm(csr, 0, ws.ws_row));
@ -488,7 +488,7 @@ Key NCursesUI::get_key()
MEVENT ev; MEVENT ev;
if (getmouse(&ev) == OK) 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_PRESS(ev.bstate, 1)) return mouse_press(pos);
if (BUTTON_RELEASE(ev.bstate, 1)) return mouse_release(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); 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; const LineCount& win_height = m_menu.size.line;
kak_assert(win_height <= menu_lines); 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), const LineCount mark_height = min(div_round_up(sq(win_height), menu_lines),
win_height); win_height);
@ -615,7 +615,7 @@ void NCursesUI::draw_menu()
const DisplayLine& item = m_menu.items[item_idx]; const DisplayLine& item = m_menu.items[item_idx];
draw_line(m_menu.win, item, 0, column_width, draw_line(m_menu.win, item, 0, column_width,
item_idx == m_menu.selected_item ? m_menu.fg : m_menu.bg); 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}); add_str(m_menu.win, String{' ', pad});
} }
const bool is_mark = line >= mark_line and const bool is_mark = line >= mark_line and
@ -629,7 +629,7 @@ void NCursesUI::draw_menu()
} }
void NCursesUI::menu_show(ConstArrayView<DisplayLine> items, void NCursesUI::menu_show(ConstArrayView<DisplayLine> items,
CharCoord anchor, Face fg, Face bg, DisplayCoord anchor, Face fg, Face bg,
MenuStyle style) MenuStyle style)
{ {
menu_hide(); menu_hide();
@ -640,11 +640,11 @@ void NCursesUI::menu_show(ConstArrayView<DisplayLine> items,
m_menu.anchor = anchor; m_menu.anchor = anchor;
if (style == MenuStyle::Prompt) 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) else if (m_status_on_top)
anchor.line += 1; anchor.line += 1;
CharCoord maxsize = m_dimensions; DisplayCoord maxsize = m_dimensions;
maxsize.column -= anchor.column; maxsize.column -= anchor.column;
if (maxsize.column <= 2) if (maxsize.column <= 2)
return; return;
@ -652,14 +652,14 @@ void NCursesUI::menu_show(ConstArrayView<DisplayLine> items,
const int item_count = items.size(); const int item_count = items.size();
m_menu.items.clear(); // make sure it is empty m_menu.items.clear(); // make sure it is empty
m_menu.items.reserve(item_count); m_menu.items.reserve(item_count);
CharCount longest = 1; ColumnCount longest = 1;
for (auto& item : items) for (auto& item : items)
longest = max(longest, item.length()); longest = max(longest, item.length());
const bool is_prompt = style == MenuStyle::Prompt; const bool is_prompt = style == MenuStyle::Prompt;
m_menu.columns = is_prompt ? max((int)((maxsize.column-1) / (longest+1)), 1) : 1; 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) if (m_menu.columns > 1 and item_count > 1)
maxlen = maxlen / m_menu.columns - 1; maxlen = maxlen / m_menu.columns - 1;
@ -720,10 +720,10 @@ void NCursesUI::menu_hide()
m_dirty = true; m_dirty = true;
} }
static CharCoord compute_needed_size(StringView str) static DisplayCoord compute_needed_size(StringView str)
{ {
CharCoord res{1,0}; DisplayCoord res{1,0};
CharCount line_len = 0; ColumnCount line_len = 0;
for (auto it = str.begin(), end = str.end(); for (auto it = str.begin(), end = str.end();
it != end; it = utf8::next(it, end)) it != end; it = utf8::next(it, end))
{ {
@ -746,32 +746,32 @@ static CharCoord compute_needed_size(StringView str)
return res; 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, NCursesUI::Rect rect, NCursesUI::Rect to_avoid,
bool prefer_above) bool prefer_above)
{ {
CharCoord pos; DisplayCoord pos;
if (prefer_above) if (prefer_above)
{ {
pos = anchor - CharCoord{size.line}; pos = anchor - DisplayCoord{size.line};
if (pos.line < 0) if (pos.line < 0)
prefer_above = false; prefer_above = false;
} }
auto rect_end = rect.pos + rect.size; auto rect_end = rect.pos + rect.size;
if (not prefer_above) if (not prefer_above)
{ {
pos = anchor + CharCoord{1_line}; pos = anchor + DisplayCoord{1_line};
if (pos.line + size.line > rect_end.line) if (pos.line + size.line > rect_end.line)
pos.line = max(rect.pos.line, anchor.line - size.line); pos.line = max(rect.pos.line, anchor.line - size.line);
} }
if (pos.column + size.column > rect_end.column) if (pos.column + size.column > rect_end.column)
pos.column = max(rect.pos.column, rect_end.column - size.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 // check intersection
if (not (end.line < to_avoid.pos.line or end.column < to_avoid.pos.column or 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; 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<StringView> assistant) ConstArrayView<StringView> assistant)
{ {
CharCoord assistant_size; DisplayCoord assistant_size;
if (not assistant.empty()) if (not assistant.empty())
assistant_size = { (int)assistant.size(), assistant[0].char_length() }; assistant_size = { (int)assistant.size(), assistant[0].column_length() };
String result; 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) if (max_bubble_width < 4)
return result; return result;
Vector<StringView> lines = wrap_lines(message, max_bubble_width); Vector<StringView> 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) 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, auto line_count = max(assistant_size.line-1,
LineCount{(int)lines.size()} + 2); 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} + "─╮"; result += "╭─" + String{dash, bubble_width} + "─╮";
else 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 left{dash, dash_count / 2};
String right{dash, dash_count - dash_count / 2}; String right{dash, dash_count - dash_count / 2};
result += "╭─" + left + "" + title +"" + right +"─╮"; 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) else if (i < lines.size() + 1)
{ {
auto& line = lines[(int)i - 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} + ""; result += "" + line + String{' ', padding} + "";
} }
else if (i == lines.size() + 1) 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, void NCursesUI::info_show(StringView title, StringView content,
CharCoord anchor, Face face, InfoStyle style) DisplayCoord anchor, Face face, InfoStyle style)
{ {
info_hide(); 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, info_box = make_info_box(m_info.title, m_info.content,
m_dimensions.column, m_assistant); 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}; m_dimensions.column-1};
} }
else else
{ {
if (m_status_on_top) if (m_status_on_top)
anchor.line += 1; anchor.line += 1;
CharCount col = anchor.column; ColumnCount col = anchor.column;
if (style == InfoStyle::MenuDoc and m_menu) if (style == InfoStyle::MenuDoc and m_menu)
col = m_menu.pos.column + m_menu.size.column; 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) if (max_width < 4)
return; return;
@ -874,10 +874,10 @@ void NCursesUI::info_show(StringView title, StringView content,
info_box += line + "\n"; 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}; const Rect rect = {m_status_on_top ? 1_line : 0_line, m_dimensions};
if (style == InfoStyle::MenuDoc and m_menu) 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 else
pos = compute_pos(anchor, size, rect, m_menu, style == InfoStyle::InlineAbove); 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); wredrawln(m_window, (int)win.pos.line, (int)win.size.line);
} }
CharCoord NCursesUI::dimensions() DisplayCoord NCursesUI::dimensions()
{ {
return m_dimensions; return m_dimensions;
} }

View File

@ -34,13 +34,13 @@ public:
Key get_key() override; Key get_key() override;
void menu_show(ConstArrayView<DisplayLine> items, void menu_show(ConstArrayView<DisplayLine> items,
CharCoord anchor, Face fg, Face bg, DisplayCoord anchor, Face fg, Face bg,
MenuStyle style) override; MenuStyle style) override;
void menu_select(int selected) override; void menu_select(int selected) override;
void menu_hide() override; void menu_hide() override;
void info_show(StringView title, StringView content, void info_show(StringView title, StringView content,
CharCoord anchor, Face face, DisplayCoord anchor, Face face,
InfoStyle style) override; InfoStyle style) override;
void info_hide() override; void info_hide() override;
@ -50,14 +50,14 @@ public:
void set_ui_options(const Options& options) override; void set_ui_options(const Options& options) override;
CharCoord dimensions() override; DisplayCoord dimensions() override;
static void abort(); static void abort();
struct Rect struct Rect
{ {
CharCoord pos; DisplayCoord pos;
CharCoord size; DisplayCoord size;
}; };
private: private:
void check_resize(bool force = false); void check_resize(bool force = false);
@ -67,12 +67,12 @@ private:
int get_color_pair(const Face& face); int get_color_pair(const Face& face);
void set_face(NCursesWin* window, Face face, const Face& default_face); void set_face(NCursesWin* window, Face face, const Face& default_face);
void draw_line(NCursesWin* window, const DisplayLine& line, void draw_line(NCursesWin* window, const DisplayLine& line,
CharCount col_index, CharCount max_column, ColumnCount col_index, ColumnCount max_column,
const Face& default_face); const Face& default_face);
NCursesWin* m_window = nullptr; NCursesWin* m_window = nullptr;
CharCoord m_dimensions; DisplayCoord m_dimensions;
using ColorPair = std::pair<Color, Color>; using ColorPair = std::pair<Color, Color>;
UnorderedMap<Color, int, MemoryDomain::Faces> m_colors; UnorderedMap<Color, int, MemoryDomain::Faces> m_colors;
@ -81,7 +81,7 @@ private:
struct Window : Rect struct Window : Rect
{ {
void create(const CharCoord& pos, const CharCoord& size); void create(const DisplayCoord& pos, const DisplayCoord& size);
void destroy(); void destroy();
void refresh(); void refresh();
@ -97,7 +97,7 @@ private:
Vector<DisplayLine> items; Vector<DisplayLine> items;
Face fg; Face fg;
Face bg; Face bg;
CharCoord anchor; DisplayCoord anchor;
MenuStyle style; MenuStyle style;
int selected_item = 0; int selected_item = 0;
int columns = 1; int columns = 1;
@ -111,7 +111,7 @@ private:
String title; String title;
String content; String content;
Face face; Face face;
CharCoord anchor; DisplayCoord anchor;
InfoStyle style; InfoStyle style;
} m_info; } m_info;

View File

@ -71,7 +71,7 @@ void select(Context& context, NormalParams)
} }
template<SelectMode mode = SelectMode::Replace> template<SelectMode mode = SelectMode::Replace>
void select_coord(Buffer& buffer, ByteCoord coord, SelectionList& selections) void select_coord(Buffer& buffer, BufferCoord coord, SelectionList& selections)
{ {
coord = buffer.clamp(coord); coord = buffer.clamp(coord);
if (mode == SelectMode::Replace) if (mode == SelectMode::Replace)
@ -118,7 +118,7 @@ void goto_commands(Context& context, NormalParams params)
case 'g': case 'g':
case 'k': case 'k':
context.push_jump(); context.push_jump();
select_coord<mode>(buffer, ByteCoord{0,0}, context.selections()); select_coord<mode>(buffer, BufferCoord{0,0}, context.selections());
break; break;
case 'l': case 'l':
select<mode, select_to_line_end<true>>(context, {}); select<mode, select_to_line_end<true>>(context, {});
@ -204,7 +204,7 @@ void goto_commands(Context& context, NormalParams params)
if (pos >= buffer.back_coord()) if (pos >= buffer.back_coord())
pos = buffer.back_coord(); pos = buffer.back_coord();
else if (buffer[pos.line].length() == pos.column + 1) else if (buffer[pos.line].length() == pos.column + 1)
pos = ByteCoord{ pos.line+1, 0 }; pos = BufferCoord{ pos.line+1, 0 };
select_coord<mode>(buffer, pos, context.selections()); select_coord<mode>(buffer, pos, context.selections());
break; break;
} }
@ -240,7 +240,7 @@ void view_commands(Context& context, NormalParams params)
if (not cp or not context.has_window()) if (not cp or not context.has_window())
return; return;
const ByteCoord cursor = context.selections().main().cursor(); const BufferCoord cursor = context.selections().main().cursor();
Window& window = context.window(); Window& window = context.window();
switch (to_lower(*cp)) switch (to_lower(*cp))
{ {
@ -250,7 +250,7 @@ void view_commands(Context& context, NormalParams params)
break; break;
case 'm': case 'm':
context.window().center_column( context.window().center_column(
context.buffer()[cursor.line].char_count_to(cursor.column)); context.buffer()[cursor.line].column_count_to(cursor.column));
break; break;
case 't': case 't':
context.window().display_line_at(cursor.line, 0); 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); context.window().display_line_at(cursor.line, window.dimensions().line-1);
break; break;
case 'h': case 'h':
context.window().scroll(-std::max<CharCount>(1, count)); context.window().scroll(-std::max<ColumnCount>(1, count));
break; break;
case 'j': case 'j':
context.window().scroll( std::max<LineCount>(1, count)); context.window().scroll( std::max<LineCount>(1, count));
@ -268,7 +268,7 @@ void view_commands(Context& context, NormalParams params)
context.window().scroll(-std::max<LineCount>(1, count)); context.window().scroll(-std::max<LineCount>(1, count));
break; break;
case 'l': case 'l':
context.window().scroll( std::max<CharCount>(1, count)); context.window().scroll( std::max<ColumnCount>(1, count));
break; break;
} }
}, "view", }, "view",
@ -592,7 +592,7 @@ void paste_all(Context& context, NormalParams params)
template<typename T> template<typename T>
void regex_prompt(Context& context, String prompt, T func) 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(); SelectionList selections = context.selections();
context.input_handler().prompt( context.input_handler().prompt(
std::move(prompt), "", get_face("Prompt"), PromptFlags::None, complete_nothing, std::move(prompt), "", get_face("Prompt"), PromptFlags::None, complete_nothing,
@ -875,8 +875,8 @@ void indent(Context& context, NormalParams)
template<bool deindent_incomplete = true> template<bool deindent_incomplete = true>
void deindent(Context& context, NormalParams) void deindent(Context& context, NormalParams)
{ {
CharCount tabstop = context.options()["tabstop"].get<int>(); ColumnCount tabstop = context.options()["tabstop"].get<int>();
CharCount indent_width = context.options()["indentwidth"].get<int>(); ColumnCount indent_width = context.options()["indentwidth"].get<int>();
if (indent_width == 0) if (indent_width == 0)
indent_width = tabstop; indent_width = tabstop;
@ -888,7 +888,7 @@ void deindent(Context& context, NormalParams)
for (auto line = std::max(sel.min().line, last_line); for (auto line = std::max(sel.min().line, last_line);
line < sel.max().line+1; ++line) line < sel.max().line+1; ++line)
{ {
CharCount width = 0; ColumnCount width = 0;
auto content = buffer[line]; auto content = buffer[line];
for (auto column = 0_byte; column < content.length(); ++column) for (auto column = 0_byte; column < content.length(); ++column)
{ {
@ -900,12 +900,12 @@ void deindent(Context& context, NormalParams)
else else
{ {
if (deindent_incomplete and width != 0) if (deindent_incomplete and width != 0)
sels.push_back({ line, ByteCoord{line, column-1} }); sels.push_back({ line, BufferCoord{line, column-1} });
break; break;
} }
if (width == indent_width) if (width == indent_width)
{ {
sels.push_back({ line, ByteCoord{line, column} }); sels.push_back({ line, BufferCoord{line, column} });
break; break;
} }
} }
@ -1048,14 +1048,14 @@ void copy_selections_on_next_lines(Context& context, NormalParams params)
{ {
auto& selections = context.selections(); auto& selections = context.selections();
auto& buffer = context.buffer(); auto& buffer = context.buffer();
const CharCount tabstop = context.options()["tabstop"].get<int>(); const ColumnCount tabstop = context.options()["tabstop"].get<int>();
Vector<Selection> result; Vector<Selection> result;
for (auto& sel : selections) for (auto& sel : selections)
{ {
auto anchor = sel.anchor(); auto anchor = sel.anchor();
auto cursor = sel.cursor(); auto cursor = sel.cursor();
CharCount cursor_col = get_column(buffer, tabstop, cursor); ColumnCount cursor_col = get_column(buffer, tabstop, cursor);
CharCount anchor_col = get_column(buffer, tabstop, anchor); ColumnCount anchor_col = get_column(buffer, tabstop, anchor);
result.push_back(std::move(sel)); result.push_back(std::move(sel));
for (int i = 0; i < std::max(params.count, 1); ++i) 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 if (anchor_byte != buffer[anchor_line].length() and
cursor_byte != buffer[cursor_line].length()) cursor_byte != buffer[cursor_line].length())
result.emplace_back(ByteCoord{anchor_line, anchor_byte}, result.emplace_back(BufferCoord{anchor_line, anchor_byte},
ByteCoordAndTarget{cursor_line, cursor_byte, cursor.target}); BufferCoordAndTarget{cursor_line, cursor_byte, cursor.target});
} }
} }
selections = std::move(result); selections = std::move(result);
@ -1206,7 +1206,7 @@ void align(Context& context, NormalParams)
{ {
auto& selections = context.selections(); auto& selections = context.selections();
auto& buffer = context.buffer(); auto& buffer = context.buffer();
const CharCount tabstop = context.options()["tabstop"].get<int>(); const ColumnCount tabstop = context.options()["tabstop"].get<int>();
Vector<Vector<const Selection*>> columns; Vector<Vector<const Selection*>> columns;
LineCount last_line = -1; LineCount last_line = -1;
@ -1227,7 +1227,7 @@ void align(Context& context, NormalParams)
const bool use_tabs = context.options()["aligntab"].get<bool>(); const bool use_tabs = context.options()["aligntab"].get<bool>();
for (auto& col : columns) for (auto& col : columns)
{ {
CharCount maxcol = 0; ColumnCount maxcol = 0;
for (auto& sel : col) for (auto& sel : col)
maxcol = std::max(get_column(buffer, tabstop, sel->cursor()), maxcol); maxcol = std::max(get_column(buffer, tabstop, sel->cursor()), maxcol);
for (auto& sel : col) for (auto& sel : col)
@ -1292,8 +1292,8 @@ void copy_indent(Context& context, NormalParams params)
void tabs_to_spaces(Context& context, NormalParams params) void tabs_to_spaces(Context& context, NormalParams params)
{ {
auto& buffer = context.buffer(); auto& buffer = context.buffer();
const CharCount opt_tabstop = context.options()["tabstop"].get<int>(); const ColumnCount opt_tabstop = context.options()["tabstop"].get<int>();
const CharCount tabstop = params.count == 0 ? opt_tabstop : params.count; const ColumnCount tabstop = params.count == 0 ? opt_tabstop : params.count;
Vector<Selection> tabs; Vector<Selection> tabs;
Vector<String> spaces; Vector<String> spaces;
for (auto& sel : context.selections()) for (auto& sel : context.selections())
@ -1303,8 +1303,8 @@ void tabs_to_spaces(Context& context, NormalParams params)
{ {
if (*it == '\t') if (*it == '\t')
{ {
CharCount col = get_column(buffer, opt_tabstop, it.coord()); ColumnCount col = get_column(buffer, opt_tabstop, it.coord());
CharCount end_col = (col / tabstop + 1) * tabstop; ColumnCount end_col = (col / tabstop + 1) * tabstop;
tabs.push_back({ it.coord() }); tabs.push_back({ it.coord() });
spaces.push_back(String{ ' ', end_col - col }); 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) void spaces_to_tabs(Context& context, NormalParams params)
{ {
auto& buffer = context.buffer(); auto& buffer = context.buffer();
const CharCount opt_tabstop = context.options()["tabstop"].get<int>(); const ColumnCount opt_tabstop = context.options()["tabstop"].get<int>();
const CharCount tabstop = params.count == 0 ? opt_tabstop : params.count; const ColumnCount tabstop = params.count == 0 ? opt_tabstop : params.count;
Vector<Selection> spaces; Vector<Selection> spaces;
for (auto& sel : context.selections()) for (auto& sel : context.selections())
{ {
@ -1329,7 +1329,7 @@ void spaces_to_tabs(Context& context, NormalParams params)
{ {
auto spaces_beg = it; auto spaces_beg = it;
auto spaces_end = spaces_beg+1; 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 while (spaces_end != end and
*spaces_end == ' ' and (col % tabstop) != 0) *spaces_end == ' ' and (col % tabstop) != 0)
{ {
@ -1570,7 +1570,7 @@ void flip_selections(Context& context, NormalParams)
{ {
for (auto& sel : context.selections()) for (auto& sel : context.selections())
{ {
const ByteCoord tmp = sel.anchor(); const BufferCoord tmp = sel.anchor();
sel.anchor() = sel.cursor(); sel.anchor() = sel.cursor();
sel.cursor() = tmp; sel.cursor() = tmp;
} }
@ -1581,7 +1581,7 @@ void ensure_forward(Context& context, NormalParams)
{ {
for (auto& sel : context.selections()) 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.anchor() = min;
sel.cursor() = max; sel.cursor() = max;
} }

View File

@ -291,17 +291,17 @@ DisplayBuffer MsgReader::read<DisplayBuffer>()
class RemoteUI : public UserInterface class RemoteUI : public UserInterface
{ {
public: public:
RemoteUI(int socket, CharCoord dimensions); RemoteUI(int socket, DisplayCoord dimensions);
~RemoteUI(); ~RemoteUI();
void menu_show(ConstArrayView<DisplayLine> choices, void menu_show(ConstArrayView<DisplayLine> choices,
CharCoord anchor, Face fg, Face bg, DisplayCoord anchor, Face fg, Face bg,
MenuStyle style) override; MenuStyle style) override;
void menu_select(int selected) override; void menu_select(int selected) override;
void menu_hide() override; void menu_hide() override;
void info_show(StringView title, StringView content, void info_show(StringView title, StringView content,
CharCoord anchor, Face face, DisplayCoord anchor, Face face,
InfoStyle style) override; InfoStyle style) override;
void info_hide() override; void info_hide() override;
@ -317,7 +317,7 @@ public:
bool is_key_available() override; bool is_key_available() override;
Key get_key() override; Key get_key() override;
CharCoord dimensions() override; DisplayCoord dimensions() override;
void set_input_callback(InputCallback callback) override; void set_input_callback(InputCallback callback) override;
@ -329,7 +329,7 @@ public:
private: private:
FDWatcher m_socket_watcher; FDWatcher m_socket_watcher;
MsgReader m_reader; MsgReader m_reader;
CharCoord m_dimensions; DisplayCoord m_dimensions;
InputCallback m_input_callback; InputCallback m_input_callback;
SafePtr<Client> m_client; SafePtr<Client> 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) { : m_socket_watcher(socket, [this](FDWatcher& watcher, EventMode mode) {
const int sock = watcher.fd(); const int sock = watcher.fd();
bool disconnect = false; bool disconnect = false;
@ -380,7 +380,7 @@ RemoteUI::~RemoteUI()
} }
void RemoteUI::menu_show(ConstArrayView<DisplayLine> choices, void RemoteUI::menu_show(ConstArrayView<DisplayLine> choices,
CharCoord anchor, Face fg, Face bg, DisplayCoord anchor, Face fg, Face bg,
MenuStyle style) MenuStyle style)
{ {
MsgWriter msg{m_socket_watcher.fd(), MessageType::MenuShow}; MsgWriter msg{m_socket_watcher.fd(), MessageType::MenuShow};
@ -403,7 +403,7 @@ void RemoteUI::menu_hide()
} }
void RemoteUI::info_show(StringView title, StringView content, void RemoteUI::info_show(StringView title, StringView content,
CharCoord anchor, Face face, DisplayCoord anchor, Face face,
InfoStyle style) InfoStyle style)
{ {
MsgWriter msg{m_socket_watcher.fd(), MessageType::InfoShow}; MsgWriter msg{m_socket_watcher.fd(), MessageType::InfoShow};
@ -466,7 +466,7 @@ Key RemoteUI::get_key()
return key; return key;
} }
CharCoord RemoteUI::dimensions() DisplayCoord RemoteUI::dimensions()
{ {
return m_dimensions; return m_dimensions;
} }
@ -535,7 +535,7 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr<UserInterface>&&
case MessageType::MenuShow: case MessageType::MenuShow:
{ {
auto choices = reader.read_vector<DisplayLine>(); auto choices = reader.read_vector<DisplayLine>();
auto anchor = reader.read<CharCoord>(); auto anchor = reader.read<DisplayCoord>();
auto fg = reader.read<Face>(); auto fg = reader.read<Face>();
auto bg = reader.read<Face>(); auto bg = reader.read<Face>();
auto style = reader.read<MenuStyle>(); auto style = reader.read<MenuStyle>();
@ -552,7 +552,7 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr<UserInterface>&&
{ {
auto title = reader.read<String>(); auto title = reader.read<String>();
auto content = reader.read<String>(); auto content = reader.read<String>();
auto anchor = reader.read<CharCoord>(); auto anchor = reader.read<DisplayCoord>();
auto face = reader.read<Face>(); auto face = reader.read<Face>();
auto style = reader.read<InfoStyle>(); auto style = reader.read<InfoStyle>();
m_ui->info_show(title, content, anchor, face, style); m_ui->info_show(title, content, anchor, face, style);
@ -643,7 +643,7 @@ private:
case MessageType::Connect: case MessageType::Connect:
{ {
auto init_command = m_reader.read<String>(); auto init_command = m_reader.read<String>();
auto dimensions = m_reader.read<CharCoord>(); auto dimensions = m_reader.read<DisplayCoord>();
auto env_vars = m_reader.read_idmap<String, MemoryDomain::EnvVars>(); auto env_vars = m_reader.read_idmap<String, MemoryDomain::EnvVars>();
RemoteUI* ui = new RemoteUI{sock, dimensions}; RemoteUI* ui = new RemoteUI{sock, dimensions};
if (auto* client = ClientManager::instance().create_client( if (auto* client = ClientManager::instance().create_client(

View File

@ -38,7 +38,7 @@ SelectionList::SelectionList(Buffer& buffer, Vector<Selection> s)
namespace namespace
{ {
ByteCoord update_insert(ByteCoord coord, ByteCoord begin, ByteCoord end) BufferCoord update_insert(BufferCoord coord, BufferCoord begin, BufferCoord end)
{ {
if (coord < begin) if (coord < begin)
return coord; return coord;
@ -50,7 +50,7 @@ ByteCoord update_insert(ByteCoord coord, ByteCoord begin, ByteCoord end)
} }
/* For reference /* For reference
ByteCoord update_erase(ByteCoord coord, ByteCoord begin, ByteCoord end) BufferCoord update_erase(BufferCoord coord, BufferCoord begin, BufferCoord end)
{ {
if (coord < begin) if (coord < begin)
return coord; return coord;
@ -101,8 +101,8 @@ Iterator merge_overlapping(Iterator begin, Iterator end, size_t& main, OverlapsF
// *after* the previous one. // *after* the previous one.
struct ForwardChangesTracker struct ForwardChangesTracker
{ {
ByteCoord cur_pos; // last change position at current modification BufferCoord cur_pos; // last change position at current modification
ByteCoord old_pos; // last change position at start BufferCoord old_pos; // last change position at start
void update(const Buffer::Change& change) void update(const Buffer::Change& change)
{ {
@ -127,7 +127,7 @@ struct ForwardChangesTracker
timestamp = buffer.timestamp(); timestamp = buffer.timestamp();
} }
ByteCoord get_old_coord(ByteCoord coord) const BufferCoord get_old_coord(BufferCoord coord) const
{ {
kak_assert(cur_pos <= coord); kak_assert(cur_pos <= coord);
auto pos_change = cur_pos - old_pos; auto pos_change = cur_pos - old_pos;
@ -141,7 +141,7 @@ struct ForwardChangesTracker
return coord; return coord;
} }
ByteCoord get_new_coord(ByteCoord coord) const BufferCoord get_new_coord(BufferCoord coord) const
{ {
kak_assert(old_pos <= coord); kak_assert(old_pos <= coord);
auto pos_change = cur_pos - old_pos; auto pos_change = cur_pos - old_pos;
@ -155,14 +155,14 @@ struct ForwardChangesTracker
return coord; return coord;
} }
ByteCoord get_new_coord_tolerant(ByteCoord coord) const BufferCoord get_new_coord_tolerant(BufferCoord coord) const
{ {
if (coord < old_pos) if (coord < old_pos)
return cur_pos; return cur_pos;
return get_new_coord(coord); 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); auto new_coord = get_new_coord_tolerant(old_coord);
return change.type == Buffer::Change::Insert ? change.begin <= new_coord return change.type == Buffer::Change::Insert ? change.begin <= new_coord
@ -202,7 +202,7 @@ void update_forward(ConstArrayView<Buffer::Change> changes, Vector<Selection>& s
ForwardChangesTracker changes_tracker; ForwardChangesTracker changes_tracker;
auto change_it = changes.begin(); 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)) while (change_it != changes.end() and changes_tracker.relevant(*change_it, pos))
changes_tracker.update(*change_it++); changes_tracker.update(*change_it++);
}; };
@ -227,7 +227,7 @@ void update_backward(ConstArrayView<Buffer::Change> changes, Vector<Selection>&
using ReverseIt = std::reverse_iterator<const Buffer::Change*>; using ReverseIt = std::reverse_iterator<const Buffer::Change*>;
auto change_it = ReverseIt(changes.end()); auto change_it = ReverseIt(changes.end());
auto change_end = ReverseIt(changes.begin()); 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) while (change_it != change_end)
{ {
auto change = *change_it; auto change = *change_it;
@ -314,7 +314,7 @@ Vector<Selection> compute_modified_ranges(Buffer& buffer, size_t timestamp)
for (auto& range : ranges) for (auto& range : ranges)
{ {
range.anchor() = std::min(range.anchor(), end_coord); range.anchor() = std::min(range.anchor(), end_coord);
range.cursor() = std::min<ByteCoord>(range.cursor(), end_coord); range.cursor() = std::min<BufferCoord>(range.cursor(), end_coord);
} }
auto touches = [&](const Selection& lhs, const Selection& rhs) { auto touches = [&](const Selection& lhs, const Selection& rhs) {
@ -401,7 +401,7 @@ void SelectionList::check_invariant() const
return; return;
const auto end_coord = buffer.end_coord(); const auto end_coord = buffer.end_coord();
ByteCoord last_min{0,0}; BufferCoord last_min{0,0};
for (auto& sel : m_selections) for (auto& sel : m_selections)
{ {
auto& min = sel.min(); auto& min = sel.min();
@ -409,11 +409,11 @@ void SelectionList::check_invariant() const
last_min = min; last_min = min;
const auto anchor = sel.anchor(); 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()); kak_assert(anchor.column < buffer[anchor.line].length());
const auto cursor = sel.cursor(); 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()); kak_assert(cursor.column < buffer[cursor.line].length());
} }
#endif #endif
@ -463,7 +463,7 @@ void SelectionList::sort_and_merge_overlapping()
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 column = coord.column;
auto line = buffer[coord.line]; 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) switch (mode)
{ {
@ -588,7 +588,7 @@ void SelectionList::erase()
changes_tracker.update(*m_buffer, m_timestamp); 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) for (auto& sel : m_selections)
{ {
if (sel.anchor() > back_coord) 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()) if (comma == desc.end() or dot_anchor == comma or dot_cursor == desc.end())
throw runtime_error(format("'{}' does not follow <line>.<column>,<line>.<column> format", desc)); throw runtime_error(format("'{}' does not follow <line>.<column>,<line>.<column> 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}; 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}; str_to_int({dot_cursor+1, desc.end()}) - 1};
return Selection{anchor, cursor}; return Selection{anchor, cursor};

View File

@ -14,19 +14,19 @@ struct Selection
static constexpr MemoryDomain Domain = MemoryDomain::Selections; static constexpr MemoryDomain Domain = MemoryDomain::Selections;
Selection() = default; Selection() = default;
Selection(ByteCoord pos) : Selection(pos,pos) {} Selection(BufferCoord pos) : Selection(pos,pos) {}
Selection(ByteCoord anchor, ByteCoord cursor, Selection(BufferCoord anchor, BufferCoord cursor,
CaptureList captures = {}) CaptureList captures = {})
: m_anchor{anchor}, m_cursor{cursor}, : m_anchor{anchor}, m_cursor{cursor},
m_captures(std::move(captures)) {} m_captures(std::move(captures)) {}
void merge_with(const Selection& range); void merge_with(const Selection& range);
ByteCoord& anchor() { return m_anchor; } BufferCoord& anchor() { return m_anchor; }
ByteCoordAndTarget& cursor() { return m_cursor; } BufferCoordAndTarget& cursor() { return m_cursor; }
const ByteCoord& anchor() const { return m_anchor; } const BufferCoord& anchor() const { return m_anchor; }
const ByteCoordAndTarget& cursor() const { return m_cursor; } const BufferCoordAndTarget& cursor() const { return m_cursor; }
CaptureList& captures() { return m_captures; } CaptureList& captures() { return m_captures; }
const CaptureList& captures() const { 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; 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 BufferCoord& 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& max() const { return m_anchor < m_cursor ? m_cursor : m_anchor; }
ByteCoord& min() { return m_anchor < m_cursor ? m_anchor : m_cursor; } BufferCoord& min() { return m_anchor < m_cursor ? m_anchor : m_cursor; }
ByteCoord& max() { return m_anchor < m_cursor ? m_cursor : m_anchor; } BufferCoord& max() { return m_anchor < m_cursor ? m_cursor : m_anchor; }
private: private:
ByteCoord m_anchor; BufferCoord m_anchor;
ByteCoordAndTarget m_cursor; BufferCoordAndTarget m_cursor;
CaptureList m_captures; CaptureList m_captures;
}; };

View File

@ -341,7 +341,7 @@ Selection select_paragraph(const Buffer& buffer, const Selection& selection, int
{ {
BufferIterator first = buffer.iterator_at(selection.cursor()); 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-1) == '\n' and *(first-2) == '\n')
--first; --first;
else if ((flags & ObjectFlags::ToEnd) and 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) Selection select_lines(const Buffer& buffer, const Selection& selection)
{ {
ByteCoord anchor = selection.anchor(); BufferCoord anchor = selection.anchor();
ByteCoord cursor = selection.cursor(); BufferCoord cursor = selection.cursor();
ByteCoord& to_line_start = anchor <= cursor ? anchor : cursor; BufferCoord& to_line_start = anchor <= cursor ? anchor : cursor;
ByteCoord& to_line_end = anchor <= cursor ? cursor : anchor; BufferCoord& to_line_end = anchor <= cursor ? cursor : anchor;
to_line_start.column = 0; to_line_start.column = 0;
to_line_end.column = buffer[to_line_end.line].length()-1; 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) Selection trim_partial_lines(const Buffer& buffer, const Selection& selection)
{ {
ByteCoord anchor = selection.anchor(); BufferCoord anchor = selection.anchor();
ByteCoord cursor = selection.cursor(); BufferCoord cursor = selection.cursor();
ByteCoord& to_line_start = anchor <= cursor ? anchor : cursor; BufferCoord& to_line_start = anchor <= cursor ? anchor : cursor;
ByteCoord& to_line_end = anchor <= cursor ? cursor : anchor; BufferCoord& to_line_end = anchor <= cursor ? cursor : anchor;
if (to_line_start.column != 0) if (to_line_start.column != 0)
to_line_start = to_line_start.line+1; to_line_start = to_line_start.line+1;
@ -591,7 +591,7 @@ Selection trim_partial_lines(const Buffer& buffer, const Selection& selection)
return selection; return selection;
auto prev_line = to_line_end.line-1; 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) if (to_line_start > to_line_end)

View File

@ -14,7 +14,7 @@ namespace Kakoune
inline Selection keep_direction(Selection res, const Selection& ref) inline Selection keep_direction(Selection res, const Selection& ref)
{ {
if ((res.cursor() < res.anchor()) != (ref.cursor() < ref.anchor())) if ((res.cursor() < res.anchor()) != (ref.cursor() < ref.anchor()))
std::swap<ByteCoord>(res.cursor(), res.anchor()); std::swap<BufferCoord>(res.cursor(), res.anchor());
return res; return res;
} }
@ -117,9 +117,9 @@ Selection select_to_reverse(const Buffer& buffer, const Selection& selection,
template<bool only_move> template<bool only_move>
Selection select_to_line_end(const Buffer& buffer, const Selection& selection) Selection select_to_line_end(const Buffer& buffer, const Selection& selection)
{ {
ByteCoord begin = selection.cursor(); BufferCoord begin = selection.cursor();
LineCount line = begin.line; 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(); buffer.iterator_at(line)).coord();
if (end < begin) // Do not go backward when cursor is on eol if (end < begin) // Do not go backward when cursor is on eol
end = begin; end = begin;
@ -129,8 +129,8 @@ Selection select_to_line_end(const Buffer& buffer, const Selection& selection)
template<bool only_move> template<bool only_move>
Selection select_to_line_begin(const Buffer& buffer, const Selection& selection) Selection select_to_line_begin(const Buffer& buffer, const Selection& selection)
{ {
ByteCoord begin = selection.cursor(); BufferCoord begin = selection.cursor();
ByteCoord end = begin.line; BufferCoord end = begin.line;
return {only_move ? end : begin, end}; return {only_move ? end : begin, end};
} }

View File

@ -366,7 +366,7 @@ bool subsequence_match(StringView str, StringView subseq)
return true; return true;
} }
String expand_tabs(StringView line, CharCount tabstop, CharCount col) String expand_tabs(StringView line, ColumnCount tabstop, ColumnCount col)
{ {
String res; String res;
res.reserve(line.length()); res.reserve(line.length());
@ -374,23 +374,23 @@ String expand_tabs(StringView line, CharCount tabstop, CharCount col)
{ {
if (*it == '\t') if (*it == '\t')
{ {
CharCount end_col = (col / tabstop + 1) * tabstop; ColumnCount end_col = (col / tabstop + 1) * tabstop;
res += String{' ', end_col - col}; res += String{' ', end_col - col};
col = end_col; col = end_col;
++it; ++it;
} }
else else
{ {
auto char_end = utf8::next(it, end); auto char_beg = it;
res += {it, char_end}; auto cp = utf8::read_codepoint(it, end);
++col; res += {char_beg, it};
it = char_end; col += get_width(cp);
} }
} }
return res; return res;
} }
Vector<StringView> wrap_lines(StringView text, CharCount max_width) Vector<StringView> wrap_lines(StringView text, ColumnCount max_width)
{ {
if (max_width <= 0) if (max_width <= 0)
throw runtime_error("Invalid max width"); throw runtime_error("Invalid max width");
@ -416,9 +416,10 @@ Vector<StringView> wrap_lines(StringView text, CharCount max_width)
while (word_end != end and categorize(*word_end) == cat) while (word_end != end and categorize(*word_end) == cat)
++word_end; ++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; : last_word_end;
lines.emplace_back(line_begin.base(), line_end.base()); lines.emplace_back(line_begin.base(), line_end.base());

View File

@ -65,18 +65,26 @@ public:
{ return utf8::codepoint(utf8::advance(begin(), end(), pos), end()); } { return utf8::codepoint(utf8::advance(begin(), end(), pos), end()); }
CharCount char_length() const { return utf8::distance(begin(), end()); } CharCount char_length() const { return utf8::distance(begin(), end()); }
ColumnCount column_length() const { return utf8::column_distance(begin(), end()); }
[[gnu::always_inline]] [[gnu::always_inline]]
bool empty() const { return type().length() == 0_byte; } bool empty() const { return type().length() == 0_byte; }
ByteCount byte_count_to(CharCount count) const 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 CharCount char_count_to(ByteCount count) const
{ return utf8::distance(begin(), begin() + (int)count); } { 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(ByteCount from, ByteCount length = INT_MAX) const;
StringView substr(CharCount from, CharCount length = INT_MAX) const; StringView substr(CharCount from, CharCount length = INT_MAX) const;
StringView substr(ColumnCount from, ColumnCount length = INT_MAX) const;
private: private:
[[gnu::always_inline]] [[gnu::always_inline]]
@ -103,6 +111,14 @@ public:
while (count-- > 0) while (count-- > 0)
utf8::dump(std::back_inserter(*this), cp); 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) {} String(const char* begin, const char* end) : m_data(begin, end-begin) {}
[[gnu::always_inline]] [[gnu::always_inline]]
@ -251,7 +267,16 @@ inline StringView StringOps<Type, CharType>::substr(CharCount from, CharCount le
{ {
if (length < 0) if (length < 0)
length = INT_MAX; 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<typename Type, typename CharType>
inline StringView StringOps<Type, CharType>::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) }; 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); 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<StringView> wrap_lines(StringView text, CharCount max_width); Vector<StringView> wrap_lines(StringView text, ColumnCount max_width);
namespace detail namespace detail
{ {

View File

@ -48,6 +48,11 @@ inline bool is_basic_alpha(Codepoint c)
return (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z'); 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 enum class CharCategories
{ {
Blank, Blank,

View File

@ -158,6 +158,18 @@ inline constexpr CharCount operator"" _char(unsigned long long int value)
return CharCount(value); return CharCount(value);
} }
struct ColumnCount : public StronglyTypedNumber<ColumnCount, int>
{
[[gnu::always_inline]]
constexpr ColumnCount(int value = 0) : StronglyTypedNumber<ColumnCount>(value) {}
};
[[gnu::always_inline]]
inline constexpr ColumnCount operator"" _col(unsigned long long int value)
{
return ColumnCount(value);
}
} }
#endif // units_hh_INCLUDED #endif // units_hh_INCLUDED

View File

@ -13,7 +13,7 @@ namespace Kakoune
class String; class String;
class DisplayBuffer; class DisplayBuffer;
class DisplayLine; class DisplayLine;
struct CharCoord; struct DisplayCoord;
struct Face; struct Face;
struct Key; struct Key;
@ -42,13 +42,13 @@ public:
virtual ~UserInterface() {} virtual ~UserInterface() {}
virtual void menu_show(ConstArrayView<DisplayLine> choices, virtual void menu_show(ConstArrayView<DisplayLine> choices,
CharCoord anchor, Face fg, Face bg, DisplayCoord anchor, Face fg, Face bg,
MenuStyle style) = 0; MenuStyle style) = 0;
virtual void menu_select(int selected) = 0; virtual void menu_select(int selected) = 0;
virtual void menu_hide() = 0; virtual void menu_hide() = 0;
virtual void info_show(StringView title, StringView content, virtual void info_show(StringView title, StringView content,
CharCoord anchor, Face face, DisplayCoord anchor, Face face,
InfoStyle style) = 0; InfoStyle style) = 0;
virtual void info_hide() = 0; virtual void info_hide() = 0;
@ -60,7 +60,7 @@ public:
const DisplayLine& mode_line, const DisplayLine& mode_line,
const Face& default_face) = 0; const Face& default_face) = 0;
virtual CharCoord dimensions() = 0; virtual DisplayCoord dimensions() = 0;
virtual bool is_key_available() = 0; virtual bool is_key_available() = 0;
virtual Key get_key() = 0; virtual Key get_key() = 0;

View File

@ -25,97 +25,6 @@ inline bool is_character_start(char c)
return (c & 0xC0) != 0x80; return (c & 0xC0) != 0x80;
} }
template<typename Iterator>
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<typename Iterator>
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<typename Iterator>
Iterator finish(Iterator it, const Iterator& end)
{
while (it != end and (*(it) & 0xC0) == 0x80)
++it;
return it;
}
template<typename Iterator>
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<typename Iterator>
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<typename Iterator>
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<typename Iterator>
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<typename Iterator>
Iterator character_start(Iterator it, const Iterator& begin)
{
while (it != begin and not is_character_start(*it))
--it;
return it;
}
namespace InvalidPolicy namespace InvalidPolicy
{ {
@ -213,6 +122,139 @@ inline ByteCount codepoint_size(Codepoint cp)
throw invalid_codepoint{}; throw invalid_codepoint{};
} }
template<typename Iterator>
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<typename Iterator>
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<typename Iterator>
Iterator finish(Iterator it, const Iterator& end)
{
while (it != end and (*(it) & 0xC0) == 0x80)
++it;
return it;
}
template<typename Iterator>
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<typename Iterator>
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<typename Iterator>
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<typename Iterator>
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<typename Iterator>
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<typename Iterator>
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<typename Iterator>
Iterator character_start(Iterator it, const Iterator& begin)
{
while (it != begin and not is_character_start(*it))
--it;
return it;
}
template<typename OutputIterator> template<typename OutputIterator>
void dump(OutputIterator&& it, Codepoint cp) void dump(OutputIterator&& it, Codepoint cp)
{ {

View File

@ -58,20 +58,20 @@ void Window::center_line(LineCount buffer_line)
display_line_at(buffer_line, m_dimensions.line/2_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) 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 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(); DisplayBuffer::LineList& lines = m_display_buffer.lines();
lines.clear(); lines.clear();
if (m_dimensions == CharCoord{0,0}) if (m_dimensions == DisplayCoord{0,0})
return m_display_buffer; return m_display_buffer;
kak_assert(&buffer() == &context.buffer()); kak_assert(&buffer() == &context.buffer());
@ -154,13 +154,13 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context)
return m_display_buffer; 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.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) if (m_dimensions != dimensions)
{ {
@ -182,12 +182,12 @@ static LineCount adapt_view_pos(LineCount line, LineCount offset,
return view_pos; return view_pos;
} }
static CharCount adapt_view_pos(const DisplayBuffer& display_buffer, CharCount offset, static ColumnCount adapt_view_pos(const DisplayBuffer& display_buffer, ColumnCount offset,
ByteCoord pos, CharCount view_pos, CharCount view_size) BufferCoord pos, ColumnCount view_pos, ColumnCount view_size)
{ {
offset = std::min(offset, (view_size + 1) / 2); offset = std::min(offset, (view_size + 1) / 2);
CharCount buffer_column = 0; ColumnCount buffer_column = 0;
CharCount non_buffer_column = 0; ColumnCount non_buffer_column = 0;
for (auto& line : display_buffer.lines()) for (auto& line : display_buffer.lines())
{ {
for (auto& atom : line) 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) if (atom.begin() <= pos and atom.end() > pos)
{ {
CharCount pos_beg, pos_end; ColumnCount pos_beg, pos_end;
if (atom.type() == DisplayAtom::BufferRange) if (atom.type() == DisplayAtom::BufferRange)
{ {
auto& buf = atom.buffer(); auto& buf = atom.buffer();
pos_beg = buffer_column + pos_beg = buffer_column +
char_length(buf, atom.begin(), pos); column_length(buf, atom.begin(), pos);
pos_end = pos_beg+1; pos_end = pos_beg+1;
} }
else else
@ -211,7 +211,7 @@ static CharCount adapt_view_pos(const DisplayBuffer& display_buffer, CharCount o
} }
if (pos_beg - offset < view_pos) 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) if (pos_end + offset >= view_pos + view_size - non_buffer_column)
return pos_end + offset - 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& anchor = selection.anchor();
const auto& cursor = selection.cursor(); const auto& cursor = selection.cursor();
const CharCoord offset = options()["scrolloff"].get<CharCoord>(); const DisplayCoord offset = options()["scrolloff"].get<DisplayCoord>();
// scroll lines if needed, try to get as much of the selection visible as possible // 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, 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 namespace
{ {
CharCount find_display_column(const DisplayLine& line, const Buffer& buffer, ColumnCount find_display_column(const DisplayLine& line, const Buffer& buffer,
ByteCoord coord) BufferCoord coord)
{ {
CharCount column = 0; ColumnCount column = 0;
for (auto& atom : line) for (auto& atom : line)
{ {
if (atom.has_buffer_range() and if (atom.has_buffer_range() and
coord >= atom.begin() and coord < atom.end()) coord >= atom.begin() and coord < atom.end())
{ {
if (atom.type() == DisplayAtom::BufferRange) if (atom.type() == DisplayAtom::BufferRange)
column += char_length(buffer, atom.begin(), coord); column += column_length(buffer, atom.begin(), coord);
return column; return column;
} }
column += atom.length(); column += atom.length();
@ -280,20 +280,20 @@ CharCount find_display_column(const DisplayLine& line, const Buffer& buffer,
return column; return column;
} }
ByteCoord find_buffer_coord(const DisplayLine& line, const Buffer& buffer, BufferCoord find_buffer_coord(const DisplayLine& line, const Buffer& buffer,
CharCount column) ColumnCount column)
{ {
auto& range = line.range(); auto& range = line.range();
for (auto& atom : line) for (auto& atom : line)
{ {
CharCount len = atom.length(); ColumnCount len = atom.length();
if (atom.has_buffer_range() and column < len) if (atom.has_buffer_range() and column < len)
{ {
if (atom.type() == DisplayAtom::BufferRange) if (atom.type() == DisplayAtom::BufferRange)
return buffer.clamp( return buffer.clamp(
utf8::advance(buffer.iterator_at(atom.begin()), utf8::advance(buffer.iterator_at(atom.begin()),
buffer.iterator_at(range.end), buffer.iterator_at(range.end),
std::max(0_char, column)).coord()); std::max(0_col, column)).coord());
return buffer.clamp(atom.begin()); return buffer.clamp(atom.begin());
} }
column -= len; 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; LineCount l = 0;
for (auto& line : m_display_buffer.lines()) for (auto& line : m_display_buffer.lines())
@ -315,25 +315,25 @@ CharCoord Window::display_position(ByteCoord coord) const
return { 0, 0 }; return { 0, 0 };
} }
ByteCoord Window::buffer_coord(CharCoord coord) const BufferCoord Window::buffer_coord(DisplayCoord coord) const
{ {
if (m_display_buffer.lines().empty()) if (m_display_buffer.lines().empty())
return {0,0}; return {0,0};
if (coord <= 0_line) if (coord <= 0_line)
coord = {0,0}; coord = {0,0};
if ((int)coord.line >= m_display_buffer.lines().size()) 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], return find_buffer_coord(m_display_buffer.lines()[(int)coord.line],
buffer(), coord.column); 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); 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); auto line = clamp(coord.line + offset, 0_line, buffer().line_count()-1);
DisplayBuffer display_buffer; 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_highlighters.highlight(input_handler.context(), HighlightFlags::MoveOnly, display_buffer, range);
m_builtin_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 }; return { find_buffer_coord(lines[1], buffer(), column), column };
} }

View File

@ -18,24 +18,24 @@ public:
Window(Buffer& buffer); Window(Buffer& buffer);
~Window(); ~Window();
const CharCoord& position() const { return m_position; } const DisplayCoord& position() const { return m_position; }
void set_position(CharCoord position); void set_position(DisplayCoord position);
const CharCoord& dimensions() const { return m_dimensions; } const DisplayCoord& dimensions() const { return m_dimensions; }
void set_dimensions(CharCoord dimensions); void set_dimensions(DisplayCoord dimensions);
void scroll(LineCount offset); void scroll(LineCount offset);
void center_line(LineCount buffer_line); void center_line(LineCount buffer_line);
void display_line_at(LineCount buffer_line, LineCount display_line); void display_line_at(LineCount buffer_line, LineCount display_line);
void scroll(CharCount offset); void scroll(ColumnCount offset);
void center_column(CharCount buffer_column); void center_column(ColumnCount buffer_column);
void display_column_at(CharCount buffer_column, CharCount display_column); void display_column_at(ColumnCount buffer_column, ColumnCount display_column);
const DisplayBuffer& update_display_buffer(const Context& context); const DisplayBuffer& update_display_buffer(const Context& context);
CharCoord display_position(ByteCoord coord) const; DisplayCoord display_position(BufferCoord coord) const;
ByteCoord buffer_coord(CharCoord coord) const; BufferCoord buffer_coord(DisplayCoord coord) const;
Highlighter& highlighters() { return m_highlighters; } Highlighter& highlighters() { return m_highlighters; }
@ -44,8 +44,8 @@ public:
bool needs_redraw(const Context& context) const; bool needs_redraw(const Context& context) const;
void force_redraw() { m_last_setup = Setup{}; } void force_redraw() { m_last_setup = Setup{}; }
ByteCoord offset_coord(ByteCoord coord, CharCount offset); BufferCoord offset_coord(BufferCoord coord, CharCount offset);
ByteCoordAndTarget offset_coord(ByteCoordAndTarget coord, LineCount offset); BufferCoordAndTarget offset_coord(BufferCoordAndTarget coord, LineCount offset);
void set_client(Client* client) { m_client = client; } void set_client(Client* client) { m_client = client; }
@ -61,8 +61,8 @@ private:
SafePtr<Buffer> m_buffer; SafePtr<Buffer> m_buffer;
SafePtr<Client> m_client; SafePtr<Client> m_client;
CharCoord m_position; DisplayCoord m_position;
CharCoord m_dimensions; DisplayCoord m_dimensions;
DisplayBuffer m_display_buffer; DisplayBuffer m_display_buffer;
HighlighterGroup m_highlighters; HighlighterGroup m_highlighters;
@ -70,8 +70,8 @@ private:
struct Setup struct Setup
{ {
CharCoord position; DisplayCoord position;
CharCoord dimensions; DisplayCoord dimensions;
size_t timestamp; size_t timestamp;
size_t main_selection; size_t main_selection;
Vector<BufferRange> selections; Vector<BufferRange> selections;

View File

@ -0,0 +1 @@
j

View File

@ -0,0 +1,2 @@
1234%(5)67%(8)9012
一二三四五六

View File

@ -0,0 +1 @@
三:四