mirror of
https://github.com/neovim/neovim
synced 2025-07-16 01:01:49 +00:00
options: make 'fillchars' and 'listchars' global-local
These options were previously global. A global-local window option behaves closer to a global option "per default" (i e with :set), but still supports local behavior via :setl Also this restores back-compat for nvim_set_option("fcs", ...) which are currently broken on 0.4.x but worked in earlier versions
This commit is contained in:
committed by
Justin M. Keyes
parent
5d41bfccec
commit
92e80f18a8
@ -2348,7 +2348,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
|
||||
*'fillchars'* *'fcs'*
|
||||
'fillchars' 'fcs' string (default "")
|
||||
local to window
|
||||
global or local to window |global-local|
|
||||
Characters to fill the statuslines and vertical separators.
|
||||
It is a comma separated list of items:
|
||||
|
||||
@ -3657,7 +3657,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
*'listchars'* *'lcs'*
|
||||
'listchars' 'lcs' string (default: "tab:> ,trail:-,nbsp:+"
|
||||
Vi default: "eol:$")
|
||||
local to window
|
||||
global or local to window |global-local|
|
||||
Strings to use in 'list' mode and for the |:list| command. It is a
|
||||
comma separated list of string settings.
|
||||
|
||||
|
@ -2204,10 +2204,10 @@ static void didset_options2(void)
|
||||
(void)opt_strings_flags(p_cb, p_cb_values, &cb_flags, true);
|
||||
|
||||
// Parse default for 'fillchars'.
|
||||
(void)set_chars_option(curwin, &curwin->w_p_fcs);
|
||||
(void)set_chars_option(curwin, &curwin->w_p_fcs, true);
|
||||
|
||||
// Parse default for 'listchars'.
|
||||
(void)set_chars_option(curwin, &curwin->w_p_lcs);
|
||||
(void)set_chars_option(curwin, &curwin->w_p_lcs, true);
|
||||
|
||||
// Parse default for 'wildmode'.
|
||||
check_opt_wim();
|
||||
@ -2661,11 +2661,11 @@ did_set_string_option(
|
||||
errmsg = e_invarg;
|
||||
} else {
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (set_chars_option(wp, &wp->w_p_lcs) != NULL) {
|
||||
if (set_chars_option(wp, &wp->w_p_lcs, true) != NULL) {
|
||||
errmsg = (char_u *)_("E834: Conflicts with value of 'listchars'");
|
||||
goto ambw_end;
|
||||
}
|
||||
if (set_chars_option(wp, &wp->w_p_fcs) != NULL) {
|
||||
if (set_chars_option(wp, &wp->w_p_fcs, true) != NULL) {
|
||||
errmsg = (char_u *)_("E835: Conflicts with value of 'fillchars'");
|
||||
goto ambw_end;
|
||||
}
|
||||
@ -2866,10 +2866,26 @@ ambw_end:
|
||||
}
|
||||
s = skip_to_option_part(s);
|
||||
}
|
||||
} else if (varp == &curwin->w_p_lcs) { // 'listchars'
|
||||
errmsg = set_chars_option(curwin, varp);
|
||||
} else if (varp == &curwin->w_p_fcs) { // 'fillchars'
|
||||
errmsg = set_chars_option(curwin, varp);
|
||||
} else if (varp == &p_lcs) { // 'listchars'
|
||||
errmsg = set_chars_option(curwin, varp, false);
|
||||
if (!errmsg) {
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
set_chars_option(wp, &wp->w_p_lcs, true);
|
||||
}
|
||||
}
|
||||
redraw_all_later(NOT_VALID);
|
||||
} else if (varp == &curwin->w_p_lcs) { // local 'listchars'
|
||||
errmsg = set_chars_option(curwin, varp, true);
|
||||
} else if (varp == &p_fcs) { // 'fillchars'
|
||||
errmsg = set_chars_option(curwin, varp, false);
|
||||
if (!errmsg) {
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
set_chars_option(wp, &wp->w_p_fcs, true);
|
||||
}
|
||||
}
|
||||
redraw_all_later(NOT_VALID);
|
||||
} else if (varp == &curwin->w_p_fcs) { // local 'fillchars'
|
||||
errmsg = set_chars_option(curwin, varp, true);
|
||||
} else if (varp == &p_cedit) { // 'cedit'
|
||||
errmsg = check_cedit();
|
||||
} else if (varp == &p_vfile) { // 'verbosefile'
|
||||
@ -3499,7 +3515,7 @@ skip:
|
||||
///
|
||||
/// @param varp either &curwin->w_p_lcs or &curwin->w_p_fcs
|
||||
/// @return error message, NULL if it's OK.
|
||||
static char_u *set_chars_option(win_T *wp, char_u **varp)
|
||||
static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
|
||||
{
|
||||
int round, i, len, entries;
|
||||
char_u *p, *s;
|
||||
@ -3534,12 +3550,18 @@ static char_u *set_chars_option(win_T *wp, char_u **varp)
|
||||
{ &wp->w_p_lcs_chars.conceal, "conceal", NUL },
|
||||
};
|
||||
|
||||
if (varp == &wp->w_p_lcs) {
|
||||
if (varp == &p_lcs || varp == &wp->w_p_lcs) {
|
||||
tab = lcs_tab;
|
||||
entries = ARRAY_SIZE(lcs_tab);
|
||||
if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL) {
|
||||
varp = &p_lcs;
|
||||
}
|
||||
} else {
|
||||
tab = fcs_tab;
|
||||
entries = ARRAY_SIZE(fcs_tab);
|
||||
if (varp == &wp->w_p_fcs && wp->w_p_fcs[0] == NUL) {
|
||||
varp = &p_fcs;
|
||||
}
|
||||
if (*p_ambw == 'd') {
|
||||
// XXX: If ambiwidth=double then "|" and "·" take 2 columns, which is
|
||||
// forbidden (TUI limitation?). Set old defaults.
|
||||
@ -3552,7 +3574,7 @@ static char_u *set_chars_option(win_T *wp, char_u **varp)
|
||||
}
|
||||
|
||||
// first round: check for valid value, second round: assign values
|
||||
for (round = 0; round <= 1; round++) {
|
||||
for (round = 0; round <= set ? 1 : 0; round++) {
|
||||
if (round > 0) {
|
||||
// After checking that the value is valid: set defaults
|
||||
for (i = 0; i < entries; i++) {
|
||||
@ -3560,7 +3582,7 @@ static char_u *set_chars_option(win_T *wp, char_u **varp)
|
||||
*(tab[i].cp) = tab[i].def;
|
||||
}
|
||||
}
|
||||
if (varp == &wp->w_p_lcs) {
|
||||
if (varp == &p_lcs || varp == &wp->w_p_lcs) {
|
||||
wp->w_p_lcs_chars.tab1 = NUL;
|
||||
wp->w_p_lcs_chars.tab3 = NUL;
|
||||
}
|
||||
@ -5560,6 +5582,16 @@ void unset_global_local_option(char *name, void *from)
|
||||
case PV_MENC:
|
||||
clear_string_option(&buf->b_p_menc);
|
||||
break;
|
||||
case PV_LCS:
|
||||
clear_string_option(&((win_T *)from)->w_p_lcs);
|
||||
set_chars_option((win_T *)from, &((win_T *)from)->w_p_lcs, true);
|
||||
redraw_win_later((win_T *)from, NOT_VALID);
|
||||
break;
|
||||
case PV_FCS:
|
||||
clear_string_option(&((win_T *)from)->w_p_fcs);
|
||||
set_chars_option((win_T *)from, &((win_T *)from)->w_p_fcs, true);
|
||||
redraw_win_later((win_T *)from, NOT_VALID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5595,6 +5627,8 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
|
||||
case PV_LW: return (char_u *)&(curbuf->b_p_lw);
|
||||
case PV_BKC: return (char_u *)&(curbuf->b_p_bkc);
|
||||
case PV_MENC: return (char_u *)&(curbuf->b_p_menc);
|
||||
case PV_FCS: return (char_u *)&(curwin->w_p_fcs);
|
||||
case PV_LCS: return (char_u *)&(curwin->w_p_lcs);
|
||||
}
|
||||
return NULL; // "cannot happen"
|
||||
}
|
||||
@ -5653,6 +5687,10 @@ static char_u *get_varp(vimoption_T *p)
|
||||
? (char_u *)&(curbuf->b_p_lw) : p->var;
|
||||
case PV_MENC: return *curbuf->b_p_menc != NUL
|
||||
? (char_u *)&(curbuf->b_p_menc) : p->var;
|
||||
case PV_FCS: return *curwin->w_p_fcs != NUL
|
||||
? (char_u *)&(curwin->w_p_fcs) : p->var;
|
||||
case PV_LCS: return *curwin->w_p_lcs != NUL
|
||||
? (char_u *)&(curwin->w_p_lcs) : p->var;
|
||||
|
||||
case PV_ARAB: return (char_u *)&(curwin->w_p_arab);
|
||||
case PV_LIST: return (char_u *)&(curwin->w_p_list);
|
||||
@ -5749,8 +5787,6 @@ static char_u *get_varp(vimoption_T *p)
|
||||
case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap);
|
||||
case PV_SCL: return (char_u *)&(curwin->w_p_scl);
|
||||
case PV_WINHL: return (char_u *)&(curwin->w_p_winhl);
|
||||
case PV_FCS: return (char_u *)&(curwin->w_p_fcs);
|
||||
case PV_LCS: return (char_u *)&(curwin->w_p_lcs);
|
||||
case PV_WINBL: return (char_u *)&(curwin->w_p_winbl);
|
||||
default: IEMSG(_("E356: get_varp ERROR"));
|
||||
}
|
||||
@ -5892,8 +5928,8 @@ void didset_window_options(win_T *wp)
|
||||
{
|
||||
check_colorcolumn(wp);
|
||||
briopt_check(wp);
|
||||
set_chars_option(wp, &wp->w_p_fcs);
|
||||
set_chars_option(wp, &wp->w_p_lcs);
|
||||
set_chars_option(wp, &wp->w_p_fcs, true);
|
||||
set_chars_option(wp, &wp->w_p_lcs, true);
|
||||
parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl
|
||||
wp->w_grid.blending = wp->w_p_winbl > 0;
|
||||
}
|
||||
|
@ -484,6 +484,7 @@ EXTERN long p_linespace; // 'linespace'
|
||||
EXTERN char_u *p_lispwords; // 'lispwords'
|
||||
EXTERN long p_ls; // 'laststatus'
|
||||
EXTERN long p_stal; // 'showtabline'
|
||||
EXTERN char_u *p_lcs; // 'listchars'
|
||||
|
||||
EXTERN int p_lz; // 'lazyredraw'
|
||||
EXTERN int p_lpl; // 'loadplugins'
|
||||
@ -652,6 +653,7 @@ EXTERN long p_ul; ///< 'undolevels'
|
||||
EXTERN long p_ur; ///< 'undoreload'
|
||||
EXTERN long p_uc; ///< 'updatecount'
|
||||
EXTERN long p_ut; ///< 'updatetime'
|
||||
EXTERN char_u *p_fcs; ///< 'fillchar'
|
||||
EXTERN char_u *p_shada; ///< 'shada'
|
||||
EXTERN char *p_shadafile; ///< 'shadafile'
|
||||
EXTERN char_u *p_vdir; ///< 'viewdir'
|
||||
|
@ -804,11 +804,12 @@ return {
|
||||
},
|
||||
{
|
||||
full_name='fillchars', abbreviation='fcs',
|
||||
type='string', list='onecomma', scope={'window'},
|
||||
type='string', list='onecomma', scope={'global', 'window'},
|
||||
deny_duplicates=true,
|
||||
vi_def=true,
|
||||
alloced=true,
|
||||
redraw={'current_window'},
|
||||
varname='p_fcs',
|
||||
defaults={if_true={vi=''}}
|
||||
},
|
||||
{
|
||||
@ -1420,11 +1421,12 @@ return {
|
||||
},
|
||||
{
|
||||
full_name='listchars', abbreviation='lcs',
|
||||
type='string', list='onecomma', scope={'window'},
|
||||
type='string', list='onecomma', scope={'global', 'window'},
|
||||
deny_duplicates=true,
|
||||
vim=true,
|
||||
alloced=true,
|
||||
redraw={'current_window'},
|
||||
varname='p_lcs',
|
||||
defaults={if_true={vi="eol:$", vim="tab:> ,trail:-,nbsp:+"}}
|
||||
},
|
||||
{
|
||||
|
@ -69,3 +69,59 @@ func! Test_display_foldtext_mbyte()
|
||||
set foldtext& fillchars& foldmethod& fdc&
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
func Test_display_listchars_precedes()
|
||||
set fillchars+=vert:\|
|
||||
call NewWindow(10, 10)
|
||||
" Need a physical line that wraps over the complete
|
||||
" window size
|
||||
call append(0, repeat('aaa aaa aa ', 10))
|
||||
call append(1, repeat(['bbb bbb bbb bbb'], 2))
|
||||
" remove blank trailing line
|
||||
$d
|
||||
set list nowrap
|
||||
call cursor(1, 1)
|
||||
" move to end of line and scroll 2 characters back
|
||||
norm! $2zh
|
||||
let lines=ScreenLines([1,4], winwidth(0)+1)
|
||||
let expect = [
|
||||
\ " aaa aa $ |",
|
||||
\ "$ |",
|
||||
\ "$ |",
|
||||
\ "~ |",
|
||||
\ ]
|
||||
call assert_equal(expect, lines)
|
||||
set list listchars+=precedes:< nowrap
|
||||
call cursor(1, 1)
|
||||
" move to end of line and scroll 2 characters back
|
||||
norm! $2zh
|
||||
let lines = ScreenLines([1,4], winwidth(0)+1)
|
||||
let expect = [
|
||||
\ "<aaa aa $ |",
|
||||
\ "< |",
|
||||
\ "< |",
|
||||
\ "~ |",
|
||||
\ ]
|
||||
call assert_equal(expect, lines)
|
||||
set wrap
|
||||
call cursor(1, 1)
|
||||
" the complete line should be displayed in the window
|
||||
norm! $
|
||||
|
||||
let lines = ScreenLines([1,10], winwidth(0)+1)
|
||||
let expect = [
|
||||
\ "<aaa aaa a|",
|
||||
\ "a aaa aaa |",
|
||||
\ "aa aaa aaa|",
|
||||
\ " aa aaa aa|",
|
||||
\ "a aa aaa a|",
|
||||
\ "aa aa aaa |",
|
||||
\ "aaa aa aaa|",
|
||||
\ " aaa aa aa|",
|
||||
\ "a aaa aa a|",
|
||||
\ "aa aaa aa |",
|
||||
\ ]
|
||||
call assert_equal(expect, lines)
|
||||
set list& listchars& wrap&
|
||||
bw!
|
||||
endfunc
|
||||
|
@ -71,15 +71,28 @@ describe("'fillchars'", function()
|
||||
shouldfail('eob:xy') -- two ascii chars
|
||||
shouldfail('eob:\255', 'eob:<ff>') -- invalid UTF-8
|
||||
end)
|
||||
it('is local to window', function()
|
||||
clear()
|
||||
screen = Screen.new(50, 5)
|
||||
screen:attach()
|
||||
it('has global value', function()
|
||||
screen:try_resize(50, 5)
|
||||
insert("foo\nbar")
|
||||
command('set laststatus=0')
|
||||
command('1,2fold')
|
||||
command('vsplit')
|
||||
command('set fillchars=fold:x')
|
||||
screen:expect([[
|
||||
^+-- 2 lines: fooxxxxxxxx│+-- 2 lines: fooxxxxxxx|
|
||||
~ │~ |
|
||||
~ │~ |
|
||||
~ │~ |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
it('has local window value', function()
|
||||
screen:try_resize(50, 5)
|
||||
insert("foo\nbar")
|
||||
command('set laststatus=0')
|
||||
command('1,2fold')
|
||||
command('vsplit')
|
||||
command('setl fillchars=fold:x')
|
||||
screen:expect([[
|
||||
^+-- 2 lines: fooxxxxxxxx│+-- 2 lines: foo·······|
|
||||
~ │~ |
|
||||
@ -100,16 +113,25 @@ describe("'listchars'", function()
|
||||
screen:attach()
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
screen:detach()
|
||||
end)
|
||||
|
||||
it('is local to window', function()
|
||||
it('has global value', function()
|
||||
feed('i<tab><tab><tab><esc>')
|
||||
command('set laststatus=0')
|
||||
command('set list listchars=tab:<->')
|
||||
command('set list laststatus=0')
|
||||
command('vsplit')
|
||||
command('set listchars&')
|
||||
command('set listchars=tab:<->')
|
||||
screen:expect([[
|
||||
<------><------>^<------> │<------><------><------>|
|
||||
~ │~ |
|
||||
~ │~ |
|
||||
~ │~ |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
it('has value local to window', function()
|
||||
feed('i<tab><tab><tab><esc>')
|
||||
command('set list laststatus=0')
|
||||
command('setl listchars=tab:<->')
|
||||
command('vsplit')
|
||||
command('setl listchars<')
|
||||
screen:expect([[
|
||||
> > ^> │<------><------><------>|
|
||||
~ │~ |
|
||||
|
@ -12,7 +12,10 @@ describe('ui/mouse/input', function()
|
||||
clear()
|
||||
meths.set_option('mouse', 'a')
|
||||
meths.set_option('list', true)
|
||||
meths.set_option('listchars', 'eol:$')
|
||||
-- NB: this is weird, but mostly irrelevant to the test
|
||||
-- So I didn't bother to change it
|
||||
command('set listchars=eol:$')
|
||||
command('setl listchars=nbsp:x')
|
||||
screen = Screen.new(25, 5)
|
||||
screen:attach()
|
||||
screen:set_default_attr_ids({
|
||||
@ -814,7 +817,8 @@ describe('ui/mouse/input', function()
|
||||
|
||||
feed_command('set concealcursor=ni')
|
||||
feed_command('set nowrap')
|
||||
feed_command('set shiftwidth=2 tabstop=4 list listchars=tab:>-')
|
||||
feed_command('set shiftwidth=2 tabstop=4 list')
|
||||
feed_command('setl listchars=tab:>-')
|
||||
feed_command('syntax match NonText "\\*" conceal')
|
||||
feed_command('syntax match NonText "cats" conceal cchar=X')
|
||||
feed_command('syntax match NonText "x" conceal cchar=>')
|
||||
|
Reference in New Issue
Block a user