I've tried to convince vim to parse my import statements in EcmaScript modules. My goal is to use vim's native include-search (and definition search) tools without tags with vanilla EcmaScript. Though the language is of little concern. The point is, these import statements (i.e. includes) are often relative and arbitrarily deep.
I have started writing a vimscript that somewhat solves the problem - not always, but it's probably buggy and may be improved - but it is terrible guess work and certainly not a good solution. I'm missing one piece of information to solve this and that is:
What's the path of the file in which the import(/include) statement was found, that I'm currently processing in my includeexpr?
I've checked all defined variables and registers but with no luck. Is it possible to solve this?
Finally, here's what I currently have. Maybe you see another/better way of doing this that I missed:
let &l:include = '\(from\s*\("\|''\)\zs[^''"]\+\)\|\(require(\zs[^)]\+\)' let &l:define = '\v(export\s+(default\s+)?)?(var|let|const|function|class)|export\s+' let &l:includeexpr = 'JsIncludeExpr(v:fname)' let s:lastFile =  function! JsIncludeExpr(file) if(!empty(s:lastFile)) for f in reverse(copy(s:lastFile)) let l:file = JsIncludeExpr2(a:file, f) if(!empty(l:file)) let s:lastFile = s:lastFile[0:index(s:lastFile, f)] + [l:file] return l:file endif endfor endif let l:file = JsIncludeExpr2(a:file, @%) if(!empty(l:file)) let s:lastFile = [l:file] return l:file endif endfunction function! JsIncludeExpr2(file, parent) let l:dir = substitute(a:parent, '\/[^/]\+$', '', 'g') " echom 'JsIncludeExpr ' . a:file . ' ' . l:dir if (a:file =~ '^\/') let l:topDir = substitute(substitute(a:file, '^/', '', 'g'), '/.*$', '', 'g') let l:prefixDir = finddir(l:topDir, l:dir . '/;') let l:postfix = substitute(a:file, '/' . l:topDir, '', 'g') if(!empty(l:prefixDir) && filereadable(l:prefixDir . l:postfix)) return l:prefixDir . l:postfix endif elseif (a:file =~ '^\.\/') let l:file = l:dir . substitute(a:file, '^\.', '', 'g') if (filereadable(l:file)) return l:file endif endif endfunction
It works like this: When it successfully resolves an import it assumes the next import will be inside of that file, so it remembers the stack of previous parent files and adds to that stack/removes from it as appropriate (assuming no bugs).