From 6b42c48c3f198d0251b8700884a022b15ac7af7a Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 13 May 2014 19:35:28 +0100 Subject: [PATCH 1/7] Refactor DynamicRegexHighlighter, search hl uses Search colalias fixes #122 --- src/color_registry.cc | 1 + src/highlighters.cc | 68 +++++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/color_registry.cc b/src/color_registry.cc index 4867234d..afe14e5c 100644 --- a/src/color_registry.cc +++ b/src/color_registry.cc @@ -64,6 +64,7 @@ ColorRegistry::ColorRegistry() { "StatusCursor", { Colors::Black, Colors::Cyan } }, { "Prompt", { Colors::Yellow, Colors::Default } }, { "MatchingChar", { Colors::Default, Colors::Magenta } }, + { "Search", { Colors::Default, Colors::Magenta } }, } {} diff --git a/src/highlighters.cc b/src/highlighters.cc index cc484b88..4c9757c6 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -267,12 +267,14 @@ HighlighterAndId colorize_regex_factory(HighlighterParameters params) } } -template +template class DynamicRegexHighlighter { public: - DynamicRegexHighlighter(const ColorSpec& colors, RegexGetter getter) - : m_regex_getter(getter), m_colors(colors), m_colorizer(Regex(), m_colors) {} + DynamicRegexHighlighter(RegexGetter regex_getter, ColorGetter color_getter) + : m_regex_getter(std::move(regex_getter)), + m_color_getter(std::move(color_getter)), + m_colorizer(Regex(), ColorSpec{}) {} void operator()(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer) { @@ -280,40 +282,56 @@ public: return; Regex regex = m_regex_getter(context); - if (regex != m_last_regex) + ColorSpec color = m_color_getter(context); + if (regex != m_last_regex or color != m_last_color) { m_last_regex = regex; + m_last_color = color; if (not m_last_regex.empty()) - m_colorizer = RegexColorizer{m_last_regex, m_colors}; + m_colorizer = RegexColorizer{m_last_regex, color}; } - if (not m_last_regex.empty()) + if (not m_last_regex.empty() and not m_last_color.empty()) m_colorizer(context, flags, display_buffer); } private: Regex m_last_regex; - ColorSpec m_colors; - RegexColorizer m_colorizer; RegexGetter m_regex_getter; + + ColorSpec m_last_color; + ColorGetter m_color_getter; + + RegexColorizer m_colorizer; }; +template +DynamicRegexHighlighter +make_dynamic_regex_highlighter(RegexGetter regex_getter, ColorGetter color_getter) +{ + return DynamicRegexHighlighter( + std::move(regex_getter), std::move(color_getter)); +} + + HighlighterAndId highlight_search_factory(HighlighterParameters params) { - if (params.size() != 1) + if (params.size() != 0) throw runtime_error("wrong parameter count"); - try - { - ColorSpec colors { { 0, &get_color(params[0]) } }; + auto get_color = [](const Context& context){ + return ColorSpec{ { 0, &Kakoune::get_color("Search") } }; + }; auto get_regex = [](const Context&){ auto s = RegisterManager::instance()['/'].values(Context{}); - return s.empty() ? Regex{} : Regex{s[0].begin(), s[0].end()}; + try + { + return s.empty() ? Regex{} : Regex{s[0].begin(), s[0].end()}; + } + catch (boost::regex_error& err) + { + return Regex{}; + } }; - return {"hlsearch", DynamicRegexHighlighter{colors, get_regex}}; - } - catch (boost::regex_error& err) - { - throw runtime_error(String("regex error: ") + err.what()); - } + return {"hlsearch", make_dynamic_regex_highlighter(get_regex, get_color)}; } HighlighterAndId highlight_regex_option_factory(HighlighterParameters params) @@ -321,13 +339,19 @@ HighlighterAndId highlight_regex_option_factory(HighlighterParameters params) if (params.size() != 2) throw runtime_error("wrong parameter count"); - ColorSpec colors { { 0, &get_color(params[1]) } }; + const ColorPair& color = get_color(params[1]); + auto get_color = [&](const Context&){ + return ColorSpec{ { 0, &color } }; + }; + String option_name = params[0]; // verify option type now GlobalOptions::instance()[option_name].get(); - auto get_regex = [option_name](const Context& context){ return context.options()[option_name].get(); }; - return {"hloption_" + option_name, DynamicRegexHighlighter{colors, get_regex}}; + auto get_regex = [option_name](const Context& context){ + return context.options()[option_name].get(); + }; + return {"hloption_" + option_name, make_dynamic_regex_highlighter(get_regex, get_color)}; } void expand_tabulations(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer) From 016ede38d169c665fdc899ba688dc4ef52cd45d3 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 13 May 2014 19:45:32 +0100 Subject: [PATCH 2/7] Fix show_matching highlighter when opening char is the first buffer char Fixes #119 --- src/highlighters.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/highlighters.cc b/src/highlighters.cc index 4c9757c6..d0858eed 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -495,7 +495,7 @@ void show_matching_char(const Context& context, HighlightFlags flags, DisplayBuf return false; return true; }); - if (it != end) + if (it != end or (*end == pair.first and level == 1)) highlight_range(display_buffer, it.coord(), (it+1).coord(), false, [&](DisplayAtom& atom) { atom.colors = colors; }); break; From 855357ee73c1a52e9d1adbe4078fe631a9d5c5bc Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 13 May 2014 19:48:16 +0100 Subject: [PATCH 3/7] Fix :delbuf! not forcing buffer deletion Fixes #116 --- src/commands.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands.cc b/src/commands.cc index e3437dfa..ecd792dc 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -332,7 +332,7 @@ const CommandDesc force_delbuf_cmd = { single_optional_name_param, CommandFlags::None, buffer_completer, - delete_buffer + delete_buffer }; const CommandDesc namebuf_cmd = { From 34e1c2ddd50fa70ecce19556cb812d135e099c26 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 14 May 2014 19:22:42 +0100 Subject: [PATCH 4/7] Fix RegexColorizer cache handling --- src/highlighters.cc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/highlighters.cc b/src/highlighters.cc index d0858eed..a73ba9e4 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -196,8 +196,8 @@ private: struct Cache { Cache(const Buffer&){} - BufferRange m_range; - size_t m_timestamp = 0; + std::pair m_range; + size_t m_timestamp = 0; std::vector>> m_matches; }; BufferSideCache m_cache; @@ -209,18 +209,21 @@ private: { Cache& cache = m_cache.get(buffer); + LineCount first_line = range.first.line; + LineCount last_line = std::min(buffer.line_count()-1, range.second.line); + if (buffer.timestamp() == cache.m_timestamp and - range.first >= cache.m_range.first and - range.second <= cache.m_range.second) + first_line >= cache.m_range.first and + last_line <= cache.m_range.second) return cache; - cache.m_range.first = buffer.clamp({range.first.line - 10, 0}); - cache.m_range.second = buffer.next(buffer.clamp({range.second.line + 10, INT_MAX})); + cache.m_range.first = std::max(0_line, first_line - 10); + cache.m_range.second = std::min(buffer.line_count()-1, last_line+10); cache.m_timestamp = buffer.timestamp(); cache.m_matches.clear(); RegexIterator re_it{buffer.iterator_at(cache.m_range.first), - buffer.iterator_at(cache.m_range.second), m_regex}; + buffer.iterator_at(cache.m_range.second+1), m_regex}; RegexIterator re_end; for (; re_it != re_end; ++re_it) { From aa481791312f19fa7aa42412fa0d8d9c5d653c89 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 15 May 2014 19:11:59 +0100 Subject: [PATCH 5/7] read all available text in fifo each time the fd is signaled --- src/buffer_utils.cc | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index 9f5892c2..f05db777 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -2,6 +2,8 @@ #include "event_manager.hh" +#include + namespace Kakoune { @@ -27,30 +29,41 @@ Buffer* create_fifo_buffer(String name, int fd, bool scroll) Buffer* buffer = new Buffer(std::move(name), Buffer::Flags::Fifo | Buffer::Flags::NoUndo); auto watcher = new FDWatcher(fd, [buffer, scroll](FDWatcher& watcher) { - constexpr size_t buffer_size = 1024 * 16; + constexpr size_t buffer_size = 2048; char data[buffer_size]; - ssize_t count = read(watcher.fd(), data, buffer_size); - auto pos = buffer->end()-1; - - bool prevent_scrolling = pos == buffer->begin() and not scroll; - if (prevent_scrolling) - ++pos; - - buffer->insert(pos, count > 0 ? String(data, data+count) - : "*** kak: fifo closed ***\n"); - - if (prevent_scrolling) + const int fifo = watcher.fd(); + timeval tv{ 0, 0 }; + fd_set rfds; + ssize_t count = 0; + do { - buffer->erase(buffer->begin(), buffer->begin()+1); - buffer->insert(buffer->end(), "\n"); + count = read(fifo, data, buffer_size); + auto pos = buffer->end()-1; + + bool prevent_scrolling = pos == buffer->begin() and not scroll; + if (prevent_scrolling) + ++pos; + + buffer->insert(pos, count > 0 ? String(data, data+count) + : "*** kak: fifo closed ***\n"); + + if (prevent_scrolling) + { + buffer->erase(buffer->begin(), buffer->begin()+1); + buffer->insert(buffer->end(), "\n"); + } + + FD_ZERO(&rfds); + FD_SET(fifo, &rfds); } + while (count > 0 and select(fifo+1, &rfds, nullptr, nullptr, &tv) == 1); if (count <= 0) { kak_assert(buffer->flags() & Buffer::Flags::Fifo); buffer->flags() &= ~Buffer::Flags::Fifo; buffer->flags() &= ~Buffer::Flags::NoUndo; - close(watcher.fd()); + close(fifo); delete &watcher; } }); From c21368cac52526afe1805b2e5a8bad32ba283e53 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 16 May 2014 19:29:39 +0100 Subject: [PATCH 6/7] DisplayAtom::content returns a StringView --- src/display_buffer.hh | 15 +++++++++++---- src/ncurses.cc | 6 ++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/display_buffer.hh b/src/display_buffer.hh index 50b1c92a..db70d840 100644 --- a/src/display_buffer.hh +++ b/src/display_buffer.hh @@ -37,18 +37,25 @@ public: : m_type(Text), m_text(std::move(str)), colors(colors), attribute(attribute) { check_invariant(); } - String content() const + StringView content() const { switch (m_type) { case BufferRange: - return m_buffer->string(m_begin, m_end); + { + auto& line = (*m_buffer)[m_begin.line]; + if (m_begin.line == m_end.line) + return line.substr(m_begin.column, m_end.column - m_begin.column); + else if (m_begin.line+1 == m_end.line and m_end.column == 0) + return line.substr(m_begin.column); + break; + } case Text: case ReplacedBufferRange: - return m_text; + return m_text; } kak_assert(false); - return 0; + return {}; } CharCount length() const diff --git a/src/ncurses.cc b/src/ncurses.cc index a4a84fb5..f48ef7ee 100644 --- a/src/ncurses.cc +++ b/src/ncurses.cc @@ -241,8 +241,10 @@ void NCursesUI::draw_line(const DisplayLine& line, CharCount col_index) const set_color(stdscr, atom.colors); - String atom_content = atom.content(); - StringView content = atom_content; + StringView content = atom.content(); + if (content.empty()) + continue; + if (content[content.length()-1] == '\n' and content.char_length() - 1 < m_dimensions.column - col_index) { From 9240cccf74ddf175eb0dac5005633d19e3068539 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sat, 17 May 2014 10:17:28 +0100 Subject: [PATCH 7/7] set Coords/Counts methods as always_inline They are well tested, and we never want to step into them when debugging --- src/coord.hh | 13 +++++++++++++ src/units.hh | 31 +++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/coord.hh b/src/coord.hh index daa8bee0..f60be779 100644 --- a/src/coord.hh +++ b/src/coord.hh @@ -12,14 +12,17 @@ struct LineAndColumn LineType line; ColumnType column; + [[gnu::always_inline]] constexpr LineAndColumn(LineType line = 0, ColumnType column = 0) : line(line), column(column) {} + [[gnu::always_inline]] constexpr EffectiveType operator+(EffectiveType other) const { return EffectiveType(line + other.line, column + other.column); } + [[gnu::always_inline]] EffectiveType& operator+=(EffectiveType other) { line += other.line; @@ -27,11 +30,13 @@ struct LineAndColumn return *static_cast(this); } + [[gnu::always_inline]] constexpr EffectiveType operator-(EffectiveType other) const { return EffectiveType(line - other.line, column - other.column); } + [[gnu::always_inline]] EffectiveType& operator-=(EffectiveType other) { line -= other.line; @@ -39,35 +44,41 @@ struct LineAndColumn return *static_cast(this); } + [[gnu::always_inline]] constexpr bool operator< (EffectiveType other) const { return (line != other.line) ? line < other.line : column < other.column; } + [[gnu::always_inline]] constexpr bool operator<= (EffectiveType other) const { return (line != other.line) ? line < other.line : column <= other.column; } + [[gnu::always_inline]] constexpr bool operator> (EffectiveType other) const { return (line != other.line) ? line > other.line : column > other.column; } + [[gnu::always_inline]] constexpr bool operator>= (EffectiveType other) const { return (line != other.line) ? line > other.line : column >= other.column; } + [[gnu::always_inline]] constexpr bool operator== (EffectiveType other) const { return line == other.line and column == other.column; } + [[gnu::always_inline]] constexpr bool operator!= (EffectiveType other) const { return line != other.line or column != other.column; @@ -76,12 +87,14 @@ struct LineAndColumn struct ByteCoord : LineAndColumn { + [[gnu::always_inline]] constexpr ByteCoord(LineCount line = 0, ByteCount column = 0) : LineAndColumn(line, column) {} }; struct CharCoord : LineAndColumn { + [[gnu::always_inline]] constexpr CharCoord(LineCount line = 0, CharCount column = 0) : LineAndColumn(line, column) {} }; diff --git a/src/units.hh b/src/units.hh index 430971e8..69ecffdb 100644 --- a/src/units.hh +++ b/src/units.hh @@ -10,6 +10,7 @@ template class StronglyTypedNumber { public: + [[gnu::always_inline]] explicit constexpr StronglyTypedNumber(ValueType value) : m_value(value) { @@ -17,72 +18,96 @@ public: "RealType is not derived from StronglyTypedNumber"); } + [[gnu::always_inline]] constexpr RealType operator+(RealType other) const { return RealType(m_value + other.m_value); } + [[gnu::always_inline]] constexpr RealType operator-(RealType other) const { return RealType(m_value - other.m_value); } + [[gnu::always_inline]] constexpr RealType operator*(RealType other) const { return RealType(m_value * other.m_value); } + [[gnu::always_inline]] constexpr RealType operator/(RealType other) const { return RealType(m_value / other.m_value); } + [[gnu::always_inline]] RealType& operator+=(RealType other) { m_value += other.m_value; return static_cast(*this); } + [[gnu::always_inline]] RealType& operator-=(RealType other) { m_value -= other.m_value; return static_cast(*this); } + [[gnu::always_inline]] RealType& operator*=(RealType other) { m_value *= other.m_value; return static_cast(*this); } + [[gnu::always_inline]] RealType& operator/=(RealType other) { m_value /= other.m_value; return static_cast(*this); } + [[gnu::always_inline]] RealType& operator++() { ++m_value; return static_cast(*this); } + [[gnu::always_inline]] RealType& operator--() { --m_value; return static_cast(*this); } + [[gnu::always_inline]] RealType operator++(int) { RealType backup(static_cast(*this)); ++m_value; return backup; } + [[gnu::always_inline]] RealType operator--(int) { RealType backup(static_cast(*this)); --m_value; return backup; } + [[gnu::always_inline]] constexpr RealType operator-() const { return RealType(-m_value); } + [[gnu::always_inline]] constexpr RealType operator%(RealType other) const { return RealType(m_value % other.m_value); } + [[gnu::always_inline]] RealType& operator%=(RealType other) { m_value %= other.m_value; return static_cast(*this); } + [[gnu::always_inline]] constexpr bool operator==(RealType other) const { return m_value == other.m_value; } + [[gnu::always_inline]] constexpr bool operator!=(RealType other) const { return m_value != other.m_value; } + [[gnu::always_inline]] constexpr bool operator<(RealType other) const { return m_value < other.m_value; } + [[gnu::always_inline]] constexpr bool operator<=(RealType other) const { return m_value <= other.m_value; } + [[gnu::always_inline]] constexpr bool operator>(RealType other) const { return m_value > other.m_value; } + [[gnu::always_inline]] constexpr bool operator>=(RealType other) const { return m_value >= other.m_value; } + [[gnu::always_inline]] constexpr bool operator!() const { return !m_value; } + [[gnu::always_inline]] explicit constexpr operator ValueType() const { return m_value; } + [[gnu::always_inline]] explicit constexpr operator bool() const { return m_value; } private: ValueType m_value; @@ -90,9 +115,11 @@ private: struct LineCount : public StronglyTypedNumber { + [[gnu::always_inline]] constexpr LineCount(int value = 0) : StronglyTypedNumber(value) {} }; +[[gnu::always_inline]] inline constexpr LineCount operator"" _line(unsigned long long int value) { return LineCount(value); @@ -100,9 +127,11 @@ inline constexpr LineCount operator"" _line(unsigned long long int value) struct ByteCount : public StronglyTypedNumber { + [[gnu::always_inline]] constexpr ByteCount(int value = 0) : StronglyTypedNumber(value) {} }; +[[gnu::always_inline]] inline constexpr ByteCount operator"" _byte(unsigned long long int value) { return ByteCount(value); @@ -110,9 +139,11 @@ inline constexpr ByteCount operator"" _byte(unsigned long long int value) struct CharCount : public StronglyTypedNumber { + [[gnu::always_inline]] constexpr CharCount(int value = 0) : StronglyTypedNumber(value) {} }; +[[gnu::always_inline]] inline constexpr CharCount operator"" _char(unsigned long long int value) { return CharCount(value);