macos - 在控制台 Vim 中使用 CMD 映射

标签 macos vim terminal keyboard-shortcuts iterm2

有没有办法使用Cmd终端中 Vim 的键? MacVim 做的事情。

我已重新映射 Cmd+S在 iTerm2 中发送 Esc:w!<CR>在 Vim 中保存文件,但这听起来有点弱。

凭借 iTerm 和 Vim 的所有功能,应该有一些方法可以做到这一点吗?

最佳答案

这是可能的,但需要做一些事情并且有一些缺点。

第一组问题是:

  • 尽管 iTerm2 可以接受命令键并将它们传递给终端程序,但它只能通过将它们重新映射为其他东西来做到这一点,例如左选项或控制键。
  • 它只能在 iTerm2 的任何地方重新映射每个修饰键;您不能只对某些窗口、 Pane 或配置文件执行此操作。
  • 为了在终端内重新映射修改器,您需要允许 iTerm2 在安全和隐私首选项 Pane 中控制计算机;当您配置 iTerm2 进行重新映射时,它会自动引导您到那里。
  • 重新映射 Left Command 后,Left Command+N 打开新窗口之类的操作将不再起作用。不过幸运的是,您可以重新映射,例如向左命令的左选项,并且您的右命令键仍然可用于 Mac 快捷方式;或者您可以切换命令和选项键。

  • 剩下的问题是 Vim 没有开箱即用地配置类似 Mac 的键绑定(bind)。幸运的是,MacVim 在/Applications/MacVim.app/Contents/Resources/vim/runtime/macmap.vim 中包含了大部分 Mac 风格的 GUI 绑定(bind),而不是在 Interface Builder 或 Objective-C 源代码中编码它们;所以我能够复制这些并将它们改编为终端。这是一个与 MacVim(和其他 Mac 应用程序)非常接近的配置:
    " Keybindings for terminal vim; mostly to emulate MacVim (somewhat)
    
    " See /Applications/MacVim.app/Contents/Resources/vim/runtime/macmap.vim (from
    " which many of the following are taken); and menu.vim in the same directory.
    
    " Since these all have native (Cmd-modified) versions in MacVim, don't bother
    " defining them there.
    
    " A utility function to help cover our bases when mapping.
    "
    " Example of use:
    "   call NvicoMapMeta('n', ':new<CR>', 1)
    " is equivalent to:
    "   exec "set <M-n>=\<Esc>n"
    "   nnoremap <special> <Esc>n :new<CR>
    "   vnoremap <special> <Esc>n <Esc><Esc>ngv
    "   inoremap <special> <Esc>n <C-o><Esc>n
    "   cnoremap <special> <Esc>n <C-c><Esc>n
    "   onoremap <special> <Esc>n <Esc><Esc>n
    function! NvicoMapMeta(key, cmd, add_gv)
        " TODO: Make this detect whether key is something that has a Meta
        " equivalent.
        let l:keycode = "<M-" . a:key . ">"
    
        let l:set_line = "set " . l:keycode . "=\<Esc>" . a:key
    
        let l:nmap_line = 'nmap <silent> <special> ' . l:keycode . ' ' . a:cmd
        let l:vnoremap_line = 'vnoremap <silent> <special> ' . l:keycode . ' <Esc>' . l:keycode
        if(a:add_gv)
            let l:vnoremap_line.='gv'
        endif
        let l:inoremap_line = 'inoremap <silent> <special> ' . l:keycode . ' <C-o>' . l:keycode
        let l:cnoremap_line = 'cnoremap <special> ' . l:keycode . ' <C-c>' . l:keycode
        let l:onoremap_line = 'onoremap <silent> <special> ' . l:keycode . ' <Esc>' . l:keycode
    
        exec l:set_line
        exec l:nmap_line
        exec l:vnoremap_line
        exec l:inoremap_line
        exec l:cnoremap_line
        exec l:onoremap_line
    endfunction
    
    " I can't think of a good function to assign to Meta+n, since in MacVim Cmd+N
    " opens a whole new editing session.
    
    " Meta+Shift+N
    " No equivalent to this in standard MacVim. Here " it just opens a window on a
    " new buffer.
    call NvicoMapMeta('N', ':new<CR>', 1)
    
    " Meta+o
    " Open netrw file browser
    call NvicoMapMeta('o', ':split %:p:h<CR>', 1)
    
    " Meta+w
    " Close window
    call NvicoMapMeta('w', ':confirm close<CR>', 1)
    
    " Meta+s
    " Save buffer
    call NvicoMapMeta('s', ':confirm w<CR>', 1)
    
    " Meta+Shift+S
    " Save as
    " TODO: This is silent, so you can't tell it's waiting for input. If anyone can
    " fix this, please do!
    call NvicoMapMeta('S', ':confirm saveas ', 1)
    
    " Meta+z
    " Undo
    call NvicoMapMeta('z', 'u', 1)
    
    " Meta+Shift+Z
    " Redo
    call NvicoMapMeta('Z', '<C-r>', 1)
    
    " Meta+x
    " Cut to system clipboard (requires register +")
    exec "set <M-x>=\<Esc>x"
    vnoremap <special> <M-x> "+x
    
    " Meta+c
    " Copy to system clipboard (requires register +")
    exec "set <M-c>=\<Esc>c"
    vnoremap <special> <M-c> "+y
    
    " Meta+v
    " Paste from system clipboard (requires register +")
    exec "set <M-v>=\<Esc>v"
    nnoremap <silent> <special> <M-v> "+gP
    cnoremap <special> <M-v> <C-r>+
    execute 'vnoremap <silent> <script> <special> <M-v>' paste#paste_cmd['v']
    execute 'inoremap <silent> <script> <special> <M-v>' paste#paste_cmd['i']
    
    " Meta+a
    " Select all
    call NvicoMapMeta('a', ':if &slm != ""<Bar>exe ":norm gggH<C-o>G"<Bar> else<Bar>exe ":norm ggVG"<Bar>endif<CR>', 0)
    
    " Meta+f
    " Find regexp. NOTE: MacVim's Cmd+f does a non-regexp search.
    call NvicoMapMeta('f', '/', 0)
    
    " Meta+g
    " Find again
    call NvicoMapMeta('g', 'n', 0)
    
    " Meta+Shift+G
    " Find again, reverse direction
    call NvicoMapMeta('G', 'N', 0)
    
    " Meta+q
    " Quit Vim
    " Not quite identical to MacVim default (which is actually coded in the app
    " itself rather than in macmap.vim)
    call NvicoMapMeta('q', ':confirm qa<CR>', 0)
    
    " Meta+Shift+{
    " Switch tab left
    call NvicoMapMeta('{', ':tabN<CR>', 0)
    
    " Meta+Shift+}
    " Switch tab right
    call NvicoMapMeta('}', ':tabn<CR>', 0)
    
    " Meta+t
    " Create new tab
    call NvicoMapMeta('t', ':tabnew<CR>', 0)
    
    " Meta+Shift+T
    " Open netrw file browser in new tab
    call NvicoMapMeta('T', ':tab split %:p:h<CR>', 0)
    
    " Meta+b
    " Call :make
    call NvicoMapMeta('b', ':make<CR>', 1)
    
    " Meta+l
    " Open error list
    call NvicoMapMeta('l', ':cl<CR>', 1)
    
    " TODO: We need to configure iTerm2 to be able to send Cmd+Ctrl+arrow keys, so
    " we can duplicate the :cnext/:cprevious/:colder/:cnewer bindings to those keys
    " in MacVim.
    " There may be a few others I've missed, too.
    
    NvicoMakeMeta函数将传递给它的键的元键修改版本映射到指定的操作;这里的“元键”只是 Command- 或 Option-modified 的通用术语。其名称中的“Nvico”表示它以正常、可视、插入、命令和运算符(operator)挂起模式映射的事实。

    由于 Vim 在解释 ESC 时的工作方式字符(这是所有元键序列以及箭头键等的开始),如果我们简单地映射 ESC 的序列加上另一个字符,我们最终会在 Vim 收到实际的 Esc 按键后等待相当长的时间(例如,表示希望返回正常模式)。我的函数避免这种情况的方法是使用 :set设置 key 代码(见 :help :set-termcap )。

    总而言之,您需要执行以下操作:
  • 把上面的代码放在你的 .vimrc 中。
  • 转到一般 iTerm2 首选项(iTerm 菜单 > Preferences…);转至Keys标签;重新映射您想用作修饰符的任何键,以便它发送左选项或右选项。按照建议允许 iTerm2 控制计算机;它应该为您打开正确的首选项 Pane 。您必须先单击锁并输入密码,然后才能选中 iTerm 旁边的框。
  • 打开您想要使用的终端配置文件的首选项(例如,通过在应用程序范围的 Preferences 对话框中的 Profiles 选项卡中打开它)并确保 +EscLeft option key acts as 旁边选中(和/或 Right option key acts as ,取决于您是否让元 key 发送正确的选项)。
  • 关于macos - 在控制台 Vim 中使用 CMD 映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26310077/

    相关文章:

    macos - 有没有办法在 macOS SwiftUI 开发中使用 SF Symbols?

    macos - 使用CoreAudio OSX读取输入音量

    ubuntu - gnome-terminal 打印不必要的日志记录

    vim - 有没有一种快速的方法可以一次编辑多个 yaml 文件?

    Java程序计算变量数组的平均值,从命令行输入,显示结果

    java - 无需 IDE 即可学习 JavaFX

    c - "BYTE_ORDER"宏在 OSX 中定义在哪里?

    php - localhost 不能在 docker for mac 中工作

    vim - 在vim中查找并替换为星号(*)

    vim - 在 Vim 中替换字符串周围的引号?