diff --git a/Makefile b/Makefile index de69007..b568a20 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,17 @@ test: dependencies vim -u test/vimrc -c 'Vader! test/*.vader' +manual-test: dependencies + vim -u test/vimrc_debug test + test-nvim: dependencies VADER_OUTPUT_FILE=/dev/stderr nvim -u test/vimrc -c 'Vader! test/*.vader' --headless +manual-test-nvim: dependencies + nvim -u test/vimrc_debug test + dependencies = \ + 'tpope/vim-scriptease' \ 'junegunn/vader.vim' \ 'cakebaker/scss-syntax.vim' \ 'digitaltoad/vim-pug' \ diff --git a/readme.md b/readme.md index 99c48a0..4a9014d 100644 --- a/readme.md +++ b/readme.md @@ -40,6 +40,34 @@ and properly [configured](https://github.com/vuejs/eslint-plugin-vue#rocket-usag npm i -g eslint eslint-plugin-vue ``` +## Options + +### `g:vue_pre_processors` + +> default value: `'detect_on_enter'` + +This options controls which preprocessors' syntax will be included when you open a new vue file. So when you are using `scss` or `typescript`, the correct syntax highlighting will be applied. + +To disable pre-processor languages altogether (only highlight HTML, JavaScript, and CSS): + +```vim +let g:vue_pre_processors = [] +``` + +Available pre-processors are: `coffee`, `haml`, `handlebars`, `less`, `pug`, `sass`, `scss`, `slm`, `stylus`, `typescript`. + +When `g:vue_pre_processors` is set to `'detect_on_enter'` instead of a list, vim-vue will detect the pre-processors used when a file is opened, and load only their syntax files. + +```vim +let g:vue_pre_processors = 'detect_on_enter' +``` + +This is the default behavior. This also matches how vim natively detects syntaxes, for example, when you create a new file and start typing, you wont see the correct syntax until you save the file under a extension so that vim can detect which syntax to load. The 'detect_on_enter' is similar. + +When you want vim-vue to detect a new syntax you just typed, just turn the syntax off (`:syntax off`) and on again (`:syntax on`). + +Loading all syntaxes by default is not recommended because doing so slows down vim quite allot due to the multiple syntax highlighting checks that are done. Also, having multiple syntaxes for the `template` tag loaded at the same time, may result in the `js` syntax in the template (like `:value="variable"`) malfunction (see #150 for details). + ## Contributing If your language is not getting highlighted open an issue or a PR with the fix. @@ -101,22 +129,11 @@ endfunction ### _Vim slows down when using this plugin_ How can I fix that? -When checking for pre-processor languages, multiple syntax highlighting checks are done, which can slow down vim. You can trim down which pre-processors to use by setting `g:vue_pre_processors` to a whitelist of languages to support: - -```vim -let g:vue_pre_processors = ['pug', 'scss'] -``` - -To disable pre-processor languages altogether (only highlight HTML, JavaScript, and CSS): - -```vim -let g:vue_pre_processors = [] -``` -Available pre-processors are: coffee, haml, handlebars, less, pug, sass, scss, slm, stylus, typescript +> This was more of a problem when the default value of 'g:vue_pre_processors' was to load all pre-processors available, now that this is not the case, this problem shouldn't happen. That said, if you still are having problems, try setting `let g:vue_pre_processors = []`, see if it helps. Read the section on this option above for more information. -When `g:vue_pre_processors` is set to 'detect_on_enter' instead of a list, vim-vue will detect the pre-processors used when a file is opened, and load only their syntax files. +When checking for pre-processor languages, multiple syntax highlighting checks are done, which can slow down vim. You can trim down which pre-processors to use by setting `g:vue_pre_processors` to a whitelist of languages to support: ```vim -let g:vue_pre_processors = 'detect_on_enter' +let g:vue_pre_processors = ['pug', 'scss'] ``` diff --git a/syntax/vue.vim b/syntax/vue.vim index 56cdf33..082ed81 100644 --- a/syntax/vue.vim +++ b/syntax/vue.vim @@ -11,6 +11,11 @@ if exists('g:vue_disable_pre_processors') && g:vue_disable_pre_processors let g:vue_pre_processors = [] endif +" If not exist, set the default value +if !exists('g:vue_pre_processors') + let g:vue_pre_processors = 'detect_on_enter' +endif + runtime! syntax/html.vim syntax clear htmlTagName syntax match htmlTagName contained "\<[a-zA-Z0-9:-]*\>" @@ -39,6 +44,49 @@ function! s:should_register(language, start_pattern) return 1 endfunction +" define the cluster that will be applied inside the template tag where +" javascript is ran by vue, this is defined so it can be redefined with other +" scripting languages such as typescript if the .vue file uses a lang="ts" +syntax cluster TemplateScript contains=@jsAll + +syn region vueSurroundingTag contained start=+<\(script\|style\|template\)+ end=+>+ fold contains=htmlTagN,htmlString,htmlArg,htmlValue,htmlTagError,htmlEvent +syn keyword htmlSpecialTagName contained template +syn keyword htmlArg contained scoped ts +syn match htmlArg "[@#v:a-z][-:.0-9_a-z]*\>" contained + +" for mustaches quotes (`{{` and `}}`) +syn region vueTemplateScript matchgroup=htmlSpecialChar start=/{{/ keepend end=/}}/ contains=@TemplateScript containedin=ALLBUT,htmlComment + +" template_script_in_* region {{{ +""""" +" if you want to add script highlighting support for a specific template +" language, you should do it in this region (marked by the {{{fold marks}}}) +" named "s:template_script_in_", the "" must match the name +" declared on the "s:languages" array (later in the file) + +function! s:template_script_in_html() + " Prevent 0 length vue dynamic attributes (:id="") from overflowing from + " the area described by two quotes ("" or '') this works because syntax + " defined earlier in the file have priority. + syn match htmlString /\(\([@#:]\|v-\)[-:.0-9_a-z\[\]]*=\)\@<=\(""\|''\)/ containedin=ALLBUT,htmlComment + + " Actually provide the JavaScript syntax highlighting. + + " for double quotes (") and for single quotes (') + " It's necessary to have both because we can't start a region with double + " quotes and it with a single quote, and removing `keepend` would result in + " side effects. + syn region vueTemplateScript start=/\(\s\([@#:]\|v-\)\([-:.0-9_a-z]*\|\[.*\]\)=\)\@<="/ms=e+1 keepend end=/"/me=s-1 contains=@TemplateScript containedin=ALLBUT,htmlComment + syn region vueTemplateScript start=/\(\s\([@#:]\|v-\)\([-:.0-9_a-z]*\|\[.*\]\)=\)\@<='/ms=e+1 keepend end=/'/me=s-1 contains=@TemplateScript containedin=ALLBUT,htmlComment + " This one is for #[thisHere] @[thisHereToo] :[thisHereAlso] + syn region vueTemplateScript matchgroup=htmlArg start=/[@#:]\[/ keepend end=/\]/ contains=@TemplateScript containedin=ALLBUT,htmlComment +endfunction +" }}} + +" Eager load template script highlighting for html because it's already being +" loaded as the base for the .vue syntax highlighting. +call s:template_script_in_html() + let s:languages = [ \ {'name': 'less', 'tag': 'style'}, \ {'name': 'pug', 'tag': 'template', 'attr_pattern': s:attr('lang', '\%(pug\|jade\)')}, @@ -65,14 +113,21 @@ for s:language in s:languages \ 'end=""me=s-1' \ 'contains=@' . s:language.name . ',vueSurroundingTag' \ 'fold' + + if (s:language.tag == 'script') + syntax clear @TemplateScript + execute 'syntax cluster TemplateScript contains=@'.s:language.name + endif + + " if function exists, call it + if (exists('*s:template_script_in_' . s:language.name)) + execute 'call s:template_script_in_' . s:language.name . '()' + endif endif endfor -syn region vueSurroundingTag contained start=+<\(script\|style\|template\)+ end=+>+ fold contains=htmlTagN,htmlString,htmlArg,htmlValue,htmlTagError,htmlEvent -syn keyword htmlSpecialTagName contained template -syn keyword htmlArg contained scoped ts -syn match htmlArg "[@v:][-:.0-9_a-z]*\>" contained - syntax sync fromstart let b:current_syntax = "vue" + +" vim: et tw=80 sts=2 fdm=marker diff --git a/test/test_indent.vader b/test/test_indent.vader index efaafb7..e8a3955 100644 --- a/test/test_indent.vader +++ b/test/test_indent.vader @@ -1,3 +1,6 @@ +Before: + let g:vue_pre_processors = 'all' + # # HTML # diff --git a/test/test_syntax.vader b/test/test_syntax.vader index 7819b3b..a044e45 100644 --- a/test/test_syntax.vader +++ b/test/test_syntax.vader @@ -1,3 +1,5 @@ +Before: + let g:vue_pre_processors="all" # # HTML # @@ -27,7 +29,7 @@ Execute (Syntax doesn't stop at the first closing template tag): # # JavaScript # -Given vue: +Given vue (Recognizes javascript syntax with bare script tag): diff --git a/test/test_syntax_template_scripts.vader b/test/test_syntax_template_scripts.vader new file mode 100644 index 0000000..58699e0 --- /dev/null +++ b/test/test_syntax_template_scripts.vader @@ -0,0 +1,123 @@ +Before: + let g:vue_pre_processors="detect_on_enter" +# +# HTML +# +Given vue (HTML directives); + + +Execute (refresh detect_on_enter): + syntax off + syntax on + +Then (expect vue directives to be highlighted as htmlArg and it's value to be highlighted as script): + AssertEqual 'htmlTag', SyntaxAt(2, 10) + AssertEqual 'vueTemplateScript', SyntaxAt(2, 19) + +Given vue (HTML slots); + + +Execute (refresh detect_on_enter): + syntax off + syntax on + +Then (expect dynamic slots and slot scopes to be script highlighted): + AssertEqual 'htmlArg', SyntaxAt(3, 5) + AssertEqual 'htmlArg', SyntaxAt(4, 5) + AssertEqual 'vueTemplateScript', SyntaxAt(3, 15) + AssertEqual 'vueTemplateScript', SyntaxAt(4, 7) + AssertEqual 'vueTemplateScript', SyntaxAt(4, 24) + +Given vue (HTML events); + + +Execute (refresh detect_on_enter): + syntax off + syntax on + +Then (expect dynamic events and event callbacks to be script highlighted): + AssertEqual 'htmlArg', SyntaxAt(3, 5) + AssertEqual 'htmlArg', SyntaxAt(4, 5) + AssertEqual 'vueTemplateScript', SyntaxAt(3, 13) + AssertEqual 'vueTemplateScript', SyntaxAt(4, 7) + AssertEqual 'vueTemplateScript', SyntaxAt(4, 33) + +Given vue (HTML attributes and props); + + +Execute (refresh detect_on_enter): + syntax off + syntax on + +Then (expect dynamic bindings and binding values to be script highlighted but static props and args to be htmlString): +# dynamic and static props + AssertEqual 'htmlArg', SyntaxAt(3, 5) + AssertEqual 'htmlArg', SyntaxAt(4, 5) + AssertEqual 'htmlArg', SyntaxAt(5, 5) + AssertEqual 'vueTemplateScript', SyntaxAt(3, 13) + AssertEqual 'vueTemplateScript', SyntaxAt(4, 7) + AssertEqual 'vueTemplateScript', SyntaxAt(4, 18) +# variant tabindex + AssertEqual 'htmlArg', SyntaxAt(5, 5) + AssertEqual 'htmlArg', SyntaxAt(6, 5) +# both types of string + AssertEqual 'htmlString', SyntaxAt(3, 12) + AssertEqual 'htmlString', SyntaxAt(6, 16) + AssertEqual 'htmlString', SyntaxAt(4, 17) + AssertEqual 'htmlString', SyntaxAt(7, 16) + +Given vue (HTML mustaches syntax); + + +Execute (refresh detect_on_enter): + syntax off + syntax on + +Then (expect inside of a mustache to be script highlighted): + AssertEqual 'htmlSpecialChar', SyntaxAt(3, 9) + AssertEqual 'vueTemplateScript', SyntaxAt(3, 11) + +Given vue (HTML with typescript); + + + +Execute (refresh detect_on_enter): + syntax off + syntax on + +Then (Expect typescript highlighting to be present in the template): + AssertEqual 'htmlSpecialChar', SyntaxAt(3, 9) + AssertEqual 'typescriptImport', SyntaxAt(7, 1) + AssertEqual 'vueTemplateScript', SyntaxAt(3, 11) + AssertEqual 'typescriptPredefinedType', SyntaxAt(3, 31) diff --git a/test/vimrc_debug b/test/vimrc_debug new file mode 100644 index 0000000..b670d4e --- /dev/null +++ b/test/vimrc_debug @@ -0,0 +1,4 @@ +source test/vimrc + +" Allow inspection of syntax +map ZI ScripteaseSynnames