Vim Tips Wiki
Advertisement

Duplicate tip

This tip is very similar to the following:

These tips need to be merged – see the merge guidelines.

Tip 65 Printable Monobook Previous Next

created April 5, 2001 · complexity basic · author Devin Weaver · version 5.7


The :set number displays line numbers. This tip, however, inserts the line numbers into the file.

On Unix, you can insert line numbers with a command like:

cat -n file > new_file

In Vim, you can use the global command to insert line numbers:

:g/^/exec "s/^/".strpart(line(".")."    ", 0, 4)

This runs the exec command on every line that matches /^/ (matches every line).
The exec command takes a string and executes it as if it were typed in.

line(".")."    "           number of the current line plus four spaces
strpart("123 ", 0, 4)      first four characters ("123 ")
"s/^/123 "                 substitute the beginning of the line with "123 "

See Insert line numbers with a Perl filter.

Comments

In Vim6, this is even easier. For more information, :help :s and look at the line about \=

:%s/^/\=strpart(line('.')." ",0,&ts)

In visual mode, type:

:s/^/\\=strpart((line('.')-line("'<")+1).' ',0,5)

Then you will get visual selection numbered as expected.


In Vim, call this function:

" Insert line numbers in front of lines.
function! Listing()
  let i=line("$")
  let pre = ' '
  while (i > 0)
    if match(i, '^9*$') == 0
      let pre = pre . '0'
    endif
    call setline(i, pre . i . "\t" . getline(i))
    let i=i-1
  endwhile
endfunction

To number a selection (or even the whole document), piping through grep can be much faster and usually offers good results:

:'<,'>!grep -n -h ^

This numbers (-n) the lines it's piped through and strips the file-name headers (-h) that grep puts in. You can even select certain lines to number by changing the pattern to match (^ is the beginning of the line, but it could be a more complex pattern).

It's a bit faster than the other suggestions for a quick down-n-dirty numbering of lines. Small variations I've noted include:

  • The other versions here have a fixed-width column--this could be a good thing or a bad thing.
  • This one (at least with the version of grep I used) places a colon after the line numbers, which again could be good or bad.
  • This does need grep to be available.

If you have the version with Python scripting, you can use the following:

:py << EOF
from vim import *
cb = current.buffer
for i in range(len(cb)):
  cb[i] = str(i) + ' ' + cb[i]
EOF

Also try this:

:%! nl -ba

If you have Perl support, just use these two commands:

:perl $linetoinsert=1;
:perldo if($_ =~ m/^[A-Z]/){ $_="$linetoinsert. $_"; $linetoinsert++;}

This will make sure it adds the line number only if the line starts with a capital letter. You can customize the regexp to handle white spaces too.


Since you had to type two commands to do this, I thought it would be better to add them into a single function that you could call. However, I couldn't get the line1,line2perldo ... statement to work inside a Vim function. I don't know why. But here is another alternative

" The -range option tells that our command takes a line range and puts them into <line1> and <line2>
:command! -range InsertLineNums call InsertLineNumbers(<line1>,<line2>)
function InsertLineNumbers(l1, l2)
  let ln1 = a:l1
  let ln2 = a:l2
  let linetoinsert = 1
  while ln1 <= ln2
    let currLine = getline(ln1)
    if currLine =~ '^[A-Z]'
      let newLine = linetoinsert.". ".currLine
      let linetoinsert = linetoinsert + 1
    else
      let newLine = " ".currLine
    endif
    call setline(ln1, newLine)
    let ln1=ln1+1
  endwhile
endfunction

If you want insert line numbers like "000103" , you can use:

:%s/^/\=substitute(printf("%4d",line("."))," ","0","g")

Advertisement