diff options
Diffstat (limited to 'src/nvim')
30 files changed, 313 insertions, 147 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 7807125b92..95ca1052af 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -164,8 +164,8 @@ if(NOT MSVC) set_source_files_properties( ${CONV_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion") # gperf generates ANSI-C with incorrect linkage, ignore it. - check_c_compiler_flag(-Wno-static-in-inline HAS_WNO_STATIC_IN_INLINE_FLAG) - if(HAS_WNO_STATIC_IN_INLINE_FLAG) + check_c_compiler_flag(-Wstatic-in-inline HAS_WSTATIC_IN_INLINE) + if(HAS_WSTATIC_IN_INLINE) set_source_files_properties( eval.c PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-static-in-inline -Wno-conversion") else() diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 8e5650633a..dbe3b66fd5 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1064,6 +1064,19 @@ fail: /// - `external`: GUI should display the window as an external /// top-level window. Currently accepts no other positioning /// configuration together with this. +/// - `style`: Configure the apparance of the window. Currently only takes +/// one non-empty value: +/// - "minimal" Nvim will display the window with many UI options +/// disabled. This is useful when displaing a temporary +/// float where the text should not be edited. Disables +/// 'number', 'relativenumber', 'cursorline', 'cursorcolumn', +/// 'spell' and 'list' options. 'signcolumn' is changed to +/// `auto`. The end-of-buffer region is hidden by setting +/// `eob` flag of 'fillchars' to a space char, and clearing +/// the |EndOfBuffer| region in 'winhighlight'. +/// +/// top-level window. Currently accepts no other positioning +/// configuration together with this. /// @param[out] err Error details, if any /// /// @return Window handle, or 0 on error @@ -1085,6 +1098,11 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config, if (buffer > 0) { nvim_win_set_buf(wp->handle, buffer, err); } + + if (fconfig.style == kWinStyleMinimal) { + win_set_minimal_style(wp); + didset_window_options(wp); + } return wp->handle; } diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 9fd1818a5c..4922dd7efc 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -13,6 +13,7 @@ #include "nvim/vim.h" #include "nvim/buffer.h" #include "nvim/cursor.h" +#include "nvim/option.h" #include "nvim/window.h" #include "nvim/screen.h" #include "nvim/move.h" @@ -475,6 +476,10 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err) win_config_float(win, fconfig); win->w_pos_changed = true; } + if (fconfig.style == kWinStyleMinimal) { + win_set_minimal_style(win); + didset_window_options(win); + } } /// Return window configuration. diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 5678f518f5..cd31adbaff 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2543,6 +2543,11 @@ void get_winopts(buf_T *buf) } else copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt); + if (curwin->w_float_config.style == kWinStyleMinimal) { + didset_window_options(curwin); + win_set_minimal_style(curwin); + } + // Set 'foldlevel' to 'foldlevelstart' if it's not negative. if (p_fdls >= 0) { curwin->w_p_fdl = p_fdls; diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index ad10f6baa2..a27672488e 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -972,7 +972,6 @@ struct matchitem { }; typedef int FloatAnchor; -typedef int FloatRelative; enum { kFloatAnchorEast = 1, @@ -985,15 +984,20 @@ enum { // SE -> kFloatAnchorSouth | kFloatAnchorEast EXTERN const char *const float_anchor_str[] INIT(= { "NW", "NE", "SW", "SE" }); -enum { +typedef enum { kFloatRelativeEditor = 0, kFloatRelativeWindow = 1, kFloatRelativeCursor = 2, -}; +} FloatRelative; EXTERN const char *const float_relative_str[] INIT(= { "editor", "window", "cursor" }); +typedef enum { + kWinStyleUnused = 0, + kWinStyleMinimal, /// Minimal UI: no number column, eob markers, etc +} WinStyle; + typedef struct { Window window; int height, width; @@ -1002,12 +1006,14 @@ typedef struct { FloatRelative relative; bool external; bool focusable; + WinStyle style; } FloatConfig; #define FLOAT_CONFIG_INIT ((FloatConfig){ .height = 0, .width = 0, \ .row = 0, .col = 0, .anchor = 0, \ .relative = 0, .external = false, \ - .focusable = true }) + .focusable = true, \ + .style = kWinStyleUnused }) // Structure to store last cursor position and topline. Used by check_lnums() // and reset_lnums(). diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 6df2b69396..418725fa44 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7097,10 +7097,14 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr) { const char *const cmd = tv_get_string_chk(&argvars[0]); garray_T ga; + int save_trylevel = trylevel; + // trylevel must be zero for a ":throw" command to be considered failed + trylevel = 0; called_emsg = false; suppress_errthrow = true; emsg_silent = true; + do_cmdline_cmd(cmd); if (!called_emsg) { prepare_assert_error(&ga); @@ -7122,6 +7126,7 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } + trylevel = save_trylevel; called_emsg = false; suppress_errthrow = false; emsg_silent = false; @@ -15873,11 +15878,10 @@ static void f_sign_getplaced(typval_T *argvars, typval_T *rettv, FunPtr fptr) } if ((di = tv_dict_find(dict, "lnum", -1)) != NULL) { // get signs placed at this line - lnum = (linenr_T)tv_get_number_chk(&di->di_tv, ¬anum); - if (notanum) { + lnum = tv_get_lnum(&di->di_tv); + if (lnum <= 0) { return; } - lnum = tv_get_lnum(&di->di_tv); } if ((di = tv_dict_find(dict, "id", -1)) != NULL) { // get sign placed with this identifier @@ -20705,11 +20709,11 @@ void ex_echohl(exarg_T *eap) */ void ex_execute(exarg_T *eap) { - char_u *arg = eap->arg; + char_u *arg = eap->arg; typval_T rettv; int ret = OK; garray_T ga; - int save_did_emsg = did_emsg; + int save_did_emsg; ga_init(&ga, 1, 80); @@ -22048,6 +22052,7 @@ static bool script_autoload(const char *const name, const size_t name_len, } /// Return the autoload script name for a function or variable name +/// Caller must make sure that "name" contains AUTOLOAD_CHAR. /// /// @param[in] name Variable/function name. /// @param[in] name_len Name length. @@ -22236,12 +22241,9 @@ static void func_clear_items(ufunc_T *fp) ga_clear_strings(&(fp->uf_args)); ga_clear_strings(&(fp->uf_lines)); - xfree(fp->uf_tml_count); - fp->uf_tml_count = NULL; - xfree(fp->uf_tml_total); - fp->uf_tml_total = NULL; - xfree(fp->uf_tml_self); - fp->uf_tml_self = NULL; + XFREE_CLEAR(fp->uf_tml_count); + XFREE_CLEAR(fp->uf_tml_total); + XFREE_CLEAR(fp->uf_tml_self); } /// Free all things that a function contains. Does not free the function diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 7a8a39dbcf..990dee0c7f 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -26,6 +26,11 @@ // For PTY processes SIGTERM is sent first (in case SIGHUP was not enough). #define KILL_TIMEOUT_MS 2000 +/// Externally defined with gcov. +#ifdef USE_GCOV +void __gcov_flush(void); +#endif + static bool process_is_tearing_down = false; /// @returns zero on success, or negative error code @@ -50,6 +55,11 @@ int process_spawn(Process *proc, bool in, bool out, bool err) proc->err.closed = true; } +#ifdef USE_GCOV + // Flush coverage data before forking, to avoid "Merge mismatch" errors. + __gcov_flush(); +#endif + int status; switch (proc->type) { case kProcessTypeUv: diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a494463f89..1d27cf338e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -6922,16 +6922,17 @@ static void ex_resize(exarg_T *eap) n = atol((char *)eap->arg); if (cmdmod.split & WSP_VERT) { - if (*eap->arg == '-' || *eap->arg == '+') + if (*eap->arg == '-' || *eap->arg == '+') { n += curwin->w_width; - else if (n == 0 && eap->arg[0] == NUL) /* default is very wide */ - n = 9999; + } else if (n == 0 && eap->arg[0] == NUL) { // default is very wide + n = Columns; + } win_setwidth_win(n, wp); } else { if (*eap->arg == '-' || *eap->arg == '+') { n += curwin->w_height; } else if (n == 0 && eap->arg[0] == NUL) { // default is very high - n = 9999; + n = Rows-1; } win_setheight_win(n, wp); } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 1f258985a6..093067894f 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2495,7 +2495,7 @@ static void realloc_cmdbuff(int len) static char_u *arshape_buf = NULL; # if defined(EXITFREE) -void free_cmdline_buf(void) +void free_arshape_buf(void) { xfree(arshape_buf); } diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 15c3d0eb7b..e5cbb4f944 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -141,10 +141,12 @@ int hl_get_ui_attr(int idx, int final_id, bool optional) HlAttrs attrs = HLATTRS_INIT; bool available = false; - int syn_attr = syn_id2attr(final_id); - if (syn_attr != 0) { - attrs = syn_attr2entry(syn_attr); - available = true; + if (final_id > 0) { + int syn_attr = syn_id2attr(final_id); + if (syn_attr != 0) { + attrs = syn_attr2entry(syn_attr); + available = true; + } } if (HLF_PNI <= idx && idx <= HLF_PST) { @@ -176,15 +178,14 @@ void update_window_hl(win_T *wp, bool invalid) // determine window specific background set in 'winhighlight' bool float_win = wp->w_floating && !wp->w_float_config.external; - if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] > 0) { + if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] != 0) { wp->w_hl_attr_normal = hl_get_ui_attr(HLF_INACTIVE, wp->w_hl_ids[HLF_INACTIVE], !has_blend); - } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] > 0) { + } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] != 0) { wp->w_hl_attr_normal = hl_get_ui_attr(HLF_NFLOAT, - // 'cursorline' wp->w_hl_ids[HLF_NFLOAT], !has_blend); - } else if (wp->w_hl_id_normal > 0) { + } else if (wp->w_hl_id_normal != 0) { wp->w_hl_attr_normal = hl_get_ui_attr(-1, wp->w_hl_id_normal, !has_blend); } else { wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0; @@ -199,14 +200,14 @@ void update_window_hl(win_T *wp, bool invalid) } } - if (wp != curwin) { + if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] == 0) { wp->w_hl_attr_normal = hl_combine_attr(HL_ATTR(HLF_INACTIVE), wp->w_hl_attr_normal); } for (int hlf = 0; hlf < (int)HLF_COUNT; hlf++) { int attr; - if (wp->w_hl_ids[hlf] > 0) { + if (wp->w_hl_ids[hlf] != 0) { attr = hl_get_ui_attr(hlf, wp->w_hl_ids[hlf], false); } else { attr = HL_ATTR(hlf); diff --git a/src/nvim/main.c b/src/nvim/main.c index 306d2f7bf5..b3654a0690 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -54,6 +54,7 @@ #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/ui.h" +#include "nvim/ui_compositor.h" #include "nvim/version.h" #include "nvim/window.h" #include "nvim/shada.h" @@ -220,6 +221,7 @@ void early_init(void) set_lang_var(); // set v:lang and v:ctype init_signs(); + ui_comp_syn_init(); } #ifdef MAKE_LIB diff --git a/src/nvim/memory.c b/src/nvim/memory.c index dced03f3d5..1384aa177b 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -648,7 +648,7 @@ void free_all_mem(void) // Free all option values. Must come after closing windows. free_all_options(); - free_cmdline_buf(); + free_arshape_buf(); /* Clear registers. */ clear_registers(); diff --git a/src/nvim/option.c b/src/nvim/option.c index e8e246c277..d6dbb14653 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2191,6 +2191,7 @@ static void didset_options(void) (void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true); (void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true); (void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true); + (void)opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true); (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false); (void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true); (void)opt_strings_flags(p_wop, p_wop_values, &wop_flags, true); @@ -2650,6 +2651,10 @@ did_set_string_option( if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true) != OK) { errmsg = e_invarg; } + } else if (varp == &p_rdb) { // 'redrawdebug' + if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) { + errmsg = e_invarg; + } } else if (varp == &p_sbo) { // 'scrollopt' if (check_opt_strings(p_sbo, p_scbopt_values, true) != OK) { errmsg = e_invarg; @@ -3762,7 +3767,8 @@ static bool parse_winhl_opt(win_T *wp) size_t nlen = (size_t)(colon-p); char *hi = colon+1; char *commap = xstrchrnul(hi, ','); - int hl_id = syn_check_group((char_u *)hi, (int)(commap-hi)); + int len = (int)(commap-hi); + int hl_id = len ? syn_check_group((char_u *)hi, len) : -1; if (strncmp("Normal", p, nlen) == 0) { w_hl_id_normal = hl_id; @@ -4274,7 +4280,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, } else if (pp == &curwin->w_p_nuw || pp == &curwin->w_allbuf_opt.wo_nuw) { if (value < 1) { errmsg = e_positive; - } else if (value > 10) { + } else if (value > 20) { errmsg = e_invarg; } } else if (pp == &curbuf->b_p_iminsert || pp == &p_iminsert) { diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 35fe3b5b00..a480de735d 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -511,6 +511,13 @@ EXTERN char_u *p_pm; // 'patchmode' EXTERN char_u *p_path; // 'path' EXTERN char_u *p_cdpath; // 'cdpath' EXTERN long p_pyx; // 'pyxversion' +EXTERN char_u *p_rdb; // 'redrawdebug' +EXTERN unsigned rdb_flags; +# ifdef IN_OPTION_C +static char *(p_rdb_values[]) = { "compositor", NULL }; +# endif +# define RDB_COMPOSITOR 0x001 + EXTERN long p_rdt; // 'redrawtime' EXTERN int p_remap; // 'remap' EXTERN long p_re; // 'regexpengine' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 27f72f6441..c48366e205 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1848,6 +1848,13 @@ return { defaults={if_true={vi=false}} }, { + full_name='redrawdebug', abbreviation='rdb', + type='string', list='onecomma', scope={'global'}, + vi_def=true, + varname='p_rdb', + defaults={if_true={vi=''}} + }, + { full_name='redrawtime', abbreviation='rdt', type='number', scope={'global'}, vi_def=true, diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index 97545a6cb1..5fdf0e6181 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -36,11 +36,6 @@ # include "os/pty_process_unix.c.generated.h" #endif -/// Externally defined with gcov. -#ifdef USE_GCOV -void __gcov_flush(void); -#endif - /// termios saved at startup (for TUI) or initialized by pty_process_spawn(). static struct termios termios_default; @@ -64,11 +59,6 @@ int pty_process_spawn(PtyProcess *ptyproc) init_termios(&termios_default); } -#ifdef USE_GCOV - // Flush coverage data before forking, to avoid "Merge mismatch" errors. - __gcov_flush(); -#endif - int status = 0; // zero or negative error code (libuv convention) Process *proc = (Process *)ptyproc; assert(proc->err.closed); diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c index 18239c5566..1094fbc946 100644 --- a/src/nvim/os/time.c +++ b/src/nvim/os/time.c @@ -39,7 +39,7 @@ void time_init(void) /// @see gettimeofday(2) /// /// @return Current time in microseconds. -uint64_t os_utime(void) +int64_t os_utime(void) FUNC_ATTR_WARN_UNUSED_RESULT { uv_timeval64_t tm; @@ -47,8 +47,8 @@ uint64_t os_utime(void) if (e != 0 || tm.tv_sec < 0 || tm.tv_usec < 0) { return 0; } - uint64_t rv = (uint64_t)tm.tv_sec * 1000 * 1000; // s => μs - STRICT_ADD(rv, tm.tv_usec, &rv, uint64_t); + int64_t rv = tm.tv_sec * 1000 * 1000; // s => μs + STRICT_ADD(rv, tm.tv_usec, &rv, int64_t); return rv; } diff --git a/src/nvim/profile.c b/src/nvim/profile.c index cc12e00396..ae3f1d9b5e 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -61,7 +61,7 @@ proftime_T profile_setlimit(int64_t msec) FUNC_ATTR_WARN_UNUSED_RESULT } assert(msec <= (INT64_MAX / 1000LL) - 1); - proftime_T usec = (proftime_T)msec * 1000ULL; + proftime_T usec = msec * 1000; return os_utime() + usec; } @@ -111,7 +111,7 @@ proftime_T profile_add(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST /// @return `tm1` - `tm2` proftime_T profile_sub(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST { - return tm1 > tm2 ? tm1 - tm2 : 0; // os_utime() may go backwards. + return tm1 - tm2; } /// Adds the `self` time from the total time and the `children` time. diff --git a/src/nvim/profile.h b/src/nvim/profile.h index 7b378577ce..2608514313 100644 --- a/src/nvim/profile.h +++ b/src/nvim/profile.h @@ -4,7 +4,7 @@ #include <stdint.h> #include <time.h> -typedef uint64_t proftime_T; +typedef int64_t proftime_T; #define TIME_MSG(s) do { \ if (time_fd != NULL) time_msg(s, NULL); \ diff --git a/src/nvim/screen.c b/src/nvim/screen.c index acff44164f..a007aa9a47 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1612,7 +1612,8 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, } } - int attr = hl_combine_attr(wp->w_hl_attr_normal, win_hl_attr(wp, hl)); + int attr = hl_combine_attr(wp->w_hl_attr_normal, + hl ? win_hl_attr(wp, hl) : 0); if (wp->w_p_rl) { grid_fill(&wp->w_grid, row, endrow, wp->w_wincol, W_ENDCOL(wp) - 1 - n, @@ -2085,7 +2086,7 @@ win_line ( int lcs_eol_one = wp->w_p_lcs_chars.eol; // 'eol' until it's been used int lcs_prec_todo = wp->w_p_lcs_chars.prec; // 'prec' until it's been used - /* saved "extra" items for when draw_state becomes WL_LINE (again) */ + // saved "extra" items for when draw_state becomes WL_LINE (again) int saved_n_extra = 0; char_u *saved_p_extra = NULL; int saved_c_extra = 0; diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 8c85fbdaa7..9c391428ca 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -83,11 +83,8 @@ static signgroup_T * sign_group_ref(const char_u *groupname) hi = hash_lookup(&sg_table, (char *)groupname, STRLEN(groupname), hash); if (HASHITEM_EMPTY(hi)) { // new group - group = (signgroup_T *)xmalloc( - (unsigned)(sizeof(signgroup_T) + STRLEN(groupname))); - if (group == NULL) { - return NULL; - } + group = xmalloc((unsigned)(sizeof(signgroup_T) + STRLEN(groupname))); + STRCPY(group->sg_name, groupname); group->refcount = 1; group->next_sign_id = 1; @@ -188,10 +185,6 @@ static void insert_sign( newsign->typenr = typenr; if (group != NULL) { newsign->group = sign_group_ref(group); - if (newsign->group == NULL) { - xfree(newsign); - return; - } } else { newsign->group = NULL; } @@ -1347,8 +1340,8 @@ static void sign_getinfo(sign_T *sp, dict_T *retdict) /// Otherwise, return information about the specified sign. void sign_getlist(const char_u *name, list_T *retlist) { - sign_T *sp = first_sign; - dict_T *dict; + sign_T *sp = first_sign; + dict_T *dict; if (name != NULL) { sp = sign_find(name, NULL); @@ -1358,9 +1351,7 @@ void sign_getlist(const char_u *name, list_T *retlist) } for (; sp != NULL && !got_int; sp = sp->sn_next) { - if ((dict = tv_dict_alloc()) == NULL) { - return; - } + dict = tv_dict_alloc(); tv_list_append_dict(retlist, dict); sign_getinfo(sp, dict); @@ -1374,14 +1365,13 @@ void sign_getlist(const char_u *name, list_T *retlist) list_T *get_buffer_signs(buf_T *buf) FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - signlist_T *sign; - dict_T *d; + signlist_T *sign; + dict_T *d; list_T *const l = tv_list_alloc(kListLenMayKnow); FOR_ALL_SIGNS_IN_BUF(buf, sign) { - if ((d = sign_get_info(sign)) != NULL) { - tv_list_append_dict(l, d); - } + d = sign_get_info(sign); + tv_list_append_dict(l, d); } return l; } @@ -1394,21 +1384,16 @@ static void sign_get_placed_in_buf( const char_u *sign_group, list_T *retlist) { - dict_T *d; - list_T *l; - signlist_T *sign; - dict_T *sdict; + dict_T *d; + list_T *l; + signlist_T *sign; - if ((d = tv_dict_alloc()) == NULL) { - return; - } + d = tv_dict_alloc(); tv_list_append_dict(retlist, d); tv_dict_add_nr(d, S_LEN("bufnr"), (long)buf->b_fnum); - if ((l = tv_list_alloc(kListLenMayKnow)) == NULL) { - return; - } + l = tv_list_alloc(kListLenMayKnow); tv_dict_add_list(d, S_LEN("signs"), l); FOR_ALL_SIGNS_IN_BUF(buf, sign) { @@ -1419,9 +1404,7 @@ static void sign_get_placed_in_buf( || (sign_id == 0 && lnum == sign->lnum) || (lnum == 0 && sign_id == sign->id) || (lnum == sign->lnum && sign_id == sign->id)) { - if ((sdict = sign_get_info(sign)) != NULL) { - tv_list_append_dict(l, sdict); - } + tv_list_append_dict(l, sign_get_info(sign)); } } } diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 354590b9ec..e39075739c 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -5970,6 +5970,10 @@ static const char *highlight_init_both[] = { "default link Whitespace NonText", "default link MsgSeparator StatusLine", "default link NormalFloat Pmenu", + "RedrawDebugNormal cterm=reverse gui=reverse", + "RedrawDebugClear ctermbg=Yellow guibg=Yellow", + "RedrawDebugComposed ctermbg=Green guibg=Green", + "RedrawDebugRecompose ctermbg=Red guibg=Red", NULL }; diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index fe9e0bc9c8..8b43d91e25 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -99,23 +99,24 @@ RM_ON_RUN := test.out X* viminfo RM_ON_START := test.ok RUN_VIM := $(TOOL) $(NVIM_PRG) -u unix.vim -U NONE -i viminfo --headless --noplugin -s dotest.in +CLEAN_FILES := *.out \ + *.failed \ + *.res \ + *.rej \ + *.orig \ + *.tlog \ + test.log \ + messages \ + $(RM_ON_RUN) \ + $(RM_ON_START) \ + valgrind.* \ + .*.swp \ + .*.swo \ + .gdbinit \ + $(TMPDIR) \ + del clean: - -rm -rf *.out \ - *.failed \ - *.res \ - *.rej \ - *.orig \ - *.tlog \ - test.log \ - messages \ - $(RM_ON_RUN) \ - $(RM_ON_START) \ - valgrind.* \ - .*.swp \ - .*.swo \ - .gdbinit \ - $(TMPDIR) \ - del + $(RM) -rf $(CLEAN_FILES) test1.out: .gdbinit test1.in @echo "[OLDTEST-PREP] Running test1" diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim index fe87bd6ef5..a4c8ce7e43 100644 --- a/src/nvim/testdir/test_assert.vim +++ b/src/nvim/testdir/test_assert.vim @@ -1,5 +1,11 @@ " Test that the methods used for testing work. +func Test_assert_fails_in_try_block() + try + call assert_equal(0, assert_fails('throw "error"')) + endtry +endfunc + " Must be last. func Test_zz_quit_detected() " Verify that if a test function ends Vim the test script detects this. diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index 00f4563f3d..1ba36ca8e9 100644 --- a/src/nvim/testdir/test_diffmode.vim +++ b/src/nvim/testdir/test_diffmode.vim @@ -752,6 +752,9 @@ func Test_diff_of_diff() if !CanRunVimInTerminal() return endif + if !has("rightleft") + throw 'Skipped: rightleft not supported' + endif call writefile([ \ 'call setline(1, ["aa","bb","cc","@@ -3,2 +5,7 @@","dd","ee","ff"])', diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 28576709a3..a6ebd7b023 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -231,7 +231,7 @@ func Test_set_errors() call assert_fails('set backupcopy=', 'E474:') call assert_fails('set regexpengine=3', 'E474:') call assert_fails('set history=10001', 'E474:') - call assert_fails('set numberwidth=11', 'E474:') + call assert_fails('set numberwidth=21', 'E474:') call assert_fails('set colorcolumn=-a') call assert_fails('set colorcolumn=a') call assert_fails('set colorcolumn=1,') diff --git a/src/nvim/testdir/test_suspend.vim b/src/nvim/testdir/test_suspend.vim index e569e49055..efda68de9b 100644 --- a/src/nvim/testdir/test_suspend.vim +++ b/src/nvim/testdir/test_suspend.vim @@ -2,6 +2,20 @@ source shared.vim +func CheckSuspended(buf, fileExists) + call WaitForAssert({-> assert_match('[$#] $', term_getline(a:buf, '.'))}) + + if a:fileExists + call assert_equal(['foo'], readfile('Xfoo')) + else + " Without 'autowrite', buffer should not be written. + call assert_equal(0, filereadable('Xfoo')) + endif + + call term_sendkeys(a:buf, "fg\<CR>\<C-L>") + call WaitForAssert({-> assert_equal(' 1 foo', term_getline(a:buf, '.'))}) +endfunc + func Test_suspend() if !has('terminal') || !executable('/bin/sh') return @@ -26,13 +40,7 @@ func Test_suspend() \ "\<C-Z>"] " Suspend and wait for shell prompt. call term_sendkeys(buf, suspend_cmd) - call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))}) - - " Without 'autowrite', buffer should not be written. - call assert_equal(0, filereadable('Xfoo')) - - call term_sendkeys(buf, "fg\<CR>") - call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))}) + call CheckSuspended(buf, 0) endfor " Test that :suspend! with 'autowrite' writes content of buffers if modified. @@ -40,10 +48,7 @@ func Test_suspend() call assert_equal(0, filereadable('Xfoo')) call term_sendkeys(buf, ":suspend\<CR>") " Wait for shell prompt. - call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))}) - call assert_equal(['foo'], readfile('Xfoo')) - call term_sendkeys(buf, "fg\<CR>") - call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))}) + call CheckSuspended(buf, 1) " Quit gracefully to dump coverage information. call term_sendkeys(buf, ":qall!\<CR>") diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 7dbb8ec790..fc4a3a403d 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -341,15 +341,15 @@ void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol, flags, (const schar_T *)grid->chars + off, (const sattr_T *)grid->attrs + off); - if (p_wd) { // 'writedelay': flush & delay each time. - int old_row = cursor_row, old_col = cursor_col; - handle_T old_grid = cursor_grid_handle; + // 'writedelay': flush & delay each time. + if (p_wd && !(rdb_flags & RDB_COMPOSITOR)) { // If 'writedelay' is active, set the cursor to indicate what was drawn. - ui_grid_cursor_goto(grid->handle, row, MIN(clearcol, (int)Columns-1)); - ui_flush(); + ui_call_grid_cursor_goto(grid->handle, row, + MIN(clearcol, (int)grid->Columns-1)); + ui_call_flush(); uint64_t wd = (uint64_t)labs(p_wd); os_microdelay(wd * 1000u, true); - ui_grid_cursor_goto(old_grid, old_row, old_col); + pending_cursor_update = true; // restore the cursor later } } @@ -372,6 +372,14 @@ void ui_grid_cursor_goto(handle_T grid_handle, int new_row, int new_col) pending_cursor_update = true; } +/// moving the cursor grid will implicitly move the cursor +void ui_check_cursor_grid(handle_T grid_handle) +{ + if (cursor_grid_handle == grid_handle) { + pending_cursor_update = true; + } +} + void ui_mode_info_set(void) { pending_mode_info_update = true; diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index d12a411019..858ffbe5bc 100644 --- a/src/nvim/ui_compositor.c +++ b/src/nvim/ui_compositor.c @@ -49,6 +49,8 @@ static bool valid_screen = true; static bool msg_scroll_mode = false; static int msg_first_invalid = 0; +static int dbghl_normal, dbghl_clear, dbghl_composed, dbghl_recompose; + void ui_comp_init(void) { if (compositor != NULL) { @@ -81,6 +83,13 @@ void ui_comp_init(void) ui_attach_impl(compositor); } +void ui_comp_syn_init(void) +{ + dbghl_normal = syn_check_group((char_u *)S_LEN("RedrawDebugNormal")); + dbghl_clear = syn_check_group((char_u *)S_LEN("RedrawDebugClear")); + dbghl_composed = syn_check_group((char_u *)S_LEN("RedrawDebugComposed")); + dbghl_recompose = syn_check_group((char_u *)S_LEN("RedrawDebugRecompose")); +} void ui_comp_attach(UI *ui) { @@ -290,10 +299,14 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, { // in case we start on the right half of a double-width char, we need to // check the left half. But skip it in output if it wasn't doublewidth. - int skip = 0; + int skipstart = 0, skipend = 0; if (startcol > 0 && (flags & kLineFlagInvalid)) { startcol--; - skip = 1; + skipstart = 1; + } + if (endcol < default_grid.Columns && (flags & kLineFlagInvalid)) { + endcol++; + skipend = 1; } int col = (int)startcol; @@ -345,20 +358,27 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, if (linebuf[col-startcol][0] == NUL) { linebuf[col-startcol][0] = ' '; linebuf[col-startcol][1] = NUL; + if (col == endcol-1) { + skipend = 0; + } } else if (n > 1 && linebuf[col-startcol+1][0] == NUL) { - skip = 0; + skipstart = 0; } if (grid->comp_col+grid->Columns > until && grid->chars[off+n][0] == NUL) { linebuf[until-1-startcol][0] = ' '; linebuf[until-1-startcol][1] = '\0'; if (col == startcol && n == 1) { - skip = 0; + skipstart = 0; } } col = until; } + if (linebuf[endcol-startcol-1][0] == NUL) { + skipend = 0; + } + assert(endcol <= chk_width); assert(row < chk_height); @@ -368,14 +388,48 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, flags = flags & ~kLineFlagWrap; } - ui_composed_call_raw_line(1, row, startcol+skip, endcol, endcol, 0, flags, - (const schar_T *)linebuf+skip, - (const sattr_T *)attrbuf+skip); + ui_composed_call_raw_line(1, row, startcol+skipstart, + endcol-skipend, endcol-skipend, 0, flags, + (const schar_T *)linebuf+skipstart, + (const sattr_T *)attrbuf+skipstart); } +static void compose_debug(Integer startrow, Integer endrow, Integer startcol, + Integer endcol, int syn_id, bool delay) +{ + if (!(rdb_flags & RDB_COMPOSITOR)) { + return; + } + + endrow = MIN(endrow, default_grid.Rows); + endcol = MIN(endcol, default_grid.Columns); + int attr = syn_id2attr(syn_id); + + for (int row = (int)startrow; row < endrow; row++) { + ui_composed_call_raw_line(1, row, startcol, startcol, endcol, attr, false, + (const schar_T *)linebuf, + (const sattr_T *)attrbuf); + } + + + if (delay) { + debug_delay(endrow-startrow); + } +} + +static void debug_delay(Integer lines) +{ + ui_call_flush(); + uint64_t wd = (uint64_t)labs(p_wd); + uint64_t factor = (uint64_t)MAX(MIN(lines, 5), 1); + os_microdelay(factor * wd * 1000u, true); +} + + static void compose_area(Integer startrow, Integer endrow, Integer startcol, Integer endcol) { + compose_debug(startrow, endrow, startcol, endcol, dbghl_recompose, true); endrow = MIN(endrow, default_grid.Rows); endcol = MIN(endcol, default_grid.Columns); if (endcol <= startcol) { @@ -420,8 +474,11 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, if (flags & kLineFlagInvalid || kv_size(layers) > curgrid->comp_index+1 || curgrid->blending) { + compose_debug(row, row+1, startcol, clearcol, dbghl_composed, true); compose_line(row, startcol, clearcol, flags); } else { + compose_debug(row, row+1, startcol, endcol, dbghl_normal, false); + compose_debug(row, row+1, endcol, clearcol, dbghl_clear, true); ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr, flags, chunk, attrs); } @@ -481,6 +538,9 @@ static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top, } else { msg_first_invalid = MIN(msg_first_invalid, (int)top); ui_composed_call_grid_scroll(1, top, bot, left, right, rows, cols); + if (rdb_flags & RDB_COMPOSITOR) { + debug_delay(2); + } } } diff --git a/src/nvim/window.c b/src/nvim/window.c index a3b1efeaaa..6ce095f976 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -375,7 +375,7 @@ newwindow: /* set current window height */ case Ctrl__: case '_': - win_setheight(Prenum ? (int)Prenum : 9999); + win_setheight(Prenum ? (int)Prenum : Rows-1); break; /* increase current window width */ @@ -390,7 +390,7 @@ newwindow: /* set current window width */ case '|': - win_setwidth(Prenum != 0 ? (int)Prenum : 9999); + win_setwidth(Prenum != 0 ? (int)Prenum : Columns); break; /* jump to tag and split window if tag exists (in preview window) */ @@ -584,15 +584,43 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err) wp->w_status_height = 0; wp->w_vsep_width = 0; - // TODO(bfredl): use set_option_to() after merging #9110 ? - wp->w_p_nu = false; - wp->w_allbuf_opt.wo_nu = false; win_config_float(wp, fconfig); wp->w_pos_changed = true; redraw_win_later(wp, VALID); return wp; } +void win_set_minimal_style(win_T *wp) +{ + wp->w_p_nu = false; + wp->w_p_rnu = false; + wp->w_p_cul = false; + wp->w_p_cuc = false; + wp->w_p_spell = false; + wp->w_p_list = false; + + // Hide EOB region: use " " fillchar and cleared highlighting + if (wp->w_p_fcs_chars.eob != ' ') { + char_u *old = wp->w_p_fcs; + wp->w_p_fcs = ((*old == NUL) + ? (char_u *)xstrdup("eob: ") + : concat_str(old, (char_u *)",eob: ")); + xfree(old); + } + if (wp->w_hl_ids[HLF_EOB] != -1) { + char_u *old = wp->w_p_winhl; + wp->w_p_winhl = ((*old == NUL) + ? (char_u *)xstrdup("EndOfBuffer:") + : concat_str(old, (char_u *)",EndOfBuffer:")); + xfree(old); + } + + if (wp->w_p_scl[0] != 'a') { + xfree(wp->w_p_scl); + wp->w_p_scl = (char_u *)xstrdup("auto"); + } +} + void win_config_float(win_T *wp, FloatConfig fconfig) { wp->w_width = MAX(fconfig.width, 1); @@ -666,6 +694,7 @@ static void ui_ext_win_position(win_T *wp) bool on_top = (curwin == wp) || !curwin->w_floating; ui_comp_put_grid(&wp->w_grid, comp_row, comp_col, wp->w_height, wp->w_width, valid, on_top); + ui_check_cursor_grid(wp->w_grid.handle); if (!valid) { wp->w_grid.valid = false; redraw_win_later(wp, NOT_VALID); @@ -821,6 +850,20 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf, "'focusable' key must be Boolean"); return false; } + } else if (!strcmp(key, "style")) { + if (val.type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, + "'style' key must be String"); + return false; + } + if (val.data.string.data[0] == NUL) { + fconfig->style = kWinStyleUnused; + } else if (striequal(val.data.string.data, "minimal")) { + fconfig->style = kWinStyleMinimal; + } else { + api_set_error(err, kErrorTypeValidation, + "Invalid value of 'style' key"); + } } else { api_set_error(err, kErrorTypeValidation, "Invalid key '%s'", key); @@ -4823,13 +4866,9 @@ void win_setheight_win(int height, win_T *win) } if (win->w_floating) { - if (win->w_float_config.external) { - win->w_float_config.height = height; - win_config_float(win, win->w_float_config); - } else { - beep_flush(); - return; - } + win->w_float_config.height = height; + win_config_float(win, win->w_float_config); + redraw_win_later(win, NOT_VALID); } else { frame_setheight(win->w_frame, height + win->w_status_height); @@ -4844,9 +4883,9 @@ void win_setheight_win(int height, win_T *win) cmdline_row = row; msg_row = row; msg_col = 0; + redraw_all_later(NOT_VALID); } - redraw_all_later(NOT_VALID); } @@ -5029,21 +5068,17 @@ void win_setwidth_win(int width, win_T *wp) width = 1; } if (wp->w_floating) { - if (wp->w_float_config.external) { - wp->w_float_config.width = width; - win_config_float(wp, wp->w_float_config); - } else { - beep_flush(); - return; - } + wp->w_float_config.width = width; + win_config_float(wp, wp->w_float_config); + redraw_win_later(wp, NOT_VALID); } else { frame_setwidth(wp->w_frame, width + wp->w_vsep_width); // recompute the window positions (void)win_comp_pos(); + redraw_all_later(NOT_VALID); } - redraw_all_later(NOT_VALID); } /* |