aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/buffer.c14
-rw-r--r--src/nvim/api/keysets_defs.h14
-rw-r--r--src/nvim/api/vim.c156
-rw-r--r--src/nvim/drawscreen.c2
-rw-r--r--src/nvim/lua/executor.h2
-rw-r--r--src/nvim/math.c17
6 files changed, 189 insertions, 16 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 b709b49dba..bda0ccc870 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -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/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)
{