22

Is there a simple way to delete all white spaces on a line until the first character on that line is met?

An example:

           #a list of comments
                # item 1
                # item 2

And I would like it to become:

#a list of comments
# item 1
# item 2

I know how to delete n characters (ex: 8x) and to repeat the command (.), but how could I do without having to input the number of white spaces?

Dom
  • 3,314
  • 5
  • 21
  • 38
calocedrus
  • 357
  • 1
  • 2
  • 6

10 Answers10

23

You can either visually select the lines and use

:'<,'>s/^\s*//

Which means 'substitute all of the whitespaces following the first column of the line by nothing'

Or go on the first line, use

  • 0 to go on the first column
  • d^ to delete until the first character of the line

And then go to the next line and use the dot command

statox
  • 49,782
  • 19
  • 148
  • 225
  • Your first method is a bit too involved for me at this point :). A note to those using an international keyboard (ex US international), don't forget to press the space bar for d^ after the ^! – calocedrus Jun 20 '17 at 07:58
  • 1
    @calocedrus, :h :substitute is really the way to go in your case. Once you'll master :substitute, you'll have a good grasp of a key feature of the major sed *nix command. – Luc Hermitte Jun 20 '17 at 12:41
  • 1
    Many good answers, and they worked for me, difficult to select one vs others! At this point (~ 1 month after I asked), @statox's answer seems to have received most votes so I'll select it as the answer, decision also supported by Luc's advice. – calocedrus Jul 18 '17 at 01:35
20

This works for me.

esc : to enter vim command mode

%s/^\s*//g

Meaning:

%s/<REGEX TO REPLACE>/<REPLACEMENT TEXT>/ for string substitution

g for global (all lines)

Regex matching leading whitespace is ^\s*

Voila

Ryan Mahaffey
  • 301
  • 2
  • 2
19

In addition to statox's methods, you can:

  • Position the cursor at the beginning of the leading whitespace and type dw
  • Position the cursor anywhere in the leading whitespace and type diw
  • Position the cursor at the first non-space character of the line and type d0
  • Visually select all the lines you want to move left, e.g., by typing V on the first line and moving the cursor to the last line, then executing :left

Update

What I actually usually do in such cases is:

  • Visually select all the lines as above, type < to move them left by one shiftwidth, then type . until they're shifted all the way to the left margin.
garyjohn
  • 6,309
  • 20
  • 21
8

Deleting a word at the beginning of the line will do the trick:

dw

If you want to repeat that for every line in the file that begins with whitespace:

:g/^ /norm dw
mkm
  • 181
  • 1
  • this only works if no line starts without leading spaces – Naumann Jun 21 '17 at 10:14
  • yes. the purpose of the match on /^ / is to apply the dw command only on lines that start with a whitespace – mkm Jun 21 '17 at 15:26
  • Could you explain what this command does? I know this is a regex match, what's the difference between :g/ and :s/? And what does the '/norm dw' do? – Harv Jun 22 '17 at 19:29
  • g executes a command on every line that matches a given regexp. In this case it executes the dw command in normal mode (hence the norm). If you don't specifiy norm it will interpret the commands as ex commands. s instead substitutes. g/re/p executes the p (print) ex command for every line matching a regexp. Here's where the name of the grep command comes from. – mkm Jun 25 '17 at 17:20
  • This is awesome. I've worked in vi for decades and didn't know this. – James Gawron Dec 16 '20 at 18:59
7

A few variations on a theme:

Method(s) that will work in vi:

  • Go to the first line that you want to manipulate.
  • Count the lines that you want to manipulate — let’s say there are 17 of them.  Type 17<<.  This will shift each of the following seventeen lines left by one shiftwidth (normally eight characters; i.e., one tab).  Assuming you still have lines with leading spaces, type . to repeat the shift command.  Type . repeatedly until all the spaces are gone.
  • If you want to remove the leading spaces from all lines to the end of the buffer, use <G and then . repeatedly.
  • Any common technique for identifying the end of the range will work similarly.  For example, with the text in your question, you could use </2/ (and then . repeatedly).

Method that will work only in vim:

  • Go to the first line that you want to manipulate.
  • Type V or Ctrl+V to go into visual selection mode (mark the beginning of the range).
  • Move to the end of the range.
  • Type 9<.  This will shift the selected lines left by nine shiftwidths.  As this will typically be 72 characters (9×8), there’s a good chance that that will do the job.  If you still have lines with leading spaces, type . to repeat the shift command (i.e., another72 characters).
  • Or, if you know that you have lines with more than 72 leading spaces (or nine tabs), just use 99<.
3

Using vi you should be able to type

<Esc>:%left<CR>

to left-align the whole file.

D. Ben Knoble
  • 26,070
  • 3
  • 29
  • 65
  • 3
    Welcome to [vi.se]! I've edited your post with a little formatting (and expanded what I understood to be the left command). It might be worth adding some explanation with an [edit]—in particular, what if someone doesn't want to :left the whole file? – D. Ben Knoble Mar 15 '21 at 13:42
2

Here is a single command to do it (starting in Normal mode, on the line you want to modify):

I<c-w><esc>

This switches to Insert mode and positions the cursor on the first non-whitespace character. Ctrl-w will then delete to the beginning of the line.

This can then be . repeated on any other line, from any column.

Joshua
  • 121
  • 2
1

In normal mode i use d/\w<CR> I often find my self using / or ? to make big surgical jumps/deletions/selections

lima jose
  • 11
  • 2
0

I've written a function for this (add this in your .vimrc) :

function RTS()
"Remove trailing spaces in every line"
    let nl = line('$')
    exe ":normal gg"
    for i in range(1, nl)
        exe ":normal 0d^j"
    endfor
endfunction

then call it whenever you want to use it:

:call RTS()
LRDPRDX
  • 103
  • 2
  • This looks pretty inefficient, and I don't see the need for a function here. You could do something similar with :global/./normal! 0d^ (no :execute needed), or even :%substitute/^\s*//, or :%left, but these are already covered. – D. Ben Knoble Jan 25 '22 at 14:27
  • I suppose you're right about inefficiency, but it's just a solution that came to my mind and was not covered here. – LRDPRDX Jan 26 '22 at 05:50
0

Not answering for this specific task, but I personally prefer df<char> and dt<char> or with c operator.

Once you are familiar with it, it deals with most cases more consistently by deleting from your cursor position to a specified character (f for inclusive, t for exclusive) at the cost of only one more keystroke than the optimal d^ and involving no complex mind calculation (IMHO, you'd better avoid F and T for backward search which do not include the character under cursor, this places more burden on memory and mind).

e.g. some of my often used commands: dt) df, cf etc. You only need to count characters or resort to Visual Mode (also remember using f or t to move cursor!) when there are multiple occurrences of the character, which seems to be a rare case for me. Also often we want to delete to a delimiter, such as , ; , which stands out clearly in the text, making obviously the argument of the command and even aiding quickly counting occurrences.

Masquue
  • 81
  • 4