diff options
| author | Adam Stankiewicz <sheerun@sher.pl> | 2020-08-18 23:09:35 +0200 | 
|---|---|---|
| committer | Adam Stankiewicz <sheerun@sher.pl> | 2020-08-18 23:09:35 +0200 | 
| commit | e521ba3ae205b2c79df9030a3db767405caf0457 (patch) | |
| tree | 931693221fcf94669bfa1f69ac4fe65eb48b4a20 | |
| parent | ee4f51587d8e306b2d9a4b0067c572a447b34b60 (diff) | |
| download | vim-polyglot-e521ba3ae205b2c79df9030a3db767405caf0457.tar.gz vim-polyglot-e521ba3ae205b2c79df9030a3db767405caf0457.zip | |
Add fennel support, closes #514
Diffstat (limited to '')
| -rw-r--r-- | README.md | 3 | ||||
| -rwxr-xr-x | build | 1 | ||||
| -rwxr-xr-x | build.py | 1 | ||||
| -rw-r--r-- | ftdetect/polyglot.vim | 4 | ||||
| -rw-r--r-- | ftplugin/fennel.vim | 30 | ||||
| -rw-r--r-- | indent/fennel.vim | 330 | ||||
| -rw-r--r-- | syntax/fennel.vim | 287 | 
7 files changed, 655 insertions, 1 deletions
| @@ -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) @@ -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 @@ -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 | 
