astro.vim 5.5 KB

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