Trigger cursor positioning and selection on going to Normal mode or ESC map

三世轮回 提交于 2019-12-23 03:22:25

问题


Anyone knows how can I trigger cursor positioning and selection from python when going to Normal?

This is the script and I had to comment out the ESC mapping in this commit.

Relevant plugin source code is bellow:

# -*- coding: utf-8 -*-

import re
import vim

#How can we fetch the first param on going to normal Mode without problems?!
vim.command( "inoremap <silent> <buffer> <esc> <c-\><c-n>:py clang_complete.firstParam()<cr>" )

r = re.compile( "@[^@]+\$" )

def firstParam():
  line = vim.current.line
  row, col = vim.current.window.cursor

  result = r.search(line)
  if result is None:
    vim.command('call feedkeys("\<esc>", "n")')
    return

  selectParams( *result.span() )

def selectParams( start, end  ):
  row, _ = vim.current.window.cursor
  vim.current.window.cursor = row, start
  isInclusive = vim.options["selection"] == "inclusive"
  vim.command( 'call feedkeys("\<c-\>\<c-n>v%dl\<c-g>", "n")' %
               ( end - start - isInclusive ) )

An ESC mapping gives issues with arrows keys in terminal on insert mode, and providing a simple InsertLeave auto command didn't work well, it was operating much slower than the mapping and it wasn't correctly setting cursor positioning to make the selection, so the selection was over the wrong place.

I also consider an alternative approach for doing the exact same thing.


回答1:


TL;DR, set ttimeout=100 (or less) and InsertLeave auto-commands will be processed much sooner (specifically, in that many milliseconds).

:imaping <Esc> will cause cursor keys and function keys to stop working in insert mode, so don't do that. With the improved timeout, using the InsertLeave autocommand should be the way to go. I'd try and help with the cursor positioning problem you mention, but there isn't enough explanation of that to address it.

There are a lot of settings in vim that are related to responding to pressing Esc. Vim might receive an escape for two main reasons:

  1. the user pressed escape on its own, or
  2. the user pressed an arrow key or function key that produced an escape sequence.

When it sees an escape in insert mode, vim cannot leave insert mode immediately but has to wait to find out if it is

  1. part of an escape sequence generated by a function key, or
  2. part of a multi-key mapping.

For the ultimate in fast escape handling you can set the option noesckeys which turns off the recognition of the special keys <Left>, <Right>, <F1>, etc. in insert mode. When vim is in compatible mode (what you got when you had no vimrc) this is the default behavior and explains why your InsertLeave autocommand was processed immediately. The documentation notes that the esckeys settings does not affect the processing of mappings which leads to the second topic.

Vim allows you to create a mapping for a sequence of keys, even when some prefix of that sequence is already mapped to some other action (either by another user mapping or a default action). When vim sees a key it will look to see if there is mapping that starts with that key. If there is only one and it is the key on its own, the mapping can be processed immediately. If there are multiple mappings beginning with the key then vim must wait to see if you complete one of the mappings.

Besides esckeys discussed above, Vim has several options for controlling whether it waits and for how long. These are

  1. timeout, which controls whether vim uses a timeout to decide if a mapping is complete;
  2. ttimeout, which controls whether vim uses a timeout to decide if an escape sequence is complete;
  3. timeoutlen, which controls how long vim waits to see if a mapping is complete; and
  4. ttimeoutlen, which control how long vim waits to see if an escape sequence is complete.

When timeout is off (notimeout) vim will wait indefinitely for a mapping to be completed. For instance, if notimeout is set and you have a mapping :inoremap teh\ the\ to fix this common type (you would actually use an iabbrev for this in real life), and you typed teh nothing will be added to the buffer until you either press Space, in which case the mapping occurs and the is added to the buffer; or you press some other key, causing the original teh to be added then processing the next key.

The ttimeout option is only consulted when notimeout is set (vim uses timeouts for both whenever timeout is set). With nottimeout set, vim will wait indefinitely after getting an escape to see if it is part of an escape sequence. If you set notimeout, nottimeout, and showmode you can see that when you press Esc in insert mode that vim remains in insert mode until some other key is pressed that isn't part of an escape sequence. A silly trick is to type EscO*D with these settings (make sure you are in an xterm) and watch the cursor move to the left.

Finally, when it is using timeouts, vim uses timeoutlen and ttimeoutlen to decide how long to wait. The defaults settings are timeoutlen=1000, which means a one second timeout, and ttimeoutlen=-1 which means use the value of timeout. Now, one second is probably ok for the mappings but is way longer than is needed for recognizing escape sequences. Vim doesn't truly leave insert mode until it sees the escape and the relevant timeouts have expired. Oddly, vim will remove the showmode insert mode indicator right away after seeing the escape but not fire InsertLeave until after the timeout has passed (it adds the indicator back if a mapping/escape sequence is seen before the timeout expires). The vim documentation suggests trying ttimeoutlen=100 but I think you could go even shorter, e.g. 50, without any problems with messed up special keys.

Now that I've researched this I'm going to go around and make sure I set ttimeoutlen=50 everyplace I use vim and maybe even lower timeoutlen too.



来源:https://stackoverflow.com/questions/22425596/trigger-cursor-positioning-and-selection-on-going-to-normal-mode-or-esc-map

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!