aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/CMakeLists.txt39
-rw-r--r--src/nvim/api/buffer.c79
-rw-r--r--src/nvim/decoration.c9
-rw-r--r--src/nvim/decoration.h15
-rw-r--r--src/nvim/edit.c2
-rw-r--r--src/nvim/eval.c24
-rw-r--r--src/nvim/eval/funcs.c3
-rw-r--r--src/nvim/eval/typval.h5
-rw-r--r--src/nvim/ex_cmds.c9
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/if_cscope.c2
-rw-r--r--src/nvim/lua/vim.lua11
-rw-r--r--src/nvim/memline.c4
-rw-r--r--src/nvim/normal.c2
-rw-r--r--src/nvim/os/input.c20
-rw-r--r--src/nvim/screen.c44
-rw-r--r--src/nvim/state.c28
-rw-r--r--src/nvim/terminal.c2
-rw-r--r--src/nvim/testdir/test_cursor_func.vim5
19 files changed, 232 insertions, 73 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 1a1a178620..2c9d655a15 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -513,8 +513,44 @@ if(WIN32)
tidy.exe
win32yank.exe
winpty-agent.exe
+ winpty.dll
xxd.exe
+ # Dependencies for neovim-qt
+ bearer/qgenericbearer.dll
+ iconengines/qsvgicon.dll
+ imageformats/qgif.dll
+ imageformats/qicns.dll
+ imageformats/qico.dll
+ imageformats/qjpeg.dll
+ imageformats/qsvg.dll
+ imageformats/qtga.dll
+ imageformats/qtiff.dll
+ imageformats/qwbmp.dll
+ imageformats/qwebp.dll
+ platforms/qwindows.dll
+ styles/qwindowsvistastyle.dll
+ translations/qt_ar.qm
+ translations/qt_bg.qm
+ translations/qt_ca.qm
+ translations/qt_cs.qm
+ translations/qt_da.qm
+ translations/qt_de.qm
+ translations/qt_en.qm
+ translations/qt_es.qm
+ translations/qt_fi.qm
+ translations/qt_fr.qm
+ translations/qt_gd.qm
+ translations/qt_he.qm
+ translations/qt_hu.qm
+ translations/qt_it.qm
+ translations/qt_ja.qm
+ translations/qt_ko.qm
+ translations/qt_lv.qm
+ translations/qt_pl.qm
+ translations/qt_ru.qm
+ translations/qt_sk.qm
+ translations/qt_uk.qm
D3Dcompiler_47.dll
libEGL.dll
libgcc_s_dw2-1.dll
@@ -522,14 +558,13 @@ if(WIN32)
libstdc++-6.dll
libwinpthread-1.dll
nvim-qt.exe
+ opengl32sw.dll
Qt5Core.dll
Qt5Gui.dll
Qt5Network.dll
Qt5Svg.dll
Qt5Widgets.dll
- winpty.dll
- platforms/qwindows.dll
)
get_filename_component(DEP_FILE_DIR ${DEP_FILE} DIRECTORY)
set(EXTERNAL_BLOBS_SCRIPT "${EXTERNAL_BLOBS_SCRIPT}\n"
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 2c2e8a024f..66c4454f7b 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -1430,6 +1430,18 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// - "eol": right after eol character (default)
/// - "overlay": display over the specified column, without
/// shifting the underlying text.
+/// - virt_text_hide : hide the virtual text when the background
+/// text is selected or hidden due to
+/// horizontal scroll 'nowrap'
+/// - hl_mode : control how highlights are combined with the
+/// highlights of the text. Currently only affects
+/// virt_text highlights, but might affect `hl_group`
+/// in later versions.
+/// - "replace": only show the virt_text color. This is the
+/// default
+/// - "combine": combine with background text color
+/// - "blend": blend with background text color.
+///
/// - ephemeral : for use with |nvim_set_decoration_provider|
/// callbacks. The mark will only be used for the current
/// redraw cycle, and not be permantently stored in the
@@ -1477,11 +1489,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
bool ephemeral = false;
uint64_t id = 0;
- int line2 = -1, hl_id = 0;
- DecorPriority priority = DECOR_PRIORITY_BASE;
+ int line2 = -1;
+ Decoration decor = DECORATION_INIT;
colnr_T col2 = -1;
- VirtText virt_text = KV_INITIAL_VALUE;
- VirtTextPos virt_text_pos = kVTEndOfLine;
+
bool right_gravity = true;
bool end_right_gravity = false;
bool end_gravity_set = false;
@@ -1528,12 +1539,12 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
switch (v->type) {
case kObjectTypeString:
hl_group = v->data.string;
- hl_id = syn_check_group(
+ decor.hl_id = syn_check_group(
(char_u *)(hl_group.data),
(int)hl_group.size);
break;
case kObjectTypeInteger:
- hl_id = (int)v->data.integer;
+ decor.hl_id = (int)v->data.integer;
break;
default:
api_set_error(err, kErrorTypeValidation,
@@ -1546,7 +1557,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
"virt_text is not an Array");
goto error;
}
- virt_text = parse_virt_text(v->data.array, err);
+ decor.virt_text = parse_virt_text(v->data.array, err);
if (ERROR_SET(err)) {
goto error;
}
@@ -1558,9 +1569,33 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
}
String str = v->data.string;
if (strequal("eol", str.data)) {
- virt_text_pos = kVTEndOfLine;
+ decor.virt_text_pos = kVTEndOfLine;
} else if (strequal("overlay", str.data)) {
- virt_text_pos = kVTOverlay;
+ decor.virt_text_pos = kVTOverlay;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_text_pos: invalid value");
+ goto error;
+ }
+ } else if (strequal("virt_text_hide", k.data)) {
+ decor.virt_text_hide = api_object_to_bool(*v,
+ "virt_text_hide", false, err);
+ if (ERROR_SET(err)) {
+ goto error;
+ }
+ } else if (strequal("hl_mode", k.data)) {
+ if (v->type != kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation,
+ "hl_mode is not a String");
+ goto error;
+ }
+ String str = v->data.string;
+ if (strequal("replace", str.data)) {
+ decor.hl_mode = kHlModeReplace;
+ } else if (strequal("combine", str.data)) {
+ decor.hl_mode = kHlModeCombine;
+ } else if (strequal("blend", str.data)) {
+ decor.hl_mode = kHlModeBlend;
} else {
api_set_error(err, kErrorTypeValidation,
"virt_text_pos: invalid value");
@@ -1583,7 +1618,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
"priority is not a valid value");
goto error;
}
- priority = (DecorPriority)v->data.integer;
+ decor.priority = (DecorPriority)v->data.integer;
} else if (strequal("right_gravity", k.data)) {
if (v->type != kObjectTypeBoolean) {
api_set_error(err, kErrorTypeValidation,
@@ -1631,23 +1666,23 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
col2 = 0;
}
- Decoration *decor = NULL, tmp = { 0 };
+ Decoration *d = NULL;
- if (kv_size(virt_text) || priority != DECOR_PRIORITY_BASE) {
+ if (ephemeral) {
+ d = &decor;
+ } else if (kv_size(decor.virt_text)
+ || decor.priority != DECOR_PRIORITY_BASE) {
// TODO(bfredl): this is a bit sketchy. eventually we should
// have predefined decorations for both marks/ephemerals
- decor = ephemeral ? &tmp : xcalloc(1, sizeof(*decor));
- decor->hl_id = hl_id;
- decor->virt_text = virt_text;
- decor->priority = priority;
- decor->virt_text_pos = virt_text_pos;
- } else if (hl_id) {
- decor = decor_hl(hl_id);
+ d = xcalloc(1, sizeof(*d));
+ *d = decor;
+ } else if (decor.hl_id) {
+ d = decor_hl(decor.hl_id);
}
// TODO(bfredl): synergize these two branches even more
if (ephemeral && decor_state.buf == buf) {
- decor_add_ephemeral((int)line, (int)col, line2, col2, decor, 0);
+ decor_add_ephemeral((int)line, (int)col, line2, col2, &decor, 0);
} else {
if (ephemeral) {
api_set_error(err, kErrorTypeException, "not yet implemented");
@@ -1655,14 +1690,14 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
}
id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col,
- line2, col2, decor, right_gravity,
+ line2, col2, d, right_gravity,
end_right_gravity, kExtmarkNoUndo);
}
return (Integer)id;
error:
- clear_virttext(&virt_text);
+ clear_virttext(&decor.virt_text);
return 0;
}
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index a1289f202a..9a20b06660 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -230,7 +230,7 @@ static void decor_add(DecorState *state, int start_row, int start_col,
HlRange range = { start_row, start_col, end_row, end_col,
attr_id, MAX(priority, decor->priority),
kv_size(decor->virt_text) ? &decor->virt_text : NULL,
- decor->virt_text_pos,
+ decor->virt_text_pos, decor->virt_text_hide, decor->hl_mode,
kv_size(decor->virt_text) && owned, -1 };
kv_pushp(state->active);
@@ -245,7 +245,8 @@ static void decor_add(DecorState *state, int start_row, int start_col,
kv_A(state->active, index) = range;
}
-int decor_redraw_col(buf_T *buf, int col, int virt_col, DecorState *state)
+int decor_redraw_col(buf_T *buf, int col, int virt_col, bool hidden,
+ DecorState *state)
{
if (col <= state->col_until) {
return state->current;
@@ -324,7 +325,7 @@ next_mark:
}
if ((item.start_row == state->row && item.start_col <= col)
&& item.virt_text && item.virt_col == -1) {
- item.virt_col = virt_col;
+ item.virt_col = (item.virt_text_hide && hidden) ? -2 : virt_col;
}
if (keep) {
kv_A(state->active, j++) = item;
@@ -345,7 +346,7 @@ void decor_redraw_end(DecorState *state)
VirtText *decor_redraw_virt_text(buf_T *buf, DecorState *state)
{
- decor_redraw_col(buf, MAXCOL, MAXCOL, state);
+ decor_redraw_col(buf, MAXCOL, MAXCOL, false, state);
for (size_t i = 0; i < kv_size(state->active); i++) {
HlRange item = kv_A(state->active, i);
if (item.start_row == state->row && item.virt_text
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index 47bd9abbc3..264e8a4a82 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -23,15 +23,26 @@ typedef enum {
kVTOverlay,
} VirtTextPos;
+typedef enum {
+ kHlModeUnknown,
+ kHlModeReplace,
+ kHlModeCombine,
+ kHlModeBlend,
+} HlMode;
+
struct Decoration
{
int hl_id; // highlight group
VirtText virt_text;
VirtTextPos virt_text_pos;
+ bool virt_text_hide;
+ HlMode hl_mode;
// TODO(bfredl): style, signs, etc
DecorPriority priority;
bool shared; // shared decoration, don't free
};
+#define DECORATION_INIT { 0, KV_INITIAL_VALUE, kVTEndOfLine, false, \
+ kHlModeUnknown, DECOR_PRIORITY_BASE, false }
typedef struct {
int start_row;
@@ -39,9 +50,13 @@ typedef struct {
int end_row;
int end_col;
int attr_id;
+ // TODO(bfredl): embed decoration instead, perhaps using an arena
+ // for ephemerals?
DecorPriority priority;
VirtText *virt_text;
VirtTextPos virt_text_pos;
+ bool virt_text_hide;
+ HlMode hl_mode;
bool virt_text_owned;
int virt_col;
} HlRange;
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 53717229f6..68c7438ea3 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -1024,7 +1024,7 @@ static int insert_handle_key(InsertState *s)
break;
case K_EVENT: // some event
- multiqueue_process_events(main_loop.events);
+ state_handle_k_event();
goto check_pum;
case K_COMMAND: // some command
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 6d97310c1c..63d5216cc4 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -5280,14 +5280,10 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
if (ht_stack == NULL) {
abort = set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack);
} else {
- ht_stack_T *newitem = try_malloc(sizeof(ht_stack_T));
- if (newitem == NULL) {
- abort = true;
- } else {
- newitem->ht = &dd->dv_hashtab;
- newitem->prev = *ht_stack;
- *ht_stack = newitem;
- }
+ ht_stack_T *const newitem = xmalloc(sizeof(ht_stack_T));
+ newitem->ht = &dd->dv_hashtab;
+ newitem->prev = *ht_stack;
+ *ht_stack = newitem;
}
QUEUE *w = NULL;
@@ -5308,14 +5304,10 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
if (list_stack == NULL) {
abort = set_ref_in_list(ll, copyID, ht_stack);
} else {
- list_stack_T *newitem = try_malloc(sizeof(list_stack_T));
- if (newitem == NULL) {
- abort = true;
- } else {
- newitem->list = ll;
- newitem->prev = *list_stack;
- *list_stack = newitem;
- }
+ list_stack_T *const newitem = xmalloc(sizeof(list_stack_T));
+ newitem->list = ll;
+ newitem->prev = *list_stack;
+ *list_stack = newitem;
}
}
break;
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 8c8e0d568b..60229e1ebc 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -3029,10 +3029,11 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].v_type == VAR_UNKNOWN) {
// getchar(): blocking wait.
+ // TODO(bfredl): deduplicate shared logic with state_enter ?
if (!(char_avail() || using_script() || input_available())) {
(void)os_inchar(NULL, 0, -1, 0, main_loop.events);
if (!multiqueue_empty(main_loop.events)) {
- multiqueue_process_events(main_loop.events);
+ state_handle_k_event();
continue;
}
}
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index 6fcb01aace..531b17cb59 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -341,8 +341,9 @@ struct ufunc {
///< used for s: variables
int uf_refcount; ///< reference count, see func_name_refcount()
funccall_T *uf_scoped; ///< l: local variables for closure
- char_u uf_name[]; ///< Name of function; can start with <SNR>123_
- ///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR)
+ char_u uf_name[]; ///< Name of function (actual size equals name);
+ ///< can start with <SNR>123_
+ ///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR)
};
struct partial_S {
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 103c081143..854faf5377 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1407,19 +1407,20 @@ do_shell(
* For autocommands we want to get the output on the current screen, to
* avoid having to type return below.
*/
- msg_putchar('\r'); /* put cursor at start of line */
- msg_putchar('\n'); /* may shift screen one line up */
+ msg_putchar('\r'); // put cursor at start of line
+ msg_putchar('\n'); // may shift screen one line up
- /* warning message before calling the shell */
+ // warning message before calling the shell
if (p_warn
&& !autocmd_busy
- && msg_silent == 0)
+ && msg_silent == 0) {
FOR_ALL_BUFFERS(buf) {
if (bufIsChanged(buf)) {
MSG_PUTS(_("[No write since last change]\n"));
break;
}
}
+ }
// This ui_cursor_goto is required for when the '\n' resulted in a "delete line
// 1" command to the terminal.
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index d470bfb418..5979f4d3a0 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -935,7 +935,7 @@ static int command_line_execute(VimState *state, int key)
if (s->c == K_EVENT || s->c == K_COMMAND) {
if (s->c == K_EVENT) {
- multiqueue_process_events(main_loop.events);
+ state_handle_k_event();
} else {
do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT);
}
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 2dad8fb781..31615e744a 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -1865,7 +1865,7 @@ static void cs_release_csp(size_t i, bool freefnpp)
alive = false; // cscope process no longer exists
break;
}
- os_delay(50L, false); // sleep 50ms
+ os_delay(50L, false); // sleep 50 ms
}
}
if (alive)
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index e13b9745a8..eb54ff28ee 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -263,8 +263,15 @@ end
-- vim.fn.{func}(...)
vim.fn = setmetatable({}, {
__index = function(t, key)
- local function _fn(...)
- return vim.call(key, ...)
+ local _fn
+ if vim.api[key] ~= nil then
+ _fn = function()
+ error(string.format("Tried to call API function with vim.fn: use vim.api.%s instead", key))
+ end
+ else
+ _fn = function(...)
+ return vim.call(key, ...)
+ end
end
t[key] = _fn
return _fn
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 293a4d01db..34d8eb0ffe 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -3859,8 +3859,8 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
/* May resize here so we don't have to do it in both cases below */
if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks) {
buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2;
- buf->b_ml.ml_chunksize = (chunksize_T *)
- xrealloc(buf->b_ml.ml_chunksize,
+ buf->b_ml.ml_chunksize = xrealloc(
+ buf->b_ml.ml_chunksize,
sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 4d8b11f832..0b4e2e1f23 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -8103,7 +8103,7 @@ static void nv_event(cmdarg_T *cap)
// lists or dicts being used.
may_garbage_collect = false;
bool may_restart = (restart_edit != 0);
- multiqueue_process_events(main_loop.events);
+ state_handle_k_event();
finish_op = false;
if (may_restart) {
// Tricky: if restart_edit was set before the handler we are in ctrl-o mode,
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 9d6518841a..eca245650a 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -159,16 +159,28 @@ bool os_char_avail(void)
return inbuf_poll(0, NULL) == kInputAvail;
}
-// Check for CTRL-C typed by reading all available characters.
+/// Poll for fast events. `got_int` will be set to `true` if CTRL-C was typed.
+///
+/// This invokes a full libuv loop iteration which can be quite costly.
+/// Prefer `line_breakcheck()` if called in a busy inner loop.
+///
+/// Caller must at least check `got_int` before calling this function again.
+/// checking for other low-level input state like `input_available()` might
+/// also be relevant (i e to throttle idle processing when user input is
+/// available)
void os_breakcheck(void)
{
+ if (got_int) {
+ return;
+ }
+
int save_us = updating_screen;
// We do not want screen_resize() to redraw here.
+ // TODO(bfredl): we are already special casing redraw events, is this
+ // hack still needed?
updating_screen++;
- if (!got_int) {
- loop_poll_events(&main_loop, 0);
- }
+ loop_poll_events(&main_loop, 0);
updating_screen = save_us;
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 20e3cc0a2e..aa3a7ae7ed 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2096,6 +2096,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext
+ bool area_active = false;
+
/* draw_state: items that are drawn in sequence: */
#define WL_START 0 /* nothing done yet */
# define WL_CMDLINE WL_START + 1 /* cmdline window column */
@@ -2656,7 +2658,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
// already be in use.
xfree(p_extra_free);
p_extra_free = xmalloc(MAX_MCO * fdc + 1);
- n_extra = fill_foldcolumn(p_extra_free, wp, foldinfo, lnum);
+ n_extra = (int)fill_foldcolumn(p_extra_free, wp, foldinfo, lnum);
p_extra_free[n_extra] = NUL;
p_extra = p_extra_free;
c_extra = NUL;
@@ -2850,6 +2852,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
if (draw_state == WL_LINE - 1 && n_extra == 0) {
sign_idx = 0;
draw_state = WL_LINE;
+
+ if (has_decor && row == startrow + filler_lines) {
+ // hide virt_text on text hidden by 'nowrap'
+ decor_redraw_col(wp->w_buffer, vcol, off, true, &decor_state);
+ }
+
if (saved_n_extra) {
/* Continue item from end of wrapped line. */
n_extra = saved_n_extra;
@@ -2934,10 +2942,14 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
&& vcol_prev < vcol // not at margin
&& vcol < tocol)) {
area_attr = attr; // start highlighting
+ if (area_highlighting) {
+ area_active = true;
+ }
} else if (area_attr != 0 && (vcol == tocol
|| (noinvcur
&& (colnr_T)vcol == wp->w_virtcol))) {
area_attr = 0; // stop highlighting
+ area_active = false;
}
if (!n_extra) {
@@ -3397,9 +3409,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
char_attr = hl_combine_attr(spell_attr, char_attr);
}
+ if (wp->w_buffer->terminal) {
+ char_attr = hl_combine_attr(term_attrs[vcol], char_attr);
+ }
+
if (has_decor && v > 0) {
+ bool selected = (area_active || (area_highlighting && noinvcur
+ && (colnr_T)vcol == wp->w_virtcol));
int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v-1, off,
- &decor_state);
+ selected, &decor_state);
if (extmark_attr != 0) {
if (!attr_pri) {
char_attr = hl_combine_attr(char_attr, extmark_attr);
@@ -3409,10 +3427,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
}
- if (wp->w_buffer->terminal) {
- char_attr = hl_combine_attr(term_attrs[vcol], char_attr);
- }
-
// Found last space before word: check for line break.
if (wp->w_p_lbr && c0 == c && vim_isbreak(c)
&& !vim_isbreak((int)(*ptr))) {
@@ -4355,10 +4369,22 @@ void draw_virt_text(buf_T *buf, int *end_col, int max_col)
virt_pos++;
continue;
}
- int cells = line_putchar(&s, &linebuf_char[col], 2, false);
- linebuf_attr[col++] = virt_attr;
+ int attr;
+ bool through = false;
+ if (item->hl_mode == kHlModeCombine) {
+ attr = hl_combine_attr(linebuf_attr[col], virt_attr);
+ } else if (item->hl_mode == kHlModeBlend) {
+ through = (*s.p == ' ');
+ attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
+ } else {
+ attr = virt_attr;
+ }
+ schar_T dummy[2];
+ int cells = line_putchar(&s, through ? dummy : &linebuf_char[col],
+ max_col-col, false);
+ linebuf_attr[col++] = attr;
if (cells > 1) {
- linebuf_attr[col++] = virt_attr;
+ linebuf_attr[col++] = attr;
}
}
*end_col = MAX(*end_col, col);
diff --git a/src/nvim/state.c b/src/nvim/state.c
index b195c1d96b..a3c74789d1 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -75,6 +75,34 @@ getkey:
}
}
+/// process events on main_loop, but interrupt if input is available
+///
+/// This should be used to handle K_EVENT in states accepting input
+/// otherwise bursts of events can block break checking indefinitely.
+void state_handle_k_event(void)
+{
+ while (true) {
+ Event event = multiqueue_get(main_loop.events);
+ if (event.handler) {
+ event.handler(event.argv);
+ }
+
+ if (multiqueue_empty(main_loop.events)) {
+ // don't breakcheck before return, caller should return to main-loop
+ // and handle input already.
+ return;
+ }
+
+ // TODO(bfredl): as an further micro-optimization, we could check whether
+ // event.handler already checked input.
+ os_breakcheck();
+ if (input_available() || got_int) {
+ return;
+ }
+ }
+}
+
+
/// Return true if in the current mode we need to use virtual.
bool virtual_active(void)
{
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 642c443318..f6995cddb6 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -457,7 +457,7 @@ static int terminal_execute(VimState *state, int key)
case K_EVENT:
// We cannot let an event free the terminal yet. It is still needed.
s->term->refcount++;
- multiqueue_process_events(main_loop.events);
+ state_handle_k_event();
s->term->refcount--;
if (s->term->buf_handle == 0) {
s->close = true;
diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim
index 2e190911b2..53b7da517e 100644
--- a/src/nvim/testdir/test_cursor_func.vim
+++ b/src/nvim/testdir/test_cursor_func.vim
@@ -92,6 +92,11 @@ func Test_screenpos()
\ 'endcol': wincol + 9}, screenpos(winid, 2, 22))
close
bwipe!
+
+ call assert_equal({'col': 1, 'row': 1, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
+ nmenu WinBar.TEST :
+ call assert_equal({'col': 1, 'row': 2, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
+ nunmenu WinBar.TEST
endfunc
func Test_screenpos_number()