diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/CMakeLists.txt | 39 | ||||
-rw-r--r-- | src/nvim/api/buffer.c | 79 | ||||
-rw-r--r-- | src/nvim/decoration.c | 9 | ||||
-rw-r--r-- | src/nvim/decoration.h | 15 | ||||
-rw-r--r-- | src/nvim/edit.c | 2 | ||||
-rw-r--r-- | src/nvim/eval.c | 24 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 3 | ||||
-rw-r--r-- | src/nvim/eval/typval.h | 5 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 9 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 2 | ||||
-rw-r--r-- | src/nvim/if_cscope.c | 2 | ||||
-rw-r--r-- | src/nvim/lua/vim.lua | 11 | ||||
-rw-r--r-- | src/nvim/memline.c | 4 | ||||
-rw-r--r-- | src/nvim/normal.c | 2 | ||||
-rw-r--r-- | src/nvim/os/input.c | 20 | ||||
-rw-r--r-- | src/nvim/screen.c | 44 | ||||
-rw-r--r-- | src/nvim/state.c | 28 | ||||
-rw-r--r-- | src/nvim/terminal.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_cursor_func.vim | 5 |
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() |