Evgeniy
Evgeniy

Reputation: 806

Force feedkeys to paste characters immediately

I am writing a plugin to enhance lexics (e.g. automatically close brackets/quotes, filetype specific rules, etc) and some things have unexpected behavior for me. The plugin rule looks like this one:

{"key": "'", "pattern": '...', "keys": "'\<Left>"}

Since I am listening to InsertCharPre event to detect what key has been pressed, there is some restrictions in editing buffer directly using setline, for instance (:help textlock). So I have to change v:char variable or call feedkeys instead of. The problem with v:char is it cannot operate with special keys (it just inserts an escaped sequence) like "\", "\" and others (however, "\" seems to be handled correctly) which are frequently used in the plugin. So my only option is feedkeys, but if there is a key in the keys (see above), vim starts a recursion. I know about <C-v> insert mode mapping but there can be a lot of such keys that will make adding new rules more complex. If there is no other option, I think, the best decision would be use set paste option but as subject indicates I have some troubles with it.

...
set paste

call feedkeys("'\<Left>")

set nopaste
...

It seems that the whole body of the function is executed firstly and then the characters are inserted to the buffer at the moment when paste is already nopaste. Further reading of feedkeys help was not successful (I tried different modes). You can try this simple code to see what I am talking about:

function! s:Foo()
    startinsert

    call feedkeys("ff")

    stopinsert
endfunction

nnoremap <silent><CR> :call <SID>Foo()<CR>

Buffer should not contain any text after pressing Enter but if you comment stopinsert command, everything goes as expected.

Ps: I know about lexima plugin but do not want to use it. I tried to solve the problem exploring the source code of lexima but there is inoremap <expr> which I also do not want to use :).

Upvotes: 2

Views: 911

Answers (1)

Ingo Karkat
Ingo Karkat

Reputation: 172688

feedkeys() is about inserting keys into the typeahead buffer. Keys from this buffer are only consumed after the current command / function has ended (or if you explicitly read keys, e.g. via getchar()). That explains you struggles to have the keys processed immediately; the function isn't meant for that :-) To submit keys immediately, you'd use :normal. Yes, that doesn't work with textlock.

Based on your problem, I think using feedkeys() with the n mode (i.e. do not remap keys) should work. The keys won't be affected by user mappings, so you know exact which (built-in) keys need to be escaped. If you really needed to brace your keys with e.g. changing 'paste', you'd have to put the toggle commands inside feedkeys() as well:

:call feedkeys(":set paste\<CR>\<Left>:set nopaste\<CR>")

Upvotes: 3

Related Questions