简体   繁体   中英

Map vim keys based on OS?

Background


I use VIM on both MacOS and windows, with just one vimrc setting

And here's one of my lightweight key mapping binding:

map <leader>cmd:exec has("mac")==1? ':!open -a terminal' : ':!start cmd'

Problem


However, it doesn't work as I thought: press <leader>cmd and without pressing an enter key then cmd or terminal pops out.

What actually happens is the whole mapping string

exec has("mac")==1? ':!open -a terminal' : ':!start cmd' exec has("mac")==1? ':!open -a terminal' : ':!start cmd' just appears in ex mode and waits for me to press the enter key to run itself.

As I know, if you use exe "your cmd string" in your mapping key setting , you don't need put a <cr> after it, but why when you are using the triple operator, it behaves differently?

Try


So I put into the string, like

map <leader>cmd:exec has("mac")==1? ':!open -a terminal<cr>' : ':!start cmd<cr>'

vim tells me:

在此处输入图片说明

(Also, I cannot figure out why <cr> in `` should be escaped, isn't that a string in `` remains the original meaning?)

So I modified as following:

map <leader>cmd:exec has("mac")==1? ':!open -a terminal\<cr\>' : ':!start cmd\<cr\>'

But it just appears in ex mode again.

Any solutions, please?

First, let's clean up your command a little:

:nnoremap <leader>cmd :execute has("mac") ? "!open -a terminal" : "!start cmd"
  • nnoremap is better than map because it ensures non-recursiveness and it's explicit about the mode it's made for,
  • no need to test the value of has() ,
  • shortened names are cool for typing in the command-line but they are useless in script,
  • the : are redundant.

But none of that will actually fix your problem, namely that you don't have a carriage return at the end of your mapping:

:nnoremap <leader>cmd :execute has("mac") ? "!open -a terminal" : "!start cmd"<CR>

And you still have to press <CR> a second time anyway to get back to Vim so…

:nnoremap <leader>cmd :execute has("mac") ? "!open -a terminal" : "!start cmd"<CR><CR>

Now, here is a pretty clean and generic way to do things differently depending on the platform:

" Define a global variable containing the current environment's name
" if it hasn't been already defined.
if !exists('g:env')
    if has('win64') || has('win32') || has('win16')
        let g:env = 'WINDOWS'
    else
        let g:env = toupper(substitute(system('uname'), '\n', '', ''))
    endif
endif

and a reworked version of your mapping, with an added path for the open command which you may or may not need depending on your use case:

nnoremap <leader>cmd :execute g:env == "DARWIN" ? "!open -a terminal ." : "!start cmd"<CR><CR>

and an alternative approach, just for the fun of it:

let cmds = { "DARWIN": "!open -a terminal .", "WINDOWS": "!start cmd" }
nnoremap <leader>cmd :execute cmds[g:env]<CR><CR>

In contrast to @romainl's answer, you don't need to dynamically evaluate the operating system during mapping execution (the operating system can hardly change while Vim is running; this is static information). Therefore, it's much easier to define the mappings conditionally:

if has("mac")
    nnoremap <leader>cmd :!open -a terminal<CR>
else
    nnoremap <leader>cmd :!start cmd<CR>
endif

This let's you get rid of the :execute , is a bit faster, and much easier to extend or tweak. (All the other caveats about :noremap and the missing <CR> from @romainl's answer still apply.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM