summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2013-06-03 18:58:09 +0200
committerMaxime Coste <frrrwww@gmail.com>2013-06-04 14:21:07 +0200
commit4ef1bfa4db03526f670213f29ed88212913be43f (patch)
tree19d8e34f788bea2e6f565708cf219226b176e898 /src
parent02b33c7d8fd0167a4cbca78be26ed32e042c7370 (diff)
Use coord instead of iterators for selections
Diffstat (limited to 'src')
-rw-r--r--src/client_manager.cc4
-rw-r--r--src/dynamic_selection_list.cc4
-rw-r--r--src/editor.cc119
-rw-r--r--src/filters.cc12
-rw-r--r--src/highlighters.cc9
-rw-r--r--src/input_handler.cc8
-rw-r--r--src/main.cc8
-rw-r--r--src/normal.cc36
-rw-r--r--src/selection.cc12
-rw-r--r--src/selection.hh30
-rw-r--r--src/selectors.cc51
-rw-r--r--src/unit_tests.cc6
-rw-r--r--src/window.cc38
13 files changed, 174 insertions, 163 deletions
diff --git a/src/client_manager.cc b/src/client_manager.cc
index 10bbbc69..c4dbda6f 100644
--- a/src/client_manager.cc
+++ b/src/client_manager.cc
@@ -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())
diff --git a/src/dynamic_selection_list.cc b/src/dynamic_selection_list.cc
index 3de8c80c..dfc78436 100644
--- a/src/dynamic_selection_list.cc
+++ b/src/dynamic_selection_list.cc
@@ -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
}
diff --git a/src/editor.cc b/src/editor.cc
index 0de58d5e..fa569d00 100644
--- a/src/editor.cc
+++ b/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,13 +38,13 @@ 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,
- InsertMode mode)
+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);
}
}
diff --git a/src/filters.cc b/src/filters.cc
index ae6aa760..53f6576d 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -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());
}
}
}
diff --git a/src/highlighters.cc b/src/highlighters.cc
index edd3d7d3..064c1660 100644
--- a/src/highlighters.cc
+++ b/src/highlighters.cc
@@ -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; });
}
}
diff --git a/src/input_handler.cc b/src/input_handler.cc
index d76d3b14..fd2be75c 100644
--- a/src/input_handler.cc
+++ b/src/input_handler.cc
@@ -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);
}
}
diff --git a/src/main.cc b/src/main.cc
index fc196564..980438a5 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -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)
diff --git a/src/normal.cc b/src/normal.cc
index 0204dc3a..65347c48 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -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> },
diff --git a/src/selection.cc b/src/selection.cc
index 0a4c4e32..f7360e7f 100644
--- a/src/selection.cc
+++ b/src/selection.cc
@@ -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;
}
};
diff --git a/src/selection.hh b/src/selection.hh
index e8754df5..c7e5e2c3 100644
--- a/src/selection.hh
+++ b/src/selection.hh
@@ -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)) {}
diff --git a/src/selectors.cc b/src/selectors.cc
index ae9f7397..c2e7e62f 100644
--- a/src/selectors.cc
+++ b/src/selectors.cc
@@ -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;
diff --git a/src/unit_tests.cc b/src/unit_tests.cc
index 77e081d6..789e9c79 100644
--- a/src/unit_tests.cc
+++ b/src/unit_tests.cc
@@ -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()
diff --git a/src/window.cc b/src/window.cc
index 6dea573e..dba0a302 100644
--- a/src/window.cc
+++ b/src/window.cc
@@ -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);