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
This commit is contained in:
parent
6942a4c0c9
commit
1e38045d70
|
@ -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;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
||||
auto cursor_off = mouse_dragging ? win_pos.line - window.position().line : 0;
|
||||
|
||||
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;
|
||||
|
||||
window.set_position(win_pos);
|
||||
main_selection = { new_anchor, new_cursor };
|
||||
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();
|
||||
|
||||
selections.sort_and_merge_overlapping();
|
||||
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);
|
||||
|
||||
const ColumnCount tabstop = context.options()["tabstop"].get<int>();
|
||||
auto new_cursor = buffer.offset_coord(cursor, line - cursor.line, tabstop);
|
||||
|
||||
main_selection = { anchor, new_cursor };
|
||||
|
||||
selections.sort_and_merge_overlapping();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"]);
|
||||
|
|
|
@ -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;
|
||||
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());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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] }'
|
||||
|
|
|
@ -1 +1 @@
|
|||
l<pagedown>
|
||||
l<c-l><pagedown>
|
||||
|
|
|
@ -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": [] }] }'
|
||||
|
|
Loading…
Reference in New Issue
Block a user