vue.vim 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. " Language: Vue
  2. " Maintainer: leaf <https://github.com/leafOfTree>
  3. " Credits: Inspired by mxw/vim-jsx.
  4. if exists('b:current_syntax') && b:current_syntax == 'vue'
  5. finish
  6. endif
  7. " <sfile> is replaced with the file name of the sourced file
  8. let s:patch_path = expand('<sfile>:p:h').'/patch'
  9. let s:test = exists('g:vim_vue_plugin_test')
  10. function! s:Init()
  11. """ Configs
  12. let s:config = vue#GetConfig('config', {})
  13. let s:config_syntax = s:config.syntax
  14. " For advanced users, it can be used to avoid overload
  15. let b:current_loading_main_syntax = 'vue'
  16. endfunction
  17. function! s:GetGroupNameForLoading(syntax)
  18. return '@'.a:syntax
  19. endfunction
  20. " Extend group name as
  21. " html defines group @htmlJavaScript and @htmlCss.
  22. " coffee defines group @coffeeJS.
  23. function! s:GetGroupNameForHighlight(syntax)
  24. let syntax = a:syntax
  25. let name = '@'.a:syntax
  26. if syntax == 'javascript'
  27. let name = '@javascript,@htmlJavaScript,@coffeeJS'
  28. elseif syntax == 'css'
  29. let name = '@css,@htmlCss'
  30. endif
  31. return name
  32. endfunction
  33. " Return name with format '<syntax><Tagname>Block'
  34. function! s:GetSynatxName(block, syntax)
  35. let block = a:block
  36. let syntax = a:syntax
  37. let name = syntax.toupper(block[0]).block[1:].'Block'
  38. let name = substitute(name, '-\(.\)', "\\U\\1", 'g')
  39. let name = vue#AlterSyntaxForEmmetVim(name, syntax)
  40. return name
  41. endfunction
  42. function! s:LoadSyntaxList(syntax_list)
  43. for syntax in a:syntax_list
  44. let loaded = s:BeforeLoadSyntax(syntax)
  45. if !loaded
  46. let syntax_group = s:GetGroupNameForLoading(syntax)
  47. call vue#LoadSyntax(syntax_group, syntax)
  48. endif
  49. call s:AfterLoadSyntax(syntax)
  50. endfor
  51. endfunction
  52. " For specific syntax, we need to handle it specially
  53. function! s:BeforeLoadSyntax(syntax)
  54. let syntax = a:syntax
  55. " Avoid overload if group already exists
  56. let loaded = 0
  57. if syntax == 'javascript'
  58. let loaded = hlexists('javaScriptComment')
  59. elseif syntax == 'css'
  60. let loaded = hlexists('cssTagName')
  61. endif
  62. return loaded
  63. endfunction
  64. function! s:AfterLoadSyntax(syntax)
  65. let syntax = a:syntax
  66. call s:LoadPatchSyntax(syntax)
  67. call s:LoadStyleAfterSyntax(syntax)
  68. endfunction
  69. function! s:LoadPatchSyntax(syntax)
  70. let file = s:patch_path.'/'.a:syntax.'.vim'
  71. if filereadable(file)
  72. execute 'syntax include '.file
  73. endif
  74. endfunction
  75. function! s:LoadStyleAfterSyntax(syntax)
  76. let syntax = a:syntax
  77. if count(['scss', 'sass', 'less', 'stylus'], syntax) == 1
  78. execute 'runtime! after/syntax/'.syntax.'.vim'
  79. endif
  80. endfunction
  81. function! s:GetSyntaxLangName(syntax)
  82. let syntax = a:syntax
  83. if syntax == 'typescript'
  84. let syntax = 'ts'
  85. endif
  86. return syntax
  87. endfunction
  88. function! s:SetSyntax(block, syntax, has_lang)
  89. let block = a:block
  90. let syntax = a:syntax
  91. let has_lang = a:has_lang
  92. let name = s:GetSynatxName(block, syntax)
  93. if has_lang
  94. let lang_name = s:GetSyntaxLangName(syntax)
  95. let lang = 'lang=["'']'.lang_name.'["'']'
  96. else
  97. let lang = ''
  98. endif
  99. let start = '^<'.block.'[^>]*'.lang
  100. let end_tag = '</'.block.'>'
  101. let end = '^'.end_tag
  102. let syntax_group = s:GetGroupNameForHighlight(syntax)
  103. " Block like
  104. " <script lang="ts">
  105. " ...
  106. " </script>
  107. execute 'syntax region '.name.' fold '
  108. \.' start=+'.start.'+'
  109. \.' end=+'.end.'+'
  110. \.' keepend contains='.syntax_group.', vueTag'
  111. execute 'syntax sync match vueSync groupthere '.name.' +'.start.'+'
  112. execute 'syntax sync match vueSync groupthere NONE +'.end.'+'
  113. " Block like <script src="...">...</script>
  114. let oneline = start.'.*'.end_tag
  115. execute 'syntax match '.name.' fold '
  116. \.' +'.oneline.'+'
  117. \.' keepend contains='.syntax_group.', vueTag, vueTagOneline'
  118. endfunction
  119. function! s:SetBlockSyntax(config_syntax)
  120. syntax sync clear
  121. for [block, syntax] in items(a:config_syntax)
  122. let type = type(syntax)
  123. if type == v:t_string
  124. call s:SetSyntax(block, syntax, 0)
  125. elseif type == v:t_list && len(syntax)
  126. call s:SetSyntax(block, syntax[0], 0)
  127. for syn in syntax
  128. call s:SetSyntax(block, syn, 1)
  129. endfor
  130. endif
  131. endfor
  132. endfunction
  133. function! s:HighlightVue()
  134. call s:HighlightVueTag()
  135. call s:HighlightVueStyle()
  136. endfunction
  137. function! s:HighlightVueTag()
  138. syntax region vueTag fold
  139. \ start=+^<[^/]+ end=+>+ skip=+></+
  140. \ contained contains=htmlTagN,htmlString,htmlArg
  141. syntax region vueTag
  142. \ start=+^</+ end=+>+
  143. \ contained contains=htmlTagN,htmlString,htmlArg
  144. syntax region vueTagOneline
  145. \ start=+</+ end=+>$+
  146. \ contained contains=htmlTagN,htmlString,htmlArg
  147. highlight default link vueTag htmlTag
  148. highlight default link vueTagOneline htmlTag
  149. endfunction
  150. function! s:HighlightVueStyle()
  151. syntax keyword cssPseudoClassId contained deep slotted global
  152. syntax region cssFunction contained matchgroup=cssFunctionName
  153. \ start="\<\(v-bind\)\s*(" end=")"
  154. \ contains=cssCustomProp,cssValue.*,cssFunction,cssColor,cssStringQ,cssStringQQ
  155. \ oneline
  156. endfunction
  157. function! s:SetIsKeyword()
  158. if has("patch-7.4-1142")
  159. if has("win32")
  160. syntax iskeyword @,48-57,_,128-167,224-235,$,-
  161. else
  162. syntax iskeyword @,48-57,_,192-255,$,-
  163. endif
  164. else
  165. setlocal iskeyword+=-
  166. endif
  167. endfunction
  168. function! s:SetCurrentSyntax()
  169. let b:current_syntax = 'vue'
  170. endfunction
  171. function! s:SetExtraSyntax()
  172. call s:SetIsKeyword()
  173. call s:HighlightVue()
  174. call s:SetCurrentSyntax()
  175. endfunction
  176. function! s:PostSetting()
  177. if exists('s:main_timer')
  178. unlet s:main_timer
  179. endif
  180. endfunction
  181. function! VimVuePluginSyntaxMain(...)
  182. call s:Init()
  183. let syntax_list = vue#GetSyntaxList(s:config_syntax)
  184. call s:LoadSyntaxList(syntax_list)
  185. call s:SetBlockSyntax(s:config_syntax)
  186. call s:SetExtraSyntax()
  187. call s:PostSetting()
  188. endfunction
  189. " Entry
  190. let s:timer = exists('*timer_start') && !exists('SessionLoad') && !s:test
  191. if s:timer
  192. if !exists('s:main_timer')
  193. let s:main_timer = timer_start(1, 'VimVuePluginSyntaxMain')
  194. endif
  195. else
  196. call VimVuePluginSyntaxMain()
  197. endif
  198. call s:SetCurrentSyntax()