[vim/vim] Add 'leadtab' option to 'listchars' (tab guide only in leading indentation) (PR #19094)

14 views
Skip to first unread message

Harsh Kapse

unread,
Jan 5, 2026, 10:39:10 AM (8 days ago) Jan 5
to vim/vim, Subscribed

Summary

It would be useful to add 'leadtab' option in 'listchars', similar to 'leadmultispace', but for tabs. This allows drawing indentation guides for tabs indented code, without affecting the tabs that appear later in the line.

This is motivated from Neovim feature request: neovim/neovim#37138

Problem

When using hard tabs for indentation (i.e not expandtab), users currently rely on listchar+=tab:.. to visualize tabs. But tab: affects all the tab character, which can look noisy
There already exist leadmultispace: which supports indentation nicely for spaces, but no equivalent for tabs

Proposed Behavior:

Add leadtab:{chars} to 'listchars'

  • leadtab should apply only to tabs that occur as leading indentation
  • once a whitespace is encountered, tabs displays using normal tab:
  • leadtab should not affect tabs that occurs after first non whitespace character
  • Mixed indentation should work naturally, spaces can be rendered with lead:/leadmultispace:/space:, while leading tabs specifically uses leadtab

Example

With:

  • set list
  • set listchars=tab:>-,leadtab:+*

Buffer:

  • \ttext
  • text\ttab

Expected display (assuming tabstop=4):

  • leading tab uses leadtab:: +****text
  • mid-line tab uses tab:: text>---tab

Test coverage / current work in the pr

I have added tests which should pass when this functionality is added in src/testdir/test_listchars.vim

If the behavior and name is accepted, I would love to work on this

Related:


You can view, comment on, or merge this pull request online at:

  https://github.com/vim/vim/pull/19094

Commit Summary

  • 17b63ff test: added new test for new option 'leadtab'

File Changes

(1 file)

Patch Links:


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094@github.com>

zeertzjq

unread,
Jan 5, 2026, 6:56:32 PM (7 days ago) Jan 5
to vim/vim, Subscribed

@zeertzjq commented on this pull request.


In src/testdir/test_listchars.vim:

> +  normal ggdG
+  set listchars=tab:>-,leadtab:├─┤
+  call append(0, ["\ttext"])
+  let expected = ['├──────┤text']
+  call Check_listchars(expected, 1, 12)
+
+  " Test leadtab with mixed indentation (spaces + tabs)
+  normal ggdG
+  set listchars=tab:>-,leadtab:+*,space:.
+  call append(0, [" \t text"])
+  let expected = ['.+****** text']
+  call Check_listchars(expected, 1, 13)
+
+  " Test leadtab without tab set in listchars
+  normal ggdG
+  set listchars=leadtab:+*

I don't think leadtab: should be allowed when tab: is not specified. It will complicate many computations.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3628800190@github.com>

Harsh Kapse

unread,
Jan 5, 2026, 8:22:08 PM (7 days ago) Jan 5
to vim/vim, Subscribed

@HarshK97 commented on this pull request.


In src/testdir/test_listchars.vim:

> +  normal ggdG
+  set listchars=tab:>-,leadtab:├─┤
+  call append(0, ["\ttext"])
+  let expected = ['├──────┤text']
+  call Check_listchars(expected, 1, 12)
+
+  " Test leadtab with mixed indentation (spaces + tabs)
+  normal ggdG
+  set listchars=tab:>-,leadtab:+*,space:.
+  call append(0, [" \t text"])
+  let expected = ['.+****** text']
+  call Check_listchars(expected, 1, 13)
+
+  " Test leadtab without tab set in listchars
+  normal ggdG
+  set listchars=leadtab:+*

ok it do make sense, I will update the tests so it dont let leadtab without tab


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3628973451@github.com>

Harsh Kapse

unread,
Jan 9, 2026, 8:38:37 AM (4 days ago) Jan 9
to vim/vim, Push

@HarshK97 pushed 2 commits.

  • d5724cb feat(diff): added 'leadtab' option in listchars
  • 56528d6 test(diff): updated tests for 'leadtab' option


View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/17b63ffa387440011bcde586c53314f4c1d27917/after/56528d6f16ca60893e55f529eb259b02d6271a7a@github.com>

Harsh Kapse

unread,
Jan 9, 2026, 9:23:53 AM (4 days ago) Jan 9
to vim/vim, Push

@HarshK97 pushed 2 commits.

  • 457c8f4 feat(diff): updated styling in drawline.c
  • 1782e53 feat(diff): added guard to not let users use 'leadtab' without 'tab' also set

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/56528d6f16ca60893e55f529eb259b02d6271a7a/after/1782e53bf5204d84586ae04aec42d0b6f78f7850@github.com>

Harsh Kapse

unread,
Jan 9, 2026, 9:33:57 AM (4 days ago) Jan 9
to vim/vim, Push

@HarshK97 pushed 1 commit.

  • 9bc0c89 test(diff): added entries of 'leadtab' in gen_opt_test.vim and test_options.vim

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/1782e53bf5204d84586ae04aec42d0b6f78f7850/after/9bc0c8925d09c58df48a5c8864e8f92ec7a2e33f@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 4:07:07 AM (3 days ago) Jan 10
to vim/vim, Push

@HarshK97 pushed 2 commits.

  • cc20bfd runtime(doc): updated the docs for the new option 'leadtab'
  • de10ef5 test(leadtab): updated the tests

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/9bc0c8925d09c58df48a5c8864e8f92ec7a2e33f/after/de10ef52727c52f59708b9ff6de1cc518fa30ef2@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 5:04:39 AM (3 days ago) Jan 10
to vim/vim, Push

@HarshK97 pushed 1 commit.

  • 7a20188 test(leadtab): updated the tests

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/de10ef52727c52f59708b9ff6de1cc518fa30ef2/after/7a20188bd84073b073fd2a9e53adf7efb68098c2@github.com>

zeertzjq

unread,
Jan 10, 2026, 7:16:50 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@zeertzjq commented on this pull request.


In runtime/doc/options.txt:

> @@ -5797,6 +5797,16 @@ A jump table for the options with a short description can be found at |Q_op|.
 				---+---+--XXX ~
 			Where "XXX" denotes the first non-blank characters in
 			the line.
+							lcs-leadtab
+	  leadtab:c...
+			leadtab:xy[z] Like |lcs-tab|, but only for leading
+			tabs. When omitted, the "tab" setting is used for
⬇️ Suggested change
-			tabs. When omitted, the "tab" setting is used for
+			tabs.  When omitted, the "tab" setting is used for

In src/errors.h:

> +EXTERN char e_leadtab_requires_tab[]
+	INIT(= N_("E1572: Listchars element leadtab requires tab to be specified"));

This should come after E1571.


In runtime/doc/options.txt:

> @@ -5797,6 +5797,16 @@ A jump table for the options with a short description can be found at |Q_op|.
 				---+---+--XXX ~
 			Where "XXX" denotes the first non-blank characters in
 			the line.
+							lcs-leadtab
+	  leadtab:c...
+			leadtab:xy[z] Like |lcs-tab|, but only for leading
+			tabs. When omitted, the "tab" setting is used for
+			leading tabs.
+			The "tab" option must be set for this to work.
⬇️ Suggested change
-			The "tab" option must be set for this to work.
+			|lcs-tab| must also be set for this to work. *E1571*

In src/testdir/util/gen_opt_test.vim:

> @@ -248,9 +248,9 @@ let test_values = {
       \ 'langmap': [['', 'xX', 'aA,bB'], ['xxx']],
       \ 'lispoptions': [['', 'expr:0', 'expr:1'], ['xxx', 'expr:x', 'expr:']],
       \ 'listchars': [['', 'eol:x', 'tab:xy', 'tab:xyz', 'space:x',
-      \		'multispace:xxxy', 'lead:x', 'leadmultispace:xxxy', 'trail:x',
-      \		'extends:x', 'precedes:x', 'conceal:x', 'nbsp:x', 'eol:\\x24',
-      \		'eol:\\u21b5', 'eol:\\U000021b5', 'eol:x,space:y'],
+      \		'multispace:xxxy', 'lead:x', 'tab:xy,leadtab:xyz', 'leadmultispace:xxxy',
+      \		'trail:x', 'extends:x', 'precedes:x', 'conceal:x', 'nbsp:x',
+      \		'eol:\\x24', 'eol:\\u21b5', 'eol:\\U000021b5', 'eol:x,space:y'],
       \		['xxx', 'eol:']],

Add test that leadtab: alone is not allowed.

⬇️ Suggested change
-      \		['xxx', 'eol:']],
+      \		['xxx', 'eol:', 'leadtab:xyz']],

In src/drawline.c:

> @@ -3258,6 +3259,18 @@ win_line(
 		{
 		    int	    tab_len = 0;
 		    long    vcol_adjusted = wlv.vcol; // removed showbreak len
+		    int	    lcs_tab1 = wp->w_lcs_chars.tab1;
+		    int	    lcs_tab2 = wp->w_lcs_chars.tab2;
+		    int	    lcs_tab3 = wp->w_lcs_chars.tab3;
+
+		    // check if leadtab is set in linechars
⬇️ Suggested change
-		    // check if leadtab is set in linechars
+		    // check if leadtab is set in 'listchars'

In src/drawline.c:

> @@ -1660,8 +1660,9 @@ win_line(
 		--trailcol;
 	    trailcol += (colnr_T)(ptr - line);
 	}
-	// find end of leading whitespace
-	if (wp->w_lcs_chars.lead || wp->w_lcs_chars.leadmultispace != NULL)
+	// find end of leading whitespace or tab

I don't think this comment needs to be changed. Whitespace includes tabs.


In src/errors.h:

> +EXTERN char e_leadtab_requires_tab[]
+	INIT(= N_("E1572: Listchars element leadtab requires tab to be specified"));

Also:

⬇️ Suggested change
-EXTERN char e_leadtab_requires_tab[]
-	INIT(= N_("E1572: Listchars element leadtab requires tab to be specified"));
+EXTERN char e_leadtab_requires_tab[]
+	INIT(= N_("E1572: 'listchars' field \"leadtab\" requires \"tab\" to be specified"));


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646750890@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 7:56:14 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@HarshK97 commented on this pull request.


In runtime/doc/options.txt:

> @@ -5797,6 +5797,16 @@ A jump table for the options with a short description can be found at |Q_op|.
 				---+---+--XXX ~
 			Where "XXX" denotes the first non-blank characters in
 			the line.
+							lcs-leadtab
+	  leadtab:c...
+			leadtab:xy[z] Like |lcs-tab|, but only for leading
+			tabs. When omitted, the "tab" setting is used for

Idk what i have to do here? just a space Before 'When'?


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646800837@github.com>

zeertzjq

unread,
Jan 10, 2026, 8:08:00 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@zeertzjq commented on this pull request.


In runtime/doc/options.txt:

> @@ -5797,6 +5797,16 @@ A jump table for the options with a short description can be found at |Q_op|.
 				---+---+--XXX ~
 			Where "XXX" denotes the first non-blank characters in
 			the line.
+							lcs-leadtab
+	  leadtab:c...
+			leadtab:xy[z] Like |lcs-tab|, but only for leading
+			tabs. When omitted, the "tab" setting is used for

See :h help-writing:

Vim help files generally use 2 spaces after a sentence (since they are written


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646814534@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 8:17:42 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@HarshK97 commented on this pull request.


In runtime/doc/options.txt:

> @@ -5797,6 +5797,16 @@ A jump table for the options with a short description can be found at |Q_op|.
 				---+---+--XXX ~
 			Where "XXX" denotes the first non-blank characters in
 			the line.
+							lcs-leadtab
+	  leadtab:c...
+			leadtab:xy[z] Like |lcs-tab|, but only for leading
+			tabs. When omitted, the "tab" setting is used for

oh I get it now. Thanks!


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646830922@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 8:18:44 AM (3 days ago) Jan 10
to vim/vim, Push

@HarshK97 pushed 1 commit.

  • 5c684be applied review suggetions

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/7a20188bd84073b073fd2a9e53adf7efb68098c2/after/5c684be4ef5ccb9fb32aff3446cb980c279e1dc6@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 8:20:24 AM (3 days ago) Jan 10
to vim/vim, Push

@HarshK97 pushed 1 commit.

  • 894231e applied review suggetions

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/5c684be4ef5ccb9fb32aff3446cb980c279e1dc6/after/894231eae418a0a9d0a137c5d5af8715c42ac7f1@github.com>

zeertzjq

unread,
Jan 10, 2026, 8:29:45 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@zeertzjq commented on this pull request.


In runtime/doc/options.txt:

> +	  leadtab:c...
+			leadtab:xy[z] Like |lcs-tab|, but only for leading
+			tabs.  When omitted, the "tab" setting is used for
+			leading tabs.

c... doesn't look right.

⬇️ Suggested change
-	  leadtab:c...
-			leadtab:xy[z] Like |lcs-tab|, but only for leading
-			tabs.  When omitted, the "tab" setting is used for
-			leading tabs.
+	  leadtab:xy[z]	Like |lcs-tab|, but only for leading tabs.  When
+			omitted, the "tab" setting is used for leading tabs.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646851914@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 8:32:44 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@HarshK97 commented on this pull request.


In runtime/doc/options.txt:

> +	  leadtab:c...
+			leadtab:xy[z] Like |lcs-tab|, but only for leading
+			tabs.  When omitted, the "tab" setting is used for
+			leading tabs.

ok, not gonna lie i kinda just tried to copy how leadmultispace was documented that's why it had c..., i will update it


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646854614@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 8:33:38 AM (3 days ago) Jan 10
to vim/vim, Push

@HarshK97 pushed 1 commit.

  • e6816c8 applied review suggetions

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/894231eae418a0a9d0a137c5d5af8715c42ac7f1/after/e6816c8575c1646b9899e860322b89c91f884e06@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 8:35:04 AM (3 days ago) Jan 10
to vim/vim, Push

@HarshK97 pushed 1 commit.

  • 671f148 applied review suggetions

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/e6816c8575c1646b9899e860322b89c91f884e06/after/671f14804c369c587d43ac507438a45868af63e0@github.com>

zeertzjq

unread,
Jan 10, 2026, 8:46:25 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@zeertzjq commented on this pull request.


In runtime/doc/options.txt:

> +			Like |lcs-tab|, but only for leading
+			tabs.  When omitted, the "tab" setting is used for
+			leading tabs.
⬇️ Suggested change
-			Like |lcs-tab|, but only for leading
-			tabs.  When omitted, the "tab" setting is used for
-			leading tabs.
+			Like |lcs-tab|, but only for leading tabs.  When
+			omitted, the "tab" setting is used for leading tabs.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646862718@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 8:47:05 AM (3 days ago) Jan 10
to vim/vim, Push

@HarshK97 pushed 1 commit.

  • ad36c46 applied review suggetions

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/671f14804c369c587d43ac507438a45868af63e0/after/ad36c4666290c996b3f85a07373460b9e8108288@github.com>

zeertzjq

unread,
Jan 10, 2026, 8:52:47 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@zeertzjq commented on this pull request.


In runtime/doc/options.txt:

> @@ -5797,6 +5797,15 @@ A jump table for the options with a short description can be found at |Q_op|.
 				---+---+--XXX ~
 			Where "XXX" denotes the first non-blank characters in
 			the line.
+							*lcs-leadtab*
+	  leadtab:xy[z]
+			Like |lcs-tab|, but only for leading tabs.  When
+			omitted, the "tab" setting is used for leading tabs.
+			|lcs-tab| must also be set for this to work. *E1572*
+			You can combine it with "tab:", for example:
+			`:set listchars=tab:>-,leadtab:\.`

This example is wrong. I guess you mean this?

⬇️ Suggested change
-			`:set listchars=tab:>-,leadtab:\.`
+			`:set listchars=tab:>-,leadtab:.\ `


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646867919@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 8:57:40 AM (3 days ago) Jan 10
to vim/vim, Push

@HarshK97 pushed 1 commit.

  • a60ab81 applied review suggetions

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/ad36c4666290c996b3f85a07373460b9e8108288/after/a60ab8172f73d6cdd958b3b57e9d3a5b9179fd3c@github.com>

zeertzjq

unread,
Jan 10, 2026, 9:12:11 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@zeertzjq commented on this pull request.


In src/drawline.c:

>  #ifdef FEAT_LINEBREAK
 			if (wp->w_p_lbr && wlv.p_extra != NULL
 							&& *wlv.p_extra != NUL)
 			    wlv.c_extra = NUL; // using p_extra from above
 			else
 #endif
-			    wlv.c_extra = wp->w_lcs_chars.tab2;
-			wlv.c_final = wp->w_lcs_chars.tab3;
+			wlv.c_extra = lcs_tab2;

The comes after the else above the #endif, so its indent should be kept.

⬇️ Suggested change
-			wlv.c_extra = lcs_tab2;
+			    wlv.c_extra = lcs_tab2;


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646897006@github.com>

zeertzjq

unread,
Jan 10, 2026, 9:12:38 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@zeertzjq commented on this pull request.


In src/screen.c:

> +    {
+	return e_leadtab_requires_tab;
+    }

Braces not needed here.

⬇️ Suggested change
-    {
-	return e_leadtab_requires_tab;
-    }
+	return e_leadtab_requires_tab;


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646897186@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 9:17:38 AM (3 days ago) Jan 10
to vim/vim, Push

@HarshK97 pushed 1 commit.

  • 6802960 applied review suggetions

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/a60ab8172f73d6cdd958b3b57e9d3a5b9179fd3c/after/6802960b3007f7156144f8f914f3e9cb5fdfb586@github.com>

zeertzjq

unread,
Jan 10, 2026, 9:20:50 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@zeertzjq commented on this pull request.


In src/drawline.c:

> +			    wlv.c_extra = lcs_tab2;
 #endif
⬇️ Suggested change
-			    wlv.c_extra = lcs_tab2;
-#endif
+#endif
+			    wlv.c_extra = lcs_tab2;


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646899697@github.com>

Harsh Kapse

unread,
Jan 10, 2026, 9:24:29 AM (3 days ago) Jan 10
to vim/vim, Push

@HarshK97 pushed 1 commit.

  • 94d41d0 applied review suggetions


View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/6802960b3007f7156144f8f914f3e9cb5fdfb586/after/94d41d05cd21896689e1c016c9c723d8868af1d4@github.com>

zeertzjq

unread,
Jan 10, 2026, 9:27:27 AM (3 days ago) Jan 10
to vim/vim, Subscribed

@zeertzjq approved this pull request.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/review/3646902014@github.com>

Harsh Kapse

unread,
Jan 12, 2026, 3:41:18 AM (21 hours ago) Jan 12
to vim/vim, Push

@HarshK97 pushed 9 commits.

  • a6f0a16 test: added new test for new option 'leadtab'
  • 438aa00 feat(diff): added 'leadtab' option in listchars
  • f424848 test(diff): updated tests for 'leadtab' option
  • 64d255e feat(diff): updated styling in drawline.c
  • 77d80f7 feat(diff): added guard to not let users use 'leadtab' without 'tab' also set
  • fb93b37 test(diff): added entries of 'leadtab' in gen_opt_test.vim and test_options.vim
  • 7a37c66 runtime(doc): updated the docs for the new option 'leadtab'
  • af80c7c test(leadtab): updated the tests
  • 2369214 applied review suggetions


View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19094/before/94d41d05cd21896689e1c016c9c723d8868af1d4/after/2369214339ab7193252b956b3213eab3d7b5a45d@github.com>

Reply all
Reply to author
Forward
0 new messages