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?

muru
  • 24,838
  • 8
  • 82
  • 143

5 Answers5

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)

VanLaser
  • 9,700
  • 2
  • 24
  • 34
  • 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: http://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
  • That returns: n y *@:call setreg(v:register, 35_recall()) Last set from ~/.vim/bundle/vim-fugitive/plugin/fugitive.vim I'm not using fugitive yet so I'll remove it – Duncan Betts Feb 12 '16 at 16:56
  • That is OK (no custom yy). But make sure you are in normal mode (that's why I put an Esc at the end of item 1) – VanLaser Feb 12 '16 at 16:58
  • I appreciated the Esc :). I tried it initially in normal mode. There must be something wrong with my vim installation. I think Rod Howard was having the same issue, I'll re-install as he suggests. System clipboard integration hasn't been working anyway and I need +python3 so it was on my todo. g Ctrl-a was what I needed, thanks again :) – Duncan Betts Feb 12 '16 at 17:06
  • You're welcome and good luck with fixing it :) – VanLaser Feb 12 '16 at 17:07
  • 1
    Fixed :D https://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 09: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
Peter Rincker
  • 15,854
  • 1
  • 36
  • 45
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
jjaderberg
  • 3,489
  • 1
  • 14
  • 19
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 .

Sakari Cajanus
  • 978
  • 4
  • 5
1

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

:r ! perl -E 'for(A..Z){say "$_ = mapping[", ord($_)-64 ,"]"}'
JJoao
  • 561
  • 4
  • 9