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
    };

  • 相关阅读:
    【CV论文阅读】ExtremeC3Net: 使用高级C3模块的极轻量人像分割模型
    【pytorch基础】pytorch的初始化
    【CV基础】如何理解空洞卷积(dilated convolution)?
    关于研发规范化的一些实践和思考
    vuecli入门项目实战
    C/C++用.ico图片替换.exe图标(VS2017)(转)
    C# 多线程修改控件时,提示在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke(转)
    C#读取ACCESS提示“未在本地计算机上注册Microsoft.ACE.OLEDB.12.0提供程序
    ubuntu的常用命令
    C# DataTable 按整形字段排序
  • 原文地址:https://www.cnblogs.com/tsecer/p/14766043.html
Copyright © 2011-2022 走看看