diff options
author | Lewis Russell <lewis6991@gmail.com> | 2025-01-08 17:56:21 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-08 17:56:21 +0000 |
commit | c4b658fed8d96a4c4098ce59b01b228ef0bda62e (patch) | |
tree | 50f10b101e425a04c646d5970eed88a4318f2069 | |
parent | 17b46d01e29443452ae8b607017f8f5c585d3f0a (diff) | |
parent | 6257270040bc5c61a489f7fb9d4102223c36cf89 (diff) | |
download | rneovim-c4b658fed8d96a4c4098ce59b01b228ef0bda62e.tar.gz rneovim-c4b658fed8d96a4c4098ce59b01b228ef0bda62e.tar.bz2 rneovim-c4b658fed8d96a4c4098ce59b01b228ef0bda62e.zip |
Merge pull request #31112 from famiu/refactor/options/set_option_for
refactor(options): set option value for non-current context directly
-rw-r--r-- | src/nvim/api/deprecated.c | 10 | ||||
-rw-r--r-- | src/nvim/api/options.c | 12 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 8 | ||||
-rw-r--r-- | src/nvim/autocmd.c | 172 | ||||
-rw-r--r-- | src/nvim/autocmd_defs.h | 22 | ||||
-rw-r--r-- | src/nvim/diff.c | 4 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 2 | ||||
-rw-r--r-- | src/nvim/insexpand.c | 6 | ||||
-rw-r--r-- | src/nvim/option.c | 760 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 18 | ||||
-rw-r--r-- | src/nvim/optionstr.c | 60 | ||||
-rw-r--r-- | src/nvim/tag.c | 2 | ||||
-rw-r--r-- | src/nvim/winfloat.c | 4 | ||||
-rw-r--r-- | test/functional/lua/with_spec.lua | 6 |
14 files changed, 529 insertions, 557 deletions
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index d5eddb74de..47a49436ab 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -649,8 +649,8 @@ static Object get_option_from(void *from, OptScope scope, String name, Error *er OptVal value = NIL_OPTVAL; if (option_has_scope(opt_idx, scope)) { - value = get_option_value_for(opt_idx, scope == kOptScopeGlobal ? OPT_GLOBAL : OPT_LOCAL, - scope, from, err); + value = get_option_value_from(opt_idx, option_ctx_from(scope, from), + scope == kOptScopeGlobal ? OPT_GLOBAL : OPT_LOCAL); if (ERROR_SET(err)) { return (Object)OBJECT_INIT; } @@ -701,7 +701,11 @@ static void set_option_to(uint64_t channel_id, void *to, OptScope scope, String : ((scope == kOptScopeGlobal) ? OPT_GLOBAL : OPT_LOCAL); WITH_SCRIPT_CONTEXT(channel_id, { - set_option_value_for(name.data, opt_idx, optval, opt_flags, scope, to, err); + const char *errmsg + = set_option_value_for(opt_idx, optval, option_ctx_from(scope, to), opt_flags); + if (errmsg) { + api_set_error(err, kErrorTypeException, "%s", errmsg); + } }); } diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 64f8a35d54..2bbbdbbe8c 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -157,8 +157,8 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) void *from = NULL; char *filetype = NULL; - if (!validate_option_value_args(opts, name.data, &opt_idx, &opt_flags, &scope, &from, - &filetype, err)) { + if (!validate_option_value_args(opts, name.data, &opt_idx, &opt_flags, &scope, &from, &filetype, + err)) { return (Object)OBJECT_INIT; } @@ -182,7 +182,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) from = ftbuf; } - OptVal value = get_option_value_for(opt_idx, opt_flags, scope, from, err); + OptVal value = get_option_value_from(opt_idx, option_ctx_from(scope, from), opt_flags); if (ftbuf != NULL) { // restore curwin/curbuf and a few other things @@ -257,7 +257,11 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( }); WITH_SCRIPT_CONTEXT(channel_id, { - set_option_value_for(name.data, opt_idx, optval, opt_flags, scope, to, err); + const char *errmsg + = set_option_value_for(opt_idx, optval, option_ctx_from(scope, to), opt_flags); + if (errmsg) { + api_set_error(err, kErrorTypeException, "%s", errmsg); + } }); } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index e3e69f4ff6..46e6b24c75 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -983,10 +983,10 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) buf_copy_options(buf, BCO_ENTER | BCO_NOHELP); if (scratch) { - set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0, - kOptScopeBuf, buf); - set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0, - kOptScopeBuf, buf); + set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), + option_ctx_from(kOptScopeBuf, buf), OPT_LOCAL, 0); + set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), + option_ctx_from(kOptScopeBuf, buf), OPT_LOCAL, 0); assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already buf->b_p_swf = false; buf->b_p_ml = false; diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index eb7c8c2880..aab09de6b4 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1251,56 +1251,82 @@ bool check_nomodeline(char **argp) return true; } -/// Prepare for executing autocommands for (hidden) buffer `buf`. -/// If the current buffer is not in any visible window, put it in a temporary -/// floating window using an entry in `aucmd_win[]`. -/// Set `curbuf` and `curwin` to match `buf`. +/// Prepare for executing autocommands for (hidden) buffer `buf` on window `win` +/// If the buffer of `win` is not `buf`, switch the buffer of `win` to `buf` temporarily. /// -/// @param aco structure to save values in -/// @param buf new curbuf -void aucmd_prepbuf(aco_save_T *aco, buf_T *buf) +/// @param aco Structure to save values in. +/// @param buf New curbuf. +/// @param win New curwin. +void aucmd_prepbuf_win(aco_save_T *aco, buf_T *buf, win_T *win) { - win_T *win; - bool need_append = true; // Append `aucmd_win` to the window list. + bool need_append = false; // Append `aucmd_win` to the window list. + int auc_idx = -1; // Index of aucmd_win[] to use. -1 if not using aucmd_win[]. - // Find a window that is for the new buffer - if (buf == curbuf) { // be quick when buf is curbuf - win = curwin; - } else { - win = NULL; - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer == buf) { - win = wp; - break; + aco->save_curtab_handle = -1; + aco->save_buf_handle = -1; + + if (win == NULL) { + // Window not provided. Find a window that is for the new buffer + if (buf == curbuf) { // be quick when buf is curbuf + win = curwin; + } else { + win = NULL; + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (wp->w_buffer == buf) { + win = wp; + break; + } } } - } - // Allocate a window when needed. - win_T *auc_win = NULL; - int auc_idx = AUCMD_WIN_COUNT; - if (win == NULL) { - for (auc_idx = 0; auc_idx < AUCMD_WIN_COUNT; auc_idx++) { - if (!aucmd_win[auc_idx].auc_win_used) { - break; + // Allocate a window when needed. + if (win == NULL) { + for (auc_idx = 0; auc_idx < AUCMD_WIN_COUNT; auc_idx++) { + if (!aucmd_win[auc_idx].auc_win_used) { + break; + } + } + + if (auc_idx == AUCMD_WIN_COUNT) { + kv_push(aucmd_win_vec, ((aucmdwin_T){ + .auc_win = NULL, + .auc_win_used = false, + })); + } + + if (aucmd_win[auc_idx].auc_win == NULL) { + win_alloc_aucmd_win(auc_idx); + } else { + need_append = true; } + win = aucmd_win[auc_idx].auc_win; + aucmd_win[auc_idx].auc_win_used = true; } + } else { + tabpage_T *tp = win_find_tabpage(win); - if (auc_idx == AUCMD_WIN_COUNT) { - kv_push(aucmd_win_vec, ((aucmdwin_T){ - .auc_win = NULL, - .auc_win_used = false, - })); + // If the window is in another tab page, switch to that tab page temporarily. + if (tp != curtab) { + aco->save_curtab_handle = curtab->handle; + unuse_tabpage(curtab); + use_tabpage(tp); } + } - if (aucmd_win[auc_idx].auc_win == NULL) { - win_alloc_aucmd_win(auc_idx); - need_append = false; + // If the buffer of the window is not the target buffer, switch to it temporarily. + if (win->w_buffer != buf) { + if (auc_idx == -1) { + // No need to store old buffer for aucmd_win[]. + aco->save_buf_handle = win->w_buffer->handle; + win->w_buffer->b_nwindows--; } - auc_win = aucmd_win[auc_idx].auc_win; - aucmd_win[auc_idx].auc_win_used = true; + + win->w_buffer = buf; + win->w_s = &buf->b_s; + buf->b_nwindows++; } + aco->use_aucmd_win_idx = auc_idx; aco->save_curwin_handle = curwin->handle; aco->save_prevwin_handle = prevwin == NULL ? 0 : prevwin->handle; aco->save_State = State; @@ -1308,26 +1334,15 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf) aco->save_prompt_insert = curbuf->b_prompt_insert; } - if (win != NULL) { - // There is a window for "buf" in the current tab page, make it the - // curwin. This is preferred, it has the least side effects (esp. if - // "buf" is curbuf). - aco->use_aucmd_win_idx = -1; - curwin = win; - } else { - // There is no window for "buf", use "auc_win". To minimize the side - // effects, insert it in the current tab page. - // Anything related to a window (e.g., setting folds) may have - // unexpected results. - aco->use_aucmd_win_idx = auc_idx; - auc_win->w_buffer = buf; - auc_win->w_s = &buf->b_s; - buf->b_nwindows++; - win_init_empty(auc_win); // set cursor and topline to safe values + if (auc_idx >= 0) { + // There is no window for "buf", use "win". To minimize the side effects, insert it in the + // current tab page. Anything related to a window (e.g., setting folds) may have unexpected + // results. + win_init_empty(win); // Set cursor and topline to safe values. - // Make sure w_localdir, tp_localdir and globaldir are NULL to avoid a - // chdir() in win_enter_ext(). - XFREE_CLEAR(auc_win->w_localdir); + // Make sure w_localdir, tp_localdir and globaldir are NULL to avoid a chdir() in + // win_enter_ext(). + XFREE_CLEAR(win->w_localdir); aco->tp_localdir = curtab->tp_localdir; curtab->tp_localdir = NULL; aco->globaldir = globaldir; @@ -1335,30 +1350,43 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf) block_autocmds(); // We don't want BufEnter/WinEnter autocommands. if (need_append) { - win_append(lastwin, auc_win, NULL); - pmap_put(int)(&window_handles, auc_win->handle, auc_win); - win_config_float(auc_win, auc_win->w_config); + win_append(lastwin, win, NULL); + pmap_put(int)(&window_handles, win->handle, win); + win_config_float(win, win->w_config); } // Prevent chdir() call in win_enter_ext(), through do_autochdir() const int save_acd = p_acd; p_acd = false; - // no redrawing and don't set the window title + // No redrawing and don't set the window title RedrawingDisabled++; - win_enter(auc_win, false); + win_enter(win, false); RedrawingDisabled--; p_acd = save_acd; unblock_autocmds(); - curwin = auc_win; } + + curwin = win; curbuf = buf; aco->new_curwin_handle = curwin->handle; set_bufref(&aco->new_curbuf, curbuf); - // disable the Visual area, the position may be invalid in another buffer + // Disable the Visual area, the position may be invalid in another buffer aco->save_VIsual_active = VIsual_active; VIsual_active = false; } +/// Prepare for executing autocommands for (hidden) buffer `buf`. +/// If the current buffer is not in any visible window, put it in a temporary +/// floating window using an entry in `aucmd_win[]`. +/// Set `curbuf` and `curwin` to match `buf`. +/// +/// @param aco structure to save values in +/// @param buf new curbuf +void aucmd_prepbuf(aco_save_T *aco, buf_T *buf) +{ + aucmd_prepbuf_win(aco, buf, NULL); +} + /// Cleanup after executing autocommands for a (hidden) buffer. /// Restore the window as it was (if possible). /// @@ -1447,6 +1475,19 @@ win_found: curwin->w_topfill = 0; } } else { + // Restore old buffer of new window if it was changed. + if (aco->save_buf_handle != -1) { + win_T *new_win = win_find_by_handle(aco->new_curwin_handle); + buf_T *new_win_buf = handle_get_buffer(aco->save_buf_handle); + + if (new_win != NULL && new_win_buf != NULL) { + new_win->w_buffer->b_nwindows--; + new_win->w_buffer = new_win_buf; + new_win->w_s = &new_win_buf->b_s; + new_win_buf->b_nwindows++; + } + } + // Restore curwin. Use the window ID, a window may have been closed // and the memory re-used for another one. win_T *const save_curwin = win_find_by_handle(aco->save_curwin_handle); @@ -1482,6 +1523,13 @@ win_found: if (VIsual_active) { check_pos(curbuf, &VIsual); } + + // Switch back to the original tab page if it was switched. + if (aco->save_curtab_handle != -1) { + tabpage_T *save_curtab = handle_get_tabpage(aco->save_curtab_handle); + unuse_tabpage(curtab); + use_tabpage(save_curtab); + } } /// Execute autocommands for "event" and file name "fname". diff --git a/src/nvim/autocmd_defs.h b/src/nvim/autocmd_defs.h index cba947e85f..777ee7b87a 100644 --- a/src/nvim/autocmd_defs.h +++ b/src/nvim/autocmd_defs.h @@ -14,16 +14,18 @@ /// Struct to save values in before executing autocommands for a buffer that is /// not the current buffer. typedef struct { - int use_aucmd_win_idx; ///< index in aucmd_win[] if >= 0 - handle_T save_curwin_handle; ///< ID of saved curwin - handle_T new_curwin_handle; ///< ID of new curwin - handle_T save_prevwin_handle; ///< ID of saved prevwin - bufref_T new_curbuf; ///< new curbuf - char *tp_localdir; ///< saved value of tp_localdir - char *globaldir; ///< saved value of globaldir - bool save_VIsual_active; ///< saved VIsual_active - int save_State; ///< saved State - int save_prompt_insert; ///< saved b_prompt_insert + int use_aucmd_win_idx; ///< index in aucmd_win[] if >= 0 + handle_T save_curwin_handle; ///< ID of saved curwin + handle_T save_curtab_handle; ///< ID of saved curtab. -1 if not switched. + handle_T new_curwin_handle; ///< ID of new curwin + handle_T save_buf_handle; ///< ID of saved buffer of new curwin. -1 if not switched. + handle_T save_prevwin_handle; ///< ID of saved prevwin + bufref_T new_curbuf; ///< new curbuf + char *tp_localdir; ///< saved value of tp_localdir + char *globaldir; ///< saved value of globaldir + bool save_VIsual_active; ///< saved VIsual_active + int save_State; ///< saved State + int save_prompt_insert; ///< saved b_prompt_insert } aco_save_T; typedef struct { diff --git a/src/nvim/diff.c b/src/nvim/diff.c index bd98a31a71..ebeb9ba088 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1391,8 +1391,8 @@ void diff_win_options(win_T *wp, bool addbuf) } wp->w_p_fdm_save = xstrdup(wp->w_p_fdm); } - set_option_direct_for(kOptFoldmethod, STATIC_CSTR_AS_OPTVAL("diff"), OPT_LOCAL, 0, - kOptScopeWin, wp); + set_option_direct_for(kOptFoldmethod, STATIC_CSTR_AS_OPTVAL("diff"), + option_ctx_from(kOptScopeWin, wp), OPT_LOCAL, 0); if (!wp->w_p_diff) { wp->w_p_fen_save = wp->w_p_fen; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 6f9f0f07c9..ceb3a074b4 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5294,7 +5294,7 @@ static char *findfunc_find_file(char *findarg, size_t findarg_len, int count) /// Returns NULL on success and an error message on failure. const char *did_set_findfunc(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; int retval; if (args->os_flags & OPT_LOCAL) { diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 9b77644085..053d97fd64 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -2401,7 +2401,7 @@ static void copy_global_to_buflocal_cb(Callback *globcb, Callback *bufcb) /// lambda expression. const char *did_set_completefunc(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; if (option_set_callback_func(buf->b_p_cfu, &cfu_cb) == FAIL) { return e_invarg; } @@ -2422,7 +2422,7 @@ void set_buflocal_cfu_callback(buf_T *buf) /// lambda expression. const char *did_set_omnifunc(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; if (option_set_callback_func(buf->b_p_ofu, &ofu_cb) == FAIL) { return e_invarg; } @@ -2443,7 +2443,7 @@ void set_buflocal_ofu_callback(buf_T *buf) /// lambda expression. const char *did_set_thesaurusfunc(optset_T *args FUNC_ATTR_UNUSED) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; int retval; if (args->os_flags & OPT_LOCAL) { diff --git a/src/nvim/option.c b/src/nvim/option.c index 551ea0be20..2b102fe1bb 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1324,7 +1324,8 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * return; } - *errmsg = set_option(opt_idx, newval, opt_flags, 0, false, op == OP_NONE, errbuf, errbuflen); + *errmsg = set_option_for(opt_idx, newval, option_ctx(), opt_flags, 0, false, + op == OP_NONE, errbuf, errbuflen); } /// Parse 'arg' for option settings. @@ -1844,7 +1845,7 @@ void set_option_sctx(OptIndex opt_idx, int opt_flags, sctx_T script_ctx) /// Apply the OptionSet autocommand. static void apply_optionset_autocmd(OptIndex opt_idx, int opt_flags, OptVal oldval, OptVal oldval_g, - OptVal oldval_l, OptVal newval, const char *errmsg) + OptVal oldval_l, OptVal newval, OptCtx ctx, const char *errmsg) { // Don't do this while starting up, failure or recursively. if (starting || errmsg != NULL || *get_vim_var_str(VV_OPTION_TYPE) != NUL) { @@ -1878,14 +1879,18 @@ static void apply_optionset_autocmd(OptIndex opt_idx, int opt_flags, OptVal oldv set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); set_vim_var_tv(VV_OPTION_OLDLOCAL, &oldval_tv); } - apply_autocmds(EVENT_OPTIONSET, options[opt_idx].fullname, NULL, false, NULL); + + WITH_AUCMD_CONTEXT(ctx, { + apply_autocmds(EVENT_OPTIONSET, options[opt_idx].fullname, NULL, false, NULL); + }); + reset_v_option_vars(); } /// Process the updated 'arabic' option value. static const char *did_set_arabic(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; const char *errmsg = NULL; if (win->w_p_arab) { @@ -1954,7 +1959,7 @@ static const char *did_set_autochdir(optset_T *args FUNC_ATTR_UNUSED) /// Process the updated 'binary' option value. static const char *did_set_binary(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; // when 'bin' is set also set some other options set_options_bin((int)args->os_oldval.boolean, buf->b_p_bin, args->os_flags); @@ -1966,7 +1971,7 @@ static const char *did_set_binary(optset_T *args) /// Process the updated 'buflisted' option value. static const char *did_set_buflisted(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; // when 'buflisted' changes, trigger autocommands if (args->os_oldval.boolean != buf->b_p_bl) { @@ -2000,7 +2005,7 @@ static const char *did_set_cmdheight(optset_T *args) /// Process the updated 'diff' option value. static const char *did_set_diff(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; // May add or remove the buffer from the list of diff buffers. diff_buf_adjust(win); if (foldmethodIsDiff(win)) { @@ -2021,7 +2026,7 @@ static const char *did_set_eof_eol_fixeol_bomb(optset_T *args FUNC_ATTR_UNUSED) /// Process the updated 'equalalways' option value. static const char *did_set_equalalways(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; if (p_ea && !args->os_oldval.boolean) { win_equal(win, false, 0); } @@ -2039,7 +2044,7 @@ static const char *did_set_foldlevel(optset_T *args FUNC_ATTR_UNUSED) /// Process the new 'foldminlines' option value. static const char *did_set_foldminlines(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; foldUpdateAll(win); return NULL; } @@ -2047,7 +2052,7 @@ static const char *did_set_foldminlines(optset_T *args) /// Process the new 'foldnestmax' option value. static const char *did_set_foldnestmax(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; if (foldmethodIsSyntax(win) || foldmethodIsIndent(win)) { foldUpdateAll(win); } @@ -2176,7 +2181,7 @@ static const char *did_set_lines_or_columns(optset_T *args) /// Process the updated 'lisp' option value. static const char *did_set_lisp(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; // When 'lisp' option changes include/exclude '-' in keyword characters. buf_init_chartab(buf, false); // ignore errors return NULL; @@ -2194,7 +2199,7 @@ static const char *did_set_modifiable(optset_T *args FUNC_ATTR_UNUSED) /// Process the updated 'modified' option value. static const char *did_set_modified(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; if (!args->os_newval.boolean) { save_file_ff(buf); // Buffer is unchanged } @@ -2206,7 +2211,7 @@ static const char *did_set_modified(optset_T *args) /// Process the updated 'number' or 'relativenumber' option value. static const char *did_set_number_relativenumber(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; if (*win->w_p_stc != NUL) { // When 'relativenumber'/'number' is changed and 'statuscolumn' is set, reset width. win->w_nrwidth_line_count = 0; @@ -2218,7 +2223,7 @@ static const char *did_set_number_relativenumber(optset_T *args) /// Process the new 'numberwidth' option value. static const char *did_set_numberwidth(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; win->w_nrwidth_line_count = 0; // trigger a redraw return NULL; @@ -2356,7 +2361,7 @@ static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED) /// Process the updated 'previewwindow' option value. static const char *did_set_previewwindow(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; if (!win->w_p_pvw) { return NULL; @@ -2388,7 +2393,7 @@ static const char *did_set_pumblend(optset_T *args FUNC_ATTR_UNUSED) /// Process the updated 'readonly' option value. static const char *did_set_readonly(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; // when 'readonly' is reset globally, also reset readonlymode if (!buf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0) { @@ -2408,7 +2413,7 @@ static const char *did_set_readonly(optset_T *args) /// Process the new 'scrollback' option value. static const char *did_set_scrollback(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; OptInt old_value = args->os_oldval.number; OptInt value = args->os_newval.number; @@ -2422,7 +2427,7 @@ static const char *did_set_scrollback(optset_T *args) /// Process the updated 'scrollbind' option value. static const char *did_set_scrollbind(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; // when 'scrollbind' is set: snapshot the current position to avoid a jump // at the end of normal_cmd() @@ -2459,8 +2464,8 @@ static const char *did_set_shellslash(optset_T *args FUNC_ATTR_UNUSED) /// Process the new 'shiftwidth' or the 'tabstop' option value. static const char *did_set_shiftwidth_tabstop(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; - win_T *win = (win_T *)args->os_win; + buf_T *buf = args->os_ctx.buf; + win_T *win = args->os_ctx.win; OptInt *pp = (OptInt *)args->os_varp; if (foldmethodIsIndent(win)) { @@ -2486,7 +2491,7 @@ static const char *did_set_showtabline(optset_T *args FUNC_ATTR_UNUSED) /// Process the updated 'smoothscroll' option value. static const char *did_set_smoothscroll(optset_T *args FUNC_ATTR_UNUSED) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; if (!win->w_p_sms) { win->w_skipcol = 0; } @@ -2497,7 +2502,7 @@ static const char *did_set_smoothscroll(optset_T *args FUNC_ATTR_UNUSED) /// Process the updated 'spell' option value. static const char *did_set_spell(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; if (win->w_p_spell) { return parse_spelllang(win); } @@ -2508,7 +2513,7 @@ static const char *did_set_spell(optset_T *args) /// Process the updated 'swapfile' option value. static const char *did_set_swapfile(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; // when 'swf' is set, create swapfile, when reset remove swapfile if (buf->b_p_swf && p_uc) { ml_open_file(buf); // create the swap file @@ -2553,7 +2558,7 @@ static const char *did_set_titlelen(optset_T *args) /// Process the updated 'undofile' option value. static const char *did_set_undofile(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; // Only take action when the option was set. if (!buf->b_p_udf && !p_udf) { @@ -2604,7 +2609,7 @@ const char *did_set_buflocal_undolevels(buf_T *buf, OptInt value, OptInt old_val /// Process the new 'undolevels' option value. static const char *did_set_undolevels(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; OptInt *pp = (OptInt *)args->os_varp; if (pp == &p_ul) { // global 'undolevels' @@ -2645,7 +2650,7 @@ static const char *did_set_wildchar(optset_T *args) /// Process the new 'winblend' option value. static const char *did_set_winblend(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; OptInt old_value = args->os_oldval.number; OptInt value = args->os_newval.number; @@ -2694,7 +2699,7 @@ static const char *did_set_winwidth(optset_T *args) /// Process the updated 'wrap' option value. static const char *did_set_wrap(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; // Set w_leftcol or w_skipcol to zero. if (win->w_p_wrap) { win->w_leftcol = 0; @@ -3143,12 +3148,6 @@ static OptValType option_get_type(const OptIndex opt_idx) OptVal optval_from_varp(OptIndex opt_idx, void *varp) FUNC_ATTR_NONNULL_ARG(2) { - // Special case: 'modified' is b_changed, but we also want to consider it set when 'ff' or 'fenc' - // changed. - if ((int *)varp == &curbuf->b_changed) { - return BOOLEAN_OPTVAL(curbufIsChanged()); - } - if (option_is_multitype(opt_idx)) { // Multitype options are stored as OptVal. return *(OptVal *)varp; @@ -3381,21 +3380,37 @@ uint32_t get_option_flags(OptIndex opt_idx) /// Gets the value for an option. /// /// @param opt_idx Option index in options[] table. +/// @param ctx Context to get the option value from. /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). /// /// @return [allocated] Option value. Returns NIL_OPTVAL for invalid option index. -OptVal get_option_value(OptIndex opt_idx, int opt_flags) +OptVal get_option_value_from(OptIndex opt_idx, OptCtx ctx, int opt_flags) { if (opt_idx == kOptInvalid) { // option not in the options[] table. return NIL_OPTVAL; } - vimoption_T *opt = &options[opt_idx]; - void *varp = get_varp_scope(opt, opt_flags); + // Special case: 'modified' is b_changed, but we also want to consider it set when 'ff' or 'fenc' + // changed. + if (opt_idx == kOptModified) { + return BOOLEAN_OPTVAL(bufIsChanged(ctx.buf)); + } + void * const varp = get_varp_scope_from(&options[opt_idx], opt_flags, ctx); return optval_copy(optval_from_varp(opt_idx, varp)); } +/// Gets the value for an option in the current context. +/// +/// @param opt_idx Option index in options[] table. +/// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). +/// +/// @return [allocated] Option value. Returns NIL_OPTVAL for invalid option index. +OptVal get_option_value(OptIndex opt_idx, int opt_flags) +{ + return get_option_value_from(opt_idx, option_ctx(), opt_flags); +} + /// Return information for option at 'opt_idx' vimoption_T *get_option(OptIndex opt_idx) { @@ -3464,6 +3479,8 @@ static bool is_option_local_value_unset(OptIndex opt_idx) /// @param opt_idx Index in options[] table. Must not be kOptInvalid. /// @param[in] varp Option variable pointer, cannot be NULL. /// @param old_value Old option value. +/// @param new_value New option value. +/// @param ctx Context in which the option is set. /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). /// @param set_sid Script ID. Special values: /// 0: Use current script ID. @@ -3475,8 +3492,9 @@ static bool is_option_local_value_unset(OptIndex opt_idx) /// /// @return NULL on success, an untranslated error message on error. static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value, OptVal new_value, - int opt_flags, scid_T set_sid, const bool direct, - const bool value_replaced, char *errbuf, size_t errbuflen) + OptCtx ctx, int opt_flags, scid_T set_sid, const bool direct, + const bool value_replaced, char *errbuf, // NOLINT(readability-non-const-parameter) + size_t errbuflen) { vimoption_T *opt = &options[opt_idx]; const char *errmsg = NULL; @@ -3495,8 +3513,7 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value .os_restore_chartab = false, .os_errbuf = errbuf, .os_errbuflen = errbuflen, - .os_buf = curbuf, - .os_win = curwin + .os_ctx = ctx, }; if (direct) { @@ -3533,7 +3550,7 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value set_option_varp(opt_idx, varp, old_value, true); // When resetting some values, need to act on it. if (restore_chartab) { - buf_init_chartab(curbuf, true); + buf_init_chartab(ctx.buf, true); } return errmsg; @@ -3564,12 +3581,12 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value if (option_is_global_local(opt_idx)) { // Global option with local value set to use global value. // Free the local value and clear it. - void *varp_local = get_varp_scope(opt, OPT_LOCAL); + void *varp_local = get_varp_scope_from(opt, OPT_LOCAL, ctx); OptVal local_unset_value = get_option_unset_value(opt_idx); set_option_varp(opt_idx, varp_local, optval_copy(local_unset_value), true); } else { // May set global value for local option. - void *varp_global = get_varp_scope(opt, OPT_GLOBAL); + void *varp_global = get_varp_scope_from(opt, OPT_GLOBAL, ctx); set_option_varp(opt_idx, varp_global, optval_copy(new_value), true); } } @@ -3580,17 +3597,23 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value } // Trigger the autocommand only after setting the flags. - if (varp == &curbuf->b_p_syn) { - do_syntax_autocmd(curbuf, value_changed); - } else if (varp == &curbuf->b_p_ft) { + if (varp == &ctx.buf->b_p_syn) { + WITH_AUCMD_CONTEXT(ctx, { + do_syntax_autocmd(ctx.buf, value_changed); + }); + } else if (varp == &ctx.buf->b_p_ft) { // 'filetype' is set, trigger the FileType autocommand // Skip this when called from a modeline // Force autocmd when the filetype was changed if (!(opt_flags & OPT_MODELINE) || value_changed) { - do_filetype_autocmd(curbuf, value_changed); + WITH_AUCMD_CONTEXT(ctx, { + do_filetype_autocmd(ctx.buf, value_changed); + }); } - } else if (varp == &curwin->w_s->b_p_spl) { - do_spelllang_source(curwin); + } else if (varp == &ctx.win->w_s->b_p_spl) { + WITH_AUCMD_CONTEXT(ctx, { + do_spelllang_source(ctx.win); + }); } // In case 'ruler' or 'showcmd' or 'columns' or 'ls' changed. @@ -3598,25 +3621,25 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value if (varp == &p_mouse) { setmouse(); // in case 'mouse' changed - } else if ((varp == &p_flp || varp == &(curbuf->b_p_flp)) && curwin->w_briopt_list) { + } else if ((varp == &p_flp || varp == &(ctx.buf->b_p_flp)) && ctx.win->w_briopt_list) { // Changing Formatlistpattern when briopt includes the list setting: // redraw redraw_all_later(UPD_NOT_VALID); - } else if (varp == &p_wbr || varp == &(curwin->w_p_wbr)) { + } else if (varp == &p_wbr || varp == &(ctx.win->w_p_wbr)) { // add / remove window bars for 'winbar' set_winbar(true); } - if (curwin->w_curswant != MAXCOL + if (ctx.win->w_curswant != MAXCOL && (opt->flags & (kOptFlagCurswant | kOptFlagRedrAll)) != 0 && (opt->flags & kOptFlagHLOnly) == 0) { - curwin->w_set_curswant = true; + ctx.win->w_set_curswant = true; } - check_redraw(opt->flags); + check_redraw_for(ctx.buf, ctx.win, opt->flags); if (errmsg == NULL) { - uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags); + uint32_t *p = insecure_flag(ctx.win, opt_idx, opt_flags); opt->flags |= kOptFlagWasSet; // When an option is set in the sandbox, from a modeline or in secure mode set the kOptFlagInsecure @@ -3676,6 +3699,7 @@ static const char *validate_option_value(const OptIndex opt_idx, OptVal *newval, /// /// @param opt_idx Index in options[] table. Must not be kOptInvalid. /// @param value New option value. Might get freed. +/// @param ctx Context in which the option is set. /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). /// @param set_sid Script ID. Special values: /// 0: Use current script ID. @@ -3686,9 +3710,9 @@ static const char *validate_option_value(const OptIndex opt_idx, OptVal *newval, /// @param errbuflen Length of error buffer. /// /// @return NULL on success, an untranslated error message on error. -static const char *set_option(const OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid, - const bool direct, const bool value_replaced, char *errbuf, - size_t errbuflen) +static const char *set_option_for(OptIndex opt_idx, OptVal value, OptCtx ctx, int opt_flags, + scid_T set_sid, const bool direct, const bool value_replaced, + char *errbuf, size_t errbuflen) { assert(opt_idx != kOptInvalid); @@ -3713,10 +3737,11 @@ static const char *set_option(const OptIndex opt_idx, OptVal value, int opt_flag // When using ":set opt=val" for a global option with a local value the local value will be reset, // use the global value in that case. - void *varp - = scope_both && option_is_global_local(opt_idx) ? opt->var : get_varp_scope(opt, opt_flags); - void *varp_local = get_varp_scope(opt, OPT_LOCAL); - void *varp_global = get_varp_scope(opt, OPT_GLOBAL); + void *varp = scope_both && option_is_global_local(opt_idx) + ? opt->var + : get_varp_scope_from(opt, opt_flags, ctx); + void *varp_local = get_varp_scope_from(opt, OPT_LOCAL, ctx); + void *varp_global = get_varp_scope_from(opt, OPT_GLOBAL, ctx); OptVal old_value = optval_from_varp(opt_idx, varp); OptVal old_global_value = optval_from_varp(opt_idx, varp_global); @@ -3729,7 +3754,7 @@ static const char *set_option(const OptIndex opt_idx, OptVal value, int opt_flag // unset. In every other case, it is the same as old_value. // This value is used instead of old_value when triggering the OptionSet autocommand. OptVal used_old_value = (scope_local && is_opt_local_unset) - ? optval_from_varp(opt_idx, get_varp(opt)) + ? optval_from_varp(opt_idx, get_varp_from(opt, ctx)) : old_value; // Save the old values and the new value in case they get changed. @@ -3739,7 +3764,7 @@ static const char *set_option(const OptIndex opt_idx, OptVal value, int opt_flag // New value (and varp) may become invalid if the buffer is closed by autocommands. OptVal saved_new_value = optval_copy(value); - uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags); + uint32_t *p = insecure_flag(ctx.win, opt_idx, opt_flags); const int secure_saved = secure; // When an option is set in the sandbox, from a modeline or in secure mode, then deal with side @@ -3752,7 +3777,7 @@ static const char *set_option(const OptIndex opt_idx, OptVal value, int opt_flag // Set option through its variable pointer. set_option_varp(opt_idx, varp, value, false); // Process any side effects. - errmsg = did_set_option(opt_idx, varp, old_value, value, opt_flags, set_sid, direct, + errmsg = did_set_option(opt_idx, varp, old_value, value, ctx, opt_flags, set_sid, direct, value_replaced, errbuf, errbuflen); secure = secure_saved; @@ -3760,7 +3785,7 @@ static const char *set_option(const OptIndex opt_idx, OptVal value, int opt_flag if (errmsg == NULL && !direct) { if (!starting) { apply_optionset_autocmd(opt_idx, opt_flags, saved_used_value, saved_old_global_value, - saved_old_local_value, saved_new_value, errmsg); + saved_old_local_value, saved_new_value, ctx, errmsg); } if (opt->flags & kOptFlagUIOption) { ui_call_option_set(cstr_as_string(opt->fullname), optval_as_object(saved_new_value)); @@ -3780,11 +3805,13 @@ static const char *set_option(const OptIndex opt_idx, OptVal value, int opt_flag /// /// @param opt_idx Option index in options[] table. /// @param value Option value. +/// @param ctx Context in which the option is set. /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). /// @param set_sid Script ID. Special values: /// 0: Use current script ID. /// SID_NONE: Don't set script ID. -void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid) +void set_option_direct_for(OptIndex opt_idx, OptVal value, OptCtx ctx, int opt_flags, + scid_T set_sid) { static char errbuf[IOSIZE]; @@ -3792,57 +3819,35 @@ void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set return; } - const char *errmsg = set_option(opt_idx, optval_copy(value), opt_flags, set_sid, true, true, - errbuf, sizeof(errbuf)); + const char *errmsg = set_option_for(opt_idx, optval_copy(value), ctx, opt_flags, set_sid, true, + true, errbuf, sizeof(errbuf)); assert(errmsg == NULL); (void)errmsg; // ignore unused warning } -/// Set option value directly for buffer / window, without processing any side effects. +/// Set option value for current context directly, without processing any side effects. /// -/// @param opt_idx Option index in options[] table. -/// @param value Option value. -/// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). -/// @param set_sid Script ID. Special values: -/// 0: Use current script ID. -/// SID_NONE: Don't set script ID. -/// @param scope Option scope. See OptScope in option.h. -/// @param[in] from Target buffer/window. -void set_option_direct_for(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid, - OptScope scope, void *const from) -{ - buf_T *save_curbuf = curbuf; - win_T *save_curwin = curwin; - - // Don't use switch_option_context(), as that calls aucmd_prepbuf(), which may have unintended - // side-effects when setting an option directly. Just change the values of curbuf and curwin if - // needed, no need to properly switch the window / buffer. - switch (scope) { - case kOptScopeGlobal: - break; - case kOptScopeWin: - curwin = (win_T *)from; - curbuf = curwin->w_buffer; - break; - case kOptScopeBuf: - curbuf = (buf_T *)from; - break; - } - - set_option_direct(opt_idx, value, opt_flags, set_sid); - - curwin = save_curwin; - curbuf = save_curbuf; +/// @param opt_idx Option index in options[] table. +/// @param value Option value. +/// @param ctx Context in which the option is set. +/// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). +/// @param set_sid Script ID. Special values: +/// 0: Use current script ID. +/// SID_NONE: Don't set script ID. +void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid) +{ + set_option_direct_for(opt_idx, value, option_ctx(), opt_flags, set_sid); } /// Set the value of an option. /// /// @param opt_idx Index in options[] table. Must not be kOptInvalid. /// @param[in] value Option value. If NIL_OPTVAL, the option value is cleared. +/// @param ctx Context to set option for. /// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). /// /// @return NULL on success, an untranslated error message on error. -const char *set_option_value(const OptIndex opt_idx, const OptVal value, int opt_flags) +const char *set_option_value_for(OptIndex opt_idx, OptVal value, OptCtx ctx, int opt_flags) { assert(opt_idx != kOptInvalid); @@ -3854,7 +3859,21 @@ const char *set_option_value(const OptIndex opt_idx, const OptVal value, int opt return _(e_sandbox); } - return set_option(opt_idx, optval_copy(value), opt_flags, 0, false, true, errbuf, sizeof(errbuf)); + return set_option_for(opt_idx, optval_copy(value), ctx, opt_flags, 0, false, true, errbuf, + sizeof(errbuf)); +} + +/// Set the value of an option for current context. +/// +/// @param opt_idx Index in options[] table. Must not be kOptInvalid. +/// @param[in] value Option value. If NIL_OPTVAL, the option value is cleared. +/// @param ctx Context to set option for. +/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). +/// +/// @return NULL on success, an untranslated error message on error. +const char *set_option_value(OptIndex opt_idx, OptVal value, int opt_flags) +{ + return set_option_value_for(opt_idx, value, option_ctx(), opt_flags); } /// Unset the local value of a global-local option. @@ -3910,135 +3929,6 @@ void set_option_value_give_err(const OptIndex opt_idx, OptVal value, int opt_fla } } -/// Switch current context to get/set option value for window/buffer. -/// -/// @param[out] ctx Current context. switchwin_T for window and aco_save_T for buffer. -/// @param scope Option scope. See OptScope in option.h. -/// @param[in] from Target buffer/window. -/// @param[out] err Error message, if any. -/// -/// @return true if context was switched, false otherwise. -static bool switch_option_context(void *const ctx, OptScope scope, void *const from, Error *err) -{ - switch (scope) { - case kOptScopeGlobal: - return false; - case kOptScopeWin: { - win_T *const win = (win_T *)from; - switchwin_T *const switchwin = (switchwin_T *)ctx; - - if (win == curwin) { - return false; - } - - if (switch_win_noblock(switchwin, win, win_find_tabpage(win), true) - == FAIL) { - restore_win_noblock(switchwin, true); - - if (ERROR_SET(err)) { - return false; - } - api_set_error(err, kErrorTypeException, "Problem while switching windows"); - return false; - } - return true; - } - case kOptScopeBuf: { - buf_T *const buf = (buf_T *)from; - aco_save_T *const aco = (aco_save_T *)ctx; - - if (buf == curbuf) { - return false; - } - aucmd_prepbuf(aco, buf); - return true; - } - } - UNREACHABLE; -} - -/// Restore context after getting/setting option for window/buffer. See switch_option_context() for -/// params. -static void restore_option_context(void *const ctx, OptScope scope) -{ - switch (scope) { - case kOptScopeGlobal: - break; - case kOptScopeWin: - restore_win_noblock((switchwin_T *)ctx, true); - break; - case kOptScopeBuf: - aucmd_restbuf((aco_save_T *)ctx); - break; - } -} - -/// Get option value for buffer / window. -/// -/// @param opt_idx Option index in options[] table. -/// @param[out] flagsp Set to the option flags (see OptFlags) (if not NULL). -/// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination). -/// @param[out] hidden Whether option is hidden. -/// @param scope Option scope. See OptScope in option.h. -/// @param[in] from Target buffer/window. -/// @param[out] err Error message, if any. -/// -/// @return Option value. Must be freed by caller. -OptVal get_option_value_for(OptIndex opt_idx, int opt_flags, const OptScope scope, void *const from, - Error *err) -{ - switchwin_T switchwin; - aco_save_T aco; - void *ctx = scope == kOptScopeWin ? (void *)&switchwin - : (scope == kOptScopeBuf ? (void *)&aco : NULL); - - bool switched = switch_option_context(ctx, scope, from, err); - if (ERROR_SET(err)) { - return NIL_OPTVAL; - } - - OptVal retv = get_option_value(opt_idx, opt_flags); - - if (switched) { - restore_option_context(ctx, scope); - } - - return retv; -} - -/// Set option value for buffer / window. -/// -/// @param name Option name. -/// @param opt_idx Option index in options[] table. -/// @param[in] value Option value. -/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). -/// @param scope Option scope. See OptScope in option.h. -/// @param[in] from Target buffer/window. -/// @param[out] err Error message, if any. -void set_option_value_for(const char *name, OptIndex opt_idx, OptVal value, const int opt_flags, - const OptScope scope, void *const from, Error *err) - FUNC_ATTR_NONNULL_ARG(1) -{ - switchwin_T switchwin; - aco_save_T aco; - void *ctx = scope == kOptScopeWin ? (void *)&switchwin - : (scope == kOptScopeBuf ? (void *)&aco : NULL); - - bool switched = switch_option_context(ctx, scope, from, err); - if (ERROR_SET(err)) { - return; - } - - const char *const errmsg = set_option_value_handle_tty(name, opt_idx, value, opt_flags); - if (errmsg) { - api_set_error(err, kErrorTypeException, "%s", errmsg); - } - - if (switched) { - restore_option_context(ctx, scope); - } -} - /// if 'all' == false: show changed options /// if 'all' == true: show all normal options /// @@ -4454,13 +4344,13 @@ static int put_set(FILE *fd, char *cmd, OptIndex opt_idx, void *varp) return OK; } -void *get_varp_scope_from(vimoption_T *p, int opt_flags, buf_T *buf, win_T *win) +void *get_varp_scope_from(vimoption_T *p, int opt_flags, OptCtx ctx) { OptIndex opt_idx = get_opt_idx(p); if ((opt_flags & OPT_GLOBAL) && !option_is_global_only(opt_idx)) { if (option_is_window_local(opt_idx)) { - return GLOBAL_WO(get_varp_from(p, buf, win)); + return GLOBAL_WO(get_varp_from(p, ctx)); } return p->var; } @@ -4468,88 +4358,73 @@ void *get_varp_scope_from(vimoption_T *p, int opt_flags, buf_T *buf, win_T *win) if ((opt_flags & OPT_LOCAL) && option_is_global_local(opt_idx)) { switch (opt_idx) { case kOptFormatprg: - return &(buf->b_p_fp); + return &(ctx.buf->b_p_fp); case kOptFindfunc: - return &(buf->b_p_ffu); + return &(ctx.buf->b_p_ffu); case kOptErrorformat: - return &(buf->b_p_efm); + return &(ctx.buf->b_p_efm); case kOptGrepprg: - return &(buf->b_p_gp); + return &(ctx.buf->b_p_gp); case kOptMakeprg: - return &(buf->b_p_mp); + return &(ctx.buf->b_p_mp); case kOptEqualprg: - return &(buf->b_p_ep); + return &(ctx.buf->b_p_ep); case kOptKeywordprg: - return &(buf->b_p_kp); + return &(ctx.buf->b_p_kp); case kOptPath: - return &(buf->b_p_path); + return &(ctx.buf->b_p_path); case kOptAutoread: - return &(buf->b_p_ar); + return &(ctx.buf->b_p_ar); case kOptTags: - return &(buf->b_p_tags); + return &(ctx.buf->b_p_tags); case kOptTagcase: - return &(buf->b_p_tc); + return &(ctx.buf->b_p_tc); case kOptSidescrolloff: - return &(win->w_p_siso); + return &(ctx.win->w_p_siso); case kOptScrolloff: - return &(win->w_p_so); + return &(ctx.win->w_p_so); case kOptDefine: - return &(buf->b_p_def); + return &(ctx.buf->b_p_def); case kOptInclude: - return &(buf->b_p_inc); + return &(ctx.buf->b_p_inc); case kOptCompleteopt: - return &(buf->b_p_cot); + return &(ctx.buf->b_p_cot); case kOptDictionary: - return &(buf->b_p_dict); + return &(ctx.buf->b_p_dict); case kOptThesaurus: - return &(buf->b_p_tsr); + return &(ctx.buf->b_p_tsr); case kOptThesaurusfunc: - return &(buf->b_p_tsrfu); + return &(ctx.buf->b_p_tsrfu); case kOptTagfunc: - return &(buf->b_p_tfu); + return &(ctx.buf->b_p_tfu); case kOptShowbreak: - return &(win->w_p_sbr); + return &(ctx.win->w_p_sbr); case kOptStatusline: - return &(win->w_p_stl); + return &(ctx.win->w_p_stl); case kOptWinbar: - return &(win->w_p_wbr); + return &(ctx.win->w_p_wbr); case kOptUndolevels: - return &(buf->b_p_ul); + return &(ctx.buf->b_p_ul); case kOptLispwords: - return &(buf->b_p_lw); + return &(ctx.buf->b_p_lw); case kOptBackupcopy: - return &(buf->b_p_bkc); + return &(ctx.buf->b_p_bkc); case kOptMakeencoding: - return &(buf->b_p_menc); + return &(ctx.buf->b_p_menc); case kOptFillchars: - return &(win->w_p_fcs); + return &(ctx.win->w_p_fcs); case kOptListchars: - return &(win->w_p_lcs); + return &(ctx.win->w_p_lcs); case kOptVirtualedit: - return &(win->w_p_ve); + return &(ctx.win->w_p_ve); default: abort(); } } - return get_varp_from(p, buf, win); -} - -/// Get pointer to option variable, depending on local or global scope. -/// -/// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). -void *get_varp_scope(vimoption_T *p, int opt_flags) -{ - return get_varp_scope_from(p, opt_flags, curbuf, curwin); + return get_varp_from(p, ctx); } -/// Get pointer to option variable at 'opt_idx', depending on local or global -/// scope. -void *get_option_varp_scope_from(OptIndex opt_idx, int opt_flags, buf_T *buf, win_T *win) -{ - return get_varp_scope_from(&(options[opt_idx]), opt_flags, buf, win); -} - -void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) +void *get_varp_from(vimoption_T *p, OptCtx ctx) { OptIndex opt_idx = get_opt_idx(p); @@ -4561,299 +4436,330 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) switch (opt_idx) { // global option with local value: use local value if it's been set case kOptEqualprg: - return *buf->b_p_ep != NUL ? &buf->b_p_ep : p->var; + return *ctx.buf->b_p_ep != NUL ? &ctx.buf->b_p_ep : p->var; case kOptKeywordprg: - return *buf->b_p_kp != NUL ? &buf->b_p_kp : p->var; + return *ctx.buf->b_p_kp != NUL ? &ctx.buf->b_p_kp : p->var; case kOptPath: - return *buf->b_p_path != NUL ? &(buf->b_p_path) : p->var; + return *ctx.buf->b_p_path != NUL ? &(ctx.buf->b_p_path) : p->var; case kOptAutoread: - return buf->b_p_ar >= 0 ? &(buf->b_p_ar) : p->var; + return ctx.buf->b_p_ar >= 0 ? &(ctx.buf->b_p_ar) : p->var; case kOptTags: - return *buf->b_p_tags != NUL ? &(buf->b_p_tags) : p->var; + return *ctx.buf->b_p_tags != NUL ? &(ctx.buf->b_p_tags) : p->var; case kOptTagcase: - return *buf->b_p_tc != NUL ? &(buf->b_p_tc) : p->var; + return *ctx.buf->b_p_tc != NUL ? &(ctx.buf->b_p_tc) : p->var; case kOptSidescrolloff: - return win->w_p_siso >= 0 ? &(win->w_p_siso) : p->var; + return ctx.win->w_p_siso >= 0 ? &(ctx.win->w_p_siso) : p->var; case kOptScrolloff: - return win->w_p_so >= 0 ? &(win->w_p_so) : p->var; + return ctx.win->w_p_so >= 0 ? &(ctx.win->w_p_so) : p->var; case kOptBackupcopy: - return *buf->b_p_bkc != NUL ? &(buf->b_p_bkc) : p->var; + return *ctx.buf->b_p_bkc != NUL ? &(ctx.buf->b_p_bkc) : p->var; case kOptDefine: - return *buf->b_p_def != NUL ? &(buf->b_p_def) : p->var; + return *ctx.buf->b_p_def != NUL ? &(ctx.buf->b_p_def) : p->var; case kOptInclude: - return *buf->b_p_inc != NUL ? &(buf->b_p_inc) : p->var; + return *ctx.buf->b_p_inc != NUL ? &(ctx.buf->b_p_inc) : p->var; case kOptCompleteopt: - return *buf->b_p_cot != NUL ? &(buf->b_p_cot) : p->var; + return *ctx.buf->b_p_cot != NUL ? &(ctx.buf->b_p_cot) : p->var; case kOptDictionary: - return *buf->b_p_dict != NUL ? &(buf->b_p_dict) : p->var; + return *ctx.buf->b_p_dict != NUL ? &(ctx.buf->b_p_dict) : p->var; case kOptThesaurus: - return *buf->b_p_tsr != NUL ? &(buf->b_p_tsr) : p->var; + return *ctx.buf->b_p_tsr != NUL ? &(ctx.buf->b_p_tsr) : p->var; case kOptThesaurusfunc: - return *buf->b_p_tsrfu != NUL ? &(buf->b_p_tsrfu) : p->var; + return *ctx.buf->b_p_tsrfu != NUL ? &(ctx.buf->b_p_tsrfu) : p->var; case kOptFormatprg: - return *buf->b_p_fp != NUL ? &(buf->b_p_fp) : p->var; + return *ctx.buf->b_p_fp != NUL ? &(ctx.buf->b_p_fp) : p->var; case kOptFindfunc: - return *buf->b_p_ffu != NUL ? &(buf->b_p_ffu) : p->var; + return *ctx.buf->b_p_ffu != NUL ? &(ctx.buf->b_p_ffu) : p->var; case kOptErrorformat: - return *buf->b_p_efm != NUL ? &(buf->b_p_efm) : p->var; + return *ctx.buf->b_p_efm != NUL ? &(ctx.buf->b_p_efm) : p->var; case kOptGrepprg: - return *buf->b_p_gp != NUL ? &(buf->b_p_gp) : p->var; + return *ctx.buf->b_p_gp != NUL ? &(ctx.buf->b_p_gp) : p->var; case kOptMakeprg: - return *buf->b_p_mp != NUL ? &(buf->b_p_mp) : p->var; + return *ctx.buf->b_p_mp != NUL ? &(ctx.buf->b_p_mp) : p->var; case kOptShowbreak: - return *win->w_p_sbr != NUL ? &(win->w_p_sbr) : p->var; + return *ctx.win->w_p_sbr != NUL ? &(ctx.win->w_p_sbr) : p->var; case kOptStatusline: - return *win->w_p_stl != NUL ? &(win->w_p_stl) : p->var; + return *ctx.win->w_p_stl != NUL ? &(ctx.win->w_p_stl) : p->var; case kOptWinbar: - return *win->w_p_wbr != NUL ? &(win->w_p_wbr) : p->var; + return *ctx.win->w_p_wbr != NUL ? &(ctx.win->w_p_wbr) : p->var; case kOptUndolevels: - return buf->b_p_ul != NO_LOCAL_UNDOLEVEL ? &(buf->b_p_ul) : p->var; + return ctx.buf->b_p_ul != NO_LOCAL_UNDOLEVEL ? &(ctx.buf->b_p_ul) : p->var; case kOptLispwords: - return *buf->b_p_lw != NUL ? &(buf->b_p_lw) : p->var; + return *ctx.buf->b_p_lw != NUL ? &(ctx.buf->b_p_lw) : p->var; case kOptMakeencoding: - return *buf->b_p_menc != NUL ? &(buf->b_p_menc) : p->var; + return *ctx.buf->b_p_menc != NUL ? &(ctx.buf->b_p_menc) : p->var; case kOptFillchars: - return *win->w_p_fcs != NUL ? &(win->w_p_fcs) : p->var; + return *ctx.win->w_p_fcs != NUL ? &(ctx.win->w_p_fcs) : p->var; case kOptListchars: - return *win->w_p_lcs != NUL ? &(win->w_p_lcs) : p->var; + return *ctx.win->w_p_lcs != NUL ? &(ctx.win->w_p_lcs) : p->var; case kOptVirtualedit: - return *win->w_p_ve != NUL ? &win->w_p_ve : p->var; + return *ctx.win->w_p_ve != NUL ? &ctx.win->w_p_ve : p->var; case kOptArabic: - return &(win->w_p_arab); + return &(ctx.win->w_p_arab); case kOptList: - return &(win->w_p_list); + return &(ctx.win->w_p_list); case kOptSpell: - return &(win->w_p_spell); + return &(ctx.win->w_p_spell); case kOptCursorcolumn: - return &(win->w_p_cuc); + return &(ctx.win->w_p_cuc); case kOptCursorline: - return &(win->w_p_cul); + return &(ctx.win->w_p_cul); case kOptCursorlineopt: - return &(win->w_p_culopt); + return &(ctx.win->w_p_culopt); case kOptColorcolumn: - return &(win->w_p_cc); + return &(ctx.win->w_p_cc); case kOptDiff: - return &(win->w_p_diff); + return &(ctx.win->w_p_diff); case kOptFoldcolumn: - return &(win->w_p_fdc); + return &(ctx.win->w_p_fdc); case kOptFoldenable: - return &(win->w_p_fen); + return &(ctx.win->w_p_fen); case kOptFoldignore: - return &(win->w_p_fdi); + return &(ctx.win->w_p_fdi); case kOptFoldlevel: - return &(win->w_p_fdl); + return &(ctx.win->w_p_fdl); case kOptFoldmethod: - return &(win->w_p_fdm); + return &(ctx.win->w_p_fdm); case kOptFoldminlines: - return &(win->w_p_fml); + return &(ctx.win->w_p_fml); case kOptFoldnestmax: - return &(win->w_p_fdn); + return &(ctx.win->w_p_fdn); case kOptFoldexpr: - return &(win->w_p_fde); + return &(ctx.win->w_p_fde); case kOptFoldtext: - return &(win->w_p_fdt); + return &(ctx.win->w_p_fdt); case kOptFoldmarker: - return &(win->w_p_fmr); + return &(ctx.win->w_p_fmr); case kOptNumber: - return &(win->w_p_nu); + return &(ctx.win->w_p_nu); case kOptRelativenumber: - return &(win->w_p_rnu); + return &(ctx.win->w_p_rnu); case kOptNumberwidth: - return &(win->w_p_nuw); + return &(ctx.win->w_p_nuw); case kOptWinfixbuf: - return &(win->w_p_wfb); + return &(ctx.win->w_p_wfb); case kOptWinfixheight: - return &(win->w_p_wfh); + return &(ctx.win->w_p_wfh); case kOptWinfixwidth: - return &(win->w_p_wfw); + return &(ctx.win->w_p_wfw); case kOptPreviewwindow: - return &(win->w_p_pvw); + return &(ctx.win->w_p_pvw); case kOptRightleft: - return &(win->w_p_rl); + return &(ctx.win->w_p_rl); case kOptRightleftcmd: - return &(win->w_p_rlc); + return &(ctx.win->w_p_rlc); case kOptScroll: - return &(win->w_p_scr); + return &(ctx.win->w_p_scr); case kOptSmoothscroll: - return &(win->w_p_sms); + return &(ctx.win->w_p_sms); case kOptWrap: - return &(win->w_p_wrap); + return &(ctx.win->w_p_wrap); case kOptLinebreak: - return &(win->w_p_lbr); + return &(ctx.win->w_p_lbr); case kOptBreakindent: - return &(win->w_p_bri); + return &(ctx.win->w_p_bri); case kOptBreakindentopt: - return &(win->w_p_briopt); + return &(ctx.win->w_p_briopt); case kOptScrollbind: - return &(win->w_p_scb); + return &(ctx.win->w_p_scb); case kOptCursorbind: - return &(win->w_p_crb); + return &(ctx.win->w_p_crb); case kOptConcealcursor: - return &(win->w_p_cocu); + return &(ctx.win->w_p_cocu); case kOptConceallevel: - return &(win->w_p_cole); + return &(ctx.win->w_p_cole); case kOptAutoindent: - return &(buf->b_p_ai); + return &(ctx.buf->b_p_ai); case kOptBinary: - return &(buf->b_p_bin); + return &(ctx.buf->b_p_bin); case kOptBomb: - return &(buf->b_p_bomb); + return &(ctx.buf->b_p_bomb); case kOptBufhidden: - return &(buf->b_p_bh); + return &(ctx.buf->b_p_bh); case kOptBuftype: - return &(buf->b_p_bt); + return &(ctx.buf->b_p_bt); case kOptBuflisted: - return &(buf->b_p_bl); + return &(ctx.buf->b_p_bl); case kOptChannel: - return &(buf->b_p_channel); + return &(ctx.buf->b_p_channel); case kOptCopyindent: - return &(buf->b_p_ci); + return &(ctx.buf->b_p_ci); case kOptCindent: - return &(buf->b_p_cin); + return &(ctx.buf->b_p_cin); case kOptCinkeys: - return &(buf->b_p_cink); + return &(ctx.buf->b_p_cink); case kOptCinoptions: - return &(buf->b_p_cino); + return &(ctx.buf->b_p_cino); case kOptCinscopedecls: - return &(buf->b_p_cinsd); + return &(ctx.buf->b_p_cinsd); case kOptCinwords: - return &(buf->b_p_cinw); + return &(ctx.buf->b_p_cinw); case kOptComments: - return &(buf->b_p_com); + return &(ctx.buf->b_p_com); case kOptCommentstring: - return &(buf->b_p_cms); + return &(ctx.buf->b_p_cms); case kOptComplete: - return &(buf->b_p_cpt); + return &(ctx.buf->b_p_cpt); #ifdef BACKSLASH_IN_FILENAME case kOptCompleteslash: - return &(buf->b_p_csl); + return &(ctx.buf->b_p_csl); #endif case kOptCompletefunc: - return &(buf->b_p_cfu); + return &(ctx.buf->b_p_cfu); case kOptOmnifunc: - return &(buf->b_p_ofu); + return &(ctx.buf->b_p_ofu); case kOptEndoffile: - return &(buf->b_p_eof); + return &(ctx.buf->b_p_eof); case kOptEndofline: - return &(buf->b_p_eol); + return &(ctx.buf->b_p_eol); case kOptFixendofline: - return &(buf->b_p_fixeol); + return &(ctx.buf->b_p_fixeol); case kOptExpandtab: - return &(buf->b_p_et); + return &(ctx.buf->b_p_et); case kOptFileencoding: - return &(buf->b_p_fenc); + return &(ctx.buf->b_p_fenc); case kOptFileformat: - return &(buf->b_p_ff); + return &(ctx.buf->b_p_ff); case kOptFiletype: - return &(buf->b_p_ft); + return &(ctx.buf->b_p_ft); case kOptFormatoptions: - return &(buf->b_p_fo); + return &(ctx.buf->b_p_fo); case kOptFormatlistpat: - return &(buf->b_p_flp); + return &(ctx.buf->b_p_flp); case kOptIminsert: - return &(buf->b_p_iminsert); + return &(ctx.buf->b_p_iminsert); case kOptImsearch: - return &(buf->b_p_imsearch); + return &(ctx.buf->b_p_imsearch); case kOptInfercase: - return &(buf->b_p_inf); + return &(ctx.buf->b_p_inf); case kOptIskeyword: - return &(buf->b_p_isk); + return &(ctx.buf->b_p_isk); case kOptIncludeexpr: - return &(buf->b_p_inex); + return &(ctx.buf->b_p_inex); case kOptIndentexpr: - return &(buf->b_p_inde); + return &(ctx.buf->b_p_inde); case kOptIndentkeys: - return &(buf->b_p_indk); + return &(ctx.buf->b_p_indk); case kOptFormatexpr: - return &(buf->b_p_fex); + return &(ctx.buf->b_p_fex); case kOptLisp: - return &(buf->b_p_lisp); + return &(ctx.buf->b_p_lisp); case kOptLispoptions: - return &(buf->b_p_lop); + return &(ctx.buf->b_p_lop); case kOptModeline: - return &(buf->b_p_ml); + return &(ctx.buf->b_p_ml); case kOptMatchpairs: - return &(buf->b_p_mps); + return &(ctx.buf->b_p_mps); case kOptModifiable: - return &(buf->b_p_ma); + return &(ctx.buf->b_p_ma); case kOptModified: - return &(buf->b_changed); + return &(ctx.buf->b_changed); case kOptNrformats: - return &(buf->b_p_nf); + return &(ctx.buf->b_p_nf); case kOptPreserveindent: - return &(buf->b_p_pi); + return &(ctx.buf->b_p_pi); case kOptQuoteescape: - return &(buf->b_p_qe); + return &(ctx.buf->b_p_qe); case kOptReadonly: - return &(buf->b_p_ro); + return &(ctx.buf->b_p_ro); case kOptScrollback: - return &(buf->b_p_scbk); + return &(ctx.buf->b_p_scbk); case kOptSmartindent: - return &(buf->b_p_si); + return &(ctx.buf->b_p_si); case kOptSofttabstop: - return &(buf->b_p_sts); + return &(ctx.buf->b_p_sts); case kOptSuffixesadd: - return &(buf->b_p_sua); + return &(ctx.buf->b_p_sua); case kOptSwapfile: - return &(buf->b_p_swf); + return &(ctx.buf->b_p_swf); case kOptSynmaxcol: - return &(buf->b_p_smc); + return &(ctx.buf->b_p_smc); case kOptSyntax: - return &(buf->b_p_syn); + return &(ctx.buf->b_p_syn); case kOptSpellcapcheck: - return &(win->w_s->b_p_spc); + return &(ctx.win->w_s->b_p_spc); case kOptSpellfile: - return &(win->w_s->b_p_spf); + return &(ctx.win->w_s->b_p_spf); case kOptSpelllang: - return &(win->w_s->b_p_spl); + return &(ctx.win->w_s->b_p_spl); case kOptSpelloptions: - return &(win->w_s->b_p_spo); + return &(ctx.win->w_s->b_p_spo); case kOptShiftwidth: - return &(buf->b_p_sw); + return &(ctx.buf->b_p_sw); case kOptTagfunc: - return &(buf->b_p_tfu); + return &(ctx.buf->b_p_tfu); case kOptTabstop: - return &(buf->b_p_ts); + return &(ctx.buf->b_p_ts); case kOptTextwidth: - return &(buf->b_p_tw); + return &(ctx.buf->b_p_tw); case kOptUndofile: - return &(buf->b_p_udf); + return &(ctx.buf->b_p_udf); case kOptWrapmargin: - return &(buf->b_p_wm); + return &(ctx.buf->b_p_wm); case kOptVarsofttabstop: - return &(buf->b_p_vsts); + return &(ctx.buf->b_p_vsts); case kOptVartabstop: - return &(buf->b_p_vts); + return &(ctx.buf->b_p_vts); case kOptKeymap: - return &(buf->b_p_keymap); + return &(ctx.buf->b_p_keymap); case kOptSigncolumn: - return &(win->w_p_scl); + return &(ctx.win->w_p_scl); case kOptWinhighlight: - return &(win->w_p_winhl); + return &(ctx.win->w_p_winhl); case kOptWinblend: - return &(win->w_p_winbl); + return &(ctx.win->w_p_winbl); case kOptStatuscolumn: - return &(win->w_p_stc); + return &(ctx.win->w_p_stc); default: iemsg(_("E356: get_varp ERROR")); } // always return a valid pointer to avoid a crash! - return &(buf->b_p_wm); + return &(ctx.buf->b_p_wm); } -/// Get option index from option pointer -static inline OptIndex get_opt_idx(vimoption_T *opt) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE +/// Get the current context for options. +OptCtx option_ctx(void) { - return (OptIndex)(opt - options); + return (OptCtx){ .buf = curbuf, .win = curwin }; +} + +/// Get the context for options from a scope and pointer to target. +/// +/// @param scope Option scope. See OptScope in option.h. +/// @param from Pointer to target buffer/window/etc. +OptCtx option_ctx_from(OptScope scope, void *from) +{ + switch (scope) { + case kOptScopeGlobal: + return option_ctx(); + case kOptScopeBuf: + return (OptCtx){ .buf = (buf_T *)from, .win = curwin }; + case kOptScopeWin: + return (OptCtx){ .buf = ((win_T *)from)->w_buffer, .win = (win_T *)from }; + } + UNREACHABLE; +} + +/// Get pointer to option variable, depending on local or global scope. +/// +/// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). +void *get_varp_scope(vimoption_T *p, int opt_flags) +{ + return get_varp_scope_from(p, opt_flags, option_ctx()); } /// Get pointer to option variable. static inline void *get_varp(vimoption_T *p) { - return get_varp_from(p, curbuf, curwin); + return get_varp_from(p, option_ctx()); +} + +/// Get option index from option pointer +static inline OptIndex get_opt_idx(vimoption_T *opt) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE +{ + return (OptIndex)(opt - options); } /// Get the value of 'equalprg', either the buffer-local one or the global one. @@ -5799,9 +5705,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c return ExpandOldSetting(numMatches, matches); } - char *option_val = *(char **)get_option_varp_scope_from(expand_option_idx, - expand_option_flags, - curbuf, curwin); + char *option_val = *(char **)get_varp_scope(get_option(expand_option_idx), expand_option_flags); uint32_t option_flags = options[expand_option_idx].flags; diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 832e03148a..b76532b1eb 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -81,6 +81,12 @@ typedef struct { OptValData data; } OptVal; +/// Context that an option is being set for. +typedef struct { + win_T *win; + buf_T *buf; +} OptCtx; + /// :set operator types typedef enum { OP_NONE = 0, @@ -122,8 +128,7 @@ typedef struct { /// length of the error buffer size_t os_errbuflen; - void *os_win; - void *os_buf; + OptCtx os_ctx; } optset_T; /// Type for the callback function that is invoked after an option value is @@ -192,3 +197,12 @@ typedef struct { OptVal def_val; ///< default value LastSet last_set; ///< script in which the option was last set } vimoption_T; + +/// Execute code with autocmd context +#define WITH_AUCMD_CONTEXT(ctx, code) \ + do { \ + aco_save_T _aco; \ + aucmd_prepbuf_win(&_aco, ctx.buf, ctx.win); \ + code; \ + aucmd_restbuf(&_aco); \ + } while (0) diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 9b7b50ae04..632b4af573 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -567,7 +567,7 @@ int expand_set_backspace(optexpand_T *args, int *numMatches, char ***matches) /// The 'backupcopy' option is changed. const char *did_set_backupcopy(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; const char *oldval = args->os_oldval.string.data; int opt_flags = args->os_flags; char *bkc = p_bkc; @@ -655,7 +655,7 @@ const char *did_set_breakat(optset_T *args FUNC_ATTR_UNUSED) /// The 'breakindentopt' option is changed. const char *did_set_breakindentopt(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; char **varp = (char **)args->os_varp; if (briopt_check(*varp, varp == &win->w_p_briopt ? win : NULL) == FAIL) { @@ -682,7 +682,7 @@ int expand_set_breakindentopt(optexpand_T *args, int *numMatches, char ***matche /// The 'bufhidden' option is changed. const char *did_set_bufhidden(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; return did_set_opt_strings(buf->b_p_bh, opt_bh_values, false); } @@ -698,8 +698,8 @@ int expand_set_bufhidden(optexpand_T *args, int *numMatches, char ***matches) /// The 'buftype' option is changed. const char *did_set_buftype(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; - win_T *win = (win_T *)args->os_win; + buf_T *buf = args->os_ctx.buf; + win_T *win = args->os_ctx.win; // When 'buftype' is set, check for valid value. if ((buf->terminal && buf->b_p_bt[0] != 't') || (!buf->terminal && buf->b_p_bt[0] == 't') @@ -780,7 +780,7 @@ static const char *did_set_global_chars_option(win_T *win, char *val, CharsOptio /// The 'fillchars' option or the 'listchars' option is changed. const char *did_set_chars_option(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; char **varp = (char **)args->os_varp; const char *errmsg = NULL; @@ -815,7 +815,7 @@ int expand_set_chars_option(optexpand_T *args, int *numMatches, char ***matches) /// The 'cinoptions' option is changed. const char *did_set_cinoptions(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; // TODO(vim): recognize errors parse_cino(buf); @@ -840,7 +840,7 @@ int expand_set_clipboard(optexpand_T *args, int *numMatches, char ***matches) /// The 'colorcolumn' option is changed. const char *did_set_colorcolumn(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; char **varp = (char **)args->os_varp; return check_colorcolumn(*varp, varp == &win->w_p_cc ? win : NULL); } @@ -985,7 +985,7 @@ const char *did_set_completeitemalign(optset_T *args) /// The 'completeopt' option is changed. const char *did_set_completeopt(optset_T *args FUNC_ATTR_UNUSED) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; char *cot = p_cot; unsigned *flags = &cot_flags; @@ -1021,7 +1021,7 @@ int expand_set_completeopt(optexpand_T *args, int *numMatches, char ***matches) /// The 'completeslash' option is changed. const char *did_set_completeslash(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; if (check_opt_strings(p_csl, opt_csl_values, false) != OK || check_opt_strings(buf->b_p_csl, opt_csl_values, false) != OK) { return e_invarg; @@ -1068,7 +1068,7 @@ int expand_set_cpoptions(optexpand_T *args, int *numMatches, char ***matches) /// The 'cursorlineopt' option is changed. const char *did_set_cursorlineopt(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; char **varp = (char **)args->os_varp; // This could be changed to use opt_strings_flags() instead. @@ -1176,12 +1176,12 @@ int expand_set_eadirection(optexpand_T *args, int *numMatches, char ***matches) /// options is changed. const char *did_set_encoding(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; char **varp = (char **)args->os_varp; int opt_flags = args->os_flags; // Get the global option to compare with, otherwise we would have to check // two values for all local options. - char **gvarp = (char **)get_option_varp_scope_from(args->os_idx, OPT_GLOBAL, buf, NULL); + char **gvarp = (char **)get_varp_scope_from(get_option(args->os_idx), OPT_GLOBAL, args->os_ctx); if (gvarp == &p_fenc) { if (!MODIFIABLE(buf) && opt_flags != OPT_GLOBAL) { @@ -1246,7 +1246,7 @@ int expand_set_eventignore(optexpand_T *args, int *numMatches, char ***matches) /// The 'fileformat' option is changed. const char *did_set_fileformat(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; char **varp = (char **)args->os_varp; const char *oldval = args->os_oldval.string.data; int opt_flags = args->os_flags; @@ -1347,7 +1347,7 @@ int expand_set_foldcolumn(optexpand_T *args, int *numMatches, char ***matches) /// The 'foldexpr' option is changed. const char *did_set_foldexpr(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; did_set_optexpr(args); if (foldmethodIsExpr(win)) { foldUpdateAll(win); @@ -1358,7 +1358,7 @@ const char *did_set_foldexpr(optset_T *args) /// The 'foldignore' option is changed. const char *did_set_foldignore(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; if (foldmethodIsIndent(win)) { foldUpdateAll(win); } @@ -1368,7 +1368,7 @@ const char *did_set_foldignore(optset_T *args) /// The 'foldmarker' option is changed. const char *did_set_foldmarker(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; char **varp = (char **)args->os_varp; char *p = vim_strchr(*varp, ','); @@ -1390,7 +1390,7 @@ const char *did_set_foldmarker(optset_T *args) /// The 'foldmethod' option is changed. const char *did_set_foldmethod(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; char **varp = (char **)args->os_varp; if (check_opt_strings(*varp, opt_fdm_values, false) != OK || **varp == NUL) { return e_invarg; @@ -1536,7 +1536,7 @@ const char *did_set_iskeyword(optset_T *args) /// changed. const char *did_set_isopt(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; // 'isident', 'iskeyword', 'isprint' or 'isfname' option: refill g_chartab[] // If the new option is invalid, use old value. // 'lisp' option: refill g_chartab[] for '-' char @@ -1565,7 +1565,7 @@ int expand_set_jumpoptions(optexpand_T *args, int *numMatches, char ***matches) /// The 'keymap' option has changed. const char *did_set_keymap(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; char **varp = (char **)args->os_varp; int opt_flags = args->os_flags; @@ -2053,7 +2053,7 @@ int expand_set_showcmdloc(optexpand_T *args, int *numMatches, char ***matches) /// The 'signcolumn' option is changed. const char *did_set_signcolumn(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; char **varp = (char **)args->os_varp; const char *oldval = args->os_oldval.string.data; if (check_signcolumn(*varp, varp == &win->w_p_scl ? win : NULL) != OK) { @@ -2079,7 +2079,7 @@ int expand_set_signcolumn(optexpand_T *args, int *numMatches, char ***matches) /// The 'spellcapcheck' option is changed. const char *did_set_spellcapcheck(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; // When 'spellcapcheck' is set compile the regexp program. return compile_cap_prog(win->w_s); } @@ -2113,7 +2113,7 @@ const char *did_set_spelllang(optset_T *args) /// The 'spelloptions' option is changed. const char *did_set_spelloptions(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; int opt_flags = args->os_flags; const char *val = args->os_newval.string.data; @@ -2189,7 +2189,7 @@ const char *did_set_statusline(optset_T *args) static const char *did_set_statustabline_rulerformat(optset_T *args, bool rulerformat, bool statuscolumn) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; char **varp = (char **)args->os_varp; if (rulerformat) { // reset ru_wid first ru_wid = 0; @@ -2264,7 +2264,7 @@ const char *did_set_tabline(optset_T *args) /// The 'tagcase' option is changed. const char *did_set_tagcase(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; int opt_flags = args->os_flags; unsigned *flags; @@ -2337,7 +2337,7 @@ const char *did_set_titlestring(optset_T *args) /// The 'varsofttabstop' option is changed. const char *did_set_varsofttabstop(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; char **varp = (char **)args->os_varp; if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { @@ -2367,8 +2367,8 @@ const char *did_set_varsofttabstop(optset_T *args) /// The 'varstabstop' option is changed. const char *did_set_vartabstop(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; - win_T *win = (win_T *)args->os_win; + buf_T *buf = args->os_ctx.buf; + win_T *win = args->os_ctx.win; char **varp = (char **)args->os_varp; if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { @@ -2417,7 +2417,7 @@ const char *did_set_viewoptions(optset_T *args FUNC_ATTR_UNUSED) /// The 'virtualedit' option is changed. const char *did_set_virtualedit(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; char *ve = p_ve; unsigned *flags = &ve_flags; @@ -2527,7 +2527,7 @@ const char *did_set_winbar(optset_T *args) /// The 'winhighlight' option is changed. const char *did_set_winhighlight(optset_T *args) { - win_T *win = (win_T *)args->os_win; + win_T *win = args->os_ctx.win; char **varp = (char **)args->os_varp; if (!parse_winhl_opt(*varp, varp == &win->w_p_winhl ? win : NULL)) { return e_invarg; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index c676b00986..9375629abc 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -228,7 +228,7 @@ static Callback tfu_cb; // 'tagfunc' callback function /// a function (string), or function(<name>) or funcref(<name>) or a lambda. const char *did_set_tagfunc(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + buf_T *buf = args->os_ctx.buf; callback_free(&tfu_cb); callback_free(&buf->b_tfu_cb); diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index 3e791e2beb..78f3551087 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -411,8 +411,8 @@ win_T *win_float_create(bool enter, bool new_buf) return handle_error_and_cleanup(wp, &err); } buf->b_p_bl = false; // unlist - set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL, 0, - kOptScopeBuf, buf); + set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), + option_ctx_from(kOptScopeBuf, buf), OPT_LOCAL, 0); win_set_buf(wp, buf, &err); if (ERROR_SET(&err)) { return handle_error_and_cleanup(wp, &err); diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua index 92e798e7f3..a68a7722a4 100644 --- a/test/functional/lua/with_spec.lua +++ b/test/functional/lua/with_spec.lua @@ -882,11 +882,7 @@ describe('vim._with', function() eq({ bo = { cms_cur = '// %s', cms_other = '-- %s', ul_cur = 250, ul_other = -123456 }, wo = { ve_cur = 'insert', ve_other = 'block', winbl_cur = 25, winbl_other = 10 }, - -- Global `winbl` inside context ideally should be untouched and equal - -- to 50. It seems to be equal to 0 because `context.buf` uses - -- `aucmd_prepbuf` C approach which has no guarantees about window or - -- window option values inside context. - go = { cms = '-- %s', ul = 0, ve = 'none', winbl = 0, lmap = 'xy,yx' }, + go = { cms = '-- %s', ul = 0, ve = 'none', winbl = 50, lmap = 'xy,yx' }, }, out.inner) eq(out.before, out.after) end) |