diff --git a/src/highlighters.cc b/src/highlighters.cc index 6e877dc4..33ec6005 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -89,13 +89,18 @@ void replace_range(DisplayBuffer& display_buffer, BufferCoord begin, BufferCoord end, T func) { // tolerate begin > end as that can be triggered by wrong encodings - if (begin > end or end <= display_buffer.range().begin - or begin >= display_buffer.range().end) + 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) + { + func(line, line.atoms().size(), line.atoms().size()); + continue; + } + if (range.end <= begin or end < range.begin) continue; @@ -103,7 +108,7 @@ void replace_range(DisplayBuffer& display_buffer, 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()) + end < atom_it->begin() or begin >= atom_it->end()) continue; if (begin >= atom_it->begin()) @@ -1573,20 +1578,22 @@ private: 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(); + }; + for (auto& [range, spec] : range_and_faces.list) { try { - if (buffer.is_valid(range.first) and (buffer.is_valid(range.last) or is_empty(range))) - { - auto replacement = parse_display_line(spec, context.context.faces()); - replace_range(display_buffer, range.first, is_empty(range) ? range.first : buffer.char_next(range.last), - [&](DisplayLine& line, int beg_idx, int end_idx){ - auto it = line.erase(line.begin() + beg_idx, line.begin() + end_idx); - for (auto& atom : replacement) - it = ++line.insert(it, std::move(atom)); - }); - } + if (!is_valid(range.first) or (!is_empty(range) and !is_valid(range.last))) + continue; + auto replacement = parse_display_line(spec, context.context.faces()); + replace_range(display_buffer, range.first, is_empty(range) ? range.first : buffer.char_next(range.last), + [&](DisplayLine& line, int beg_idx, int end_idx){ + auto it = line.erase(line.begin() + beg_idx, line.begin() + end_idx); + std::move(replacement.begin(), replacement.end(), std::inserter(line, it)); + }); } catch (runtime_error&) {} diff --git a/test/highlight/replace-empty-range/cmd b/test/highlight/replace-empty-range/cmd new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/highlight/replace-empty-range/cmd @@ -0,0 +1 @@ + diff --git a/test/highlight/replace-empty-range/in b/test/highlight/replace-empty-range/in new file mode 100644 index 00000000..b28e3e21 --- /dev/null +++ b/test/highlight/replace-empty-range/in @@ -0,0 +1,2 @@ +12345 +12345 diff --git a/test/highlight/replace-empty-range/rc b/test/highlight/replace-empty-range/rc new file mode 100644 index 00000000..054759c6 --- /dev/null +++ b/test/highlight/replace-empty-range/rc @@ -0,0 +1,2 @@ +declare-option range-specs test_ranges %val{timestamp} '1.1+0|A' '1.7+0|B' '2.3+0|C' +add-highlighter window/ replace-ranges test_ranges diff --git a/test/highlight/replace-empty-range/script b/test/highlight/replace-empty-range/script new file mode 100644 index 00000000..3f4df30d --- /dev/null +++ b/test/highlight/replace-empty-range/script @@ -0,0 +1,7 @@ +ui_out '{ "jsonrpc": "2.0", "method": "set_ui_options", "params": [{}] }' +ui_out '{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "A" }, { "face": { "fg": "black", "bg": "white", "attributes": [] }, "contents": "1" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "2345\u000a" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "B" }], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "12" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "C" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "345\u000a" }]], { "fg": "default", "bg": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "attributes": [] }] }' +ui_out '{ "jsonrpc": "2.0", "method": "menu_hide", "params": [] }' +ui_out '{ "jsonrpc": "2.0", "method": "info_hide", "params": [] }' +ui_out '{ "jsonrpc": "2.0", "method": "draw_status", "params": [[], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "out 1:1 " }, { "face": { "fg": "black", "bg": "yellow", "attributes": [] }, "contents": "" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "blue", "bg": "default", "attributes": [] }, "contents": "1 sel" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " - client0@[kak-tests]" }], { "fg": "cyan", "bg": "default", "attributes": [] }] }' +ui_out '{ "jsonrpc": "2.0", "method": "set_cursor", "params": ["buffer", { "line": 0, "column": 1 }] }' +ui_out '{ "jsonrpc": "2.0", "method": "refresh", "params": [true] }'