diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 10:50:16 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 10:50:16 -0700 |
commit | 8a98d50685575d20fcd6ad0dc7031d489d5e5361 (patch) | |
tree | 9a2b95594af2c6fc1128c7cbfb73b67c1a8749cc | |
parent | 49fd5b067fed9744ee7e84f7db9209417023b5db (diff) | |
parent | 23fd9a2b29cedef01ad6597854bc42ffb1bab86a (diff) | |
download | rneovim-8a98d50685575d20fcd6ad0dc7031d489d5e5361.tar.gz rneovim-8a98d50685575d20fcd6ad0dc7031d489d5e5361.tar.bz2 rneovim-8a98d50685575d20fcd6ad0dc7031d489d5e5361.zip |
Merge branch 'userreg' into 20231130_mix
-rw-r--r-- | runtime/autoload/usermark.vim | 7 | ||||
-rw-r--r-- | runtime/autoload/userreg.vim | 7 | ||||
-rw-r--r-- | runtime/doc/options.txt | 51 | ||||
-rw-r--r-- | runtime/lua/vim/usermark.lua | 68 | ||||
-rw-r--r-- | runtime/lua/vim/userreg.lua | 51 | ||||
-rw-r--r-- | runtime/plugin/usermark.vim | 1 | ||||
-rw-r--r-- | runtime/plugin/userreg.vim | 1 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/eval.c | 10 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 2 | ||||
-rw-r--r-- | src/nvim/eval/vars.c | 15 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 8 | ||||
-rw-r--r-- | src/nvim/map.c | 3 | ||||
-rw-r--r-- | src/nvim/map_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/mark.c | 159 | ||||
-rw-r--r-- | src/nvim/ops.c | 412 | ||||
-rw-r--r-- | src/nvim/ops.h | 11 | ||||
-rw-r--r-- | src/nvim/option.c | 473 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/option_vars.h | 4 | ||||
-rw-r--r-- | src/nvim/options.lua | 92 | ||||
-rw-r--r-- | src/nvim/po/da.po | 2 | ||||
-rw-r--r-- | src/nvim/po/fr.po | 2 | ||||
-rw-r--r-- | src/nvim/po/tr.po | 2 | ||||
-rw-r--r-- | src/nvim/po/uk.po | 2 | ||||
-rw-r--r-- | src/nvim/shada.c | 4 | ||||
-rw-r--r-- | src/nvim/yankmap.c | 45 | ||||
-rw-r--r-- | src/nvim/yankmap.h | 25 |
28 files changed, 1107 insertions, 354 deletions
diff --git a/runtime/autoload/usermark.vim b/runtime/autoload/usermark.vim new file mode 100644 index 0000000000..b1b4113d1a --- /dev/null +++ b/runtime/autoload/usermark.vim @@ -0,0 +1,7 @@ +" This is used for the default userreg function. + +lua vim.usermark = require('vim.usermark') + +function! usermark#func(action, mark) abort + return v:lua.vim.usermark.fn(a:action, a:mark) +endfunction diff --git a/runtime/autoload/userreg.vim b/runtime/autoload/userreg.vim new file mode 100644 index 0000000000..fd026a12e6 --- /dev/null +++ b/runtime/autoload/userreg.vim @@ -0,0 +1,7 @@ +" This is used for the default userreg function. + +lua vim.userreg = require('vim.userreg') + +function! userreg#func(action, register, content) abort + return v:lua.vim.userreg.fn(a:action, a:register, a:content) +endfunction diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index f47093782c..ba1d848962 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -6757,6 +6757,57 @@ A jump table for the options with a short description can be found at |Q_op|. written to disk (see |crash-recovery|). Also used for the |CursorHold| autocommand event. + *'userregfunc'* *'urf'* +'userregfunc' 'urf' string (default "") + global + The option specifies a function to be used to handle any registers + that Neovim does not natively handle. This option unlocks all + characters to be used as registers by the user. + + The 'userregfunc' function is called each time a user register is read + from or written to. + + The 'userregfunc' function must take the following parameters: + + {action} The action being done on this register (either 'yank' + or 'put' + + {register} The string holding the name of the register. This + is always a single character, though multi-byte + characters are allowed. + + {content} If the action is 'yank' this is the content being + yanked into the register. The content is a dictionary + with the following items: + + {lines} The lines being yanked, as a list. + + {type} The type of yank, either "line", "char", or + "block" + + {width} The width in case of "block" mode. + + {additional_data} Additional data. (can be returned in + put mode). + + In case the action is 'put', the 'userregfunc' function should return + the content to place in that location. The content can either be a + string, in which case "char" mode is inferred, or it can return a + dictionary of the same template that populates 'content'. + + A very simple example of a 'userregfunc' function that behaves exactly + like traditional registers would look like: > + + let s:contents = {} + function! MyUserregFunction(action, register, content) abort + if a:action == "put" + return get(s:contents, a:register, "") + else + let s:contents[a:register] = a:content + endif + endfunction + set userregfunc=MyUserregFunction +< *'varsofttabstop'* *'vsts'* 'varsofttabstop' 'vsts' string (default "") local to buffer diff --git a/runtime/lua/vim/usermark.lua b/runtime/lua/vim/usermark.lua new file mode 100644 index 0000000000..0d1ec0ae0f --- /dev/null +++ b/runtime/lua/vim/usermark.lua @@ -0,0 +1,68 @@ +-- Defualt implementation of the usermarkfunc. This default implementation is +-- extensible and allows other plugins to register handlers for different +-- registers. +-- +-- The default handler behaves just as a normal register would. + +local vim = assert(vim) +local usermark = {} + +-- Returns a "default handler" which behaves like normal global marks. When a +-- call to set() is made, it stores the current line and col of the cursor and +-- the filename of the current file. +function usermark._default_handler() + local d = {} + + -- Called when a mark is recalled using the "'" command. Just returns what was + -- stored before or nothing if it was never set before. + function d.get(self, mark) + return self.content or {} + end + + -- Called when a mark is set using the "m" command. Stores the current cursor + -- position to be recalled at a later time. + function d.set(self, mark) + local r,c = unpack(vim.api.nvim_win_get_cursor(0)) + local file = vim.fn.expand("%:p") + + self.content = { + line = r; + col = c; + } + + if file ~= '' then + self.content.file = file + end + end + + return d +end + +-- The store for register default handler +usermark._marktable = {} + +-- Function for the 'usermarkfunc'. Will defer to the handler associated with +-- the provided mark. +-- +-- If not handler is registered to a given mark, the default handler is used, +-- which is a re-implementation of standard mark behavior. +function usermark.fn(action, mark) + if not usermark._marktable[mark] then + usermark._marktable[mark] = usermark._default_handler() + end + + if action == "get" then + return usermark._marktable[mark]:get(mark) + else + usermark._marktable[mark]:set(mark) + return nil + end +end + +-- Registers a handler with a mark. Gets and sets will then defer to this +-- handler when determining the mark's behavior. +function usermark.register_handler(mark, handler) + usermark._marktable[mark] = handler +end + +return usermark diff --git a/runtime/lua/vim/userreg.lua b/runtime/lua/vim/userreg.lua new file mode 100644 index 0000000000..5abcff0407 --- /dev/null +++ b/runtime/lua/vim/userreg.lua @@ -0,0 +1,51 @@ +-- Defualt implementation of the userregfunc. This default implementation is +-- extensible and allows other plugins to register handlers for different +-- registers. +-- +-- The default handler behaves just as a normal register would. + +local userreg = {} + +-- Returns a "default handler" which behaves exactly like the builtin registers +-- in Vim. Simply stores whatever was yanked and returns the last thing that was +-- yanked. +function userreg._default_handler() + local d = {} + + function d.do_yank(self, content) + self.content = content + end + + function d.do_put(self) + return self.content or {} + end + + return d +end + +-- The store for registers default handler +userreg._regtable = {} + +-- Function for the userreg. This function will defer to the handler registered +-- to the given register. If no handler is registered to the given register, the +-- default handler is used. +function userreg.fn(action, register, content) + if not userreg._regtable[register] then + userreg._regtable[register] = userreg._default_handler() + end + + if action == "yank" then + userreg._regtable[register]:do_yank(content) + return nil + else + return userreg._regtable[register]:do_put() + end +end + +-- Registers a handler with a register. Future yanks and puts will defer to the +-- handler when determining the content to put/yank. +function userreg.register_handler(register, handler) + userreg._regtable[register] = handler +end + +return userreg diff --git a/runtime/plugin/usermark.vim b/runtime/plugin/usermark.vim new file mode 100644 index 0000000000..917e7510f1 --- /dev/null +++ b/runtime/plugin/usermark.vim @@ -0,0 +1 @@ +set usermarkfunc=usermark#func diff --git a/runtime/plugin/userreg.vim b/runtime/plugin/userreg.vim new file mode 100644 index 0000000000..099e7c65cb --- /dev/null +++ b/runtime/plugin/userreg.vim @@ -0,0 +1 @@ +set userregfunc=userreg#func diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 8928eea028..93dfdaf6b7 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -540,12 +540,14 @@ struct file_buffer { #ifdef BACKSLASH_IN_FILENAME char *b_p_csl; ///< 'completeslash' #endif + char *b_p_umf; ///< 'usermarkfunc' char *b_p_cfu; ///< 'completefunc' Callback b_cfu_cb; ///< 'completefunc' callback char *b_p_ofu; ///< 'omnifunc' Callback b_ofu_cb; ///< 'omnifunc' callback char *b_p_tfu; ///< 'tagfunc' Callback b_tfu_cb; ///< 'tagfunc' callback + char *b_p_urf; ///< 'userregfunc' int b_p_eof; ///< 'endoffile' int b_p_eol; ///< 'endofline' int b_p_fixeol; ///< 'fixendofline' diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 6786316b8e..b11f2f2922 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3165,12 +3165,10 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan // Register contents: @r. case '@': (*arg)++; + int regname = mb_cptr2char_adv((const char**) arg); if (evaluate) { rettv->v_type = VAR_STRING; - rettv->vval.v_string = get_reg_contents(**arg, kGRegExprSrc); - } - if (**arg != NUL) { - (*arg)++; + rettv->vval.v_string = get_reg_contents(regname, kGRegExprSrc); } break; @@ -4483,7 +4481,7 @@ bool garbage_collect(bool testing) // registers (ShaDa additional data) { - const void *reg_iter = NULL; + iter_register_T reg_iter = ITER_REGISTER_NULL; do { yankreg_T reg; char name = NUL; @@ -4492,7 +4490,7 @@ bool garbage_collect(bool testing) if (name != NUL) { ABORTING(set_ref_dict)(reg.additional_data, copyID); } - } while (reg_iter != NULL); + } while (reg_iter != ITER_REGISTER_NULL); } // global marks (ShaDa additional data) diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 0054c47678..7191ad34fc 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3165,6 +3165,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) "title", "user-commands", // was accidentally included in 5.4 "user_commands", + "usermarks", "vartabs", "vertsplit", "vimscript-1", @@ -3181,6 +3182,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) "xattr", #endif "nvim", + "rneovim", }; // XXX: eval_has_provider() may shell out :( diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 670ee39f4b..74d70ca482 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -552,7 +552,7 @@ const char *skip_var_list(const char *arg, int *var_count, int *semicolon) static const char *skip_var_one(const char *arg) { if (*arg == '@' && arg[1] != NUL) { - return arg + 2; + return arg + 1 + utfc_ptr2len(arg + 1); } return find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START); @@ -856,16 +856,20 @@ static char *ex_let_register(char *arg, typval_T *const tv, const bool is_const, char *arg_end = NULL; arg++; + + int regname = utf_ptr2char(arg); + int mblen = utf_ptr2len(arg); + if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) { semsg(_(e_letwrong), op); } else if (endchars != NULL - && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + 1))) == NULL) { + && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + mblen))) == NULL) { emsg(_(e_letunexp)); } else { char *ptofree = NULL; const char *p = tv_get_string_chk(tv); if (p != NULL && op != NULL && *op == '.') { - char *s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc); + char *s = get_reg_contents(*arg == '@' ? '"' : regname, kGRegExprSrc); if (s != NULL) { ptofree = concat_str(s, p); p = ptofree; @@ -873,8 +877,9 @@ static char *ex_let_register(char *arg, typval_T *const tv, const bool is_const, } } if (p != NULL) { - write_reg_contents(*arg == '@' ? '"' : *arg, p, (ssize_t)strlen(p), false); - arg_end = arg + 1; + write_reg_contents(*arg == '@' ? '"' : regname, + p, (ssize_t)strlen(p), false); + arg_end = arg + mblen; } xfree(ptofree); } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index bf5a3944e6..99e16bae11 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3223,7 +3223,7 @@ char *skip_range(const char *cmd, int *ctx) } } if (*cmd != NUL) { - cmd++; + cmd += utf_ptr2len(cmd); } } @@ -3367,13 +3367,13 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int goto error; } if (skip) { - cmd++; + cmd += utfc_ptr2len(cmd); } else { // Only accept a mark in another file when it is // used by itself: ":'M". MarkGet flag = to_other_file && cmd[1] == NUL ? kMarkAll : kMarkBufLocal; - fmark_T *fm = mark_get(curbuf, curwin, NULL, flag, *cmd); - cmd++; + fmark_T *fm = mark_get(curbuf, curwin, NULL, flag, utf_ptr2char(cmd)); + cmd += utf_ptr2len(cmd); if (fm != NULL && fm->fnum != curbuf->handle) { (void)mark_move_to(fm, 0); // Jumped to another file. diff --git a/src/nvim/map.c b/src/nvim/map.c index be6bf58daa..d7d1a00158 100644 --- a/src/nvim/map.c +++ b/src/nvim/map.c @@ -118,6 +118,9 @@ void mh_clear(MapHash *h) #define VAL_NAME(x) quasiquote(x, ptr_t) #include "nvim/map_value_impl.c.h" #undef VAL_NAME +#define VAL_NAME(x) quasiquote(x, int) +#include "nvim/map_value_impl.c.h" +#undef VAL_NAME #undef KEY_NAME #define KEY_NAME(x) x##cstr_t diff --git a/src/nvim/map_defs.h b/src/nvim/map_defs.h index 147c03327a..b6bb172bb0 100644 --- a/src/nvim/map_defs.h +++ b/src/nvim/map_defs.h @@ -152,6 +152,7 @@ KEY_DECLS(HlEntry) KEY_DECLS(ColorKey) MAP_DECLS(int, int) +MAP_DECLS(ptr_t, int) MAP_DECLS(int, ptr_t) MAP_DECLS(cstr_t, ptr_t) MAP_DECLS(cstr_t, int) diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 5839cf7a2e..7dacd03891 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -22,6 +22,7 @@ #include "nvim/globals.h" #include "nvim/highlight.h" #include "nvim/mark.h" +#include "nvim/mark_defs.h" #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" @@ -37,6 +38,8 @@ #include "nvim/strings.h" #include "nvim/textobject.h" #include "nvim/vim_defs.h" +#include "nvim/map_defs.h" +#include "nvim/eval/userfunc.h" // This file contains routines to maintain and manipulate marks. @@ -46,6 +49,33 @@ // There are marks 'A - 'Z (set by user) and '0 to '9 (set when writing // shada). +static struct { + Map(int, ptr_t) named; +} usermarks; +bool usermarks_init; + +static xfmark_T* lookup_user_mark(int mark) +{ + if (!usermarks_init) { + usermarks.named = (Map(int, ptr_t)) MAP_INIT; + usermarks_init = 1; + } + + bool is_new = false; + xfmark_T **ret = + (xfmark_T**) map_put_ref(int, ptr_t)(&usermarks.named, mark, NULL, &is_new); + + if (ret) { + if (is_new) { + *ret = xcalloc(sizeof(xfmark_T), 1); + } + + return *ret; + } + + return NULL; +} + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "mark.c.generated.h" #endif @@ -153,7 +183,8 @@ int setmark_pos(int c, pos_T *pos, int fnum, fmarkv_T *view_pt) RESET_XFMARK(namedfm + i, *pos, fnum, view, NULL); return OK; } - return FAIL; + + return mark_set_user(buf, c); } // Set the previous context mark to the current position and add it to the @@ -334,6 +365,15 @@ fmark_T *mark_get(buf_T *buf, win_T *win, fmark_T *fmp, MarkGet flag, int name) // Local Marks fm = mark_get_local(buf, win, name); } + + if (!fm) { + // Get usermark. + xfmark_T* xm = mark_get_user(buf, name); + if (xm) { + fm = &xm->fmark; + } + } + if (fmp != NULL && fm != NULL) { *fmp = *fm; return fmp; @@ -422,6 +462,123 @@ fmark_T *mark_get_local(buf_T *buf, win_T *win, int name) return mark; } +/// Loads the mark 'out' with the results from calling the usermarkfunc. +/// +/// @param umf String for the usermarkfunc +/// @param name name for the mark +/// @param[out] out the mark to write the results to. +static int call_umf( + const char* umf, int name, typval_T* out, const char* get_or_set_a) +{ + char markname_str[5]; + char get_or_set[4]; + int len; + + strncpy(get_or_set, get_or_set_a, sizeof(get_or_set)); + get_or_set[3] = 0; + + len = (*utf_char2len)(name); + markname_str[len] = 0; + utf_char2bytes(name, markname_str); + + typval_T args[3]; + args[0].v_type = VAR_STRING; + args[1].v_type = VAR_STRING; + args[2].v_type = VAR_UNKNOWN; + + args[0].vval.v_string = get_or_set; + args[1].vval.v_string = markname_str; + + funcexe_T funcexe = FUNCEXE_INIT; + funcexe.fe_evaluate = true; + + return call_func(umf, -1, out, 2, args, &funcexe); +} + +static int typval_to_xfmark(buf_T* buf, xfmark_T* out, typval_T* in) +{ + varnumber_T line; + varnumber_T col; + char* filename = NULL; + + switch (in->v_type) { + case VAR_DICT: + line = tv_dict_get_number(in->vval.v_dict, "line"); + col = tv_dict_get_number(in->vval.v_dict, "col"); + filename = tv_dict_get_string(in->vval.v_dict, "file", true); + break; + + case VAR_NUMBER: + line = in->vval.v_number; + col = 1; + break; + + default: + return -1; + } + + free_xfmark(*out); + memset(out, 0, sizeof(*out)); + + out->fname = filename; + out->fmark.mark.col = (int) col; + out->fmark.mark.lnum = (int) line; + out->fmark.fnum = 0; + out->fmark.timestamp = os_time(); + + return 0; +} + +/// Gets marks that are defined by the user. +/// +/// @param buf the buffer +/// @param name name fo the mark +xfmark_T *mark_get_user(buf_T* buf, int name) +{ + const char* umf = (const char*) buf->b_p_umf; + + if (!umf) { + return NULL; + } + + xfmark_T* mark = lookup_user_mark(name); + if (mark) { + typval_T* typval = xcalloc(sizeof(typval_T), 1); + call_umf(umf, name, typval, "get"); + typval_to_xfmark(buf, mark, typval); + tv_free(typval); + + if (mark->fname) { + buf_T* buffer = + buflist_new( + mark->fname, NULL, mark->fmark.mark.lnum, BLN_CURBUF | BLN_LISTED); + + if (buffer) { + mark->fmark.fnum = buffer->b_fnum; + } + } else { + mark->fmark.fnum = buf->b_fnum; + } + } + + return mark; +} + +int mark_set_user(buf_T* buf, int name) +{ + const char* umf = (const char*) buf->b_p_umf; + + if (!umf) { + return FAIL; + } + + typval_T* out = xcalloc(sizeof(typval_T), 1); + call_umf(umf, name, out, "set"); + tv_free(out); + + return OK; +} + /// Get marks that are actually motions but return them as marks /// /// Gets the following motions as marks: '{', '}', '(', ')' diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 3a4e87edf7..8c8900710d 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -23,6 +23,7 @@ #include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/eval/userfunc.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_getln.h" @@ -62,8 +63,24 @@ #include "nvim/undo.h" #include "nvim/vim_defs.h" #include "nvim/window.h" +#include "nvim/yankmap.h" -static yankreg_T y_regs[NUM_REGISTERS] = { 0 }; +struct yank_registers { + yankmap_T inner; +}; + +yank_registers_T y_regs; + +static yankreg_T *get_reg(yank_registers_T *regs, int idx) +{ + return yankmap_get(®s->inner, idx); + +} + +static yankreg_T *get_global_reg(int idx) +{ + return get_reg(&y_regs, idx); +} static yankreg_T *y_previous = NULL; // ptr to last written yankreg @@ -771,6 +788,24 @@ char *get_expr_line_src(void) return xstrdup(expr_line); } + +int get_userreg(int regname) +{ + if ((regname >= 'a' && regname <= 'z') + || (regname >= 'A' && regname <= 'Z') + || (regname >= '0' && regname <= '9') + || (regname <= 127 && strchr("\"-:.%#=*+_/", regname)) + || regname == Ctrl_F + || regname == Ctrl_P + || regname == Ctrl_W + || regname == Ctrl_A + || (regname + USER_REGISTERS_START) < regname) { + return -1; + } + + return regname + USER_REGISTERS_START; +} + /// @return whether `regname` is a valid name of a yank register. /// /// @note: There is no check for 0 (default register), caller should do this. @@ -787,12 +822,156 @@ bool valid_yank_reg(int regname, bool writing) || regname == '-' || regname == '_' || regname == '*' - || regname == '+') { + || regname == '+' + || get_userreg(regname) != -1) { return true; } return false; } +static int call_userreg_put(const char* urf, int regname, typval_T* out) +{ + char regname_str[5]; + int len; + + len = utf_char2len(regname); + regname_str[len] = 0; + utf_char2bytes(regname, regname_str); + + typval_T args[3]; + args[0].v_type = VAR_STRING; + args[1].v_type = VAR_STRING; + args[2].v_type = VAR_NUMBER; + + args[0].vval.v_string = "put"; + args[1].vval.v_string = regname_str; + args[2].vval.v_number = 0; + + funcexe_T funcexe = FUNCEXE_INIT; + funcexe.fe_evaluate = true; + + return call_func( + urf, + -1, + out, + /* argcount_in = */ 3, + args, + &funcexe); +} + +// Converts a typval returned from the userregfunction to a register. +static void typval_to_yankreg(yankreg_T* yankreg, typval_T* val) +{ + if (!yankreg || !val) { + return; + } + + char* type; + dict_T* dict; + typval_T tv; + size_t i; + size_t sz; + + free_register(yankreg); + memset(yankreg, 0, sizeof(*yankreg)); + + switch (val->v_type) { + + case VAR_DICT: + dict = val->vval.v_dict; + type = tv_dict_get_string(dict, "type", false); + + if (!strcmp(type, "block")) { + yankreg->y_width = (int) tv_dict_get_number(dict, "width"); + yankreg->y_type = kMTBlockWise; + } else if (!strcmp(type, "line")) { + yankreg->y_type = kMTLineWise; + } else { + yankreg->y_type = kMTCharWise; + } + + if (tv_dict_get_tv(dict, "lines", &tv) == OK) { + if (tv.v_type == VAR_STRING) { + yankreg->y_array = (char**) xcalloc(sizeof(char*), 1); + yankreg->y_array[0] = strdup(tv.vval.v_string); + } else if (tv.v_type == VAR_LIST) { + yankreg->y_array = + (char**) xcalloc(sizeof(char*), (size_t) tv_list_len(tv.vval.v_list)); + + i = 0; + TV_LIST_ITER_CONST(tv.vval.v_list, li, { + if (li->li_tv.v_type == VAR_STRING) { + yankreg->y_array[i] = strdup(tv_get_string(&li->li_tv)); + } else { + yankreg->y_array[i] = NULL; + } + ++ i; + }); + + yankreg->y_size = i; + } + } else { + yankreg->y_array = NULL; + } + + if (tv_dict_get_tv(dict, "additional_data", &tv) == OK) { + if (tv.v_type == VAR_DICT) { + yankreg->additional_data = tv.vval.v_dict; + } + } + break; + + case VAR_LIST: + yankreg->y_type = kMTLineWise; + sz = (size_t) tv_list_len(val->vval.v_list); + yankreg->y_array = (char**) xcalloc(sizeof(char*), sz); + yankreg->y_size = sz; + i = 0; + TV_LIST_ITER_CONST(val->vval.v_list, li, { + yankreg->y_array[i] = strdup(tv_get_string(&li->li_tv)); + i ++; + }); + break; + + default: + yankreg->y_type = kMTCharWise; + yankreg->y_size = 1; + + if (val->vval.v_string) { + yankreg->y_array = (char**) xcalloc(sizeof(char*), 1); + yankreg->y_array[0] = strdup(tv_get_string(val)); + } else { + yankreg->y_array = NULL; + } + + break; + + } + + yankreg->timestamp = os_time(); +} + +static void copy_userreg(yankreg_T* into, int regname) +{ + if (!into) { + return; + } + + if (!curbuf->b_p_urf || strlen(curbuf->b_p_urf) == 0) { + return; + } + + typval_T* ret = xmalloc(sizeof(typval_T)); + + if (call_userreg_put(curbuf->b_p_urf, regname, ret) == FAIL) { + return; + } + + typval_to_yankreg(into, ret); + + tv_free(ret); +} + /// @return yankreg_T to use, according to the value of `regname`. /// Cannot handle the '_' (black hole) register. /// Must only be called with a valid register name! @@ -830,7 +1009,11 @@ yankreg_T *get_yank_register(int regname, int mode) if (i == -1) { i = 0; } - reg = &y_regs[i]; + reg = get_global_reg(i); + if (get_userreg(regname) != -1 && mode != YREG_YANK) { + // If the mode is not yank, copy the userreg data to the reg. + copy_userreg(reg, regname); + } if (mode == YREG_YANK) { // remember the written register for unnamed paste @@ -856,7 +1039,7 @@ yankreg_T *copy_register(int name) if (copy->y_size == 0) { copy->y_array = NULL; } else { - copy->y_array = xcalloc(copy->y_size, sizeof(char *)); + copy->y_array = (char**) xcalloc(copy->y_size, sizeof(char *)); for (size_t i = 0; i < copy->y_size; i++) { copy->y_array[i] = xstrdup(reg->y_array[i]); } @@ -887,8 +1070,7 @@ int do_record(int c) if (reg_recording == 0) { // start recording - // registers 0-9, a-z and " are allowed - if (c < 0 || (!ASCII_ISALNUM(c) && c != '"')) { + if (c < 0) { retval = FAIL; } else { reg_recording = c; @@ -913,9 +1095,10 @@ int do_record(int c) } // Name of requested register, or empty string for unnamed operation. - char buf[NUMBUFLEN + 2]; - buf[0] = (char)regname; - buf[1] = NUL; + char buf[NUMBUFLEN + 5]; + int len = (*utf_char2len)(regname); + utf_char2bytes(regname, buf); + buf[len] = NUL; (void)tv_dict_add_str(dict, S_LEN("regname"), buf); tv_dict_set_keys_readonly(dict); @@ -992,6 +1175,9 @@ static int stuff_yank(int regname, char *p) reg->y_type = kMTCharWise; } reg->timestamp = os_time(); + if (get_userreg(regname) != -1) { + return eval_yank_userreg(curbuf->b_p_urf, regname, reg); + } return OK; } @@ -1284,6 +1470,90 @@ int insert_reg(int regname, bool literally_arg) return retval; } +/// Converts a yankreg to a dict which can be used as an argument to the +// userregfunc. +static dict_T* yankreg_to_dict(yankreg_T* yankreg) { + dict_T *const dict = tv_dict_alloc(); + dict->dv_refcount = 1; + tv_dict_add_nr(dict, S_LEN("width"), yankreg->y_width); + + const char* type; + + switch(yankreg->y_type) { + case kMTLineWise: + type = "line"; + break; + case kMTCharWise: + type = "char"; + break; + case kMTBlockWise: + type = "block"; + break; + default: + type = "unknown"; + } + + tv_dict_add_str(dict, S_LEN("type"), type); + if (yankreg->additional_data) { + tv_dict_add_dict(dict, S_LEN("additional_data"), yankreg->additional_data); + } + + list_T *const lines = tv_list_alloc((long)yankreg->y_size); + + size_t i; + for (i = 0; i < yankreg->y_size; ++ i) { + tv_list_append_string( + lines, yankreg->y_array[i], (long)strlen(yankreg->y_array[i])); + } + + tv_dict_add_list(dict, S_LEN("lines"), lines); + + return dict; +} + +/* + * Executes the yank() function on a user-defined register to set the contents + * of that register. + */ +static int eval_yank_userreg(const char *ufn, int regname, yankreg_T *reg) +{ + if (!reg) + return -1; + + int ret, len; + char regname_str[5]; + + len = (*utf_char2len)(regname); + regname_str[len] = 0; + utf_char2bytes(regname, regname_str); + + typval_T args[4]; + args[0].v_type = VAR_STRING; + args[1].v_type = VAR_STRING; + args[2].v_type = VAR_DICT; + args[3].v_type = VAR_UNKNOWN; + + args[0].vval.v_string = "yank"; + args[1].vval.v_string = regname_str; + args[2].vval.v_dict = yankreg_to_dict(reg); + + funcexe_T funcexe = FUNCEXE_INIT; + funcexe.fe_evaluate = true; + + typval_T* out = xmalloc(sizeof(typval_T)); + return call_func( + ufn, + -1, + out, + /* argcount_in = */ 3, + args, + &funcexe + ); + + tv_free(out); + return ret; +} + /// If "regname" is a special register, return true and store a pointer to its /// value in "argp". /// @@ -1367,6 +1637,9 @@ bool get_spec_reg(int regname, char **argp, bool *allocated, bool errmsg) case '_': // black hole: always empty *argp = ""; return true; + + default: + break; } return false; @@ -1413,14 +1686,14 @@ bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr) /// Shift the delete registers: "9 is cleared, "8 becomes "9, etc. static void shift_delete_registers(bool y_append) { - free_register(&y_regs[9]); // free register "9 + free_register(get_global_reg(9)); // free register "9 for (int n = 9; n > 1; n--) { - y_regs[n] = y_regs[n - 1]; + *get_global_reg(n) = *get_global_reg(n - 1); } if (!y_append) { - y_previous = &y_regs[1]; + y_previous = get_global_reg(1); } - y_regs[1].y_array = NULL; // set register "1 to empty + get_global_reg(1)->y_array = NULL; // set register "1 to empty } /// Handle a delete operation. @@ -1513,7 +1786,7 @@ int op_delete(oparg_T *oap) if (oap->motion_type == kMTLineWise || oap->line_count > 1 || oap->use_reg_one) { shift_delete_registers(is_append_register(oap->regname)); - reg = &y_regs[1]; + reg = get_global_reg(1); op_yank_reg(oap, false, reg, false); did_yank = true; } @@ -2520,11 +2793,20 @@ int op_change(oparg_T *oap) return retval; } + +/* + * set all the yank registers to empty (called from main()) + */ +void init_yank(void) +{ + init_yankmap(&y_regs.inner); +} + #if defined(EXITFREE) void clear_registers(void) { for (int i = 0; i < NUM_REGISTERS; i++) { - free_register(&y_regs[i]); + free_register(get_global_reg(i)); } } @@ -2570,6 +2852,14 @@ bool op_yank(oparg_T *oap, bool message) yankreg_T *reg = get_yank_register(oap->regname, YREG_YANK); op_yank_reg(oap, message, reg, is_append_register(oap->regname)); + + if (get_userreg(oap->regname) != -1) { + if (eval_yank_userreg(curbuf->b_p_urf, oap->regname, reg) == -1) { + beep_flush(); + return false; + } + } + set_clipboard(oap->regname, reg); do_autocmd_textyankpost(oap, reg); @@ -2748,7 +3038,11 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) if (oap->regname == NUL) { *namebuf = NUL; } else { - vim_snprintf(namebuf, sizeof(namebuf), _(" into \"%c"), oap->regname); + char buf[5]; + int len = (*utf_char2len) (oap->regname); + utf_char2bytes(oap->regname, buf); + buf[len] = 0; + vim_snprintf(namebuf, sizeof(namebuf), _(" into \"%s"), buf); } // redisplay now, so message is not deleted @@ -2818,6 +3112,7 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg) FUNC_ATTR_NONNULL_ALL { static bool recursive = false; + int len; if (recursive || !has_event(EVENT_TEXTYANKPOST)) { // No autocommand was defined, or we yanked from this autocommand. @@ -2839,13 +3134,15 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg) (void)tv_dict_add_list(dict, S_LEN("regcontents"), list); // Register type. - char buf[NUMBUFLEN + 2]; + char buf[NUMBUFLEN + 6]; format_reg_type(reg->y_type, reg->y_width, buf, ARRAY_SIZE(buf)); (void)tv_dict_add_str(dict, S_LEN("regtype"), buf); // Name of requested register, or empty string for unnamed operation. - buf[0] = (char)oap->regname; - buf[1] = NUL; + len = (*utf_char2len)(oap->regname); + buf[len] = 0; + utf_char2bytes(oap->regname, buf); + recursive = true; (void)tv_dict_add_str(dict, S_LEN("regname"), buf); // Motion type: inclusive or exclusive. @@ -3050,6 +3347,10 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) reg = get_yank_register(regname, YREG_PASTE); } + if (get_userreg(regname) != -1) { + copy_userreg(reg, regname); + } + y_type = reg->y_type; y_width = reg->y_width; y_size = reg->y_size; @@ -3724,7 +4025,7 @@ int get_register_name(int num) /// @return the index of the register "" points to. int get_unname_register(void) { - return y_previous == NULL ? -1 : (int)(y_previous - &y_regs[0]); + return yankmap_find(&y_regs.inner, y_previous); } /// ":dis" and ":registers": Display the contents of the yank registers. @@ -3761,10 +4062,10 @@ void ex_display(exarg_T *eap) if (y_previous != NULL) { yb = y_previous; } else { - yb = &(y_regs[0]); + yb = get_global_reg(0); } } else { - yb = &(y_regs[i]); + yb = get_global_reg(i); } get_clipboard(name, &yb, true); @@ -4957,6 +5258,10 @@ static yankreg_T *init_write_reg(int name, yankreg_T **old_y_previous, bool must static void finish_write_reg(int name, yankreg_T *reg, yankreg_T *old_y_previous) { + if (get_userreg(name) != -1) { + eval_yank_userreg(curbuf->b_p_urf, name, reg); + } + // Send text of clipboard register to the clipboard. set_clipboard(name, reg); @@ -6409,7 +6714,7 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing) } if (explicit_cb_reg) { - target = &y_regs[*name == '*' ? STAR_REGISTER : PLUS_REGISTER]; + target = get_global_reg(*name == '*' ? STAR_REGISTER : PLUS_REGISTER); if (writing && (cb_flags & (*name == '*' ? CB_UNNAMED : CB_UNNAMEDPLUS))) { clipboard_needs_update = false; } @@ -6426,10 +6731,10 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing) if (cb_flags & CB_UNNAMEDPLUS) { *name = (cb_flags & CB_UNNAMED && writing) ? '"' : '+'; - target = &y_regs[PLUS_REGISTER]; + target = get_global_reg(PLUS_REGISTER); } else { *name = '*'; - target = &y_regs[STAR_REGISTER]; + target = get_global_reg(STAR_REGISTER); } goto end; } @@ -6745,11 +7050,11 @@ static inline bool reg_empty(const yankreg_T *const reg) /// Iterate over global registers. /// /// @see op_register_iter -const void *op_global_reg_iter(const void *const iter, char *const name, yankreg_T *const reg, - bool *is_unnamed) +iter_register_T op_global_reg_iter(iter_register_T iter, char *const name, + yankreg_T *const reg, bool *is_unnamed) FUNC_ATTR_NONNULL_ARG(2, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT { - return op_reg_iter(iter, y_regs, name, reg, is_unnamed); + return op_reg_iter(iter, &y_regs, name, reg, is_unnamed); } /// Iterate over registers `regs`. @@ -6761,30 +7066,33 @@ const void *op_global_reg_iter(const void *const iter, char *const name, yankreg /// /// @return Pointer that must be passed to next `op_register_iter` call or /// NULL if iteration is over. -const void *op_reg_iter(const void *const iter, const yankreg_T *const regs, char *const name, - yankreg_T *const reg, bool *is_unnamed) +iter_register_T op_reg_iter(iter_register_T iter, yank_registers_T *regs, + char *const name, yankreg_T *const reg, + bool *is_unnamed) FUNC_ATTR_NONNULL_ARG(3, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT { *name = NUL; - const yankreg_T *iter_reg = (iter == NULL - ? &(regs[0]) - : (const yankreg_T *const)iter); - while (iter_reg - &(regs[0]) < NUM_SAVED_REGISTERS && reg_empty(iter_reg)) { - iter_reg++; + int iter_idx = (int)(iter == ITER_REGISTER_NULL ? 0 : iter - 1); + + while (iter_idx < NUM_SAVED_REGISTERS && reg_empty(get_reg(regs, iter_idx))) { + ++iter_idx; } - if (iter_reg - &(regs[0]) == NUM_SAVED_REGISTERS || reg_empty(iter_reg)) { - return NULL; + + if (iter_idx >= NUM_SAVED_REGISTERS || reg_empty(get_reg(regs, iter_idx))) { + return ITER_REGISTER_NULL; } - int iter_off = (int)(iter_reg - &(regs[0])); - *name = (char)get_register_name(iter_off); - *reg = *iter_reg; - *is_unnamed = (iter_reg == y_previous); - while (++iter_reg - &(regs[0]) < NUM_SAVED_REGISTERS) { - if (!reg_empty(iter_reg)) { - return (void *)iter_reg; + + *reg = *get_reg(regs, iter_idx); + *name = (char) get_register_name(iter_idx); + *is_unnamed = (get_reg(regs, iter_idx) == y_previous); + + while (++iter_idx < NUM_SAVED_REGISTERS) { + if (!reg_empty(get_reg(regs, iter_idx))) { + return iter_idx + 1; } } - return NULL; + + return ITER_REGISTER_NULL; } /// Get a number of non-empty registers @@ -6792,8 +7100,8 @@ size_t op_reg_amount(void) FUNC_ATTR_WARN_UNUSED_RESULT { size_t ret = 0; - for (size_t i = 0; i < NUM_SAVED_REGISTERS; i++) { - if (!reg_empty(y_regs + i)) { + for (int i = 0; i < NUM_SAVED_REGISTERS; i++) { + if (!reg_empty(get_global_reg(i))) { ret++; } } @@ -6813,11 +7121,11 @@ bool op_reg_set(const char name, const yankreg_T reg, bool is_unnamed) if (i == -1) { return false; } - free_register(&y_regs[i]); - y_regs[i] = reg; + free_register(get_global_reg(i)); + *get_global_reg(i) = reg; if (is_unnamed) { - y_previous = &y_regs[i]; + y_previous = get_global_reg(i); } return true; } @@ -6833,7 +7141,7 @@ const yankreg_T *op_reg_get(const char name) if (i == -1) { return NULL; } - return &y_regs[i]; + return get_global_reg(i); } /// Set the previous yank register @@ -6848,7 +7156,7 @@ bool op_reg_set_previous(const char name) return false; } - y_previous = &y_regs[i]; + y_previous = get_global_reg(i); return true; } diff --git a/src/nvim/ops.h b/src/nvim/ops.h index 4dab51b15d..519b946f6d 100644 --- a/src/nvim/ops.h +++ b/src/nvim/ops.h @@ -19,6 +19,7 @@ typedef int (*Indenter)(void); /// flags for do_put() enum { + ITER_REGISTER_NULL = 0, PUT_FIXINDENT = 1, ///< make indent look nice PUT_CURSEND = 2, ///< leave cursor after end of new text PUT_CURSLINE = 4, ///< leave cursor on last line of new text @@ -42,6 +43,7 @@ enum { STAR_REGISTER = 37, PLUS_REGISTER = 38, NUM_REGISTERS = 39, + USER_REGISTERS_START = 39 }; /// Operator IDs; The order must correspond to opchars[] in ops.c! @@ -101,6 +103,8 @@ typedef enum { YREG_YANK, YREG_PUT, } yreg_mode_t; +/// Returns a reference to a user-defined register. +int get_userreg(const int regname); static inline int op_reg_index(int regname) REAL_FATTR_CONST; @@ -125,13 +129,18 @@ static inline int op_reg_index(const int regname) } else if (regname == '+') { return PLUS_REGISTER; } else { - return -1; + return get_userreg(regname); } } static inline bool is_literal_register(int regname) REAL_FATTR_CONST; +struct yank_registers; +typedef struct yank_registers yank_registers_T; + +typedef size_t iter_register_T; + /// @see get_yank_register /// @return true when register should be inserted literally /// (selection or clipboard) diff --git a/src/nvim/option.c b/src/nvim/option.c index 882722a575..fd4f1eb50f 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -24,8 +24,6 @@ #include <stdlib.h> #include <string.h> -#include "auto/config.h" -#include "klib/kvec.h" #include "nvim/api/extmark.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" @@ -98,22 +96,20 @@ #include "nvim/vim_defs.h" #include "nvim/window.h" +#include "auto/config.h" +#include "klib/kvec.h" + #ifdef BACKSLASH_IN_FILENAME # include "nvim/arglist.h" #endif -static const char e_unknown_option[] - = N_("E518: Unknown option"); -static const char e_not_allowed_in_modeline[] - = N_("E520: Not allowed in a modeline"); +static const char e_unknown_option[] = N_("E518: Unknown option"); +static const char e_not_allowed_in_modeline[] = N_("E520: Not allowed in a modeline"); static const char e_not_allowed_in_modeline_when_modelineexpr_is_off[] = N_("E992: Not allowed in a modeline when 'modelineexpr' is off"); -static const char e_key_code_not_set[] - = N_("E846: Key code not set"); -static const char e_number_required_after_equal[] - = N_("E521: Number required after ="); -static const char e_preview_window_already_exists[] - = N_("E590: A preview window already exists"); +static const char e_key_code_not_set[] = N_("E846: Key code not set"); +static const char e_number_required_after_equal[] = N_("E521: Number required after ="); +static const char e_preview_window_already_exists[] = N_("E590: A preview window already exists"); static char *p_term = NULL; static char *p_ttytype = NULL; @@ -156,13 +152,10 @@ typedef enum { # include "options.generated.h" #endif -static char *(p_bin_dep_opts[]) = { - "textwidth", "wrapmargin", "modeline", "expandtab", NULL -}; -static char *(p_paste_dep_opts[]) = { - "autoindent", "expandtab", "ruler", "showmatch", "smarttab", - "softtabstop", "textwidth", "wrapmargin", "revins", "varsofttabstop", NULL -}; +static char *(p_bin_dep_opts[]) = { "textwidth", "wrapmargin", "modeline", "expandtab", NULL }; +static char *(p_paste_dep_opts[]) + = { "autoindent", "expandtab", "ruler", "showmatch", "smarttab", "softtabstop", + "textwidth", "wrapmargin", "revins", "varsofttabstop", NULL }; void set_init_tablocal(void) { @@ -225,8 +218,7 @@ static void set_init_default_backupskip(void) xstrlcpy(item, p, len); add_pathsep(item); xstrlcat(item, "*", len); - if (find_dup_item(ga.ga_data, item, options[opt_idx].flags) - == NULL) { + if (find_dup_item(ga.ga_data, item, options[opt_idx].flags) == NULL) { ga_grow(&ga, (int)len); if (!GA_EMPTY(&ga)) { STRCAT(ga.ga_data, ","); @@ -256,7 +248,7 @@ static void set_init_default_cdpath(void) } char *buf = xmalloc(2 * strlen(cdpath) + 2); - buf[0] = ','; // start with ",", current dir first + buf[0] = ','; // start with ",", current dir first int j = 1; for (int i = 0; cdpath[i] != NUL; i++) { if (vim_ispathlistsep(cdpath[i])) { @@ -274,7 +266,7 @@ static void set_init_default_cdpath(void) options[opt_idx].def_val = buf; options[opt_idx].flags |= P_DEF_ALLOCED; } else { - xfree(buf); // cannot happen + xfree(buf); // cannot happen } xfree(cdpath); } @@ -347,12 +339,9 @@ void set_init_1(bool clean_arg) memmove(backupdir + 2, backupdir, backupdir_len + 1); memmove(backupdir, ".,", 2); set_string_default("backupdir", backupdir, true); - set_string_default("viewdir", stdpaths_user_state_subpath("view", 2, true), - true); - set_string_default("directory", stdpaths_user_state_subpath("swap", 2, true), - true); - set_string_default("undodir", stdpaths_user_state_subpath("undo", 2, true), - true); + set_string_default("viewdir", stdpaths_user_state_subpath("view", 2, true), true); + set_string_default("directory", stdpaths_user_state_subpath("swap", 2, true), true); + set_string_default("undodir", stdpaths_user_state_subpath("undo", 2, true), true); // Set default for &runtimepath. All necessary expansions are performed in // this function. char *rtp = runtimepath_default(clean_arg); @@ -368,7 +357,7 @@ void set_init_1(bool clean_arg) set_options_default(0); curbuf->b_p_initialized = true; - curbuf->b_p_ar = -1; // no local 'autoread' value + curbuf->b_p_ar = -1; // no local 'autoread' value curbuf->b_p_ul = NO_LOCAL_UNDOLEVEL; check_buf_options(curbuf); check_win_options(curwin); @@ -390,7 +379,7 @@ void set_init_1(bool clean_arg) // Expand environment variables and things like "~" for the defaults. set_init_expand_env(); - save_file_ff(curbuf); // Buffer is unchanged + save_file_ff(curbuf); // Buffer is unchanged // Detect use of mlterm. // Mlterm is a terminal emulator akin to xterm that has some special @@ -428,7 +417,7 @@ static void set_option_default(const int opt_idx, int opt_flags) vimoption_T *opt = &options[opt_idx]; void *varp = get_varp_scope(opt, both ? OPT_LOCAL : opt_flags); uint32_t flags = opt->flags; - if (varp != NULL) { // skip hidden option, nothing to do for it + if (varp != NULL) { // skip hidden option, nothing to do for it if (flags & P_STRING) { // Use set_string_option_direct() for local options to handle // freeing and allocating the value. @@ -446,8 +435,7 @@ static void set_option_default(const int opt_idx, int opt_flags) win_comp_scroll(curwin); } else { OptInt def_val = (OptInt)(intptr_t)opt->def_val; - if ((OptInt *)varp == &curwin->w_p_so - || (OptInt *)varp == &curwin->w_p_siso) { + if ((OptInt *)varp == &curwin->w_p_so || (OptInt *)varp == &curwin->w_p_siso) { // 'scrolloff' and 'sidescrolloff' local values have a // different default value than the global default. *(OptInt *)varp = -1; @@ -469,8 +457,7 @@ static void set_option_default(const int opt_idx, int opt_flags) #endif // May also set global value for local option. if (both) { - *(int *)get_varp_scope(opt, OPT_GLOBAL) = - *(int *)varp; + *(int *)get_varp_scope(opt, OPT_GLOBAL) = *(int *)varp; } } @@ -507,8 +494,7 @@ static void set_options_default(int opt_flags) /// @param name The name of the option /// @param val The value of the option /// @param allocated If true, do not copy default as it was already allocated. -static void set_string_default(const char *name, char *val, bool allocated) - FUNC_ATTR_NONNULL_ALL +static void set_string_default(const char *name, char *val, bool allocated) FUNC_ATTR_NONNULL_ALL { int opt_idx = findoption(name); if (opt_idx >= 0) { @@ -543,8 +529,7 @@ static char *find_dup_item(char *origval, const char *newval, uint32_t flags) // Count backslashes. Only a comma with an even number of backslashes // or a single backslash preceded by a comma before it is recognized as // a separator. - if ((s > origval + 1 && s[-1] == '\\' && s[-2] != ',') - || (s == origval + 1 && s[-1] == '\\')) { + if ((s > origval + 1 && s[-1] == '\\' && s[-2] != ',') || (s == origval + 1 && s[-1] == '\\')) { bs++; } else { bs = 0; @@ -611,19 +596,15 @@ void set_init_2(bool headless) /// Initialize the options, part three: After reading the .vimrc void set_init_3(void) { - parse_shape_opt(SHAPE_CURSOR); // set cursor shapes from 'guicursor' + parse_shape_opt(SHAPE_CURSOR); // set cursor shapes from 'guicursor' // Set 'shellpipe' and 'shellredir', depending on the 'shell' option. // This is done after other initializations, where 'shell' might have been // set, but only if they have not been set before. int idx_srr = findoption("srr"); - int do_srr = (idx_srr < 0) - ? false - : !(options[idx_srr].flags & P_WAS_SET); + int do_srr = (idx_srr < 0) ? false : !(options[idx_srr].flags & P_WAS_SET); int idx_sp = findoption("sp"); - int do_sp = (idx_sp < 0) - ? false - : !(options[idx_sp].flags & P_WAS_SET); + int do_sp = (idx_sp < 0) ? false : !(options[idx_sp].flags & P_WAS_SET); size_t len = 0; char *p = (char *)invocation_path_tail(p_sh, &len); @@ -634,8 +615,7 @@ void set_init_3(void) // Default for p_sp is "| tee", for p_srr is ">". // For known shells it is changed here to include stderr. // - if (path_fnamecmp(p, "csh") == 0 - || path_fnamecmp(p, "tcsh") == 0) { + if (path_fnamecmp(p, "csh") == 0 || path_fnamecmp(p, "tcsh") == 0) { if (do_sp) { p_sp = "|& tee"; options[idx_sp].def_val = p_sp; @@ -644,16 +624,11 @@ void set_init_3(void) p_srr = ">&"; options[idx_srr].def_val = p_srr; } - } else if (path_fnamecmp(p, "sh") == 0 - || path_fnamecmp(p, "ksh") == 0 - || path_fnamecmp(p, "mksh") == 0 - || path_fnamecmp(p, "pdksh") == 0 - || path_fnamecmp(p, "zsh") == 0 - || path_fnamecmp(p, "zsh-beta") == 0 - || path_fnamecmp(p, "bash") == 0 - || path_fnamecmp(p, "fish") == 0 - || path_fnamecmp(p, "ash") == 0 - || path_fnamecmp(p, "dash") == 0) { + } else if (path_fnamecmp(p, "sh") == 0 || path_fnamecmp(p, "ksh") == 0 + || path_fnamecmp(p, "mksh") == 0 || path_fnamecmp(p, "pdksh") == 0 + || path_fnamecmp(p, "zsh") == 0 || path_fnamecmp(p, "zsh-beta") == 0 + || path_fnamecmp(p, "bash") == 0 || path_fnamecmp(p, "fish") == 0 + || path_fnamecmp(p, "ash") == 0 || path_fnamecmp(p, "dash") == 0) { // Always use POSIX shell style redirection if we reach this if (do_sp) { p_sp = "2>&1| tee"; @@ -795,13 +770,10 @@ static char *stropt_copy_value(char *origval, char **argp, set_op_T op, while (*arg != NUL && !ascii_iswhite(*arg)) { if (*arg == '\\' && arg[1] != NUL #ifdef BACKSLASH_IN_FILENAME - && !((flags & P_EXPAND) - && vim_isfilec((uint8_t)arg[1]) - && !ascii_iswhite(arg[1]) - && (arg[1] != '\\' - || (s == newval && arg[2] != '\\'))) + && !((flags & P_EXPAND) && vim_isfilec((uint8_t)arg[1]) && !ascii_iswhite(arg[1]) + && (arg[1] != '\\' || (s == newval && arg[2] != '\\'))) #endif - ) { + ) { arg++; // remove backslash } int i = utfc_ptr2len(arg); @@ -848,9 +820,7 @@ static void stropt_concat_with_comma(char *origval, char *newval, set_op_T op, u if (op == OP_ADDING) { len = (int)strlen(origval); // Strip a trailing comma, would get 2. - if (comma && len > 1 - && (flags & P_ONECOMMA) == P_ONECOMMA - && origval[len - 1] == ',' + if (comma && len > 1 && (flags & P_ONECOMMA) == P_ONECOMMA && origval[len - 1] == ',' && origval[len - 2] != '\\') { len--; } @@ -898,15 +868,13 @@ static void stropt_remove_dupflags(char *newval, uint32_t flags) for (s = newval; *s;) { // if options have P_FLAGLIST and P_ONECOMMA such as 'whichwrap' if (flags & P_ONECOMMA) { - if (*s != ',' && *(s + 1) == ',' - && vim_strchr(s + 2, (uint8_t)(*s)) != NULL) { + if (*s != ',' && *(s + 1) == ',' && vim_strchr(s + 2, (uint8_t)(*s)) != NULL) { // Remove the duplicated value and the next comma. STRMOVE(s, s + 2); continue; } } else { - if ((!(flags & P_COMMA) || *s != ',') - && vim_strchr(s + 1, (uint8_t)(*s)) != NULL) { + if ((!(flags & P_COMMA) || *s != ',') && vim_strchr(s + 1, (uint8_t)(*s)) != NULL) { STRMOVE(s, s + 1); continue; } @@ -1000,11 +968,11 @@ static set_op_T get_op(const char *arg) set_op_T op = OP_NONE; if (*arg != NUL && *(arg + 1) == '=') { if (*arg == '+') { - op = OP_ADDING; // "+=" + op = OP_ADDING; // "+=" } else if (*arg == '^') { - op = OP_PREPENDING; // "^=" + op = OP_PREPENDING; // "^=" } else if (*arg == '-') { - op = OP_REMOVING; // "-=" + op = OP_REMOVING; // "-=" } } return op; @@ -1090,14 +1058,12 @@ static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t fla // Skip all options that are not window-local (used when showing // an already loaded buffer in a window). - if ((opt_flags & OPT_WINONLY) - && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) { + if ((opt_flags & OPT_WINONLY) && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) { return FAIL; } // Skip all options that are window-local (used for :vimgrep). - if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 - && options[opt_idx].var == VAR_WIN) { + if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 && options[opt_idx].var == VAR_WIN) { return FAIL; } @@ -1114,10 +1080,8 @@ static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t fla // In diff mode some options are overruled. This avoids that // 'foldmethod' becomes "marker" instead of "diff" and that // "wrap" gets set. - if (win->w_p_diff - && opt_idx >= 0 // shut up coverity warning - && (options[opt_idx].indir == PV_FDM - || options[opt_idx].indir == PV_WRAP)) { + if (win->w_p_diff && opt_idx >= 0 // shut up coverity warning + && (options[opt_idx].indir == PV_FDM || options[opt_idx].indir == PV_WRAP)) { return FAIL; } } @@ -1134,8 +1098,8 @@ static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t fla /// Get new option value from argp. Allocated OptVal must be freed by caller. static OptVal get_option_newval(int opt_idx, int opt_flags, set_prefix_T prefix, char **argp, int nextchar, set_op_T op, uint32_t flags, void *varp, char *errbuf, - const size_t errbuflen, const char **errmsg) - FUNC_ATTR_WARN_UNUSED_RESULT + const size_t errbuflen, + const char **errmsg) FUNC_ATTR_WARN_UNUSED_RESULT { assert(varp != NULL); @@ -1293,21 +1257,20 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * uint8_t nextchar = (uint8_t)arg[len]; // next non-white char after option name - if (opt_idx == -1 && key == 0) { // found a mismatch: skip + if (opt_idx == -1 && key == 0) { // found a mismatch: skip *errmsg = e_unknown_option; return; } - uint32_t flags; // flags for current option + uint32_t flags; // flags for current option void *varp = NULL; // pointer to variable for current option if (opt_idx >= 0) { - if (options[opt_idx].var == NULL) { // hidden option: skip + if (options[opt_idx].var == NULL) { // hidden option: skip // Only give an error message when requesting the value of // a hidden option, ignore setting it. if (vim_strchr("=:!&<", nextchar) == NULL - && (!(options[opt_idx].flags & P_BOOL) - || nextchar == '?')) { + && (!(options[opt_idx].flags & P_BOOL) || nextchar == '?')) { *errmsg = e_unsupportedoption; } return; @@ -1332,8 +1295,7 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * *argp += 2; } } - if (vim_strchr("?!&<", nextchar) != NULL - && (*argp)[1] != NUL && !ascii_iswhite((*argp)[1])) { + if (vim_strchr("?!&<", nextchar) != NULL && (*argp)[1] != NUL && !ascii_iswhite((*argp)[1])) { *errmsg = e_trailing; return; } @@ -1344,15 +1306,13 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * // '=' character per "set" command line. grrr. (jw) // if (nextchar == '?' - || (prefix == PREFIX_NONE - && vim_strchr("=:&<", nextchar) == NULL - && !(flags & P_BOOL))) { + || (prefix == PREFIX_NONE && vim_strchr("=:&<", nextchar) == NULL && !(flags & P_BOOL))) { // print value if (*did_show) { - msg_putchar('\n'); // cursor below last one + msg_putchar('\n'); // cursor below last one } else { - gotocmdline(true); // cursor at status line - *did_show = true; // remember that we did a line + gotocmdline(true); // cursor at status line + *did_show = true; // remember that we did a line } if (opt_idx >= 0) { showoneopt(&options[opt_idx], opt_flags); @@ -1425,15 +1385,14 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * /// @return FAIL if an error is detected, OK otherwise int do_set(char *arg, int opt_flags) { - bool did_show = false; // already showed one value + bool did_show = false; // already showed one value if (*arg == NUL) { showoptions(false, opt_flags); did_show = true; } else { - while (*arg != NUL) { // loop to process all options - if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3]) - && !(opt_flags & OPT_MODELINE)) { + while (*arg != NUL) { // loop to process all options + if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3]) && !(opt_flags & OPT_MODELINE)) { // ":set all" show all options. // ":set all&" set all options to their default value. arg += 3; @@ -1450,7 +1409,7 @@ int do_set(char *arg, int opt_flags) did_show = true; } } else { - char *startarg = arg; // remember for error message + char *startarg = arg; // remember for error message const char *errmsg = NULL; char errbuf[80]; @@ -1481,8 +1440,8 @@ int do_set(char *arg, int opt_flags) // make sure all characters are printable trans_characters(IObuff, IOSIZE); - no_wait_return++; // wait_return() done later - emsg(IObuff); // show error highlighted + no_wait_return++; // wait_return() done later + emsg(IObuff); // show error highlighted no_wait_return--; return FAIL; @@ -1496,10 +1455,10 @@ int do_set(char *arg, int opt_flags) if (silent_mode && did_show) { // After displaying option values in silent mode. silent_mode = false; - info_message = true; // use os_msg(), not os_errmsg() + info_message = true; // use os_msg(), not os_errmsg() msg_putchar('\n'); silent_mode = true; - info_message = false; // use os_msg(), not os_errmsg() + info_message = false; // use os_msg(), not os_errmsg() } return OK; @@ -1537,7 +1496,7 @@ void set_options_bin(int oldval, int newval, int opt_flags) // The option values that are changed when 'bin' changes are // copied when 'bin is set and restored when 'bin' is reset. if (newval) { - if (!oldval) { // switched on + if (!oldval) { // switched on if (!(opt_flags & OPT_GLOBAL)) { curbuf->b_p_tw_nobin = curbuf->b_p_tw; curbuf->b_p_wm_nobin = curbuf->b_p_wm; @@ -1553,19 +1512,19 @@ void set_options_bin(int oldval, int newval, int opt_flags) } if (!(opt_flags & OPT_GLOBAL)) { - curbuf->b_p_tw = 0; // no automatic line wrap - curbuf->b_p_wm = 0; // no automatic line wrap - curbuf->b_p_ml = 0; // no modelines - curbuf->b_p_et = 0; // no expandtab + curbuf->b_p_tw = 0; // no automatic line wrap + curbuf->b_p_wm = 0; // no automatic line wrap + curbuf->b_p_ml = 0; // no modelines + curbuf->b_p_et = 0; // no expandtab } if (!(opt_flags & OPT_LOCAL)) { p_tw = 0; p_wm = 0; p_ml = false; p_et = false; - p_bin = true; // needed when called for the "-b" argument + p_bin = true; // needed when called for the "-b" argument } - } else if (oldval) { // switched off + } else if (oldval) { // switched off if (!(opt_flags & OPT_GLOBAL)) { curbuf->b_p_tw = curbuf->b_p_tw_nobin; curbuf->b_p_wm = curbuf->b_p_wm_nobin; @@ -1607,11 +1566,11 @@ char *find_shada_parameter(int type) if (*p == type) { return p + 1; } - if (*p == 'n') { // 'n' is always the last one + if (*p == 'n') { // 'n' is always the last one break; } - p = vim_strchr(p, ','); // skip until next ',' - if (p == NULL) { // hit the end without finding parameter + p = vim_strchr(p, ','); // skip until next ',' + if (p == NULL) { // hit the end without finding parameter break; } } @@ -1643,11 +1602,9 @@ static char *option_expand(int opt_idx, char *val) // Escape spaces when expanding 'tags', they are used to separate file // names. // For 'spellsuggest' expand after "file:". - expand_env_esc(val, NameBuff, MAXPATHL, - (char **)options[opt_idx].var == &p_tags, false, - (char **)options[opt_idx].var == &p_sps ? "file:" - : NULL); - if (strcmp(NameBuff, val) == 0) { // they are the same + expand_env_esc(val, NameBuff, MAXPATHL, (char **)options[opt_idx].var == &p_tags, false, + (char **)options[opt_idx].var == &p_sps ? "file:" : NULL); + if (strcmp(NameBuff, val) == 0) { // they are the same return NULL; } @@ -1691,7 +1648,7 @@ static void didset_options2(void) xfree(curbuf->b_p_vsts_array); (void)tabstop_set(curbuf->b_p_vsts, &curbuf->b_p_vsts_array); xfree(curbuf->b_p_vts_array); - (void)tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array); + (void)tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array); } /// Check for string options that are NULL (normally only termcap options). @@ -1762,8 +1719,7 @@ bool valid_name(const char *val, const char *allowed) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { for (const char *s = val; *s != NUL; s++) { - if (!ASCII_ISALNUM(*s) - && vim_strchr(allowed, (uint8_t)(*s)) == NULL) { + if (!ASCII_ISALNUM(*s) && vim_strchr(allowed, (uint8_t)(*s)) == NULL) { return false; } } @@ -1772,8 +1728,7 @@ bool valid_name(const char *val, const char *allowed) void check_blending(win_T *wp) { - wp->w_grid_alloc.blending = - wp->w_p_winbl > 0 || (wp->w_floating && wp->w_float_config.shadow); + wp->w_grid_alloc.blending = wp->w_p_winbl > 0 || (wp->w_floating && wp->w_float_config.shadow); } /// Handle setting `winhighlight' in window "wp" @@ -1857,7 +1812,7 @@ void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) // Remember where the option was set. For local options need to do that // in the buffer or window structure. - if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0) { + if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF | PV_WIN)) == 0) { options[opt_idx].last_set = last_set; } if (both || (opt_flags & OPT_LOCAL)) { @@ -2017,8 +1972,7 @@ static const char *did_set_buflisted(optset_T *args) // when 'buflisted' changes, trigger autocommands if (args->os_oldval.boolean != buf->b_p_bl) { - apply_autocmds(buf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE, - NULL, NULL, true, buf); + apply_autocmds(buf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE, NULL, NULL, true, buf); } return NULL; } @@ -2192,7 +2146,7 @@ static const char *did_set_lisp(optset_T *args) { buf_T *buf = (buf_T *)args->os_buf; // When 'lisp' option changes include/exclude '-' in keyword characters. - (void)buf_init_chartab(buf, false); // ignore errors + (void)buf_init_chartab(buf, false); // ignore errors return NULL; } @@ -2261,9 +2215,8 @@ static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED) if (buf->b_p_vsts_nopaste) { xfree(buf->b_p_vsts_nopaste); } - buf->b_p_vsts_nopaste = buf->b_p_vsts && buf->b_p_vsts != empty_string_option - ? xstrdup(buf->b_p_vsts) - : NULL; + buf->b_p_vsts_nopaste + = buf->b_p_vsts && buf->b_p_vsts != empty_string_option ? xstrdup(buf->b_p_vsts) : NULL; } // save global options @@ -2287,11 +2240,11 @@ static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED) // already on. // set options for each buffer FOR_ALL_BUFFERS(buf) { - buf->b_p_tw = 0; // textwidth is 0 - buf->b_p_wm = 0; // wrapmargin is 0 - buf->b_p_sts = 0; // softtabstop is 0 - buf->b_p_ai = 0; // no auto-indent - buf->b_p_et = 0; // no expandtab + buf->b_p_tw = 0; // textwidth is 0 + buf->b_p_wm = 0; // wrapmargin is 0 + buf->b_p_sts = 0; // softtabstop is 0 + buf->b_p_ai = 0; // no auto-indent + buf->b_p_et = 0; // no expandtab if (buf->b_p_vsts) { free_string_option(buf->b_p_vsts); } @@ -2300,13 +2253,13 @@ static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED) } // set global options - p_sm = 0; // no showmatch - p_sta = 0; // no smarttab + p_sm = 0; // no showmatch + p_sta = 0; // no smarttab if (p_ru) { - status_redraw_all(); // redraw to remove the ruler + status_redraw_all(); // redraw to remove the ruler } - p_ru = 0; // no ruler - p_ri = 0; // no reverse insert + p_ru = 0; // no ruler + p_ri = 0; // no reverse insert // set global values for local buffer options p_tw = 0; p_wm = 0; @@ -2343,7 +2296,7 @@ static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED) p_sm = save_sm; p_sta = save_sta; if (p_ru != save_ru) { - status_redraw_all(); // redraw to draw the ruler + status_redraw_all(); // redraw to draw the ruler } p_ru = save_ru; p_ri = save_ri; @@ -2524,11 +2477,11 @@ static const char *did_set_swapfile(optset_T *args) buf_T *buf = (buf_T *)args->os_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 + ml_open_file(buf); // create the swap file } else { // no need to reset curbuf->b_may_swap, ml_open_file() will check // buf->b_p_swf - mf_close_file(buf, true); // remove the swap file + mf_close_file(buf, true); // remove the swap file } return NULL; } @@ -2581,9 +2534,8 @@ static const char *did_set_undofile(optset_T *args) // only for the current buffer: Try to read in the undofile, // if one exists, the buffer wasn't changed and the buffer was // loaded - if ((curbuf == bp - || (args->os_flags & OPT_GLOBAL) || args->os_flags == 0) - && !bufIsChanged(bp) && bp->b_ml.ml_mfp != NULL) { + if ((curbuf == bp || (args->os_flags & OPT_GLOBAL) || args->os_flags == 0) && !bufIsChanged(bp) + && bp->b_ml.ml_mfp != NULL) { u_compute_hash(bp, hash); u_read_undo(NULL, hash, bp->b_fname); } @@ -2619,9 +2571,9 @@ static const char *did_set_undolevels(optset_T *args) buf_T *buf = (buf_T *)args->os_buf; OptInt *pp = (OptInt *)args->os_varp; - if (pp == &p_ul) { // global 'undolevels' + if (pp == &p_ul) { // global 'undolevels' did_set_global_undolevels(args->os_newval.number, args->os_oldval.number); - } else if (pp == &curbuf->b_p_ul) { // buffer local 'undolevels' + } else if (pp == &curbuf->b_p_ul) { // buffer local 'undolevels' did_set_buflocal_undolevels(buf, args->os_newval.number, args->os_oldval.number); } @@ -2728,8 +2680,8 @@ static void do_syntax_autocmd(buf_T *buf, bool value_changed) syn_recursive++; // Only pass true for "force" when the value changed or not used // recursively, to avoid endless recurrence. - apply_autocmds(EVENT_SYNTAX, buf->b_p_syn, buf->b_fname, - value_changed || syn_recursive == 1, buf); + apply_autocmds(EVENT_SYNTAX, buf->b_p_syn, buf->b_fname, value_changed || syn_recursive == 1, + buf); buf->b_flags |= BF_SYN_SET; syn_recursive--; } @@ -3096,9 +3048,7 @@ int findoption_len(const char *const arg, const size_t len) bool is_tty_option(const char *name) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - return (name[0] == 't' && name[1] == '_') - || strequal(name, "term") - || strequal(name, "ttytype"); + return (name[0] == 't' && name[1] == '_') || strequal(name, "term") || strequal(name, "ttytype"); } #define TCO_BUFFER_SIZE 8 @@ -3169,8 +3119,7 @@ bool set_tty_option(const char *name, char *value) /// @param[in] arg Option name. /// /// @return Option index or -1 if option was not found. -int findoption(const char *const arg) - FUNC_ATTR_NONNULL_ALL +int findoption(const char *const arg) FUNC_ATTR_NONNULL_ALL { return findoption_len(arg, strlen(arg)); } @@ -3547,20 +3496,18 @@ static const char *did_set_option(int opt_idx, void *varp, OptVal old_value, Opt bool free_oldval = (opt->flags & P_ALLOCED); bool value_changed = false; - optset_T did_set_cb_args = { - .os_varp = varp, - .os_idx = opt_idx, - .os_flags = opt_flags, - .os_oldval = old_value.data, - .os_newval = new_value.data, - .os_value_checked = false, - .os_value_changed = false, - .os_restore_chartab = false, - .os_errbuf = errbuf, - .os_errbuflen = errbuflen, - .os_buf = curbuf, - .os_win = curwin - }; + optset_T did_set_cb_args = { .os_varp = varp, + .os_idx = opt_idx, + .os_flags = opt_flags, + .os_oldval = old_value.data, + .os_newval = new_value.data, + .os_value_checked = false, + .os_value_changed = false, + .os_restore_chartab = false, + .os_errbuf = errbuf, + .os_errbuflen = errbuflen, + .os_buf = curbuf, + .os_win = curwin }; // Disallow changing immutable options. if (opt->immutable && !optval_equal(old_value, new_value)) { @@ -3614,8 +3561,8 @@ static const char *did_set_option(int opt_idx, void *varp, OptVal old_value, Opt // Check the bound for num options. if (new_value.type == kOptValTypeNumber) { - errmsg = check_num_option_bounds((OptInt *)varp, old_value.data.number, errbuf, errbuflen, - errmsg); + errmsg + = check_num_option_bounds((OptInt *)varp, old_value.data.number, errbuf, errbuflen, errmsg); // Re-assign new_value because the new value was modified by the bound check. new_value = optval_from_varp(opt_idx, varp); } @@ -3703,12 +3650,10 @@ static const char *set_option(const int opt_idx, void *varp, OptVal value, int o vimoption_T *opt = &options[opt_idx]; - static const char *optval_type_names[] = { - [kOptValTypeNil] = "Nil", - [kOptValTypeBoolean] = "Boolean", - [kOptValTypeNumber] = "Number", - [kOptValTypeString] = "String" - }; + static const char *optval_type_names[] = { [kOptValTypeNil] = "Nil", + [kOptValTypeBoolean] = "Boolean", + [kOptValTypeNumber] = "Number", + [kOptValTypeString] = "String" }; if (value.type == kOptValTypeNil) { // Don't try to unset local value if scope is global. @@ -3898,8 +3843,8 @@ int find_key_option_len(const char *arg_arg, size_t len, bool has_lt) } else if (has_lt) { arg--; // put arg at the '<' int modifiers = 0; - key = find_special_key(&arg, len + 1, &modifiers, - FSK_KEYCODE | FSK_KEEP_X_KEY | FSK_SIMPLIFY, NULL); + key = find_special_key(&arg, len + 1, &modifiers, FSK_KEYCODE | FSK_KEEP_X_KEY | FSK_SIMPLIFY, + NULL); if (modifiers) { // can't handle modifiers here key = 0; } @@ -3958,13 +3903,12 @@ static void showoptions(bool all, int opt_flags) if (opt_flags & OPT_ONECOLUMN) { len = Columns; } else if (p->flags & P_BOOL) { - len = 1; // a toggle option fits always + len = 1; // a toggle option fits always } else { option_value2string(p, opt_flags); len = (int)strlen(p->fullname) + vim_strsize(NameBuff) + 1; } - if ((len <= INC - GAP && run == 1) - || (len > INC - GAP && run == 2)) { + if ((len <= INC - GAP && run == 1) || (len > INC - GAP && run == 2)) { items[item_count++] = p; } } @@ -3974,26 +3918,24 @@ static void showoptions(bool all, int opt_flags) // display the items if (run == 1) { - assert(Columns <= INT_MAX - GAP - && Columns + GAP >= INT_MIN + 3 - && (Columns + GAP - 3) / INC >= INT_MIN - && (Columns + GAP - 3) / INC <= INT_MAX); + assert(Columns <= INT_MAX - GAP && Columns + GAP >= INT_MIN + 3 + && (Columns + GAP - 3) / INC >= INT_MIN && (Columns + GAP - 3) / INC <= INT_MAX); int cols = (Columns + GAP - 3) / INC; if (cols == 0) { cols = 1; } rows = (item_count + cols - 1) / cols; - } else { // run == 2 + } else { // run == 2 rows = item_count; } for (int row = 0; row < rows && !got_int; row++) { - msg_putchar('\n'); // go to next line - if (got_int) { // 'q' typed in more + msg_putchar('\n'); // go to next line + if (got_int) { // 'q' typed in more break; } int col = 0; for (int i = row; i < item_count; i += rows) { - msg_col = col; // make columns + msg_col = col; // make columns showoneopt(items[i], opt_flags); col += INC; } @@ -4007,7 +3949,7 @@ static void showoptions(bool all, int opt_flags) static int optval_default(vimoption_T *p, const void *varp) { if (varp == NULL) { - return true; // hidden option is always at default + return true; // hidden option is always at default } if (p->flags & P_NUM) { return *(OptInt *)varp == (OptInt)(intptr_t)p->def_val; @@ -4054,13 +3996,13 @@ static void showoneopt(vimoption_T *p, int opt_flags) int save_silent = silent_mode; silent_mode = false; - info_message = true; // use os_msg(), not os_errmsg() + info_message = true; // use os_msg(), not os_errmsg() void *varp = get_varp_scope(p, opt_flags); // for 'modified' we also need to check if 'ff' or 'fenc' changed. - if ((p->flags & P_BOOL) && ((int *)varp == &curbuf->b_changed - ? !curbufIsChanged() : !*(int *)varp)) { + if ((p->flags & P_BOOL) + && ((int *)varp == &curbuf->b_changed ? !curbufIsChanged() : !*(int *)varp)) { msg_puts("no"); } else if ((p->flags & P_BOOL) && *(int *)varp < 0) { msg_puts("--"); @@ -4110,8 +4052,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) // P_PRI_MKRC flag and once without. for (int pri = 1; pri >= 0; pri--) { for (vimoption_T *p = &options[0]; p->fullname; p++) { - if (!(p->flags & P_NO_MKRC) - && ((pri == 1) == ((p->flags & P_PRI_MKRC) != 0))) { + if (!(p->flags & P_NO_MKRC) && ((pri == 1) == ((p->flags & P_PRI_MKRC) != 0))) { // skip global option when only doing locals if (p->indir == PV_NONE && !(opt_flags & OPT_GLOBAL)) { continue; @@ -4133,8 +4074,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) continue; } - if ((opt_flags & OPT_SKIPRTP) - && (p->var == &p_rtp || p->var == &p_pp)) { + if ((opt_flags & OPT_SKIPRTP) && (p->var == &p_rtp || p->var == &p_pp)) { continue; } @@ -4177,14 +4117,13 @@ int makeset(FILE *fd, int opt_flags, int local_only) if (put_setnum(fd, cmd, p->fullname, (OptInt *)varp) == FAIL) { return FAIL; } - } else { // P_STRING + } else { // P_STRING int do_endif = false; // Don't set 'syntax' and 'filetype' again if the value is // already right, avoids reloading the syntax file. if (p->indir == PV_SYN || p->indir == PV_FT) { - if (fprintf(fd, "if &%s != '%s'", p->fullname, - *(char **)(varp)) < 0 + if (fprintf(fd, "if &%s != '%s'", p->fullname, *(char **)(varp)) < 0 || put_eol(fd) < 0) { return FAIL; } @@ -4244,8 +4183,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_ // If the option value is longer than MAXPATHL, we need to append // each comma separated part of the option separately, so that it // can be expanded when read back. - if (size >= MAXPATHL && (flags & P_COMMA) != 0 - && vim_strchr(*valuep, ',') != NULL) { + if (size >= MAXPATHL && (flags & P_COMMA) != 0 && vim_strchr(*valuep, ',') != NULL) { part = xmalloc(size); // write line break to clear the option, e.g. ':set rtp=' @@ -4309,11 +4247,10 @@ static int put_setnum(FILE *fd, char *cmd, char *name, OptInt *valuep) static int put_setbool(FILE *fd, char *cmd, char *name, int value) { - if (value < 0) { // global/local option using global value + if (value < 0) { // global/local option using global value return OK; } - if (fprintf(fd, "%s %s%s", cmd, value ? "" : "no", name) < 0 - || put_eol(fd) < 0) { + if (fprintf(fd, "%s %s%s", cmd, value ? "" : "no", name) < 0 || put_eol(fd) < 0) { return FAIL; } return OK; @@ -4386,7 +4323,7 @@ void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win) case PV_VE: return &(win->w_p_ve); } - return NULL; // "cannot happen" + return NULL; // "cannot happen" } return get_varp_from(p, buf, win); } @@ -4586,6 +4523,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) return &(buf->b_p_cfu); case PV_OFU: return &(buf->b_p_ofu); + case PV_URF: + return &(buf->b_p_urf); case PV_EOF: return &(buf->b_p_eof); case PV_EOL: @@ -4666,6 +4605,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) return &(buf->b_p_sw); case PV_TFU: return &(buf->b_p_tfu); + case PV_UMF: + return &(buf->b_p_umf); case PV_TS: return &(buf->b_p_ts); case PV_TW: @@ -4789,7 +4730,7 @@ void copy_winopt(winopt_T *from, winopt_T *to) // Copy the script context so that we know were the value was last set. memmove(to->wo_script_ctx, from->wo_script_ctx, sizeof(to->wo_script_ctx)); - check_winopt(to); // don't want NULL pointers + check_winopt(to); // don't want NULL pointers } /// Check string options in a window for a NULL value. @@ -4897,7 +4838,7 @@ static void init_buf_opt_idx(void) void buf_copy_options(buf_T *buf, int flags) { int should_copy = true; - char *save_p_isk = NULL; // init for GCC + char *save_p_isk = NULL; // init for GCC int did_isk = false; // Skip this when the option defaults have not been set yet. Happens when @@ -4917,8 +4858,7 @@ void buf_copy_options(buf_T *buf, int flags) /// if ((vim_strchr(p_cpo, CPO_BUFOPTGLOB) == NULL || !(flags & BCO_ENTER)) && (buf->b_p_initialized - || (!(flags & BCO_ENTER) - && vim_strchr(p_cpo, CPO_BUFOPT) != NULL))) { + || (!(flags & BCO_ENTER) && vim_strchr(p_cpo, CPO_BUFOPT) != NULL))) { should_copy = false; } @@ -4929,7 +4869,7 @@ void buf_copy_options(buf_T *buf, int flags) // BCO_NOHELP is given or the options were initialized already // (jumping back to a help file with CTRL-T or CTRL-O) bool dont_do_help = ((flags & BCO_NOHELP) && buf->b_help) || buf->b_p_initialized; - if (dont_do_help) { // don't free b_p_isk + if (dont_do_help) { // don't free b_p_isk save_p_isk = buf->b_p_isk; buf->b_p_isk = NULL; } @@ -4937,7 +4877,7 @@ void buf_copy_options(buf_T *buf, int flags) // reset 'readonly' and copy 'fileformat'. if (!buf->b_p_initialized) { free_buf_options(buf, true); - buf->b_p_ro = false; // don't copy readonly + buf->b_p_ro = false; // don't copy readonly buf->b_p_fenc = xstrdup(p_fenc); switch (*p_ffs) { case 'm': @@ -5006,9 +4946,13 @@ void buf_copy_options(buf_T *buf, int flags) set_buflocal_cfu_callback(buf); buf->b_p_ofu = xstrdup(p_ofu); COPY_OPT_SCTX(buf, BV_OFU); + buf->b_p_urf = xstrdup(p_urf); + COPY_OPT_SCTX(buf, BV_URF); set_buflocal_ofu_callback(buf); buf->b_p_tfu = xstrdup(p_tfu); COPY_OPT_SCTX(buf, BV_TFU); + buf->b_p_umf = xstrdup(p_umf); + COPY_OPT_SCTX(buf, BV_UMF); set_buflocal_tfu_callback(buf); buf->b_p_sts = p_sts; COPY_OPT_SCTX(buf, BV_STS); @@ -5160,7 +5104,7 @@ void buf_copy_options(buf_T *buf, int flags) } } - check_buf_options(buf); // make sure we don't have NULLs + check_buf_options(buf); // make sure we don't have NULLs if (did_isk) { (void)buf_init_chartab(buf, false); } @@ -5246,12 +5190,12 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) if (*arg == '<') { while (*p != '>') { - if (*p++ == NUL) { // expand terminal option name + if (*p++ == NUL) { // expand terminal option name return; } } int key = get_special_key_code(arg + 1); - if (key == 0) { // unknown name + if (key == 0) { // unknown name xp->xp_context = EXPAND_NOTHING; return; } @@ -5266,7 +5210,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) p++; } if (*p == NUL) { - return; // expand option name + return; // expand option name } nextchar = *++p; is_term_option = true; @@ -5306,8 +5250,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) p++; nextchar = '='; } - if ((nextchar != '=' && nextchar != ':') - || xp->xp_context == EXPAND_BOOL_SETTINGS) { + if ((nextchar != '=' && nextchar != ':') || xp->xp_context == EXPAND_BOOL_SETTINGS) { xp->xp_context = EXPAND_UNSUCCESSFUL; return; } @@ -5339,8 +5282,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) if (expand_option_subtract) { xp->xp_context = EXPAND_SETTING_SUBTRACT; return; - } else if (expand_option_idx >= 0 - && options[expand_option_idx].opt_expand_cb != NULL) { + } else if (expand_option_idx >= 0 && options[expand_option_idx].opt_expand_cb != NULL) { xp->xp_context = EXPAND_STRING_SETTING; } else if (*xp->xp_pattern == NUL) { xp->xp_context = EXPAND_OLD_SETTING; @@ -5358,13 +5300,8 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) // Options that have P_EXPAND are considered to all use file/dir expansion. if (flags & P_EXPAND) { p = options[opt_idx].var; - if (p == (char *)&p_bdir - || p == (char *)&p_dir - || p == (char *)&p_path - || p == (char *)&p_pp - || p == (char *)&p_rtp - || p == (char *)&p_cdpath - || p == (char *)&p_vdir) { + if (p == (char *)&p_bdir || p == (char *)&p_dir || p == (char *)&p_path || p == (char *)&p_pp + || p == (char *)&p_rtp || p == (char *)&p_cdpath || p == (char *)&p_vdir) { xp->xp_context = EXPAND_DIRECTORIES; if (p == (char *)&p_path || p == (char *)&p_cdpath) { xp->xp_backslash = XP_BS_THREE; @@ -5488,10 +5425,9 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numM for (int loop = 0; loop <= 1; loop++) { regmatch->rm_ic = ic; if (xp->xp_context != EXPAND_BOOL_SETTINGS) { - for (int match = 0; match < (int)ARRAY_SIZE(names); - match++) { - if (match_str(names[match], regmatch, *matches, - count, (loop == 0), fuzzy, fuzzystr, fuzmatch)) { + for (int match = 0; match < (int)ARRAY_SIZE(names); match++) { + if (match_str(names[match], regmatch, *matches, count, (loop == 0), fuzzy, fuzzystr, + fuzmatch)) { if (loop == 0) { num_normal++; } else { @@ -5501,18 +5437,15 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numM } } char *str; - for (size_t opt_idx = 0; (str = options[opt_idx].fullname) != NULL; - opt_idx++) { + for (size_t opt_idx = 0; (str = options[opt_idx].fullname) != NULL; opt_idx++) { if (options[opt_idx].var == NULL) { continue; } - if (xp->xp_context == EXPAND_BOOL_SETTINGS - && !(options[opt_idx].flags & P_BOOL)) { + if (xp->xp_context == EXPAND_BOOL_SETTINGS && !(options[opt_idx].flags & P_BOOL)) { continue; } - if (match_str(str, regmatch, *matches, count, (loop == 0), - fuzzy, fuzzystr, fuzmatch)) { + if (match_str(str, regmatch, *matches, count, (loop == 0), fuzzy, fuzzystr, fuzmatch)) { if (loop == 0) { num_normal++; } else { @@ -5565,10 +5498,8 @@ static char *escape_option_str_cmdline(char *var) // before a file name character. // The reverse is found at stropt_copy_value(). for (var = buf; *var != NUL; MB_PTR_ADV(var)) { - if (var[0] == '\\' && var[1] == '\\' - && expand_option_idx >= 0 - && (options[expand_option_idx].flags & P_EXPAND) - && vim_isfilec((uint8_t)var[2]) + if (var[0] == '\\' && var[1] == '\\' && expand_option_idx >= 0 + && (options[expand_option_idx].flags & P_EXPAND) && vim_isfilec((uint8_t)var[2]) && (var[2] != '\\' || (var == buf && var[4] != '\\'))) { STRMOVE(var, var + 1); } @@ -5608,8 +5539,7 @@ int ExpandOldSetting(int *numMatches, char ***matches) /// Expansion handler for :set=/:set+= when the option has a custom expansion handler. int ExpandStringSetting(expand_T *xp, regmatch_T *regmatch, int *numMatches, char ***matches) { - if (expand_option_idx < 0 - || options[expand_option_idx].opt_expand_cb == NULL) { + if (expand_option_idx < 0 || options[expand_option_idx].opt_expand_cb == NULL) { // Not supposed to reach this. This function is only for options with // custom expansion callbacks. return FAIL; @@ -5646,9 +5576,8 @@ 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_option_varp_scope_from(expand_option_idx, expand_option_flags, curbuf, curwin); uint32_t option_flags = options[expand_option_idx].flags; @@ -5759,10 +5688,7 @@ static void option_value2string(vimoption_T *opp, int scope) } else if (wc != 0) { xstrlcpy(NameBuff, transchar((int)wc), sizeof(NameBuff)); } else { - snprintf(NameBuff, - sizeof(NameBuff), - "%" PRId64, - (int64_t)(*(OptInt *)varp)); + snprintf(NameBuff, sizeof(NameBuff), "%" PRId64, (int64_t)(*(OptInt *)varp)); } } else { // P_STRING varp = *(char **)(varp); @@ -5796,8 +5722,7 @@ bool shortmess(int x) { return (p_shm != NULL && (vim_strchr(p_shm, x) != NULL - || (vim_strchr(p_shm, 'a') != NULL - && vim_strchr(SHM_ALL_ABBREVIATIONS, x) != NULL))); + || (vim_strchr(p_shm, 'a') != NULL && vim_strchr(SHM_ALL_ABBREVIATIONS, x) != NULL))); } /// vimrc_found() - Called when a vimrc or "VIMINIT" has been found. @@ -5921,8 +5846,7 @@ int option_set_callback_func(char *optval, Callback *optcb) } typval_T *tv; - if (*optval == '{' - || (strncmp(optval, "function(", 9) == 0) + if (*optval == '{' || (strncmp(optval, "function(", 9) == 0) || (strncmp(optval, "funcref(", 8) == 0)) { // Lambda expression or a funcref tv = eval_expr(optval, NULL); @@ -6008,8 +5932,7 @@ unsigned get_ve_flags(void) /// /// @param win If not NULL, the window to get the local option from; global /// otherwise. -char *get_showbreak_value(win_T *const win) - FUNC_ATTR_WARN_UNUSED_RESULT +char *get_showbreak_value(win_T *const win) FUNC_ATTR_WARN_UNUSED_RESULT { if (win->w_p_sbr == NULL || *win->w_p_sbr == NUL) { return p_sbr; @@ -6039,16 +5962,14 @@ int get_fileformat(const buf_T *buf) /// argument. /// /// @param eap can be NULL! -int get_fileformat_force(const buf_T *buf, const exarg_T *eap) - FUNC_ATTR_NONNULL_ARG(1) +int get_fileformat_force(const buf_T *buf, const exarg_T *eap) FUNC_ATTR_NONNULL_ARG(1) { int c; if (eap != NULL && eap->force_ff != 0) { c = eap->force_ff; } else { - if ((eap != NULL && eap->force_bin != 0) - ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin) { + if ((eap != NULL && eap->force_bin != 0) ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin) { return EOL_UNIX; } c = (unsigned char)(*buf->b_p_ff); @@ -6151,7 +6072,7 @@ size_t copy_option_part(char **option, char *buf, size_t maxlen, char *sep_chars if (*p != NUL && *p != ',') { // skip non-standard separator p++; } - p = skip_to_option_part(p); // p points to next file name + p = skip_to_option_part(p); // p points to next file name *option = p; return len; @@ -6184,25 +6105,21 @@ int win_signcol_count(win_T *wp) } /// Get window or buffer local options -dict_T *get_winbuf_options(const int bufopt) - FUNC_ATTR_WARN_UNUSED_RESULT +dict_T *get_winbuf_options(const int bufopt) FUNC_ATTR_WARN_UNUSED_RESULT { dict_T *const d = tv_dict_alloc(); for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) { struct vimoption *opt = &options[opt_idx]; - if ((bufopt && (opt->indir & PV_BUF)) - || (!bufopt && (opt->indir & PV_WIN))) { + if ((bufopt && (opt->indir & PV_BUF)) || (!bufopt && (opt->indir & PV_WIN))) { void *varp = get_varp(opt); if (varp != NULL) { if (opt->flags & P_STRING) { - tv_dict_add_str(d, opt->fullname, strlen(opt->fullname), - *(const char **)varp); + tv_dict_add_str(d, opt->fullname, strlen(opt->fullname), *(const char **)varp); } else if (opt->flags & P_NUM) { - tv_dict_add_nr(d, opt->fullname, strlen(opt->fullname), - *(OptInt *)varp); + tv_dict_add_nr(d, opt->fullname, strlen(opt->fullname), *(OptInt *)varp); } else { tv_dict_add_nr(d, opt->fullname, strlen(opt->fullname), *(int *)varp); } @@ -6234,9 +6151,8 @@ int get_sidescrolloff_value(win_T *wp) Dictionary get_vimoption(String name, int scope, buf_T *buf, win_T *win, Error *err) { int opt_idx = findoption_len(name.data, name.size); - VALIDATE_S(opt_idx >= 0, "option (not found)", name.data, { - return (Dictionary)ARRAY_DICT_INIT; - }); + VALIDATE_S(opt_idx >= 0, "option (not found)", name.data, + { return (Dictionary)ARRAY_DICT_INIT; }); return vimoption2dict(&options[opt_idx], scope, buf, win); } @@ -6310,7 +6226,8 @@ static Dictionary vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, wi type = "boolean"; def = BOOLEAN_OBJ((intptr_t)def_val); } else { - type = ""; def = NIL; + type = ""; + def = NIL; } PUT(dict, "type", CSTR_TO_OBJ(type)); PUT(dict, "default", def); diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index b2e8081a08..1bbff8e522 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -23,7 +23,6 @@ typedef union { String string; } OptValData; -/// Option value typedef struct { OptValType type; OptValData data; diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index b0e9ff9434..af2e31f7c7 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -733,6 +733,8 @@ EXTERN char *p_udir; ///< 'undodir' EXTERN int p_udf; ///< 'undofile' EXTERN OptInt p_ul; ///< 'undolevels' EXTERN OptInt p_ur; ///< 'undoreload' +EXTERN char* p_umf; ///< 'usermarkfunc' +EXTERN char* p_urf; ///< 'userregfunction' EXTERN OptInt p_uc; ///< 'updatecount' EXTERN OptInt p_ut; ///< 'updatetime' EXTERN char *p_shada; ///< 'shada' @@ -874,6 +876,8 @@ enum { BV_TX, BV_UDF, BV_UL, + BV_UMF, + BV_URF, BV_WM, BV_VSTS, BV_VTS, diff --git a/src/nvim/options.lua b/src/nvim/options.lua index daaf73d241..4fdee925ad 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -9217,6 +9217,98 @@ return { varname = 'p_ut', }, { + abbreviation='umf', + full_name='usermarkfunc', + desc= [=[ + This option specifies a function to be used to handle any marks + that Neovim does not natively handle. This option unlocks all + characters to be used as marks by the user. + + The 'usermarkfunc' function is called each time a user mark is read + from or written to. + + The 'usermarkfunc' function must take the following parameters: + + {get_or_set} The action being done on this mark (either 'set' + or 'get' + + {markname} The name of the mark either being read or . + + In case the action is 'get', the 'usermarkfunc' function should return + the content associated with that mark. This can be a number indicating a + line number or it could be a dictionary with the keys: + + {line} the line number + + {col} the column number + + {filename} the filename +< + ]=], + short_desc=N_("Function used to define behavior of user-defined marks."), + type='string', scope={'buffer'}, + varname='p_umf', + defaults={if_true=""} + }, + { + abbreviation='urf', + full_name='userregfunc', + desc= [=[ + This option specifies a function to be used to handle any registers + that Neovim does not natively handle. This option unlocks all + characters to be used as registers by the user. + + The 'userregfunc' function is called each time a user register is read + from or written to. + + The 'userregfunc' function must take the following parameters: + + {action} The action being done on this register (either 'yank' + or 'put' + + {register} The string holding the name of the register. This + is always a single character, though multi-byte + characters are allowed. + + {content} If the action is 'yank' this is the content being + yanked into the register. The content is a dictionary + with the following items: + + {lines} The lines being yanked, as a list. + + {type} The type of yank, either "line", "char", or + "block" + + {width} The width in case of "block" mode. + + {additional_data} Additional data. (can be returned in + put mode). + + In case the action is 'put', the 'userregfunc' function should return + the content to place in that location. The content can either be a + string, in which case "char" mode is inferred, or it can return a + dictionary of the same template that populates 'content'. + + A very simple example of a 'userregfunc' function that behaves exactly + like traditional registers would look like: > + + let s:contents = {} + function! MyUserregFunction(action, register, content) abort + if a:action == "put" + return get(s:contents, a:register, "") + else + let s:contents[a:register] = a:content + endif + endfunction + set userregfunc=MyUserregFunction +< + ]=], + short_desc=N_("Function used to define behavior of user-defined registers."), + type='string', scope={'buffer'}, + varname='p_urf', + defaults={if_true=""} + }, + { abbreviation = 'vsts', cb = 'did_set_varsofttabstop', defaults = { if_true = '' }, diff --git a/src/nvim/po/da.po b/src/nvim/po/da.po index 0345d3e243..ba0301589c 100644 --- a/src/nvim/po/da.po +++ b/src/nvim/po/da.po @@ -4049,7 +4049,7 @@ msgid "freeing %ld lines" msgstr "frigør %ld linjer" #, c-format -msgid " into \"%c" +msgid " into \"%s" msgstr " i \"%c" #, c-format diff --git a/src/nvim/po/fr.po b/src/nvim/po/fr.po index d9058326d5..fae6fe2297 100644 --- a/src/nvim/po/fr.po +++ b/src/nvim/po/fr.po @@ -4313,7 +4313,7 @@ msgid "freeing %ld lines" msgstr "libration de %ld lignes" #, c-format -msgid " into \"%c" +msgid " into \"%s" msgstr " dans \"%c" #, c-format diff --git a/src/nvim/po/tr.po b/src/nvim/po/tr.po index f3c55fe9ab..08b97ec180 100644 --- a/src/nvim/po/tr.po +++ b/src/nvim/po/tr.po @@ -4208,7 +4208,7 @@ msgstr[0] "%<PRId64> satır değiştirildi" msgstr[1] "%<PRId64> satır değiştirildi" #, c-format -msgid " into \"%c" +msgid " into \"%s" msgstr " \"%c" #, c-format diff --git a/src/nvim/po/uk.po b/src/nvim/po/uk.po index 83898cda12..1c1da14a22 100644 --- a/src/nvim/po/uk.po +++ b/src/nvim/po/uk.po @@ -5360,7 +5360,7 @@ msgstr[1] "Змінено %<PRId64> рядки" msgstr[2] "Змінено %<PRId64> рядків" #, c-format -msgid " into \"%c" +msgid " into \"%s" msgstr " у \"%c" #, c-format diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 819fbcf885..f64dd0e786 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -2372,7 +2372,7 @@ static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse, static inline void shada_initialize_registers(WriteMergerState *const wms, int max_reg_lines) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE { - const void *reg_iter = NULL; + iter_register_T reg_iter = ITER_REGISTER_NULL; const bool limit_reg_lines = max_reg_lines >= 0; do { yankreg_T reg; @@ -2403,7 +2403,7 @@ static inline void shada_initialize_registers(WriteMergerState *const wms, int m } } }; - } while (reg_iter != NULL); + } while (reg_iter != ITER_REGISTER_NULL); } /// Replace numbered mark in WriteMergerState diff --git a/src/nvim/yankmap.c b/src/nvim/yankmap.c new file mode 100644 index 0000000000..591bcffe33 --- /dev/null +++ b/src/nvim/yankmap.c @@ -0,0 +1,45 @@ +#include "nvim/yankmap.h" + +#include "nvim/memory.h" + +void init_yankmap(yankmap_T* map) +{ + memset(map, 0, sizeof(yankmap_T)); + + map->reg_to_yankreg = (Map(int, ptr_t))MAP_INIT; + map->yankreg_to_reg = (Map(ptr_t, int))MAP_INIT; + // map_init(int, ptr_t, &map->reg_to_yankreg); + // map_init(ptr_t, int, &map->yankreg_to_reg); +} + +yankreg_T* yankmap_get(yankmap_T* yankmap, int reg) +{ + bool is_new = false; + yankreg_T** ret + = (yankreg_T**)map_put_ref(int, ptr_t)(&yankmap->reg_to_yankreg, reg, NULL, &is_new); + + if (ret) { + if (is_new) { + *ret = xcalloc(sizeof(yankreg_T), 1); + } + + /* Add the back-reference */ + int* ref = map_put_ref(ptr_t, int)(&yankmap->yankreg_to_reg, *ret, NULL, NULL); + *ref = reg; + + return *ret; + } + + return NULL; +} + +int yankmap_find(yankmap_T* yankmap, yankreg_T* yankreg) +{ + int* ref = map_ref(ptr_t, int)(&yankmap->yankreg_to_reg, yankreg, NULL); + + if (ref) { + return *ref; + } + + return -1; +} diff --git a/src/nvim/yankmap.h b/src/nvim/yankmap.h new file mode 100644 index 0000000000..4468f3a016 --- /dev/null +++ b/src/nvim/yankmap.h @@ -0,0 +1,25 @@ +#ifndef YANK_TRIE_H_ +#define YANK_TRIE_H_ + +#include <stdbool.h> + +#include "nvim/map_defs.h" +#include "nvim/ops.h" + +typedef struct { + /* Register name to yank register. */ + Map(int, ptr_t) reg_to_yankreg; + + /* Yank register to register name. */ + Map(ptr_t, int) yankreg_to_reg; +} yankmap_T; + +void init_yankmap(yankmap_T* yankmap); + +yankreg_T* yankmap_get(yankmap_T* yankmap, int reg); + +yankreg_T* yankmap_put(yankmap_T* yankmap, int index); + +int yankmap_find(yankmap_T* yankmap, yankreg_T* yankreg); + +#endif |