mirror of
https://github.com/neovim/neovim.git
synced 2026-02-20 01:09:56 +10:00
Merge pull request #19493 from zeertzjq/vim-8.2.1469
vim-patch:8.2.{1469,2254,2284,2285,2969,4228}: option fixes and refactorings
This commit is contained in:
@@ -104,20 +104,20 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
|
||||
|
||||
long numval = 0;
|
||||
char *stringval = NULL;
|
||||
int result = access_option_value_for(name.data, &numval, &stringval, scope, opt_type, from,
|
||||
true, err);
|
||||
getoption_T result = access_option_value_for(name.data, &numval, &stringval, scope, opt_type,
|
||||
from, true, err);
|
||||
if (ERROR_SET(err)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case 0:
|
||||
case gov_string:
|
||||
rv = STRING_OBJ(cstr_as_string(stringval));
|
||||
break;
|
||||
case 1:
|
||||
case gov_number:
|
||||
rv = INTEGER_OBJ(numval);
|
||||
break;
|
||||
case 2:
|
||||
case gov_bool:
|
||||
switch (numval) {
|
||||
case 0:
|
||||
case 1:
|
||||
@@ -483,8 +483,8 @@ void set_option_to(uint64_t channel_id, void *to, int type, String name, Object
|
||||
});
|
||||
}
|
||||
|
||||
static int access_option_value(char *key, long *numval, char **stringval, int opt_flags, bool get,
|
||||
Error *err)
|
||||
static getoption_T access_option_value(char *key, long *numval, char **stringval, int opt_flags,
|
||||
bool get, Error *err)
|
||||
{
|
||||
if (get) {
|
||||
return get_option_value(key, numval, stringval, opt_flags);
|
||||
@@ -501,13 +501,13 @@ static int access_option_value(char *key, long *numval, char **stringval, int op
|
||||
}
|
||||
}
|
||||
|
||||
static int access_option_value_for(char *key, long *numval, char **stringval, int opt_flags,
|
||||
int opt_type, void *from, bool get, Error *err)
|
||||
static getoption_T access_option_value_for(char *key, long *numval, char **stringval, int opt_flags,
|
||||
int opt_type, void *from, bool get, Error *err)
|
||||
{
|
||||
bool need_switch = false;
|
||||
switchwin_T switchwin;
|
||||
aco_save_T aco;
|
||||
int result = 0;
|
||||
getoption_T result = 0;
|
||||
|
||||
try_start();
|
||||
switch (opt_type) {
|
||||
|
||||
@@ -3774,7 +3774,7 @@ int get_option_tv(const char **const arg, typval_T *const rettv, const bool eval
|
||||
{
|
||||
long numval;
|
||||
char *stringval;
|
||||
int opt_type;
|
||||
getoption_T opt_type;
|
||||
bool working = (**arg == '+'); // has("+option")
|
||||
int ret = OK;
|
||||
int opt_flags;
|
||||
@@ -3798,26 +3798,28 @@ int get_option_tv(const char **const arg, typval_T *const rettv, const bool eval
|
||||
opt_type = get_option_value(*arg, &numval,
|
||||
rettv == NULL ? NULL : &stringval, opt_flags);
|
||||
|
||||
if (opt_type == -3) { // invalid name
|
||||
if (opt_type == gov_unknown) {
|
||||
if (rettv != NULL) {
|
||||
semsg(_("E113: Unknown option: %s"), *arg);
|
||||
}
|
||||
ret = FAIL;
|
||||
} else if (rettv != NULL) {
|
||||
if (opt_type == -2) { // hidden string option
|
||||
if (opt_type == gov_hidden_string) {
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
} else if (opt_type == -1) { // hidden number option
|
||||
} else if (opt_type == gov_hidden_bool || opt_type == gov_hidden_number) {
|
||||
rettv->v_type = VAR_NUMBER;
|
||||
rettv->vval.v_number = 0;
|
||||
} else if (opt_type == 1 || opt_type == 2) { // number or boolean option
|
||||
} else if (opt_type == gov_bool || opt_type == gov_number) {
|
||||
rettv->v_type = VAR_NUMBER;
|
||||
rettv->vval.v_number = numval;
|
||||
} else { // string option
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = stringval;
|
||||
}
|
||||
} else if (working && (opt_type == -2 || opt_type == -1)) {
|
||||
} else if (working && (opt_type == gov_hidden_bool
|
||||
|| opt_type == gov_hidden_number
|
||||
|| opt_type == gov_hidden_string)) {
|
||||
ret = FAIL;
|
||||
}
|
||||
|
||||
|
||||
@@ -619,26 +619,38 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
|
||||
&& vim_strchr(endchars, *skipwhite(p)) == NULL)) {
|
||||
emsg(_(e_letunexp));
|
||||
} else {
|
||||
int opt_type;
|
||||
varnumber_T n = 0;
|
||||
getoption_T opt_type;
|
||||
long numval;
|
||||
char *stringval = NULL;
|
||||
const char *s = NULL;
|
||||
bool failed = false;
|
||||
|
||||
const char c1 = *p;
|
||||
*p = NUL;
|
||||
|
||||
varnumber_T n = tv_get_number(tv);
|
||||
if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
|
||||
s = tv_get_string_chk(tv); // != NULL if number or string.
|
||||
opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
|
||||
if (opt_type == gov_bool
|
||||
|| opt_type == gov_number
|
||||
|| opt_type == gov_hidden_bool
|
||||
|| opt_type == gov_hidden_number) {
|
||||
// number, possibly hidden
|
||||
n = (long)tv_get_number(tv);
|
||||
}
|
||||
if (s != NULL && op != NULL && *op != '=') {
|
||||
opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
|
||||
if ((opt_type == 1 && *op == '.')
|
||||
|| (opt_type == 0 && *op != '.')) {
|
||||
|
||||
// Avoid setting a string option to the text "v:false" or similar.
|
||||
if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
|
||||
s = tv_get_string_chk(tv);
|
||||
}
|
||||
|
||||
if (op != NULL && *op != '=') {
|
||||
if (((opt_type == gov_bool || opt_type == gov_number) && *op == '.')
|
||||
|| (opt_type == gov_string && *op != '.')) {
|
||||
semsg(_(e_letwrong), op);
|
||||
s = NULL; // don't set the value
|
||||
failed = true; // don't set the value
|
||||
} else {
|
||||
if (opt_type == 1) { // number
|
||||
// number or bool
|
||||
if (opt_type == gov_number || opt_type == gov_bool) {
|
||||
switch (*op) {
|
||||
case '+':
|
||||
n = numval + n; break;
|
||||
@@ -651,7 +663,9 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
|
||||
case '%':
|
||||
n = num_modulus(numval, n); break;
|
||||
}
|
||||
} else if (opt_type == 0 && stringval != NULL) { // string
|
||||
s = NULL;
|
||||
} else if (opt_type == gov_string && stringval != NULL && s != NULL) {
|
||||
// string
|
||||
char *const oldstringval = stringval;
|
||||
stringval = (char *)concat_str((const char_u *)stringval,
|
||||
(const char_u *)s);
|
||||
@@ -660,10 +674,14 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s != NULL || tv->v_type == VAR_BOOL
|
||||
|| tv->v_type == VAR_SPECIAL) {
|
||||
set_option_value((const char *)arg, n, s, opt_flags);
|
||||
arg_end = p;
|
||||
|
||||
if (!failed) {
|
||||
if (opt_type != gov_string || s != NULL) {
|
||||
set_option_value(arg, n, s, opt_flags);
|
||||
arg_end = p;
|
||||
} else {
|
||||
emsg(_(e_stringreq));
|
||||
}
|
||||
}
|
||||
*p = c1;
|
||||
xfree(stringval);
|
||||
@@ -1547,10 +1565,18 @@ static void getwinvar(typval_T *argvars, typval_T *rettv, int off)
|
||||
/// Set option "varname" to the value of "varp" for the current buffer/window.
|
||||
static void set_option_from_tv(const char *varname, typval_T *varp)
|
||||
{
|
||||
long numval = 0;
|
||||
const char *strval;
|
||||
bool error = false;
|
||||
char nbuf[NUMBUFLEN];
|
||||
const long numval = (long)tv_get_number_chk(varp, &error);
|
||||
const char *const strval = tv_get_string_buf_chk(varp, nbuf);
|
||||
|
||||
if (varp->v_type == VAR_BOOL) {
|
||||
numval = (long)varp->vval.v_number;
|
||||
strval = "0"; // avoid using "false"
|
||||
} else {
|
||||
numval = (long)tv_get_number_chk(varp, &error);
|
||||
strval = tv_get_string_buf_chk(varp, nbuf);
|
||||
}
|
||||
if (!error && strval != NULL) {
|
||||
set_option_value(varname, numval, strval, OPT_LOCAL);
|
||||
}
|
||||
|
||||
@@ -3485,7 +3485,8 @@ void scroll_redraw(int up, long count)
|
||||
redraw_later(curwin, VALID);
|
||||
}
|
||||
|
||||
/// Get the count specified after a 'z' command.
|
||||
/// Get the count specified after a 'z' command. Only the 'z<CR>', 'zl', 'zh',
|
||||
/// 'z<Left>', and 'z<Right>' commands accept a count after 'z'.
|
||||
/// @return true to process the 'z' command and false to skip it.
|
||||
static bool nv_z_get_count(cmdarg_T *cap, int *nchar_arg)
|
||||
{
|
||||
|
||||
@@ -5046,28 +5046,29 @@ static int findoption(const char *const arg)
|
||||
/// @param stringval NULL when only checking existence
|
||||
///
|
||||
/// @returns:
|
||||
/// Toggle option: 2, *numval gets value.
|
||||
/// Number option: 1, *numval gets value.
|
||||
/// String option: 0, *stringval gets allocated string.
|
||||
/// Hidden Number or Toggle option: -1.
|
||||
/// hidden String option: -2.
|
||||
/// unknown option: -3.
|
||||
int get_option_value(const char *name, long *numval, char **stringval, int opt_flags)
|
||||
/// Number option: gov_number, *numval gets value.
|
||||
/// Tottle option: gov_bool, *numval gets value.
|
||||
/// String option: gov_string, *stringval gets allocated string.
|
||||
/// Hidden Number option: gov_hidden_number.
|
||||
/// Hidden Toggle option: gov_hidden_bool.
|
||||
/// Hidden String option: gov_hidden_string.
|
||||
/// Unknown option: gov_unknown.
|
||||
getoption_T get_option_value(const char *name, long *numval, char **stringval, int opt_flags)
|
||||
{
|
||||
if (get_tty_option(name, stringval)) {
|
||||
return 0;
|
||||
return gov_string;
|
||||
}
|
||||
|
||||
int opt_idx = findoption(name);
|
||||
if (opt_idx < 0) { // Unknown option.
|
||||
return -3;
|
||||
if (opt_idx < 0) { // option not in the table
|
||||
return gov_unknown;
|
||||
}
|
||||
|
||||
char_u *varp = get_varp_scope(&(options[opt_idx]), opt_flags);
|
||||
|
||||
if (options[opt_idx].flags & P_STRING) {
|
||||
if (varp == NULL) { // hidden option
|
||||
return -2;
|
||||
return gov_hidden_string;
|
||||
}
|
||||
if (stringval != NULL) {
|
||||
if ((char_u **)varp == &p_pt) { // 'pastetoggle'
|
||||
@@ -5076,26 +5077,24 @@ int get_option_value(const char *name, long *numval, char **stringval, int opt_f
|
||||
*stringval = xstrdup(*(char **)(varp));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return gov_string;
|
||||
}
|
||||
|
||||
if (varp == NULL) { // hidden option
|
||||
return -1;
|
||||
return (options[opt_idx].flags & P_NUM) ? gov_hidden_number : gov_hidden_bool;
|
||||
}
|
||||
if (options[opt_idx].flags & P_NUM) {
|
||||
*numval = *(long *)varp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
*numval = curbufIsChanged();
|
||||
} else {
|
||||
*numval = (long)*(int *)varp; // NOLINT(whitespace/cast)
|
||||
// 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) {
|
||||
*numval = curbufIsChanged();
|
||||
} else {
|
||||
*numval = (long)(*(int *)varp);
|
||||
}
|
||||
}
|
||||
|
||||
return 2;
|
||||
return (options[opt_idx].flags & P_NUM) ? gov_number : gov_bool;
|
||||
}
|
||||
|
||||
// Returns the option attributes and its value. Unlike the above function it
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
|
||||
#include "nvim/ex_cmds_defs.h" // for exarg_T
|
||||
|
||||
/// Returned by get_option_value().
|
||||
typedef enum {
|
||||
gov_unknown,
|
||||
gov_bool,
|
||||
gov_number,
|
||||
gov_string,
|
||||
gov_hidden_bool,
|
||||
gov_hidden_number,
|
||||
gov_hidden_string,
|
||||
} getoption_T;
|
||||
|
||||
// flags for buf_copy_options()
|
||||
#define BCO_ENTER 1 // going to enter the buffer
|
||||
#define BCO_ALWAYS 2 // always copy the options
|
||||
|
||||
@@ -6880,7 +6880,7 @@ void ex_spelldump(exarg_T *eap)
|
||||
if (no_spell_checking(curwin)) {
|
||||
return;
|
||||
}
|
||||
get_option_value("spl", &dummy, &spl, OPT_LOCAL);
|
||||
(void)get_option_value("spl", &dummy, &spl, OPT_LOCAL);
|
||||
|
||||
// Create a new empty buffer in a new window.
|
||||
do_cmdline_cmd("new");
|
||||
|
||||
@@ -1332,4 +1332,50 @@ func Test_diff_binary()
|
||||
set diffopt&vim
|
||||
endfunc
|
||||
|
||||
" Test for using the 'zi' command to invert 'foldenable' in diff windows (test
|
||||
" for the issue fixed by patch 6.2.317)
|
||||
func Test_diff_foldinvert()
|
||||
%bw!
|
||||
edit Xfile1
|
||||
new Xfile2
|
||||
new Xfile3
|
||||
windo diffthis
|
||||
" open a non-diff window
|
||||
botright new
|
||||
1wincmd w
|
||||
call assert_true(getwinvar(1, '&foldenable'))
|
||||
call assert_true(getwinvar(2, '&foldenable'))
|
||||
call assert_true(getwinvar(3, '&foldenable'))
|
||||
normal zi
|
||||
call assert_false(getwinvar(1, '&foldenable'))
|
||||
call assert_false(getwinvar(2, '&foldenable'))
|
||||
call assert_false(getwinvar(3, '&foldenable'))
|
||||
normal zi
|
||||
call assert_true(getwinvar(1, '&foldenable'))
|
||||
call assert_true(getwinvar(2, '&foldenable'))
|
||||
call assert_true(getwinvar(3, '&foldenable'))
|
||||
|
||||
" If the current window has 'noscrollbind', then 'zi' should not change
|
||||
" 'foldenable' in other windows.
|
||||
1wincmd w
|
||||
set noscrollbind
|
||||
normal zi
|
||||
call assert_false(getwinvar(1, '&foldenable'))
|
||||
call assert_true(getwinvar(2, '&foldenable'))
|
||||
call assert_true(getwinvar(3, '&foldenable'))
|
||||
|
||||
" 'zi' should not change the 'foldenable' for windows with 'noscrollbind'
|
||||
1wincmd w
|
||||
set scrollbind
|
||||
normal zi
|
||||
call setwinvar(2, '&scrollbind', v:false)
|
||||
normal zi
|
||||
call assert_false(getwinvar(1, '&foldenable'))
|
||||
call assert_true(getwinvar(2, '&foldenable'))
|
||||
call assert_false(getwinvar(3, '&foldenable'))
|
||||
|
||||
%bw!
|
||||
set scrollbind&
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -580,6 +580,7 @@ endfunc
|
||||
func Test_normal_z_error()
|
||||
call assert_beeps('normal! z2p')
|
||||
call assert_beeps('normal! zq')
|
||||
call assert_beeps('normal! cz1')
|
||||
endfunc
|
||||
|
||||
func Test_normal15_z_scroll_vert()
|
||||
@@ -619,7 +620,7 @@ func Test_normal15_z_scroll_vert()
|
||||
call assert_equal(10, winheight(0))
|
||||
exe "norm! z12\<cr>"
|
||||
call assert_equal(12, winheight(0))
|
||||
exe "norm! z10\<cr>"
|
||||
exe "norm! z15\<Del>0\<cr>"
|
||||
call assert_equal(10, winheight(0))
|
||||
|
||||
" Test for z.
|
||||
|
||||
@@ -1661,16 +1661,25 @@ func Test_compound_assignment_operators()
|
||||
call assert_equal(6, &scrolljump)
|
||||
let &scrolljump %= 5
|
||||
call assert_equal(1, &scrolljump)
|
||||
call assert_fails('let &scrolljump .= "j"', 'E734')
|
||||
call assert_fails('let &scrolljump .= "j"', 'E734:')
|
||||
set scrolljump&vim
|
||||
|
||||
let &foldlevelstart = 2
|
||||
let &foldlevelstart -= 1
|
||||
call assert_equal(1, &foldlevelstart)
|
||||
let &foldlevelstart -= 1
|
||||
call assert_equal(0, &foldlevelstart)
|
||||
let &foldlevelstart = 2
|
||||
let &foldlevelstart -= 2
|
||||
call assert_equal(0, &foldlevelstart)
|
||||
|
||||
" Test for register
|
||||
let @/ = 1
|
||||
call assert_fails('let @/ += 1', 'E734')
|
||||
call assert_fails('let @/ -= 1', 'E734')
|
||||
call assert_fails('let @/ *= 1', 'E734')
|
||||
call assert_fails('let @/ /= 1', 'E734')
|
||||
call assert_fails('let @/ %= 1', 'E734')
|
||||
call assert_fails('let @/ += 1', 'E734:')
|
||||
call assert_fails('let @/ -= 1', 'E734:')
|
||||
call assert_fails('let @/ *= 1', 'E734:')
|
||||
call assert_fails('let @/ /= 1', 'E734:')
|
||||
call assert_fails('let @/ %= 1', 'E734:')
|
||||
let @/ .= 's'
|
||||
call assert_equal('1s', @/)
|
||||
let @/ = ''
|
||||
|
||||
Reference in New Issue
Block a user