Unexpected indentation with :left

21 views
Skip to first unread message

Tim Chase

unread,
Feb 25, 2025, 7:10:46 PMFeb 25
to Vim Users
Reading the help for :left, it says:

Sets the indent in the lines to [indent] (default 0).

However, it seems to do that indenting with N spaces rather than
respecting 'shiftwidth' and 'expandtab' settings.

Or do I just need to roll an independent solution? It's not as simple
as using

:{range}>>>>

because `:left` first removes all left-indentation before indenting.

The best I've been able to come up with is

:{range}le | {range}>>>>

With cpo-star in the default and using a linewise-visual-range, that
simplifies a bit to

:'<,'>le|*>>>>

While kinda-opaque, it does the Right Thing(tm)

Is there a way to get the indent-count parameter of `:left` to behave
like using the > motion (which respects 'shiftwidth' and 'expandtab')?

-tim

brought to my attention by this Reddit thread:
https://www.reddit.com/r/vim/comments/1ixcyt5/put_all_lines_in_visual_bloc_on_the_same_indent/

--





D. Ben Knoble

unread,
Feb 26, 2025, 1:31:04 PMFeb 26
to vim_use
On Tuesday, February 25, 2025 at 7:10:46 PM UTC-5 Tim Chase wrote:
Reading the help for :left, it says:

Sets the indent in the lines to [indent] (default 0).

However, it seems to do that indenting with N spaces rather than
respecting 'shiftwidth' and 'expandtab' settings.
[snip]

Is there a way to get the indent-count parameter of `:left` to behave
like using the > motion (which respects 'shiftwidth' and 'expandtab')?

-tim

brought to my attention by this Reddit thread:
https://www.reddit.com/r/vim/comments/1ixcyt5/put_all_lines_in_visual_bloc_on_the_same_indent/ 

It took me a while to figure out what the question was, but I think you could something like this:

    V<motions>:left N | *retab!

You'll probably have to adjust N above if you want to use tabs (so 3 indents with tab stops of 8 would be 24; I'm not sure if tabstop or softtabstop is what matters here).

Tim Chase

unread,
Feb 26, 2025, 7:45:07 PMFeb 26
to vim...@googlegroups.com
On 2025-02-26 10:31, D. Ben Knoble wrote:
> On Tuesday, February 25, 2025 at 7:10:46???PM UTC-5 Tim Chase wrote:
>>> Sets the indent in the lines to [indent] (default 0).
>>
>> indenting with N spaces rather than respecting 'shiftwidth' and 'expandtab'
>> [snip]
>> Is there a way to get the indent-count parameter of `:left` to behave
>> like using the > motion (which respects 'shiftwidth' and 'expandtab')?
>
> It took me a while to figure out what the question was, but I think you
> could something like this:
>
> V<motions>:left N | *retab!

The gist of my question/hope was wanting to get the N in

:left N

to prepend N *indents* (using N tabs if 'noet' and N*shiftwidth if 'et'
is set)

As it currently stands, with 'et' set, I get N spaces, not N
'shiftwidth', and if I have 'noet' set, I get int(N/tabstop) tabs
followed by mod(N, tabstop) spaces. E.g.

:set ts=8 sw=4

with

:set et
:'<,'>left 10

puts 10 spaces at the beginning of each trimmed line.

And without 'et' set:

:set noet
:'<,'>left 10

gives me one tab (8-worth) followed by 2 spaces.

Neither gives me 10 tabstops or 10 shiftwidths which is what I'd
expected.

-tim





Salman Halim

unread,
Feb 27, 2025, 12:30:33 AMFeb 27
to vim...@googlegroups.com
On Wed, Feb 26, 2025 at 7:44 PM Tim Chase <v...@tim.thechases.com> wrote:

The gist of my question/hope was wanting to get the N in

  :left N

to prepend N *indents* (using N tabs if 'noet' and N*shiftwidth if 'et'
is set)

As it currently stands, with 'et' set, I get N spaces, not N
'shiftwidth', and if I have 'noet' set, I get int(N/tabstop) tabs
followed by mod(N, tabstop) spaces.  E.g.

  :set ts=8 sw=4

with

  :set et
  :'<,'>left 10

puts 10 spaces at the beginning of each trimmed line.

And without 'et' set:

  :set noet
  :'<,'>left 10

gives me one tab (8-worth) followed by 2 spaces.

Neither gives me 10 tabstops or 10 shiftwidths which is what I'd
expected.

-tim

This seemed like it might be useful, so I wrote it:

# Different from regular :left in that the indent is taken to be a multiple of the &shiftwidth setting and not just a number of spaces.
export def g:LeftIndentLines( line1: number, line2: number, indent: string )
  var indentSize: number = indent == '' ? 0 : str2nr( indent )

  if ( indentSize > 0 )
    # Replace existing indent with the number of spaces required
    execute $':{line1},{line2}s/^\s*/{repeat(" ", indentSize * &shiftwidth)}'

    # Use retab to insert tabs if tab-based indentation is enabled3
    execute $':{line1},{line2}retab!'
  else
    execute $':{line1},{line2}left'
  endif
enddef
com! -nargs=? -range Left g:LeftIndentLines( <line1>, <line2>, <q-args> )

Call just like the regular :left, except with :Left. Takes a range and an indent (default is 0, just like regular :left). The only difference between this and the built in version is that the number passed to this is seen as a multiple of the shiftwidth instead of an absolute number of spaces. It will also call `retab!` to convert indents to tabs as needed.
Reply all
Reply to author
Forward
0 new messages