diff options
26 files changed, 337 insertions, 89 deletions
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 1a1b4f5ed5..40abb4209a 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -415,6 +415,8 @@ The following changes to existing APIs or features add new behavior. • 'errorfile' (|-q|) accepts `-` as an alias for stdin. +• |--startuptime| reports the startup times for both processes (TUI + server) as separate sections. + ============================================================================== REMOVED FEATURES *news-removed* diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index 8b29727196..f46ab8023f 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -1535,7 +1535,7 @@ function vim.api.nvim_open_term(buffer, opts) end --- --- @param buffer integer Buffer to display, or 0 for current buffer --- @param enter boolean Enter the window (make it the current window) ---- @param config vim.api.keyset.float_config Map defining the window configuration. Keys: +--- @param config vim.api.keyset.win_config Map defining the window configuration. Keys: --- • relative: Sets the window layout to "floating", placed at --- (row,col) coordinates relative to: --- • "editor" The global editor grid @@ -2093,7 +2093,7 @@ function vim.api.nvim_win_set_buf(window, buffer) end --- changed. `row`/`col` and `relative` must be reconfigured together. --- --- @param window integer Window handle, or 0 for current window ---- @param config vim.api.keyset.float_config Map defining the window configuration, see `nvim_open_win()` +--- @param config vim.api.keyset.win_config Map defining the window configuration, see `nvim_open_win()` function vim.api.nvim_win_set_config(window, config) end --- Sets the (1,0)-indexed cursor position in the window. `api-indexing` This diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua index 1b6c6811a2..0442a89e3f 100644 --- a/runtime/lua/vim/_meta/api_keysets.lua +++ b/runtime/lua/vim/_meta/api_keysets.lua @@ -111,30 +111,6 @@ error('Cannot require a meta file') --- @class vim.api.keyset.exec_opts --- @field output? boolean ---- @class vim.api.keyset.float_config ---- @field row? number ---- @field col? number ---- @field width? integer ---- @field height? integer ---- @field anchor? string ---- @field relative? string ---- @field split? string ---- @field win? integer ---- @field bufpos? any[] ---- @field external? boolean ---- @field focusable? boolean ---- @field vertical? boolean ---- @field zindex? integer ---- @field border? any ---- @field title? any ---- @field title_pos? string ---- @field footer? any ---- @field footer_pos? string ---- @field style? string ---- @field noautocmd? boolean ---- @field fixed? boolean ---- @field hide? boolean - --- @class vim.api.keyset.get_autocmds --- @field event? any --- @field group? any @@ -292,6 +268,30 @@ error('Cannot require a meta file') --- @field range? any --- @field register? boolean +--- @class vim.api.keyset.win_config +--- @field row? number +--- @field col? number +--- @field width? integer +--- @field height? integer +--- @field anchor? string +--- @field relative? string +--- @field split? string +--- @field win? integer +--- @field bufpos? any[] +--- @field external? boolean +--- @field focusable? boolean +--- @field vertical? boolean +--- @field zindex? integer +--- @field border? any +--- @field title? any +--- @field title_pos? string +--- @field footer? any +--- @field footer_pos? string +--- @field style? string +--- @field noautocmd? boolean +--- @field fixed? boolean +--- @field hide? boolean + --- @class vim.api.keyset.win_text_height --- @field start_row? integer --- @field end_row? integer diff --git a/src/clint.py b/src/clint.py index 78eabb698f..062901b43a 100755 --- a/src/clint.py +++ b/src/clint.py @@ -152,8 +152,10 @@ _ERROR_CATEGORIES = [ 'build/endif_comment', 'build/header_guard', 'build/include_defs', + 'build/defs_header', 'build/printf_format', 'build/storage_class', + 'build/init_macro', 'readability/bool', 'readability/multiline_comment', 'readability/multiline_string', @@ -2086,6 +2088,11 @@ def CheckLanguage(filename, clean_lines, linenum, error): " named ('k' followed by CamelCase) compile-time constant for" " the size.") + # INIT() macro should only be used in header files. + if not filename.endswith('.h') and Search(r' INIT\(', line): + error(filename, linenum, 'build/init_macro', 4, + 'INIT() macro should only be used in header files.') + # Detect TRUE and FALSE. match = Search(r'\b(TRUE|FALSE)\b', line) if match: diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h index 2f1b38d1e5..0ba33ca9a7 100644 --- a/src/nvim/api/keysets_defs.h +++ b/src/nvim/api/keysets_defs.h @@ -108,7 +108,7 @@ typedef struct { } Dict(user_command); typedef struct { - OptionalKeys is_set__float_config_; + OptionalKeys is_set__win_config_; Float row; Float col; Integer width; @@ -131,7 +131,7 @@ typedef struct { Boolean noautocmd; Boolean fixed; Boolean hide; -} Dict(float_config); +} Dict(win_config); typedef struct { Boolean is_lua; diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 8e299d264c..8841bd225b 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -200,10 +200,10 @@ /// @param[out] err Error details, if any /// /// @return Window handle, or 0 on error -Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, Error *err) +Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Error *err) FUNC_API_SINCE(6) FUNC_API_TEXTLOCK_ALLOW_CMDWIN { -#define HAS_KEY_X(d, key) HAS_KEY(d, float_config, key) +#define HAS_KEY_X(d, key) HAS_KEY(d, win_config, key) buf_T *buf = find_buffer_by_handle(buffer, err); if (!buf) { return 0; @@ -213,7 +213,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, E return 0; } - FloatConfig fconfig = FLOAT_CONFIG_INIT; + WinConfig fconfig = WIN_CONFIG_INIT; if (!parse_float_config(config, &fconfig, false, true, err)) { return 0; } @@ -332,10 +332,10 @@ static int win_split_flags(WinSplit split, bool toplevel) /// @param config Map defining the window configuration, /// see |nvim_open_win()| /// @param[out] err Error details, if any -void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err) +void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) FUNC_API_SINCE(6) { -#define HAS_KEY_X(d, key) HAS_KEY(d, float_config, key) +#define HAS_KEY_X(d, key) HAS_KEY(d, win_config, key) win_T *win = find_window_by_handle(window, err); if (!win) { return; @@ -345,7 +345,7 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err) bool has_split = HAS_KEY_X(config, split); bool has_vertical = HAS_KEY_X(config, vertical); // reuse old values, if not overridden - FloatConfig fconfig = win->w_float_config; + WinConfig fconfig = win->w_float_config; bool to_split = config->relative.size == 0 && !(HAS_KEY_X(config, external) ? config->external : fconfig.external) @@ -539,8 +539,8 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err) #undef HAS_KEY_X } -#define PUT_KEY_X(d, key, value) PUT_KEY(d, float_config, key, value) -static void config_put_bordertext(Dict(float_config) *config, FloatConfig *fconfig, +#define PUT_KEY_X(d, key, value) PUT_KEY(d, win_config, key, value) +static void config_put_bordertext(Dict(win_config) *config, WinConfig *fconfig, BorderTextType bordertext_type, Arena *arena) { VirtText vt; @@ -591,7 +591,7 @@ static void config_put_bordertext(Dict(float_config) *config, FloatConfig *fconf /// @param window Window handle, or 0 for current window /// @param[out] err Error details, if any /// @return Map defining the window configuration, see |nvim_open_win()| -Dict(float_config) nvim_win_get_config(Window window, Arena *arena, Error *err) +Dict(win_config) nvim_win_get_config(Window window, Arena *arena, Error *err) FUNC_API_SINCE(6) { /// Keep in sync with FloatRelative in buffer_defs.h @@ -600,14 +600,14 @@ Dict(float_config) nvim_win_get_config(Window window, Arena *arena, Error *err) /// Keep in sync with WinSplit in buffer_defs.h static const char *const win_split_str[] = { "left", "right", "above", "below" }; - Dict(float_config) rv = { 0 }; + Dict(win_config) rv = { 0 }; win_T *wp = find_window_by_handle(window, err); if (!wp) { return rv; } - FloatConfig *config = &wp->w_float_config; + WinConfig *config = &wp->w_float_config; PUT_KEY_X(rv, focusable, config->focusable); PUT_KEY_X(rv, external, config->external); @@ -734,8 +734,8 @@ static bool parse_float_bufpos(Array bufpos, lpos_T *out) return true; } -static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, - FloatConfig *fconfig, Error *err) +static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, WinConfig *fconfig, + Error *err) { if (bordertext.type != kObjectTypeString && bordertext.type != kObjectTypeArray) { api_set_error(err, kErrorTypeValidation, "title/footer must be string or array"); @@ -793,7 +793,7 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, } static bool parse_bordertext_pos(String bordertext_pos, BorderTextType bordertext_type, - FloatConfig *fconfig, Error *err) + WinConfig *fconfig, Error *err) { AlignTextPos *align; switch (bordertext_type) { @@ -832,7 +832,7 @@ static bool parse_bordertext_pos(String bordertext_pos, BorderTextType bordertex return true; } -static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) +static void parse_border_style(Object style, WinConfig *fconfig, Error *err) { struct { const char *name; @@ -937,10 +937,10 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) } } -static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, bool reconf, +static bool parse_float_config(Dict(win_config) *config, WinConfig *fconfig, bool reconf, bool new_win, Error *err) { -#define HAS_KEY_X(d, key) HAS_KEY(d, float_config, key) +#define HAS_KEY_X(d, key) HAS_KEY(d, win_config, key) bool has_relative = false, relative_is_win = false, is_split = false; if (config->relative.size > 0) { if (!parse_float_relative(config->relative, &fconfig->relative)) { diff --git a/src/nvim/arglist.c b/src/nvim/arglist.c index e9108f72cc..a02c22deae 100644 --- a/src/nvim/arglist.c +++ b/src/nvim/arglist.c @@ -1093,11 +1093,6 @@ static void do_arg_all(int count, int forceit, int keep_tabs) // When the ":tab" modifier was used do this for all tab pages. arg_all_close_unused_windows(&aall); - // Now set the last used tabpage to where we started. - if (valid_tabpage(new_lu_tp)) { - lastused_tabpage = new_lu_tp; - } - // Open a window for files in the argument list that don't have one. // ARGCOUNT may change while doing this, because of autocommands. if (count > aall.opened_len || count <= 0) { @@ -1134,6 +1129,12 @@ static void do_arg_all(int count, int forceit, int keep_tabs) if (valid_tabpage(aall.new_curtab)) { goto_tabpage_tp(aall.new_curtab, true, true); } + + // Now set the last used tabpage to where we started. + if (valid_tabpage(new_lu_tp)) { + lastused_tabpage = new_lu_tp; + } + if (win_valid(aall.new_curwin)) { win_enter(aall.new_curwin, false); } diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index ea014c3918..adbece20f2 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -941,19 +941,19 @@ typedef struct { bool noautocmd; bool fixed; bool hide; -} FloatConfig; - -#define FLOAT_CONFIG_INIT ((FloatConfig){ .height = 0, .width = 0, \ - .bufpos = { -1, 0 }, \ - .row = 0, .col = 0, .anchor = 0, \ - .relative = 0, .external = false, \ - .focusable = true, \ - .split = 0, \ - .zindex = kZIndexFloatDefault, \ - .style = kWinStyleUnused, \ - .noautocmd = false, \ - .hide = false, \ - .fixed = false }) +} WinConfig; + +#define WIN_CONFIG_INIT ((WinConfig){ .height = 0, .width = 0, \ + .bufpos = { -1, 0 }, \ + .row = 0, .col = 0, .anchor = 0, \ + .relative = 0, .external = false, \ + .focusable = true, \ + .split = 0, \ + .zindex = kZIndexFloatDefault, \ + .style = kWinStyleUnused, \ + .noautocmd = false, \ + .hide = false, \ + .fixed = false }) // Structure to store last cursor position and topline. Used by check_lnums() // and reset_lnums(). @@ -1278,7 +1278,7 @@ struct window_S { bool w_pos_changed; // true if window position changed bool w_floating; ///< whether the window is floating bool w_float_is_info; // the floating window is info float - FloatConfig w_float_config; + WinConfig w_float_config; // w_fraction is the fractional row of the cursor within the window, from // 0 at the top row to FRACTION_MULT at the last row. diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 41df039b85..b7b32883c2 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -363,7 +363,13 @@ static void insert_enter(InsertState *s) ins_apply_autocmds(EVENT_INSERTLEAVE); } did_cursorhold = false; - curbuf->b_last_changedtick = buf_get_changedtick(curbuf); + + // ins_redraw() triggers TextChangedI only when no characters + // are in the typeahead buffer, so only reset curbuf->b_last_changedtick + // if the TextChangedI was not blocked by char_avail() (e.g. using :norm!) + if (!char_avail()) { + curbuf->b_last_changedtick = buf_get_changedtick(curbuf); + } } static int insert_check(VimState *state) diff --git a/src/nvim/globals.h b/src/nvim/globals.h index a06e9fe542..bcac32a252 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -979,6 +979,8 @@ EXTERN const char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP" EXTERN const char line_msg[] INIT(= N_(" line ")); EXTERN FILE *time_fd INIT(= NULL); // where to write startup timing +#define STARTUP_TIME_BUF_SIZE 8192 +EXTERN char *startuptime_buf INIT(= NULL); // --startuptime buffer // Some compilers warn for not using a return value, but in some situations we // can't do anything useful with the value. Assign to this variable to avoid diff --git a/src/nvim/main.c b/src/nvim/main.c index f858313682..f2893dc9e3 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -399,6 +399,7 @@ int main(int argc, char **argv) } if (ui_client_channel_id) { + time_finish(); ui_client_run(remote_ui); // NORETURN } assert(!ui_client_channel_id && !use_builtin_ui); @@ -695,6 +696,9 @@ void getout(int exitval) assert(!ui_client_channel_id); exiting = true; + // make sure startuptimes have been flushed + time_finish(); + // On error during Ex mode, exit with a non-zero code. // POSIX requires this, although it's not 100% clear from the standard. if (exmode_active) { @@ -1495,9 +1499,16 @@ static void init_params(mparm_T *paramp, int argc, char **argv) /// Initialize global startuptime file if "--startuptime" passed as an argument. static void init_startuptime(mparm_T *paramp) { + bool is_embed = false; + for (int i = 1; i < paramp->argc - 1; i++) { + if (STRICMP(paramp->argv[i], "--embed") == 0) { + is_embed = true; + break; + } + } for (int i = 1; i < paramp->argc - 1; i++) { if (STRICMP(paramp->argv[i], "--startuptime") == 0) { - time_fd = fopen(paramp->argv[i + 1], "a"); + time_init(paramp->argv[i + 1], is_embed ? "Embedded" : "Primary/TUI"); time_start("--- NVIM STARTING ---"); break; } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 9966e6129c..8b6ef62873 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1451,9 +1451,7 @@ static int normal_check(VimState *state) // has been done, close any file for startup messages. if (time_fd != NULL) { TIME_MSG("first screen update"); - TIME_MSG("--- NVIM STARTED ---"); - fclose(time_fd); - time_fd = NULL; + time_finish(); } // After the first screen update may start triggering WinScrolled // autocmd events. Store all the scroll positions and sizes now. diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index e24ebec458..d116b46d88 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -669,7 +669,7 @@ void pum_redraw(void) /// @return NULL when no enough room to show static win_T *pum_create_float_preview(bool enter) { - FloatConfig config = FLOAT_CONFIG_INIT; + WinConfig config = WIN_CONFIG_INIT; config.relative = kFloatRelativeEditor; // when pum_above is SW otherwise is NW config.anchor = pum_above ? kFloatAnchorSouth : 0; diff --git a/src/nvim/profile.c b/src/nvim/profile.c index f7776ef74f..84b58de4a3 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -907,7 +907,7 @@ void time_start(const char *message) // initialize the global variables g_prev_time = g_start_time = profile_start(); - fprintf(time_fd, "\n\ntimes in msec\n"); + fprintf(time_fd, "\ntimes in msec\n"); fprintf(time_fd, " clock self+sourced self: sourced script\n"); fprintf(time_fd, " clock elapsed: other lines\n\n"); @@ -944,3 +944,49 @@ void time_msg(const char *mesg, const proftime_T *start) g_prev_time = now; fprintf(time_fd, ": %s\n", mesg); } + +/// Initializes the time time_fd stream used to write startup times +/// +/// @param startup_time_file the startuptime report file path +/// @param process_name the name of the current process to write in the report. +void time_init(const char *startup_time_file, const char *process_name) +{ + time_fd = fopen(startup_time_file, "a"); + if (time_fd == NULL) { + semsg(_(e_notopen), startup_time_file); + return; + } + startuptime_buf = xmalloc(sizeof(char) * (STARTUP_TIME_BUF_SIZE + 1)); + // The startuptime file is (potentially) written by multiple nvim processes concurrently. So + // startuptime info is buffered, and flushed to disk only after startup completed. To achieve that + // we set a buffer big enough to store all startup times. The `_IOFBF` mode ensures the buffer is + // not auto-flushed ("controlled buffering"). + // The times are flushed to disk manually when "time_finish" is called. + int r = setvbuf(time_fd, startuptime_buf, _IOFBF, STARTUP_TIME_BUF_SIZE + 1); + if (r != 0) { + xfree(startuptime_buf); + fclose(time_fd); + time_fd = NULL; + // Might as well ELOG also I guess. + ELOG("time_init: setvbuf failed: %d %s", r, uv_err_name(r)); + semsg("time_init: setvbuf failed: %d %s", r, uv_err_name(r)); + return; + } + fprintf(time_fd, "--- Startup times for process: %s ---\n", process_name); +} + +/// Flushes the startuptimes to disk for the current process +void time_finish(void) +{ + if (time_fd == NULL) { + return; + } + assert(startuptime_buf != NULL); + TIME_MSG("--- NVIM STARTED ---\n"); + + // flush buffer to disk + fclose(time_fd); + time_fd = NULL; + + XFREE_CLEAR(startuptime_buf); +} diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 5b4d4191b9..9caacd8115 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -55,8 +55,8 @@ # include "sign.c.generated.h" #endif -static PMap(cstr_t) sign_map INIT( = MAP_INIT); -static kvec_t(Integer) sign_ns INIT( = MAP_INIT); +static PMap(cstr_t) sign_map = MAP_INIT; +static kvec_t(Integer) sign_ns = KV_INITIAL_VALUE; static char *cmds[] = { "define", diff --git a/src/nvim/window.c b/src/nvim/window.c index 06d2bcac0d..a188d75000 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -669,7 +669,7 @@ wingotofile: beep_flush(); break; } - FloatConfig config = FLOAT_CONFIG_INIT; + WinConfig config = WIN_CONFIG_INIT; config.width = curwin->w_width; config.height = curwin->w_height; config.external = true; @@ -763,7 +763,7 @@ void ui_ext_win_position(win_T *wp, bool validate) return; } - FloatConfig c = wp->w_float_config; + WinConfig c = wp->w_float_config; if (!c.external) { ScreenGrid *grid = &default_grid; Float row = c.row; @@ -1213,7 +1213,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) new_frame(wp); wp->w_floating = false; // non-floating window doesn't store float config or have a border. - wp->w_float_config = FLOAT_CONFIG_INIT; + wp->w_float_config = WIN_CONFIG_INIT; CLEAR_FIELD(wp->w_border_adj); } @@ -3879,7 +3879,7 @@ void win_alloc_first(void) void win_alloc_aucmd_win(int idx) { Error err = ERROR_INIT; - FloatConfig fconfig = FLOAT_CONFIG_INIT; + WinConfig fconfig = WIN_CONFIG_INIT; fconfig.width = Columns; fconfig.height = 5; fconfig.focusable = false; @@ -4983,7 +4983,7 @@ win_T *win_alloc(win_T *after, bool hidden) new_wp->w_cursor.lnum = 1; new_wp->w_scbind_pos = 1; new_wp->w_floating = 0; - new_wp->w_float_config = FLOAT_CONFIG_INIT; + new_wp->w_float_config = WIN_CONFIG_INIT; new_wp->w_viewport_invalid = true; new_wp->w_viewport_last_topline = 1; diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index 1d22590ac0..f22c0f3cfa 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -38,7 +38,7 @@ /// @param last make the window the last one in the window list. /// Only used when allocating the autocommand window. /// @param config must already have been validated! -win_T *win_new_float(win_T *wp, bool last, FloatConfig fconfig, Error *err) +win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err) { if (wp == NULL) { wp = win_alloc(last ? lastwin : lastwin_nofloating(), false); @@ -138,7 +138,7 @@ int win_border_width(win_T *wp) return wp->w_border_adj[1] + wp->w_border_adj[3]; } -void win_config_float(win_T *wp, FloatConfig fconfig) +void win_config_float(win_T *wp, WinConfig fconfig) { wp->w_width = MAX(fconfig.width, 1); wp->w_height = MAX(fconfig.height, 1); diff --git a/test/functional/autocmd/textchanged_spec.lua b/test/functional/autocmd/textchanged_spec.lua index 850d67a18d..d501560dc1 100644 --- a/test/functional/autocmd/textchanged_spec.lua +++ b/test/functional/autocmd/textchanged_spec.lua @@ -180,3 +180,14 @@ it('TextChangedI and TextChanged', function() validate_mixed_textchangedi({ 's', '<esc>' }) validate_mixed_textchangedi({ 'S', '<esc>' }) end) + +-- oldtest: Test_TextChanged_with_norm() +it('TextChanged is triggered after :norm that enters Insert mode', function() + exec([[ + let g:a = 0 + au TextChanged * let g:a += 1 + ]]) + eq(0, eval('g:a')) + feed(':norm! ia<CR>') + eq(1, eval('g:a')) +end) diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index f4a9c0c8d7..cc58226f48 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -73,6 +73,7 @@ describe('startup', function() os.remove(testfile) end) clear({ args = { '--startuptime', testfile } }) + assert_log('Embedded', testfile, 100) assert_log('sourcing', testfile, 100) assert_log("require%('vim%._editor'%)", testfile, 100) end) diff --git a/test/functional/legacy/listlbr_utf8_spec.lua b/test/functional/legacy/listlbr_utf8_spec.lua index d7f4c71af2..2788e7ae9f 100644 --- a/test/functional/legacy/listlbr_utf8_spec.lua +++ b/test/functional/legacy/listlbr_utf8_spec.lua @@ -1,12 +1,14 @@ -- Test for linebreak and list option in utf-8 mode local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local source = helpers.source local feed = helpers.feed +local exec = helpers.exec local clear, expect = helpers.clear, helpers.expect describe('linebreak', function() - setup(clear) + before_each(clear) -- luacheck: ignore 621 (Indentation) -- luacheck: ignore 613 (Trailing whitespaces in a string) @@ -208,4 +210,29 @@ describe('linebreak', function() a b c¶ Screen attributes are the same!]]) end) + + -- oldtest: Test_visual_ends_before_showbreak() + it("Visual area is correct when it ends before multibyte 'showbreak'", function() + local screen = Screen.new(60, 8) + screen:set_default_attr_ids({ + [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText + [1] = { background = Screen.colors.LightGrey }, -- Visual + [2] = { bold = true }, -- ModeMsg + }) + screen:attach() + exec([[ + let &wrap = v:true + let &linebreak = v:true + let &showbreak = '↪ ' + eval ['xxxxx ' .. 'y'->repeat(&columns - 6) .. ' zzzz']->setline(1) + normal! wvel + ]]) + screen:expect([[ + xxxxx | + {0:↪ }{1:yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy}^ {1: }| + {0:↪ }zzzz | + {0:~ }|*4 + {2:-- VISUAL --} | + ]]) + end) end) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 9dd5b00b83..d63338845a 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -655,6 +655,20 @@ describe('TUI', function() end screen:expect_unchanged() if esc then + feed_data('\027[<64;5;1M') + else + api.nvim_input_mouse('wheel', 'up', '', 0, 0, 4) + end + screen:expect([[ + {1:p}opup menu test | + {4:~ }{14: foo }{4: }| + {4:~ }{13: bar }{4: }| + {4:~ }{13: baz }{4: }| + {5:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + if esc then feed_data('\027[<35;7;4M') else api.nvim_input_mouse('move', '', '', 0, 3, 6) @@ -669,6 +683,20 @@ describe('TUI', function() {3:-- TERMINAL --} | ]]) if esc then + feed_data('\027[<65;7;4M') + else + api.nvim_input_mouse('wheel', 'down', '', 0, 3, 6) + end + screen:expect([[ + {1:p}opup menu test | + {4:~ }{13: foo }{4: }| + {4:~ }{14: bar }{4: }| + {4:~ }{13: baz }{4: }| + {5:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + if esc then feed_data('\027[<0;7;3M') else api.nvim_input_mouse('left', 'press', '', 0, 2, 6) diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 6a1b3fb0ed..7f551c5ee5 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -188,6 +188,9 @@ describe('ui/mouse/input', function() | ]]) feed('<LeftMouse><11,0>') + -- Prevent the case where screen:expect() with "unchanged" returns too early, + -- causing the click position to be overwritten by the next drag. + poke_eventloop() screen:expect { grid = [[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| @@ -282,6 +285,9 @@ describe('ui/mouse/input', function() | ]]) feed('<LeftMouse><11,0>') + -- Prevent the case where screen:expect() with "unchanged" returns too early, + -- causing the click position to be overwritten by the next drag. + poke_eventloop() screen:expect { grid = [[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 1f7d187016..1f0d20f66d 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -3784,9 +3784,7 @@ describe('builtin popupmenu', function() {n: bar }| {n: baz }| ]], - float_pos = { - [4] = { -1, 'NW', 2, 1, 17, false, 250 }, - }, + float_pos = { [4] = { -1, 'NW', 2, 1, 17, false, 250 } }, } else feed('<RightMouse><18,0>') @@ -3969,7 +3967,38 @@ describe('builtin popupmenu', function() end eq(true, screen.options.mousemoveevent) if multigrid then - api.nvim_input_mouse('move', '', '', 2, 3, 6) + api.nvim_input_mouse('wheel', 'up', '', 2, 0, 4) + screen:expect({ + grid = [[ + ## grid 1 + [2:--------------------------------]|*5 + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }|*4 + ## grid 3 + :let g:menustr = 'foo' | + ## grid 4 + {s: foo }| + {n: bar }| + {n: baz }| + ]], + float_pos = { [4] = { -1, 'NW', 2, 1, 3, false, 250 } }, + }) + else + feed('<ScrollWheelUp><4,0>') + screen:expect([[ + ^popup menu test | + {1:~ }{s: foo }{1: }| + {1:~ }{n: bar }{1: }| + {1:~ }{n: baz }{1: }| + {1:~ }| + :let g:menustr = 'foo' | + ]]) + end + eq(true, screen.options.mousemoveevent) + if multigrid then + api.nvim_input_mouse('move', '', '', 4, 2, 3) screen:expect({ grid = [[ ## grid 1 @@ -4000,7 +4029,38 @@ describe('builtin popupmenu', function() end eq(true, screen.options.mousemoveevent) if multigrid then - api.nvim_input_mouse('left', 'press', '', 2, 2, 6) + api.nvim_input_mouse('wheel', 'down', '', 4, 2, 3) + screen:expect({ + grid = [[ + ## grid 1 + [2:--------------------------------]|*5 + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }|*4 + ## grid 3 + :let g:menustr = 'foo' | + ## grid 4 + {n: foo }| + {s: bar }| + {n: baz }| + ]], + float_pos = { [4] = { -1, 'NW', 2, 1, 3, false, 250 } }, + }) + else + feed('<ScrollWheelDown><6,3>') + screen:expect([[ + ^popup menu test | + {1:~ }{n: foo }{1: }| + {1:~ }{s: bar }{1: }| + {1:~ }{n: baz }{1: }| + {1:~ }| + :let g:menustr = 'foo' | + ]]) + end + eq(true, screen.options.mousemoveevent) + if multigrid then + api.nvim_input_mouse('left', 'press', '', 4, 1, 3) screen:expect({ grid = [[ ## grid 1 diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index 7926411dcd..0a28ae6147 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -2533,7 +2533,25 @@ func Test_TextChangedI_with_setline() call assert_equal('', getline(1)) call assert_equal('', getline(2)) - call test_override('starting', 0) + call test_override('char_avail', 0) + bwipe! +endfunc + +func Test_TextChanged_with_norm() + " For unknown reason this fails on MS-Windows + CheckNotMSWindows + CheckFeature terminal + let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3}) + call assert_equal('running', term_getstatus(buf)) + call term_sendkeys(buf, ":let g:a=0\<cr>") + call term_wait(buf, 50) + call term_sendkeys(buf, ":au! TextChanged * :let g:a+=1\<cr>") + call term_wait(buf, 50) + call term_sendkeys(buf, ":norm! ia\<cr>") + call term_wait(buf, 50) + call term_sendkeys(buf, ":echo g:a\<cr>") + call term_wait(buf, 50) + call WaitForAssert({-> assert_match('^1.*$', term_getline(buf, 3))}) bwipe! endfunc diff --git a/test/old/testdir/test_listlbr_utf8.vim b/test/old/testdir/test_listlbr_utf8.vim index 1bbbd2d2ae..313ff30cc4 100644 --- a/test/old/testdir/test_listlbr_utf8.vim +++ b/test/old/testdir/test_listlbr_utf8.vim @@ -9,6 +9,7 @@ CheckFeature conceal CheckFeature signs source view_util.vim +source screendump.vim func s:screen_lines(lnum, width) abort return ScreenLines(a:lnum, a:width) @@ -358,4 +359,24 @@ func Test_unprintable_char_on_wrap_column() call s:close_windows() endfunc +" Test that Visual selection is drawn correctly when 'linebreak' is set and +" selection ends before multibyte 'showbreak'. +func Test_visual_ends_before_showbreak() + CheckScreendump + + let lines =<< trim END + vim9script + &wrap = true + &linebreak = true + &showbreak = '↪ ' + ['xxxxx ' .. 'y'->repeat(&columns - 6) .. ' zzzz']->setline(1) + normal! wvel + END + call writefile(lines, 'XvisualEndsBeforeShowbreak', 'D') + let buf = RunVimInTerminal('-S XvisualEndsBeforeShowbreak', #{rows: 6}) + call VerifyScreenDump(buf, 'Test_visual_ends_before_showbreak', {}) + + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_tabpage.vim b/test/old/testdir/test_tabpage.vim index d335f3c1ee..adb9e13269 100644 --- a/test/old/testdir/test_tabpage.vim +++ b/test/old/testdir/test_tabpage.vim @@ -156,10 +156,13 @@ func Test_tabpage_drop() tab split f3 normal! gt call assert_equal(1, tabpagenr()) + tab drop f4 + call assert_equal(1, tabpagenr('#')) tab drop f3 - call assert_equal(3, tabpagenr()) - call assert_equal(1, tabpagenr('#')) + call assert_equal(4, tabpagenr()) + call assert_equal(2, tabpagenr('#')) + bwipe! bwipe! bwipe! bwipe! |