diff options
Diffstat (limited to 'src')
| -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 |
13 files changed, 528 insertions, 552 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 |