9

I am in the slightly unusual position of using two different keyboard layouts on a regular basis (Programmers-Dvorak and Turkish-F). These layouts are quite different from each-other and I am only able to be proficient in vim with one set of muscle memories. I'm pretty proficient with vim commands in the Dvorak layout, but it's almost impossible to use if my keyboard is in the Turkish-F layout. Unfortunately I regularly edit files in both English and Turkish and even mixed languages. My proficiency is such that I can type either language in it's respective keyboard layout rather well, but my brain refuses to cross-wire them and type even a few letters of a word in Turkish from the Dvorak layout or vise versa.

I have two-key-salute bindings for changing the layout in Xorg, but even this leaves me with an awkward workflow in vim when editing mixed language files:

<vim commands…>i<switch to tr>…content…<escape><switch to en><vim commands…>

I would like to be able to shorten this to something like:

<vim commands…><leader>i…content…<escape><vim commands…>

...such that using <leader>i sets a bunch of :imap values to emulate the Turkish layout without changing the system keyboard layout. At the same time, i would switch to insert mode but without the extra :imap values. The values themselves are easy, I just need the alphabet mappings something like these:

:imap a u
:imap A U
:imap o i
:imap O İ
"etc.

The question is, how to setup two insert modes, one normal insert mode and one pseudo insert mode that is identical except for a bunch of mappings, and how can I trigger these modes with <leader>i, <leader>a, etc.?

  • 1
    Here's a different idea: You have the InsertEnter and InsertLeave autocmds, which you can use to switch layouts automatically. Specifically, on the InsertLeave you can check if it's Turkish, if it is, switch to Dvorak, set a flag, and when you enter insert again switch back to Turkish if that was the case last time you left insert mode. – Martin Tournoij Feb 27 '15 at 13:33
  • @Carpetsmoker I don't see how that fixes my issues. Even if there was something to "check" (I'm not sure what you think I'd be checking there...part of the problem is I go back and forth on a word by word basis), one of the reasons I was thinking along the lines of :imap is that it would work even in a remote ssh session or when $DISPLAY is otherwise not set. – Caleb Feb 27 '15 at 20:07
7

Vim has something like this in the form of keymaps. From :help mbyte-keymap:

When the keyboard doesn't produce the characters you want to enter in your
text, you can use the 'keymap' option.  This will translate one or more
(English) characters to another (non-English) character.  This only happens
when typing text, not when typing Vim commands.  This avoids having to switch
between two keyboard settings.

Insert-mode only Caps Lock describes such a mapping for emulation of Caps Lock; as you can see there, the mappings file is similar to what you outline in your question.

You enable this setting via :set iminsert=1 or dynamically via i_CTRL-^. It also works for /search with the 'imsearch' option.

3

Ingo Karkat's answer seems like it was exactly the right solution and has solved my situation. However here are a little bit more verbose instructions for anyone else just getting started with vim's language map functions.

First, you need a language map file. As in the Caps Lock example, you'll want to put something like the following in ~/.vim/keymap/dvorak2turkishf.vim (download my full mapping from Github):

let b:keymap_name = "dvorak2turkishf"
loadkeymap
; f
, g
. ğ
p ı
y o
f d
g r
" etc...

With that in place, it remains to setup bindings to activate it in some cases but not others. You'll want to add something to your ~/.vimrc file.

First, bind the search keymap to the input one:

set imsearch=-1

Then set which keymap will be used for alternate-language input mode:

set keymap=dvorak2turkishf

Turn off the alternate input mode so by default there will be no change:

set iminsert=0

Setup an auto-command to run whenever leaving insert mode to turn off the alternate language switch:

autocmd InsertLeave * set iminsert=0

Add bindings for all the various ways you might end up in the alternate-language input mode so that using <leader> (Usually \) before them sets the language map swtich to on before switching:

nnoremap <leader>i :set iminsert=1<Cr>i
nnoremap <leader>I :set iminsert=1<Cr>I
nnoremap <leader>a :set iminsert=1<Cr>a
nnoremap <leader>A :set iminsert=1<Cr>A
nnoremap <leader>c :set iminsert=1<Cr>c
nnoremap <leader>C :set iminsert=1<Cr>C
nnoremap <leader>r :set iminsert=1<Cr>r
nnoremap <leader>R :set iminsert=1<Cr>R
nnoremap <leader>o :set iminsert=1<Cr>o
nnoremap <leader>O :set iminsert=1<Cr>O

Set a different cursor color for when the map is enabled:

:highlight Cursor guifg=NONE guibg=Green
:highlight lCursor guifg=NONE guibg=Cyan

All together, here is what changed in my config. As a final note, one you are in insert mode you can toggle the language map option on and off using <ctrl>+^.

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.