So i found the following vimscript code:

let s:mappings = {
        \ 'k': {id -> s:scroll_line(id, -1)},
        \ 'j': {id -> s:scroll_line(id, 1)},
        \ 'd': {id -> s:scroll_page(id, 0.5)},
        \ 'u': {id -> s:scroll_page(id, -0.5)},
        \ 'f': {id -> s:scroll_page(id, 1)},
        \ 'b': {id -> s:scroll_page(id, -1)},
        \ 'g': {id -> popup_setoptions(id, #{firstline: 1})},
        \ 'G': {id -> s:bottom(id)},
        \ 'q': {id -> popup_close(id)}
        \ }

function! s:scroll_line(winid, step) abort
    let line = popup_getoptions(a:winid).firstline
    if a:step < 0
        let newline = (line + a:step) > 0 ? (line + a:step) : 1
        let nlines = line('$', a:winid)
        let newline = (line + a:step) <= nlines ? (line + a:step) : nlines
    call popup_setoptions(a:winid, #{firstline: newline})

function! s:scroll_page(winid, size) abort
    let height = popup_getpos(a:winid).core_height
    let step = float2nr(height*a:size)
    call s:scroll_line(a:winid, step)

function! s:bottom(winid) abort
    let height = popup_getpos(a:winid).core_height
    let nlines = line('$', a:winid)
    let newline = (nlines - height) >= 0 ? (nlines - height + 1) : 1
    call popup_setoptions(a:winid, #{firstline: newline})

function! s:popup_filter(winid, key) abort
    if has_key(s:mappings, a:key)
        call get(s:mappings, a:key)(a:winid)
        return v:true
    return v:false

let text = range(50)->map({_,i -> string(i)})
call popup_create(text, #{
        \ minwidth: 40,
        \ maxwidth: 40,
        \ minheight: 8,
        \ maxheight: 8,
        \ firstline: 1,
        \ scrollbar: 1,
        \ mapping: v:false,
        \ filter: funcref('s:popup_filter')
        \ })

which run successfully if i run it with vim --clean popup.vim -c "source %" when put inside a file called popup.vim but fail if run by yanking and doing @", with the following error E120: Using <SID> not in a script context: s:scroll_line.

I basically want to run it in the commandline, so i can do faster testing when adding/removing code, instead of saving/opening the file it reside at...(eg: fast prototyping etc)

How can i run this snippet on the Vim commandline?

1 Answer 1


TL;DR: Use :source % instead.

Local functions and variables are indeed a limitation of the :@ approach. As I actually mentioned in my answer to your previous question:

There are some limitations, such as you can't define local functions and variables (in the s: namespace.)

If you want to be able to only load parts of it using the :@ command, then you should turn the functions into global functions (without the s:, and starting with an uppercase letter), or perhaps using a namespace autoload-style function name will work (as in mylinenumbers#scroll_page, etc.) In either case, you'll have to go through all the call sites for every function to adapt them to the new style, which is not great...

Since you're editing them from a *.vim file, though, perhaps the best approach is to reload it using :source % every time you want to reload it. I don't see any reason why this wouldn't work, in fact I'd say that's probably the easiest approach of all.

  • 2
    Or :Runtime, if you use tpope/scriptease.
    – D. Ben Knoble
    Commented Sep 15, 2020 at 0:39
  • Using :source % was fine until i noticed you had to save first for it to work :/. At least i can make a mapping out of it that save first, and using tpope's scriptease work great too, as an alternative. Commented Sep 16, 2020 at 19:25
  • 1
    Actually it seems like :Runtime need the file to be saved first (afaik). Guess I'll post something related to that. :D Commented Sep 16, 2020 at 19:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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