summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2023-08-12 13:40:55 +1000
committerMaxime Coste <mawww@kakoune.org>2023-08-16 21:02:42 +1000
commit1e38045d702ec6eb2425016d9b02636270ab1b1e (patch)
tree0298a655119e5d87d9650d5aadc0f1fc76ffcbfd
parent6942a4c0c9428a9e2ddb65de3969d2dcb5c5eb2f (diff)
Only make cursor visible after buffer or selection change
Kakoune now does not touch cursors when scrolling. It checks if either the buffer or selections has been modified since last redraw. Fixes #4124 Fixes #2844
-rw-r--r--src/context.hh24
-rw-r--r--src/highlighter.hh1
-rw-r--r--src/highlighters.cc6
-rw-r--r--src/input_handler.cc30
-rw-r--r--src/normal.cc2
-rw-r--r--src/window.cc57
-rw-r--r--src/window.hh6
-rw-r--r--test/regression/3219-scroll-json-ui/script4
-rw-r--r--test/regression/4839-scroll-invalid-cursor/cmd2
-rw-r--r--test/regression/4839-scroll-invalid-cursor/script4
10 files changed, 81 insertions, 55 deletions
diff --git a/src/context.hh b/src/context.hh
index 69377148..119e4495 100644
--- a/src/context.hh
+++ b/src/context.hh
@@ -144,6 +144,7 @@ public:
void repeat_last_select() { if (m_last_select) m_last_select(*this); }
Buffer* last_buffer() const;
+
private:
void begin_edition();
void end_edition();
@@ -215,9 +216,16 @@ struct ScopedEdition
ScopedEdition(Context& context)
: m_context{context},
m_buffer{context.has_buffer() ? &context.buffer() : nullptr}
- { if (m_buffer) m_context.begin_edition(); }
+ {
+ if (m_buffer)
+ m_context.begin_edition();
+ }
- ~ScopedEdition() { if (m_buffer) m_context.end_edition(); }
+ ~ScopedEdition()
+ {
+ if (m_buffer)
+ m_context.end_edition();
+ }
Context& context() const { return m_context; }
private:
@@ -230,11 +238,19 @@ struct ScopedSelectionEdition
ScopedSelectionEdition(Context& context)
: m_context{context},
m_buffer{not (m_context.flags() & Context::Flags::Draft) and context.has_buffer() ? &context.buffer() : nullptr}
- { if (m_buffer) m_context.m_selection_history.begin_edition(); }
+ {
+ if (m_buffer)
+ m_context.m_selection_history.begin_edition();
+ }
+
ScopedSelectionEdition(ScopedSelectionEdition&& other) : m_context{other.m_context}, m_buffer{other.m_buffer}
{ other.m_buffer = nullptr; }
- ~ScopedSelectionEdition() { if (m_buffer) m_context.m_selection_history.end_edition(); }
+ ~ScopedSelectionEdition()
+ {
+ if (m_buffer)
+ m_context.m_selection_history.end_edition();
+ }
private:
Context& m_context;
SafePtr<Buffer> m_buffer;
diff --git a/src/highlighter.hh b/src/highlighter.hh
index ad94f44d..925dcaa7 100644
--- a/src/highlighter.hh
+++ b/src/highlighter.hh
@@ -46,6 +46,7 @@ struct DisplaySetup
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 65f801cb..156b4b2c 100644
--- a/src/highlighters.cc
+++ b/src/highlighters.cc
@@ -752,7 +752,8 @@ struct WrapHighlighter : Highlighter
win_line += wrap_count + 1;
// scroll window to keep cursor visible, and update range as lines gets removed
- while (buf_line >= cursor.line and setup.first_line < cursor.line and
+ 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);
@@ -1660,7 +1661,8 @@ private:
setup.cursor_pos.column += cursor_move;
}
- if (last.line >= setup.first_line and
+ if (setup.ensure_cursor_visible and
+ 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/input_handler.cc b/src/input_handler.cc
index 66d30391..ef45e149 100644
--- a/src/input_handler.cc
+++ b/src/input_handler.cc
@@ -1870,25 +1870,27 @@ void scroll_window(Context& context, LineCount offset, bool mouse_dragging)
win_pos.line = clamp(win_pos.line + offset, 0_line, line_count-1);
- ScopedSelectionEdition selection_edition{context};
- SelectionList& selections = context.selections();
- Selection& main_selection = selections.main();
- const BufferCoord anchor = main_selection.anchor();
- const BufferCoordAndTarget cursor = main_selection.cursor();
+ window.set_position(win_pos);
+ if (mouse_dragging)
+ {
+ ScopedSelectionEdition selection_edition{context};
+ SelectionList& selections = context.selections();
+ Selection& main_selection = selections.main();
+ const BufferCoord anchor = main_selection.anchor();
+ const BufferCoordAndTarget cursor = main_selection.cursor();
- auto cursor_off = mouse_dragging ? win_pos.line - window.position().line : 0;
+ auto cursor_off = win_pos.line - window.position().line;
- auto line = clamp(cursor.line + cursor_off, win_pos.line + scrolloff.line,
- win_pos.line + win_dim.line - 1 - scrolloff.line);
+ auto line = clamp(cursor.line + cursor_off, win_pos.line + scrolloff.line,
+ win_pos.line + win_dim.line - 1 - scrolloff.line);
- const ColumnCount tabstop = context.options()["tabstop"].get<int>();
- auto new_cursor = buffer.offset_coord(cursor, line - cursor.line, tabstop);
- BufferCoord new_anchor = (mouse_dragging or new_cursor == cursor) ? anchor : new_cursor;
+ const ColumnCount tabstop = context.options()["tabstop"].get<int>();
+ auto new_cursor = buffer.offset_coord(cursor, line - cursor.line, tabstop);
- window.set_position(win_pos);
- main_selection = { new_anchor, new_cursor };
+ main_selection = { anchor, new_cursor };
- selections.sort_and_merge_overlapping();
+ selections.sort_and_merge_overlapping();
+ }
}
}
diff --git a/src/normal.cc b/src/normal.cc
index b16b9c37..8b26b1ff 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -848,7 +848,7 @@ void regex_prompt(Context& context, String prompt, char reg, T func)
{
selections.update();
context.selections_write_only() = selections;
- if (context.has_window())
+ if (context.has_window() and event != PromptEvent::Validate)
context.window().set_position(position);
context.input_handler().set_prompt_face(context.faces()["Prompt"]);
diff --git a/src/window.cc b/src/window.cc
index 2a0469cf..b5d1db40 100644
--- a/src/window.cc
+++ b/src/window.cc
@@ -85,37 +85,34 @@ static uint32_t compute_faces_hash(const FaceRegistry& faces)
Window::Setup Window::build_setup(const Context& context) const
{
- Vector<BufferRange, MemoryDomain::Display> selections;
- for (auto& sel : context.selections())
- selections.push_back({sel.cursor(), sel.anchor()});
-
- return { m_position, m_dimensions,
- context.buffer().timestamp(),
- compute_faces_hash(context.faces()),
- context.selections().main_index(),
- std::move(selections) };
+ return {m_position, m_dimensions,
+ context.buffer().timestamp(),
+ compute_faces_hash(context.faces()),
+ context.selections().main_index(),
+ context.selections() | gather<Vector<BasicSelection, MemoryDomain::Display>>()};
}
bool Window::needs_redraw(const Context& context) const
{
auto& selections = context.selections();
-
- if (m_position != m_last_setup.position or
+ return m_position != m_last_setup.position or
m_dimensions != m_last_setup.dimensions or
context.buffer().timestamp() != m_last_setup.timestamp or
selections.main_index() != m_last_setup.main_selection or
selections.size() != m_last_setup.selections.size() or
- compute_faces_hash(context.faces()) != m_last_setup.faces_hash)
- return true;
-
- for (int i = 0; i < selections.size(); ++i)
- {
- if (selections[i].cursor() != m_last_setup.selections[i].begin or
- selections[i].anchor() != m_last_setup.selections[i].end)
- return true;
- }
+ compute_faces_hash(context.faces()) != m_last_setup.faces_hash or
+ not std::equal(selections.begin(), selections.end(),
+ m_last_setup.selections.begin(), m_last_setup.selections.end());
+}
- return false;
+bool Window::should_make_cursor_visible(const Context& context) const
+{
+ auto& selections = context.selections();
+ return context.buffer().timestamp() != m_last_setup.timestamp or
+ selections.main_index() != m_last_setup.main_selection or
+ selections.size() != m_last_setup.selections.size() or
+ not std::equal(selections.begin(), selections.end(),
+ m_last_setup.selections.begin(), m_last_setup.selections.end());
}
const DisplayBuffer& Window::update_display_buffer(const Context& context)
@@ -215,11 +212,15 @@ DisplaySetup Window::compute_display_setup(const Context& context) const
const int tabstop = context.options()["tabstop"].get<int>();
const auto& cursor = context.selections().main().cursor();
- // Ensure cursor line is visible
- if (cursor.line - offset.line < win_pos.line)
- win_pos.line = std::max(0_line, cursor.line - offset.line);
- if (cursor.line + offset.line >= win_pos.line + m_dimensions.line)
- win_pos.line = std::min(buffer().line_count()-1, cursor.line + offset.line - m_dimensions.line + 1);
+ bool ensure_cursor_visible = should_make_cursor_visible(context);
+
+ if (ensure_cursor_visible)
+ {
+ if (cursor.line - offset.line < win_pos.line)
+ win_pos.line = std::max(0_line, cursor.line - offset.line);
+ if (cursor.line + offset.line >= win_pos.line + m_dimensions.line)
+ win_pos.line = std::min(buffer().line_count()-1, cursor.line + offset.line - m_dimensions.line + 1);
+ }
DisplaySetup setup{
win_pos.line,
@@ -228,13 +229,15 @@ DisplaySetup Window::compute_display_setup(const Context& context) const
0_col,
{cursor.line - win_pos.line,
get_column(buffer(), tabstop, cursor) - win_pos.column},
- offset
+ offset,
+ ensure_cursor_visible
};
for (auto pass : { HighlightPass::Move, HighlightPass::Wrap })
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);
diff --git a/src/window.hh b/src/window.hh
index dd7a325b..4a6a5e47 100644
--- a/src/window.hh
+++ b/src/window.hh
@@ -43,7 +43,7 @@ public:
Buffer& buffer() const { return *m_buffer; }
bool needs_redraw(const Context& context) const;
- void force_redraw() { m_last_setup = Setup{}; }
+ void force_redraw() { m_last_setup.dimensions = {}; }
void set_client(Client* client) { m_client = client; }
@@ -60,6 +60,8 @@ private:
void run_hook_in_own_context(Hook hook, StringView param,
String client_name = "");
+ bool should_make_cursor_visible(const Context& context) const;
+
SafePtr<Buffer> m_buffer;
SafePtr<Client> m_client;
@@ -77,7 +79,7 @@ private:
size_t timestamp;
size_t faces_hash;
size_t main_selection;
- Vector<BufferRange, MemoryDomain::Display> selections;
+ Vector<BasicSelection, MemoryDomain::Display> selections;
};
Setup build_setup(const Context& context) const;
Setup m_last_setup;
diff --git a/test/regression/3219-scroll-json-ui/script b/test/regression/3219-scroll-json-ui/script
index 0cfd5b58..2ba5f829 100644
--- a/test/regression/3219-scroll-json-ui/script
+++ b/test/regression/3219-scroll-json-ui/script
@@ -6,8 +6,8 @@ ui_out '{ "jsonrpc": "2.0", "method": "draw_status", "params": [[], [{ "face": {
ui_out '{ "jsonrpc": "2.0", "method": "set_cursor", "params": ["buffer", { "line": 0, "column": 0 }] }'
ui_out '{ "jsonrpc": "2.0", "method": "refresh", "params": [true] }'
ui_in '{ "jsonrpc": "2.0", "method": "scroll", "params": [ 2 ] }'
-ui_out '{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "black", "bg": "white", "underline": "default", "attributes": [] }, "contents": "0" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "3\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "04\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "05\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "06\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "07\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "08\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "09\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "10\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "11\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "12\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "13\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "14\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "15\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "16\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "17\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "18\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "19\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "20\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "21\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "22\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "23\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "24\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "25\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "26\u000a" }]], { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }] }'
+ui_out '{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "03\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "04\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "05\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "06\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "07\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "08\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "09\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "10\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "11\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "12\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "13\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "14\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "15\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "16\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "17\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "18\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "19\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "20\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "21\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "22\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "23\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "24\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "25\u000a" }], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "26\u000a" }]], { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }] }'
ui_out '{ "jsonrpc": "2.0", "method": "info_hide", "params": [] }'
-ui_out '{ "jsonrpc": "2.0", "method": "draw_status", "params": [[], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "out 3:1 " }, { "face": { "fg": "black", "bg": "yellow", "underline": "default", "attributes": [] }, "contents": "" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }, "contents": "1 sel" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " - client0@[kak-tests]" }], { "fg": "cyan", "bg": "default", "underline": "default", "attributes": [] }] }'
+ui_out '{ "jsonrpc": "2.0", "method": "draw_status", "params": [[], [{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "out 1:1 " }, { "face": { "fg": "black", "bg": "yellow", "underline": "default", "attributes": [] }, "contents": "" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }, "contents": "1 sel" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " - client0@[kak-tests]" }], { "fg": "cyan", "bg": "default", "underline": "default", "attributes": [] }] }'
ui_out '{ "jsonrpc": "2.0", "method": "set_cursor", "params": ["buffer", { "line": 0, "column": 0 }] }'
ui_out '{ "jsonrpc": "2.0", "method": "refresh", "params": [false] }'
diff --git a/test/regression/4839-scroll-invalid-cursor/cmd b/test/regression/4839-scroll-invalid-cursor/cmd
index ec0f73a0..10ba8aba 100644
--- a/test/regression/4839-scroll-invalid-cursor/cmd
+++ b/test/regression/4839-scroll-invalid-cursor/cmd
@@ -1 +1 @@
-l<pagedown>
+l<c-l><pagedown>
diff --git a/test/regression/4839-scroll-invalid-cursor/script b/test/regression/4839-scroll-invalid-cursor/script
index 03227629..31d58187 100644
--- a/test/regression/4839-scroll-invalid-cursor/script
+++ b/test/regression/4839-scroll-invalid-cursor/script
@@ -1,2 +1,2 @@
-ui_out -ignore 1
-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": "\u000a" }]], { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }] }'
+ui_out -ignore 7
+ui_out '{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "😃\u000a" }]], { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "underline": "default", "attributes": [] }] }'