zoukankan      html  css  js  c++  java
  • 为什么vim编辑模式下ctrl-w可以前向删除单词及按键映射的展开

    一、问题

    在vim的编辑模式下,我之前一直以为只能进行字符的插入操作,但是意外看到可以在编辑模式下通过ctrl-w来前向删除一个单词,并且可以通过ctrl-h来前向删除一个字符。根据通常的ASCII码内置控制方法,通过ctrl-h对应的是ASCII码的BS(backspace)字符,所以通过ctrl-h前向删除单个字符在逻辑上是可以理解的。但是,ctrl-w对应的ASCII码却是ETB (end of trans. blk),这个明显不是标准的前向删除一个单词的意思,所以它是vim内部完成的一个功能。那么vim具体是通过什么方式来完成的呢?是否是内置的标准用法,还是通过编辑器定制的方法?

    二、vim读到终端输入是什么

    这一点很容易确认,通过strace可以看到,当在vim下按下ctrl-w按键时,此时vim通过read读到的就是转换之后的23这个输入。
    select(1, [0], [], [0], {0, 0}) = 0 (Timeout)
    select(1, [0], [], [0], NULL) = 1 (in [0])
    read(0, "27", 4096) = 1

    三、vim对终端的配置格式

    通过对比可以看到,vim使用的终端比标准终端添加了下面几个选项
    -icrnl
    -onlcr
    -isig -icanon -iexten -echo -echoe
    为了便于查看,将这些字段的意义整理罗列下
    [-]icrnl
    translate carriage return to newline
    * [-]onlcr
    translate newline to carriage return-newline
    [-]isig
    enable interrupt, quit, and suspend special characters
    [-]icanon
    enable erase, kill, werase, and rprnt special characters
    [-]iexten
    enable non-POSIX special characters
    [-]echo
    echo input characters
    [-]echoe
    same as [-]crterase
    [-]crterase
    echo erase characters as backspace-space-backspace
    这里比较关键的就是其实是关闭了icanon选项,所以终端默认的erase、kill、werase内置功能是被禁用的,也就是说,通过ctrl-w删除单词不是终端完成而是有vim自己完成的。

    #下面是标准终端的配置
    tsecer@harry: stty
    speed 38400 baud; line = 0;
    -brkint -imaxbel
    #下面是vim使用的终端的配置
    tsecer@harry: stty -F /dev/pts/3
    speed 38400 baud; line = 0;
    min = 1; time = 0;
    -brkint -icrnl -imaxbel
    -onlcr
    -isig -icanon -iexten -echo -echoe

    四、vim如何完成这个功能

    通过查看Vim的源代码,可以知道这个功能是vim的内置功能。
    edit.c
    int
    edit(
    int cmdchar,
    int startln, /* if set, insert at start of line */
    long count)
    {
    ……
    case Ctrl_W: /* delete word before the cursor */
    #ifdef FEAT_JOB_CHANNEL
    if (bt_prompt(curbuf) && (mod_mask & MOD_MASK_SHIFT) == 0)
    {
    // In a prompt window CTRL-W is used for window commands.
    // Use Shift-CTRL-W to delete a word.
    stuffcharReadbuff(Ctrl_W);
    restart_edit = 'A';
    nomove = TRUE;
    count = 0;
    goto doESCkey;
    }
    #endif
    did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space);
    auto_format(FALSE, TRUE);
    break;

    case Ctrl_U: /* delete all inserted text in current line */
    # ifdef FEAT_COMPL_FUNC
    /* CTRL-X CTRL-U completes with 'completefunc'. */
    if (ctrl_x_mode == CTRL_X_FUNCTION)
    goto docomplete;
    # endif
    did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space);
    auto_format(FALSE, TRUE);
    inserted_space = FALSE;
    break;
    ……
    }

    vim中可以通过help index查看所有的内置(按键)功能。其中可以找到关于这个ctrl-w的说明
    i_CTRL-U CTRL-U delete all entered characters in the current
    line
    i_CTRL-V CTRL-V {char} insert next non-digit literally
    i_CTRL-V_digit CTRL-V {number} insert three digit decimal number as a single
    byte.
    i_CTRL-W CTRL-W delete word before the cursor

    五、map功能

    除了这些内置功能之外,vim和包含了可以定制的键盘映射功能。可以通过imap、vmap、nmap来查看在isert、visual、normal模式下的键盘映射。
    在这些map中,可能需要有一些特定的按键,最为常见的就是配合Ctrl按键。所有这些内容可以通过在vim中执行help keycode命令查看:

    <k0> - <k9> keypad 0 to 9 *keypad-0* *keypad-9*

    <S-...> shift-key *shift* *<S-*

    <C-...> control-key *control* *ctrl* *<C-*

    <M-...> alt-key or meta-key *meta* *alt* *<M-*

    <A-...> same as <M-...> *<A-*

    <D-...> command-key (Macintosh only) *<D-*
    <t_xx> key with "xx" entry in termcap
    这里看到,对于修饰符都是单个字符开始的,也就是Ctrl通过C-表示(而不是Ctrl-)表示,通常的Ctrl-W是vim文档中使用的表示方法,它通常也表示在键盘上按下Ctrl的同时按下W键。例如,当希望查找在命令模式下,ctrl-r ctrl-w代表的什么意义,可以通过

    :h c_ctrl-r_ctrl-w 

    查找,当然,使用c_<C-R>_<C-W>也可以,只是使用ctrl-R比输入<C-r>更简单一些。从这个地方也可以看出,vim中通过通过下划线"_"表示空白,而"-"表示连接/连续。

    CTRL-R CTRL-F c_CTRL-R_CTRL-F c_<C-R>_<C-F>
    CTRL-R CTRL-P c_CTRL-R_CTRL-P c_<C-R>_<C-P>
    CTRL-R CTRL-W c_CTRL-R_CTRL-W c_<C-R>_<C-W>
    CTRL-R CTRL-A c_CTRL-R_CTRL-A c_<C-R>_<C-A>
    CTRL-R CTRL-L c_CTRL-R_CTRL-L c_<C-R>_<C-L>
    Insert the object under the cursor:
    CTRL-F the Filename under the cursor
    CTRL-P the Filename under the cursor, expanded with
    'path' as in gf
    CTRL-W the Word under the cursor
    CTRL-A the WORD under the cursor; see WORD
    CTRL-L the line under the cursor

    六、vim中map的展开

    srcgetchar.c
    static int
    vgetorpeek(int advance)
    {
    ……

    /*
    * Handle ":map <expr>": evaluate the {rhs} as an
    * expression. Also save and restore the command line
    * for "normal :".
    */
    if (mp->m_expr)
    {
    int save_vgetc_busy = vgetc_busy;

    vgetc_busy = 0;
    save_m_keys = vim_strsave(mp->m_keys);
    save_m_str = vim_strsave(mp->m_str);
    s = eval_map_expr(save_m_str, NUL);
    vgetc_busy = save_vgetc_busy;
    }
    else
    #endif
    s = mp->m_str;
    ……
    i = ins_typebuf(s, noremap,
    0, TRUE, cmd_silent || save_m_silent);
    ……
    }
    结构的定义
    structs.h
    /*
    * Structure used for mappings and abbreviations.
    */
    typedef struct mapblock mapblock_T;
    struct mapblock
    {
    mapblock_T *m_next; /* next mapblock in list */
    char_u *m_keys; /* mapped from, lhs */
    char_u *m_str; /* mapped to, rhs */
    char_u *m_orig_str; /* rhs as entered by the user */
    int m_keylen; /* strlen(m_keys) */
    int m_mode; /* valid mode */
    int m_noremap; /* if non-zero no re-mapping for m_str */
    char m_silent; /* <silent> used, don't echo commands */
    char m_nowait; /* <nowait> used */
    #ifdef FEAT_EVAL
    char m_expr; /* <expr> used, m_str is an expression */
    scid_T m_script_ID; /* ID of script where map was defined */
    #endif
    };

  • 相关阅读:
    How to alter department in PMS system
    Can't create new folder in windows7
    calculate fraction by oracle
    Long Wei information technology development Limited by Share Ltd interview summary.
    ORACLE BACKUP AND RECOVERY
    DESCRIBE:When you mouse click right-side is open an application and click left-side is attribution.
    ORACLE_TO_CHAR Function
    电脑BOIS设置
    JSP点击表头排序
    jsp+js实现可排序表格
  • 原文地址:https://www.cnblogs.com/tsecer/p/14766043.html
Copyright © 2011-2022 走看看