1

I write using LaTeX a lot for scientific writing. I often need to modify some text that includes numbers and units like:

4.2 cm

into:

\SI{4.2}{cm}

to be properly typeset by LaTeX. Of course, the exact number and unit can change.

I would like to know a "magic" command I can do that—when 4.2 cm is highlighted in visual mode—will change to the \SI{4.2}{cm}.

What is the magic here?

To make this particularly useful, I'd like to have the substitution take place, but leave the curser at the beginning of the units with the units visually selected. I have to do additional formatting of the units that can't be done automatically with a simple mapping; I have to touch it up at the end.

1

You could try the following to use F1 to call your magic function:

vmap <F1> c<C-R>=substitute(@", '\v(\S+)\s+(\S+)', '\\SI{\1}{\2}', '')<CR><ESC>

Relevant documentation:


Ideas:

If you always have a number followed by a unit, you could avoid the visual selection by placing the cursor on the number:

nmap <F1> c2aW<C-R>=substitute(@", '\v(\S+)\s+(\S+)', '\\SI{\1}{\2}', '')<CR><ESC>

And if you have a list of known units, you could use a regular :s to replace all the occurences:

nmap <F2> :%s/\v\C(\S+)\s+(km<bar>m<bar>cm<bar>mm)>/\\SI{\1}{\2}/gc<CR>

(in this case you could tune the regular expression - e.g: checking for a number with or without decimal separator instead of selecting non-space characters before the units)


Edit:

1) I've tried changing the command from F1 to CTRL-s by using , but the mapping no longer works.

I've tried in gVim and it worked fine. I guess you are using Vim in terminal, where it is very likely it won't work. Check the following FAQs for more info:

2) Is it possible to—after the substitution is done—to leave the curser at the beginning of the units (and have the units visually selected)? I've updated my question to reflect 2).

You just have to appending the commands to that mapping as needed. In this case:

vmap <F1> c<C-R>=substitute(@", '\v(\S+)\s+(\S+)', '\\SI{\1}{\2}', '')<CR><ESC>vb
  • This is great! I've got two commands, one for visual mode and one for normal mode. I have just two questions: 1) I've tried changing the command from F1 to CTRL-s by using <C-s>, but the mapping no longer works. 2) Is it possible to—after the substitution is done—to leave the curser at the beginning of the units (and have the units visually selected)? I've updated my question to reflect 2). – jlconlin Apr 19 '18 at 21:25
  • @jlconlin please check the edit. – mMontu Apr 20 '18 at 12:10
  • This works great and is fast. The reason I couldn't do <C-s> was that tmux was capturing it before ViM could. – jlconlin Apr 20 '18 at 14:17
1

The first answer is perfectly fine but I think it's worth mentioning use of a macro with Normal mode commands as an alternative. One Normal mode command sequence to do the formatting and leave the units visually selected is:

i\SI{<Esc>f s}{<Esc>Ea}<Esc>2T{vt}

Put the cursor on the first character of the units before executing this. Here <Esc> means hit the Esc key.

To record it as a macro in register "q" first enter qq and end the sequence with q. Then you can put the cursor on an occurrence and do @q to rerun.

You'll surely want to make this reusable. You could save the macro in your vimrc...

let @q="i\\SI{\<Esc>f s}{\<Esc>Ea}\<Esc>2T{vt}"

Here <Esc> is literally those five characters, starting with <. Don't forget the backslash that precedes these and note the double quotes that surround everything. Even easier: copy/paste the whole line from here to your vimrc.

But at this point it probably makes more sense to put the command sequence in a mapping:

nnoremap <F1> i\SI{<Esc>f s}{<Esc>Ea}<Esc>2T{vt}

No escaping of <Esc> or \ needed here.

Update: Here's a mapping with an improved version of the command sequence:

nnoremap <F1> i\SI{<C-O>W<BS>}{<C-O>E<Right>}<Esc>2T{vt}

This eliminates two of the three <Esc> by using ctrl-o. That allows the whole thing to be undone with a single u. (And, as a positive side effect, it may also seem to run faster if you are on a slow machine.)

  • This works like the accepted answer does, but this takes about 2 seconds to complete while the other answer virtually instantaneous. – jlconlin Apr 20 '18 at 14:17
  • @jlconlin That's not normal at all. It should be near instantaneous as well...and is for me. This is with macro or the mapping? Or both? If you run the command sequence manually does any one part seem to take longer than expected? – B Layer Apr 20 '18 at 20:07
  • See the update to my answer. The new version is likely faster though that may be noticeable only on a slow machine (don't know if that's what you have). Note, though, that in all cases I'm using run-of-the-mill Vim commands so if you're seeing 2 second run times I'm guessing one of these applies to you: very old hardware, interference from a third-party plugin, or use of complex Vim configuration (e.g. resource-intensive autocommands); any of which may cause other problems down the line. – B Layer Apr 20 '18 at 21:17

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.