Use coord instead of iterators for selections
This commit is contained in:
parent
02b33c7d8f
commit
4ef1bfa4db
|
@ -187,11 +187,11 @@ static DisplayLine generate_status_line(Client& client)
|
|||
{
|
||||
auto& context = client.context();
|
||||
auto pos = context.editor().main_selection().last();
|
||||
auto col = utf8::distance(context.buffer().iterator_at_line_begin(pos), pos);
|
||||
auto col = context.buffer().char_distance({pos.line, 0}, pos);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << context.buffer().display_name()
|
||||
<< " " << (int)pos.line()+1 << ":" << (int)col+1;
|
||||
<< " " << (int)pos.line+1 << ":" << (int)col+1;
|
||||
if (context.buffer().is_modified())
|
||||
oss << " [+]";
|
||||
if (context.input_handler().is_recording())
|
||||
|
|
|
@ -30,8 +30,8 @@ void DynamicSelectionList::check_invariant() const
|
|||
kak_assert(buffer.is_valid(sel.last()));
|
||||
kak_assert(not buffer.is_end(sel.first()));
|
||||
kak_assert(not buffer.is_end(sel.last()));
|
||||
kak_assert(utf8::is_character_start(sel.first()));
|
||||
kak_assert(utf8::is_character_start(sel.last()));
|
||||
kak_assert(utf8::is_character_start(buffer.iterator_at(sel.first())));
|
||||
kak_assert(utf8::is_character_start(buffer.iterator_at(sel.last())));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
117
src/editor.cc
117
src/editor.cc
|
@ -20,17 +20,17 @@ Editor::Editor(Buffer& buffer)
|
|||
m_main_sel = 0;
|
||||
}
|
||||
|
||||
static void avoid_eol(BufferIterator& it)
|
||||
static void avoid_eol(const Buffer& buffer, BufferCoord& coord)
|
||||
{
|
||||
const auto column = it.column();
|
||||
if (column != 0 and column == it.buffer().line_length(it.line()) - 1)
|
||||
it = utf8::previous(it);
|
||||
const auto column = coord.column;
|
||||
if (column != 0 and column == buffer.line_length(coord.line) - 1)
|
||||
coord = buffer.char_prev(coord);
|
||||
}
|
||||
|
||||
static void avoid_eol(Selection& sel)
|
||||
static void avoid_eol(const Buffer& buffer, Range& sel)
|
||||
{
|
||||
avoid_eol(sel.first());
|
||||
avoid_eol(sel.last());
|
||||
avoid_eol(buffer, sel.first());
|
||||
avoid_eol(buffer, sel.last());
|
||||
}
|
||||
|
||||
void Editor::erase()
|
||||
|
@ -38,12 +38,12 @@ void Editor::erase()
|
|||
scoped_edition edition(*this);
|
||||
for (auto& sel : m_selections)
|
||||
{
|
||||
m_buffer->erase(sel.min(), utf8::next(sel.max()));
|
||||
avoid_eol(sel);
|
||||
Kakoune::erase(*m_buffer, sel);
|
||||
avoid_eol(*m_buffer, sel);
|
||||
}
|
||||
}
|
||||
|
||||
static BufferIterator prepare_insert(Buffer& buffer, const Selection& sel,
|
||||
static BufferCoord prepare_insert(Buffer& buffer, const Selection& sel,
|
||||
InsertMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
|
@ -52,37 +52,37 @@ static BufferIterator prepare_insert(Buffer& buffer, const Selection& sel,
|
|||
return sel.min();
|
||||
case InsertMode::Replace:
|
||||
{
|
||||
BufferIterator pos = sel.min();
|
||||
buffer.erase(sel.min(), utf8::next(sel.max()));
|
||||
BufferCoord pos = sel.min();
|
||||
Kakoune::erase(buffer, sel);
|
||||
return pos;
|
||||
}
|
||||
case InsertMode::Append:
|
||||
{
|
||||
// special case for end of lines, append to current line instead
|
||||
auto pos = std::max(sel.first(), sel.last());
|
||||
if (pos.column() == buffer.line_length(pos.line()) - 1)
|
||||
if (pos.column == buffer.line_length(pos.line) - 1)
|
||||
return pos;
|
||||
else
|
||||
return utf8::next(pos);
|
||||
return buffer.char_next(pos);
|
||||
}
|
||||
case InsertMode::InsertAtLineBegin:
|
||||
return buffer.iterator_at_line_begin(sel.min());
|
||||
return sel.min().line;
|
||||
case InsertMode::AppendAtLineEnd:
|
||||
return buffer.iterator_at_line_end(sel.max())-1;
|
||||
return buffer.char_prev(sel.max().line+1);
|
||||
case InsertMode::InsertAtNextLineBegin:
|
||||
return buffer.iterator_at_line_end(sel.max());
|
||||
return sel.max().line+1;
|
||||
case InsertMode::OpenLineBelow:
|
||||
case InsertMode::OpenLineAbove:
|
||||
{
|
||||
auto line = mode == InsertMode::OpenLineAbove ?
|
||||
sel.min().line() : sel.max().line() + 1;
|
||||
sel.min().line : sel.max().line + 1;
|
||||
buffer.insert(line, "\n");
|
||||
return {buffer, line};
|
||||
return line;
|
||||
}
|
||||
|
||||
}
|
||||
kak_assert(false);
|
||||
return BufferIterator{};
|
||||
return {};
|
||||
}
|
||||
|
||||
void Editor::insert(const String& str, InsertMode mode)
|
||||
|
@ -91,14 +91,15 @@ void Editor::insert(const String& str, InsertMode mode)
|
|||
|
||||
for (auto& sel : m_selections)
|
||||
{
|
||||
BufferIterator pos = prepare_insert(*m_buffer, sel, mode);
|
||||
BufferCoord pos = prepare_insert(*m_buffer, sel, mode);
|
||||
m_buffer->insert(pos, str);
|
||||
if (mode == InsertMode::Replace and not pos.is_end())
|
||||
if (mode == InsertMode::Replace and not m_buffer->is_end(pos))
|
||||
{
|
||||
sel.first() = pos;
|
||||
sel.last() = str.empty() ? pos : utf8::character_start(pos + str.length() - 1);
|
||||
sel.last() = str.empty() ?
|
||||
pos : m_buffer->char_advance(pos, str.char_length() - 1);
|
||||
}
|
||||
avoid_eol(sel);
|
||||
avoid_eol(*m_buffer, sel);
|
||||
}
|
||||
check_invariant();
|
||||
}
|
||||
|
@ -112,15 +113,16 @@ void Editor::insert(const memoryview<String>& strings, InsertMode mode)
|
|||
for (size_t i = 0; i < selections().size(); ++i)
|
||||
{
|
||||
auto& sel = m_selections[i];
|
||||
BufferIterator pos = prepare_insert(*m_buffer, sel, mode);
|
||||
BufferCoord pos = prepare_insert(*m_buffer, sel, mode);
|
||||
const String& str = strings[std::min(i, strings.size()-1)];
|
||||
m_buffer->insert(pos, str);
|
||||
if (mode == InsertMode::Replace and not pos.is_end())
|
||||
if (mode == InsertMode::Replace and not m_buffer->is_end(pos))
|
||||
{
|
||||
sel.first() = pos;
|
||||
sel.last() = str.empty() ? pos : utf8::character_start(pos + str.length() - 1);
|
||||
sel.last() = str.empty() ?
|
||||
pos : m_buffer->char_advance(pos, str.char_length() - 1);
|
||||
}
|
||||
avoid_eol(sel);
|
||||
avoid_eol(*m_buffer, sel);
|
||||
}
|
||||
check_invariant();
|
||||
}
|
||||
|
@ -129,7 +131,7 @@ std::vector<String> Editor::selections_content() const
|
|||
{
|
||||
std::vector<String> contents;
|
||||
for (auto& sel : m_selections)
|
||||
contents.push_back(m_buffer->string(sel.min(), utf8::next(sel.max())));
|
||||
contents.push_back(m_buffer->string(sel.min(), m_buffer->char_next(sel.max())));
|
||||
return contents;
|
||||
}
|
||||
|
||||
|
@ -183,12 +185,11 @@ void Editor::move_selections(CharCount offset, SelectMode mode)
|
|||
for (auto& sel : m_selections)
|
||||
{
|
||||
auto last = sel.last();
|
||||
auto limit = offset < 0 ? buffer().iterator_at_line_begin(last)
|
||||
: utf8::previous(buffer().iterator_at_line_end(last));
|
||||
last = utf8::advance(last, limit, offset);
|
||||
last = clamp<BufferCoord>(m_buffer->char_advance(last, offset),
|
||||
last.line, m_buffer->char_prev(last.line+1));
|
||||
sel.first() = mode == SelectMode::Extend ? sel.first() : last;
|
||||
sel.last() = last;
|
||||
avoid_eol(sel);
|
||||
avoid_eol(*m_buffer, sel);
|
||||
}
|
||||
sort_and_merge_overlapping(m_selections, m_main_sel);
|
||||
}
|
||||
|
@ -198,14 +199,14 @@ void Editor::move_selections(LineCount offset, SelectMode mode)
|
|||
kak_assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
|
||||
for (auto& sel : m_selections)
|
||||
{
|
||||
BufferCoord pos = sel.last().coord();
|
||||
CharCount column = utf8::distance(m_buffer->iterator_at_line_begin(pos.line), sel.last());
|
||||
auto pos = sel.last();
|
||||
CharCount column = m_buffer->char_distance(pos.line, pos);
|
||||
pos.line += offset;
|
||||
BufferIterator last = utf8::advance(m_buffer->iterator_at_line_begin(pos.line),
|
||||
m_buffer->iterator_at_line_end(pos.line)-1, column);
|
||||
auto last = std::min(m_buffer->char_advance(pos.line, column),
|
||||
m_buffer->char_prev(pos.line+1));
|
||||
sel.first() = mode == SelectMode::Extend ? sel.first() : last;
|
||||
sel.last() = last;
|
||||
avoid_eol(sel);
|
||||
avoid_eol(*m_buffer, sel);
|
||||
}
|
||||
sort_and_merge_overlapping(m_selections, m_main_sel);
|
||||
}
|
||||
|
@ -215,8 +216,8 @@ void Editor::clear_selections()
|
|||
auto& sel = m_selections[m_main_sel];
|
||||
auto& pos = sel.last();
|
||||
|
||||
if (*pos == '\n' and not pos.is_begin() and *utf8::previous(pos) != '\n')
|
||||
pos = utf8::previous(pos);
|
||||
if (pos.column != 0 and pos.column == m_buffer->line_length(pos.line) - 1)
|
||||
pos = m_buffer->char_prev(pos);
|
||||
sel.first() = pos;
|
||||
|
||||
m_selections.erase(m_selections.begin(), m_selections.begin() + m_main_sel);
|
||||
|
@ -392,21 +393,22 @@ private:
|
|||
SelectionList m_ranges;
|
||||
};
|
||||
|
||||
inline bool touches(const Range& lhs, const Range& rhs)
|
||||
inline bool touches(const Buffer& buffer, const Range& lhs, const Range& rhs)
|
||||
{
|
||||
return lhs.min() <= rhs.min() ? utf8::next(lhs.max()) >= rhs.min()
|
||||
: lhs.min() <= utf8::next(rhs.max());
|
||||
return lhs.min() <= rhs.min() ? buffer.char_next(lhs.max()) >= rhs.min()
|
||||
: lhs.min() <= buffer.char_next(rhs.max());
|
||||
}
|
||||
|
||||
bool Editor::undo()
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
ModifiedRangesListener listener(buffer());
|
||||
bool res = m_buffer->undo();
|
||||
if (res and not listener.ranges().empty())
|
||||
{
|
||||
m_selections = std::move(listener.ranges());
|
||||
m_main_sel = m_selections.size() - 1;
|
||||
merge_overlapping(m_selections, m_main_sel, touches);
|
||||
merge_overlapping(m_selections, m_main_sel, std::bind(touches, std::ref(buffer()), _1, _2));
|
||||
}
|
||||
check_invariant();
|
||||
return res;
|
||||
|
@ -414,13 +416,14 @@ bool Editor::undo()
|
|||
|
||||
bool Editor::redo()
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
ModifiedRangesListener listener(buffer());
|
||||
bool res = m_buffer->redo();
|
||||
if (res and not listener.ranges().empty())
|
||||
{
|
||||
m_selections = std::move(listener.ranges());
|
||||
m_main_sel = m_selections.size() - 1;
|
||||
merge_overlapping(m_selections, m_main_sel, touches);
|
||||
merge_overlapping(m_selections, m_main_sel, std::bind(touches, std::ref(buffer()), _1, _2));
|
||||
}
|
||||
check_invariant();
|
||||
return res;
|
||||
|
@ -463,17 +466,17 @@ IncrementalInserter::IncrementalInserter(Editor& editor, InsertMode mode)
|
|||
utf8_it first, last;
|
||||
switch (mode)
|
||||
{
|
||||
case InsertMode::Insert: first = sel.max(); last = sel.min(); break;
|
||||
case InsertMode::Insert: first = buffer.iterator_at(sel.max()); last = buffer.iterator_at(sel.min()); break;
|
||||
case InsertMode::Replace:
|
||||
{
|
||||
buffer.erase(sel.min(), utf8::next(sel.max()));
|
||||
first = last = sel.min();
|
||||
Kakoune::erase(buffer, sel);
|
||||
first = last = buffer.iterator_at(sel.min());
|
||||
break;
|
||||
}
|
||||
case InsertMode::Append:
|
||||
{
|
||||
first = sel.min();
|
||||
last = std::max(sel.first(), sel.last());
|
||||
first = buffer.iterator_at(sel.min());
|
||||
last = buffer.iterator_at(sel.max());
|
||||
// special case for end of lines, append to current line instead
|
||||
auto coord = last.underlying_iterator().coord();
|
||||
if (coord.column != buffer.line_length(coord.line) - 1)
|
||||
|
@ -483,13 +486,13 @@ IncrementalInserter::IncrementalInserter(Editor& editor, InsertMode mode)
|
|||
|
||||
case InsertMode::OpenLineBelow:
|
||||
case InsertMode::AppendAtLineEnd:
|
||||
first = utf8_it(buffer.iterator_at_line_end(sel.max())) - 1;
|
||||
first = utf8_it(buffer.iterator_at(sel.max().line+1)) - 1;
|
||||
last = first;
|
||||
break;
|
||||
|
||||
case InsertMode::OpenLineAbove:
|
||||
case InsertMode::InsertAtLineBegin:
|
||||
first = buffer.iterator_at_line_begin(sel.min());
|
||||
first = buffer.iterator_at(sel.min().line);
|
||||
if (mode == InsertMode::OpenLineAbove)
|
||||
--first;
|
||||
else
|
||||
|
@ -534,9 +537,9 @@ IncrementalInserter::~IncrementalInserter()
|
|||
{
|
||||
for (auto& sel : m_editor.m_selections)
|
||||
{
|
||||
if (m_mode == InsertMode::Append and sel.last().column() > 0)
|
||||
sel.last() = utf8::previous(sel.last());
|
||||
avoid_eol(sel);
|
||||
if (m_mode == InsertMode::Append and sel.last().column > 0)
|
||||
sel.last() = m_editor.buffer().char_prev(sel.last());
|
||||
avoid_eol(m_editor.buffer(), sel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -564,8 +567,8 @@ void IncrementalInserter::erase()
|
|||
{
|
||||
for (auto& sel : m_editor.m_selections)
|
||||
{
|
||||
BufferIterator pos = sel.last();
|
||||
m_editor.buffer().erase(utf8::previous(pos), pos);
|
||||
BufferCoord pos = sel.last();
|
||||
m_editor.buffer().erase(m_editor.buffer().char_prev(pos), pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ void preserve_indent(Buffer& buffer, Selection& selection, String& content)
|
|||
{
|
||||
if (content == "\n")
|
||||
{
|
||||
BufferCoord line_begin{selection.last().line(), 0};
|
||||
BufferCoord line_begin{selection.last().line, 0};
|
||||
auto first_non_white = buffer.iterator_at(line_begin);
|
||||
while ((*first_non_white == '\t' or *first_non_white == ' ') and
|
||||
not first_non_white.is_end())
|
||||
|
@ -82,12 +82,12 @@ struct RegexFilter
|
|||
String suffix(it+1, content.end());
|
||||
content = String(content.begin(), it-1);
|
||||
|
||||
auto first = selection.first();
|
||||
auto last = selection.last();
|
||||
auto& first = selection.first();
|
||||
auto& last = selection.last();
|
||||
buffer.insert(position, suffix);
|
||||
if (selection.first() == selection.last())
|
||||
selection.first() -= suffix.length();
|
||||
selection.last() -= suffix.length();
|
||||
if (first == last)
|
||||
first = buffer.advance(first, -suffix.length());
|
||||
last = buffer.advance(last, -suffix.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -280,22 +280,23 @@ void show_line_numbers(const Window& window, DisplayBuffer& display_buffer)
|
|||
void highlight_selections(const Window& window, DisplayBuffer& display_buffer)
|
||||
{
|
||||
const bool only_cursor = window.is_editing() and window.options()["insert_hide_sel"].get<bool>();
|
||||
const auto& buffer = window.buffer();
|
||||
for (size_t i = 0; i < window.selections().size(); ++i)
|
||||
{
|
||||
auto& sel = window.selections()[i];
|
||||
const bool forward = sel.first() <= sel.last();
|
||||
BufferIterator begin = forward ? sel.first() : utf8::next(sel.last());
|
||||
BufferIterator end = forward ? sel.last() : utf8::next(sel.first());
|
||||
BufferCoord begin = forward ? sel.first() : buffer.char_next(sel.last());
|
||||
BufferCoord end = forward ? sel.last() : buffer.char_next(sel.first());
|
||||
|
||||
const bool primary = (i == window.main_selection_index());
|
||||
if (not only_cursor)
|
||||
{
|
||||
ColorPair sel_colors = get_color(primary ? "PrimarySelection" : "SecondarySelection");
|
||||
highlight_range(display_buffer, begin.coord(), end.coord(), false,
|
||||
highlight_range(display_buffer, begin, end, false,
|
||||
[&](DisplayAtom& atom) { atom.colors = sel_colors; });
|
||||
}
|
||||
ColorPair cur_colors = get_color(primary ? "PrimaryCursor" : "SecondaryCursor");
|
||||
highlight_range(display_buffer, sel.last().coord(), utf8::next(sel.last()).coord(), false,
|
||||
highlight_range(display_buffer, sel.last(), buffer.char_next(sel.last()), false,
|
||||
[&](DisplayAtom& atom) { atom.colors = cur_colors; });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -610,11 +610,13 @@ public:
|
|||
for (auto& sel : m_context.editor().selections())
|
||||
{
|
||||
auto offset = buffer.offset(sel.last());
|
||||
auto pos = buffer.iterator_at(sel.last());
|
||||
if (offset >= beg_offset and offset + end_offset < buffer_len and
|
||||
std::equal(sel.last() - beg_offset, sel.last(), begin))
|
||||
std::equal(pos - beg_offset, pos, begin))
|
||||
{
|
||||
buffer.erase(sel.last() - beg_offset, sel.last() + end_offset);
|
||||
buffer.insert(sel.last(), candidate);
|
||||
auto beg = pos - beg_offset;
|
||||
buffer.erase(beg, pos + end_offset);
|
||||
buffer.insert(beg, candidate);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ void register_env_vars()
|
|||
shell_manager.register_env_var("selection",
|
||||
[](const String& name, const Context& context)
|
||||
{ const Range& sel = context.editor().main_selection();
|
||||
return context.buffer().string(sel.min(), utf8::next(sel.max())); });
|
||||
return content(context.buffer(), sel); });
|
||||
shell_manager.register_env_var("selections",
|
||||
[](const String& name, const Context& context)
|
||||
{ auto sels = context.editor().selections_content();
|
||||
|
@ -91,15 +91,15 @@ void register_env_vars()
|
|||
{ return ClientManager::instance().get_client(context).name(); });
|
||||
shell_manager.register_env_var("cursor_line",
|
||||
[](const String& name, const Context& context)
|
||||
{ return to_string(context.editor().main_selection().last().line() + 1); });
|
||||
{ return to_string(context.editor().main_selection().last().line + 1); });
|
||||
shell_manager.register_env_var("cursor_column",
|
||||
[](const String& name, const Context& context)
|
||||
{ return to_string(context.editor().main_selection().last().column() + 1); });
|
||||
{ return to_string(context.editor().main_selection().last().column + 1); });
|
||||
shell_manager.register_env_var("selection_desc",
|
||||
[](const String& name, const Context& context)
|
||||
{ auto& sel = context.editor().main_selection();
|
||||
auto beg = sel.min();
|
||||
return to_string(beg.line() + 1) + ':' + to_string(beg.column() + 1) + '+' +
|
||||
return to_string(beg.line + 1) + ':' + to_string(beg.column + 1) + '+' +
|
||||
to_string((int)context.buffer().distance(beg, sel.max())+1); });
|
||||
shell_manager.register_env_var("window_width",
|
||||
[](const String& name, const Context& context)
|
||||
|
|
|
@ -136,14 +136,15 @@ void goto_commands(Context& context)
|
|||
case 'f':
|
||||
{
|
||||
const Range& sel = context.editor().main_selection();
|
||||
String filename = context.buffer().string(sel.min(), utf8::next(sel.max()));
|
||||
const Buffer& buffer = context.buffer();
|
||||
String filename = content(buffer, sel);
|
||||
static constexpr char forbidden[] = { '\'', '\\', '\0' };
|
||||
for (auto c : forbidden)
|
||||
if (contains(filename, c))
|
||||
return;
|
||||
|
||||
auto paths = context.options()["path"].get<std::vector<String>>();
|
||||
const String& buffer_name = context.buffer().name();
|
||||
const String& buffer_name = buffer.name();
|
||||
auto it = find(reversed(buffer_name), '/');
|
||||
if (it != buffer_name.rend())
|
||||
paths.insert(paths.begin(), String{buffer_name.begin(), it.base()});
|
||||
|
@ -248,7 +249,7 @@ void pipe(Context& context)
|
|||
Editor& editor = context.editor();
|
||||
std::vector<String> strings;
|
||||
for (auto& sel : context.editor().selections())
|
||||
strings.push_back(ShellManager::instance().pipe({sel.min(), utf8::next(sel.max())},
|
||||
strings.push_back(ShellManager::instance().pipe(content(context.buffer(), sel),
|
||||
cmdline, context, {},
|
||||
EnvVarMap{}));
|
||||
editor.insert(strings, InsertMode::Replace);
|
||||
|
@ -332,20 +333,21 @@ void use_selection_as_search_pattern(Context& context)
|
|||
{
|
||||
std::vector<String> patterns;
|
||||
auto& sels = context.editor().selections();
|
||||
const auto& buffer = context.buffer();
|
||||
for (auto& sel : sels)
|
||||
{
|
||||
auto begin = sel.min();
|
||||
auto end = utf8::next(sel.max());
|
||||
auto end = buffer.char_next(sel.max());
|
||||
auto content = "\\Q" + context.buffer().string(begin, end) + "\\E";
|
||||
if (smart)
|
||||
{
|
||||
if (begin.is_begin() or
|
||||
(is_word(utf8::codepoint(begin)) and not
|
||||
is_word(utf8::codepoint(utf8::previous(begin)))))
|
||||
if (begin == BufferCoord{0,0} or
|
||||
(is_word(buffer.char_at(begin)) and not
|
||||
is_word(buffer.char_at(buffer.char_prev(begin)))))
|
||||
content = "\\b" + content;
|
||||
if (end.is_end() or
|
||||
(is_word(utf8::codepoint(utf8::previous(end))) and not
|
||||
is_word(utf8::codepoint(end))))
|
||||
if (buffer.is_end(end) or
|
||||
(is_word(buffer.char_at(buffer.char_prev(end))) and not
|
||||
is_word(buffer.char_at(end))))
|
||||
content = content + "\\b";
|
||||
}
|
||||
patterns.push_back(std::move(content));
|
||||
|
@ -371,7 +373,7 @@ void cat_yank(Context& context)
|
|||
to_string(sels.size()) + " selections", get_color("Information") });
|
||||
}
|
||||
|
||||
void erase(Context& context)
|
||||
void erase_selections(Context& context)
|
||||
{
|
||||
RegisterManager::instance()['"'] = context.editor().selections_content();
|
||||
context.editor().erase();
|
||||
|
@ -478,7 +480,7 @@ void join_select_spaces(Context& context)
|
|||
kak_assert(std::is_sorted(res.begin(), res.end(),
|
||||
[](const Selection& lhs, const Selection& rhs)
|
||||
{ return lhs.min() < rhs.min(); }));
|
||||
if (not res.empty() and utf8::next(res.back().max()).is_end())
|
||||
if (not res.empty() and buffer.is_end(buffer.char_next(res.back().max())))
|
||||
res.pop_back();
|
||||
return res;
|
||||
});
|
||||
|
@ -499,11 +501,13 @@ void keep(Context& context)
|
|||
constexpr const char* prompt = matching ? "keep matching:" : "keep not matching:";
|
||||
regex_prompt(context, prompt, [](const Regex& ex, Context& context) {
|
||||
Editor& editor = context.editor();
|
||||
const Buffer& buffer = context.buffer();
|
||||
SelectionList sels = editor.selections();
|
||||
SelectionList keep;
|
||||
for (auto& sel : sels)
|
||||
{
|
||||
if (boost::regex_search(sel.min(), utf8::next(sel.max()), ex) == matching)
|
||||
if (boost::regex_search(buffer.iterator_at(sel.min()),
|
||||
utf8::next(buffer.iterator_at(sel.max())), ex) == matching)
|
||||
keep.push_back(sel);
|
||||
}
|
||||
if (keep.empty())
|
||||
|
@ -703,8 +707,8 @@ void align(Context& context)
|
|||
{
|
||||
auto& selections = context.editor().selections();
|
||||
auto& buffer = context.buffer();
|
||||
auto get_column = [&buffer](const BufferIterator& it)
|
||||
{ return utf8::distance(buffer.iterator_at_line_begin(it), it); };
|
||||
auto get_column = [&buffer](const BufferCoord& coord)
|
||||
{ return buffer.char_distance({coord.line, 0}, coord); };
|
||||
|
||||
CharCount max_col = 0;
|
||||
for (auto& sel : selections)
|
||||
|
@ -774,7 +778,7 @@ KeyMap keymap =
|
|||
{ { Key::Modifiers::Alt, 'T' }, select_to_next_char<SelectFlags::Extend | SelectFlags::Reverse> },
|
||||
{ { Key::Modifiers::Alt, 'F' }, select_to_next_char<SelectFlags::Inclusive | SelectFlags::Extend | SelectFlags::Reverse> },
|
||||
|
||||
{ { Key::Modifiers::None, 'd' }, erase },
|
||||
{ { Key::Modifiers::None, 'd' }, erase_selections },
|
||||
{ { Key::Modifiers::None, 'c' }, change },
|
||||
{ { Key::Modifiers::None, 'i' }, insert<InsertMode::Insert> },
|
||||
{ { Key::Modifiers::None, 'I' }, insert<InsertMode::InsertAtLineBegin> },
|
||||
|
|
|
@ -22,9 +22,9 @@ void on_buffer_change(const Buffer& buffer, SelectionList& sels,
|
|||
const BufferCoord& begin, const BufferCoord& end, LineCount end_line)
|
||||
{
|
||||
auto update_beg = std::lower_bound(sels.begin(), sels.end(), begin,
|
||||
[](const Selection& s, const BufferCoord& c) { return std::max(s.first().coord(), s.last().coord()) < c; });
|
||||
[](const Selection& s, const BufferCoord& c) { return std::max(s.first(), s.last()) < c; });
|
||||
auto update_only_line_beg = std::upper_bound(sels.begin(), sels.end(), end_line,
|
||||
[](LineCount l, const Selection& s) { return l < std::min(s.first().coord(), s.last().coord()).line; });
|
||||
[](LineCount l, const Selection& s) { return l < std::min(s.first(), s.last()).line; });
|
||||
|
||||
if (update_beg != update_only_line_beg)
|
||||
{
|
||||
|
@ -50,10 +50,9 @@ void on_buffer_change(const Buffer& buffer, SelectionList& sels,
|
|||
template<bool assume_different_line, bool assume_greater_than_begin>
|
||||
struct UpdateInsert
|
||||
{
|
||||
void operator()(const Buffer& buffer, BufferIterator& it,
|
||||
void operator()(const Buffer& buffer, BufferCoord& coord,
|
||||
const BufferCoord& begin, const BufferCoord& end) const
|
||||
{
|
||||
auto coord = it.coord();
|
||||
if (assume_different_line)
|
||||
kak_assert(begin.line < coord.line);
|
||||
if (not assume_greater_than_begin and coord < begin)
|
||||
|
@ -62,17 +61,15 @@ struct UpdateInsert
|
|||
coord.column = end.column + coord.column - begin.column;
|
||||
|
||||
coord.line += end.line - begin.line;
|
||||
it = coord;
|
||||
}
|
||||
};
|
||||
|
||||
template<bool assume_different_line, bool assume_greater_than_begin>
|
||||
struct UpdateErase
|
||||
{
|
||||
void operator()(const Buffer& buffer, BufferIterator& it,
|
||||
void operator()(const Buffer& buffer, BufferCoord& coord,
|
||||
const BufferCoord& begin, const BufferCoord& end) const
|
||||
{
|
||||
auto coord = it.coord();
|
||||
if (not assume_greater_than_begin and coord < begin)
|
||||
return;
|
||||
if (assume_different_line)
|
||||
|
@ -89,7 +86,6 @@ struct UpdateErase
|
|||
else
|
||||
coord.line -= end.line - begin.line;
|
||||
}
|
||||
it = coord;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -10,28 +10,28 @@ namespace Kakoune
|
|||
struct Range
|
||||
{
|
||||
public:
|
||||
Range(const BufferIterator& first, const BufferIterator& last)
|
||||
Range(const BufferCoord& first, const BufferCoord& last)
|
||||
: m_first{first}, m_last{last} {}
|
||||
|
||||
void merge_with(const Range& range);
|
||||
|
||||
BufferIterator& first() { return m_first; }
|
||||
BufferIterator& last() { return m_last; }
|
||||
BufferCoord& first() { return m_first; }
|
||||
BufferCoord& last() { return m_last; }
|
||||
|
||||
const BufferIterator& first() const { return m_first; }
|
||||
const BufferIterator& last() const { return m_last; }
|
||||
const BufferCoord& first() const { return m_first; }
|
||||
const BufferCoord& last() const { return m_last; }
|
||||
|
||||
bool operator== (const Range& other) const
|
||||
{
|
||||
return m_first == other.m_first and m_last == other.m_last;
|
||||
}
|
||||
|
||||
const BufferIterator& min() const { return std::min(m_first, m_last); }
|
||||
const BufferIterator& max() const { return std::max(m_first, m_last); }
|
||||
const BufferCoord& min() const { return std::min(m_first, m_last); }
|
||||
const BufferCoord& max() const { return std::max(m_first, m_last); }
|
||||
|
||||
private:
|
||||
BufferIterator m_first;
|
||||
BufferIterator m_last;
|
||||
BufferCoord m_first;
|
||||
BufferCoord m_last;
|
||||
};
|
||||
|
||||
inline bool overlaps(const Range& lhs, const Range& rhs)
|
||||
|
@ -40,12 +40,22 @@ inline bool overlaps(const Range& lhs, const Range& rhs)
|
|||
: lhs.min() <= rhs.max();
|
||||
}
|
||||
|
||||
inline String content(const Buffer& buffer, const Range& range)
|
||||
{
|
||||
return buffer.string(range.min(), buffer.char_next(range.max()));
|
||||
}
|
||||
|
||||
inline void erase(Buffer& buffer, const Range& range)
|
||||
{
|
||||
return buffer.erase(range.min(), buffer.char_next(range.max()));
|
||||
}
|
||||
|
||||
using CaptureList = std::vector<String>;
|
||||
|
||||
// A selection is a Range, associated with a CaptureList
|
||||
struct Selection : public Range
|
||||
{
|
||||
Selection(const BufferIterator& first, const BufferIterator& last,
|
||||
Selection(const BufferCoord& first, const BufferCoord& last,
|
||||
CaptureList captures = {})
|
||||
: Range(first, last), m_captures(std::move(captures)) {}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ typedef boost::regex_iterator<BufferIterator> RegexIterator;
|
|||
template<bool punctuation_is_word>
|
||||
Selection select_to_next_word(const Buffer& buffer, const Selection& selection)
|
||||
{
|
||||
Utf8Iterator begin = selection.last();
|
||||
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
||||
if (categorize<punctuation_is_word>(*begin) !=
|
||||
categorize<punctuation_is_word>(*(begin+1)))
|
||||
++begin;
|
||||
|
@ -108,7 +108,7 @@ template Selection select_to_next_word<true>(const Buffer&, const Selection&);
|
|||
template<bool punctuation_is_word>
|
||||
Selection select_to_next_word_end(const Buffer& buffer, const Selection& selection)
|
||||
{
|
||||
Utf8Iterator begin = selection.last();
|
||||
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
||||
if (categorize<punctuation_is_word>(*begin) !=
|
||||
categorize<punctuation_is_word>(*(begin+1)))
|
||||
++begin;
|
||||
|
@ -130,7 +130,7 @@ template Selection select_to_next_word_end<true>(const Buffer&, const Selection&
|
|||
template<bool punctuation_is_word>
|
||||
Selection select_to_previous_word(const Buffer& buffer, const Selection& selection)
|
||||
{
|
||||
Utf8Iterator begin = selection.last();
|
||||
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
||||
|
||||
if (categorize<punctuation_is_word>(*begin) !=
|
||||
categorize<punctuation_is_word>(*(begin-1)))
|
||||
|
@ -159,7 +159,7 @@ template Selection select_to_previous_word<true>(const Buffer&, const Selection&
|
|||
|
||||
Selection select_line(const Buffer& buffer, const Selection& selection)
|
||||
{
|
||||
Utf8Iterator first = selection.last();
|
||||
Utf8Iterator first = buffer.iterator_at(selection.last());
|
||||
if (*first == '\n' and not is_end(first + 1))
|
||||
++first;
|
||||
|
||||
|
@ -175,7 +175,7 @@ Selection select_line(const Buffer& buffer, const Selection& selection)
|
|||
Selection select_matching(const Buffer& buffer, const Selection& selection)
|
||||
{
|
||||
std::vector<Codepoint> matching_pairs = { '(', ')', '{', '}', '[', ']', '<', '>' };
|
||||
Utf8Iterator it = selection.last();
|
||||
Utf8Iterator it = buffer.iterator_at(selection.last());
|
||||
std::vector<Codepoint>::iterator match = matching_pairs.end();
|
||||
while (not is_eol(*it))
|
||||
{
|
||||
|
@ -289,15 +289,15 @@ Selection select_surrounding(const Buffer& buffer, const Selection& selection,
|
|||
const CodepointPair& matching,
|
||||
ObjectFlags flags)
|
||||
{
|
||||
auto res = find_surrounding(selection.last(), matching, flags);
|
||||
auto res = find_surrounding(buffer.iterator_at(selection.last()), matching, flags);
|
||||
if (not res)
|
||||
return selection;
|
||||
|
||||
if (flags == (ObjectFlags::ToBegin | ObjectFlags::ToEnd) and
|
||||
matching.first != matching.second and not res->last().is_end() and
|
||||
matching.first != matching.second and not buffer.is_end(res->last()) and
|
||||
(*res == selection or Range{res->last(), res->first()} == selection))
|
||||
{
|
||||
res = find_surrounding(res->last() + 1, matching, flags);
|
||||
res = find_surrounding(buffer.iterator_at(res->last()) + 1, matching, flags);
|
||||
return res ? Selection{*res} : selection;
|
||||
}
|
||||
return *res;
|
||||
|
@ -306,7 +306,7 @@ Selection select_surrounding(const Buffer& buffer, const Selection& selection,
|
|||
Selection select_to(const Buffer& buffer, const Selection& selection,
|
||||
Codepoint c, int count, bool inclusive)
|
||||
{
|
||||
Utf8Iterator begin = selection.last();
|
||||
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
||||
Utf8Iterator end = begin;
|
||||
do
|
||||
{
|
||||
|
@ -323,7 +323,7 @@ Selection select_to(const Buffer& buffer, const Selection& selection,
|
|||
Selection select_to_reverse(const Buffer& buffer, const Selection& selection,
|
||||
Codepoint c, int count, bool inclusive)
|
||||
{
|
||||
Utf8Iterator begin = selection.last();
|
||||
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
||||
Utf8Iterator end = begin;
|
||||
do
|
||||
{
|
||||
|
@ -339,7 +339,7 @@ Selection select_to_reverse(const Buffer& buffer, const Selection& selection,
|
|||
|
||||
Selection select_to_eol(const Buffer& buffer, const Selection& selection)
|
||||
{
|
||||
Utf8Iterator begin = selection.last();
|
||||
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
||||
Utf8Iterator end = begin + 1;
|
||||
skip_while(end, [](Codepoint cur) { return not is_eol(cur); });
|
||||
return utf8_range(begin, end-1);
|
||||
|
@ -347,7 +347,7 @@ Selection select_to_eol(const Buffer& buffer, const Selection& selection)
|
|||
|
||||
Selection select_to_eol_reverse(const Buffer& buffer, const Selection& selection)
|
||||
{
|
||||
Utf8Iterator begin = selection.last();
|
||||
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
||||
Utf8Iterator end = begin - 1;
|
||||
skip_while_reverse(end, [](Codepoint cur) { return not is_eol(cur); });
|
||||
return utf8_range(begin, is_begin(end) ? end : end+1);
|
||||
|
@ -356,7 +356,7 @@ Selection select_to_eol_reverse(const Buffer& buffer, const Selection& selection
|
|||
template<bool punctuation_is_word>
|
||||
Selection select_whole_word(const Buffer& buffer, const Selection& selection, ObjectFlags flags)
|
||||
{
|
||||
Utf8Iterator first = selection.last();
|
||||
Utf8Iterator first = buffer.iterator_at(selection.last());
|
||||
Utf8Iterator last = first;
|
||||
if (is_word<punctuation_is_word>(*first))
|
||||
{
|
||||
|
@ -399,7 +399,7 @@ template Selection select_whole_word<true>(const Buffer&, const Selection&, Obje
|
|||
|
||||
Selection select_whole_sentence(const Buffer& buffer, const Selection& selection, ObjectFlags flags)
|
||||
{
|
||||
BufferIterator first = selection.last();
|
||||
BufferIterator first = buffer.iterator_at(selection.last());
|
||||
BufferIterator last = first;
|
||||
|
||||
if (flags & ObjectFlags::ToBegin)
|
||||
|
@ -450,7 +450,7 @@ Selection select_whole_sentence(const Buffer& buffer, const Selection& selection
|
|||
|
||||
Selection select_whole_paragraph(const Buffer& buffer, const Selection& selection, ObjectFlags flags)
|
||||
{
|
||||
BufferIterator first = selection.last();
|
||||
BufferIterator first = buffer.iterator_at(selection.last());
|
||||
BufferIterator last = first;
|
||||
|
||||
if (flags & ObjectFlags::ToBegin and not is_begin(first))
|
||||
|
@ -493,8 +493,8 @@ Selection select_whole_paragraph(const Buffer& buffer, const Selection& selectio
|
|||
Selection select_whole_lines(const Buffer& buffer, const Selection& selection)
|
||||
{
|
||||
// no need to be utf8 aware for is_eol as we only use \n as line seperator
|
||||
BufferIterator first = selection.first();
|
||||
BufferIterator last = selection.last();
|
||||
BufferIterator first = buffer.iterator_at(selection.first());
|
||||
BufferIterator last = buffer.iterator_at(selection.last());
|
||||
BufferIterator& to_line_start = first <= last ? first : last;
|
||||
BufferIterator& to_line_end = first <= last ? last : first;
|
||||
|
||||
|
@ -513,8 +513,8 @@ Selection select_whole_lines(const Buffer& buffer, const Selection& selection)
|
|||
Selection trim_partial_lines(const Buffer& buffer, const Selection& selection)
|
||||
{
|
||||
// same as select_whole_lines
|
||||
BufferIterator first = selection.first();
|
||||
BufferIterator last = selection.last();
|
||||
BufferIterator first = buffer.iterator_at(selection.first());
|
||||
BufferIterator last = buffer.iterator_at(selection.last());
|
||||
BufferIterator& to_line_start = first <= last ? first : last;
|
||||
BufferIterator& to_line_end = first <= last ? last : first;
|
||||
|
||||
|
@ -565,7 +565,7 @@ Selection select_next_match(const Buffer& buffer, const Selection& selection, co
|
|||
{
|
||||
// regex matching do not use Utf8Iterator as boost::regex handle utf8
|
||||
// decoding itself
|
||||
BufferIterator begin = selection.last();
|
||||
BufferIterator begin = buffer.iterator_at(selection.last());
|
||||
BufferIterator end = begin;
|
||||
CaptureList captures;
|
||||
|
||||
|
@ -594,8 +594,8 @@ template Selection select_next_match<false>(const Buffer&, const Selection&, con
|
|||
|
||||
SelectionList select_all_matches(const Buffer& buffer, const Selection& selection, const Regex& regex)
|
||||
{
|
||||
auto sel_end = utf8::next(selection.max());
|
||||
RegexIterator re_it(selection.min(), sel_end, regex);
|
||||
auto sel_end = utf8::next(buffer.iterator_at(selection.max()));
|
||||
RegexIterator re_it(buffer.iterator_at(selection.min()), sel_end, regex);
|
||||
RegexIterator re_end;
|
||||
|
||||
SelectionList result;
|
||||
|
@ -620,13 +620,12 @@ SelectionList select_all_matches(const Buffer& buffer, const Selection& selectio
|
|||
SelectionList split_selection(const Buffer& buffer, const Selection& selection,
|
||||
const Regex& regex)
|
||||
{
|
||||
auto sel_end = utf8::next(selection.max());
|
||||
RegexIterator re_it(selection.min(), sel_end, regex,
|
||||
boost::regex_constants::match_nosubs);
|
||||
auto begin = buffer.iterator_at(selection.min());
|
||||
auto sel_end = utf8::next(buffer.iterator_at(selection.max()));
|
||||
RegexIterator re_it(begin, sel_end, regex, boost::regex_constants::match_nosubs);
|
||||
RegexIterator re_end;
|
||||
|
||||
SelectionList result;
|
||||
BufferIterator begin = selection.min();
|
||||
for (; re_it != re_end; ++re_it)
|
||||
{
|
||||
BufferIterator end = (*re_it)[0].first;
|
||||
|
|
|
@ -62,8 +62,8 @@ void test_editor()
|
|||
editor.multi_select(std::bind(select_all_matches, _1, _2, Regex{"\\n\\h*"}));
|
||||
for (auto& sel : editor.selections())
|
||||
{
|
||||
kak_assert(*sel.min() == '\n');
|
||||
editor.buffer().erase(sel.min(), utf8::next(sel.max()));
|
||||
kak_assert(buffer.byte_at(sel.min()) == '\n');
|
||||
erase(buffer, sel);
|
||||
}
|
||||
}
|
||||
editor.undo();
|
||||
|
@ -71,7 +71,7 @@ void test_editor()
|
|||
Selection sel{ buffer.iterator_at_line_begin(2_line), buffer.end()-1 };
|
||||
editor.select(sel, SelectMode::Replace);
|
||||
editor.insert("",InsertMode::Replace);
|
||||
kak_assert(not editor.main_selection().first().is_end());
|
||||
kak_assert(not buffer.is_end(editor.main_selection().first()));
|
||||
}
|
||||
|
||||
void test_incremental_inserter()
|
||||
|
|
|
@ -42,7 +42,7 @@ void Window::display_selection_at(LineCount line)
|
|||
{
|
||||
if (line >= 0 or line < m_dimensions.line)
|
||||
{
|
||||
auto cursor_line = main_selection().last().line();
|
||||
auto cursor_line = main_selection().last().line;
|
||||
m_position.line = std::max(0_line, cursor_line - line);
|
||||
}
|
||||
}
|
||||
|
@ -69,14 +69,12 @@ void Window::update_display_buffer()
|
|||
LineCount buffer_line = m_position.line + line;
|
||||
if (buffer_line >= buffer().line_count())
|
||||
break;
|
||||
BufferIterator line_begin = buffer().iterator_at_line_begin(buffer_line);
|
||||
BufferIterator line_end = buffer().iterator_at_line_end(buffer_line);
|
||||
|
||||
BufferIterator begin = utf8::advance(line_begin, line_end, (int)m_position.column);
|
||||
BufferIterator end = utf8::advance(begin, line_end, (int)m_dimensions.column);
|
||||
BufferCoord limit{buffer_line+1, 0};
|
||||
auto begin = std::min(buffer().char_advance(buffer_line, m_position.column), limit);
|
||||
auto end = std::min(buffer().char_advance(begin, m_dimensions.column), limit);
|
||||
|
||||
lines.push_back(DisplayLine(buffer_line));
|
||||
lines.back().push_back(DisplayAtom(AtomContent(buffer(), begin.coord(), end.coord())));
|
||||
lines.back().push_back(DisplayAtom(AtomContent(buffer(), begin, end)));
|
||||
}
|
||||
|
||||
m_display_buffer.compute_range();
|
||||
|
@ -112,26 +110,24 @@ static LineCount adapt_view_pos(LineCount line, LineCount offset,
|
|||
|
||||
void Window::scroll_to_keep_cursor_visible_ifn()
|
||||
{
|
||||
const BufferIterator first = main_selection().first();
|
||||
const BufferIterator last = main_selection().last();
|
||||
const auto& first = main_selection().first();
|
||||
const auto& last = main_selection().last();
|
||||
|
||||
const LineCount offset = std::min<LineCount>(options()["scrolloff"].get<int>(),
|
||||
(m_dimensions.line - 1) / 2);
|
||||
|
||||
// scroll lines if needed, try to get as much of the selection visible as possible
|
||||
m_position.line = adapt_view_pos(first.line(), offset, m_position.line,
|
||||
m_position.line = adapt_view_pos(first.line, offset, m_position.line,
|
||||
m_dimensions.line, buffer().line_count());
|
||||
m_position.line = adapt_view_pos(last.line(), offset, m_position.line,
|
||||
m_position.line = adapt_view_pos(last.line, offset, m_position.line,
|
||||
m_dimensions.line, buffer().line_count());
|
||||
|
||||
// highlight only the line containing the cursor
|
||||
DisplayBuffer display_buffer;
|
||||
DisplayBuffer::LineList& lines = display_buffer.lines();
|
||||
lines.push_back(DisplayLine(last.line()));
|
||||
lines.push_back(DisplayLine(last.line));
|
||||
|
||||
BufferIterator line_begin = buffer().iterator_at_line_begin(last);
|
||||
BufferIterator line_end = buffer().iterator_at_line_end(last);
|
||||
lines.back().push_back(DisplayAtom(AtomContent(buffer(), line_begin.coord(), line_end.coord())));
|
||||
lines.back().push_back(DisplayAtom(AtomContent(buffer(), last.line, last.line+1)));
|
||||
|
||||
display_buffer.compute_range();
|
||||
m_highlighters(*this, display_buffer);
|
||||
|
@ -145,21 +141,21 @@ void Window::scroll_to_keep_cursor_visible_ifn()
|
|||
for (auto& atom : lines.back())
|
||||
{
|
||||
if (atom.content.has_buffer_range() and
|
||||
atom.content.begin() <= last.coord() and atom.content.end() > last.coord())
|
||||
atom.content.begin() <= last and atom.content.end() > last)
|
||||
{
|
||||
if (atom.content.type() == AtomContent::BufferRange)
|
||||
column += utf8::distance(buffer().iterator_at(atom.content.begin()), last);
|
||||
column += buffer().char_distance(atom.content.begin(), last);
|
||||
else
|
||||
column += atom.content.content().char_length();
|
||||
|
||||
CharCount first_col = first.line() == last.line() ?
|
||||
utf8::distance(line_begin, first) : 0_char;
|
||||
CharCount first_col = first.line == last.line ?
|
||||
buffer().char_distance(last.line, first) : 0_char;
|
||||
if (first_col < m_position.column)
|
||||
m_position.column = first_col;
|
||||
else if (column >= m_position.column + m_dimensions.column)
|
||||
m_position.column = column - (m_dimensions.column - 1);
|
||||
|
||||
CharCount last_col = utf8::distance(line_begin, last);
|
||||
CharCount last_col = buffer().char_distance(last.line, last);
|
||||
if (last_col < m_position.column)
|
||||
m_position.column = last_col;
|
||||
else if (column >= m_position.column + m_dimensions.column)
|
||||
|
@ -169,7 +165,7 @@ void Window::scroll_to_keep_cursor_visible_ifn()
|
|||
}
|
||||
column += atom.content.content().char_length();
|
||||
}
|
||||
if (last != buffer().end())
|
||||
if (not buffer().is_end(last))
|
||||
{
|
||||
// the cursor should always be visible.
|
||||
kak_assert(false);
|
||||
|
|
Loading…
Reference in New Issue
Block a user