4

Sometimes, such as when transcribing FORTRAN code, I find it useful to enter uppercase letters without holding down the Shift key.

However, enabling Caps Lock is a problem in command mode. Here is my (admittedly inelegant) workaround:

function! AllCaps()
    inoremap a A
    inoremap b B
    inoremap c C
    inoremap d D
    inoremap e E
    inoremap f F
    inoremap g G
    inoremap h H
    inoremap i I
    inoremap j J
    inoremap k K
    inoremap l L
    inoremap m M
    inoremap n N
    inoremap o O
    inoremap p P
    inoremap q Q
    inoremap r R
    inoremap s S
    inoremap t T
    inoremap u U
    inoremap v V
    inoremap w W
    inoremap x X
    inoremap y Y
    inoremap z Z
endfunction

command! AllCaps call AllCaps()

I have an similar command called NoAllCaps that maps them back to normal. It does the job, but it's not pretty.

Is there a better way?

1
  • Have you looked at the Visual Foxpro syntax file, vfp.vim? There's a function or two in there that upper cases keywords. I don't understand them well enough to be able to modify them to work for you.
    – Herb
    Aug 15, 2017 at 22:04

3 Answers 3

3

This isn't as concise as my earlier solution (see below) or statox's answer, but it's much cleaner than the former and has the advantage over the latter in that it uppercases individual letters as you type:

function! AllCaps()
  augroup all_caps
    autocmd!
    autocmd InsertCharPre * call <sid>Capitalise()
  augroup END
endfunction

function! NoAllCaps()
  autocmd! all_caps
endfunction

function! s:Capitalise()
  let ascii_number = char2nr(v:char)
  if 97 <= ascii_number && ascii_number <= 122
    let v:char = nr2char(ascii_number - 32)
  endif
endfunction

The AllCaps() function sets up an autocommand to intercept keypresses during insert mode.

The s:Capitalise() function upper cases each individual keypress if it's a lower case letter.

The NoAllCaps() function simply removes the autocommand.

Older Solution

This is a more concise version of your existing solution that creates the maps programmatically in a loop.

function! AllCaps()
  for letter in range(97,122)
    execute "inoremap " . nr2char(letter, 1) . " " . nr2char(letter - 32, 1)
  endfor
endfunction

The capslock.vim Plugin

I have subsequently discovered Tim Pope's capslock.vim plugin, which uses both of the methods described above to implement this functionality.

Alternative methods

You can also set up language mappings or a keymap to translate lower to upper case and vice versa, as described on the Vim Tips Wiki.

Once set up, both of the above can be toggled by pressing Ctrl+^. (See :help i_CTRL-^.) See the linked page on the Wiki for more details.

2

You could use the following lines to get an automated solution, I'm not sure if it is really prettier but it seems to be working and takes only 3 lines:

let g:capslockfortran = 1
nnoremap <F5> :let g:capslockfortran = !g:capslockfortran<CR>

autocmd InsertLeave * if g:capslockfortran | execute "normal! `[v`]U | `]" | endif

The first two lines create a variable g:capslockfortran initialized to 1 and a mapping (<F5>) which toggle the value of this variable between 1 and 0

The third line creates an autocommand which is triggered each time you leave insert mode in fortran files (I never wrote fortran before, it seems that the extension is .f90 but you might want to change that if it is not the correct extension)

The command executed tests the value of g:capslockfortran and if it is set to 1 it will select the last inserted text (`[,`]) and uppercase it with U.

Edit Thanks to @BLayer comments I also added `] so that the cursor doesn't change of position.

Some notes:

You could use b:capslockfortran instead of g:capslockfortran to be able to enable/disable the automatic uppercase on a buffer basis. That would probably require another autocommand which would initialize the variable for each buffer.

For more details you can have a look at the following help topics:

6
  • @BLayer that's weird I just tried it again and it works for me... When do you get the error?
    – statox
    Aug 16, 2017 at 14:21
  • Sorry, that was user error. However, do you want to move the cursor back to the end of insertion? For me anyways, it remains at the beginning of insertion.
    – B Layer
    Aug 16, 2017 at 14:21
  • @BLayer no problem, the execute wasn't nessecary anyway (see my edit). About where the cursor ends up indeed there may be a problem. I guess one could try to add `] at the end of the command to go back to the previous position, or use getpos() and setpos()
    – statox
    Aug 16, 2017 at 14:48
  • That seems reasonable. I just tried this and it seems to work okay (I'm leaving off the feature flag and execute) au InsertLeave * normal! `[v`]U | `].
    – B Layer
    Aug 16, 2017 at 14:53
  • 1
    Cool, sounds good. (And I just escaped backtick with backslash and that seemed to do the trick.)
    – B Layer
    Aug 16, 2017 at 14:59
0

Are you okay converting the text after you enter it? If so, type in lowercase, select the text with Visual mode and type U.

Or avoid Visual mode with gU{motion}. (See :help uppercase)

Too easy? :)

4
  • That's what I've done previously, but it gets fiddly after a while. Aug 15, 2017 at 19:40
  • @bariumbitmap Can you elaborate on 'fiddly'? What goes wrong?
    – B Layer
    Aug 15, 2017 at 19:47
  • Nothing goes wrong, but it's distracting to go back and re-select what I typed, and it makes it harder to catch typos while transcribing. Thanks for the tip, though; before I was using ~ instead of U. Aug 16, 2017 at 12:48
  • Fair enough...'twas a low-tech suggestion to begin with.
    – B Layer
    Aug 16, 2017 at 14:04

Your Answer

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

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