astro.vim (5926B)
1 " Vim filetype plugin file 2 " Language: Astro 3 " Maintainer: Romain Lafourcade <romainlafourcade@gmail.com> 4 " Last Change: 2024 Apr 21 5 " 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring') 6 " 2025 Aug 29 by Vim project, add try/catch around json_decode(), #18141 7 8 if exists("b:did_ftplugin") 9 finish 10 endif 11 let b:did_ftplugin = 1 12 13 let s:cpo_save = &cpo 14 set cpo-=C 15 16 function! s:IdentifyScope(start, end) abort 17 let pos_start = searchpairpos(a:start, '', a:end, 'bnW') 18 let pos_end = searchpairpos(a:start, '', a:end, 'nW') 19 20 return pos_start != [0, 0] 21 \ && pos_end != [0, 0] 22 \ && pos_start[0] != getpos('.')[1] 23 endfunction 24 25 function! s:AstroComments() abort 26 if s:IdentifyScope('^---\n\s*\S', '^---\n\n') 27 \ || s:IdentifyScope('^\s*<script', '^\s*<\/script>') 28 " ECMAScript comments 29 setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// 30 setlocal commentstring=//\ %s 31 32 elseif s:IdentifyScope('^\s*<style', '^\s*<\/style>') 33 " CSS comments 34 setlocal comments=s1:/*,mb:*,ex:*/ 35 setlocal commentstring=/*\ %s\ */ 36 37 else 38 " HTML comments 39 setlocal comments=s:<!--,m:\ \ \ \ ,e:--> 40 setlocal commentstring=<!--\ %s\ --> 41 endif 42 endfunction 43 44 " https://code.visualstudio.com/docs/languages/jsconfig 45 function! s:CollectPathsFromConfig() abort 46 let config_json = findfile('tsconfig.json', '.;') 47 48 if empty(config_json) 49 let config_json = findfile('jsconfig.json', '.;') 50 51 if empty(config_json) 52 return 53 endif 54 endif 55 56 try 57 let paths_from_config = config_json 58 \ ->readfile() 59 \ ->filter({ _, val -> val =~ '^\s*[\[\]{}"0-9]' }) 60 \ ->join() 61 \ ->json_decode() 62 \ ->get('compilerOptions', {}) 63 \ ->get('paths', {}) 64 catch /^Vim\%((\a\+)\)\=:E491:/ " invalid json 65 let paths_from_config = {} 66 catch /^Vim\%((\a\+)\)\=:E474:/ " invalid json in Nvim 67 let paths_from_config = {} 68 endtry 69 70 if !empty(paths_from_config) 71 let b:astro_paths = paths_from_config 72 \ ->map({key, val -> [ 73 \ key->glob2regpat(), 74 \ val[0]->substitute('\/\*$', '', '') 75 \ ]}) 76 \ ->values() 77 endif 78 79 let b:undo_ftplugin ..= " | unlet! b:astro_paths" 80 endfunction 81 82 function! s:AstroInclude(filename) abort 83 let decorated_filename = a:filename 84 \ ->substitute("^", "@", "") 85 86 let found_path = b: 87 \ ->get("astro_paths", []) 88 \ ->indexof({ key, val -> decorated_filename =~ val[0]}) 89 90 if found_path != -1 91 let alias = b:astro_paths[found_path][0] 92 let path = b:astro_paths[found_path][1] 93 \ ->substitute('\(\/\)*$', '/', '') 94 95 return decorated_filename 96 \ ->substitute(alias, path, '') 97 endif 98 99 return a:filename 100 endfunction 101 102 let b:undo_ftplugin = "setlocal" 103 \ .. " formatoptions<" 104 \ .. " path<" 105 \ .. " suffixesadd<" 106 \ .. " matchpairs<" 107 \ .. " comments<" 108 \ .. " commentstring<" 109 \ .. " iskeyword<" 110 \ .. " define<" 111 \ .. " include<" 112 \ .. " includeexpr<" 113 114 " Create self-resetting autocommand group 115 augroup Astro 116 autocmd! * <buffer> 117 augroup END 118 119 " Set 'formatoptions' to break comment lines but not other lines, 120 " and insert the comment leader when hitting <CR> or using "o". 121 setlocal formatoptions-=t 122 setlocal formatoptions+=croql 123 124 " Remove irrelevant part of 'path'. 125 setlocal path-=/usr/include 126 127 " Seed 'path' with default directories for :find, gf, etc. 128 setlocal path+=src/** 129 setlocal path+=public/** 130 131 " Help Vim find extension-less filenames 132 let &l:suffixesadd = 133 \ ".astro" 134 \ .. ",.js,.jsx,.es,.es6,.cjs,.mjs,.jsm" 135 \ .. ",.json" 136 \ .. ",.scss,.sass,.css" 137 \ .. ",.svelte" 138 \ .. ",.ts,.tsx,.d.ts" 139 \ .. ",.vue" 140 141 " From $VIMRUNTIME/ftplugin/html.vim 142 setlocal matchpairs+=<:> 143 144 " Matchit configuration 145 if exists("loaded_matchit") 146 let b:match_ignorecase = 0 147 148 " From $VIMRUNTIME/ftplugin/javascript.vim 149 let b:match_words = 150 \ '\<do\>:\<while\>,' 151 \ .. '<\@<=\([^ \t>/]\+\)\%(\s\+[^>]*\%([^/]>\|$\)\|>\|$\):<\@<=/\1>,' 152 \ .. '<\@<=\%([^ \t>/]\+\)\%(\s\+[^/>]*\|$\):/>' 153 154 " From $VIMRUNTIME/ftplugin/html.vim 155 let b:match_words ..= 156 \ '<!--:-->,' 157 \ .. '<:>,' 158 \ .. '<\@<=[ou]l\>[^>]*\%(>\|$\):<\@<=li\>:<\@<=/[ou]l>,' 159 \ .. '<\@<=dl\>[^>]*\%(>\|$\):<\@<=d[td]\>:<\@<=/dl>,' 160 \ .. '<\@<=\([^/!][^ \t>]*\)[^>]*\%(>\|$\):<\@<=/\1>' 161 162 let b:undo_ftplugin ..= " | unlet! b:match_ignorecase b:match_words" 163 endif 164 165 " Change what constitutes a word, mainly useful for CSS/SASS 166 setlocal iskeyword+=- 167 setlocal iskeyword+=$ 168 setlocal iskeyword+=% 169 170 " Define paths/aliases for module resolution 171 call s:CollectPathsFromConfig() 172 173 " Find ESM imports 174 setlocal include=^\\s*\\(import\\\|import\\s\\+[^\/]\\+from\\)\\s\\+['\"] 175 176 " Process aliases if file can't be found 177 setlocal includeexpr=s:AstroInclude(v:fname) 178 179 " Set 'define' to a comprehensive value 180 " From $VIMRUNTIME/ftplugin/javascript.vim and 181 " $VIMRUNTIME/ftplugin/sass.vim 182 let &l:define = 183 \ '\(^\s*(*async\s\+function\|(*function\)' 184 \ .. '\|^\s*\(\*\|static\|async\|get\|set\|\i\+\.\)' 185 \ .. '\|^\s*\(\ze\i\+\)\(([^)]*).*{$\|\s*[:=,]\)' 186 187 188 " Set &comments and &commentstring according to current scope 189 autocmd Astro CursorMoved <buffer> call s:AstroComments() 190 191 let &cpo = s:cpo_save 192 unlet s:cpo_save 193 194 " vim: textwidth=78 tabstop=8 shiftwidth=4 softtabstop=4 expandtab