8

I have a function definition in my .vimrc. This .vimrc is sufficient to demonstrate the problem I'm asking about:

function! Greet()
    echo "hello"
endfunction

I want to be able use the same .vimrc with a version of vim configured with

--with-features=tiny

I don't expect the function to be defined, but I don't want error messages on startup.

Currently, if I run a tiny vim, I get:

Error detected while processing /home/kst/.vimrc:
line    1:
E319: Sorry, the command is not available in this version: function! Greet()
line    2:
E319: Sorry, the command is not available in this version:     echo "hello"
line    3:
E319: Sorry, the command is not available in this version: endfunction
Press ENTER or type command to continue

I'm looking for something like:

if has("function")
    function! Greet()
        echo "hello"
   endfunction
endif

but that doesn't do the job because has() doesn't recognize "function". (The result is that the function definition is disabled even for versions of vim that support functions.)

I didn't see anything obvious in the documentation for has(), and web searches with the word "function" give me a lot of irrelevant hits.

Keith Thompson
  • 207
  • 1
  • 6

1 Answers1

15

The problem is that "tiny" is missing the +eval feature and that's what prevents it from seeing your function definitions.

So you could try something like:

if has('eval')
    function! Greet()
        echo "hello"
    endfunction
endif

But it turns out you can go even simpler than that, as :help no-eval-feature suggests:

When the +eval feature was disabled at compile time, none of the expression evaluation commands are available. To prevent this from causing Vim scripts to generate all kinds of errors, the :if and :endif commands are still recognized, though the argument of the :if and everything between the :if and the matching :endif is ignored. Nesting of :if blocks is allowed, but only if the commands are at the start of the line. The :else command is not recognized.

So you can simply use:

if 1
    function! Greet()
        echo "hello"
    endfunction
endif

(I strongly suggest adding a comment to indicate why you're using if 1, why it makes sense, why it's needed!)

Looking inside $VIMRUNTIME/defaults.vim, there's a snippet there that uses a hack to only run a command whenever +eval is not available. Adapting that to your specific case:

" Use a trick to break out when the
" +eval feature is missing.
silent! while 0
    finish
silent! endwhile

function! Greet()
    echo "hello"
endfunction

If +eval is missing, it won't recognize the while statement and will finish, breaking out of the script and skipping everything that follows.

When +eval is present, the while 0 block will be skipped, since the condition is false.

The :help no-eval-feature section also mentions this technique (with a different command as example) and explains it:

When the +eval feature is available the command is skipped because of the while 0. Without the +eval feature the while 0 is an error, which is silently ignored, and the command is executed.

filbranden
  • 28,785
  • 3
  • 26
  • 71
  • 4
    you can also use :if 1 tiny vim will not read anything in between this. – Christian Brabandt Jan 07 '20 at 07:25
  • @ChristianBrabandt I was in doubt whether tiny vim would ignore :if as a whole or just (complex) expressions... Why does the silent! while 0 work then? Is it because it's while and not if so vim-tiny doesn't ignore it? Why the silent!? – filbranden Jan 07 '20 at 07:34
  • 5
    the if 1 is the documented way how to make vim.tiny skip eval code (don't ask me where this is documented, don't find it currently) and this is also what defaults.vim used initially. The thing why silent! while 0 was needed, was because we wanted to run a piece of code only in tiny vim, but not a vim that has eval feature. So eval vims would skip that, while tiny vim does read it. Since tiny vim do not understand while, we needed :silent! to not show any error message. – Christian Brabandt Jan 07 '20 at 07:49
  • 2
    see also this issue: https://github.com/vim/vim/issues/1630 that lead to that part of the code. – Christian Brabandt Jan 07 '20 at 07:52
  • 4
    and the related help topic is :h no-eval-feature – Christian Brabandt Jan 07 '20 at 07:58
  • 1
    @ChristianBrabandt Both if has('eval') and if 1 work. I think the former works just because the expression is ignored. I'll use if 1. – Keith Thompson Jan 07 '20 at 18:37
  • 1
    Thanks @ChristianBrabandt and Keith! I'll update the answer to include more deatils (in particular the great reference to :h no-eval-feature!) Most likely later this evening or tomorrow. Thanks again for the great discussion! – filbranden Jan 07 '20 at 18:51
  • 1
    Confirmed with tiny, small, normal, big, and huge builds. The tiny and small builds don't support functions, and I don't get a diagnostic on startup. The normal, big, and huge builds do support functions, and the function is defined correctly. – Keith Thompson Jan 07 '20 at 19:36
  • Updated to include background on :help no-eval-feature, thanks @ChristianBrabandt for mentioning it! – filbranden Jan 08 '20 at 00:31