lyokha / vim-xkbswitch

vim plugin for automatic keyboard layout switching in insert mode
MIT License
481 stars 23 forks source link

Libcalls to `libxkbswitch` don't work properly #27

Closed rkiyanchuk closed 8 years ago

rkiyanchuk commented 8 years ago

Disclaimer

The issue is very weird and I completely understand and acknowledge its weirdness, I also assume there could be something terribly wrong with my setup, however despite my thorough trials I couldn't figure out the root cause, so decided to ask for an advice here.

Issue

vim-xkbswitch plugin doesn't switch the layout when exiting to normal mode (from insert). For instance: I start Vim, go into insert mode, switch layout to Russian and type some text, press Esc to return to normal: layout doesn't change. What's weird: if I manually switch back to English and repeat the procedure: go to insert, type something, exit to normal again --- then the layout gets switched (but back to Russian, since I already was in English after manual switch, so it just inverts the layout).

Sounds crazy, but basically layout switch works only on the second call.

Troubleshooting

I have tried to remove all plugins and configurations from my .vimrc, only leave the minimal few lines to enable vim-xkbswitch, removed xxkb, changed Xkb settings to simplest possible setup setxkbmap -layout 'us,ru' even though I usually have more complicated configuration and 3 layouts.

But the issue persisted: libcall to libxkbswitch switched the layout only on the second call, so the plugin messes up and gets completely confused. At the same time console utility (xkb-switch) works as expected and successfully switches layouts with just one call. That's the reason why I decided to open issue here instead of xkb-switch repo, as the issue actually happens only when I use it through Vim.

I went down to just manually perform the libcall from Vim console like so:

:call libcall(g:XkbSwitchLib, Xkb_Switch_setXkbLayout, 'ru')

And again nothing happens on the first call, only when I repeat this command for the second time, the layout actually changes (same when I use this command to switch back to English).

I even tried to remove the plugin and Vundle completely, and just paste the code from your article straight into .vimrc, but the behavior is the same.

For now I could only workaround the issue by literally duplicating all set calls to Xkb in the plugin --- then it works.

Debug info

OS: Arch Linux (of course everything is updated to latest versions).

$ pacman -Qi xkb-switch-git
Name            : xkb-switch-git
Version         : 20150826-4
...
$ pacman -Qi libxkbcommon-x11 
Name            : libxkbcommon-x11
Version         : 0.6.1-1
...
$ vim --version
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Aug  2 2016 05:21:06)
Included patches: 1-2143
Compiled by Arch Linux
Huge version with GTK2 GUI.
...

Please let me know if there's any other useful debug info I can provide. If only I could debug the libcall to Xkb in detail to see what's actually going on, but I don't know how, and strace on xkb-switch itself wouldn't help, as the command line utility works fine: it's only libcall from Vim that misbehaves.

Thank you!

lyokha commented 8 years ago

Looks like the plugin is unable to determine keyboard layout that was set on vim load in your case. I'll look at details tomorrow because I do not have time today. But anyway setting

let g:XkbSwitchNLayout = 'us'

must work. Please try this and also show all your vim settings regarding the plugin. You can try also

let g:XkbSwitchLoadOnBufRead = 1

this forces to load plugin on BufRead event but may clash with other plugins like EnhancedJumps in my case. If you're using the second setting, the first one is optional, however I would recommend to use the first because forcing English layout in Normal mode always looks sound. Btw here are my settings:

" ---- Automatic keyboard layout switching upon entering/leaving insert mode
" ---- using xkb-switch utility and plugin xkbswitch
" ----
let g:XkbSwitchEnabled = 1
let g:XkbSwitchIMappings = ['ru']
let g:XkbSwitchNLayout = 'us'
let g:XkbSwitchILayout = 'us'
" loading xkbswitch on BufRead when bufhidden=delete will clash xkbswitch
" function imappings_load() and plugin EnhancedJumps as soon as both will do
" redir simultaneously!
let g:XkbSwitchLoadOnBufRead = 0
let g:XkbSwitchSkipIMappings =
            \ {'c'   : ['.', '>', ':', '{<CR>', '/*', '/*<CR>'],
            \  'cpp' : ['.', '>', ':', '{<CR>', '/*', '/*<CR>']}
let g:XkbSwitchSkipFt = [ 'conque_term' ]
let g:XkbSwitchAssistNKeymap = 1    " for commands r and f
let g:XkbSwitchAssistSKeymap = 1    " for search lines
let g:XkbSwitchDynamicKeymap = 1
let g:XkbSwitchKeymapNames = {'ru' : 'russian-jcukenwin'}
rkiyanchuk commented 8 years ago

Thanks for the reply! Unfortunately I've tried all the suggestions, including just copying your config, but the problem still persists.

My current config:

let $VIMHOME=$HOME . "/.vim"
let $VIMBUNDLE=$VIMHOME . "/bundle"

filetype off  " Filetype recognition must be disabled for Vundle setup.
set rtp+=$VIMBUNDLE/Vundle.vim/
call vundle#begin()

Plugin 'VundleVim/Vundle.vim'  " Vim plugin manager.
Plugin 'lyokha/vim-xkbswitch'  " Automatic keyboard layout switcher.

call vundle#end()
filetype plugin indent on

let g:XkbSwitchEnabled = 1
let g:XkbSwitchIMappings = ['ru']
let g:XkbSwitchNLayout = 'us'
let g:XkbSwitchILayout = 'us'
let g:XkbSwitchLoadOnBufRead = 0
let g:XkbSwitchSkipIMappings =
            \ {'c'   : ['.', '>', ':', '{<CR>', '/*', '/*<CR>'],
            \  'cpp' : ['.', '>', ':', '{<CR>', '/*', '/*<CR>']}
let g:XkbSwitchSkipFt = [ 'conque_term' ]
let g:XkbSwitchAssistNKeymap = 1    " for commands r and f
let g:XkbSwitchAssistSKeymap = 1    " for search lines
let g:XkbSwitchDynamicKeymap = 1
let g:XkbSwitchKeymapNames = {'ru' : 'russian-jcukenwin'}

If I set

let g:XkbSwitchLoadOnBufRead = 1

I get error No mapping found on startup, however I do have russian-jcukenwin.vim mapping in /usr/share/vim74/keymap directory :\

lyokha commented 8 years ago

I went down to just manually perform the libcall from Vim console like so:

:call libcall(g:XkbSwitchLib, Xkb_Switch_setXkbLayout, 'ru')

And again nothing happens on the first call, only when I repeat this command for the second time, the layout actually changes (same when I use this command to switch back to English).

This is really suspicious. Here vim must call the function from the library without any additional processing and if it fails then there is something wrong with the function or libcall. I built latest xkb-switch on my desktop and it works as fine as before. What if there is something wrong with the Arch xkb-switch? I have looked at this and read in comments that it must depend on libxkbfile but it does not if I got it correctly.

Can you build xkb-switch manually from here and try the new library that it would install?

rkiyanchuk commented 8 years ago

@lyokha You are right, it is indeed something wrong with Arch AUR package xkb-switch-git — once I built locally from upstream repo and replaced libxkbswitch.so, the plugin started working as expected again.

Though the symptoms were indeed suspicious, the Arch PKGFILE seems to be straightforward, yet it does something wrong that libxkbswitch starts to act so weird.

I'll try to figure it out and fix the AUR package for Arch, but now that's a different story :)

Thanks for the help to sort this out!

rkiyanchuk commented 8 years ago

Just for your information, turns out makepkg builds Arch packages with -O2 compile flag by default and this causes problem with xkb-switch library. I've tried to manually compile upstream xkb-switch code with -O2 and was able to reproduce the same problem using the resulting lib without building Arch package.

Now it's clear that the problem originates from xkb-switch code.

Thanks for the help!

lyokha commented 8 years ago

Hmm. Actually I built my old fork of xkb-switch and it worked fine at any optimization level. The upstream xkb-switch does work as you explained at any optimization level. I will try to figure out what's wrong.

lyokha commented 8 years ago

I re-checked that and found that It worked bad only when optimization was on, exactly as you told. See my comment and the patch at the xkb-switch bug report. This must work. Surprisingly, my old fork worked fine with optimization set, yet it used the same XkbLockGroup() without accommodation.