summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2013-12-11 21:38:43 +0000
committerMaxime Coste <frrrwww@gmail.com>2013-12-11 23:19:24 +0000
commit277b02eee6cb0037d2ecce46d1f2a455dfb0b001 (patch)
treea4a34fbc87541d995c526f73d780a94c8f68f15e /src
parent39512914ad6adbb91de57ac5957594acde543848 (diff)
Add experimental region_ref highlighter
highlights a region using another highlighter.
Diffstat (limited to 'src')
-rw-r--r--src/display_buffer.cc19
-rw-r--r--src/display_buffer.hh2
-rw-r--r--src/highlighters.cc134
3 files changed, 145 insertions, 10 deletions
diff --git a/src/display_buffer.cc b/src/display_buffer.cc
index e4827673..89f2c74b 100644
--- a/src/display_buffer.cc
+++ b/src/display_buffer.cc
@@ -61,6 +61,13 @@ void DisplayLine::push_back(DisplayAtom atom)
m_atoms.push_back(std::move(atom));
}
+DisplayLine::iterator DisplayLine::erase(iterator beg, iterator end)
+{
+ iterator res = m_atoms.erase(beg, end);
+ compute_range();
+ return res;
+}
+
void DisplayLine::optimize()
{
if (m_atoms.empty())
@@ -142,9 +149,11 @@ void DisplayLine::trim(CharCount first_char, CharCount char_count)
compute_range();
}
+constexpr BufferRange init_range{ {INT_MAX, INT_MAX}, {INT_MIN, INT_MIN} };
+
void DisplayLine::compute_range()
{
- m_range = { {INT_MAX, INT_MAX}, {INT_MIN, INT_MIN} };
+ m_range = init_range;
for (auto& atom : m_atoms)
{
if (not atom.has_buffer_range())
@@ -152,17 +161,21 @@ void DisplayLine::compute_range()
m_range.first = std::min(m_range.first, atom.begin());
m_range.second = std::max(m_range.second, atom.end());
}
+ if (m_range == init_range)
+ m_range = { { 0, 0 }, { 0, 0 } };
+ kak_assert(m_range.first <= m_range.second);
}
void DisplayBuffer::compute_range()
{
- m_range.first = {INT_MAX,INT_MAX};
- m_range.second = {0,0};
+ m_range = init_range;
for (auto& line : m_lines)
{
m_range.first = std::min(line.range().first, m_range.first);
m_range.second = std::max(line.range().second, m_range.second);
}
+ if (m_range == init_range)
+ m_range = { { 0, 0 }, { 0, 0 } };
kak_assert(m_range.first <= m_range.second);
}
diff --git a/src/display_buffer.hh b/src/display_buffer.hh
index 320019d6..92896ee9 100644
--- a/src/display_buffer.hh
+++ b/src/display_buffer.hh
@@ -122,6 +122,7 @@ class DisplayLine
public:
using iterator = AtomList::iterator;
using const_iterator = AtomList::const_iterator;
+ using value_type = AtomList::value_type;
DisplayLine() = default;
DisplayLine(AtomList atoms);
@@ -143,6 +144,7 @@ public:
iterator split(iterator it, BufferCoord 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
diff --git a/src/highlighters.cc b/src/highlighters.cc
index 67641f46..5f1c8ed1 100644
--- a/src/highlighters.cc
+++ b/src/highlighters.cc
@@ -61,6 +61,89 @@ void highlight_range(DisplayBuffer& display_buffer,
}
}
+template<typename T>
+void apply_highlighter(const Window& window,
+ DisplayBuffer& display_buffer,
+ BufferCoord begin, BufferCoord end,
+ T&& highlighter)
+{
+ using LineIterator = DisplayBuffer::LineList::iterator;
+ LineIterator first_line;
+ std::vector<DisplayLine::iterator> insert_pos;
+ auto line_end = display_buffer.lines().end();
+
+ DisplayBuffer region_display;
+ auto& region_lines = region_display.lines();
+ for (auto line_it = display_buffer.lines().begin(); line_it != line_end; ++line_it)
+ {
+ auto& line = *line_it;
+ auto& range = line.range();
+ if (range.second <= begin or end < range.first)
+ continue;
+
+ if (region_lines.empty())
+ first_line = line_it;
+ region_lines.emplace_back();
+ insert_pos.emplace_back();
+
+ if (range.first < begin or range.second > end)
+ {
+ size_t beg_idx = 0;
+ size_t end_idx = line.atoms().size();
+
+ for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
+ {
+ if (not atom_it->has_buffer_range() or end <= atom_it->begin() or begin >= atom_it->end())
+ continue;
+
+ bool is_replaced = atom_it->type() == DisplayAtom::ReplacedBufferRange;
+ if (atom_it->begin() <= begin)
+ {
+ if (is_replaced or atom_it->begin() == begin)
+ beg_idx = atom_it - line.begin();
+ else
+ {
+ atom_it = ++line.split(atom_it, begin);
+ beg_idx = atom_it - line.begin();
+ ++end_idx;
+ }
+ }
+
+ if (atom_it->end() >= end)
+ {
+ if (is_replaced or atom_it->end() == end)
+ beg_idx = atom_it - line.begin();
+ else
+ {
+ atom_it = ++line.split(atom_it, end);
+ end_idx = atom_it - line.begin();
+ }
+ }
+ }
+ std::move(line.begin() + beg_idx, line.begin() + end_idx,
+ std::back_inserter(region_lines.back()));
+ insert_pos.back() = line.erase(line.begin() + beg_idx, line.begin() + end_idx);
+ }
+ else
+ {
+ region_lines.back() = std::move(line);
+ insert_pos.back() = line.begin();
+ }
+ }
+
+ region_display.compute_range();
+ highlighter(window, region_display);
+
+ for (size_t i = 0; i < region_lines.size(); ++i)
+ {
+ auto& line = *(first_line + i);
+ auto pos = insert_pos[i];
+ for (auto& atom : region_lines[i])
+ pos = ++line.insert(pos, std::move(atom));
+ }
+ display_buffer.compute_range();
+}
+
typedef std::unordered_map<size_t, const ColorPair*> ColorSpec;
class RegexColorizer
@@ -418,29 +501,29 @@ HighlighterAndId reference_factory(HighlighterParameters params)
{ DefinedHighlighters::instance().get_group(name, '/')(window, display_buffer); });
}
+template<typename HighlightFunc>
struct RegionHighlighter
{
public:
RegionHighlighter(String begin, String end, String ignore_prefix,
- ColorPair colors)
+ HighlightFunc func)
: m_begin(std::move(begin)),
m_end(std::move(end)),
m_ignore_prefix(std::move(ignore_prefix)),
- m_colors(colors)
+ m_func(std::move(func))
{}
void operator()(const Window& window, DisplayBuffer& display_buffer)
{
auto& cache = update_cache_ifn(window.buffer());
for (auto& pair : cache.regions)
- highlight_range(display_buffer, pair.first, pair.second, true,
- [this](DisplayAtom& atom) { atom.colors = m_colors; });
+ m_func(window, display_buffer, pair.first, pair.second);
}
private:
String m_begin;
String m_end;
String m_ignore_prefix;
- ColorPair m_colors;
+ HighlightFunc m_func;
struct RegionCache
{
@@ -482,6 +565,15 @@ private:
}
};
+template<typename HighlightFunc>
+RegionHighlighter<HighlightFunc>
+make_region_highlighter(String begin, String end, String ignore_prefix,
+ HighlightFunc func)
+{
+ return RegionHighlighter<HighlightFunc>(std::move(begin), std::move(end),
+ std::move(ignore_prefix), std::move(func));
+}
+
HighlighterAndId region_factory(HighlighterParameters params)
{
if (params.size() != 3 and params.size() != 4)
@@ -492,10 +584,37 @@ HighlighterAndId region_factory(HighlighterParameters params)
const String& ignore_prefix = params.size() == 4 ? params[2] : "";
const ColorPair colors = get_color(params.back());
- return HighlighterAndId("region("+begin+","+end+","+ignore_prefix+")",
- RegionHighlighter{begin, end, ignore_prefix, colors});
+ auto func = [colors](const Window&, DisplayBuffer& display_buffer,
+ BufferCoord begin, BufferCoord end)
+ {
+ highlight_range(display_buffer, begin, end, true,
+ [&colors](DisplayAtom& atom) { atom.colors = colors; });
+ };
+
+ return HighlighterAndId("region(" + begin + "," + end + "," + ignore_prefix + ")",
+ make_region_highlighter(begin, end, ignore_prefix, func));
}
+HighlighterAndId region_ref_factory(HighlighterParameters params)
+{
+ if (params.size() != 3 and params.size() != 4)
+ throw runtime_error("wrong parameter count");
+
+ const String& begin = params[0];
+ const String& end = params[1];
+ const String& ignore_prefix = params.size() == 4 ? params[2] : "";
+ const String& name = params.back();
+
+ auto func = [name](const Window& window, DisplayBuffer& display_buffer,
+ BufferCoord begin, BufferCoord end)
+ {
+ HighlighterGroup& ref = DefinedHighlighters::instance().get_group(name, '/');
+ apply_highlighter(window, display_buffer, begin, end, ref);
+ };
+
+ return HighlighterAndId("regionref(" + begin + "," + end + "," + ignore_prefix + "," + name + ")",
+ make_region_highlighter(begin, end, ignore_prefix, func));
+}
void register_highlighters()
{
@@ -509,6 +628,7 @@ void register_highlighters()
registry.register_func("flag_lines", flag_lines_factory);
registry.register_func("ref", reference_factory);
registry.register_func("region", region_factory);
+ registry.register_func("region_ref", region_ref_factory);
}
}