3

I want to organize my vimrc better, so I want to put all the custom functions at bottom:

"different setting between different os
if MyDetectOS() ==? "windows"
    set rtp+=~/vimfiles/bundle/Vundle.vim/
    let path='~/vimfiles/bundle'
else 
    set rtp+=~/.vim/bundle/Vundle.vim
endif
if MyDetectOS() ==? "linux" 
    set clipboard=unnamedplus
else
    set clipboard=unnamed
endif



function! MyDetectOS()
    if has("win32") || has("win16") || has("win64")
        return "windows"
    elseif has("mac") || has("macunix")
        return "mac"
    elseif has("win32unix")
        return "cygwin"
    elseif has("unix")
        let l:uname = substitute(system("uname"), '\n', '', '')
        if l:uname ==? "linux"
            return "linux"
        else
            return "unix"
        endif
    endif
endfunction

If I put the MyDetectOS function at bottom like above. Then I'll get errors like below:

E117: Unknown function: MyDetectOS
E15: Invalid expression: MyDetectOS() ==? "linux"

Why it doesn't work?

2

The way to understand this is that a function decleration is just an assignment, similar to x = 2.

So when you do:

function! MyDetectOS()
    [...]
endfunction

You're really just doing:

MyDetectOS = function!
    [...]
endfunction

So it doesn't work for the same reason that something like this doesn't work:

a = 40 + b
b = 2

The reason that it does work in some languages, is that those languages use a more advanced parser; they will first look for all functions and assign references to them, and then do a second pass where the code is actually executed with those references in place. Note that neither method can be considered "better" than the other; the simpler method is more flexible in some ways and suited for functional programming, the more complex allows you to not worry so much about the order of code and is somewhat less surprising for some.

One technique that you can use to "get around" this is put most code in a function, and kick that off at the end:

function! Main()
    if MyDetectOS() ==? "windows"
        [...]
    endif
endfunction

function! MyDetectOS()
    [...]
endfunction

Main()

This way the entire file is read, before the actual code is being executed.

An alternative method putting your functions in a seperate file, and then use source to include that:

source ~/.vim/functions.vim

if MyDetectOS() ==? "windows"
    [...]
endif
3

Vim has a neat mechanism that allows you to put all your custom functions in an autoload directory somewhere in your $RUNTIMEPATH and source them only when needed.

  1. Move all your custom functions to ~/.vim/autoload/myfunctions.vim.

  2. Rename them:

    function! MyDetectOS()    ===>    function myfunctions#MyDetectOS()
    
  3. Change all your calls to use the new name:

    if myfunctions#MyDetectOS() ==? "linux"
    

One benefit is that functions are not sourced before their first call so that's less work for Vim on startup. Of course, your example is called in your vimrc so that's a moot point.

Another — more obvious — one is that you have less stuff in your vimrc.

See :help autoload.

1

The error says it all:

E117: Unknown function: MyDetectOS

You can't call a function that has not been defined yet. Move the definition of the function above the point where it is first used.

  • That's why I asked this question, I want to put all custom function at bottom. I see a lot of vimrc files online, they all put it at bottom. But it doesn't work for me. – Aaron Shen Oct 18 '15 at 8:11
  • 1
    You can put functions at vimrc bottom, only if the functions are used later - e.g. when they are called in an autocmd event, which may be defined above. The important thing is that, at call time, vimrc was already parsed. That might have confused you. – VanLaser Oct 18 '15 at 8:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.