]> granicus.if.org Git - vim/commitdiff
patch 8.2.2518: 'listchars' should be window-local v8.2.2518
authorBram Moolenaar <Bram@vim.org>
Mon, 15 Feb 2021 19:38:25 +0000 (20:38 +0100)
committerBram Moolenaar <Bram@vim.org>
Mon, 15 Feb 2021 19:38:25 +0000 (20:38 +0100)
Problem:    'listchars' should be window-local.
Solution:   Make 'listchars' global-local. (Yegappan Lakshmanan, Marco Hinz,
            closes #5206, closes #7850)

20 files changed:
runtime/doc/options.txt
src/buffer.c
src/charset.c
src/drawline.c
src/drawscreen.c
src/evalfunc.c
src/globals.h
src/indent.c
src/message.c
src/misc1.c
src/option.c
src/option.h
src/optiondefs.h
src/optionstr.c
src/proto/screen.pro
src/screen.c
src/structs.h
src/testdir/test_listchars.vim
src/testdir/test_listlbr.vim
src/version.c

index 08d205ceff0fde778919167555cb16455906a811..d5264ecff9579f014254006e1122d6eb26e6c445 100644 (file)
@@ -4854,7 +4854,7 @@ A jump table for the options with a short description can be found at |Q_op|.
 
                                                *'listchars'* *'lcs'*
 'listchars' 'lcs'      string  (default "eol:$")
-                       global
+                       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.
                                                        *lcs-eol*
index ca1fd36efe0ab9058345febcd256765e2535ad2f..4e4f87c9269f957f03e4b343f26f861d58b5201b 100644 (file)
@@ -4549,7 +4549,7 @@ build_stl_str_hl(
        case STL_VIRTCOL_ALT:
            // In list mode virtcol needs to be recomputed
            virtcol = wp->w_virtcol;
-           if (wp->w_p_list && lcs_tab1 == NUL)
+           if (wp->w_p_list && wp->w_lcs_chars.tab1 == NUL)
            {
                wp->w_p_list = FALSE;
                getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
index 4289360e474a9c7ab397ac092143a6cc02467362..d06a273643c62ce6e84064baac7c5d7f78ec8694 100644 (file)
@@ -753,7 +753,7 @@ vim_strnsize(char_u *s, int len)
 
 #ifdef FEAT_VARTABS
 # define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \
-    if (*(p) == TAB && (!(wp)->w_p_list || lcs_tab1)) \
+    if (*(p) == TAB && (!(wp)->w_p_list || wp->w_lcs_chars.tab1)) \
     { \
        return tabstop_padding(col, (buf)->b_p_ts, (buf)->b_p_vts_array); \
     } \
@@ -761,7 +761,7 @@ vim_strnsize(char_u *s, int len)
        return ptr2cells(p);
 #else
 # define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \
-    if (*(p) == TAB && (!(wp)->w_p_list || lcs_tab1)) \
+    if (*(p) == TAB && (!(wp)->w_p_list || wp->w_lcs_chars.tab1)) \
     { \
        int ts; \
        ts = (buf)->b_p_ts; \
@@ -1153,7 +1153,7 @@ win_nolbr_chartabsize(
 {
     int                n;
 
-    if (*s == TAB && (!wp->w_p_list || lcs_tab1))
+    if (*s == TAB && (!wp->w_p_list || wp->w_lcs_chars.tab1))
     {
 # ifdef FEAT_VARTABS
        return tabstop_padding(col, wp->w_buffer->b_p_ts,
@@ -1248,7 +1248,7 @@ getvcol(
      * use a simple loop.
      * Also use this when 'list' is set but tabs take their normal size.
      */
-    if ((!wp->w_p_list || lcs_tab1 != NUL)
+    if ((!wp->w_p_list || wp->w_lcs_chars.tab1 != NUL)
 #ifdef FEAT_LINEBREAK
            && !wp->w_p_lbr && *get_showbreak_value(wp) == NUL && !wp->w_p_bri
 #endif
index 077e7fcde37f8270af11c0c8f4111031093867cf..2f865127f7127f7fc80744988680f3aa41b5254b 100644 (file)
@@ -248,9 +248,9 @@ win_line(
     int                c_final = NUL;          // final char, mandatory if set
     int                extra_attr = 0;         // attributes when n_extra != 0
     static char_u *at_end_str = (char_u *)""; // used for p_extra when
-                                          // displaying lcs_eol at end-of-line
-    int                lcs_eol_one = lcs_eol;  // lcs_eol until it's been used
-    int                lcs_prec_todo = lcs_prec;   // lcs_prec until it's been used
+                                       // displaying eol at end-of-line
+    int                lcs_eol_one = wp->w_lcs_chars.eol; // eol until it's been used
+    int                lcs_prec_todo = wp->w_lcs_chars.prec; // prec until it's been used
 
     // saved "extra" items for when draw_state becomes WL_LINE (again)
     int                saved_n_extra = 0;
@@ -735,11 +735,14 @@ win_line(
 
     if (wp->w_p_list)
     {
-       if (lcs_space || lcs_trail || lcs_lead || lcs_nbsp)
+       if (wp->w_lcs_chars.space
+               || wp->w_lcs_chars.trail
+               || wp->w_lcs_chars.lead
+               || wp->w_lcs_chars.nbsp)
            extra_check = TRUE;
 
        // find start of trailing whitespace
-       if (lcs_trail)
+       if (wp->w_lcs_chars.trail)
        {
            trailcol = (colnr_T)STRLEN(ptr);
            while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1]))
@@ -747,7 +750,7 @@ win_line(
            trailcol += (colnr_T) (ptr - line);
        }
        // find end of leading whitespace
-       if (lcs_lead)
+       if (wp->w_lcs_chars.lead)
        {
            leadcol = 0;
            while (VIM_ISWHITE(ptr[leadcol]))
@@ -2000,22 +2003,23 @@ win_line(
                }
 #endif
 
-               // 'list': Change char 160 to lcs_nbsp and space to lcs_space.
-               // But not when the character is followed by a composing
-               // character (use mb_l to check that).
+               // 'list': Change char 160 to 'nbsp' and space to 'space'
+               // setting in 'listchars'.  But not when the character is
+               // followed by a composing character (use mb_l to check that).
                if (wp->w_p_list
                        && ((((c == 160 && mb_l == 1)
                              || (mb_utf8
                                  && ((mb_c == 160 && mb_l == 2)
                                      || (mb_c == 0x202f && mb_l == 3))))
-                            && lcs_nbsp)
+                            && wp->w_lcs_chars.nbsp)
                            || (c == ' '
                                && mb_l == 1
-                               && lcs_space
+                               && wp->w_lcs_chars.space
                                && ptr - line >= leadcol
                                && ptr - line <= trailcol)))
                {
-                   c = (c == ' ') ? lcs_space : lcs_nbsp;
+                   c = (c == ' ') ? wp->w_lcs_chars.space :
+                                                       wp->w_lcs_chars.nbsp;
                    if (area_attr == 0 && search_attr == 0)
                    {
                        n_attr = 1;
@@ -2036,7 +2040,8 @@ win_line(
                if ((trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
                        || (leadcol != 0 && ptr < line + leadcol && c == ' '))
                {
-                   c = (ptr > line + trailcol) ? lcs_trail : lcs_lead;
+                   c = (ptr > line + trailcol) ? wp->w_lcs_chars.trail
+                                                       : wp->w_lcs_chars.lead;
                    if (!attr_pri)
                    {
                        n_attr = 1;
@@ -2061,7 +2066,7 @@ win_line(
                // when getting a character from the file, we may have to
                // turn it into something else on the way to putting it
                // into "ScreenLines".
-               if (c == TAB && (!wp->w_p_list || lcs_tab1))
+               if (c == TAB && (!wp->w_p_list || wp->w_lcs_chars.tab1))
                {
                    int tab_len = 0;
                    long vcol_adjusted = vcol; // removed showbreak length
@@ -2101,18 +2106,19 @@ win_line(
                            // there are characters to conceal
                            tab_len += vcol_off;
                        // boguscols before FIX_FOR_BOGUSCOLS macro from above
-                       if (wp->w_p_list && lcs_tab1 && old_boguscols > 0
-                                                        && n_extra > tab_len)
+                       if (wp->w_p_list && wp->w_lcs_chars.tab1
+                                                       && old_boguscols > 0
+                                                       && n_extra > tab_len)
                            tab_len += n_extra - tab_len;
 #endif
 
                        // if n_extra > 0, it gives the number of chars, to
                        // use for a tab, else we need to calculate the width
                        // for a tab
-                       len = (tab_len * mb_char2len(lcs_tab2));
+                       len = (tab_len * mb_char2len(wp->w_lcs_chars.tab2));
                        if (n_extra > 0)
                            len += n_extra - tab_len;
-                       c = lcs_tab1;
+                       c = wp->w_lcs_chars.tab1;
                        p = alloc(len + 1);
                        vim_memset(p, ' ', len);
                        p[len] = NUL;
@@ -2120,7 +2126,7 @@ win_line(
                        p_extra_free = p;
                        for (i = 0; i < tab_len; i++)
                        {
-                           int lcs = lcs_tab2;
+                           int lcs = wp->w_lcs_chars.tab2;
 
                            if (*p == NUL)
                            {
@@ -2128,10 +2134,10 @@ win_line(
                                break;
                            }
 
-                           // if lcs_tab3 is given, need to change the char
+                           // if tab3 is given, need to change the char
                            // for tab
-                           if (lcs_tab3 && i == tab_len - 1)
-                               lcs = lcs_tab3;
+                           if (wp->w_lcs_chars.tab3 && i == tab_len - 1)
+                               lcs = wp->w_lcs_chars.tab3;
                            mb_char2bytes(lcs, p);
                            p += mb_char2len(lcs);
                            n_extra += mb_char2len(lcs)
@@ -2162,21 +2168,23 @@ win_line(
                        // correctly set further below (effectively reverts the
                        // FIX_FOR_BOGSUCOLS macro
                        if (n_extra == tab_len + vc_saved && wp->w_p_list
-                                                                 && lcs_tab1)
+                                               && wp->w_lcs_chars.tab1)
                            tab_len += vc_saved;
                    }
 #endif
                    mb_utf8 = FALSE;    // don't draw as UTF-8
                    if (wp->w_p_list)
                    {
-                       c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1;
+                       c = (n_extra == 0 && wp->w_lcs_chars.tab3)
+                                                       ? wp->w_lcs_chars.tab3
+                                                       : wp->w_lcs_chars.tab1;
 #ifdef FEAT_LINEBREAK
                        if (wp->w_p_lbr)
                            c_extra = NUL; // using p_extra from above
                        else
 #endif
-                           c_extra = lcs_tab2;
-                       c_final = lcs_tab3;
+                           c_extra = wp->w_lcs_chars.tab2;
+                       c_final = wp->w_lcs_chars.tab3;
                        n_attr = tab_len + 1;
                        extra_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_8));
                        saved_attr2 = char_attr; // save current attr
@@ -2241,8 +2249,8 @@ win_line(
                            c_final = NUL;
                        }
                    }
-                   if (wp->w_p_list && lcs_eol > 0)
-                       c = lcs_eol;
+                   if (wp->w_p_list && wp->w_lcs_chars.eol > 0)
+                       c = wp->w_lcs_chars.eol;
                    else
                        c = ' ';
                    lcs_eol_one = -1;
@@ -2344,7 +2352,8 @@ win_line(
                    // don't do search HL for the rest of the line
                    if (line_attr != 0 && char_attr == search_attr
                                        && (did_line_attr > 1
-                                           || (wp->w_p_list && lcs_eol > 0)))
+                                           || (wp->w_p_list &&
+                                               wp->w_lcs_chars.eol > 0)))
                        char_attr = line_attr;
 # ifdef FEAT_DIFF
                    if (diff_hlf == HLF_TXD)
@@ -2404,8 +2413,8 @@ win_line(
                        c = match_conc;
                    else if (syn_get_sub_char() != NUL)
                        c = syn_get_sub_char();
-                   else if (lcs_conceal != NUL)
-                       c = lcs_conceal;
+                   else if (wp->w_lcs_chars.conceal != NUL)
+                       c = wp->w_lcs_chars.conceal;
                    else
                        c = ' ';
 
@@ -2548,7 +2557,7 @@ win_line(
                && draw_state > WL_NR
                && c != NUL)
        {
-           c = lcs_prec;
+           c = wp->w_lcs_chars.prec;
            lcs_prec_todo = NUL;
            if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
            {
@@ -2594,7 +2603,7 @@ win_line(
            // highlight match at end of line. If it's beyond the last
            // char on the screen, just overwrite that one (tricky!)  Not
            // needed when a '$' was displayed for 'list'.
-           if (lcs_eol == lcs_eol_one
+           if (wp->w_lcs_chars.eol == lcs_eol_one
                    && ((area_attr != 0 && vcol == fromcol
                            && (VIsual_mode != Ctrl_V
                                || lnum == VIsual.lnum
@@ -2764,7 +2773,7 @@ win_line(
 
        // Show "extends" character from 'listchars' if beyond the line end and
        // 'list' is set.
-       if (lcs_ext != NUL
+       if (wp->w_lcs_chars.ext != NUL
                && wp->w_p_list
                && !wp->w_p_wrap
 #ifdef FEAT_DIFF
@@ -2779,7 +2788,7 @@ win_line(
                    || (wp->w_p_list && lcs_eol_one > 0)
                    || (n_extra && (c_extra != NUL || *p_extra != NUL))))
        {
-           c = lcs_ext;
+           c = wp->w_lcs_chars.ext;
            char_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_AT));
            mb_c = c;
            if (enc_utf8 && utf_char2len(c) > 1)
@@ -3036,7 +3045,8 @@ win_line(
 #ifdef FEAT_DIFF
                    || filler_todo > 0
 #endif
-                   || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
+                   || (wp->w_p_list && wp->w_lcs_chars.eol != NUL
+                                               && p_extra != at_end_str)
                    || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
                )
        {
@@ -3161,7 +3171,7 @@ win_line(
 #endif
                saved_char_attr = 0;
            n_extra = 0;
-           lcs_prec_todo = lcs_prec;
+           lcs_prec_todo = wp->w_lcs_chars.prec;
 #ifdef FEAT_LINEBREAK
 # ifdef FEAT_DIFF
            if (filler_todo <= 0)
index 694b9dac313bd5a0f784ba540ed846eb55f1ecf1..3fe1c0c7971139aca217aa5e3dadbdb50740d4f9 100644 (file)
@@ -696,7 +696,7 @@ win_redr_ruler(win_T *wp, int always, int ignore_pum)
 
        // In list mode virtcol needs to be recomputed
        virtcol = wp->w_virtcol;
-       if (wp->w_p_list && lcs_tab1 == NUL)
+       if (wp->w_p_list && wp->w_lcs_chars.tab1 == NUL)
        {
            wp->w_p_list = FALSE;
            getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
index b3da9f6cf6f4e365c71fc059ee77192d11d5e551..bee76c6eafcba48b343f22ff21acb99c29ad2bdc 100644 (file)
@@ -9736,7 +9736,8 @@ f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
            {
                cchar = syn_get_sub_char();
                if (cchar == NUL && curwin->w_p_cole == 1)
-                   cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
+                   cchar = (curwin->w_lcs_chars.conceal == NUL) ? ' '
+                                       : curwin->w_lcs_chars.conceal;
                if (cchar != NUL)
                {
                    if (has_mbyte)
index 3ad4227ebc1874b2468066b9e56436eac1375619..bc4a3d5d539387d5815d65921688f53e677a40ec 100644 (file)
@@ -1342,21 +1342,6 @@ EXTERN char_u    *homedir INIT(= NULL);
 // directory is not a local directory, globaldir is NULL.
 EXTERN char_u  *globaldir INIT(= NULL);
 
-// Characters from 'listchars' option
-EXTERN int     lcs_eol INIT(= '$');
-EXTERN int     lcs_ext INIT(= NUL);
-EXTERN int     lcs_prec INIT(= NUL);
-EXTERN int     lcs_nbsp INIT(= NUL);
-EXTERN int     lcs_space INIT(= NUL);
-EXTERN int     lcs_tab1 INIT(= NUL);
-EXTERN int     lcs_tab2 INIT(= NUL);
-EXTERN int     lcs_tab3 INIT(= NUL);
-EXTERN int     lcs_trail INIT(= NUL);
-EXTERN int     lcs_lead INIT(= NUL);
-#ifdef FEAT_CONCEAL
-EXTERN int     lcs_conceal INIT(= ' ');
-#endif
-
 // Characters from 'fillchars' option
 EXTERN int     fill_stl INIT(= ' ');
 EXTERN int     fill_stlnc INIT(= ' ');
index 6ac6182df4d4233aa2ad6b896c9031a7f63f882b..e1c6f522a9bb0339db4ac91b2a5a2614c3e27d50 100644 (file)
@@ -432,7 +432,8 @@ get_indent_str(
     {
        if (*ptr == TAB)
        {
-           if (!list || lcs_tab1)    // count a tab for what it is worth
+           if (!list || curwin->w_lcs_chars.tab1)
+               // count a tab for what it is worth
                count += ts - (count % ts);
            else
                // In list mode, when tab is not set, count screen char width
@@ -462,7 +463,7 @@ get_indent_str_vtab(char_u *ptr, int ts, int *vts, int list)
     {
        if (*ptr == TAB)    // count a tab for what it is worth
        {
-           if (!list || lcs_tab1)
+           if (!list || curwin->w_lcs_chars.tab1)
                count += tabstop_padding(count, ts, vts);
            else
                // In list mode, when tab is not set, count screen char width
index 012811f9cf173b673d4313f2a960489440f3e694..07c3943ab4dab3d913eac909201dded1ae0cdb2f 100644 (file)
@@ -1848,14 +1848,14 @@ msg_prt_line(char_u *s, int list)
     if (list)
     {
        // find start of trailing whitespace
-       if (lcs_trail)
+       if (curwin->w_lcs_chars.trail)
        {
            trail = s + STRLEN(s);
            while (trail > s && VIM_ISWHITE(trail[-1]))
                --trail;
        }
        // find end of leading whitespace
-       if (lcs_lead)
+       if (curwin->w_lcs_chars.lead)
        {
            lead = s;
            while (VIM_ISWHITE(lead[0]))
@@ -1868,7 +1868,7 @@ msg_prt_line(char_u *s, int list)
 
     // output a space for an empty line, otherwise the line will be
     // overwritten
-    if (*s == NUL && !(list && lcs_eol != NUL))
+    if (*s == NUL && !(list && curwin->w_lcs_chars.eol != NUL))
        msg_putchar(' ');
 
     while (!got_int)
@@ -1890,11 +1890,11 @@ msg_prt_line(char_u *s, int list)
            {
                STRCPY(buf, "?");
            }
-           else if (lcs_nbsp != NUL && list
+           else if (curwin->w_lcs_chars.nbsp != NUL && list
                    && (mb_ptr2char(s) == 160
                        || mb_ptr2char(s) == 0x202f))
            {
-               mb_char2bytes(lcs_nbsp, buf);
+               mb_char2bytes(curwin->w_lcs_chars.nbsp, buf);
                buf[(*mb_ptr2len)(buf)] = NUL;
            }
            else
@@ -1910,7 +1910,7 @@ msg_prt_line(char_u *s, int list)
        {
            attr = 0;
            c = *s++;
-           if (c == TAB && (!list || lcs_tab1))
+           if (c == TAB && (!list || curwin->w_lcs_chars.tab1))
            {
                // tab amount depends on current column
 #ifdef FEAT_VARTABS
@@ -1927,24 +1927,26 @@ msg_prt_line(char_u *s, int list)
                }
                else
                {
-                   c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1;
-                   c_extra = lcs_tab2;
-                   c_final = lcs_tab3;
+                   c = (n_extra == 0 && curwin->w_lcs_chars.tab3)
+                                               ? curwin->w_lcs_chars.tab3
+                                               : curwin->w_lcs_chars.tab1;
+                   c_extra = curwin->w_lcs_chars.tab2;
+                   c_final = curwin->w_lcs_chars.tab3;
                    attr = HL_ATTR(HLF_8);
                }
            }
-           else if (c == 160 && list && lcs_nbsp != NUL)
+           else if (c == 160 && list && curwin->w_lcs_chars.nbsp != NUL)
            {
-               c = lcs_nbsp;
+               c = curwin->w_lcs_chars.nbsp;
                attr = HL_ATTR(HLF_8);
            }
-           else if (c == NUL && list && lcs_eol != NUL)
+           else if (c == NUL && list && curwin->w_lcs_chars.eol != NUL)
            {
                p_extra = (char_u *)"";
                c_extra = NUL;
                c_final = NUL;
                n_extra = 1;
-               c = lcs_eol;
+               c = curwin->w_lcs_chars.eol;
                attr = HL_ATTR(HLF_AT);
                --s;
            }
@@ -1961,17 +1963,17 @@ msg_prt_line(char_u *s, int list)
            }
            else if (c == ' ' && lead != NULL && s <= lead)
            {
-               c = lcs_lead;
+               c = curwin->w_lcs_chars.lead;
                attr = HL_ATTR(HLF_8);
            }
            else if (c == ' ' && trail != NULL && s > trail)
            {
-               c = lcs_trail;
+               c = curwin->w_lcs_chars.trail;
                attr = HL_ATTR(HLF_8);
            }
-           else if (c == ' ' && list && lcs_space != NUL)
+           else if (c == ' ' && list && curwin->w_lcs_chars.space != NUL)
            {
-               c = lcs_space;
+               c = curwin->w_lcs_chars.space;
                attr = HL_ATTR(HLF_8);
            }
        }
index 010622ee5ccd589769fa21294c84784d6160680f..a72dc9bf212ea6a469e87ea53ec4fe713d2bb156 100644 (file)
@@ -403,7 +403,7 @@ plines_win_nofold(win_T *wp, linenr_T lnum)
      * If list mode is on, then the '$' at the end of the line may take up one
      * extra column.
      */
-    if (wp->w_p_list && lcs_eol != NUL)
+    if (wp->w_p_list && wp->w_lcs_chars.eol != NUL)
        col += 1;
 
     /*
@@ -460,7 +460,8 @@ plines_win_col(win_T *wp, linenr_T lnum, long column)
      * from one screen line to the next (when 'columns' is not a multiple of
      * 'ts') -- webb.
      */
-    if (*s == TAB && (State & NORMAL) && (!wp->w_p_list || lcs_tab1))
+    if (*s == TAB && (State & NORMAL) && (!wp->w_p_list ||
+                                                       wp->w_lcs_chars.tab1))
        col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL) - 1;
 
     /*
index bba467e5e97f7e23f1e05b3f77cd0adb79760a04..9db9c2633f15db9a9128fb166805fc4937647518 100644 (file)
@@ -2337,9 +2337,11 @@ didset_options2(void)
     // Parse default for 'wildmode'
     check_opt_wim();
 
-    (void)set_chars_option(&p_lcs);
+    // Parse default for 'listchars'.
+    (void)set_chars_option(curwin, &curwin->w_p_lcs);
+
     // Parse default for 'fillchars'.
-    (void)set_chars_option(&p_fcs);
+    (void)set_chars_option(curwin, &p_fcs);
 
 #ifdef FEAT_CLIPBOARD
     // Parse default for 'clipboard'
@@ -5063,6 +5065,11 @@ unset_global_local_option(char_u *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);
+           redraw_later(NOT_VALID);
+           break;
     }
 }
 #endif
@@ -5121,6 +5128,8 @@ get_varp_scope(struct vimoption *p, int opt_flags)
 #endif
            case PV_BKC:  return (char_u *)&(curbuf->b_p_bkc);
            case PV_MENC: return (char_u *)&(curbuf->b_p_menc);
+           case PV_LCS: return (char_u *)&(curwin->w_p_lcs);
+
        }
        return NULL; // "cannot happen"
     }
@@ -5218,6 +5227,8 @@ get_varp(struct vimoption *p)
        case PV_ARAB:   return (char_u *)&(curwin->w_p_arab);
 #endif
        case PV_LIST:   return (char_u *)&(curwin->w_p_list);
+       case PV_LCS:    return *curwin->w_p_lcs != NUL
+                                   ? (char_u *)&(curwin->w_p_lcs) : p->var;
 #ifdef FEAT_SPELL
        case PV_SPELL:  return (char_u *)&(curwin->w_p_spell);
 #endif
@@ -5445,6 +5456,7 @@ after_copy_winopt(win_T *wp UNUSED)
     fill_culopt_flags(NULL, wp);
     check_colorcolumn(wp);
 #endif
+    set_chars_option(wp, &wp->w_p_lcs);
 }
 
 /*
@@ -5460,6 +5472,7 @@ copy_winopt(winopt_T *from, winopt_T *to)
     to->wo_arab = from->wo_arab;
 #endif
     to->wo_list = from->wo_list;
+    to->wo_lcs = vim_strsave(from->wo_lcs);
     to->wo_nu = from->wo_nu;
     to->wo_rnu = from->wo_rnu;
 #ifdef FEAT_LINEBREAK
@@ -5594,6 +5607,7 @@ check_winopt(winopt_T *wop UNUSED)
     check_string_option(&wop->wo_briopt);
 #endif
     check_string_option(&wop->wo_wcr);
+    check_string_option(&wop->wo_lcs);
 }
 
 /*
@@ -5639,6 +5653,7 @@ clear_winopt(winopt_T *wop UNUSED)
     clear_string_option(&wop->wo_twk);
     clear_string_option(&wop->wo_tws);
 #endif
+    clear_string_option(&wop->wo_lcs);
 }
 
 #ifdef FEAT_EVAL
index 4bc189ca73da52f52c571c839f7321ca9edb0a26..349268c3d41deedab15b1e578dfb6f9610701526 100644 (file)
@@ -1231,6 +1231,7 @@ enum
 enum
 {
     WV_LIST = 0
+    , WV_LCS
 #ifdef FEAT_ARABIC
     , WV_ARAB
 #endif
index 3e76c8ace71ec4cf13b08a436856e21905103428..dcd195d7efb6e51f693cb4b2d7136821a636c19b 100644 (file)
 #ifdef FEAT_LINEBREAK
 # define PV_LBR                OPT_WIN(WV_LBR)
 #endif
+#define PV_LCS         OPT_BOTH(OPT_WIN(WV_LCS))
 #define PV_NU          OPT_WIN(WV_NU)
 #define PV_RNU         OPT_WIN(WV_RNU)
 #ifdef FEAT_LINEBREAK
@@ -1598,7 +1599,7 @@ static struct vimoption options[] =
                            (char_u *)VAR_WIN, PV_LIST,
                            {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"listchars",   "lcs",  P_STRING|P_VI_DEF|P_RALL|P_ONECOMMA|P_NODUP,
-                           (char_u *)&p_lcs, PV_NONE,
+                           (char_u *)&p_lcs, PV_LCS,
                            {(char_u *)"eol:$", (char_u *)0L} SCTX_INIT},
     {"loadplugins", "lpl",  P_BOOL|P_VI_DEF,
                            (char_u *)&p_lpl, PV_NONE,
index c8a5b0c6583da1afc207a529cc06c2b61fb2ad8d..a1cbe262f4b9047cb5020e7d970d8db2a602a41a 100644 (file)
@@ -862,10 +862,24 @@ did_set_string_option(
     {
        if (check_opt_strings(p_ambw, p_ambw_values, FALSE) != OK)
            errmsg = e_invarg;
-       else if (set_chars_option(&p_lcs) != NULL)
-           errmsg = _("E834: Conflicts with value of 'listchars'");
-       else if (set_chars_option(&p_fcs) != NULL)
+       else if (set_chars_option(curwin, &p_fcs) != NULL)
            errmsg = _("E835: Conflicts with value of 'fillchars'");
+       else
+       {
+           tabpage_T   *tp;
+           win_T       *wp;
+
+           FOR_ALL_TAB_WINDOWS(tp, wp)
+           {
+               if (set_chars_option(wp, &wp->w_p_lcs) != NULL)
+               {
+                   errmsg = _("E834: Conflicts with value of 'listchars'");
+                   goto ambw_end;
+               }
+           }
+       }
+ambw_end:
+       {}
     }
 
     // 'background'
@@ -1292,16 +1306,37 @@ did_set_string_option(
        }
     }
 
-    // 'listchars'
+    // global 'listchars'
     else if (varp == &p_lcs)
     {
-       errmsg = set_chars_option(varp);
+       errmsg = set_chars_option(curwin, varp);
+       if (errmsg == NULL)
+       {
+           tabpage_T   *tp;
+           win_T               *wp;
+
+           // The current window is set to use the global 'listchars' value.
+           // So clear the window-local value.
+           if (!(opt_flags & OPT_GLOBAL))
+               clear_string_option(&curwin->w_p_lcs);
+           FOR_ALL_TAB_WINDOWS(tp, wp)
+           {
+               errmsg = set_chars_option(wp, &wp->w_p_lcs);
+               if (errmsg)
+                   break;
+           }
+           redraw_all_later(NOT_VALID);
+       }
     }
 
+    // local 'listchars'
+    else if (varp == &curwin->w_p_lcs)
+       errmsg = set_chars_option(curwin, varp);
+
     // 'fillchars'
     else if (varp == &p_fcs)
     {
-       errmsg = set_chars_option(varp);
+       errmsg = set_chars_option(curwin, varp);
     }
 
 #ifdef FEAT_CMDWIN
index 3f475ec12c56842e67e13b291bf84463aa2ab280..1ab40df0c93619a46bce258824e99250e3010bfa 100644 (file)
@@ -55,5 +55,5 @@ void comp_col(void);
 int number_width(win_T *wp);
 int screen_screencol(void);
 int screen_screenrow(void);
-char *set_chars_option(char_u **varp);
+char *set_chars_option(win_T *wp, char_u **varp);
 /* vim: set ft=c : */
index b3944a71dae7c12132f0a53183e17858a6477b52..176f98d571a124c9b712091e9731a100d3d6d747 100644 (file)
@@ -4745,10 +4745,11 @@ screen_screenrow(void)
 
 /*
  * Handle setting 'listchars' or 'fillchars'.
+ * Assume monocell characters.
  * Returns error message, NULL if it's OK.
  */
     char *
-set_chars_option(char_u **varp)
+set_chars_option(win_T *wp, char_u **varp)
 {
     int                round, i, len, entries;
     char_u     *p, *s;
@@ -4767,28 +4768,30 @@ set_chars_option(char_u **varp)
        {&fill_diff,    "diff"},
        {&fill_eob,     "eob"},
     };
-    static struct charstab lcstab[] =
+    struct charstab lcstab[] =
     {
-       {&lcs_eol,      "eol"},
-       {&lcs_ext,      "extends"},
-       {&lcs_nbsp,     "nbsp"},
-       {&lcs_prec,     "precedes"},
-       {&lcs_space,    "space"},
-       {&lcs_tab2,     "tab"},
-       {&lcs_trail,    "trail"},
-       {&lcs_lead,     "lead"},
+       {&wp->w_lcs_chars.eol,  "eol"},
+       {&wp->w_lcs_chars.ext,  "extends"},
+       {&wp->w_lcs_chars.nbsp, "nbsp"},
+       {&wp->w_lcs_chars.prec, "precedes"},
+       {&wp->w_lcs_chars.space,"space"},
+       {&wp->w_lcs_chars.tab2, "tab"},
+       {&wp->w_lcs_chars.trail,"trail"},
+       {&wp->w_lcs_chars.lead, "lead"},
 #ifdef FEAT_CONCEAL
-       {&lcs_conceal,  "conceal"},
+       {&wp->w_lcs_chars.conceal,      "conceal"},
 #else
        {NULL,          "conceal"},
 #endif
     };
     struct charstab *tab;
 
-    if (varp == &p_lcs)
+    if (varp == &p_lcs || varp == &wp->w_p_lcs)
     {
        tab = lcstab;
        entries = sizeof(lcstab) / sizeof(struct charstab);
+       if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL)
+           varp = &p_lcs;
     }
     else
     {
@@ -4805,12 +4808,13 @@ set_chars_option(char_u **varp)
            // 'fillchars', NUL for 'listchars'
            for (i = 0; i < entries; ++i)
                if (tab[i].cp != NULL)
-                   *(tab[i].cp) = (varp == &p_lcs ? NUL : ' ');
+                   *(tab[i].cp) =
+                       ((varp == &p_lcs || varp == &wp->w_p_lcs) ? NUL : ' ');
 
-           if (varp == &p_lcs)
+           if (varp == &p_lcs || varp == &wp->w_p_lcs)
            {
-               lcs_tab1 = NUL;
-               lcs_tab3 = NUL;
+               wp->w_lcs_chars.tab1 = NUL;
+               wp->w_lcs_chars.tab3 = NUL;
            }
            else
            {
@@ -4833,7 +4837,7 @@ set_chars_option(char_u **varp)
                    c1 = mb_ptr2char_adv(&s);
                    if (mb_char2cells(c1) > 1)
                        continue;
-                   if (tab[i].cp == &lcs_tab2)
+                   if (tab[i].cp == &wp->w_lcs_chars.tab2)
                    {
                        if (*s == NUL)
                            continue;
@@ -4852,11 +4856,11 @@ set_chars_option(char_u **varp)
                    {
                        if (round)
                        {
-                           if (tab[i].cp == &lcs_tab2)
+                           if (tab[i].cp == &wp->w_lcs_chars.tab2)
                            {
-                               lcs_tab1 = c1;
-                               lcs_tab2 = c2;
-                               lcs_tab3 = c3;
+                               wp->w_lcs_chars.tab1 = c1;
+                               wp->w_lcs_chars.tab2 = c2;
+                               wp->w_lcs_chars.tab3 = c3;
                            }
                            else if (tab[i].cp != NULL)
                                *(tab[i].cp) = c1;
index 7bcbc389e8361de6675cb9bda6569191a49f7218..0ca9203406eb5c18b6ea139c62ce62830885861a 100644 (file)
@@ -225,6 +225,8 @@ typedef struct
 #endif
     int                wo_list;
 #define w_p_list w_onebuf_opt.wo_list  // 'list'
+    char_u     *wo_lcs;
+#define w_p_lcs w_onebuf_opt.wo_lcs    // 'listchars'
     int                wo_nu;
 #define w_p_nu w_onebuf_opt.wo_nu      // 'number'
     int                wo_rnu;
@@ -3332,6 +3334,26 @@ typedef struct {
 } winbar_item_T;
 #endif
 
+/*
+ * Characters from the 'listchars' option
+ */
+typedef struct
+{
+    int                eol;
+    int                ext;
+    int                prec;
+    int                nbsp;
+    int                space;
+    int                tab1;
+    int                tab2;
+    int                tab3;
+    int                trail;
+    int                lead;
+#ifdef FEAT_CONCEAL
+    int                conceal;
+#endif
+} lcs_chars_T;
+
 /*
  * Structure which contains all information that belongs to a window
  *
@@ -3380,6 +3402,8 @@ struct window_S
     colnr_T    w_old_visual_col;   // last known start of visual part
     colnr_T    w_old_curswant;     // last known value of Curswant
 
+    lcs_chars_T        w_lcs_chars;        // 'listchars' characters
+
     /*
      * "w_topline", "w_leftcol" and "w_skipcol" specify the offsets for
      * displaying the buffer.
index 69c98b9269685530e51077216d3bd6b921db04f0..ca47d5283aadf88bc6f9809eb6cac7941ca76789 100644 (file)
@@ -234,4 +234,110 @@ func Test_listchars_composing()
   set listchars& ff&
 endfunction
 
+" Check for the value of the 'listchars' option
+func s:CheckListCharsValue(expected)
+  call assert_equal(a:expected, &listchars)
+  call assert_equal(a:expected, getwinvar(0, '&listchars'))
+endfunc
+
+" Test for using a window local value for 'listchars'
+func Test_listchars_window_local()
+  %bw!
+  set list listchars&
+  new
+  " set a local value for 'listchars'
+  setlocal listchars=tab:+-,eol:#
+  call s:CheckListCharsValue('tab:+-,eol:#')
+  " When local value is reset, global value should be used
+  setlocal listchars=
+  call s:CheckListCharsValue('eol:$')
+  " Use 'setlocal <' to copy global value
+  setlocal listchars=space:.,extends:>
+  setlocal listchars<
+  call s:CheckListCharsValue('eol:$')
+  " Use 'set <' to copy global value
+  setlocal listchars=space:.,extends:>
+  set listchars<
+  call s:CheckListCharsValue('eol:$')
+  " Changing global setting should not change the local setting
+  setlocal listchars=space:.,extends:>
+  setglobal listchars=tab:+-,eol:#
+  call s:CheckListCharsValue('space:.,extends:>')
+  " when split opening a new window, local value should be copied
+  split
+  call s:CheckListCharsValue('space:.,extends:>')
+  " clearing local value in one window should not change the other window
+  set listchars&
+  call s:CheckListCharsValue('eol:$')
+  close
+  call s:CheckListCharsValue('space:.,extends:>')
+
+  " use different values for 'listchars' items in two different windows
+  call setline(1, ["\t  one  two  "])
+  setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+  split
+  setlocal listchars=tab:[.],lead:#,space:_,trail:.,eol:&
+  split
+  set listchars=tab:+-+,lead:^,space:>,trail:<,eol:%
+  call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$')))
+  close
+  call assert_equal(['[......]##one__two..&'], ScreenLines(1, virtcol('$')))
+  close
+  call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+  " changing the global setting should not change the local value
+  setglobal listchars=tab:[.],lead:#,space:_,trail:.,eol:&
+  call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+  set listchars<
+  call assert_equal(['[......]##one__two..&'], ScreenLines(1, virtcol('$')))
+
+  " Using setglobal in a window with local setting should not affect the
+  " window. But should impact other windows using the global setting.
+  enew! | only
+  call setline(1, ["\t  one  two  "])
+  set listchars=tab:[.],lead:#,space:_,trail:.,eol:&
+  split
+  setlocal listchars=tab:+-+,lead:^,space:>,trail:<,eol:%
+  split
+  setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+  setglobal listchars=tab:{.},lead:-,space:=,trail:#,eol:$
+  call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+  close
+  call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$')))
+  close
+  call assert_equal(['{......}--one==two##$'], ScreenLines(1, virtcol('$')))
+
+  " Setting the global setting to the default value should not impact a window
+  " using a local setting
+  split
+  setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+  setglobal listchars&vim
+  call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+  close
+  call assert_equal(['^I  one  two  $'], ScreenLines(1, virtcol('$')))
+
+  " Setting the local setting to the default value should not impact a window
+  " using a global setting
+  set listchars=tab:{.},lead:-,space:=,trail:#,eol:$
+  split
+  setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+  call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+  setlocal listchars&vim
+  call assert_equal(['^I  one  two  $'], ScreenLines(1, virtcol('$')))
+  close
+  call assert_equal(['{......}--one==two##$'], ScreenLines(1, virtcol('$')))
+
+  " Using set in a window with a local setting should change it to use the
+  " global setting and also impact other windows using the global setting
+  split
+  setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+  call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+  set listchars=tab:+-+,lead:^,space:>,trail:<,eol:%
+  call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$')))
+  close
+  call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$')))
+
+  %bw!
+  set list& listchars&
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index 37bc44bb698f5d00eed63ae4a3937dea15b9aa77..24bd25679a654e58357afebacba6f4fcbbe3c99d 100644 (file)
@@ -43,6 +43,7 @@ func Test_set_linebreak()
 endfunc
 
 func Test_linebreak_with_list()
+  set listchars=
   call s:test_windows('setl ts=4 sbr=+ list listchars=')
   call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ")
   let lines = s:screen_lines([1, 4], winwidth(0))
@@ -54,6 +55,7 @@ func Test_linebreak_with_list()
 \ ]
   call s:compare_lines(expect, lines)
   call s:close_windows()
+  set listchars&vim
 endfunc
 
 func Test_linebreak_with_nolist()
index 60d7d62dc44948d99445ca5eec98e5718edffbd5..774ff529e061f74819ad049bc31c621b48dc40d5 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2518,
 /**/
     2517,
 /**/