summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2020-04-27 13:36:12 +1000
committerMaxime Coste <mawww@kakoune.org>2020-04-27 17:39:21 +1000
commit954373d3cfa9d168f7949f12cb7b2e730d18de99 (patch)
tree780e9cd53936d9d0fa54d0dea2b7edf5203e7123 /src
parent65620fb8306f65247c8a2fb9732aa68dfe707308 (diff)
Support multi-line replace-ranges
This likely has lots of rough edges, but should be an initial proof of concept to support folding.
Diffstat (limited to 'src')
-rw-r--r--src/display_buffer.cc12
-rw-r--r--src/display_buffer.hh15
-rw-r--r--src/highlighters.cc114
3 files changed, 93 insertions, 48 deletions
diff --git a/src/display_buffer.cc b/src/display_buffer.cc
index 3d68356f..8ade4047 100644
--- a/src/display_buffer.cc
+++ b/src/display_buffer.cc
@@ -111,6 +111,14 @@ DisplayLine::iterator DisplayLine::split(iterator it, ColumnCount count)
return split(it, pos);
}
+DisplayLine::iterator DisplayLine::split(BufferCoord pos)
+{
+ auto it = find_if(begin(), end(), [pos](const DisplayAtom& a) { return a.type() == DisplayAtom::Range and a.end() > pos; });
+ if (it == end() or it->begin() >= pos)
+ return it;
+ return ++split(it, pos);
+}
+
DisplayLine::iterator DisplayLine::insert(iterator it, DisplayAtom atom)
{
if (atom.has_buffer_range())
@@ -118,7 +126,9 @@ DisplayLine::iterator DisplayLine::insert(iterator it, DisplayAtom atom)
m_range.begin = std::min(m_range.begin, atom.begin());
m_range.end = std::max(m_range.end, atom.end());
}
- return m_atoms.insert(it, std::move(atom));
+ auto res = m_atoms.insert(it, std::move(atom));
+ compute_range();
+ return res;
}
void DisplayLine::push_back(DisplayAtom atom)
diff --git a/src/display_buffer.hh b/src/display_buffer.hh
index abd1a244..308b1993 100644
--- a/src/display_buffer.hh
+++ b/src/display_buffer.hh
@@ -126,16 +126,27 @@ public:
// returns an iterator to the first atom
iterator split(iterator it, ColumnCount pos);
+ iterator split(BufferCoord pos);
+
iterator insert(iterator it, DisplayAtom atom);
+
+ template<typename It>
+ iterator insert(iterator it, It beg, It end)
+ {
+ auto res = m_atoms.insert(it, beg, end);
+ compute_range();
+ return res;
+ }
+
iterator erase(iterator beg, iterator end);
- void push_back(DisplayAtom atom);
+ void push_back(DisplayAtom atom);
// remove first_col from the begining of the line, and make sure
// the line is less that col_count character
bool trim(ColumnCount first_col, ColumnCount col_count);
// Merge together consecutive atoms sharing the same display attributes
- void optimize();
+ void optimize();
private:
void compute_range();
BufferRange m_range = { { INT_MAX, INT_MAX }, { INT_MIN, INT_MIN } };
diff --git a/src/highlighters.cc b/src/highlighters.cc
index 3ead3f6f..3ccbc097 100644
--- a/src/highlighters.cc
+++ b/src/highlighters.cc
@@ -92,41 +92,37 @@ void replace_range(DisplayBuffer& display_buffer,
if (begin > end or end < display_buffer.range().begin or begin > display_buffer.range().end)
return;
- for (auto& line : display_buffer.lines())
- {
- auto& range = line.range();
- if ((begin == end) and begin == range.end)
- return func(line, line.end());
+ auto& lines = display_buffer.lines();
+ auto first_it = std::lower_bound(lines.begin(), lines.end(), begin, [](const DisplayLine& l, const BufferCoord& c) { return l.range().end < c; });
+ if (first_it == lines.end())
+ return;
- if (range.end <= begin or end < range.begin)
- continue;
+ auto first_atom_it = std::find_if(first_it->begin(), first_it->end(), [&begin](const DisplayAtom& a) { return a.has_buffer_range() and a.end() > begin; });
+ first_atom_it = first_it->split(begin);
- int beg_idx = -1, end_idx = -1;
- for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
+ auto last_it = std::lower_bound(first_it, lines.end(), end, [](const DisplayLine& l, const BufferCoord& c) { return l.range().end < c; });
+
+ if (first_it == last_it)
+ {
+ auto first_atom_idx = first_atom_it - first_it->begin();
+ auto end_atom_it = first_it->split(end);
+ first_atom_it = first_it->erase(first_it->begin() + first_atom_idx, end_atom_it);
+ }
+ else
+ {
+ first_atom_it = first_it->erase(first_atom_it, first_it->end());
+ if (last_it != lines.end())
{
- if (not atom_it->has_buffer_range() or
- end < atom_it->begin() or begin >= atom_it->end())
- continue;
+ auto end_atom_it = last_it->split(end);
+ end_atom_it = last_it->erase(last_it->begin(), end_atom_it);
- if (begin >= atom_it->begin())
- {
- if (begin > atom_it->begin())
- atom_it = ++line.split(atom_it, begin);
- beg_idx = atom_it - line.begin();
- }
- if (end == atom_it->begin())
- end_idx = atom_it - line.begin();
- else if (end <= atom_it->end())
- {
- if (end < atom_it->end())
- atom_it = line.split(atom_it, end);
- end_idx = (atom_it - line.begin()) + 1;
- }
+ first_atom_it = first_it->insert(first_atom_it, end_atom_it, last_it->end());
+ ++last_it;
}
-
- if (beg_idx != -1 and end_idx != -1)
- return func(line, line.erase(line.begin() + beg_idx, line.begin() + end_idx));
+ first_it = --lines.erase(first_it+1, last_it);
}
+
+ func(*first_it, first_atom_it);
}
void apply_highlighter(HighlightContext context,
@@ -1495,11 +1491,11 @@ InclusiveBufferRange option_from_string(Meta::Type<InclusiveBufferRange>, String
return { std::min(first, last), std::max(first, last) };
}
-template<typename OptionType, typename DerivedType>
+template<typename OptionType, typename DerivedType, HighlightPass pass = HighlightPass::Colorize>
struct OptionBasedHighlighter : Highlighter
{
OptionBasedHighlighter(String option_name)
- : Highlighter{HighlightPass::Colorize}
+ : Highlighter{pass}
, m_option_name{std::move(option_name)} {}
static std::unique_ptr<Highlighter> create(HighlighterParameters params, Highlighter*)
@@ -1514,7 +1510,7 @@ struct OptionBasedHighlighter : Highlighter
return std::make_unique<DerivedType>(option_name);
}
- OptionType& get_option(const HighlightContext& context)
+ OptionType& get_option(const HighlightContext& context) const
{
return context.context.options()[m_option_name].get_mutable<OptionType>();
}
@@ -1565,32 +1561,35 @@ private:
}
};
-struct ReplaceRangesHighlighter : OptionBasedHighlighter<RangeAndStringList, ReplaceRangesHighlighter>
+struct ReplaceRangesHighlighter : OptionBasedHighlighter<RangeAndStringList, ReplaceRangesHighlighter, HighlightPass::Move>
{
using ReplaceRangesHighlighter::OptionBasedHighlighter::OptionBasedHighlighter;
private:
+ static bool is_valid(Buffer& buffer, BufferCoord c)
+ {
+ return c.line >= 0 and c.column >= 0 and c.line < buffer.line_count() and c.column <= buffer[c.line].length();
+ };
+
+ static bool is_fully_selected(const SelectionList& sels, const InclusiveBufferRange& range)
+ {
+ auto it = std::lower_bound(sels.begin(), sels.end(), range.first, [](const Selection& s, const BufferCoord& c) { return s.max() < c; });
+ if (it == sels.end())
+ return true;
+ return it->min() > range.last or (it->min() <= range.first and it->max() >= range.last);
+ };
+
void do_highlight(HighlightContext context, DisplayBuffer& display_buffer, BufferRange) override
{
auto& buffer = context.context.buffer();
+ auto& sels = context.context.selections();
auto& range_and_faces = get_option(context);
update_ranges(buffer, range_and_faces.prefix, range_and_faces.list);
- auto is_valid = [&buffer](BufferCoord c) {
- return c.line >= 0 and c.column >= 0 and c.line < buffer.line_count() and c.column <= buffer[c.line].length();
- };
-
- auto is_fully_selected = [&sels=context.context.selections()](const InclusiveBufferRange& range) {
- auto it = std::lower_bound(sels.begin(), sels.end(), range.first, [](const Selection& s, const BufferCoord& c) { return s.max() < c; });
- if (it == sels.end())
- return true;
- return it->min() > range.last or (it->min() <= range.first and it->max() >= range.last);
- };
-
for (auto& [range, spec] : range_and_faces.list)
{
try
{
- if (!is_valid(range.first) or (!is_empty(range) and !is_valid(range.last)) or !is_fully_selected(range))
+ if (!is_valid(buffer, range.first) or (!is_empty(range) and !is_valid(buffer, range.last)) or !is_fully_selected(sels, range))
continue;
auto replacement = parse_display_line(spec, context.context.faces());
auto end = is_empty(range) ? range.first : buffer.char_next(range.last);
@@ -1607,6 +1606,31 @@ private:
{}
}
}
+
+ void do_compute_display_setup(HighlightContext context, DisplaySetup& setup) const override
+ {
+ auto& buffer = context.context.buffer();
+ auto& sels = context.context.selections();
+ auto& range_and_faces = get_option(context);
+ update_ranges(buffer, range_and_faces.prefix, range_and_faces.list);
+
+ for (auto& [range, spec] : range_and_faces.list)
+ {
+ if (!is_valid(buffer, range.first) or (!is_empty(range) and !is_valid(buffer, range.last)) or !is_fully_selected(sels, range))
+ continue;
+
+ if (range.first.line < setup.window_pos.line and range.last.line >= setup.window_pos.line)
+ setup.window_pos.line = range.first.line;
+
+ if (range.last.line >= setup.window_pos.line and
+ range.first.line <= setup.window_pos.line + setup.window_range.line and
+ range.first.line != range.last.line)
+ {
+ auto removed_count = range.last.line - range.first.line;
+ setup.window_range.line += removed_count;
+ }
+ }
+ }
};
HighlightPass parse_passes(StringView str)