diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2024-05-02 07:49:07 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-02 07:49:07 -0700 |
commit | e5c69df679159cd56fe34d6fc66a898bed9a87d0 (patch) | |
tree | c2b20f0b3581f8e861134c177489ff294be911ea /src | |
parent | 350d81856473b45100d6b0e5920b757df1b4ad27 (diff) | |
parent | 037ea6e786b5d05f4a8965e4c2ba6aa60ec7c01a (diff) | |
download | rneovim-e5c69df679159cd56fe34d6fc66a898bed9a87d0.tar.gz rneovim-e5c69df679159cd56fe34d6fc66a898bed9a87d0.tar.bz2 rneovim-e5c69df679159cd56fe34d6fc66a898bed9a87d0.zip |
Merge #28101 nvim__redraw
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/buffer.c | 14 | ||||
-rw-r--r-- | src/nvim/api/keysets_defs.h | 14 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 156 | ||||
-rw-r--r-- | src/nvim/drawscreen.c | 22 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 2 | ||||
-rw-r--r-- | src/nvim/lua/executor.h | 2 | ||||
-rw-r--r-- | src/nvim/math.c | 17 | ||||
-rw-r--r-- | src/nvim/popupmenu.c | 2 |
8 files changed, 201 insertions, 28 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 452ba49e04..7e64808709 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -230,20 +230,6 @@ Boolean nvim_buf_detach(uint64_t channel_id, Buffer buffer, Error *err) return true; } -/// @nodoc -void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last, Error *err) -{ - buf_T *buf = find_buffer_by_handle(buffer, err); - if (!buf) { - return; - } - if (last < 0) { - last = buf->b_ml.ml_line_count; - } - - redraw_buf_range_later(buf, (linenr_T)first + 1, (linenr_T)last); -} - /// Gets a line-range from the buffer. /// /// Indexing is zero-based, end-exclusive. Negative indices are interpreted diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h index 7c5fddff55..00d8aa8428 100644 --- a/src/nvim/api/keysets_defs.h +++ b/src/nvim/api/keysets_defs.h @@ -373,3 +373,17 @@ typedef struct { Boolean ignore_blank_lines; Boolean indent_heuristic; } Dict(xdl_diff); + +typedef struct { + OptionalKeys is_set__redraw_; + Boolean flush; + Boolean cursor; + Boolean valid; + Boolean statuscolumn; + Boolean statusline; + Boolean tabline; + Boolean winbar; + Array range; + Window win; + Buffer buf; +} Dict(redraw); diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index e75f4e629b..d8ebc4b94f 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -50,6 +50,7 @@ #include "nvim/mapping.h" #include "nvim/mark.h" #include "nvim/mark_defs.h" +#include "nvim/math.h" #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" @@ -2305,3 +2306,158 @@ Dictionary nvim__complete_set(Integer index, Dict(complete_set) *opts, Arena *ar } return rv; } + +static void redraw_status(win_T *wp, Dict(redraw) *opts, bool *flush) +{ + if (opts->statuscolumn && *wp->w_p_stc != NUL) { + wp->w_nrwidth_line_count = 0; + changed_window_setting(wp); + } + win_grid_alloc(wp); + + // Flush later in case winbar was just hidden or shown for the first time, or + // statuscolumn is being drawn. + if (wp->w_lines_valid == 0) { + *flush = true; + } + + // Mark for redraw in case flush will happen, otherwise redraw now. + if (*flush && (opts->statusline || opts->winbar)) { + wp->w_redr_status = true; + } else if (opts->statusline || opts->winbar) { + win_check_ns_hl(wp); + if (opts->winbar) { + win_redr_winbar(wp); + } + if (opts->statusline) { + win_redr_status(wp); + } + win_check_ns_hl(NULL); + } +} + +/// EXPERIMENTAL: this API may change in the future. +/// +/// Instruct Nvim to redraw various components. +/// +/// @see |:redraw| +/// +/// @param opts Optional parameters. +/// - win: Target a specific |window-ID| as described below. +/// - buf: Target a specific buffer number as described below. +/// - flush: Update the screen with pending updates. +/// - valid: When present mark `win`, `buf`, or all windows for +/// redraw. When `true`, only redraw changed lines (useful for +/// decoration providers). When `false`, forcefully redraw. +/// - range: Redraw a range in `buf`, the buffer in `win` or the +/// current buffer (useful for decoration providers). Expects a +/// tuple `[first, last]` with the first and last line number +/// of the range, 0-based end-exclusive |api-indexing|. +/// - cursor: Immediately update cursor position on the screen in +/// `win` or the current window. +/// - statuscolumn: Redraw the 'statuscolumn' in `buf`, `win` or +/// all windows. +/// - statusline: Redraw the 'statusline' in `buf`, `win` or all +/// windows. +/// - winbar: Redraw the 'winbar' in `buf`, `win` or all windows. +/// - tabline: Redraw the 'tabline'. +void nvim__redraw(Dict(redraw) *opts, Error *err) + FUNC_API_SINCE(12) +{ + win_T *win = NULL; + buf_T *buf = NULL; + + if (HAS_KEY(opts, redraw, win)) { + win = find_window_by_handle(opts->win, err); + if (ERROR_SET(err)) { + return; + } + } + + if (HAS_KEY(opts, redraw, buf)) { + VALIDATE(win == NULL, "%s", "cannot use both 'buf' and 'win'", { + return; + }); + buf = find_buffer_by_handle(opts->buf, err); + if (ERROR_SET(err)) { + return; + } + } + + int count = (win != NULL) + (buf != NULL); + VALIDATE(popcount(opts->is_set__redraw_) > count, "%s", "at least one action required", { + return; + }); + + if (HAS_KEY(opts, redraw, valid)) { + // UPD_VALID redraw type does not actually do anything on it's own. Setting + // it here without scrolling or changing buffer text seems pointless but + // the expectation is that this may be called by decoration providers whose + // "on_win" callback may set "w_redr_top/bot". + int type = opts->valid ? UPD_VALID : UPD_NOT_VALID; + if (win != NULL) { + redraw_later(win, type); + } else if (buf != NULL) { + redraw_buf_later(buf, type); + } else { + redraw_all_later(type); + } + } + + if (HAS_KEY(opts, redraw, range)) { + VALIDATE(kv_size(opts->range) == 2 + && kv_A(opts->range, 0).type == kObjectTypeInteger + && kv_A(opts->range, 1).type == kObjectTypeInteger + && kv_A(opts->range, 0).data.integer >= 0 + && kv_A(opts->range, 1).data.integer >= -1, + "%s", "Invalid 'range': Expected 2-tuple of Integers", { + return; + }); + linenr_T first = (linenr_T)kv_A(opts->range, 0).data.integer + 1; + linenr_T last = (linenr_T)kv_A(opts->range, 1).data.integer; + if (last < 0) { + last = buf->b_ml.ml_line_count; + } + redraw_buf_range_later(win ? win->w_buffer : (buf ? buf : curbuf), first, last); + } + + if (opts->cursor) { + setcursor_mayforce(win ? win : curwin, true); + } + + bool flush = opts->flush; + if (opts->tabline) { + // Flush later in case tabline was just hidden or shown for the first time. + if (redraw_tabline && firstwin->w_lines_valid == 0) { + flush = true; + } else { + draw_tabline(); + } + } + + bool save_lz = p_lz; + int save_rd = RedrawingDisabled; + RedrawingDisabled = 0; + p_lz = false; + if (opts->statuscolumn || opts->statusline || opts->winbar) { + if (win == NULL) { + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (buf == NULL || wp->w_buffer == buf) { + redraw_status(wp, opts, &flush); + } + } + } else { + redraw_status(win, opts, &flush); + } + } + + // Flush pending screen updates if "flush" or "clear" is true, or when + // redrawing a status component may have changed the grid dimensions. + if (flush && !cmdpreview) { + update_screen(); + } + ui_flush(); + + RedrawingDisabled = save_rd; + p_lz = save_lz; +} diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 5e834e4b79..bda0ccc870 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -821,25 +821,25 @@ static void win_redr_border(win_T *wp) /// Set cursor to its position in the current window. void setcursor(void) { - setcursor_mayforce(false); + setcursor_mayforce(curwin, false); } /// Set cursor to its position in the current window. /// @param force when true, also when not redrawing. -void setcursor_mayforce(bool force) +void setcursor_mayforce(win_T *wp, bool force) { if (force || redrawing()) { - validate_cursor(curwin); + validate_cursor(wp); - ScreenGrid *grid = &curwin->w_grid; - int row = curwin->w_wrow; - int col = curwin->w_wcol; - if (curwin->w_p_rl) { + ScreenGrid *grid = &wp->w_grid; + int row = wp->w_wrow; + int col = wp->w_wcol; + if (wp->w_p_rl) { // With 'rightleft' set and the cursor on a double-wide character, // position it on the leftmost column. - col = curwin->w_width_inner - curwin->w_wcol - - ((utf_ptr2cells(get_cursor_pos_ptr()) == 2 - && vim_isprintc(gchar_cursor())) ? 2 : 1); + char *cursor = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum) + wp->w_cursor.col; + col = wp->w_width_inner - wp->w_wcol - ((utf_ptr2cells(cursor) == 2 + && vim_isprintc(utf_ptr2char(cursor))) ? 2 : 1); } grid_adjust(&grid, &row, &col); @@ -2713,7 +2713,7 @@ void redraw_buf_line_later(buf_T *buf, linenr_T line, bool force) } } -void redraw_buf_range_later(buf_T *buf, linenr_T firstline, linenr_T lastline) +void redraw_buf_range_later(buf_T *buf, linenr_T firstline, linenr_T lastline) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_buffer == buf diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index e0a5e3e2bb..47b4c1e47d 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5886,7 +5886,7 @@ static void ex_equal(exarg_T *eap) static void ex_sleep(exarg_T *eap) { if (cursor_valid(curwin)) { - setcursor_mayforce(true); + setcursor_mayforce(curwin, true); } int64_t len = eap->line2; diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index 299df2fdde..32fde3853b 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -43,7 +43,7 @@ typedef enum { kRetLuaref, ///< return value becomes a single Luaref, regardless of type (except NIL) } LuaRetMode; -/// To use with kRetNilBool for quick thuthyness check +/// To use with kRetNilBool for quick truthiness check #define LUARET_TRUTHY(res) ((res).type == kObjectTypeBoolean && (res).data.boolean == true) #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/math.c b/src/nvim/math.c index 47a667416c..1ccf4d7806 100644 --- a/src/nvim/math.c +++ b/src/nvim/math.c @@ -77,6 +77,23 @@ int xctz(uint64_t x) #endif } +/// Count number of set bits in bit field. +int popcount(uint64_t x) +{ + // Use compiler builtin if possible. +#if defined(__clang__) || defined(__GNUC__) + return __builtin_popcountll(x); +#else + int count = 0; + for (; x != 0; x >>= 1) { + if (x & 1) { + count++; + } + } + return count; +#endif +} + /// For overflow detection, add a digit safely to an int value. int vim_append_digit_int(int *value, int digit) { diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 0a8842a136..86f3611ec5 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -1281,7 +1281,7 @@ void pum_show_popupmenu(vimmenu_T *menu) pum_is_drawn = true; pum_grid.zindex = kZIndexCmdlinePopupMenu; // show above cmdline area #23275 pum_redraw(); - setcursor_mayforce(true); + setcursor_mayforce(curwin, true); int c = vgetc(); |