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?


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)

| improve this answer | |
  • 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 :) – Duncan Betts Feb 12 '16 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 Feb 12 '16 at 16:55
  • 1
    Fixed :D asciinema.org/a/2zqavz00sbzvumxwg742h3ozi – Duncan Betts Feb 12 '16 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 Feb 12 '16 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 Feb 13 '16 at 9:27

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 v_CTRL-A
| improve this answer | |
  • Nice one :) 25? – VanLaser Feb 12 '16 at 17:53
  • 1
    @VanLaser: 1 (starting line) + 1 (recording the macro) + 24 = 26. – Peter Rincker Feb 12 '16 at 17:56

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
| improve this answer | |
  • very cool ! (+1) – JJoao Feb 15 '16 at 18:29

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 .

| improve this answer | |

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

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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