[vim/vim] How to implement vim9 and non-vim9 scripts together (#7851)

156 views
Skip to first unread message

rickhowe

unread,
Feb 15, 2021, 9:30:54 AM2/15/21
to vim/vim, Subscribed

I am modifying some functions in my script to work on different vim versions. For example, the following Add() works fine on the latest vim which has vim9 feature,

 1  if !exists(':def')
 2      function! Add(x, y)
 3          return a:x + a:y
 4      endfunction
 5  else
 6      def! Add(x: number, y: number): number
 7          return x + y
 8      enddef
 9  endif
10
11  echo Add(3, 5)

But on the old vim which does not have it, an error message is shown.

Line    7:
E133: :return not inside a function

I am wondering why vim checks the line 7. Is there a good approach to avoid the error? And is exists(':def') appropriate to check if vim9 or non-vim9?


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.

lacygoill

unread,
Feb 15, 2021, 9:50:27 AM2/15/21
to vim/vim, Subscribed

There might be a better way, but in the meantime, try this:

if exists(':def') != 2
    fu Add(x, y) abort
        return a:x + a:y
    endfu
else
    fu DefineAdd() abort
        def Add(x: number, y: number): number
            return x + y
        enddef
    endfu
    call DefineAdd()
endif

echo Add(3, 5)

Christian Brabandt

unread,
Feb 15, 2021, 9:54:38 AM2/15/21
to vim/vim, Subscribed

I think you can put a finish just before the else

rdcx...@ybb.ne.jp

unread,
Feb 16, 2021, 4:05:00 AM2/16/21
to vim_dev
That  works fine. Thank you.

bfrg

unread,
Feb 16, 2021, 9:12:05 PM2/16/21
to vim/vim, Subscribed

Using something like exists(':def') != 2 is probably not enough because :def was added pretty early, but there have been hundreds of bugs some of which might crash your Vim. I'd be very careful using vim9script in older Vim versions. Better use has('patch-8.2.XXXX') instead.

It is probably easier to separate the two versions into two files IMO, something like:

" File: plugin/calc.vim
if has('patch-8.2.XXXX')
    command -bar Calculator call calc9#run(<q-args>)
else
    command -bar Calculator call calc#run(<q-args>)
endif

And then put the vim9script version into the file autoload/calc9.vim whereas the legacy version using :function into autoload/calc.vim. The same check can be done for mappings and autocommands.

rickhowe

unread,
Feb 17, 2021, 8:13:21 AM2/17/21
to vim/vim, Subscribed

Yes, vim9script is still under development. It is too early to release the script. Meanwhile, we can enjoy to implement the script using exists(':def') for different vim versions.

When it becomes officially available, I would expect that something like 'vim9script' is to be included in the feature-list, then we can check using has().

Separating into two files might be an ideal approach. But mixing them in a single file still can be attractive depending on the script. In my case, only time consuming/sensitive parts are to be implemented in both vim9 and legacy scripts in one file.

Bram Moolenaar

unread,
Feb 17, 2021, 10:22:43 AM2/17/21
to vim/vim, Subscribed

For small scripts it would be convenient to be able to keep using one file. Perhaps we can allow for "vim9script" after an if/endif block that is not executed. Thus if/endif itself would not count as a command when encountering "vim9script". Then this should work:

if !has('vim9script')
   ... legacy script implementation
  finish
endif
vim9script
... vim9script implementation

Bram Moolenaar

unread,
Feb 17, 2021, 3:57:45 PM2/17/21
to vim/vim, Subscribed

Closed #7851 via d3f8a9e.

rickhowe

unread,
May 3, 2022, 12:22:31 AM5/3/22
to vim/vim, Subscribed

Hi, again.
As lacygoill mentioned above, has('vim9script') is available now and the following is still usable ad convenient on the latest 8.2.

if !has('vim9script')
    fu Add(x, y) abort
        return a:x + a:y
    endfu
else
    fu DefineAdd() abort
        def Add(x: number, y: number): number
            return x + y
        enddef
    endfu
    call DefineAdd()
endif

But it is not described in vim9-mix. Is there any regression or disadvantage on it?


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/7851/1115728941@github.com>

Bram Moolenaar

unread,
May 4, 2022, 2:33:56 PM5/4/22
to vim/vim, Subscribed

The help at "vim9-mix" shows the preferred way to do this. I'm not sure why you would use this if/else construct, defining a :def function inside a legacy function (to be able to skip over the unknown :def command in an old Vim version). It looks more complicated.


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/7851/1117672847@github.com>

rickhowe

unread,
May 5, 2022, 11:15:21 PM5/5/22
to vim/vim, Subscribed

Thank you for your reply. A main reason is defining not all but a few time-consuming functions in both legacy and vim9 scripts, on each different place, in a plugin/autoload file. Using :finish command, as described in "vim9-mix", does not allow to do that. I would like to make sure if that approach does not have any problem and negative impact. Or I would like to know if there would be more useful approach.


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/7851/1119223598@github.com>

Christian Brabandt

unread,
May 6, 2022, 2:08:55 AM5/6/22
to vim/vim, Subscribed

FWIW: I am using this in vim-airline: https://github.com/vim-airline/vim-airline/blob/master/autoload/airline/highlighter.vim So far, I haven't heard any complaints


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/7851/1119288551@github.com>

rickhowe

unread,
May 6, 2022, 5:21:23 AM5/6/22
to vim/vim, Subscribed

Yes, that is a good option. But in my plugin, something like cpo restoring is needed at the end. So I am looking for another good option in which :finish command is not necessary


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/7851/1119420629@github.com>

Bram Moolenaar

unread,
May 6, 2022, 7:23:38 AM5/6/22
to vim/vim, Subscribed

Perhaps you can move some code to another script file, where items are exported, and using "import" in the main script file.


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/7851/1119514110@github.com>

rickhowe

unread,
May 7, 2022, 11:35:34 PM5/7/22
to vim/vim, Subscribed

Like this, how would you think to mention another way in vim9-mix?

There is another way to define both syntax in any place in one script file:

" legacy script commands go here
...
if has('vim9script')
  function DefineVim9script()
    # Vim9 script commands go here
  endfunction
  call DefineVim9script()
endif

To replace the existing legacy functions, ":def!" should be used and overwrite them in the Vim9 script.


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/7851/1120342847@github.com>

rickhowe

unread,
May 8, 2022, 12:11:59 AM5/8/22
to vim/vim, Subscribed

Like this, how would you think to mention another way in the vim9-mix?
(I reposted this. sorry if my previous post was not deleted.)

There is another way to define functions in both syntax in one script file:

function ABC()
  " legacy script commands go here
endfunction
...
if has('vim9script')
  function DefineVim9script()
    def! ABC()
      # Vim9 script commands go here
    enddef
  endfunction
  call DefineVim9script()
endif

Note that ":def!" should be used to overwrite the legacy functions.


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/7851/1120346248@github.com>

Reply all
Reply to author
Forward
0 new messages