1

By outside, I want solutions that does not use Vim's scripting hacks but try to reuse certain basic *ix tools. Inside Vim stuff asks for solutions to get the column-increment with inside stuff such as scripting.

1           1 
1           2 
1           3 
1   --->    4
1           5
1           6
.           .
.           .

Vim has a script that does column-vise incrementing, VisIncr. It has gathered about 50/50 ups and down, perhaps tasting a bit reinventing-the-wheel. How do you column-increment stuff in Vim without using such script? Then the other question is, how do you column-increment stuff without/outside Vim?

Most elegant, reusable and preferably-small wins the race!

ib.
  • 27,830
  • 11
  • 80
  • 100
hhh
  • 50,788
  • 62
  • 179
  • 282
  • The answer depends on the scope of the operation: Whether this column are the only content in a file? Or is it a paragraph, or a an arbitrary range of lines? Also, does those lines originally contain some numbers (like `1` in the above example) or additional text (or both)? Is it necessary to insert numbers or modify existing? – ib. Mar 24 '12 at 04:38
  • Could you please state exactly what task should an answer solve? What specific requirements do you have in mind? Would you like the linked script (or a particular piece of its functionality; specify it then) to be re-implemented from scratch in an answer? – ib. Mar 24 '12 at 10:03
  • The function I have proposed just follows the behavior of the reference script (including usage of column-wise visual selection), since you *still* refuse to formulate *exactly* what behavior do you want (and ignore my clarification questions). – ib. Mar 29 '12 at 02:17
  • Please move extended discussions to [chat]. – Tim Post Mar 29 '12 at 12:37

3 Answers3

3

I don't see a need for a script, a simple macro would do

 "a   yyp^Ayy

then play it, or map to play it.

Of course, there is always the possibility that I misunderstood the question entirely...

Rook
  • 60,248
  • 49
  • 165
  • 242
  • @hhh - No, only the second part is part of the macro itself. The first part is just due to the fact that I recorded it in macro named "a". So basically it is, yank the line, paste it below, increase by one, yank it again. – Rook Mar 24 '12 at 10:10
  • Improve it a little bit. In the first line, input "1". Record a macro by: `qayyp^Aq`. Play it 5 times: `5@a`. – Hong Jun 19 '14 at 02:41
3

The optimal choice of a technique highly depends on the actual circumstances of the transformation. There are at least two points variations affecting implementation:

  1. Whether the lines to operate on are the only ones in a file? If not, is the range of lines defined by context (i.e. it separated by blank lines, like a paragraph) or is it arbitrary and should be specified by user?

  2. Are those lines already contain numbers that should be changed or is it necessary to insert new ones leaving the text on the lines in tact?

Since there is no information to answer these questions, below we will try to construct a flexible solution.

A general solution is a substitution operating on the beginnings of the lines in the range specified by the user. Visual mode is probably the simplest way of selecting an arbitrary range of lines, so we assume here that boundaries of the range are defined by the visual selection.

:'<,'>s/^\d\+/\=line(".")-line("''")+1/

If it is necessary to number every line in a buffer, the command can be simplified as follows.

:%s/^\d\+/\=line('.')/

In any case, if the number should be merely inserted at the beginnings of the lines (without modifying the ones that already exist), one can change the pattern from ^\d\+ to ^, and optionally add a separator:

:'<,'>s/^\d\+/\=(line(".")-line("''")+1).' '/

or

:%s/^/\=line('.').' '/

respectively.

For a solution based on command-line tools, one can consider using stream editors like Sed or text extraction and reporting tools like AWK.

To number each of the lines in a file using Sed, run the commands

$ sed = filename | sed 'N;s/\n/ /'

In order to do the same in AWK, use the command

$ awk '{print NR " " $0}' filename

which could be easily modfied to limit numbering to a particular range of lines satisfying a certain condition. For example, the following command numbers the lines two through eight.

$ awk '{print (2<=NR && NR<=8 ? ++n " " : "") $0}' filename

Having an interest in how commands similar to those from the script linked in the question statement are implemented, one can use the following command as a reference.

vnoremap <leader>i :call EnumVisualBlock()<cr>
function! EnumVisualBlock() range
    if visualmode() != "\<c-v>"
        return
    endif
    let [l, r] = [virtcol("'<"), virtcol("'>")]
    let [l, r] = [min([l, r]), max([l, r])]
    let start = matchstr(getline("'<"), '^\d\+', col("'<")-1)
    let off = start - line("'<")
    let w = max(map([start, line("'>") + off], 'len("".v:val)'))
    exe "'<,'>" 's/\%'.l.'v.*\%<'.(r+1).'v./'.
    \   '\=printf("%'.w.'d",line(".")+off).repeat(" ",r-l+1-w)'
endfunction
ib.
  • 27,830
  • 11
  • 80
  • 100
  • For a more general technique implementing a counter-based substitution in Vim, see my [answer](http://stackoverflow.com/a/8074421/254635) to the question "[Using Vim, how do you use a variable to store count of patterns found?](http://stackoverflow.com/q/8073780/254635)". – ib. Mar 24 '12 at 06:11
  • @hhh: I have taken a look at the script linked in the question statement. However, that code does not state a question by itself. Are you asking to propose an alternative implementation of that script? Please, elaborate on what exactly an ideal solution should do (or what functionality of the said script it should mimic): All requirements for possible solution should be clearly stated in the question. – ib. Mar 24 '12 at 09:59
  • @hhh: What do you mean? Why don't you answer any of clarification questions? To get help, please, describe what you want to achieve. (By the way, take a look at the update of the answer. Maybe, it is close to what you are trying to implement.) – ib. Mar 24 '12 at 11:04
  • @hhh: What do you what to achieve then? There is still no more or less specific statement of the problem to be solved. (On what kind of input and user actions should a solution work, and what output should it produce.) Trying to read your mind, I have implemented an example command that mimics one of those from the aforementioned script. Have you seen it in the latest update of the answer? – ib. Mar 24 '12 at 14:49
  • @hhh: Similarly to the way you use the `:I` command from the original script. Select a column-wise block in Visual mode, then type the mapping issuing the transformation: your leader key (backslash by default) followed by `i`. – ib. Mar 26 '12 at 00:59
1

If you want change 1 1 1 1 ... to 1 2 3 4 .... (Those numbers should be on different lines.)

:let i=1 | g/1/s//\=i/g | let i+=1

If some of 1 1 1 1 ... are in the same line:

:let g:i = 0

:func! Inc()
:    let g:i+=1
:    return g:i
:endfun

:%s/1/\=Inc()/g
kev
  • 155,172
  • 47
  • 273
  • 272