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