74

Can I retrieve the current operating system (Windows, Linux, OS X, ..) using pure Vimscript (no Python or Perl)?

I want to enable different settings in my (synchronized) .vimrc for different types of operation systems I am using.

muffel
  • 1,027
  • 1
  • 8
  • 7
  • Could you provide some specific examples of OS-dependent behaviours that you seek to implement? – 200_success Mar 16 '15 at 08:47
  • @200_success I have some scripts and key bindings for MS TFS and msbuild that are pretty useless in non-Windows environments, while I don't need tmux support in gVim on Windows. In addition, there are different fonts installed on different systems, and paths may differ as well. – muffel Mar 16 '15 at 08:52

6 Answers6

75

The best way is to use has(), with this function you can check for features of Vim; OS specific features from :help feature-list:

macunix                 Macintosh version of Vim, using Unix files (OS-X).
unix                    Unix version of Vim.
win32                   Win32 version of Vim (MS-Windows 95 and later, 32 or
                        64 bits)
win32unix               Win32 version of Vim, using Unix files (Cygwin)

And some older (semi-deprecated) systems:

amiga                   Amiga version of Vim.
os2                     OS/2 version of Vim.
win16                   Win16 version of Vim (MS-Windows 3.1).
win64                   Win64 version of Vim (MS-Windows 64 bit).
win95                   Win32 version for MS-Windows 95/98/ME.

Example:

if has('win32')
    echo "Someone please open the Window(s)!"
endif

An alternative way with more flexibility is to call the external uname, this also allows you to get the version number and such:

let uname = system('uname -a')

Note that uname isn't present on most Windows systems.

It's generally best to use feature detection, rather than OS detection. For example by using one of the features in has() or checking if some path exists. 200_success' post gives a good overview of that, so I'll not repeat the same content here.

Martin Tournoij
  • 62,054
  • 25
  • 192
  • 271
39

has() sounds like a good idea until you try it on Mac OS X: in the default /usr/bin/vim, has('unix') is true but both has('macunix') and has('mac') are false while, in the regular MacVim download, all three are true whether you use the GUI or the TUI.

So the best solution is a mix of has('winXX') for Windows and uname on unix-like systems. Note that the output of uname ends with a newline so it must be cleaned before use.

Here is the code I've been using for a while, updated for win64:

if !exists("g:os")
    if has("win64") || has("win32") || has("win16")
        let g:os = "Windows"
    else
        let g:os = substitute(system('uname'), '\n', '', '')
    endif
endif

After that, you can use the g:os variable anywhere in your vimrc:

if has("gui_running")
    if g:os == "Darwin"
        set guifont=Fira\ Mono:h12
    elseif g:os == "Linux"
        set guifont=Fira\ Mono\ 10
    elseif g:os == "Windows"
        set guifont=Fira_Mono:h12:cANSI
    endif
endif
romainl
  • 40,486
  • 5
  • 85
  • 117
  • 1
    Well, OSX is a UNIX system, I believe it's even "certified UNIX". So has('unix') is accurate. It's odd that has('macunix') is false, though. This almost sounds like a bug? – Martin Tournoij Mar 16 '15 at 10:48
  • 2
    I did some checking, and has('macunix') seems to depend on MACOS_X_UNIX, which is set if uname is Darwin in the configure script... – Martin Tournoij Mar 16 '15 at 10:56
  • Oddly enough, has ("win32") seems to work for me even in 64-bit Vim. – Rich Mar 16 '15 at 14:29
  • 1
    @Rich Yes, and that's documented as such. This is really the sane thing to do, do you care if your app is 32 or 64 bits? I don't. The reason it's called 'win32', is because that's the name Microsoft choose for their Windows NT API. Naming things isn't Microsoft's strong point. – Martin Tournoij Mar 16 '15 at 16:55
  • @Carpetsmoker I agree it makes sense from pragmatism. If the documentation is using Win32 to mean "Windows API", though, what does it (and romainl) mean when it refers to "Win64"? – Rich Mar 16 '15 at 17:26
  • @Rich This is also in the documentation: "Win64 version of Vim (MS-Windows 64 bit)."... – Martin Tournoij Mar 16 '15 at 17:41
  • @Carpetsmoker I'm looking at the documentation. What I can't figure out is how you're interpreting it. To me, it's saying that win32 will be set on 32-bit Vim (regardless of what version of Windows it's running under), and that win64 will be set in 64-bit Vim. You're saying it means something different, but I can't figure out what. – Rich Mar 16 '15 at 18:06
  • 2
    has('unix') is also true on Windows Git Bash, so it's not very useful for distinguishing real unix from emulated. – wisbucky Jun 05 '18 at 09:45
  • 1
    @wisbucky why would you want to distinguish emulated unix? The emulator means to be compatible in the first place. – lilydjwg Aug 21 '21 at 12:26
  • What is the purpose to use if !exists("g:os") in the very beginning? – user90726 Aug 07 '22 at 07:28
  • 1
    @user90726, it is there to prevent the code from running each time you source your vimrc. It is not strictly necessary for the code to work. – romainl Aug 07 '22 at 08:54
8

Environment variables would be useful.

To detect tmux, you could check if !empty($TMUX) or if $TERM == 'screen'.

You can also deduce the operating system from environment variables such as $MACHTYPE (which is set by Bash) or $PATH.

To detect whether a feature such as TFS is installed, you can use the executable() function.

200_success
  • 9,549
  • 5
  • 51
  • 64
  • 1
    "$MACHTYPE (which is set by Bash)". Actually, if a variable is set by Bash, that means it is not an environment variable, and you will not be able to access it in vim simply with $MACHTYPE. You will have to do something like let machtype=system('echo -n $MACHTYPE') first. – wisbucky Jun 06 '18 at 00:02
5

As others have already indicated, a reliable detection can be tricky. Better not reinvent the wheel, so I'd like to mention the vim-misc library, which provides xolox#misc#os#is_mac() and xolox#misc#os#is_win() functions.

Ingo Karkat
  • 17,819
  • 1
  • 45
  • 61
3

I tried has('unix'), but I didn't find it helpful since all my Linux, Mac, and Windows Git Bash returned true for it.

I found uname to be suitable as it distinguishes between Linux, Mac, Windows, without too much granularity.

let uname = substitute(system('uname'), '\n', '', '')
" Example values: Linux, Darwin, MINGW64_NT-10.0, MINGW32_NT-6.1

if uname == 'Linux' || uname == 'Darwin'
    " do linux/mac command
else " windows
    " do windows command
endif
wisbucky
  • 950
  • 8
  • 6
1

I use this on my vimscript, currently on Vim v8.0:

if has("mac")
    "Mac
elseif has("win32")
    "all Windows, ie win32,win64
elseif has("win32unix")
    "Cygwin
elseif has("bsd")
    "BSD-based, ie freeBSD"
elseif has("linux")
    "Linux
end

This covers most of the OS, I hope. One should use has(feature) if possible, and avoid uname, since uname is not portable (ie not available on non-unix-like OS)

otter.pro
  • 498
  • 4
  • 11