aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2019-02-02 21:27:09 +0100
committerGitHub <noreply@github.com>2019-02-02 21:27:09 +0100
commit79a0ea2bec7c4a1c82990c07c87098b87bc2a1da (patch)
treeffdf0820ab0b70622d58d40936ac6f0d9e2658fd /src
parentf89d0d8230f34dca49eddbea179d274955b572b9 (diff)
parent0f96a21e3fd6ba989e27a992e48c084dd02d8885 (diff)
downloadrneovim-79a0ea2bec7c4a1c82990c07c87098b87bc2a1da.tar.gz
rneovim-79a0ea2bec7c4a1c82990c07c87098b87bc2a1da.tar.bz2
rneovim-79a0ea2bec7c4a1c82990c07c87098b87bc2a1da.zip
Merge pull request #9530 from bfredl/pum_float
Implement popupmenu as a floating grid internally to reduce flicker
Diffstat (limited to 'src')
-rw-r--r--src/nvim/CMakeLists.txt3
-rw-r--r--src/nvim/api/ui.c4
-rw-r--r--src/nvim/api/ui_events.in.h26
-rw-r--r--src/nvim/edit.c50
-rw-r--r--src/nvim/ex_getln.c8
-rw-r--r--src/nvim/generators/c_grammar.lua2
-rw-r--r--src/nvim/generators/gen_api_ui_events.lua30
-rw-r--r--src/nvim/globals.h15
-rw-r--r--src/nvim/grid_defs.h11
-rw-r--r--src/nvim/highlight.c3
-rw-r--r--src/nvim/main.c1
-rw-r--r--src/nvim/memline.c4
-rw-r--r--src/nvim/message.c3
-rw-r--r--src/nvim/os_unix.c2
-rw-r--r--src/nvim/popupmnu.c104
-rw-r--r--src/nvim/screen.c100
-rw-r--r--src/nvim/tui/tui.c5
-rw-r--r--src/nvim/ui.c89
-rw-r--r--src/nvim/ui.h16
-rw-r--r--src/nvim/ui_bridge.c6
-rw-r--r--src/nvim/ui_compositor.c411
-rw-r--r--src/nvim/ui_compositor.h12
22 files changed, 710 insertions, 195 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 928d473b04..8abc43c2aa 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -23,6 +23,7 @@ set(GENERATOR_DIR ${CMAKE_CURRENT_LIST_DIR}/generators)
set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/nvim/auto)
set(API_DISPATCH_GENERATOR ${GENERATOR_DIR}/gen_api_dispatch.lua)
set(API_UI_EVENTS_GENERATOR ${GENERATOR_DIR}/gen_api_ui_events.lua)
+set(GENERATOR_C_GRAMMAR ${GENERATOR_DIR}/c_grammar.lua)
set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack)
set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack)
set(MSGPACK_LUA_C_BINDINGS ${GENERATED_DIR}/msgpack_lua_c_bindings.generated.c)
@@ -269,6 +270,7 @@ add_custom_command(
${API_HEADERS}
${MSGPACK_RPC_HEADERS}
${API_DISPATCH_GENERATOR}
+ ${GENERATOR_C_GRAMMAR}
${CMAKE_CURRENT_LIST_DIR}/api/dispatch_deprecated.lua
)
@@ -300,6 +302,7 @@ add_custom_command(
${GENERATED_UI_EVENTS_METADATA}
DEPENDS
${API_UI_EVENTS_GENERATOR}
+ ${GENERATOR_C_GRAMMAR}
${CMAKE_CURRENT_LIST_DIR}/api/ui_events.in.h
)
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index bc8a1a941f..b77516d588 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -113,6 +113,8 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->set_title = remote_ui_set_title;
ui->set_icon = remote_ui_set_icon;
ui->option_set = remote_ui_option_set;
+ ui->win_scroll_over_start = remote_ui_win_scroll_over_start;
+ ui->win_scroll_over_reset = remote_ui_win_scroll_over_reset;
ui->event = remote_ui_event;
ui->inspect = remote_ui_inspect;
@@ -459,7 +461,7 @@ static void remote_ui_put(UI *ui, const char *cell)
static void remote_ui_raw_line(UI *ui, Integer grid, Integer row,
Integer startcol, Integer endcol,
Integer clearcol, Integer clearattr,
- Boolean wrap, const schar_T *chunk,
+ LineFlags flags, const schar_T *chunk,
const sattr_T *attrs)
{
UIData *data = ui->data;
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 59a7780651..ef3ff0f4c2 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -38,6 +38,9 @@ void set_icon(String icon)
FUNC_API_SINCE(3);
void option_set(String name, Object value)
FUNC_API_SINCE(4) FUNC_API_BRIDGE_IMPL;
+// Stop event is not exported as such, represented by EOF in the msgpack stream.
+void stop(void)
+ FUNC_API_NOEXPORT;
// First revison of the grid protocol, used by default
void update_fg(Integer fg)
@@ -71,28 +74,39 @@ void hl_attr_define(Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs,
Array info)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL;
void grid_resize(Integer grid, Integer width, Integer height)
- FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL;
+ FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL;
void grid_clear(Integer grid)
- FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL;
+ FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL;
void grid_cursor_goto(Integer grid, Integer row, Integer col)
- FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL;
+ FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL;
void grid_line(Integer grid, Integer row, Integer col_start, Array data)
FUNC_API_SINCE(5) FUNC_API_REMOTE_ONLY;
void grid_scroll(Integer grid, Integer top, Integer bot,
Integer left, Integer right, Integer rows, Integer cols)
- FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL;
+ FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL;
void grid_destroy(Integer grid)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
+// For perfomance and simplicity, we use the dense screen representation
+// in internal code, such as compositor and TUI. The remote_ui module will
+// translate this in to the public grid_line format.
+void raw_line(Integer grid, Integer row, Integer startcol,
+ Integer endcol, Integer clearcol, Integer clearattr,
+ LineFlags flags, const schar_T *chunk, const sattr_T *attrs)
+ FUNC_API_NOEXPORT FUNC_API_COMPOSITOR_IMPL;
+
+void event(char *name, Array args, bool *args_consumed)
+ FUNC_API_NOEXPORT;
+
void win_pos(Integer grid, Integer win, Integer startrow,
Integer startcol, Integer width, Integer height)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
void win_hide(Integer grid)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
void win_scroll_over_start(void)
- FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
+ FUNC_API_SINCE(6) FUNC_API_BRIDGE_IMPL FUNC_API_COMPOSITOR_IMPL;
void win_scroll_over_reset(void)
- FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
+ FUNC_API_SINCE(6) FUNC_API_BRIDGE_IMPL FUNC_API_COMPOSITOR_IMPL;
void popupmenu_show(Array items, Integer selected,
Integer row, Integer col, Integer grid)
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index bb16e2ae4d..a63dd97ba8 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -473,6 +473,8 @@ static void insert_enter(InsertState *s)
o_lnum = curwin->w_cursor.lnum;
}
+ pum_check_clear();
+
foldUpdateAfterInsert();
// When CTRL-C was typed got_int will be set, with the result
// that the autocommands won't be executed. When mapped got_int
@@ -1447,6 +1449,7 @@ ins_redraw (
redrawWinline(curwin, curwin->w_cursor.lnum);
}
+ pum_check_clear();
if (must_redraw) {
update_screen(0);
} else if (clear_cmdline || redraw_cmdline) {
@@ -2490,20 +2493,10 @@ void set_completion(colnr_T startcol, list_T *list)
static pumitem_T *compl_match_array = NULL;
static int compl_match_arraysize;
+
/*
* Update the screen and when there is any scrolling remove the popup menu.
*/
-static void ins_compl_upd_pum(void)
-{
- int h;
-
- if (compl_match_array != NULL) {
- h = curwin->w_cline_height;
- update_screen(0);
- if (h != curwin->w_cline_height)
- ins_compl_del_pum();
- }
-}
/*
* Remove any popup menu.
@@ -2511,7 +2504,7 @@ static void ins_compl_upd_pum(void)
static void ins_compl_del_pum(void)
{
if (compl_match_array != NULL) {
- pum_undisplay();
+ pum_undisplay(false);
xfree(compl_match_array);
compl_match_array = NULL;
}
@@ -4305,17 +4298,14 @@ ins_compl_next (
}
if (!allow_get_expansion) {
- /* may undisplay the popup menu first */
- ins_compl_upd_pum();
-
- /* redraw to show the user what was inserted */
+ // redraw to show the user what was inserted
update_screen(0);
- /* display the updated popup menu */
+ // display the updated popup menu
ins_compl_show_pum();
- /* Delete old text to be replaced, since we're still searching and
- * don't want to match ourselves! */
+ // Delete old text to be replaced, since we're still searching and
+ // don't want to match ourselves!
ins_compl_delete();
}
@@ -4862,8 +4852,6 @@ static int ins_complete(int c, bool enable_pum)
save_w_leftcol = curwin->w_leftcol;
n = ins_compl_next(true, ins_compl_key2count(c), insert_match, false);
- /* may undisplay the popup menu */
- ins_compl_upd_pum();
if (n > 1) /* all matches have been found */
compl_matches = n;
@@ -7144,11 +7132,17 @@ static void ins_reg(void)
* message for it. Only call it explicitly. */
++no_u_sync;
if (regname == '=') {
- /* Sync undo when evaluating the expression calls setline() or
- * append(), so that it can be undone separately. */
+ pos_T curpos = curwin->w_cursor;
+
+ // Sync undo when evaluating the expression calls setline() or
+ // append(), so that it can be undone separately.
u_sync_once = 2;
regname = get_expr_register();
+
+ // Cursor may be moved back a column.
+ curwin->w_cursor = curpos;
+ check_cursor();
}
if (regname == NUL || !valid_yank_reg(regname, false)) {
vim_beep(BO_REG);
@@ -7939,7 +7933,6 @@ static void ins_mouse(int c)
static void ins_mousescroll(int dir)
{
win_T *const old_curwin = curwin;
- bool did_scroll = false;
pos_T tpos = curwin->w_cursor;
if (mouse_row >= 0 && mouse_col >= 0) {
@@ -7969,7 +7962,6 @@ static void ins_mousescroll(int dir)
} else {
mouse_scroll_horiz(dir);
}
- did_scroll = true;
}
curwin->w_redr_status = TRUE;
@@ -7977,14 +7969,6 @@ static void ins_mousescroll(int dir)
curwin = old_curwin;
curbuf = curwin->w_buffer;
- /* The popup menu may overlay the window, need to redraw it.
- * TODO: Would be more efficient to only redraw the windows that are
- * overlapped by the popup menu. */
- if (pum_visible() && did_scroll) {
- redraw_all_later(NOT_VALID);
- ins_compl_show_pum();
- }
-
if (!equalpos(curwin->w_cursor, tpos)) {
start_arrow(&tpos);
can_cindent = true;
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 786769dc7d..bd03160bcd 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -51,6 +51,7 @@
#include "nvim/option.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
+#include "nvim/popupmnu.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
@@ -6051,7 +6052,12 @@ static int open_cmdwin(void)
/* Don't execute autocommands while creating the window. */
block_autocmds();
- /* don't use a new tab page */
+
+ // When using completion in Insert mode with <C-R>=<C-F> one can open the
+ // command line window, but we don't want the popup menu then.
+ pum_undisplay(true);
+
+ // don't use a new tab page
cmdmod.tab = 0;
cmdmod.noswapfile = 1;
diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua
index d3047e1a9c..40bdc3e30c 100644
--- a/src/nvim/generators/c_grammar.lua
+++ b/src/nvim/generators/c_grammar.lua
@@ -25,6 +25,7 @@ local c_id = (
local c_void = P('void')
local c_param_type = (
((P('Error') * fill * P('*') * fill) * Cc('error')) +
+ C((P('const ') ^ -1) * (c_id) * (ws ^ 1) * P('*')) +
(C(c_id) * (ws ^ 1))
)
local c_type = (C(c_void) * (ws ^ 1)) + c_param_type
@@ -43,6 +44,7 @@ local c_proto = Ct(
(fill * Cg((P('FUNC_API_REMOTE_ONLY') * Cc(true)), 'remote_only') ^ -1) *
(fill * Cg((P('FUNC_API_REMOTE_IMPL') * Cc(true)), 'remote_impl') ^ -1) *
(fill * Cg((P('FUNC_API_BRIDGE_IMPL') * Cc(true)), 'bridge_impl') ^ -1) *
+ (fill * Cg((P('FUNC_API_COMPOSITOR_IMPL') * Cc(true)), 'compositor_impl') ^ -1) *
fill * P(';')
)
diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua
index e76b601d8a..c8ab310b02 100644
--- a/src/nvim/generators/gen_api_ui_events.lua
+++ b/src/nvim/generators/gen_api_ui_events.lua
@@ -54,7 +54,7 @@ for i = 1, #events do
ev = events[i]
assert(ev.return_type == 'void')
- if ev.since == nil then
+ if ev.since == nil and not ev.noexport then
print("Ui event "..ev.name.." lacks since field.\n")
os.exit(1)
end
@@ -65,7 +65,7 @@ for i = 1, #events do
write_signature(proto_output, ev, 'UI *ui')
proto_output:write(';\n')
- if not ev.remote_impl then
+ if not ev.remote_impl and not ev.noexport then
remote_output:write('static void remote_ui_'..ev.name)
write_signature(remote_output, ev, 'UI *ui')
remote_output:write('\n{\n')
@@ -74,8 +74,7 @@ for i = 1, #events do
remote_output:write('}\n\n')
end
- if not ev.bridge_impl then
-
+ if not ev.bridge_impl and not ev.noexport then
send, argv, recv, recv_argv, recv_cleanup = '', '', '', '', ''
argc = 1
for j = 1, #ev.parameters do
@@ -138,21 +137,36 @@ for i = 1, #events do
call_output:write('\n{\n')
if ev.remote_only then
write_arglist(call_output, ev, false)
- call_output:write(' UI_LOG('..ev.name..', 0);\n')
+ call_output:write(' UI_LOG('..ev.name..');\n')
call_output:write(' ui_event("'..ev.name..'", args);\n')
+ elseif ev.compositor_impl then
+ call_output:write(' UI_CALL')
+ write_signature(call_output, ev, '!ui->composed, '..ev.name..', ui', true)
+ call_output:write(";\n")
else
call_output:write(' UI_CALL')
- write_signature(call_output, ev, ev.name, true)
+ write_signature(call_output, ev, 'true, '..ev.name..', ui', true)
call_output:write(";\n")
end
call_output:write("}\n\n")
end
+ if ev.compositor_impl then
+ call_output:write('void ui_composed_call_'..ev.name)
+ write_signature(call_output, ev, '')
+ call_output:write('\n{\n')
+ call_output:write(' UI_CALL')
+ write_signature(call_output, ev, 'ui->composed, '..ev.name..', ui', true)
+ call_output:write(";\n")
+ call_output:write("}\n\n")
+ end
+
end
proto_output:close()
call_output:close()
remote_output:close()
+bridge_output:close()
-- don't expose internal attributes like "impl_name" in public metadata
exported_attributes = {'name', 'parameters',
@@ -168,7 +182,9 @@ for _,ev in ipairs(events) do
p[1] = 'Dictionary'
end
end
- exported_events[#exported_events+1] = ev_exported
+ if not ev.noexport then
+ exported_events[#exported_events+1] = ev_exported
+ end
end
packed = mpack.pack(exported_events)
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index ccdf8f87ab..f47697b190 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -194,12 +194,15 @@ EXTERN int compl_cont_status INIT(= 0);
EXTERN int cmdmsg_rl INIT(= false); // cmdline is drawn right to left
EXTERN int msg_col;
EXTERN int msg_row;
-EXTERN int msg_scrolled; /* Number of screen lines that windows have
- * scrolled because of printing messages. */
-EXTERN int msg_scrolled_ign INIT(= FALSE);
-/* when TRUE don't set need_wait_return in
- msg_puts_attr() when msg_scrolled is
- non-zero */
+EXTERN int msg_scrolled; // Number of screen lines that windows have
+ // scrolled because of printing messages.
+// when true don't set need_wait_return in msg_puts_attr()
+// when msg_scrolled is non-zero
+EXTERN bool msg_scrolled_ign INIT(= false);
+// Whether the screen is damaged due to scrolling. Sometimes msg_scrolled
+// is reset before the screen is redrawn, so we need to keep track of this.
+EXTERN bool msg_did_scroll INIT(= false);
+
EXTERN char_u *keep_msg INIT(= NULL); /* msg to be shown after redraw */
EXTERN int keep_msg_attr INIT(= 0); /* highlight attr for keep_msg */
diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h
index cf9e550f48..d9ccdbbdab 100644
--- a/src/nvim/grid_defs.h
+++ b/src/nvim/grid_defs.h
@@ -1,6 +1,8 @@
#ifndef NVIM_GRID_DEFS_H
#define NVIM_GRID_DEFS_H
+#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
#include "nvim/types.h"
@@ -48,8 +50,15 @@ typedef struct {
// offsets for the grid relative to the global screen
int row_offset;
int col_offset;
+
+ // state owned by the compositor.
+ int comp_row;
+ int comp_col;
+ size_t comp_index;
+ bool comp_disabled;
} ScreenGrid;
-#define SCREEN_GRID_INIT { 0, NULL, NULL, NULL, NULL, 0, 0, 0, 0 }
+#define SCREEN_GRID_INIT { 0, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, \
+ false }
#endif // NVIM_GRID_DEFS_H
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 41d60fa3ea..20cdbc7ec9 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -101,6 +101,9 @@ static int get_attr_entry(HlEntry entry)
/// When a UI connects, we need to send it the table of highlights used so far.
void ui_send_all_hls(UI *ui)
{
+ if (!ui->hl_attr_define) {
+ return;
+ }
for (size_t i = 1; i < kv_size(attr_entries); i++) {
Array inspect = hl_inspect((int)i);
ui->hl_attr_define(ui, (Integer)i, kv_A(attr_entries, i).attr,
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 17f3a894d4..9c8711495c 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -154,6 +154,7 @@ void event_init(void)
remote_ui_init();
api_vim_init();
terminal_init();
+ ui_init();
}
/// @returns false if main_loop could not be closed gracefully
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 4c4f7d65bd..662eda3c7c 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -3412,7 +3412,9 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
# endif
xfree(name);
- /* pretend screen didn't scroll, need redraw anyway */
+ // pretend screen didn't scroll, need redraw anyway
+ // TODO(bfredl): when doing the message grid refactor,
+ // simplify this special case.
msg_scrolled = 0;
redraw_all_later(NOT_VALID);
}
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 1330460867..4552999256 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -1960,8 +1960,9 @@ int msg_scrollsize(void)
*/
static void msg_scroll_up(void)
{
- if (msg_scrolled == 0) {
+ if (!msg_did_scroll) {
ui_call_win_scroll_over_start();
+ msg_did_scroll = true;
}
if (dy_flags & DY_MSGSEP) {
if (msg_scrolled == 0) {
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index 09ba718302..351350d939 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -139,7 +139,7 @@ void mch_exit(int r)
exiting = true;
ui_flush();
- ui_builtin_stop();
+ ui_call_stop();
ml_close_all(true); // remove all memfiles
if (!event_teardown() && r == 0) {
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 056770f2c0..d64406846a 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -19,6 +19,7 @@
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/screen.h"
+#include "nvim/ui_compositor.h"
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/memory.h"
@@ -41,8 +42,11 @@ static int pum_row; // top row of pum
static int pum_col; // left column of pum
static bool pum_is_visible = false;
+static bool pum_is_drawn = false;
static bool pum_external = false;
+static ScreenGrid pum_grid = SCREEN_GRID_INIT;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "popupmnu.c.generated.h"
#endif
@@ -85,6 +89,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed)
// Mark the pum as visible already here,
// to avoid that must_redraw is set when 'cursorcolumn' is on.
pum_is_visible = true;
+ pum_is_drawn = true;
validate_cursor_col();
above_row = 0;
below_row = cmdline_row;
@@ -317,7 +322,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed)
/// Redraw the popup menu, using "pum_first" and "pum_selected".
void pum_redraw(void)
{
- int row = pum_row;
+ int row = 0;
int col;
int attr_norm = win_hl_attr(curwin, HLF_PNI);
int attr_select = win_hl_attr(curwin, HLF_PSI);
@@ -334,6 +339,37 @@ void pum_redraw(void)
int round;
int n;
+ int grid_width = pum_width;
+ int col_off = 0;
+ bool extra_space = false;
+ if (curwin->w_p_rl) {
+ col_off = pum_width;
+ if (pum_col < curwin->w_wincol + curwin->w_width - 1) {
+ grid_width += 1;
+ extra_space = true;
+ }
+ } else if (pum_col > 0) {
+ grid_width += 1;
+ col_off = 1;
+ extra_space = true;
+ }
+ if (pum_scrollbar > 0) {
+ grid_width++;
+ }
+
+ grid_assign_handle(&pum_grid);
+ bool moved = ui_comp_put_grid(&pum_grid, pum_row, pum_col-col_off,
+ pum_height, grid_width);
+
+ if (!pum_grid.chars
+ || pum_grid.Rows != pum_height || pum_grid.Columns != grid_width) {
+ grid_alloc(&pum_grid, pum_height, grid_width, !moved, false);
+ ui_call_grid_resize(pum_grid.handle, pum_grid.Columns, pum_grid.Rows);
+ } else if (moved) {
+ grid_invalidate(&pum_grid);
+ }
+
+
// Never display more than we have
if (pum_first > pum_size - pum_height) {
pum_first = pum_size - pum_height;
@@ -356,17 +392,17 @@ void pum_redraw(void)
screen_puts_line_start(row);
// prepend a space if there is room
- if (curwin->w_p_rl) {
- if (pum_col < curwin->w_wincol + curwin->w_width - 1) {
- grid_putchar(&default_grid, ' ', row, pum_col + 1, attr);
+ if (extra_space) {
+ if (curwin->w_p_rl) {
+ grid_putchar(&pum_grid, ' ', row, col_off + 1, attr);
+ } else {
+ grid_putchar(&pum_grid, ' ', row, col_off - 1, attr);
}
- } else if (pum_col > 0) {
- grid_putchar(&default_grid, ' ', row, pum_col - 1, attr);
}
// Display each entry, use two spaces for a Tab.
// Do this 3 times: For the main text, kind and extra info
- col = pum_col;
+ col = col_off;
totwidth = 0;
for (round = 1; round <= 3; ++round) {
@@ -423,13 +459,13 @@ void pum_redraw(void)
size++;
}
}
- grid_puts_len(&default_grid, rt, (int)STRLEN(rt), row,
+ grid_puts_len(&pum_grid, rt, (int)STRLEN(rt), row,
col - size + 1, attr);
xfree(rt_start);
xfree(st);
col -= width;
} else {
- grid_puts_len(&default_grid, st, (int)STRLEN(st), row, col, attr);
+ grid_puts_len(&pum_grid, st, (int)STRLEN(st), row, col, attr);
xfree(st);
col += width;
}
@@ -440,11 +476,11 @@ void pum_redraw(void)
// Display two spaces for a Tab.
if (curwin->w_p_rl) {
- grid_puts_len(&default_grid, (char_u *)" ", 2, row, col - 1,
+ grid_puts_len(&pum_grid, (char_u *)" ", 2, row, col - 1,
attr);
col -= 2;
} else {
- grid_puts_len(&default_grid, (char_u *)" ", 2, row, col, attr);
+ grid_puts_len(&pum_grid, (char_u *)" ", 2, row, col, attr);
col += 2;
}
totwidth += 2;
@@ -475,37 +511,37 @@ void pum_redraw(void)
}
if (curwin->w_p_rl) {
- grid_fill(&default_grid, row, row + 1, pum_col - pum_base_width - n + 1,
+ grid_fill(&pum_grid, row, row + 1, col_off - pum_base_width - n + 1,
col + 1, ' ', ' ', attr);
- col = pum_col - pum_base_width - n + 1;
+ col = col_off - pum_base_width - n + 1;
} else {
- grid_fill(&default_grid, row, row + 1, col,
- pum_col + pum_base_width + n, ' ', ' ', attr);
- col = pum_col + pum_base_width + n;
+ grid_fill(&pum_grid, row, row + 1, col,
+ col_off + pum_base_width + n, ' ', ' ', attr);
+ col = pum_base_width + n;
}
totwidth = pum_base_width + n;
}
if (curwin->w_p_rl) {
- grid_fill(&default_grid, row, row + 1, pum_col - pum_width + 1, col + 1,
+ grid_fill(&pum_grid, row, row + 1, col_off - pum_width + 1, col + 1,
' ', ' ', attr);
} else {
- grid_fill(&default_grid, row, row + 1, col, pum_col + pum_width, ' ', ' ',
+ grid_fill(&pum_grid, row, row + 1, col, col_off + pum_width, ' ', ' ',
attr);
}
if (pum_scrollbar > 0) {
if (curwin->w_p_rl) {
- grid_putchar(&default_grid, ' ', row, pum_col - pum_width,
+ grid_putchar(&pum_grid, ' ', row, col_off - pum_width,
i >= thumb_pos && i < thumb_pos + thumb_heigth
? attr_thumb : attr_scroll);
} else {
- grid_putchar(&default_grid, ' ', row, pum_col + pum_width,
+ grid_putchar(&pum_grid, ' ', row, col_off + pum_width,
i >= thumb_pos && i < thumb_pos + thumb_heigth
? attr_thumb : attr_scroll);
}
}
- grid_puts_line_flush(&default_grid, false);
+ grid_puts_line_flush(&pum_grid, false);
row++;
}
}
@@ -696,6 +732,8 @@ static int pum_set_selected(int n, int repeat)
// Update the screen before drawing the popup menu.
// Enable updating the status lines.
+ // TODO(bfredl): can simplify, get rid of the flag munging?
+ // or at least eliminate extra redraw before win_enter()?
pum_is_visible = false;
update_screen(0);
pum_is_visible = true;
@@ -725,17 +763,27 @@ static int pum_set_selected(int n, int repeat)
}
/// Undisplay the popup menu (later).
-void pum_undisplay(void)
+void pum_undisplay(bool immediate)
{
pum_is_visible = false;
pum_array = NULL;
- if (pum_external) {
- ui_call_popupmenu_hide();
- } else {
- redraw_all_later(SOME_VALID);
- redraw_tabline = true;
- status_redraw_all();
+ if (immediate) {
+ pum_check_clear();
+ }
+}
+
+void pum_check_clear(void)
+{
+ if (!pum_is_visible && pum_is_drawn) {
+ if (pum_external) {
+ ui_call_popupmenu_hide();
+ } else {
+ ui_comp_remove_grid(&pum_grid);
+ // TODO(bfredl): consider keeping float grids allocated.
+ grid_free(&pum_grid);
+ }
+ pum_is_drawn = false;
}
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 2038fb4d2c..759eefaecc 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -110,6 +110,7 @@
#include "nvim/syntax.h"
#include "nvim/terminal.h"
#include "nvim/ui.h"
+#include "nvim/ui_compositor.h"
#include "nvim/undo.h"
#include "nvim/version.h"
#include "nvim/window.h"
@@ -153,6 +154,8 @@ static bool highlights_invalid = false;
static bool conceal_cursor_used = false;
+static bool floats_invalid = false;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "screen.c.generated.h"
#endif
@@ -304,11 +307,15 @@ void update_screen(int type)
++display_tick; /* let syntax code know we're in a next round of
* display updating */
- /*
- * if the screen was scrolled up when displaying a message, scroll it down
- */
- if (msg_scrolled) {
+ // Tricky: vim code can reset msg_scrolled behind our back, so need
+ // separate bookkeeping for now.
+ if (msg_did_scroll) {
ui_call_win_scroll_over_reset();
+ msg_did_scroll = false;
+ }
+
+ // if the screen was scrolled up when displaying a message, scroll it down
+ if (msg_scrolled) {
clear_cmdline = true;
if (dy_flags & DY_MSGSEP) {
int valid = MAX(Rows - msg_scrollsize(), 0);
@@ -453,17 +460,20 @@ void update_screen(int type)
/* redraw status line after the window to minimize cursor movement */
if (wp->w_redr_status) {
- win_redr_status(wp, true); // any popup menu will be redrawn below
+ win_redr_status(wp);
}
}
- send_grid_resize = false;
- highlights_invalid = false;
+
end_search_hl();
// May need to redraw the popup menu.
- if (pum_drawn()) {
+ if (pum_drawn() && floats_invalid) {
pum_redraw();
}
+ send_grid_resize = false;
+ highlights_invalid = false;
+ floats_invalid = false;
+
/* Reset b_mod_set flags. Going through all windows is probably faster
* than going through all buffers (there could be many buffers). */
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
@@ -4287,7 +4297,7 @@ win_line (
/// screen positions.
static void screen_adjust_grid(ScreenGrid **grid, int *row_off, int *col_off)
{
- if (!ui_is_external(kUIMultigrid) && *grid != &default_grid) {
+ if (!(*grid)->chars && *grid != &default_grid) {
*row_off += (*grid)->row_offset;
*col_off += (*grid)->col_offset;
*grid = &default_grid;
@@ -4537,7 +4547,7 @@ void redraw_statuslines(void)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_redr_status) {
- win_redr_status(wp, false);
+ win_redr_status(wp);
}
}
if (redraw_tabline)
@@ -4808,7 +4818,7 @@ win_redr_status_matches (
/// If inversion is possible we use it. Else '=' characters are used.
/// If "ignore_pum" is true, also redraw statusline when the popup menu is
/// displayed.
-static void win_redr_status(win_T *wp, int ignore_pum)
+static void win_redr_status(win_T *wp)
{
int row;
char_u *p;
@@ -4831,7 +4841,7 @@ static void win_redr_status(win_T *wp, int ignore_pum)
if (wp->w_status_height == 0) {
// no status line, can only be last window
redraw_cmdline = true;
- } else if (!redrawing() || (!ignore_pum && pum_drawn())) {