summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYukai Huang <yukaihuangtw@gmail.com>2025-06-27 23:11:23 +0800
committerGitHub <noreply@github.com>2025-06-27 23:11:23 +0800
commit38a7a49ae85789f3b2aaaf7e263d6eabdccdf046 (patch)
tree27a9ea5ed53be4c049c5177010cc889cdb4cbcb1 /src
parent58414edb7b9b3d4cfde27a37ebec7f3906025675 (diff)
parentb3c3baef518d65f30a34b06764c6529b8247b837 (diff)
Merge branch 'master' into feature/native-cursor
Diffstat (limited to 'src')
-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
9 files changed, 130 insertions, 244 deletions
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;
}