summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rwxr-xr-xbuild1
-rwxr-xr-xbuild.py1
-rw-r--r--ftdetect/polyglot.vim4
-rw-r--r--ftplugin/fennel.vim30
-rw-r--r--indent/fennel.vim330
-rw-r--r--syntax/fennel.vim287
7 files changed, 655 insertions, 1 deletions
diff --git a/README.md b/README.md
index dac21607..f96ed08c 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ A collection of language packs for Vim.
> One to rule them all, one to find them, one to bring them all and in the darkness bind them.
- It **won't affect your startup time**, as scripts are loaded only on demand\*.
-- It **installs and updates 120+ times faster** than the <!--Package Count-->153<!--/Package Count--> packages it consists of.
+- It **installs and updates 120+ times faster** than the <!--Package Count-->154<!--/Package Count--> packages it consists of.
- Solid syntax and indentation support (other features skipped). Only the best language packs.
- All unnecessary files are ignored (like enormous documentation from php support).
- No support for esoteric languages, only most popular ones (modern too, like `slim`).
@@ -77,6 +77,7 @@ If you need full functionality of any plugin, please use it directly with your p
- [emberscript](https://github.com/yalesov/vim-ember-script) (syntax, indent, ftplugin)
- [emblem](https://github.com/yalesov/vim-emblem) (syntax, indent, ftplugin)
- [erlang](https://github.com/vim-erlang/vim-erlang-runtime) (syntax, indent)
+- [fennel](https://github.com/bakpakin/fennel.vim) (syntax, indent, ftplugin)
- [ferm](https://github.com/vim-scripts/ferm.vim) (syntax)
- [fish](https://github.com/georgewitteman/vim-fish) (syntax, indent, compiler, autoload, ftplugin)
- [flatbuffers](https://github.com/dcharbon/vim-flatbuffers) (syntax)
diff --git a/build b/build
index f9a05d09..a7dc6610 100755
--- a/build
+++ b/build
@@ -171,6 +171,7 @@ PACKS="
emberscript:yalesov/vim-ember-script
emblem:yalesov/vim-emblem
erlang:vim-erlang/vim-erlang-runtime
+ fennel:bakpakin/fennel.vim
ferm:vim-scripts/ferm.vim
fish:georgewitteman/vim-fish
flatbuffers:dcharbon/vim-flatbuffers
diff --git a/build.py b/build.py
index f1dcc33d..0f1a3ebb 100755
--- a/build.py
+++ b/build.py
@@ -254,6 +254,7 @@ language("XDC", extensions=[".xdc"])
language("Zig", extra_extensions=[".zir"])
language("Zir", extensions=[".zir"], polyglot="zig", filetype="zir")
language("Jsonnet")
+language("Fennel", extensions=[".fnl"])
lines.append('" restore Vi compatibility settings')
lines.append('let &cpo = s:cpo_save')
diff --git a/ftdetect/polyglot.vim b/ftdetect/polyglot.vim
index dfcab62f..028b8eb4 100644
--- a/ftdetect/polyglot.vim
+++ b/ftdetect/polyglot.vim
@@ -1147,6 +1147,10 @@ if index(g:polyglot_disabled, 'jsonnet') == -1
au BufNewFile,BufRead *.libsonnet set ft=jsonnet
endif
+if index(g:polyglot_disabled, 'fennel') == -1
+ au BufNewFile,BufRead *.fnl set ft=fennel
+endif
+
" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save \ No newline at end of file
diff --git a/ftplugin/fennel.vim b/ftplugin/fennel.vim
new file mode 100644
index 00000000..1fba74f1
--- /dev/null
+++ b/ftplugin/fennel.vim
@@ -0,0 +1,30 @@
+if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'fennel') == -1
+
+" Vim filetype plugin file
+" Language: FENNEL
+" Maintainer: Calvin Rose
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+"setlocal iskeyword+=!,_,%,?,-,*,!,+,/,=,<,>,.,:,$,^
+setlocal iskeyword=!,$,%,#,*,+,-,.,/,:,<,=,>,?,_,a-z,A-Z,48-57,128-247,124,126,38,94
+
+" There will be false positives, but this is better than missing the whole set
+" of user-defined def* definitions.
+setlocal define=\\v[(/]def(ault)@!\\S*
+
+" Remove 't' from 'formatoptions' to avoid auto-wrapping code.
+setlocal formatoptions-=t
+
+setlocal comments=n:;
+setlocal commentstring=;\ %s
+
+let &cpo = s:cpo_save
+
+endif
diff --git a/indent/fennel.vim b/indent/fennel.vim
new file mode 100644
index 00000000..c4516135
--- /dev/null
+++ b/indent/fennel.vim
@@ -0,0 +1,330 @@
+if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'fennel') == -1
+
+" Vim filetype plugin file
+" Language: FENNEL
+" Maintainer: Calvin Rose
+"
+" Modified from vim-clojure-static
+" https://github.com/guns/vim-clojure-static/blob/master/indent/clojure.vim
+" This should eventually be replaced by a more standard and performant
+" indenter.
+
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+setlocal noautoindent nosmartindent
+setlocal softtabstop=2 shiftwidth=2 expandtab
+setlocal indentkeys=!,o,O
+
+if exists("*searchpairpos")
+
+ if !exists('g:fennel_maxlines')
+ let g:fennel_maxlines = 100
+ endif
+
+ if !exists('g:fennel_fuzzy_indent')
+ let g:fennel_fuzzy_indent = 1
+ endif
+
+ if !exists('g:fennel_fuzzy_indent_patterns')
+ let g:fennel_fuzzy_indent_patterns = ['^def', '^let', '^while', '^if', '^fn$', '^var$', '^case$', '^for$', '^each$', '^local$', '^global$', '^match$', '^macro', '^lambda$']
+ endif
+
+ if !exists('g:fennel_fuzzy_indent_blacklist')
+ let g:fennel_fuzzy_indent_blacklist = []
+ endif
+
+ if !exists('g:fennel_special_indent_words')
+ let g:fennel_special_indent_words = ''
+ endif
+
+ if !exists('g:fennel_align_multiline_strings')
+ let g:fennel_align_multiline_strings = 0
+ endif
+
+ if !exists('g:fennel_align_subforms')
+ let g:fennel_align_subforms = 0
+ endif
+
+ function! s:syn_id_name()
+ return synIDattr(synID(line("."), col("."), 0), "name")
+ endfunction
+
+ function! s:ignored_region()
+ return s:syn_id_name() =~? '\vstring|comment|character'
+ endfunction
+
+ function! s:current_char()
+ return getline('.')[col('.')-1]
+ endfunction
+
+ function! s:current_word()
+ return getline('.')[col('.')-1 : searchpos('\v>', 'n', line('.'))[1]-2]
+ endfunction
+
+ function! s:is_paren()
+ return s:current_char() =~# '\v[\(\)\[\]\{\}]' && !s:ignored_region()
+ endfunction
+
+ " Returns 1 if string matches a pattern in 'patterns', which may be a
+ " list of patterns, or a comma-delimited string of implicitly anchored
+ " patterns.
+ function! s:match_one(patterns, string)
+ let list = type(a:patterns) == type([])
+ \ ? a:patterns
+ \ : map(split(a:patterns, ','), '"^" . v:val . "$"')
+ for pat in list
+ if a:string =~# pat | return 1 | endif
+ endfor
+ endfunction
+
+ function! s:match_pairs(open, close, stopat)
+ " Stop only on vector and map [ resp. {. Ignore the ones in strings and
+ " comments.
+ if a:stopat == 0 && g:fennel_maxlines > 0
+ let stopat = max([line(".") - g:fennel_maxlines, 0])
+ else
+ let stopat = a:stopat
+ endif
+
+ let pos = searchpairpos(a:open, '', a:close, 'bWn', "!s:is_paren()", stopat)
+ return [pos[0], col(pos)]
+ endfunction
+
+ function! s:fennel_check_for_string_worker()
+ " Check whether there is the last character of the previous line is
+ " highlighted as a string. If so, we check whether it's a ". In this
+ " case we have to check also the previous character. The " might be the
+ " closing one. In case the we are still in the string, we search for the
+ " opening ". If this is not found we take the indent of the line.
+ let nb = prevnonblank(v:lnum - 1)
+
+ if nb == 0
+ return -1
+ endif
+
+ call cursor(nb, 0)
+ call cursor(0, col("$") - 1)
+ if s:syn_id_name() !~? "string"
+ return -1
+ endif
+
+ " This will not work for a " in the first column...
+ if s:current_char() == '"' || s:current_char() == '`'
+ call cursor(0, col("$") - 2)
+ if s:syn_id_name() !~? "string"
+ return -1
+ endif
+ if s:current_char() != '\'
+ return -1
+ endif
+ call cursor(0, col("$") - 1)
+ endif
+
+ let p = searchpos('\(^\|[^\\]\)\zs"\`', 'bW')
+
+ if p != [0, 0]
+ return p[1] - 1
+ endif
+
+ return indent(".")
+ endfunction
+
+ function! s:check_for_string()
+ let pos = getpos('.')
+ try
+ let val = s:fennel_check_for_string_worker()
+ finally
+ call setpos('.', pos)
+ endtry
+ return val
+ endfunction
+
+ " Returns 1 for opening brackets, -1 for _anything else_.
+ function! s:bracket_type(char)
+ return stridx('([{', a:char) > -1 ? 1 : -1
+ endfunction
+
+ " Returns: [opening-bracket-lnum, indent]
+ function! s:fennel_indent_pos()
+ " Get rid of special case.
+ if line(".") == 1
+ return [0, 0]
+ endif
+
+ " We have to apply some heuristics here to figure out, whether to use
+ " normal lisp indenting or not.
+ let i = s:check_for_string()
+ if i > -1
+ return [0, i + !!g:fennel_align_multiline_strings]
+ endif
+
+ call cursor(0, 1)
+
+ " Find the next enclosing [ or {. We can limit the second search
+ " to the line, where the [ was found. If no [ was there this is
+ " zero and we search for an enclosing {.
+ let paren = s:match_pairs('(', ')', 0)
+ let bracket = s:match_pairs('\[', '\]', paren[0])
+ let curly = s:match_pairs('{', '}', bracket[0])
+
+ " In case the curly brace is on a line later then the [ or - in
+ " case they are on the same line - in a higher column, we take the
+ " curly indent.
+ if curly[0] > bracket[0] || curly[1] > bracket[1]
+ if curly[0] > paren[0] || curly[1] > paren[1]
+ return curly
+ endif
+ endif
+
+ " If the curly was not chosen, we take the bracket indent - if
+ " there was one.
+ if bracket[0] > paren[0] || bracket[1] > paren[1]
+ return bracket
+ endif
+
+ " There are neither { nor [ nor (, ie. we are at the toplevel.
+ if paren == [0, 0]
+ return paren
+ endif
+
+ " Now we have to reimplement lispindent. This is surprisingly easy, as
+ " soon as one has access to syntax items.
+ "
+ " - Check whether we are in a special position after a word in
+ " g:fennel_special_indent_words. These are special cases.
+ " - Get the next keyword after the (.
+ " - If its first character is also a (, we have another sexp and align
+ " one column to the right of the unmatched (.
+ " - In case it is in lispwords, we indent the next line to the column of
+ " the ( + sw.
+ " - If not, we check whether it is last word in the line. In that case
+ " we again use ( + sw for indent.
+ " - In any other case we use the column of the end of the word + 2.
+ call cursor(paren)
+
+ " In case we are at the last character, we use the paren position.
+ if col("$") - 1 == paren[1]
+ return paren
+ endif
+
+ " In case after the paren is a whitespace, we search for the next word.
+ call cursor(0, col('.') + 1)
+ if s:current_char() == ' '
+ call search('\v\S', 'W')
+ endif
+
+ " If we moved to another line, there is no word after the (. We
+ " use the ( position for indent.
+ if line(".") > paren[0]
+ return paren
+ endif
+
+ " We still have to check, whether the keyword starts with a (, [ or {.
+ " In that case we use the ( position for indent.
+ let w = s:current_word()
+ if s:bracket_type(w[0]) == 1
+ return paren
+ endif
+
+ let ww = w
+
+ if &lispwords =~# '\V\<' . ww . '\>'
+ return [paren[0], paren[1] + &shiftwidth - 1]
+ endif
+
+ if g:fennel_fuzzy_indent
+ \ && !s:match_one(g:fennel_fuzzy_indent_blacklist, ww)
+ \ && s:match_one(g:fennel_fuzzy_indent_patterns, ww)
+ return [paren[0], paren[1] + &shiftwidth - 1]
+ endif
+
+ call search('\v\_s', 'cW')
+ call search('\v\S', 'W')
+ if paren[0] < line(".")
+ return [paren[0], paren[1] + (g:fennel_align_subforms ? 0 : &shiftwidth - 1)]
+ endif
+
+ call search('\v\S', 'bW')
+ return [line('.'), col('.') + 1]
+ endfunction
+
+ function! GetFennelIndent()
+ let lnum = line('.')
+ let orig_lnum = lnum
+ let orig_col = col('.')
+ let [opening_lnum, indent] = s:fennel_indent_pos()
+
+ " Account for multibyte characters
+ if opening_lnum > 0
+ let indent -= indent - virtcol([opening_lnum, indent])
+ endif
+
+ " Return if there are no previous lines to inherit from
+ if opening_lnum < 1 || opening_lnum >= lnum - 1
+ call cursor(orig_lnum, orig_col)
+ return indent
+ endif
+
+ let bracket_count = 0
+
+ " Take the indent of the first previous non-white line that is
+ " at the same sexp level. cf. src/misc1.c:get_lisp_indent()
+ while 1
+ let lnum = prevnonblank(lnum - 1)
+ let col = 1
+
+ if lnum <= opening_lnum
+ break
+ endif
+
+ call cursor(lnum, col)
+
+ " Handle bracket counting edge case
+ if s:is_paren()
+ let bracket_count += s:bracket_type(s:current_char())
+ endif
+
+ while 1
+ if search('\v[(\[{}\])]', '', lnum) < 1
+ break
+ elseif !s:ignored_region()
+ let bracket_count += s:bracket_type(s:current_char())
+ endif
+ endwhile
+
+ if bracket_count == 0
+ " Check if this is part of a multiline string
+ call cursor(lnum, 1)
+ if s:syn_id_name() !~? '\vString|Buffer'
+ call cursor(orig_lnum, orig_col)
+ return indent(lnum)
+ endif
+ endif
+ endwhile
+
+ call cursor(orig_lnum, orig_col)
+ return indent
+ endfunction
+
+ setlocal indentexpr=GetFennelIndent()
+
+else
+
+ " In case we have searchpairpos not available we fall back to
+ " normal lisp indenting.
+ setlocal indentexpr=
+ setlocal lisp
+ let b:undo_indent .= '| setlocal lisp<'
+
+endif
+
+let &cpo = s:save_cpo
+unlet! s:save_cpo
+
+endif
diff --git a/syntax/fennel.vim b/syntax/fennel.vim
new file mode 100644
index 00000000..ec6f8084
--- /dev/null
+++ b/syntax/fennel.vim
@@ -0,0 +1,287 @@
+if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'fennel') == -1
+
+" Vim syntax file
+" Language: FENNEL
+" Maintainer: Calvin Rose
+
+if exists("b:current_syntax")
+ finish
+endif
+
+let s:cpo_sav = &cpo
+set cpo&vim
+
+if has("folding") && exists("g:fennel_fold") && g:fennel_fold > 0
+ setlocal foldmethod=syntax
+endif
+
+syntax keyword FennelCommentTodo contained FIXME XXX TODO FIXME: XXX: TODO:
+
+" FENNEL comments
+syn match FennelComment ";.*$" contains=FennelCommentTodo,@Spell
+
+syntax match FennelStringEscape '\v\\%([abfnrtv'"\\]|x[[0-9a-fA-F]]\{2}|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])' contained
+syntax region FennelString matchgroup=FennelStringDelimiter start=/"/ skip=/\\\\\|\\"/ end=/"/ contains=FennelStringEscape,@Spell
+syntax region FennelString matchgroup=FennelStringDelimiter start=/'/ skip=/\\\\\|\\'/ end=/'/ contains=FennelStringEscape,@Spell
+
+syn keyword FennelConstant nil
+
+syn keyword FennelBoolean true
+syn keyword FennelBoolean false
+
+" Fennel special forms
+syn keyword FennelSpecialForm #
+syn keyword FennelSpecialForm %
+syn keyword FennelSpecialForm *
+syn keyword FennelSpecialForm +
+syn keyword FennelSpecialForm -
+syn keyword FennelSpecialForm ->
+syn keyword FennelSpecialForm ->>
+syn keyword FennelSpecialForm -?>
+syn keyword FennelSpecialForm -?>>
+syn keyword FennelSpecialForm .
+syn keyword FennelSpecialForm ..
+syn keyword FennelSpecialForm /
+syn keyword FennelSpecialForm //
+syn keyword FennelSpecialForm :
+syn keyword FennelSpecialForm <
+syn keyword FennelSpecialForm <=
+syn keyword FennelSpecialForm =
+syn keyword FennelSpecialForm >
+syn keyword FennelSpecialForm >=
+syn keyword FennelSpecialForm ^
+syn keyword FennelSpecialForm and
+syn keyword FennelSpecialForm comment
+syn keyword FennelSpecialForm do
+syn keyword FennelSpecialForm doc
+syn keyword FennelSpecialForm doto
+syn keyword FennelSpecialForm each
+syn keyword FennelSpecialForm eval-compiler
+syn keyword FennelSpecialForm fn
+syn keyword FennelSpecialForm for
+syn keyword FennelSpecialForm global
+syn keyword FennelSpecialForm hashfn
+syn keyword FennelSpecialForm if
+syn keyword FennelSpecialForm include
+syn keyword FennelSpecialForm lambda
+syn keyword FennelSpecialForm length
+syn keyword FennelSpecialForm let
+syn keyword FennelSpecialForm local
+syn keyword FennelSpecialForm lua
+syn keyword FennelSpecialForm macro
+syn keyword FennelSpecialForm macros
+syn keyword FennelSpecialForm match
+syn keyword FennelSpecialForm not
+syn keyword FennelSpecialForm not=
+syn keyword FennelSpecialForm or
+syn keyword FennelSpecialForm partial
+syn keyword FennelSpecialForm quote
+syn keyword FennelSpecialForm require-macros
+syn keyword FennelSpecialForm set
+syn keyword FennelSpecialForm set-forcibly!
+syn keyword FennelSpecialForm tset
+syn keyword FennelSpecialForm values
+syn keyword FennelSpecialForm var
+syn keyword FennelSpecialForm when
+syn keyword FennelSpecialForm while
+syn keyword FennelSpecialForm ~=
+syn keyword FennelSpecialForm λ
+
+" Lua keywords
+syntax keyword LuaSpecialValue
+ \ _G
+ \ _VERSION
+ \ assert
+ \ collectgarbage
+ \ dofile
+ \ error
+ \ getmetatable
+ \ ipairs
+ \ load
+ \ loadfile
+ \ next
+ \ pairs
+ \ pcall
+ \ print
+ \ rawequal
+ \ rawget
+ \ rawlen
+ \ rawset
+ \ require
+ \ select
+ \ setmetatable
+ \ tonumber
+ \ tostring
+ \ type
+ \ xpcall
+ \ coroutine
+ \ coroutine.create
+ \ coroutine.isyieldable
+ \ coroutine.resume
+ \ coroutine.running
+ \ coroutine.status
+ \ coroutine.wrap
+ \ coroutine.yield
+ \ debug
+ \ debug.debug
+ \ debug.gethook
+ \ debug.getinfo
+ \ debug.getlocal
+ \ debug.getmetatable
+ \ debug.getregistry
+ \ debug.getupvalue
+ \ debug.getuservalue
+ \ debug.sethook
+ \ debug.setlocal
+ \ debug.setmetatable
+ \ debug.setupvalue
+ \ debug.setuservalue
+ \ debug.traceback
+ \ debug.upvalueid
+ \ debug.upvaluejoin
+ \ io
+ \ io.close
+ \ io.flush
+ \ io.input
+ \ io.lines
+ \ io.open
+ \ io.output
+ \ io.popen
+ \ io.read
+ \ io.stderr
+ \ io.stdin
+ \ io.stdout
+ \ io.tmpfile
+ \ io.type
+ \ io.write
+ \ math
+ \ math.abs
+ \ math.acos
+ \ math.asin
+ \ math.atan
+ \ math.ceil
+ \ math.cos
+ \ math.deg
+ \ math.exp
+ \ math.floor
+ \ math.fmod
+ \ math.huge
+ \ math.log
+ \ math.max
+ \ math.maxinteger
+ \ math.min
+ \ math.mininteger
+ \ math.modf
+ \ math.pi
+ \ math.rad
+ \ math.random
+ \ math.randomseed
+ \ math.sin
+ \ math.sqrt
+ \ math.tan
+ \ math.tointeger
+ \ math.type
+ \ math.ult
+ \ os
+ \ os.clock
+ \ os.date
+ \ os.difftime
+ \ os.execute
+ \ os.exit
+ \ os.getenv
+ \ os.remove
+ \ os.rename
+ \ os.setlocale
+ \ os.time
+ \ os.tmpname
+ \ package
+ \ package.config
+ \ package.cpath
+ \ package.loaded
+ \ package.loadlib
+ \ package.path
+ \ package.preload
+ \ package.searchers
+ \ package.searchpath
+ \ string
+ \ string.byte
+ \ string.char
+ \ string.dump
+ \ string.find
+ \ string.format
+ \ string.gmatch
+ \ string.gsub
+ \ string.len
+ \ string.lower
+ \ string.match
+ \ string.pack
+ \ string.packsize
+ \ string.rep
+ \ string.reverse
+ \ string.sub
+ \ string.unpack
+ \ string.upper
+ \ table
+ \ table.concat
+ \ table.insert
+ \ table.move
+ \ table.pack
+ \ table.remove
+ \ table.sort
+ \ table.unpack
+ \ utf8
+ \ utf8.char
+ \ utf8.charpattern
+ \ utf8.codepoint
+ \ utf8.codes
+ \ utf8.len
+ \ utf8.offset
+
+" Fennel Symbols
+let s:symcharnodig = '\!\$%\&\#\*\+\-./:<=>?A-Z^_a-z|\x80-\U10FFFF'
+let s:symchar = '0-9' . s:symcharnodig
+execute 'syn match FennelSymbol "\v<%([' . s:symcharnodig . '])%([' . s:symchar . '])*>"'
+execute 'syn match FennelKeyword "\v<:%([' . s:symchar . '])*>"'
+unlet! s:symchar s:symcharnodig
+
+syn match FennelQuote "`"
+syn match FennelQuote "@"
+
+" FENNEL numbers
+syntax match FennelNumber "\v\c<[-+]?\d*\.?\d*%([eE][-+]?\d+)?>"
+syntax match FennelNumber "\v\c<[-+]?0x[0-9A-F]*\.?[0-9A-F]*>"
+
+" Grammar root
+syntax cluster FennelTop contains=@Spell,FennelComment,FennelConstant,FennelQuote,FennelKeyword,LuaSpecialValue,FennelSymbol,FennelNumber,FennelString,FennelList,FennelArray,FennelTable,FennelSpecialForm,FennelBoolean
+
+syntax region FennelList matchgroup=FennelParen start="(" end=")" contains=@FennelTop fold
+syntax region FennelArray matchgroup=FennelParen start="\[" end="]" contains=@FennelTop fold
+syntax region FennelTable matchgroup=FennelParen start="{" end="}" contains=@FennelTop fold
+
+" Highlight superfluous closing parens, brackets and braces.
+syntax match FennelError "]\|}\|)"
+
+syntax sync fromstart
+
+" Highlighting
+hi def link FennelComment Comment
+hi def link FennelSymbol Identifier
+hi def link FennelNumber Number
+hi def link FennelConstant Constant
+hi def link FennelKeyword Keyword
+hi def link FennelSpecialForm Special
+hi def link LuaSpecialValue Special
+hi def link FennelString String
+hi def link FennelBuffer String
+hi def link FennelStringDelimiter String
+hi def link FennelBoolean Boolean
+
+hi def link FennelQuote SpecialChar
+hi def link FennelParen Delimiter
+
+let b:current_syntax = "fennel"
+
+let &cpo = s:cpo_sav
+unlet! s:cpo_sav
+
+endif