summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/pages/options.asciidoc2
-rw-r--r--rc/filetype/julia.kak4
-rw-r--r--src/buffer_utils.cc3
-rw-r--r--src/client.cc3
-rw-r--r--src/client_manager.cc10
-rw-r--r--src/hash_map.hh7
-rw-r--r--src/highlighter.hh12
-rw-r--r--src/highlighters.cc225
-rw-r--r--src/normal.cc26
-rw-r--r--src/ranges.hh28
-rw-r--r--src/window.cc60
-rw-r--r--test/highlight/wrap/basic/cmd1
-rw-r--r--test/highlight/wrap/basic/in2
-rw-r--r--test/highlight/wrap/basic/rc1
-rw-r--r--test/highlight/wrap/basic/script4
-rw-r--r--test/highlight/wrap/interact-with-number-lines/cmd1
-rw-r--r--test/highlight/wrap/interact-with-number-lines/in2
-rw-r--r--test/highlight/wrap/interact-with-number-lines/rc2
-rw-r--r--test/highlight/wrap/interact-with-number-lines/script3
-rw-r--r--test/highlight/wrap/interact-with-replace-ranges/cmd1
-rw-r--r--test/highlight/wrap/interact-with-replace-ranges/in3
-rw-r--r--test/highlight/wrap/interact-with-replace-ranges/rc4
-rw-r--r--test/highlight/wrap/interact-with-replace-ranges/script3
-rw-r--r--test/highlight/wrap/interact-with-tabulation/cmd1
-rw-r--r--test/highlight/wrap/interact-with-tabulation/in1
-rw-r--r--test/highlight/wrap/interact-with-tabulation/rc2
-rw-r--r--test/highlight/wrap/interact-with-tabulation/script4
-rw-r--r--test/highlight/wrap/marker-and-indent/cmd1
-rw-r--r--test/highlight/wrap/marker-and-indent/in4
-rw-r--r--test/highlight/wrap/marker-and-indent/rc1
-rw-r--r--test/highlight/wrap/marker-and-indent/script4
-rw-r--r--test/normal/pipe-replaces-all-lines/cmd1
-rw-r--r--test/normal/pipe-replaces-all-lines/in2
-rw-r--r--test/normal/pipe-replaces-all-lines/out2
-rw-r--r--test/regression/0-slow-BufCloseFifo/cmd1
-rw-r--r--test/regression/0-slow-BufCloseFifo/in1
-rw-r--r--test/regression/0-slow-BufCloseFifo/rc16
-rw-r--r--test/regression/0-slow-BufCloseFifo/script2
-rw-r--r--test/regression/2999-buggy-wrapping/cmd2
-rw-r--r--test/regression/5338-crash-when-changing-buffer-on-WinDiplay/cmd1
-rw-r--r--test/regression/5338-crash-when-changing-buffer-on-WinDiplay/in1
-rw-r--r--test/regression/5338-crash-when-changing-buffer-on-WinDiplay/rc1
-rwxr-xr-xtest/run10
-rw-r--r--test/tools/git/blame-in-diff/rc15
-rw-r--r--test/tools/git/blame-in-diff/script11
45 files changed, 229 insertions, 262 deletions
diff --git a/doc/pages/options.asciidoc b/doc/pages/options.asciidoc
index e5cb4c38..85a6e098 100644
--- a/doc/pages/options.asciidoc
+++ b/doc/pages/options.asciidoc
@@ -342,7 +342,7 @@ are exclusively available to built-in options.
*ui_options* `str-to-str-map`::
a list of `key=value` pairs that are forwarded to the user
- interface implementation. The NCurses UI supports the following options:
+ interface implementation. The Terminal UI supports the following options:
*terminal_set_title*:::
if *yes* or *true*, the terminal emulator title will
diff --git a/rc/filetype/julia.kak b/rc/filetype/julia.kak
index 5b125bc2..6dc2af13 100644
--- a/rc/filetype/julia.kak
+++ b/rc/filetype/julia.kak
@@ -24,7 +24,7 @@ hook -group julia-highlight global WinSetOption filetype=julia %{
}
-provide-module julia %{
+provide-module julia %§
# Highlighters
# ‾‾‾‾‾‾‾‾‾‾‾‾
@@ -64,4 +64,4 @@ define-command -hidden julia-insert-on-new-line %<
try %{ execute-keys -draft x <a-k> ^\h*end <ret> <lt> }
>
>
-}
diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc
index a2d2e709..bb64e9c1 100644
--- a/src/buffer_utils.cc
+++ b/src/buffer_utils.cc
@@ -290,7 +290,8 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, AutoScroll
kak_assert(m_buffer.flags() & Buffer::Flags::Fifo);
close_fd();
m_buffer.run_hook_in_own_context(Hook::BufCloseFifo, "");
- m_buffer.flags() &= ~(Buffer::Flags::Fifo | Buffer::Flags::NoUndo);
+ if (not m_buffer.values().contains(fifo_watcher_id))
+ m_buffer.flags() &= ~(Buffer::Flags::Fifo | Buffer::Flags::NoUndo);
}
void read_fifo()
diff --git a/src/client.cc b/src/client.cc
index 2cb1c973..14b7b7bc 100644
--- a/src/client.cc
+++ b/src/client.cc
@@ -194,6 +194,9 @@ void Client::change_buffer(Buffer& buffer, Optional<FunctionRef<void()>> set_sel
if (m_buffer_reload_dialog_opened)
close_buffer_reload_dialog();
+ if (context().buffer().flags() & Buffer::Flags::Locked)
+ throw runtime_error("Changing buffer is not allowed while current buffer is locked");
+
buffer.flags() |= Buffer::Flags::Locked;
OnScopeEnd unlock{[&] { buffer.flags() &= ~Buffer::Flags::Locked; }};
diff --git a/src/client_manager.cc b/src/client_manager.cc
index 2e7d76e7..6798864e 100644
--- a/src/client_manager.cc
+++ b/src/client_manager.cc
@@ -67,17 +67,18 @@ Client* ClientManager::create_client(std::unique_ptr<UserInterface>&& ui, int pi
m_clients.emplace_back(client);
auto& context = client->context();
- if (buffer->name() == "*scratch*")
+ if (context.buffer().name() == "*scratch*")
context.print_status({"This *scratch* buffer won't be automatically saved",
context.faces()["Information"]});
if (init_coord)
{
- auto& selections = context.selections_write_only();
- selections = SelectionList(*buffer, buffer->clamp(*init_coord));
+ context.selections_write_only() = SelectionList(*buffer, context.buffer().clamp(*init_coord));
context.window().center_line(init_coord->line);
}
+ auto(std::move(unlock)); // unlock now
+
try
{
context.hooks().run_hook(Hook::ClientCreate, context.name(), context);
@@ -86,8 +87,7 @@ Client* ClientManager::create_client(std::unique_ptr<UserInterface>&& ui, int pi
catch (Kakoune::runtime_error& error)
{
context.print_status({error.what().str(), context.faces()["Error"]});
- context.hooks().run_hook(Hook::RuntimeError, error.what(),
- context);
+ context.hooks().run_hook(Hook::RuntimeError, error.what(), context);
}
// Do not return the client if it already got moved to the trash
diff --git a/src/hash_map.hh b/src/hash_map.hh
index eef082dd..60ebc6ab 100644
--- a/src/hash_map.hh
+++ b/src/hash_map.hh
@@ -274,6 +274,7 @@ struct HashMap
int index = find_index(key, hash);
if (index >= 0)
{
+ [[maybe_unused]] Item keepalive = std::move(m_items[index]);
m_items.erase(m_items.begin() + index);
m_index.remove(hash, index);
m_index.ordered_fix_entries(index);
@@ -287,7 +288,8 @@ struct HashMap
int index = find_index(key, hash);
if (index >= 0)
{
- constexpr_swap(m_items[index], m_items.back());
+ [[maybe_unused]] Item keepalive = std::move(m_items[index]);
+ m_items[index] = std::move(m_items.back());
m_items.pop_back();
m_index.remove(hash, index);
if (index != m_items.size())
@@ -296,7 +298,7 @@ struct HashMap
}
template<typename KeyType> requires IsHashCompatible<Key, KeyType>
- constexpr void erase(const KeyType& key) { unordered_remove(key); }
+ constexpr void erase(const KeyType& key) { return unordered_remove(key); }
template<typename KeyType> requires IsHashCompatible<Key, KeyType>
constexpr void remove_all(const KeyType& key)
@@ -305,6 +307,7 @@ struct HashMap
for (int index = find_index(key, hash); index >= 0;
index = find_index(key, hash))
{
+ [[maybe_unused]] Item keepalive = std::move(m_items[index]);
m_items.erase(m_items.begin() + index);
m_index.remove(hash, index);
m_index.ordered_fix_entries(index);
diff --git a/src/highlighter.hh b/src/highlighter.hh
index 73520c53..fbeef9e4 100644
--- a/src/highlighter.hh
+++ b/src/highlighter.hh
@@ -22,11 +22,12 @@ using BufferRange = Range<BufferCoord>;
enum class HighlightPass
{
- Wrap = 1 << 0,
- Move = 1 << 1,
- Colorize = 1 << 2,
+ Replace = 1 << 0,
+ Wrap = 1 << 1,
+ Move = 1 << 2,
+ Colorize = 1 << 3,
- All = Wrap | Move | Colorize,
+ All = Replace | Wrap | Move | Colorize,
};
constexpr bool with_bit_ops(Meta::Type<HighlightPass>) { return true; }
@@ -43,11 +44,8 @@ struct DisplaySetup
LineCount line_count;
ColumnCount first_column;
ColumnCount widget_columns;
- // Position of the cursor in the window
- DisplayCoord cursor_pos;
// Offset of line and columns that must remain visible around cursor
DisplayCoord scroll_offset;
- bool ensure_cursor_visible;
};
using HighlighterIdList = ConstArrayView<StringView>;
diff --git a/src/highlighters.cc b/src/highlighters.cc
index 25f93245..5dc2b38a 100644
--- a/src/highlighters.cc
+++ b/src/highlighters.cc
@@ -601,7 +601,7 @@ struct WrapHighlighter : Highlighter
static constexpr StringView ms_id = "wrap";
- struct SplitPos{ ByteCount byte; ColumnCount column; };
+ struct SplitPos{ DisplayLine::iterator atom_it; ByteCount byte; ColumnCount column; };
void do_highlight(HighlightContext context, DisplayBuffer& display_buffer, BufferRange) override
{
@@ -613,42 +613,27 @@ struct WrapHighlighter : Highlighter
return;
const Buffer& buffer = context.context.buffer();
- const auto& cursor = context.context.selections().main().cursor();
const int tabstop = context.context.options()["tabstop"].get<int>();
- const LineCount win_height = context.context.window().dimensions().line;
const ColumnCount marker_len = zero_if_greater(m_marker.column_length(), wrap_column);
const Face face_marker = context.context.faces()["WrapMarker"];
for (auto it = display_buffer.lines().begin();
it != display_buffer.lines().end(); ++it)
{
- const LineCount buf_line = it->range().begin.line;
- const ByteCount line_length = buffer[buf_line].length();
const ColumnCount indent = m_preserve_indent ?
- zero_if_greater(line_indent(buffer, tabstop, buf_line), wrap_column) : 0_col;
+ zero_if_greater(line_indent(buffer, tabstop, it->range().begin.line), wrap_column) : 0_col;
const ColumnCount prefix_len = std::max(marker_len, indent);
- auto pos = next_split_pos(buffer, wrap_column, prefix_len, tabstop, buf_line, {0, 0});
- if (pos.byte == line_length)
- continue;
-
- for (auto atom_it = it->begin();
- pos.byte != line_length and atom_it != it->end(); )
+ SplitPos pos{it->begin(), 0, 0}; ;
+ while (next_split_pos(pos, it->end(), wrap_column, prefix_len))
{
- const BufferCoord coord{buf_line, pos.byte};
- if (!atom_it->has_buffer_range() or
- coord < atom_it->begin() or coord >= atom_it->end())
- {
- ++atom_it;
- continue;
- }
-
auto& line = *it;
- if (coord > atom_it->begin())
- atom_it = ++line.split(atom_it, coord);
+ if (pos.byte > 0 and pos.atom_it->type() == DisplayAtom::Range)
+ pos.atom_it = ++line.split(pos.atom_it, pos.atom_it->begin() + BufferCoord{0, pos.byte});
- DisplayLine new_line{ AtomList{ atom_it, line.end() } };
- line.erase(atom_it, line.end());
+ auto coord = pos.atom_it->begin();
+ DisplayLine new_line{ AtomList{ pos.atom_it, line.end() } };
+ line.erase(pos.atom_it, line.end());
if (marker_len != 0)
new_line.insert(new_line.begin(), {m_marker, face_marker});
@@ -658,23 +643,13 @@ struct WrapHighlighter : Highlighter
it->replace(String{' ', indent - marker_len});
}
- if (it+1 - display_buffer.lines().begin() == win_height)
+ it = display_buffer.lines().insert(it+1, new_line);
+ pos = SplitPos{it->begin(), 0, 0};
+ if (pos.atom_it->type() != DisplayAtom::Range) // avoid infinite loop trying to split too long non-buffer ranges
{
- if (cursor >= new_line.range().begin) // strip first lines if cursor is not visible
- {
- display_buffer.lines().erase(display_buffer.lines().begin(), display_buffer.lines().begin()+1);
- --it;
- }
- else
- {
- display_buffer.lines().erase(it+1, display_buffer.lines().end());
- return;
- }
+ pos.column += pos.atom_it->content().column_length();
+ ++pos.atom_it;
}
- it = display_buffer.lines().insert(it+1, new_line);
-
- pos = next_split_pos(buffer, wrap_column - prefix_len, prefix_len, tabstop, buf_line, pos);
- atom_it = it->begin();
}
}
}
@@ -688,80 +663,9 @@ struct WrapHighlighter : Highlighter
if (wrap_column <= 0)
return;
- const Buffer& buffer = context.context.buffer();
- const auto& cursor = context.context.selections().main().cursor();
- const int tabstop = context.context.options()["tabstop"].get<int>();
-
- auto line_wrap_count = [&](LineCount line, ColumnCount prefix_len) {
- LineCount count = 0;
- const ByteCount line_length = buffer[line].length();
- SplitPos pos{0, 0};
- while (true)
- {
- pos = next_split_pos(buffer, wrap_column - (pos.byte == 0 ? 0_col : prefix_len),
- prefix_len, tabstop, line, pos);
- if (pos.byte == line_length)
- break;
- ++count;
- }
- return count;
- };
-
- const auto win_height = context.context.window().dimensions().line;
-
// Disable horizontal scrolling when using a WrapHighlighter
setup.first_column = 0;
- setup.line_count = 0;
setup.scroll_offset.column = 0;
-
- const ColumnCount marker_len = zero_if_greater(m_marker.column_length(), wrap_column);
-
- for (auto buf_line = setup.first_line, win_line = 0_line;
- win_line < win_height or (setup.ensure_cursor_visible and buf_line <= cursor.line);
- ++buf_line, ++setup.line_count)
- {
- if (buf_line >= buffer.line_count())
- break;
-
- const ColumnCount indent = m_preserve_indent ?
- zero_if_greater(line_indent(buffer, tabstop, buf_line), wrap_column) : 0_col;
- const ColumnCount prefix_len = std::max(marker_len, indent);
-
- if (buf_line == cursor.line)
- {
- SplitPos pos{0, 0};
- for (LineCount count = 0; true; ++count)
- {
- auto next_pos = next_split_pos(buffer, wrap_column - (pos.byte != 0 ? prefix_len : 0_col),
- prefix_len, tabstop, buf_line, pos);
- if (next_pos.byte > cursor.column)
- {
- setup.cursor_pos = DisplayCoord{
- win_line + count,
- get_column(buffer, tabstop, cursor) -
- pos.column + (pos.byte != 0 ? indent : 0_col)
- };
- break;
- }
- pos = next_pos;
- }
- }
- const auto wrap_count = line_wrap_count(buf_line, prefix_len);
- win_line += wrap_count + 1;
-
- // scroll window to keep cursor visible, and update range as lines gets removed
- while (setup.ensure_cursor_visible and
- buf_line >= cursor.line and setup.first_line < cursor.line and
- setup.cursor_pos.line + setup.scroll_offset.line >= win_height)
- {
- auto remove_count = 1 + line_wrap_count(setup.first_line, indent);
- ++setup.first_line;
- --setup.line_count;
- setup.cursor_pos.line -= std::min(win_height, remove_count);
- win_line -= remove_count;
- kak_assert(setup.cursor_pos.line >= 0);
- }
- }
}
void fill_unique_ids(Vector<StringView>& unique_ids) const override
@@ -769,79 +673,72 @@ struct WrapHighlighter : Highlighter
unique_ids.push_back(ms_id);
}
- SplitPos next_split_pos(const Buffer& buffer, ColumnCount wrap_column, ColumnCount prefix_len,
- int tabstop, LineCount line, SplitPos current) const
+ bool next_split_pos(SplitPos& pos, DisplayLine::iterator line_end,
+ ColumnCount wrap_column, ColumnCount prefix_len) const
{
- const ColumnCount target_column = current.column + wrap_column;
- StringView content = buffer[line];
-
- SplitPos pos = current;
- SplitPos last_word_boundary = {0, 0};
- SplitPos last_WORD_boundary = {0, 0};
+ SplitPos last_word_boundary = pos;
+ SplitPos last_WORD_boundary = pos;
- auto update_boundaries = [&](Codepoint cp) {
- if (not m_word_wrap)
- return;
- if (!is_word<Word>(cp))
+ auto update_word_boundaries = [&](Codepoint cp) {
+ if (m_word_wrap and not is_word<Word>(cp))
last_word_boundary = pos;
- if (!is_word<WORD>(cp))
+ if (m_word_wrap and not is_word<WORD>(cp))
last_WORD_boundary = pos;
};
- while (pos.byte < content.length() and pos.column < target_column)
+ while (pos.atom_it != line_end and pos.column < wrap_column)
{
- if (content[pos.byte] == '\t')
+ auto content = pos.atom_it->content();
+ const char* it = &content[pos.byte];
+ const Codepoint cp = utf8::read_codepoint(it, content.end());
+ const ColumnCount width = codepoint_width(cp);
+ if (pos.column + width > wrap_column) // the target column was in the char
{
- const ColumnCount next_column = (pos.column / tabstop + 1) * tabstop;
- if (next_column > target_column and pos.byte != current.byte) // the target column was in the tab
- break;
- pos.column = next_column;
- ++pos.byte;
- last_word_boundary = last_WORD_boundary = pos;
+ update_word_boundaries(cp);
+ break;
}
- else
+ pos.column += width;
+ pos.byte = (int)(it - content.begin());
+ update_word_boundaries(cp);
+ if (it == content.end())
{
- const char* it = &content[pos.byte];
- const Codepoint cp = utf8::read_codepoint(it, content.end());
- const ColumnCount width = codepoint_width(cp);
- if (pos.column + width > target_column and pos.byte != current.byte) // the target column was in the char
- {
- update_boundaries(cp);
- break;
- }
- pos.column += width;
- pos.byte = (int)(it - content.begin());
- update_boundaries(cp);
+ ++pos.atom_it;
+ pos.byte = 0;
}
}
+ if (pos.atom_it == line_end)
+ return false;
+ auto content = pos.atom_it->content();
if (m_word_wrap and pos.byte < content.length())
{
- auto find_split_pos = [&](SplitPos start_pos, auto is_word) -> Optional<SplitPos> {
+ auto find_split_pos = [&](SplitPos start_pos, auto is_word) {
if (start_pos.byte == 0)
- return {};
+ return false;
const char* it = &content[pos.byte];
// split at current position if is a word boundary
if (not is_word(utf8::codepoint(it, content.end()), {'_'}))
- return pos;
+ return true;
// split at last word boundary if the word is shorter than our wrapping width
ColumnCount word_length = pos.column - start_pos.column;
while (it != content.end() and word_length <= (wrap_column - prefix_len))
{
const Codepoint cp = utf8::read_codepoint(it, content.end());
if (not is_word(cp, {'_'}))
- return start_pos;
+ {
+ pos = start_pos;
+ return true;
+ }
word_length += codepoint_width(cp);
}
- return {};
+ return false;
};
- if (auto split = find_split_pos(last_WORD_boundary, is_word<WORD>))
- return *split;
- if (auto split = find_split_pos(last_word_boundary, is_word<Word>))
- return *split;
+ if (find_split_pos(last_WORD_boundary, is_word<WORD>) or
+ find_split_pos(last_word_boundary, is_word<Word>))
+ return true;
}
- return pos;
+ return true;
}
static ColumnCount line_indent(const Buffer& buffer, int tabstop, LineCount line)
@@ -876,7 +773,7 @@ constexpr StringView WrapHighlighter::ms_id;
struct TabulationHighlighter : Highlighter
{
- TabulationHighlighter() : Highlighter{HighlightPass::Move} {}
+ TabulationHighlighter() : Highlighter{HighlightPass::Replace} {}
void do_highlight(HighlightContext context, DisplayBuffer& display_buffer, BufferRange) override
{
@@ -947,7 +844,6 @@ struct TabulationHighlighter : Highlighter
const ColumnCount offset = std::max(column + width - win_end, 0_col);
setup.first_column += offset;
- setup.cursor_pos.column -= offset;
}
};
@@ -968,7 +864,7 @@ const HighlighterDesc show_whitespace_desc = {
struct ShowWhitespacesHighlighter : Highlighter
{
ShowWhitespacesHighlighter(String tab, String tabpad, String spc, String lf, String nbsp, String indent, bool only_trailing)
- : Highlighter{HighlightPass::Move}, m_tab{std::move(tab)}, m_tabpad{std::move(tabpad)},
+ : Highlighter{HighlightPass::Replace}, m_tab{std::move(tab)}, m_tabpad{std::move(tabpad)},
m_spc{std::move(spc)}, m_lf{std::move(lf)}, m_nbsp{std::move(nbsp)}, m_indent{std::move(indent)}, m_only_trailing{std::move(only_trailing)}
{}
@@ -1641,7 +1537,7 @@ const HighlighterDesc replace_ranges_desc = {
"each spec is interpreted as a display line to display in place of the range",
{}
};
-struct ReplaceRangesHighlighter : OptionBasedHighlighter<RangeAndStringList, ReplaceRangesHighlighter, HighlightPass::Move>
+struct ReplaceRangesHighlighter : OptionBasedHighlighter<RangeAndStringList, ReplaceRangesHighlighter, HighlightPass::Replace>
{
using ReplaceRangesHighlighter::OptionBasedHighlighter::OptionBasedHighlighter;
private:
@@ -1694,7 +1590,6 @@ private:
auto& buffer = context.context.buffer();
auto& sels = context.context.selections();
auto& range_and_faces = get_option(context);
- const int tabstop = context.context.options()["tabstop"].get<int>();
update_ranges(buffer, range_and_faces.prefix, range_and_faces.list);
range_and_faces.prefix = buffer.timestamp();
@@ -1707,19 +1602,7 @@ private:
if (range.first.line < setup.first_line and last.line >= setup.first_line)
setup.first_line = range.first.line;
- const auto& cursor = context.context.selections().main().cursor();
- if (cursor.line == last.line and cursor.column >= last.column)
- {
- auto first_column = get_column(buffer, tabstop, range.first);
- auto last_column = get_column(buffer, tabstop, last);
- auto replacement = parse_display_line(spec, context.context.faces());
- auto cursor_move = replacement.length() - ((range.first.line == last.line) ? last_column - first_column : last_column);
- setup.cursor_pos.line -= last.line - range.first.line;
- setup.cursor_pos.column += cursor_move;
- }
-
- if (setup.ensure_cursor_visible and
- last.line >= setup.first_line and
+ if (last.line >= setup.first_line and
range.first.line <= setup.first_line + setup.line_count and
range.first.line != last.line)
{
diff --git a/src/normal.cc b/src/normal.cc
index 0d216436..cdc618a0 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -6,6 +6,7 @@
#include "changes.hh"
#include "command_manager.hh"
#include "context.hh"
+#include "coord.hh"
#include "diff.hh"
#include "enum.hh"
#include "face_registry.hh"
@@ -537,8 +538,9 @@ void command(Context& context, NormalParams params)
command(context, std::move(env_vars), params.reg);
}
-BufferCoord apply_diff(Buffer& buffer, BufferCoord pos, ArrayView<StringView> lines_before, StringView after)
+BufferRange apply_diff(Buffer& buffer, BufferCoord pos, ArrayView<StringView> lines_before, StringView after)
{
+ BufferCoord first = pos;
const auto lines_after = after | split_after<StringView>('\n') | gather<Vector<StringView>>();
auto byte_count = [](auto&& lines, int first, int count) {
@@ -546,6 +548,7 @@ BufferCoord apply_diff(Buffer& buffer, BufferCoord pos, ArrayView<StringView> li
[](ByteCount l, StringView s) { return l + s.length(); });
};
+ bool tried_to_erase_final_newline = false;
for_each_diff(lines_before.begin(), (int)lines_before.size(),
lines_after.begin(), (int)lines_after.size(),
[&, posA = 0, posB = 0](DiffOp op, int len) mutable {
@@ -557,17 +560,28 @@ BufferCoord apply_diff(Buffer& buffer, BufferCoord pos, ArrayView<StringView> li
posB += len;
break;
case DiffOp::Add:
+ if (buffer.is_end(pos) and tried_to_erase_final_newline)
+ pos = buffer.prev(pos);
pos = buffer.insert(pos, {lines_after[posB].begin(),
lines_after[posB + len - 1].end()}).end;
posB += len;
break;
case DiffOp::Remove:
- pos = buffer.erase(pos, buffer.advance(pos, byte_count(lines_before, posA, len)));
+ {
+ BufferCoord end = buffer.advance(pos, byte_count(lines_before, posA, len));
+ tried_to_erase_final_newline |= buffer.is_end(end);
+ pos = buffer.erase(pos, end);
posA += len;
break;
}
+ }
});
- return pos;
+ if (tried_to_erase_final_newline)
+ {
+ first = std::min(first, buffer.back_coord());
+ pos = buffer.erase(buffer.back_coord(), buffer.end_coord());
+ }
+ return {first, pos};
}
template<bool replace>
@@ -628,12 +642,12 @@ void pipe(Context& context, NormalParams params)
if (in_lines.back().back() != '\n' and not out.empty() and out.back() == '\n')
out.resize(out.length()-1, 0);
- auto new_end = apply_diff(buffer, first, in_lines, out);
- if (new_end != first)
+ auto [new_first, new_end] = apply_diff(buffer, first, in_lines, out);
+ if (new_first != new_end)
{
auto& min = sel.min();
auto& max = sel.max();
- min = first;
+ min = new_first;
max = buffer.char_prev(new_end);
}
else
diff --git a/src/ranges.hh b/src/ranges.hh
index af13d6f8..affafda9 100644
--- a/src/ranges.hh
+++ b/src/ranges.hh
@@ -546,10 +546,10 @@ auto find(Range&& range, const T& value)
}
template<typename Range, typename T>
-auto find_if(Range&& range, T op)
+auto find_if(Range&& range, T&& op)
{
using std::begin; using std::end;
- return std::find_if(begin(range), end(range), op);
+ return std::find_if(begin(range), end(range), std::forward<T>(op));
}
template<typename Range, typename T>
@@ -560,24 +560,24 @@ bool contains(Range&& range, const T& value)
}
template<typename Range, typename T>
-bool all_of(Range&& range, T op)
+bool all_of(Range&& range, T&& op)
{
using std::begin; using std::end;
- return std::all_of(begin(range), end(range), op);
+ return std::all_of(begin(range), end(range), std::forward<T>(op));
}
template<typename Range, typename T>
-bool any_of(Range&& range, T op)
+bool any_of(Range&& range, T&& op)
{
using std::begin; using std::end;
- return std::any_of(begin(range), end(range), op);
+ return std::any_of(begin(range), end(range), std::forward<T>(op));
}
template<typename Range, typename T>
-auto remove_if(Range&& range, T op)
+auto remove_if(Range&& range, T&& op)
{
using std::begin; using std::end;
- return std::remove_if(begin(range), end(range), op);
+ return std::remove_if(begin(range), end(range), std::forward<T>(op));
}
template<typename Range, typename U>
@@ -596,7 +596,7 @@ template<typename Range, typename Init, typename BinOp>
Init accumulate(Range&& c, Init&& init, BinOp&& op)
{
using std::begin; using std::end;
- return std::accumulate(begin(c), end(c), init, op);
+ return std::accumulate(begin(c), end(c), init, std::forward<BinOp>(op));
}
template<typename Range, typename Compare, typename Func>
@@ -652,16 +652,12 @@ auto elements()
}};
}
-template<typename ExceptionType, bool exact_size, size_t... Indexes>
-auto static_gather_impl(std::index_sequence<Indexes...>)
-{
- return elements<ExceptionType, exact_size, Indexes...>();
-}
-
template<typename ExceptionType, size_t size, bool exact_size = true>
auto static_gather()
{
- return static_gather_impl<ExceptionType, exact_size>(std::make_index_sequence<size>());
+ return []<size_t... Indexes>(std::index_sequence<Indexes...>) {
+ return elements<ExceptionType, exact_size, Indexes...>();
+ }(std::make_index_sequence<size>());
}
}
diff --git a/src/window.cc b/src/window.cc
index 520d77e1..c65bebe8 100644
--- a/src/window.cc
+++ b/src/window.cc
@@ -132,7 +132,7 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context)
return m_display_buffer;
kak_assert(&buffer() == &context.buffer());
- const DisplaySetup setup = compute_display_setup(context);
+ DisplaySetup setup = compute_display_setup(context);
for (LineCount line = 0; line < setup.line_count; ++line)
{
@@ -144,8 +144,26 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context)
m_display_buffer.compute_range();
const BufferRange range{{0,0}, buffer().end_coord()};
- m_builtin_highlighters.highlight({context, setup, HighlightPass::Wrap, {}}, m_display_buffer, range);
- m_builtin_highlighters.highlight({context, setup, HighlightPass::Move, {}}, m_display_buffer, range);
+ for (auto pass : {HighlightPass::Replace, HighlightPass::Wrap, HighlightPass::Move})
+ m_builtin_highlighters.highlight({context, setup, pass, {}}, m_display_buffer, range);
+
+ if (context.ensure_cursor_visible)
+ {
+ auto cursor_pos = display_coord(context.selections().main().cursor());
+ kak_assert(cursor_pos);
+
+ if (auto line_overflow = cursor_pos->line - m_dimensions.line + setup.scroll_offset.line + 1; line_overflow > 0)
+ {
+ lines.erase(lines.begin(), lines.begin() + (size_t)line_overflow);
+ setup.first_line = lines.begin()->range().begin.line;
+ }
+
+ auto max_first_column = cursor_pos->column - (setup.widget_columns + setup.scroll_offset.column);
+ setup.first_column = std::min(setup.first_column, max_first_column);
+
+ auto min_first_column = cursor_pos->column - (m_dimensions.column - setup.scroll_offset.column) + 1;
+ setup.first_column = std::max(setup.first_column, min_first_column);
+ }
for (auto& line : m_display_buffer.lines())
line.trim_from(setup.widget_columns, setup.first_column, m_dimensions.column);
@@ -203,11 +221,9 @@ DisplaySetup Window::compute_display_setup(const Context& context) const
offset.line = std::min(offset.line, (m_dimensions.line + 1) / 2);
offset.column = std::min(offset.column, (m_dimensions.column + 1) / 2);
- const int tabstop = context.options()["tabstop"].get<int>();
const auto& cursor = context.selections().main().cursor();
- bool ensure_cursor_visible = context.ensure_cursor_visible;
- if (ensure_cursor_visible)
+ if (context.ensure_cursor_visible)
{
if (cursor.line - offset.line < win_pos.line)
win_pos.line = std::max(0_line, cursor.line - offset.line);
@@ -216,39 +232,11 @@ DisplaySetup Window::compute_display_setup(const Context& context) const
}
win_pos.line = std::min(win_pos.line, buffer().line_count()-1);
- DisplaySetup setup{
- win_pos.line,
- m_dimensions.line,
- win_pos.column,
- 0_col,
- {cursor.line - win_pos.line,
- get_column(buffer(), tabstop, cursor) - win_pos.column},
- offset,
- ensure_cursor_visible
- };
- for (auto pass : { HighlightPass::Move, HighlightPass::Wrap })
+ DisplaySetup setup{win_pos.line, m_dimensions.line, win_pos.column, 0_col, offset};
+ for (auto pass : {HighlightPass::Move, HighlightPass::Wrap, HighlightPass::Replace})
m_builtin_highlighters.compute_display_setup({context, setup, pass, {}}, setup);
check_display_setup(setup, *this);
- // now ensure the cursor column is visible
- if (ensure_cursor_visible)
- {
- auto underflow = std::max(-setup.first_column,
- setup.cursor_pos.column - setup.scroll_offset.column);
- if (underflow < 0)
- {
- setup.first_column += underflow;
- setup.cursor_pos.column -= underflow;
- }
- auto overflow = setup.cursor_pos.column + setup.scroll_offset.column - (m_dimensions.column - setup.widget_columns) + 1;
- if (overflow > 0)
- {
- setup.first_column += overflow;
- setup.cursor_pos.column -= overflow;
- }
- check_display_setup(setup, *this);
- }
-
return setup;
}
diff --git a/test/highlight/wrap/basic/cmd b/test/highlight/wrap/basic/cmd
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/highlight/wrap/basic/cmd
@@ -0,0 +1 @@
+
diff --git a/test/highlight/wrap/basic/in b/test/highlight/wrap/basic/in
new file mode 100644
index 00000000..fb85aeed
--- /dev/null
+++ b/test/highlight/wrap/basic/in
@@ -0,0 +1,2 @@
+--------------------------------------------------------------------------------wrap
+--------------------------------------------------------------------------------wrap----------------------------------------------------------------------------wrap
diff --git a/test/highlight/wrap/basic/rc b/test/highlight/wrap/basic/rc
new file mode 100644
index 00000000..2cd258c4
--- /dev/null
+++ b/test/highlight/wrap/basic/rc
@@ -0,0 +1 @@
+add-highlighter window/ wrap
diff --git a/test/highlight/wrap/basic/script b/test/highlight/wrap/basic/script
new file mode 100644
index 00000000..7151f6a6
--- /dev/null
+++ b/test/highlight/wrap/basic/script
@@ -0,0 +1,4 @@
+ui_out '{ "jsonrpc": "2.0", "method": "set_ui_options", "params": [{}] }'
+ui_out '{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "black", "bg": "white", "underline": "default", "attributes": [] }, "contents": "-" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "-------------------------------------------------------------------------------" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "wrap\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "--------------------------------------------------------------------------------" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "wrap----------------------------------------------------------------------------" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "wrap\u000a" }]], { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }] }'
+ui_out -until '{ "jsonrpc": "2.0", "method": "refresh", "params": [true] }'
+
diff --git a/test/highlight/wrap/interact-with-number-lines/cmd b/test/highlight/wrap/interact-with-number-lines/cmd
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/highlight/wrap/interact-with-number-lines/cmd
@@ -0,0 +1 @@
+
diff --git a/test/highlight/wrap/interact-with-number-lines/in b/test/highlight/wrap/interact-with-number-lines/in
new file mode 100644
index 00000000..7bba8c8e
--- /dev/null
+++ b/test/highlight/wrap/interact-with-number-lines/in
@@ -0,0 +1,2 @@
+line 1
+line 2
diff --git a/test/highlight/wrap/interact-with-number-lines/rc b/test/highlight/wrap/interact-with-number-lines/rc
new file mode 100644
index 00000000..8f447491
--- /dev/null
+++ b/test/highlight/wrap/interact-with-number-lines/rc
@@ -0,0 +1,2 @@
+add-highlighter window/ wrap -word -width 4
+add-highlighter window/ number-lines
diff --git a/test/highlight/wrap/interact-with-number-lines/script b/test/highlight/wrap/interact-with-number-lines/script
new file mode 100644
index 00000000..67e34fea
--- /dev/null
+++ b/test/highlight/wrap/interact-with-number-lines/script
@@ -0,0 +1,3 @@
+ui_out '{ "jsonrpc": "2.0", "method": "set_ui_options", "params": [{}] }'
+ui_out '{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " 1│" }, { "face": { "fg": "black", "bg": "white", "underline": "default", "attributes": [] }, "contents": "l" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "ine" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": ["italic"] }, "contents": " 1" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "│" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " 1\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " 2│" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "line" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": ["italic"] }, "contents": " 2" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "│" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " 2\u000a" }]], { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }] }'
+ui_out -until '{ "jsonrpc": "2.0", "method": "refresh", "params": [true] }'
diff --git a/test/highlight/wrap/interact-with-replace-ranges/cmd b/test/highlight/wrap/interact-with-replace-ranges/cmd
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/highlight/wrap/interact-with-replace-ranges/cmd
@@ -0,0 +1 @@
+
diff --git a/test/highlight/wrap/interact-with-replace-ranges/in b/test/highlight/wrap/interact-with-replace-ranges/in
new file mode 100644
index 00000000..1c17e1bf
--- /dev/null
+++ b/test/highlight/wrap/interact-with-replace-ranges/in
@@ -0,0 +1,3 @@
+------------------------------------------------------------------------- wrap
+-------------------------------------------------------------------------
+prefix replaced wrapped
diff --git a/test/highlight/wrap/interact-with-replace-ranges/rc b/test/highlight/wrap/interact-with-replace-ranges/rc
new file mode 100644
index 00000000..563fc934
--- /dev/null
+++ b/test/highlight/wrap/interact-with-replace-ranges/rc
@@ -0,0 +1,4 @@
+declare-option range-specs ranges %val{timestamp} '1.1+0|HINT:' '2.74+0|WRAPPED HINT' '3.8+8|OVERFLOWING HINT XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
+
+add-highlighter window/ wrap -word
+add-highlighter window/ replace-ranges ranges
diff --git a/test/highlight/wrap/interact-with-replace-ranges/script b/test/highlight/wrap/interact-with-replace-ranges/script
new file mode 100644
index 00000000..6511f11c
--- /dev/null
+++ b/test/highlight/wrap/interact-with-replace-ranges/script
@@ -0,0 +1,3 @@
+ui_out '{ "jsonrpc": "2.0", "method": "set_ui_options", "params": [{}] }'
+ui_out '{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "HINT:" }, { "face": { "fg": "black", "bg": "white", "underline": "default", "attributes": [] }, "contents": "-" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "------------------------------------------------------------------------ " }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "wrap\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "-------------------------------------------------------------------------" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "WRAPPED HINT" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "prefix " }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "OVERFLOWING HINT XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " wrapped\u000a" }]], { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }] }'
+ui_out -until '{ "jsonrpc": "2.0", "method": "refresh", "params": [true] }'
diff --git a/test/highlight/wrap/interact-with-tabulation/cmd b/test/highlight/wrap/interact-with-tabulation/cmd
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/highlight/wrap/interact-with-tabulation/cmd
@@ -0,0 +1 @@
+
diff --git a/test/highlight/wrap/interact-with-tabulation/in b/test/highlight/wrap/interact-with-tabulation/in
new file mode 100644
index 00000000..9077d5dc
--- /dev/null
+++ b/test/highlight/wrap/interact-with-tabulation/in
@@ -0,0 +1 @@
+----------------------------------------------------------------------------
diff --git a/test/highlight/wrap/interact-with-tabulation/rc b/test/highlight/wrap/interact-with-tabulation/rc
new file mode 100644
index 00000000..784f691c
--- /dev/null
+++ b/test/highlight/wrap/interact-with-tabulation/rc
@@ -0,0 +1,2 @@
+add-highlighter window/ number-lines
+add-highlighter window/ wrap
diff --git a/test/highlight/wrap/interact-with-tabulation/script b/test/highlight/wrap/interact-with-tabulation/script
new file mode 100644
index 00000000..4961bd6c
--- /dev/null
+++ b/test/highlight/wrap/interact-with-tabulation/script
@@ -0,0 +1,4 @@
+ui_out '{ "jsonrpc": "2.0", "method": "set_ui_options", "params": [{}] }'
+ui_out '{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " 1│" }, { "face": { "fg": "black", "bg": "white", "underline": "default", "attributes": [] }, "contents": "-" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "---------------------------------------------------------------------------" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": ["italic"] }, "contents": " 1" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "│" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "\u000a" }]], { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }] }'
+ui_out -until '{ "jsonrpc": "2.0", "method": "refresh", "params": [true] }'
+
diff --git a/test/highlight/wrap/marker-and-indent/cmd b/test/highlight/wrap/marker-and-indent/cmd
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/highlight/wrap/marker-and-indent/cmd
@@ -0,0 +1 @@
+
diff --git a/test/highlight/wrap/marker-and-indent/in b/test/highlight/wrap/marker-and-indent/in
new file mode 100644
index 00000000..37962f9e
--- /dev/null
+++ b/test/highlight/wrap/marker-and-indent/in
@@ -0,0 +1,4 @@
+--------------------------------------------------------------------------------wrap
+--------------------------------------------------------------------------------wrap-------------------------------------------------------------------------wrap
+ ----------------------------------------------------------------------------wrap
+ ----------------------------------------------------------------------------wrap------------------------------------------------------------------------wrap
diff --git a/test/highlight/wrap/marker-and-indent/rc b/test/highlight/wrap/marker-and-indent/rc
new file mode 100644
index 00000000..3ac2bf1e
--- /dev/null
+++ b/test/highlight/wrap/marker-and-indent/rc
@@ -0,0 +1 @@
+add-highlighter window/ wrap -marker '>>>' -indent
diff --git a/test/highlight/wrap/marker-and-indent/script b/test/highlight/wrap/marker-and-indent/script
new file mode 100644
index 00000000..72861f73
--- /dev/null
+++ b/test/highlight/wrap/marker-and-indent/script
@@ -0,0 +1,4 @@
+ui_out '{ "jsonrpc": "2.0", "method": "set_ui_options", "params": [{}] }'
+ui_out '{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "black", "bg": "white", "underline": "default", "attributes": [] }, "contents": "-" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "-------------------------------------------------------------------------------" }], [{ "face": { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }, "contents": ">>>" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "wrap\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "--------------------------------------------------------------------------------" }], [{ "face": { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }, "contents": ">>>" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "wrap-------------------------------------------------------------------------" }], [{ "face": { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }, "contents": ">>>" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "wrap\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " ----------------------------------------------------------------------------" }], [{ "face": { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }, "contents": ">>>" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "wrap\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " ----------------------------------------------------------------------------" }], [{ "face": { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }, "contents": ">>>" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "wrap------------------------------------------------------------------------" }], [{ "face": { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }, "contents": ">>>" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "wrap\u000a" }]], { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }] }'
+ui_out -until '{ "jsonrpc": "2.0", "method": "refresh", "params": [true] }'
+
diff --git a/test/normal/pipe-replaces-all-lines/cmd b/test/normal/pipe-replaces-all-lines/cmd
new file mode 100644
index 00000000..fb90dc1a
--- /dev/null
+++ b/test/normal/pipe-replaces-all-lines/cmd
@@ -0,0 +1 @@
+%|printf '\n\n'<ret>
diff --git a/test/normal/pipe-replaces-all-lines/in b/test/normal/pipe-replaces-all-lines/in
new file mode 100644
index 00000000..422c2b7a
--- /dev/null
+++ b/test/normal/pipe-replaces-all-lines/in
@@ -0,0 +1,2 @@
+a
+b
diff --git a/test/normal/pipe-replaces-all-lines/out b/test/normal/pipe-replaces-all-lines/out
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/test/normal/pipe-replaces-all-lines/out
@@ -0,0 +1,2 @@
+
+
diff --git a/test/regression/0-slow-BufCloseFifo/cmd b/test/regression/0-slow-BufCloseFifo/cmd
new file mode 100644
index 00000000..2eeea72e
--- /dev/null
+++ b/test/regression/0-slow-BufCloseFifo/cmd
@@ -0,0 +1 @@
+:run<ret>
diff --git a/test/regression/0-slow-BufCloseFifo/in b/test/regression/0-slow-BufCloseFifo/in
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/regression/0-slow-BufCloseFifo/in
@@ -0,0 +1 @@
+
diff --git a/test/regression/0-slow-BufCloseFifo/rc b/test/regression/0-slow-BufCloseFifo/rc
new file mode 100644
index 00000000..8a953e18
--- /dev/null
+++ b/test/regression/0-slow-BufCloseFifo/rc
@@ -0,0 +1,16 @@
+define-command run %{
+ evaluate-commands %sh{
+ mkfifo fifo1 fifo2 2>/dev/null
+ ( : >fifo1 & ) > /dev/null 2>&1 </dev/null
+ }
+ edit! -fifo fifo1 *fifo*
+ add-highlighter global/myhl regex foo 0:green
+ hook -once global BufCloseFifo .* %{
+ evaluate-commands -client client0 %{
+ nop %sh{sleep 2}
+ }
+ hook -once buffer NormalIdle .* %{
+ echo -to-file fifo2 still alive
+ }
+ }
+}
diff --git a/test/regression/0-slow-BufCloseFifo/script b/test/regression/0-slow-BufCloseFifo/script
new file mode 100644
index 00000000..2147a8e8
--- /dev/null
+++ b/test/regression/0-slow-BufCloseFifo/script
@@ -0,0 +1,2 @@
+mkfifo fifo2 2>/dev/null
+assert_eq "$(cat fifo2)" "still alive"
diff --git a/test/regression/2999-buggy-wrapping/cmd b/test/regression/2999-buggy-wrapping/cmd
index 4c559f78..5238dfce 100644
--- a/test/regression/2999-buggy-wrapping/cmd
+++ b/test/regression/2999-buggy-wrapping/cmd
@@ -1 +1 @@
-j
+jvt
diff --git a/test/regression/5338-crash-when-changing-buffer-on-WinDiplay/cmd b/test/regression/5338-crash-when-changing-buffer-on-WinDiplay/cmd
new file mode 100644
index 00000000..a1a5692c
--- /dev/null
+++ b/test/regression/5338-crash-when-changing-buffer-on-WinDiplay/cmd
@@ -0,0 +1 @@
+:e -scratch<ret><c-o>
diff --git a/test/regression/5338-crash-when-changing-buffer-on-WinDiplay/in b/test/regression/5338-crash-when-changing-buffer-on-WinDiplay/in
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/regression/5338-crash-when-changing-buffer-on-WinDiplay/in
@@ -0,0 +1 @@
+
diff --git a/test/regression/5338-crash-when-changing-buffer-on-WinDiplay/rc b/test/regression/5338-crash-when-changing-buffer-on-WinDiplay/rc
new file mode 100644
index 00000000..6240a36f
--- /dev/null
+++ b/test/regression/5338-crash-when-changing-buffer-on-WinDiplay/rc
@@ -0,0 +1 @@
+hook global WinDisplay .* %{ edit out }
diff --git a/test/run b/test/run
index 8ce73f2a..670f6858 100755
--- a/test/run
+++ b/test/run
@@ -136,7 +136,7 @@ fail_ifn() {
fi
}
-check_json_eq() {
+assert_eq() {
if [ ! "$1" = "$2" ]; then
fail_ifn
if command -v git > /dev/null; then
@@ -204,13 +204,13 @@ ui_out() {
[ "$event" = "$expected" ] && break
done
;;
- -until-eval | -until-grep)
+ -until-grep)
pattern=$1
shift
while read -r event <&4; do
- if printf %s "$event" | "${arg#-until-}" "$pattern" >/dev/null; then
+ if printf %s "$event" | grep "$pattern" >/dev/null; then
if [ $# -ne 0 ]; then
- check_json_eq "$1" "$event"
+ assert_eq "$1" "$event"
shift
fi
break
@@ -219,7 +219,7 @@ ui_out() {
;;
*)
read -r event <&4
- check_json_eq "$arg" "$event"
+ assert_eq "$arg" "$event"
;;
esac
}
diff --git a/test/tools/git/blame-in-diff/rc b/test/tools/git/blame-in-diff/rc
index eba02270..1fc54f3f 100644
--- a/test/tools/git/blame-in-diff/rc
+++ b/test/tools/git/blame-in-diff/rc
@@ -11,4 +11,19 @@ define-command run %{
git commit --all --message 'changed line 2'
# Show the commit, jumping to the new version of line 2.
git blame-jump
+ hook -once buffer BufCloseFifo .* %{
+ evaluate-commands -client client0 %{
+ # We've jumped to the new version of line 2. Move to the old
+ # version so we can annotate the old version of the file.
+ execute-keys k
+ git blame
+ hook -once buffer BufCloseFifo .* %{
+ execute-keys -client client0 x
+ # Wait for a redraw before reporting completion.
+ hook -once buffer NormalIdle .* %{
+ echo -to-file fifo
+ }
+ }
+ }
+ }
}
diff --git a/test/tools/git/blame-in-diff/script b/test/tools/git/blame-in-diff/script
index 0cee0ca7..4c371348 100644
--- a/test/tools/git/blame-in-diff/script
+++ b/test/tools/git/blame-in-diff/script
@@ -1,10 +1,3 @@
-ui_out -until '{ "jsonrpc": "2.0", "method": "refresh", "params": [false] }'
-
-# We've jumped to the new version of line 2. Move to the old version so we
-# can annotate the old file.
-ui_in '{ "jsonrpc": "2.0", "method": "keys", "params": [ "k:git blame<ret>" ] }'
-ui_out -until-eval 'grep "draw_status" | grep -v "\[fifo\]"'
-
+mkfifo fifo 2>/dev/null
+cat fifo
# We should have jumped to the old version of line 2, assert on kak_selection.
-ui_in '{ "jsonrpc": "2.0", "method": "keys", "params": [ "x" ] }'
-ui_out -until '{ "jsonrpc": "2.0", "method": "refresh", "params": [false] }'