9

I wanted to write this:

A = mapping[0]
B = mapping[1]
C = mapping[2]
D = mapping[3]
E = mapping[4]
F = mapping[5]
G = mapping[6]
H = mapping[7]
I = mapping[8]
J = mapping[9]
K = mapping[10]
L = mapping[11]
M = mapping[12]
N = mapping[13]
O = mapping[14]
P = mapping[15]
Q = mapping[16]
R = mapping[17]
S = mapping[18]
T = mapping[19]
U = mapping[20]
V = mapping[21]
W = mapping[22]
X = mapping[23]
Y = mapping[24]
Z = mapping[25]

I ended up using LibreCalc, putting the different parts in different cells, adding the letters and numbers, concatenating the results and pasting the lot back into Vim.

I appreciate that what I wanted to write is awful code. I'm studying Python at the moment and have been trying to avoid going to find information myself that I know will be covered later in the course I'm following (http://interactivepython.org/).

The quickest way I knew of to do this in vim was to type something like

A = mapping[0] <ESC> hh <CTRL>+<V> BBh y $ o B <ESC> y 1] <CR>

I know vim is very powerful (I've been using it for a couple of weeks, am really enjoying it).

Would it have been possible to write what I wanted to with some vim command?

5 Answers 5

12

While it can be done with scripting, if you have a very recent version of Vim (e.g. the one in Arch Linux), you can use g Ctrl-a to increment a visual block. In your case:

  1. Write the original line: A = mapping[0] Esc
  2. Yank line and put 25 copies of it below: yy25p
  3. Visually select the column containing the 0 char (block selection, using Ctrl-v), excluding the 0 from the 1st line (so you end up with a column containing the last 25 zeroes), then increment them with g Ctrl-a.
  4. Apply the same method for the column containing A.

(Note: As comments show, one needs to add alpha to the nrformats options, in order to be able to increment letters, e.g.: set nrformats+=alpha.My vimrc has: set nrformats=hex,alpha, thus disabling octal and binary increment, which I don't use)

9
  • yy isn't working for me. I can see on the cheatsheet I've printed out from www.vimcheatsheet.com that this is a very standard command. vim --version returns this: pastebin.com/DcFxZh1S. I'll have to investigate why it's not working for me... (I've tried in visual command and insert modes). Also when I paste, it all appears on the same line. However I've tried out g Ctrl-a and it does exactly what I wanted, thank you :) Commented Feb 12, 2016 at 16:52
  • 1
    :verbose map y should show you what mappings that start with y you have, and where they were set. But you have to use yy in normal mode.
    – VanLaser
    Commented Feb 12, 2016 at 16:55
  • 1
    Fixed :D asciinema.org/a/2zqavz00sbzvumxwg742h3ozi Commented Feb 12, 2016 at 17:26
  • 1
    What version of vim will increment A to B with the Ctrl-a action? Mine definitely does not, and I'm on 7.4 1-1202.
    – Cory Klein
    Commented Feb 12, 2016 at 23:37
  • 4
    @CoryKlein Try typing :set nrformats+=alpha. It will add the value alpha to the option 'nrformats' and should allow Ctrl-a to "increment" alphabetical characters. If you like this behavior, you could add it to your vimrc. Otherwise, you could add it to the option with the operator += and remove it afterwards with the operator -= (:set nrformats-=alpha).
    – saginaw
    Commented Feb 13, 2016 at 9:27
6

I prefer the visual increment solution that @VanLaser used (See :h v_CTRL-A). However I will show this can be done via macro as well.

Start with:

A = mapping[0]

Record the following keypresses into a macro of your choice (e.g q):

yyp:set nrformats+=alpha<cr><c-a>:set nrformats-=alpha<c-a>

This will duplicate the line and then increment the first character (e.g. A) and then increment the number portion. Run this macro 24 times and you are done, e.g. 24@q.

  • qq - start recording into register q
  • yyp - duplicate the line
  • :set nrformats+=alpha<cr> - 'nrformats does not have alpha by default
  • <c-a> - With alpha we can now increment letters
  • :set nrformats-=alpha<cr> - remove alpha from 'nrformats'
  • <c-a> - increment the next number
  • q - stop recording
  • 24@q - replay macro in register q 24 times

For more help see:

:h q
:h @
:h yy
:h p
:h 'nrformats'
:h :set
:h CTRL-A
:h v_CTRL-A
2
  • Nice one :) 25?
    – VanLaser
    Commented Feb 12, 2016 at 17:53
  • 1
    @VanLaser: 1 (starting line) + 1 (recording the macro) + 24 = 26. Commented Feb 12, 2016 at 17:56
4

Fine answers already provided, I wouldn't have thought to go about it as nicely. I would have typed out all the letters on a single line and then introduced text and line break with an expression substitution (using line number for incremental number), something like

iABCDEFGHIJKLMNOPQRSTUVXYZ<Esc>:s/./\=submatch(0)." = mapping[".line('.')."]\n"/g
1
  • very cool ! (+1)
    – JJoao
    Commented Feb 15, 2016 at 18:29
2

Almost always when doing something like this, I choose to use :substitute over macros. Especially the capability to evaluate expression in replacement when starting with \= makes it often possible (see :h sub-replace-special).

Once you have empty lines in place (25i<Enter><Esc>), you can use command

:1,26s/^/\=nr2char(line('.')+64) . ' = mapping[' . (line('.')-1) . ']'

the necessary sequences are generated using current line ('.' argument) number returned by function line(), and using nr2char() to convert decimal numbers to ASCII equivalents (65 = A). Necessary strings are concatenated using .

1

You can always try to use the operating system...

:r ! perl -E 'for(A..Z){say "$_ = mapping[", ord($_)-64 ,"]"}'
1
  • 1
    Perl isn't in the operating system. Commented Feb 16, 2016 at 20:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.