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