Skip to content

Instantly share code, notes, and snippets.

@tyru
Last active Jul 2, 2019
Embed
What would you like to do?
require() function for deeply nested very loooooooooong named autoload function
let s:L = vital#of('vital').import('Data.List')
function! s:require(ns, ...) abort
let ns = strtrans(a:ns)
let fnlist = map(
\ split(execute('function /' . ns), '\n'),
\ {_,l -> matchstr(l, '^function ' . ns . '#\zs\w\+\ze(')}
\)
call filter(fnlist, '!empty(v:val)')
if a:0
let nofuncs = filter(copy(a:1), {_,fn -> index(fnlist, fn) is -1})
if !empty(nofuncs)
" TODO: show multiple func name at once?
throw printf('Exxx: Unknown function in %s: %s', ns, nofuncs[0])
endif
return map(fnlist, {_,fn -> function(ns . '#' . fn)})
endif
let d = {}
for fn in fnlist
let d[fn] = function(ns . '#' . fn)
endfor
return d
endfunction
let v:errors = []
" vital#of('vital').import('Data.List').pop([1,2,3])
call assert_equal(function('vital#of'), s:require('vital').of)
call assert_equal(3, s:require('vital').of('vital').import('Data.List').pop([1,2,3]))
call assert_equal([function('vital#of')], s:require('vital', ['of']))
call assert_equal(3, s:require('vital', ['of'])[0]('vital').import('Data.List').pop([1,2,3]))
try
call s:require('vital', ['xxx'])
call assert_true(0, 'Exxx was not thrown')
catch
call assert_exception('Exxx:')
endtry
echohl ErrorMsg
for s:_ in v:errors
echo s:_
endfor
echohl None
@lambdalisue
Copy link

lambdalisue commented Jul 2, 2019

こんなんどうでしょう? Vital 依存無くして簡易化したやつ

let s:name = fnamemodify(expand('<sfile>:p'), ':t:r')

function! z#_#require(path) abort
  let l:prefix = printf('z#%s#%s', s:name, a:path)
  let l:script = printf(
        \ 'autoload/%s.vim',
        \ substitute(l:prefix, '#', '/', 'g')
        \)
  execute printf(
        \ 'runtime! %s',
        \ fnameescape(s:from_slash(l:script)),
        \)
  let l:fnames = map(
        \ split(execute('function /' . l:prefix), '\n'),
        \ { -> matchstr(v:val, '^function \zs[a-zA-Z0-9_#]\+\ze(') }
        \)
  let l:module = {}
  for l:fname in filter(l:fnames, '!empty(v:val)')
    let l:name = matchstr(l:fname, '.*#\zs[a-zA-Z0-9_]\+')
    let l:module[l:name] = funcref(l:fname)
  endfor
  return l:module
endfunction

function! s:from_slash(path) abort
  return fnamemodify(a:path, 'gs?/?\\?')
endfunction

@tyru
Copy link
Author

tyru commented Jul 2, 2019

あ、すみません。
冒頭で vital import してますがその後使ってないです (issue にあげるために依存切った)。

簡易化いいですね。
というか今気づきましたが自分のバージョンだとスクリプトがロードされてない場合に対処できてないですね。
あざます。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment