diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..0d08e26
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,11 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
+
+version: 2
+updates:
+ - package-ecosystem: "github-actions" # See documentation for possible values
+ directory: "/" # Location of package manifests
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/vader.yml b/.github/workflows/vader.yml
new file mode 100644
index 0000000..3c8215a
--- /dev/null
+++ b/.github/workflows/vader.yml
@@ -0,0 +1,69 @@
+name: Tests on vim and neovim
+
+# Controls when the workflow will run
+on:
+ # Triggers the workflow on push or pull request events but only for the master branch
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ lint:
+ name: Lint code with Vint and shellcheck
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v7
+ # There exists a vint github action but it can't install the alpha
+ # version. vint has not been moving since 2020 and we need to use the
+ # alpha release since it fixed some things wrt the latest stable release.
+ - uses: actions/setup-python@v6
+ with:
+ python-version: '3.10'
+ - name: Install vint
+ run: pip install --pre vim-vint
+ - name: Lint vimscript files
+ run: vint --warning --enable-neovim ./ftdetect ./ftplugin ./indent ./syntax
+ - uses: lunarmodules/luacheck@v1
+ - name: Lint shell scripts
+ uses: ludeeus/action-shellcheck@master
+ - name: Lint Markdown files
+ uses: DavidAnson/markdownlint-cli2-action@v24
+
+ tests:
+ runs-on: ubuntu-latest
+ needs: lint
+ strategy:
+ fail-fast: false
+ matrix:
+ # bullseye: vim 8.2.2434 neovim 0.4.4
+ # bookworm: vim 9.0.1378 neovim 0.7.2
+ # trixie: vim 9.1.0496 neovim 0.9.5
+ # jammy: vim 8.2.3995 neovim 0.6.1
+ # mantic: vim 9.0.1672 neovim 0.7.2
+ # noble: vim 9.1.0016 neovim 0.9.5 <- vim version currently used by github action as vim-stable
+ # mageia 9: vim 9.1.071 neovim 0.9.5
+ # mageia cauldron: vim 9.1.1122 neovim 0.10.4
+ # neovim < 0.9.0 segfaut on github action (even the one installed from apt)
+ editor: ["vim-v8.0.0000", "vim-v8.2.2434", "vim-v9.1.1122", "nvim-v0.9.0", "nvim-v0.9.5", "nvim-v0.10.4"]
+
+ steps:
+ - uses: actions/checkout@v7
+ - name: get editor name
+ env:
+ EDITORVERSION: ${{matrix.editor}}
+ id: split
+ run: |
+ echo "SELECTEDEDITOR=${EDITORVERSION%%-*}" >> $GITHUB_ENV
+ echo "SELECTEDVERSION=${EDITORVERSION##*-}" >> $GITHUB_ENV
+ - name: Setup ${{ matrix.editor }}
+ uses: rhysd/action-setup-vim@v1
+ id: vim
+ with:
+ neovim: ${{ env.SELECTEDEDITOR == 'nvim' }}
+ version: ${{ env.SELECTEDVERSION }}
+ - name: Run Vader unit tests
+ run: |
+ TESTVIM=${{ env.SELECTEDEDITOR }}
+ export TESTVIM
+ ./test/run-tests.sh
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..43246ce
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,25 @@
+# test
+/vader.vim
+\#*\#
+/.vim/
+/.vimrc
+## Swap
+[._]*.s[a-v][a-z]
+!*.svg # comment out if you don't need vector files
+[._]*.sw[a-p]
+[._]s[a-rt-v][a-z]
+[._]ss[a-gi-z]
+[._]sw[a-p]
+## Session
+Session.vim
+Sessionx.vim
+## Temporary
+.netrwhist
+*~
+## Persistent undo
+[._]*.un~
+## Auto-generated tag files
+tags
+GTAGS
+GRTAGS
+GPATH
diff --git a/README.markdown b/README.markdown
index d207d3d..74ffb10 100644
--- a/README.markdown
+++ b/README.markdown
@@ -1,6 +1,7 @@
# Smarty plugin for Vim
-This plugin provides syntax highlighting, indenting and general filetype settings for the Smarty templating language.
+This plugin provides syntax highlighting, indenting and general filetype
+settings for the Smarty templating language.
This is a fork of [Vim Script #1798](http://www.vim.org/scripts/script.php?script_id=1798)
(see the original README below).
@@ -9,28 +10,126 @@ This is a fork of [Vim Script #1798](http://www.vim.org/scripts/script.php?scrip
The following (probably incomplete) list of enhancements are provided:
- * Various improvements throughout the syntax handling.
- * `{php}…{/php}` blocks are delegated to PHP syntax.
- * `filetype` is set to "smarty" for `*.tpl` files.
- * syntax is based on HTML filetype.
- * matchit (jumping between tags via `%`) is configured for Smarty tags
- (`{foo}` .. `{/foo}`), and based on the html setup.
- * line endings have been converted to unix fileformat (to prevent
- parse errors on Linux/Mac).
- * Smarter indenting, handling PHP blocks and delegating to HTML (includes
- JavaScript).
+* Various improvements throughout the syntax handling.
+* `{php}…{/php}` blocks are delegated to PHP syntax.
+* `filetype` is set to "smarty" for `*.tpl` files.
+* syntax is based on HTML filetype.
+* matchit (jumping between tags via `%`) is configured for Smarty tags
+ (`{foo}` .. `{/foo}`), and based on the html setup.
+* line endings have been converted to unix fileformat (to prevent
+ parse errors on Linux/Mac).
+* Smarter indenting, handling PHP blocks and delegating to HTML (includes
+ JavaScript).
+* Syntax updated to Smarty5
+* add doc for variable configuration
+* unit tests
+
+## Installation
+
+If you use [Vundle](https://github.com/gmarik/vundle), add the following lines
+to your `~/.vimrc`:
+
+```vim
+Plugin 'shadowwa/smarty.vim'
+```
+
+Then run inside Vim:
+
+```vim
+:so ~/.vimrc
+:PluginInstall
+```
+
+If you use [Pathogen](https://github.com/tpope/vim-pathogen), do this:
+
+```sh
+cd ~/.vim/bundle
+git clone https://github.com/shadowwa/smarty.vim.git
+```
+
+For [vim-plug](https://github.com/junegunn/vim-plug) users:
+
+```vim
+Plug 'shadowwa/smarty.vim'
+```
+
+in your `.vimrc` or `init.vim`, then restart Vim and run `:PlugInstall`.
+
+## Variables
+
+### indenting
+
+When this variable is set, the indentation is done on html tags and smarty
+tags otherwise smarty tags are not indented
+
+```vim
+let g:smarty_indent_block = 1
+```
+
+```smarty
+
+
+ {if $test}
+ {$variable}
+ {/if}
+
+
+```
+
+```vim
+ let g:smarty_indent_block = 0
+```
+
+```smarty
+
+
+ {if $test}
+ {$variable}
+ {/if}
+
+
+```
+
+### Verbose mode for debugging
+
+```vim
+ let g:smarty_indent_verbose = 1
+```
+
+## Testing
+
+Testing is based on vader.vim testing framework, see:
+ . To run full test suit use
+`./test/run-tests.sh`, this will also download vader.vim plugin to project's
+folder.
## About Smarty
-[Smarty](http://www.smarty.net/) is a PHP template language.
-## About this fork
-I am not using Smarty that much (anymore), but wanted to get these enhancements
-published, for others to pick them up.
+[Smarty](https://smarty-php.github.io/smarty/stable/) is a PHP template language.
+
+[Pull requests](https://github.com/shadowwa/smarty.vim) are welcome, of course.
+
+## Additional useful plugins
-[Pull requests](https://github.com/blueyed/smarty.vim) are welcome, of course.
+* [vim-textobj-smarty](https://github.com/kana/vim-textobj-smarty/) add textobj
+ for smarty, allowing to work on loop and conditional code with `*ak` and on
+ content only with `*ik` ([vim-textobj-user](https://github.com/kana/vim-textobj-user)
+ is also required)
+* [vim-snippets](https://github.com/honza/vim-snippets) is a library of
+ snippets for multiple languages, including Smarty. Works with:
+ * [snipmate](https://github.com/garbas/vim-snipmate),
+ * [ultisnips](https://github.com/SirVer/ultisnips) or
+ * [coc-snippets](https://github.com/neoclide/coc-snippets) if you are using [coc](https://github.com/neoclide/coc.nvim)
+* [coc-smarty](https://github.com/shadowwa/coc-smarty) is an extension for [coc](https://github.com/neoclide/coc.nvim),
+ a test of using [coc-html](https://github.com/neoclide/coc-html) with code
+ from [vscode-smarty](https://github.com/ssigwart/vscode-smarty)
+## Original README
-# Original README
-This is a mirror of http://www.vim.org/scripts/script.php?script_id=1798
+This is a mirror of
-A friend and I found that there were no acceptable vim syntax files for smarty, so we took the only one we could find and added everything from the smarty documentation (http://smarty.php.net/manual/en) to it. If nothing else, this is a very good start on a complete smarty syntax file. We have even used vimtip #498 to use autocomplete with this syntax and so far it seems to work well.
+A friend and I found that there were no acceptable vim syntax files for smarty,
+so we took the only one we could find and added everything from the smarty
+documentation () to it. If nothing else,
+this is a very good start on a complete smarty syntax file. We have even used
+vimtip #498 to use autocomplete with this syntax and so far it seems to work well.
diff --git a/doc/smarty.txt b/doc/smarty.txt
new file mode 100644
index 0000000..9b461e7
--- /dev/null
+++ b/doc/smarty.txt
@@ -0,0 +1,76 @@
+*smarty.txt* Syntax highlighting
+
+This plugin provides syntax highlighting, indenting and general filetype
+settings for the Smarty templating language.
+https://smarty-php.github.io/.
+
+The following (probably incomplete) list of enhancements are provided:
+
+ * Various improvements throughout the syntax handling.
+ * `{php}…{/php}` blocks are delegated to PHP syntax.
+ * `filetype` is set to "smarty" for `*.tpl` files.
+ * syntax is based on HTML filetype.
+ * matchit (jumping between tags via `%`) is configured for Smarty tags
+ (`{foo}` .. `{/foo}`), and based on the html setup.
+ * line endings have been converted to unix fileformat (to prevent parse
+ errors on Linux/Mac).
+ * Smarter indenting, handling PHP blocks and delegating to HTML (includes
+ JavaScript).
+ * Syntax updated to Smarty5
+ * add doc for variable configuration
+ * unit tests
+
+==============================================================================
+VARIABLES *smarty-variables*
+
+Put these variables into your vimrc. The provided examples also indicate the
+default values, as long as no "Default:" section is given.
+
+ |g:smarty_indent_block|
+ |g:smarty_indent_verbose|
+
+------------------------------------------------------------------------------
+ *g:smarty_indent_block*
+When this variable is set, the indentation is done on html tags and smarty
+tags otherwise smarty tags are not indented
+
+>vim
+ let g:smarty_indent_block = 1
+<
+>smarty
+
+
+ {if $test}
+ {$variable}
+ {/if}
+
+
+<
+
+>vim
+ let g:smarty_indent_block = 0
+<
+>smarty
+
+
+ {if $test}
+ {$variable}
+ {/if}
+
+
+<
+------------------------------------------------------------------------------
+ *g:smarty_indent_verbose*
+>vim
+ let g:smarty_indent_verbose = 1
+<
+Verbose mode for debugging
+
+==============================================================================
+ABOUT *smarty-about*
+
+Grab the latest version or report a bug on GitHub:
+
+https://github.com/shadowwa/smarty.vim
+
+ vim:tw=78:et:ft=help:norl:
diff --git a/ftdetect/smarty.vim b/ftdetect/smarty.vim
index fc23556..2a13ed2 100644
--- a/ftdetect/smarty.vim
+++ b/ftdetect/smarty.vim
@@ -1 +1,2 @@
+" vint: -ProhibitAutocmdWithNoGroup
au BufRead,BufNewFile *.tpl if &ft == '' | setfiletype smarty | endif
diff --git a/ftplugin/smarty.vim b/ftplugin/smarty.vim
index b5491ef..49f931b 100644
--- a/ftplugin/smarty.vim
+++ b/ftplugin/smarty.vim
@@ -1,15 +1,19 @@
-if exists("b:did_ftplugin") | finish | endif
+if exists('b:did_ftplugin') | finish | endif
" Use HTML template ftplugins.
runtime! ftplugin/html.vim
" Append to b:match_words to match smarty tags ("{foo}..{/foo}")
-if exists("loaded_matchit")
- if exists("b:match_words")
- let b:match_words .= ','
- else
- let b:match_words = ''
- endif
- let b:match_words .= '{\@<=\([^/][^ \t}]*\)[^}]*\%(}\|$\):{\@<=/\1}'
- let b:match_words .= ',{:},\[:\],(:)'
+if exists('loaded_matchit')
+ if exists('b:match_words')
+ let b:match_words .= ','
+ else
+ let b:match_words = ''
+ endif
+ let b:match_words .= '{\@<=if:{\@<=elseif:{\@<=else}:{\@<=/if},'
+ let b:match_words .= '{\@<=foreach :{\@<=foreachelse}:{\@<=break}:{\@<=continue}:{\@<=/foreach},'
+ let b:match_words .= '{\@<=for :{\@<=forelse}:{\@<=/for},'
+ let b:match_words .= '{\@<=section :{\@<=sectionelse:{\@<=/section},'
+ let b:match_words .= '{\@<=\([^/][^ \t}]*\)[^}]*\%(}\|$\):{\@<=/\1}'
+ let b:match_words .= ',{:},\[:\],(:)'
endif
diff --git a/indent/smarty.vim b/indent/smarty.vim
index 1a585e3..bca1cfd 100644
--- a/indent/smarty.vim
+++ b/indent/smarty.vim
@@ -46,11 +46,12 @@ function! s:handle(lnum, ft, searchpairargs)
if scriptlnum && scriptlnum != prevlnum
exec 'return ' s:indentexprs[a:ft]
endif
- return ""
+ return ''
endfun
function! s:syn(lnum)
- return synIDattr(synID(a:lnum,1+indent(a:lnum),1),'name')
+ let nonemptycol=match(getline(a:lnum), '\S')+1
+ return synIDattr(synID(a:lnum,nonemptycol,1),'name')
endfunction
function! GetSmartyHtmlIndent(lnum)
@@ -65,14 +66,25 @@ function! GetSmartyHtmlIndent(lnum)
if g:smarty_indent_block
let sw = exists('*shiftwidth') ? shiftwidth() : shiftwidth()
- if csyn == 'smartyStartTag'
- if syn == 'htmlTag' || syn == 'smartyStartTag'
+ if csyn ==# 'smartyStartTag' || csyn ==# 'smartyMiddleTag'
+ call cursor(a:lnum, match(getline(a:lnum), '\S')+1)
+ let pairline = searchpair('{', '', '}', 'bW')
+ if pairline > 0
+ return sw + indent(pairline)
+ endif
+ endif
+ if csyn ==# 'smartyStartTag'
+ if syn ==# 'htmlTag' || syn ==# 'htmlScriptTag'
+ let indent = call(substitute(s:indentexprs['html'], '(\|)', '', 'g'), [])
+ return indent
+ endif
+ if (syn ==# 'smartyStartTag' || syn ==# 'smartyMiddleTag') && !(line =~? '{\([a-z]\+\)[^}]*}[^\n]*{\/\1}')
return sw + indent(prevnonblank(v:lnum-1))
endif
return indent(prevnonblank(v:lnum-1))
- elseif csyn == 'smartyEndTag' || csyn == 'smartyMiddleTag'
- if syn == 'smartyStartTag'
+ elseif csyn ==# 'smartyEndTag' || csyn ==# 'smartyMiddleTag'
+ if syn ==# 'smartyStartTag' && !(line =~? '{\([a-z]\+\)[^}]*}[^\n]*{\/\1}')
return indent(prevnonblank(v:lnum-1))
endif
@@ -84,18 +96,18 @@ function! GetSmartyHtmlIndent(lnum)
let indent = call('s:handle', [a:lnum, ft, args])
if type(indent) == type(0)
if g:smarty_indent_verbose
- echom "Line " . a:lnum . ": using " . ft . " indenting via " . s:indentexprs[ft]
+ echom 'Line ' . a:lnum . ': using ' . ft . ' indenting via ' . s:indentexprs[ft]
endif
if g:smarty_indent_block
" Indent {php}
- if cline =~ '\s*{php}\s*'
+ if cline =~# '\s*{php}\s*'
return sw + indent(prevnonblank(v:lnum-1))
endif
" Indent/unindent {/php}
- if cline =~ '\s*{/php}\s*'
- if line =~ '\s*{php}\s*'
+ if cline =~# '\s*{/php}\s*'
+ if line =~# '\s*{php}\s*'
return indent(prevnonblank(v:lnum-1))
else
return indent(prevnonblank(v:lnum-1)) - sw
@@ -103,7 +115,7 @@ function! GetSmartyHtmlIndent(lnum)
endif
" Indent line if previous line is {php}
- if line =~ '\s*{php}\s*'
+ if line =~# '\s*{php}\s*'
return sw + indent(prevnonblank(v:lnum-1))
endif
endif
@@ -114,14 +126,21 @@ function! GetSmartyHtmlIndent(lnum)
" Fallback to HTML
if g:smarty_indent_verbose
- echom "Line " . a:lnum . ": using HTML indenting via " . s:indentexprs['html']
+ echom 'Line ' . a:lnum . ': using HTML indenting via ' . s:indentexprs['html']
endif
let indent = call(substitute(s:indentexprs['html'], '(\|)', '', 'g'), [])
if g:smarty_indent_block
+ if syn ==# 'smartyStartTag' || syn ==# 'smartyMiddleTag'
+ call cursor(a:lnum -1, col('$'))
+ let pairline = searchpair('{', '', '}', 'bW')
+ if pairline > 0
+ return sw + indent(pairline)
+ endif
+ endif
" Indent if previous line is a smartyStartTag but ignore inline tags
- if (syn == 'smartyStartTag' || syn == 'smartyMiddleTag') && !(line =~ '{\([a-z]\+\)[^}]*}[^\n]*{\/\1}')
+ if (syn ==# 'smartyStartTag' || syn ==# 'smartyMiddleTag') && !(line =~? '{\([a-z]\+\)[^}]*}[^\n]*{\/\1}')
return sw + indent
endif
endif
diff --git a/syntax/smarty.vim b/syntax/smarty.vim
index 252bd93..afe68e9 100644
--- a/syntax/smarty.vim
+++ b/syntax/smarty.vim
@@ -1,16 +1,19 @@
" Vim syntax file
-" Language: Smarty Templates
-" Maintainer: Daniel Hahler, original: Manfred Stienstra manfred.stienstra@dwerg.net
-" Last Change: Di 10 Jun 2014 15:09:10 CEST
-" Filenames: *.tpl
-" URL: https://github.com/blueyed/smarty.vim
+" Language: Smarty Templates
+" Maintainer: Shad
+" Previous Maintainer: Diego Blanco
+" Previous Maintainer: Daniel Hahler
+" Original Maintainer: Manfred Stienstra manfred.stienstra@dwerg.net
+" Last Change: Sun Mar 2 17:00:39 CET 2025
+" Filenames: *.tpl
+" URL: https://github.com/shadowwa/smarty.vim
-" For version 5.x: Clear all syntax items
-" For version 6.x: Quit when a syntax file was already loaded
-if !exists("main_syntax")
- if version < 600
+" For vim version 5.x: Clear all syntax items
+" For vim version 6.x: Quit when a syntax file was already loaded
+if !exists('main_syntax')
+ if v:version < 600
syntax clear
- elseif exists("b:current_syntax")
+ elseif exists('b:current_syntax')
finish
endif
let main_syntax = 'smarty'
@@ -22,163 +25,198 @@ runtime! syntax/html.vim
unlet b:current_syntax
syn keyword smartySTags contained append assign call capture config_load debug eval extends fetch html_checkboxes html_image html_options html_radios html_select_date html_select_time html_table include include_php insert mailto math ldelim rdelim
-syn keyword smartyDTags contained block for function literal nocache php setfilter strip textformat
-syn keyword smartyConditional contained if elseif else
+syn keyword smartyDTags contained block for capture function literal nocache php setfilter strip textformat
+syn keyword smartyConditional contained if elseif else forelse
syn keyword smartySRepeat contained cycle counter
syn keyword smartyDRepeat contained foreach foreachelse section sectionelse while
+syn keyword smartyForeachConstruct contained break continue
syn match smartyCProperty contained "[a-zA-Z0-9_]\+="
-syn match smartyProperty contained "file="
-syn match smartyProperty contained "loop="
-syn match smartyProperty contained "name="
-syn match smartyProperty contained "include="
-syn match smartyProperty contained "skip="
-syn match smartyProperty contained "section="
-syn match smartyProperty contained "from="
-syn match smartyProperty contained "item="
-syn match smartyProperty contained "key="
-syn match smartyProperty contained "once="
-syn match smartyProperty contained "global="
-syn match smartyProperty contained "scope="
-syn match smartyProperty contained "script="
-syn match smartyProperty contained "assign="
-syn match smartyProperty contained "start="
-syn match smartyProperty contained "stop="
-syn match smartyProperty contained "max="
-syn match smartyProperty contained "show="
-syn match smartyProperty contained "step="
-syn match smartyProperty contained "var="
-syn match smartyProperty contained "value="
-syn match smartyProperty contained "skip="
-syn match smartyProperty contained "direction="
-syn match smartyProperty contained "print="
+syn match smartyProperty contained "above="
+syn match smartyProperty contained "address="
syn match smartyProperty contained "advance="
-syn match smartyProperty contained "delimiter="
-syn match smartyProperty contained "reset="
-syn match smartyProperty contained "output="
-syn match smartyProperty contained "selected="
-syn match smartyProperty contained "options="
-syn match smartyProperty contained "separator="
-syn match smartyProperty contained "labels="
-syn match smartyProperty contained "height="
-syn match smartyProperty contained "width="
-syn match smartyProperty contained "basedir="
+syn match smartyProperty contained "all_empty="
+syn match smartyProperty contained "all_extra="
+syn match smartyProperty contained "all_id="
syn match smartyProperty contained "alt="
-syn match smartyProperty contained "href="
-syn match smartyProperty contained "path_prefix="
-syn match smartyProperty contained "values="
-syn match smartyProperty contained "prefix="
-syn match smartyProperty contained "time="
-syn match smartyProperty contained "start_year="
-syn match smartyProperty contained "end_year="
-syn match smartyProperty contained "display_days="
-syn match smartyProperty contained "display_months="
-syn match smartyProperty contained "display_years="
-syn match smartyProperty contained "month_format="
+syn match smartyProperty contained "append="
+syn match smartyProperty contained "assign="
+syn match smartyProperty contained "autostatus="
+syn match smartyProperty contained "autostatuscap="
+syn match smartyProperty contained "background="
+syn match smartyProperty contained "basedir="
+syn match smartyProperty contained "bcc="
+syn match smartyProperty contained "below="
+syn match smartyProperty contained "bgbackground="
+syn match smartyProperty contained "bgcolor="
+syn match smartyProperty contained "border="
+syn match smartyProperty contained "cache_id="
+syn match smartyProperty contained "cache_lifetime="
+syn match smartyProperty contained "caparray="
+syn match smartyProperty contained "capcolor="
+syn match smartyProperty contained "capicon="
+syn match smartyProperty contained "caption="
+syn match smartyProperty contained "captionfont="
+syn match smartyProperty contained "captionsize="
+syn match smartyProperty contained "cc="
+syn match smartyProperty contained "center="
+syn match smartyProperty contained "closecolor="
+syn match smartyProperty contained "closefont="
+syn match smartyProperty contained "closesize="
+syn match smartyProperty contained "closetext="
+syn match smartyProperty contained "cols="
+syn match smartyProperty contained "compile_id="
+syn match smartyProperty contained "day_empty="
+syn match smartyProperty contained "day_extra="
syn match smartyProperty contained "day_format="
-syn match smartyProperty contained "day_value_format="
-syn match smartyProperty contained "year_as_text="
-syn match smartyProperty contained "reverse_years="
+syn match smartyProperty contained "day_id="
syn match smartyProperty contained "day_size="
-syn match smartyProperty contained "month_size="
-syn match smartyProperty contained "year_size="
-syn match smartyProperty contained "day_extra="
-syn match smartyProperty contained "month_extra="
-syn match smartyProperty contained "year_extra="
-syn match smartyProperty contained "field_order="
-syn match smartyProperty contained "field_separator="
-syn match smartyProperty contained "month_value_format="
-syn match smartyProperty contained "year_empty="
-syn match smartyProperty contained "month_empty="
-syn match smartyProperty contained "day_empty="
+syn match smartyProperty contained "day_value_format="
+syn match smartyProperty contained "delay="
+syn match smartyProperty contained "delimiter="
+syn match smartyProperty contained "direction="
+syn match smartyProperty contained "display_days="
syn match smartyProperty contained "display_hours="
+syn match smartyProperty contained "display_meridian="
syn match smartyProperty contained "display_minutes="
+syn match smartyProperty contained "display_months="
syn match smartyProperty contained "display_seconds="
-syn match smartyProperty contained "minute_interval="
-syn match smartyProperty contained "second_interval="
+syn match smartyProperty contained "display_years="
+syn match smartyProperty contained "encode="
+syn match smartyProperty contained "end_year="
+syn match smartyProperty contained "equation="
+syn match smartyProperty contained "escape="
+syn match smartyProperty contained "extra="
+syn match smartyProperty contained "fgbackground="
+syn match smartyProperty contained "fgcolor="
syn match smartyProperty contained "field_array="
-syn match smartyProperty contained "all_extra="
+syn match smartyProperty contained "field_order="
+syn match smartyProperty contained "field_separator="
+syn match smartyProperty contained "file="
+syn match smartyProperty contained "fixx="
+syn match smartyProperty contained "fixy="
+syn match smartyProperty contained "followupto="
+syn match smartyProperty contained "format="
+syn match smartyProperty contained "frame="
+syn match smartyProperty contained "from="
+syn match smartyProperty contained "fullhtml="
+syn match smartyProperty contained "function="
+syn match smartyProperty contained "global="
+syn match smartyProperty contained "hauto="
+syn match smartyProperty contained "hdir="
+syn match smartyProperty contained "height="
+syn match smartyProperty contained "hour_empty="
syn match smartyProperty contained "hour_extra="
-syn match smartyProperty contained "minute_extra="
-syn match smartyProperty contained "second_extra="
+syn match smartyProperty contained "hour_format="
+syn match smartyProperty contained "hour_id="
+syn match smartyProperty contained "hour_value_format="
+syn match smartyProperty contained "href="
+syn match smartyProperty contained "inarray="
+syn match smartyProperty contained "include="
+syn match smartyProperty contained "indent="
+syn match smartyProperty contained "indent_char="
+syn match smartyProperty contained "indent_first="
+syn match smartyProperty contained "inner="
+syn match smartyProperty contained "item="
+syn match smartyProperty contained "key="
+syn match smartyProperty contained "label_ids="
+syn match smartyProperty contained "labels="
+syn match smartyProperty contained "left="
+syn match smartyProperty contained "loop="
+syn match smartyProperty contained "max="
+syn match smartyProperty contained "meridian_empty="
syn match smartyProperty contained "meridian_extra="
-syn match smartyProperty contained "display_meridian="
-syn match smartyProperty contained "use_24_hours="
-syn match smartyProperty contained "cols="
+syn match smartyProperty contained "meridian_id="
+syn match smartyProperty contained "minute_empty="
+syn match smartyProperty contained "minute_extra="
+syn match smartyProperty contained "minute_format="
+syn match smartyProperty contained "minute_id="
+syn match smartyProperty contained "minute_interval="
+syn match smartyProperty contained "minute_value_format="
+syn match smartyProperty contained "month_empty="
+syn match smartyProperty contained "month_extra="
+syn match smartyProperty contained "month_format="
+syn match smartyProperty contained "month_id="
+syn match smartyProperty contained "month_names="
+syn match smartyProperty contained "month_size="
+syn match smartyProperty contained "month_value_format="
+syn match smartyProperty contained "name="
+syn match smartyProperty contained "newsgroups="
+syn match smartyProperty contained "noclose="
+syn match smartyProperty contained "offsetx="
+syn match smartyProperty contained "offsety="
+syn match smartyProperty contained "once="
+syn match smartyProperty contained "option_separator="
+syn match smartyProperty contained "options="
+syn match smartyProperty contained "output="
+syn match smartyProperty contained "padx="
+syn match smartyProperty contained "pady="
+syn match smartyProperty contained "path_prefix="
+syn match smartyProperty contained "prefix="
+syn match smartyProperty contained "print="
+syn match smartyProperty contained "reset="
+syn match smartyProperty contained "reverse_years="
+syn match smartyProperty contained "right="
syn match smartyProperty contained "rows="
-syn match smartyProperty contained "inner="
-syn match smartyProperty contained "caption="
+syn match smartyProperty contained "scope="
+syn match smartyProperty contained "script="
+syn match smartyProperty contained "second_empty="
+syn match smartyProperty contained "second_extra="
+syn match smartyProperty contained "second_format="
+syn match smartyProperty contained "second_id="
+syn match smartyProperty contained "second_interval="
+syn match smartyProperty contained "second_value_format="
+syn match smartyProperty contained "section="
+syn match smartyProperty contained "selected="
+syn match smartyProperty contained "separator="
+syn match smartyProperty contained "show="
+syn match smartyProperty contained "skip="
+syn match smartyProperty contained "snapx="
+syn match smartyProperty contained "snapy="
+syn match smartyProperty contained "start="
+syn match smartyProperty contained "start_year="
+syn match smartyProperty contained "status="
+syn match smartyProperty contained "step="
+syn match smartyProperty contained "sticky="
+syn match smartyProperty contained "stop="
+syn match smartyProperty contained "strict="
+syn match smartyProperty contained "style="
+syn match smartyProperty contained "subject="
syn match smartyProperty contained "table_attr="
-syn match smartyProperty contained "th_attr="
-syn match smartyProperty contained "tr_attr="
syn match smartyProperty contained "td_attr="
-syn match smartyProperty contained "trailpad="
-syn match smartyProperty contained "hdir="
-syn match smartyProperty contained "vdir="
-syn match smartyProperty contained "address="
syn match smartyProperty contained "text="
-syn match smartyProperty contained "encode="
-syn match smartyProperty contained "cc="
-syn match smartyProperty contained "bcc="
-syn match smartyProperty contained "subject="
-syn match smartyProperty contained "newsgroups="
-syn match smartyProperty contained "followupto="
-syn match smartyProperty contained "extra="
-syn match smartyProperty contained "equation="
-syn match smartyProperty contained "format="
-syn match smartyProperty contained "trigger="
-syn match smartyProperty contained "sticky="
-syn match smartyProperty contained "caption="
-syn match smartyProperty contained "fgcolor="
-syn match smartyProperty contained "bgcolor="
syn match smartyProperty contained "textcolor="
-syn match smartyProperty contained "capcolor="
-syn match smartyProperty contained "closecolor="
syn match smartyProperty contained "textfont="
-syn match smartyProperty contained "captionfont="
-syn match smartyProperty contained "closefont="
syn match smartyProperty contained "textsize="
-syn match smartyProperty contained "captionsize="
-syn match smartyProperty contained "closesize="
+syn match smartyProperty contained "th_attr="
+syn match smartyProperty contained "time="
+syn match smartyProperty contained "tr_attr="
+syn match smartyProperty contained "trailpad="
+syn match smartyProperty contained "trigger="
+syn match smartyProperty contained "use_24_hours="
+syn match smartyProperty contained "value="
+syn match smartyProperty contained "values="
+syn match smartyProperty contained "var="
+syn match smartyProperty contained "vauto="
+syn match smartyProperty contained "vdir="
+syn match smartyProperty contained "width="
syn match smartyProperty contained "width="
-syn match smartyProperty contained "height="
-syn match smartyProperty contained "left="
-syn match smartyProperty contained "right="
-syn match smartyProperty contained "center="
-syn match smartyProperty contained "above="
-syn match smartyProperty contained "below="
-syn match smartyProperty contained "border="
-syn match smartyProperty contained "offsetx="
-syn match smartyProperty contained "offsety="
-syn match smartyProperty contained "fgbackground="
-syn match smartyProperty contained "bgbackground="
-syn match smartyProperty contained "closetext="
-syn match smartyProperty contained "noclose="
-syn match smartyProperty contained "status="
-syn match smartyProperty contained "autostatus="
-syn match smartyProperty contained "autostatuscap="
-syn match smartyProperty contained "inarray="
-syn match smartyProperty contained "caparray="
-syn match smartyProperty contained "capicon="
-syn match smartyProperty contained "snapx="
-syn match smartyProperty contained "snapy="
-syn match smartyProperty contained "fixx="
-syn match smartyProperty contained "fixy="
-syn match smartyProperty contained "background="
-syn match smartyProperty contained "padx="
-syn match smartyProperty contained "pady="
-syn match smartyProperty contained "fullhtml="
-syn match smartyProperty contained "frame="
-syn match smartyProperty contained "function="
-syn match smartyProperty contained "delay="
-syn match smartyProperty contained "hauto="
-syn match smartyProperty contained "indent="
-syn match smartyProperty contained "indent_first="
-syn match smartyProperty contained "indent_char="
syn match smartyProperty contained "wrap="
syn match smartyProperty contained "wrap_char="
-syn match smartyProperty contained "vauto="
syn match smartyProperty contained "wrap_cut="
+syn match smartyProperty contained "year_as_text="
+syn match smartyProperty contained "year_empty="
+syn match smartyProperty contained "year_extra="
+syn match smartyProperty contained "year_id="
+syn match smartyProperty contained "year_size="
+
+syn match smartyForeachProperty contained "@first"
+syn match smartyForeachProperty contained "@index"
+syn match smartyForeachProperty contained "@iteration"
+syn match smartyForeachProperty contained "@key"
+syn match smartyForeachProperty contained "@last"
+syn match smartyForeachProperty contained "@show"
+syn match smartyForeachProperty contained "@total"
syn match smartyConstant contained "\$smarty"
syn keyword smartyTodo contained FIXME NOTE TODO OPTIMIZE XXX
@@ -191,38 +229,46 @@ syn match smartyNumber "\<0x\x\{1,8}\>" contained display
syn keyword smartyBoolean contained true false
" Operator
-syn match smartyOperator contained "||\|&&\| neq \| gte \| lte \| not \| mod \| ne \| eq \| gt \| lt \| ge \| le \|===\|==\|!=\|>\|<\|>=\|<=\|!\|%"
+syn match smartyOperator contained "||\|&&\|===\|==\|!=\|>\|<\|>=\|<=\|!\|%"
+syn match smartyOperator contained " \@<=\(neq\|gte\|lte\|not\|mod\|ne\|eq\|gt\|lt\|ge\|le\|matches\) \@="
+syn match smartyOperator contained " \@<=is\( not\)\? \(even\|odd\)"
+syn match smartyOperator contained " \@<=is\( not\)\? \(div by\|even by\|odd by\) \@="
syn match smartyGlue contained "\.\|\->"
" Dollar
syn match smartyDollarSign contained "\$" " nextgroup=smartyVariable
syn match smartyMaybeDollarSign contained "\([^\\]\|\\\\\)\@<=\$"
+" Hash
+syn match smartyHashSign contained "#"
+
" Variable
-syn match smartyVariable contained "\$\@<=\(\h\w\{-}\(\.\|\->\|\[\w\{-}\]\(\.\|\->\)\)\)*\w*" contains=smartyGlue nextgroup=smartyFunctionArgs
+syn match smartyVariable contained "\$\@<=\(\h\w\{-}\(\.\|\->\|\[\w\{-}\]\(\.\|\->\)\)\)*\w*" contains=smartyGlue nextgroup=smartyForeachProperty
+syn match smartyVariable contained "#\@<=\w\+#\@="
syn match smartyMaybeVariable contained "\(\(^\|[^\\]\|\\\\\)\$\)\@<=\h\w*"
syn match smartyEscapedVariable contained "\\$\h\w*"
syn region smartyInBracket contained matchgroup=Constant start=+\[+ end=+\]+ contains=smartyVariable
syn region smartyInBacktick contained matchgroup=Constant start=+\`+ end=+\`+ contains=smartyVariable
-syn region smartyString contained matchgroup=Constant start=+'+ end=+'+ contains=smartyMaybeVariable, smartyInBacktick, smartyMaybeDollarSign keepend
-syn region smartyStringDouble contained matchgroup=Constant start=+"+ end=+"+ contains=smartyMaybeVariable, smartyInBacktick, smartyMaybeDollarSign keepend
+syn region smartyString contained matchgroup=Constant start=+'+ end=+'+ skip=+\\'+ contains=smartyMaybeVariable, smartyInBacktick, smartyMaybeDollarSign keepend
+syn region smartyStringDouble contained matchgroup=Constant start=+"+ end=+"+ skip=+\\"+ contains=smartyMaybeVariable, smartyInBacktick, smartyMaybeDollarSign keepend
syn region smartyModifier contained matchgroup=Statement start=+||\@!+ end=+\ze:\|\>+
-syn region smartyParameter contained matchgroup=Statement start=+:+ end=+\ze\(}\||\)+ contains=smartyVariable, smartyDollarSign, smartyGlue, smartyInBracket, smartyStringDouble contained
+syn region smartyParameter contained matchgroup=Statement start=+:+ end=+\ze\(}\||\)+ contains=smartyVariable, smartyDollarSign, smartyGlue, smartyInBracket, smartyString, smartyStringDouble contained
-syn region smartySimpleTag start="{\s\{-}[a-z$]\@=" end="}" contains=smartyParameter, smartyCProperty, smartyProperty, smartyGlue, smartyModifier, smartyDollarSign, smartyInBracket, smartyStringDouble, smartyVariable, smartyString, smartySTags, smartyConstant, smartySRepeat, smartyNumber, smartyBoolean, smartyOperator, smartyTodo
-syn region smartyStartTag start="{\(block\|for\|foreach\|function\|if\|literal\|nocache\|php\|section\|setfilter\|strip\|textformat\|while\)\@=" end="}" contains=smartyParameter, smartyCProperty, smartyProperty, smartyGlue, smartyModifier, smartyDollarSign, smartyInBracket, smartyStringDouble, smartyVariable, smartyString, smartyDTags, smartyConstant, smartyDRepeat, smartyNumber, smartyBoolean, smartyOperator, smartyConditional, smartyOperator
-syn region smartyMiddleTag start="{\(elseif\|else\|foreachelse\|sectionelse\)" end="}" contains=smartyConditional, smartyDRepeat
-syn region smartyEndTag start="{/\(block\|for\|foreach\|function\|if\|literal\|nocache\|php\|section\|setfilter\|strip\|textformat\|while\)\@=" end="}" contains=smartyDTags, smartyConditional, smartyDRepeat
-syn region smartyComment matchgroup=Comment start="{\*" end="\*}" contains=smartyTodo
+syn region smartySimpleTag start="{\s\{-}[a-z$'"#]\@=" end="}" contains=smartyParameter, smartyCProperty, smartyProperty, smartyGlue, smartyModifier, smartyDollarSign, smartyHashSign, smartyInBracket, smartyStringDouble, smartyVariable, smartyString, smartySTags, smartyConstant, smartySRepeat, smartyNumber, smartyBoolean, smartyOperator, smartyTodo, smartyForeachConstruct
+syn region smartyStartTag start="{\(block\|capture\|for\|foreach\|function\|if\|literal\|nocache\|php\|section\|setfilter\|strip\|textformat\|while\)\@=" end="}" contains=smartyParameter, smartyCProperty, smartyProperty, smartyGlue, smartyModifier, smartyDollarSign, smartyHashSign, smartyInBracket, smartyStringDouble, smartyVariable, smartyString, smartyDTags, smartyConstant, smartyDRepeat, smartyNumber, smartyBoolean, smartyOperator, smartyConditional, smartyOperator containedin=@htmlJavaScript
+syn region smartyMiddleTag start="{\(elseif\)\@=" end="}" contains=smartyParameter, smartyCProperty, smartyProperty, smartyGlue, smartyModifier, smartyDollarSign, smartyHashSign, smartyInBracket, smartyStringDouble, smartyVariable, smartyString, smartyDTags, smartyConstant, smartyDRepeat, smartyNumber, smartyBoolean, smartyOperator, smartyConditional, smartyOperator containedin=@htmlJavaScript
+syn region smartyMiddleTag start="{\(else\|foreachelse\|forelse\|sectionelse\)\>" end="}" contains=smartyConditional, smartyDRepeat containedin=@htmlJavaScript
+syn region smartyEndTag start="{/\(block\|capture\|for\|foreach\|function\|if\|literal\|nocache\|php\|section\|setfilter\|strip\|textformat\|while\)\@=" end="}" contains=smartyDTags, smartyConditional, smartyDRepeat containedin=@htmlJavaScript
+syn region smartyComment matchgroup=Comment start="{\*" end="\*}" contains=smartyTodo containedin=htmlString,@htmlJavaScript
-syn cluster htmlPreproc add=smartyZone add=smartyComment add=smartySimpleTag add=smartyStartTag add=smartyMiddleTag add=smartyEndTag
+syn cluster htmlPreproc add=smartySimpleTag add=smartyStartTag add=smartyMiddleTag add=smartyEndTag
syn region htmlString contained start=+"+ end=+"+ contains=htmlSpecialChar,javaScriptExpression,@htmlPreproc
syn region htmlString contained start=+'+ end=+'+ contains=htmlSpecialChar,javaScriptExpression,@htmlPreproc
-if version >= 508 || !exists("did_smarty_syn_inits")
- if version < 508
+if v:version >= 508 || !exists('did_smarty_syn_inits')
+ if v:version < 508
let did_smarty_syn_inits = 1
command -nargs=+ HiLink hi link
else
@@ -236,6 +282,9 @@ if version >= 508 || !exists("did_smarty_syn_inits")
HiLink smartyDRepeat Keyword
HiLink smartyDTags Keyword
HiLink smartyDollarSign Statement
+ HiLink smartyHashSign Statement
+ HiLink smartyForeachConstruct Keyword
+ HiLink smartyForeachProperty Keyword
HiLink smartyGlue Statement
HiLink smartyInBacktick Statement
HiLink smartyInBracket PreProc
@@ -261,9 +310,9 @@ endif
syn include syntax/php.vim
syn region phpRegion matchgroup=Delimiter start="{php}" end="{/php}" contains=@phpClTop
-let b:current_syntax = "smarty"
+let b:current_syntax = 'smarty'
-if main_syntax == 'smarty'
+if main_syntax ==# 'smarty'
unlet main_syntax
endif
diff --git a/test/filetype/smarty.vader b/test/filetype/smarty.vader
new file mode 100644
index 0000000..43ba5a9
--- /dev/null
+++ b/test/filetype/smarty.vader
@@ -0,0 +1,5 @@
+Execute (Load simple smarty file):
+ edit simple.tpl
+
+Then (Detected simple.tpl as a smarty file):
+ AssertEqual &filetype, 'smarty'
diff --git a/test/indent/hardtab.vader b/test/indent/hardtab.vader
new file mode 100644
index 0000000..99e56a5
--- /dev/null
+++ b/test/indent/hardtab.vader
@@ -0,0 +1,81 @@
+Execute (setup hardtab indent configuration):
+ set noexpandtab
+ set shiftwidth=4
+ set tabstop=4
+ set softtabstop=4
+ let g:smarty_indent_block=1
+
+Given smarty (non indented smarty template):
+ {if $test}
+ black
+ {elseif $test2}
+ white
+ {/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (hardtab indented result):
+ {if $test}
+ black
+ {elseif $test2}
+ white
+ {/if}
+
+############################################
+
+Given smarty (softtab indented result):
+
+
+ {if $test}
+ black
+ {elseif $test2}
+ white
+ {/if}
+
+
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (hardtab indented smarty template):
+
+
+ {if $test}
+ black
+ {elseif $test2}
+ white
+ {/if}
+
+
+
+############################################
+
+Execute (setup softtab indent configuration):
+ set expandtab
+
+Given smarty (hardtab indented smarty template):
+
+
+ {if $test}
+ black
+ {elseif $test2}
+ white
+ {/if}
+
+
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (softtab indented result):
+
+
+ {if $test}
+ black
+ {elseif $test2}
+ white
+ {/if}
+
+
+
diff --git a/test/indent/indent.vader b/test/indent/indent.vader
new file mode 100644
index 0000000..b689ba1
--- /dev/null
+++ b/test/indent/indent.vader
@@ -0,0 +1,329 @@
+Execute (setup indent configuration):
+ set expandtab
+ set shiftwidth=4
+ set tabstop=4
+ set softtabstop=4
+ let g:smarty_indent_block=1
+
+Given smarty (non indented smarty template):
+ {if $test}
+ black
+ {elseif $test2}
+ white
+ {/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (very basic indentation result):
+ {if $test}
+ black
+ {elseif $test2}
+ white
+ {/if}
+
+############################################
+
+Given smarty (non indented smarty template):
+ {if $test}
+ {if $test}
+ black
+ {/if}
+ {else}
+ {if $test}
+ white
+ {/if}
+ {/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (two levels elsif indentation result):
+ {if $test}
+ {if $test}
+ black
+ {/if}
+ {else}
+ {if $test}
+ white
+ {/if}
+ {/if}
+
+############################################
+
+Given smarty (non indented smarty template):
+ {if $test}
+ {if $test}
+ black
+ {/if}
+ {elseif $test2}
+ {if $test}
+ white
+ {/if}
+ {/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (two levels elsif indentation result):
+ {if $test}
+ {if $test}
+ black
+ {/if}
+ {elseif $test2}
+ {if $test}
+ white
+ {/if}
+ {/if}
+
+############################################
+
+Given smarty (non indented smarty template):
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (several oneline tags alone):
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+
+############################################
+
+Given smarty (non indented smarty template):
+ bla {if $test}bla{/if} bla
+ bla {if $test}bla{/if} bla
+ bla {if $test}bla{/if} bla
+ bla {if $test}bla{/if} bla
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (several oneline tags with text before and after):
+ bla {if $test}bla{/if} bla
+ bla {if $test}bla{/if} bla
+ bla {if $test}bla{/if} bla
+ bla {if $test}bla{/if} bla
+
+############################################
+
+Given smarty (non indented smarty template):
+ {if $test2}
+ {if $test}bla{/if}
+ {else}
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+ {/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (several oneline tags alone and nested):
+ {if $test2}
+ {if $test}bla{/if}
+ {else}
+ {if $test}bla{/if}
+ {if $test}bla{/if}
+ {/if}
+
+############################################
+# multiline tags
+
+Given smarty (non indented smarty template):
+ {if $test1 }
+
+
+ simple
+
+
+ {/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (onleline starting tag + html):
+ {if $test1 }
+
+
+ simple
+
+
+ {/if}
+
+############################################
+
+Given smarty (non indented smarty template):
+ {if
+ $test1
+ }
+
+
+ multi 1 condition
+
+
+ {/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (multiline starting tag one condition):
+ {if
+ $test1
+ }
+
+
+ multi 1 condition
+
+
+ {/if}
+
+############################################
+
+Given smarty (non indented smarty template):
+ {if $test1 &&
+ $test2 ||
+ $test3}
+
+
+ multi several conditions
+
+
+ {/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (multiline starting tag several simple conditions):
+ {if $test1 &&
+ $test2 ||
+ $test3}
+
+
+ multi several conditions
+
+
+ {/if}
+
+############################################
+
+Given smarty (non indented smarty template):
+ {if $test1 &&
+ $test2 ||
+ $test3
+ }
+
+
+ multi several conditions
+
+
+ {/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (multiline starting tag several simple conditions end bracket alone):
+ {if $test1 &&
+ $test2 ||
+ $test3
+ }
+
+
+ multi several conditions
+
+
+ {/if}
+
+############################################
+
+Given smarty (non indented smarty template):
+ {if {plugin $test1} &&
+ {$test2} ||
+ {$test3}}
+
+
+ multi several conditions and nested
+
+
+ {/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (multiline starting tag several conditions inside nested tags):
+ {if {plugin $test1} &&
+ {$test2} ||
+ {$test3}}
+
+
+ multi several conditions and nested
+
+
+ {/if}
+
+############################################
+
+Given smarty (non indented smarty template):
+ {if
+ {$test1} &&
+ {$test2} ||
+ {$test3}}
+
+
+ multi several conditions and nested
+
+
+ {/if}
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (multiline starting tag several conditions inside nested tags bracket and if on separate tag):
+ {if
+ {$test1} &&
+ {$test2} ||
+ {$test3}}
+
+
+ multi several conditions and nested
+
+
+ {/if}
+
+############################################
+
+Given smarty (non indented smarty template):
+ {if
+ ($test1) &&
+ ($test2) ||
+ ($test3)}
+
+
+ multi several conditions with parentheses
+
+
+ {/if}
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (multiline starting tag several conditions with parentheses):
+ {if
+ ($test1) &&
+ ($test2) ||
+ ($test3)}
+
+
+ multi several conditions with parentheses
+
+
+ {/if}
+
+############################################
diff --git a/test/indent/nosmartyindent.vader b/test/indent/nosmartyindent.vader
new file mode 100644
index 0000000..af94fda
--- /dev/null
+++ b/test/indent/nosmartyindent.vader
@@ -0,0 +1,44 @@
+Execute (setup indent configuration):
+ set expandtab
+ set shiftwidth=4
+ set tabstop=4
+ set softtabstop=4
+ let g:smarty_indent_block=0
+
+Given smarty (indented smarty template):
+ {if $test}
+ black
+ {elseif $test2}
+ white
+ {/if}
+
+Do (Indent the whole buffer without smarty indent option):
+ gg=G
+
+Expect smarty (non indented result):
+ {if $test}
+ black
+ {elseif $test2}
+ white
+ {/if}
+
+############################################
+
+Given smarty (non indented html content):
+
+
+ black
+
+
+
+Do (indented html content):
+ gg=G
+
+Expect smarty (non indented result):
+
+
+ black
+
+
+
+############################################
diff --git a/test/indent/smartyinjs.vader b/test/indent/smartyinjs.vader
new file mode 100644
index 0000000..61ad9da
--- /dev/null
+++ b/test/indent/smartyinjs.vader
@@ -0,0 +1,64 @@
+Execute (setup indent configuration):
+ set expandtab
+ set shiftwidth=4
+ set tabstop=4
+ set softtabstop=4
+ let g:smarty_indent_block=1
+ let g:html_indent_script1 = 'inc'
+
+Given smarty (indented smarty in
+
+# does not work in vim 8, maybe bug in syntax/html.vim
+Do (TODO: Indent the whole buffer):
+ gg=G
+
+Expect smarty (indented smarty in
+
+############################################
+
+Given smarty (indented smarty in
+
+Do (Indent the whole buffer):
+ gg=G
+
+Expect smarty (indented smarty in
diff --git a/test/init.vim b/test/init.vim
new file mode 100644
index 0000000..cdf2549
--- /dev/null
+++ b/test/init.vim
@@ -0,0 +1,19 @@
+" minimum vim configuration for test runner
+set nocompatible
+"let &packpath = expand(':p:h:h')
+" Remove first and last entry from runtimepath, to prevent loading plugins from ~/.vim
+" Replace first entry rom runtimepath, by current directory, preventing
+" loading plugins from ~/.vim and ensure the local syntax file is loaded
+" instead of the bundled one
+let &runtimepath = substitute(&runtimepath, '\v^.{-},(.*),.*$', '.,\1', '')
+
+filetype off
+set runtimepath+=vader.vim
+set runtimepath+=.
+set runtimepath+=after
+"force loading current syntax file first
+filetype plugin indent on
+syntax enable
+" Avoid closing up any fold since it results in some tests skipping lines and
+" their output ends up diverging from what we expect them to be.
+set foldlevel=99
diff --git a/test/run-tests.sh b/test/run-tests.sh
new file mode 100755
index 0000000..7f83feb
--- /dev/null
+++ b/test/run-tests.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# Download dependencies for tests and run full test suit
+# Can use TESTVIM env variable to choose between vim and nvim (neovim)
+# Optional first script argument can be path to vader file (run only one suite)
+#
+set -x
+TEST_FILE=$1
+SCRIPT_FOLDER=$(dirname "$(readlink -f "$0")")
+
+# TESTVIM env variable has precedence over installed programs
+# next in row is neovim and last one is vim
+if [ "$TESTVIM" == "vim" ]; then
+ RUNVIM=vim
+elif [ "$TESTVIM" == "nvim" ] || [ -x "$(command -v nvim)" ]; then
+ RUNVIM=nvim
+ VADER_OUTPUT_FILE=$(mktemp)
+ export VADER_OUTPUT_FILE
+ trap 'rm -f ${VADER_OUTPUT_FILE}' EXIT INT QUIT TERM
+elif [ -x "$(command -v vim)" ]; then
+ RUNVIM=vim
+else
+ echo 'Error: vim is not installed.' >&2
+ exit 1
+fi
+
+cd "${SCRIPT_FOLDER}/.." || exit
+
+if [ ! -d "vader.vim" ]; then
+ git clone https://github.com/junegunn/vader.vim.git
+fi
+
+if [ -z "$TEST_FILE" ]; then
+ TEST_SUITE='test/**/*.vader'
+else
+ TEST_SUITE=$TEST_FILE
+fi
+
+"${RUNVIM}" -u test/init.vim -c "Vader! ${TEST_SUITE}"
+vader_exit=$?
+[ -n "${VADER_OUTPUT_FILE}" ] && cat "${VADER_OUTPUT_FILE}"
+exit $vader_exit
+
diff --git a/test/syntax/comment.vader b/test/syntax/comment.vader
new file mode 100644
index 0000000..4ac4c9f
--- /dev/null
+++ b/test/syntax/comment.vader
@@ -0,0 +1,59 @@
+Given smarty (simple comment):
+ {* simple comment *}
+ content
+ {*
+ * multiline
+ *}
+
+
+Execute (comment detected inline, multiline and in html string):
+ AssertEqual 'smartyComment', SyntaxOf("comment")
+ AssertEqual 'smartyComment', SyntaxOf("multiline")
+ AssertEqual 'smartyComment', SyntaxOf("string")
+ AssertNotEqual 'smartyComment', SyntaxOf("content")
+
+############################################
+
+Given smarty (commented smarty code):
+ {* commented code
+ {if $condition}
+ {$variable}
+ {/if}
+ *}
+ {$outside}
+
+Execute (commented code detected as comment):
+ AssertEqual 'smartyComment', SyntaxOf("commented")
+ AssertEqual 'smartyComment', SyntaxOf("condition")
+ AssertEqual 'smartyComment', SyntaxOf("variable")
+ AssertNotEqual 'smartyComment', SyntaxOf("outside")
+
+############################################
+
+Given smarty (commented html code):
+ {* commented code
+
+ commented
+
+ *}
+ outside
+
+Execute (commented code detected as comment):
+ AssertEqual 'smartyComment', SyntaxOf("commented")
+ AssertEqual 'smartyComment', SyntaxOf("indiv")
+ AssertNotEqual 'smartyComment', SyntaxOf("outside")
+
+############################################
+
+Given smarty (commented html code):
+
+
+Execute (commented code detected as comment):
+ AssertEqual 'smartyComment', SyntaxOf("commented")
+ AssertEqual 'smartyComment', SyntaxOf("jsvar")
+ AssertNotEqual 'smartyComment', SyntaxOf("outside")
diff --git a/test/syntax/quote.vader b/test/syntax/quote.vader
new file mode 100644
index 0000000..886a9a0
--- /dev/null
+++ b/test/syntax/quote.vader
@@ -0,0 +1,31 @@
+Given smarty (simple quote):
+ {tag attribute='simple quote'}
+
+Execute (string in simple quote):
+ AssertEqual 'smartyString', SyntaxOf("simple")
+
+############################################
+
+Given smarty (double quote):
+ {tag attribute="double quote"}
+
+Execute (string in double quote):
+ AssertEqual 'smartyStringDouble', SyntaxOf("double")
+
+############################################
+
+Given smarty (simple escaped quote):
+ {tag attribute='simple quote \'escaped'}
+
+Execute (string in simple quote):
+ AssertEqual 'smartyString', SyntaxOf("escaped")
+
+############################################
+
+Given smarty (double escaped quote):
+ {tag attribute="double quote \"escaped"}
+
+Execute (string in double quote):
+ AssertEqual 'smartyStringDouble', SyntaxOf("escaped")
+
+############################################