Merge pull request #62 from posva/register-function

Add a register function that makes it easier to add new languages
This commit is contained in:
Adriaan Zonnenberg
2017-03-26 22:45:19 +02:00
committed by GitHub
10 changed files with 490 additions and 106 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/pack

10
circle.yml Normal file
View File

@@ -0,0 +1,10 @@
dependencies:
override:
- sudo add-apt-repository ppa:jonathonf/vim -y
- sudo apt-get update
- sudo apt-get install vim
- bash test/install.sh
test:
override:
- vim -u test/vimrc -c 'Vader! test/*.vader'

View File

@@ -3,39 +3,62 @@
" Maintainer: Eduardo San Martin Morote
" Author: Adriaan Zonnenberg
if exists("b:did_indent")
if exists('b:did_indent')
finish
endif
" Load indent files for required languages
for language in ['stylus', 'pug', 'css', 'javascript', 'html', 'coffee']
function! s:get_indentexpr(language)
unlet! b:did_indent
exe "runtime! indent/".language.".vim"
exe "let s:".language."indent = &indentexpr"
execute 'runtime! indent/' . a:language . '.vim'
return &indentexpr
endfunction
" The order is important here, tags without attributes go last.
" HTML is left out, it will be used when there is no match.
let s:languages = [
\ { 'name': 'pug', 'pairs': ['<template lang="pug"', '</template>'] },
\ { 'name': 'stylus', 'pairs': ['<style lang="stylus"', '</style>'] },
\ { 'name': 'css', 'pairs': ['<style', '</style>'] },
\ { 'name': 'coffee', 'pairs': ['<script lang="coffee"', '</script>'] },
\ { 'name': 'javascript', 'pairs': ['<script', '</script>'] },
\ ]
for language in s:languages
" Set 'indentexpr' if the user has an indent file installed for the language
if strlen(globpath(&rtp, 'indent/'. language.name .'.vim'))
let language.indentexpr = s:get_indentexpr(language.name)
endif
endfor
let s:html_indent = s:get_indentexpr('html')
let b:did_indent = 1
setlocal indentexpr=GetVueIndent()
if exists("*GetVueIndent")
if exists('*GetVueIndent')
finish
endif
function! GetVueIndent()
if searchpair('<template lang="pug"', '', '</template>', 'bWr')
exe "let indent = ".s:pugindent
elseif searchpair('<style lang="stylus"', '', '</style>', 'bWr')
exe "let indent = ".s:stylusindent
elseif searchpair('<style', '', '</style>', 'bWr')
exe "let indent = ".s:cssindent
elseif searchpair('<script lang="coffee"', '', '</script>', 'bWr')
exe "let indent = ".s:coffeeindent
elseif searchpair('<script', '', '</script>', 'bWr')
exe "let indent = ".s:javascriptindent
for language in s:languages
let opening_tag_line = searchpair(language.pairs[0], '', language.pairs[1], 'bWr')
if opening_tag_line
execute 'let indent = ' . get(language, 'indentexpr', -1)
break
endif
endfor
if exists('l:indent')
if (opening_tag_line == prevnonblank(v:lnum - 1) || opening_tag_line == v:lnum)
\ || getline(v:lnum) =~ '\v^\s*\</(script|style|template)'
return 0
endif
else
exe "let indent = ".s:htmlindent
" Couldn't find language, fall back to html
execute 'let indent = ' . s:html_indent
endif
return indent > -1 ? indent : s:htmlindent
return indent
endfunction

View File

@@ -1,4 +1,4 @@
# vim-vue
# vim-vue [![CircleCI](https://img.shields.io/circleci/project/github/posva/vim-vue.svg)](https://circleci.com/gh/posva/vim-vue)
Vim syntax highlighting for [Vue
components](https://vuejs.org/v2/guide/single-file-components.html).
@@ -38,7 +38,21 @@ Currently only `eslint` is available. Please make sure `eslint` and
npm i -g eslint eslint-plugin-vue
```
## Typescript support
## Contributing
If your language is not getting highlighted open an issue or a PR with the fix.
You only need to add a line to the `syntax/vue.vim` file.
## FAQ
### Where is Jade?
[Jade has been renamed to pug](https://github.com/pugjs/jade/issues/2184).
Therefore you have to replace all your `jade` occurrences with `pug`. The new
plugin for `pug` can be found on [the same repository](https://github.com/digitaltoad/vim-pug)
(the name has already been updated).
### Typescript support
You can use typescript by adding one of the following attributes/values to
your component's script tag:
@@ -51,16 +65,17 @@ your component's script tag:
Choose one that works with your module bundler
### My syntax highlighting stops working randomly
## Contributing
This is because Vim tries to highlight text in an efficient way. Especially in
files that include multiple languages, it can get confused. To work around
this, you can run `:syntax sync fromstart` when it happens.
If your language is not getting highlighted open an issue or a PR with the fix.
You only need to add some lines to the `syntax/vue.vim` file.
You can also setup an autocmd for this:
## FAQ
```vim
autocmd FileType vue syntax sync fromstart
```
Where is Jade?
[Jade has been renamed to pug](https://github.com/pugjs/jade/issues/2184).
Therefore you have to replace all your `jade` occurrences with `pug`. The new
plugin for `pug` can be found on [the same repository](https://github.com/digitaltoad/vim-pug) (the name has already been updated).
See `:h :syn-sync-first` and [this article](http://vim.wikia.com/wiki/Fix_syntax_highlighting)
for more details.

View File

@@ -6,89 +6,52 @@ if exists("b:current_syntax")
finish
endif
if !exists("s:syntaxes")
" Search available syntax files.
function s:search_syntaxes(...)
let syntaxes = {}
let names = a:000
for name in names
let syntaxes[name] = 0
endfor
for path in split(&runtimepath, ',')
if isdirectory(path . '/syntax')
for name in names
let syntaxes[name] = syntaxes[name] || filereadable(path . '/syntax/' . name . '.vim')
endfor
endif
endfor
return syntaxes
endfunction
let s:syntaxes = s:search_syntaxes('pug', 'slm', 'coffee', 'stylus', 'sass', 'scss', 'less', 'typescript')
endif
syntax include @HTML syntax/html.vim
runtime! syntax/html.vim
unlet! b:current_syntax
syntax region html keepend start=/^<template\_[^>]*>/ end=/^<\/template>/ contains=@HTML fold
if s:syntaxes.pug
syntax include @PUG syntax/pug.vim
unlet! b:current_syntax
syntax region pug keepend start=/<template lang=\("\|'\)[^\1]*pug[^\1]*\1>/ end="</template>" contains=@PUG fold
syntax region pug keepend start=/<template lang=\("\|'\)[^\1]*jade[^\1]*\1>/ end="</template>" contains=@PUG fold
endif
""
" Get the pattern for a HTML {name} attribute with {value}.
function! s:attr(name, value)
return a:name . '=\("\|''\)[^\1]*' . a:value . '[^\1]*\1'
endfunction
if s:syntaxes.slm
syntax include @SLM syntax/slm.vim
unlet! b:current_syntax
syntax region slm keepend start=/<template lang=\("\|'\)[^\1]*slm[^\1]*\1>/ end="</template>" contains=@SLM fold
endif
""
" Check whether a syntax file for a given {language} exists.
function! s:syntax_available(language)
return !empty(globpath(&runtimepath, 'syntax/' . a:language . '.vim'))
endfunction
syntax include @JS syntax/javascript.vim
unlet! b:current_syntax
syntax region javascript keepend matchgroup=Delimiter start=/<script\( lang="babel"\)\?\( type="text\/babel"\)\?>/ end="</script>" contains=@JS fold
""
" Register {language} for a given {tag}. If [attr_override] is given and not
" empty, it will be used for the attribute pattern.
function! s:register_language(language, tag, ...)
let attr_override = a:0 ? a:1 : ''
let attr = !empty(attr_override) ? attr_override : s:attr('lang', a:language)
if s:syntaxes.typescript
syntax include @TS syntax/typescript.vim
unlet! b:current_syntax
syntax region typescript keepend matchgroup=Delimiter start=/<script \_[^>]*\(lang=\("\|'\)[^\2]*\(ts\|typescript\)[^\2]*\2\|ts\)\_[^>]*>/ end="</script>" contains=@TS fold
endif
if s:syntax_available(a:language)
execute 'syntax include @' . a:language . ' syntax/' . a:language . '.vim'
unlet! b:current_syntax
execute 'syntax region vue_' . a:language
\ 'keepend'
\ 'start=/<' . a:tag . ' \_[^>]*' . attr . '\_[^>]*>/'
\ 'end="</' . a:tag . '>"me=s-1'
\ 'contains=@' . a:language . ',vueSurroundingTag'
\ 'fold'
endif
endfunction
if s:syntaxes.coffee
syntax include @COFFEE syntax/coffee.vim
unlet! b:current_syntax
" Matchgroup seems to be necessary for coffee
syntax region coffee keepend matchgroup=Delimiter start="<script lang=\"coffee\">" end="</script>" contains=@COFFEE fold
endif
call s:register_language('pug', 'template', s:attr('lang', '\%(pug\|jade\)'))
call s:register_language('slm', 'template')
call s:register_language('handlebars', 'template')
call s:register_language('typescript', 'script', '\%(lang=\("\|''\)[^\1]*\(ts\|typescript\)[^\1]*\1\|ts\)')
call s:register_language('coffee', 'script')
call s:register_language('stylus', 'style')
call s:register_language('sass', 'style')
call s:register_language('scss', 'style')
call s:register_language('less', 'style')
syntax include @CSS syntax/css.vim
unlet! b:current_syntax
syntax region css keepend start=/<style\_[^>]*>/ end="</style>" contains=@CSS fold
if s:syntaxes.stylus
syntax include @stylus syntax/stylus.vim
unlet! b:current_syntax
syntax region stylus keepend start=/<style \_[^>]*lang=\("\|'\)[^\1]*stylus[^\1]*\1\_[^>]*>/ end="</style>" contains=@stylus fold
endif
if s:syntaxes.sass
syntax include @sass syntax/sass.vim
unlet! b:current_syntax
syntax region sass keepend start=/<style \_[^>]*lang=\("\|'\)[^\1]*sass[^\1]*\1\_[^>]*>/ end="</style>" contains=@sass fold
endif
if s:syntaxes.scss
syntax include @scss syntax/scss.vim
unlet! b:current_syntax
syntax region scss keepend start=/<style \_[^>]*lang=\("\|'\)[^\1]*scss[^\1]*\1\_[^>]*>/ end="</style>" contains=@scss fold
endif
if s:syntaxes.less
syntax include @less syntax/less.vim
unlet! b:current_syntax
syntax region less keepend matchgroup=PreProc start=/<style \_[^>]*lang=\("\|'\)[^\1]*less[^\1]*\1\_[^>]*>/ end="</style>" contains=@less fold
endif
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
let b:current_syntax = "vue"

26
test/install.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -e
repos=(
'junegunn/vader.vim'
'cakebaker/scss-syntax.vim'
'digitaltoad/vim-pug'
'groenewege/vim-less'
'kchmck/vim-coffee-script'
'leafgarland/typescript-vim'
'slm-lang/vim-slm'
'wavded/vim-stylus'
)
cd "$(dirname "$0")/.."
mkdir -p pack/testing/start
cd pack/testing/start
# Add our plugin to the pack.
ln -s ../../.. vim-vue
for repo in ${repos[@]}
do
git clone https://github.com/$repo.git
done

32
test/readme.md Normal file
View File

@@ -0,0 +1,32 @@
# Vader Tests
> Requires Vim 8 or Neovim, due to the way dependencies are installed.
To run the tests, you need to install the dependencies first. Use the
[installation script](install.sh):
```sh
test/install.sh
```
## Running the tests from the command line
You can run the tests with the following command:
```sh
vim -u test/vimrc -c 'Vader! test/*.vader'
```
## Running the tests from within Vim
Open vim with:
```
vim -u test/vimrc
```
Then, you can run the tests with the following command:
```vim
:Vader test/*.vader
```

135
test/test_indent.vader Normal file
View File

@@ -0,0 +1,135 @@
#
# HTML
#
Given vue (An unindented html template):
<template>
<div>
Hello
</div>
</template>
Do (Indent the whole buffer):
gg=G
Expect (The html template got indented):
<template>
<div>
Hello
</div>
</template>
Given vue (Template tag inside a template):
<template>
<div>
<template v-if="loading">
Loading...
</template>
</div>
</template>
Do (Indent the whole buffer):
gg=G
Expect (It didn't get unindented):
<template>
<div>
<template v-if="loading">
Loading...
</template>
</div>
</template>
#
# JavaScript
#
Given vue (An unindented JavaScript region):
<script>
export default {
methods: {
foo() {
//
}
}
}
</script>
Do (Indent the whole buffer):
gg=G
Expect vue (The JavaScript region got indented):
<script>
export default {
methods: {
foo() {
//
}
}
}
</script>
#
# CSS
#
Given vue (An unindented css region):
<style>
body {
background: tomato;
}
</style>
Do (Indent the whole buffer):
gg=G
Expect vue (The css region got indented):
<style>
body {
background: tomato;
}
</style>
#
# Pug
#
Given vue (Empty Pug region):
<template lang="pug">
</template>
Do (Insert list items):
o
ul\<CR>
li Item A\<CR>
li Item B
Expect:
<template lang="pug">
ul
li Item A
li Item B
</template>
#
# Stylus
#
Given vue (Empty Stylus region):
<style lang="stylus">
</style>
Do (Insert some styles):
o
body\<CR>
font-size: 14px\<CR>
\<CR>\<C-d>
h1\<CR>
font-size: 30px\<CR>
display: block
Expect:
<style lang="stylus">
body
font-size: 14px
h1
font-size: 30px
display: block
</style>

166
test/test_syntax.vader Normal file
View File

@@ -0,0 +1,166 @@
#
# HTML
#
Given vue (HTML template without lang attribute):
<template>
<div></div>
</template>
Execute:
AssertEqual 'htmlTag', SyntaxAt(2, 3)
AssertEqual 'htmlTag', SyntaxAt(1, 1)
AssertEqual 'htmlSpecialTagName', SyntaxAt(1, 2)
Given vue (Template tag inside a template):
<template>
<div>
<template v-if="loading">
Loading...
</template>
</div>
</template>
Execute (Syntax doesn't stop at the first closing template tag):
AssertEqual 'htmlEndTag', SyntaxAt(6, 3)
#
# JavaScript
#
Given vue:
<script>
//
</script>
Execute:
AssertEqual 'javaScriptLineComment', SyntaxAt(2, 1)
AssertEqual 'htmlScriptTag', SyntaxAt(1, 1)
Given vue (Script tag with misc. attributes and newline):
<script type="text/babel"
lang="babel"
>
//
</script>
Execute:
AssertEqual 'javaScriptLineComment', SyntaxAt(4, 1)
AssertEqual 'htmlArg', SyntaxAt(2, 9)
AssertEqual 'htmlScriptTag', SyntaxAt(1, 1)
#
# CSS
#
Given vue (CSS region without lang attribute):
<style>
/**/
</style>
Execute:
AssertEqual 'cssComment', SyntaxAt(2, 1)
AssertEqual 'htmlTag', SyntaxAt(1, 1)
#
# Pug
#
Given vue (Pug template):
<template lang="pug">
p #{name}'s Pug source code!
</template>
Execute:
AssertEqual 'htmlTagName', SyntaxAt(2, 1)
AssertEqual 'pugInterpolationDelimiter', SyntaxAt(2, 3)
AssertEqual 'vueSurroundingTag', SyntaxAt(1, 1)
Given vue (Pug template using their former name):
<template lang="jade">
p #{name}'s Pug source code!
</template>
Execute:
AssertEqual 'htmlTagName', SyntaxAt(2, 1)
AssertEqual 'pugInterpolationDelimiter', SyntaxAt(2, 3)
#
# SCSS
#
Given vue (SCSS region):
<style lang="scss">
$green: #42b983;
</style>
Execute:
AssertEqual 'scssVariable', SyntaxAt(2, 1)
AssertEqual 'vueSurroundingTag', SyntaxAt(1, 1)
#
# Sass
#
Given vue (Sass region):
<style lang="sass">
$green: #42b983
</style>
Execute:
AssertEqual 'sassVariable', SyntaxAt(2, 1)
AssertEqual 'vueSurroundingTag', SyntaxAt(1, 1)
Given vue (Sass region with modifier):
<style lang="sass?indentedSyntax">
$green: #42b983
</style>
Execute:
AssertEqual 'sassVariable', SyntaxAt(2, 1)
#
# Stylus
#
Given vue (Sass region):
<style lang="stylus">
@import 'variables'
body
font: 12px Helvetica, Arial, sans-serif
</style>
Execute:
AssertEqual 'stylusImport', SyntaxAt(2, 1)
AssertEqual 'cssTagName', SyntaxAt(4, 1)
AssertEqual 'vueSurroundingTag', SyntaxAt(1, 1)
#
# TypeScript
#
Given vue (Typescript region using "ts" as name):
<script lang="ts">
@Component({})
</script>
Execute:
AssertEqual 'typescriptDecorators', SyntaxAt(2, 1)
AssertEqual 'vueSurroundingTag', SyntaxAt(1, 1)
Given vue (Typescript region using "typescript" as name):
<script lang="typescript">
@Component({})
</script>
Execute:
AssertEqual 'typescriptDecorators', SyntaxAt(2, 1)
Given vue (Typescript region using "ts" attribute):
<script ts>
@Component({})
</script>
Execute:
AssertEqual 'typescriptDecorators', SyntaxAt(2, 1)
AssertEqual 'htmlArg', SyntaxAt(1, 9)

13
test/vimrc Normal file
View File

@@ -0,0 +1,13 @@
set nocompatible
let &packpath = expand('<sfile>:p:h:h')
" Remove first and last entry from runtimepath, to prevent loading plugins from ~/.vim
let &runtimepath = substitute(&runtimepath, '\v^.{-},(.*),.*$', '\1', '')
filetype plugin indent on
syntax on
set expandtab
set shiftwidth=2
set softtabstop=2