From 02c7d9e3fe9647c72d36ea7cb49e885072e3fcbd Mon Sep 17 00:00:00 2001 From: Matt Singleton Date: Thu, 15 Dec 2011 12:37:21 -0500 Subject: adding coffescript vim support --- vim/after/syntax/haml.vim | 9 ++ vim/after/syntax/html.vim | 10 ++ vim/compiler/coffee.vim | 68 ++++++++++ vim/ftdetect/coffee.vim | 8 ++ vim/ftdetect/eco.vim | 1 + vim/ftplugin/coffee.vim | 221 +++++++++++++++++++++++++++++++ vim/indent/coffee.vim | 328 ++++++++++++++++++++++++++++++++++++++++++++++ vim/syntax/coffee.vim | 236 +++++++++++++++++++++++++++++++++ vim/syntax/eco.vim | 62 +++++++++ vimrc | 2 +- 10 files changed, 944 insertions(+), 1 deletion(-) create mode 100755 vim/after/syntax/haml.vim create mode 100755 vim/after/syntax/html.vim create mode 100755 vim/compiler/coffee.vim create mode 100755 vim/ftdetect/coffee.vim create mode 100755 vim/ftdetect/eco.vim create mode 100755 vim/ftplugin/coffee.vim create mode 100755 vim/indent/coffee.vim create mode 100755 vim/syntax/coffee.vim create mode 100755 vim/syntax/eco.vim diff --git a/vim/after/syntax/haml.vim b/vim/after/syntax/haml.vim new file mode 100755 index 0000000..d82fbea --- /dev/null +++ b/vim/after/syntax/haml.vim @@ -0,0 +1,9 @@ +" Language: CoffeeScript +" Maintainer: Sven Felix Oberquelle +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +" Inherit coffee from html so coffeeComment isn't redefined and given higher +" priority than hamlInterpolation. +syn cluster hamlCoffeescript contains=@htmlCoffeeScript +syn region hamlCoffeescriptFilter matchgroup=hamlFilter start="^\z(\s*\):coffeescript\s*$" end="^\%(\z1 \| *$\)\@!" contains=@hamlCoffeeScript,hamlInterpolation keepend diff --git a/vim/after/syntax/html.vim b/vim/after/syntax/html.vim new file mode 100755 index 0000000..63ebaec --- /dev/null +++ b/vim/after/syntax/html.vim @@ -0,0 +1,10 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +" Syntax highlighting for text/coffeescript script tags +syn include @htmlCoffeeScript syntax/coffee.vim +syn region coffeeScript start=++me=s-1 keepend +\ contains=@htmlCoffeeScript,htmlScriptTag,@htmlPreproc diff --git a/vim/compiler/coffee.vim b/vim/compiler/coffee.vim new file mode 100755 index 0000000..6d97cd8 --- /dev/null +++ b/vim/compiler/coffee.vim @@ -0,0 +1,68 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +if exists('current_compiler') + finish +endif + +let current_compiler = 'coffee' +" Pattern to check if coffee is the compiler +let s:pat = '^' . current_compiler + +" Extra options passed to CoffeeMake +if !exists("coffee_make_options") + let coffee_make_options = "" +endif + +" Get a `makeprg` for the current filename. This is needed to support filenames +" with spaces and quotes, but also not break generic `make`. +function! s:GetMakePrg() + return 'coffee -c ' . g:coffee_make_options . ' $* ' . fnameescape(expand('%')) +endfunction + +" Set `makeprg` and return 1 if coffee is still the compiler, else return 0. +function! s:SetMakePrg() + if &l:makeprg =~ s:pat + let &l:makeprg = s:GetMakePrg() + elseif &g:makeprg =~ s:pat + let &g:makeprg = s:GetMakePrg() + else + return 0 + endif + + return 1 +endfunction + +" Set a dummy compiler so we can check whether to set locally or globally. +CompilerSet makeprg=coffee +call s:SetMakePrg() + +CompilerSet errorformat=Error:\ In\ %f\\,\ %m\ on\ line\ %l, + \Error:\ In\ %f\\,\ Parse\ error\ on\ line\ %l:\ %m, + \SyntaxError:\ In\ %f\\,\ %m, + \%-G%.%# + +" Compile the current file. +command! -bang -bar -nargs=* CoffeeMake make + +" Set `makeprg` on rename since we embed the filename in the setting. +augroup CoffeeUpdateMakePrg + autocmd! + + " Update `makeprg` if coffee is still the compiler, else stop running this + " function. + function! s:UpdateMakePrg() + if !s:SetMakePrg() + autocmd! CoffeeUpdateMakePrg + endif + endfunction + + " Set autocmd locally if compiler was set locally. + if &l:makeprg =~ s:pat + autocmd BufFilePost,BufWritePost call s:UpdateMakePrg() + else + autocmd BufFilePost,BufWritePost call s:UpdateMakePrg() + endif +augroup END diff --git a/vim/ftdetect/coffee.vim b/vim/ftdetect/coffee.vim new file mode 100755 index 0000000..25daf12 --- /dev/null +++ b/vim/ftdetect/coffee.vim @@ -0,0 +1,8 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +autocmd BufNewFile,BufRead *.coffee set filetype=coffee +autocmd BufNewFile,BufRead *Cakefile set filetype=coffee +autocmd BufNewFile,BufRead *.coffeekup set filetype=coffee diff --git a/vim/ftdetect/eco.vim b/vim/ftdetect/eco.vim new file mode 100755 index 0000000..b420649 --- /dev/null +++ b/vim/ftdetect/eco.vim @@ -0,0 +1 @@ +autocmd BufNewFile,BufRead *.eco set filetype=eco diff --git a/vim/ftplugin/coffee.vim b/vim/ftplugin/coffee.vim new file mode 100755 index 0000000..12ae3f0 --- /dev/null +++ b/vim/ftplugin/coffee.vim @@ -0,0 +1,221 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +if exists("b:did_ftplugin") + finish +endif + +let b:did_ftplugin = 1 + +setlocal formatoptions-=t formatoptions+=croql +setlocal comments=:# +setlocal commentstring=#\ %s +setlocal omnifunc=javascriptcomplete#CompleteJS + +" Enable CoffeeMake if it won't overwrite any settings. +if !len(&l:makeprg) + compiler coffee +endif + +" Reset the global variables used by CoffeeCompile. +function! s:CoffeeCompileResetVars() + " Position in the source buffer + let s:coffee_compile_src_buf = -1 + let s:coffee_compile_src_pos = [] + + " Position in the CoffeeCompile buffer + let s:coffee_compile_buf = -1 + let s:coffee_compile_win = -1 + let s:coffee_compile_pos = [] + + " If CoffeeCompile is watching a buffer + let s:coffee_compile_watch = 0 +endfunction + +" Save the cursor position when moving to and from the CoffeeCompile buffer. +function! s:CoffeeCompileSavePos() + let buf = bufnr('%') + let pos = getpos('.') + + if buf == s:coffee_compile_buf + let s:coffee_compile_pos = pos + else + let s:coffee_compile_src_buf = buf + let s:coffee_compile_src_pos = pos + endif +endfunction + +" Restore the cursor to the source buffer. +function! s:CoffeeCompileRestorePos() + let win = bufwinnr(s:coffee_compile_src_buf) + + if win != -1 + exec win 'wincmd w' + call setpos('.', s:coffee_compile_src_pos) + endif +endfunction + +" Close the CoffeeCompile buffer and clean things up. +function! s:CoffeeCompileClose() + silent! autocmd! CoffeeCompileAuPos + silent! autocmd! CoffeeCompileAuWatch + + call s:CoffeeCompileRestorePos() + call s:CoffeeCompileResetVars() +endfunction + +" Update the CoffeeCompile buffer given some input lines. +function! s:CoffeeCompileUpdate(startline, endline) + let input = join(getline(a:startline, a:endline), "\n") + + " Coffee doesn't like empty input. + if !len(input) + return + endif + + " Compile input. + let output = system('coffee -scb 2>&1', input) + + " Move to the CoffeeCompile buffer. + exec s:coffee_compile_win 'wincmd w' + + " Replace buffer contents with new output and delete the last empty line. + setlocal modifiable + exec '% delete _' + put! =output + exec '$ delete _' + setlocal nomodifiable + + " Highlight as JavaScript if there is no compile error. + if v:shell_error + setlocal filetype= + else + setlocal filetype=javascript + endif + + " Restore the cursor in the compiled output. + call setpos('.', s:coffee_compile_pos) +endfunction + +" Update the CoffeeCompile buffer with the whole source buffer and restore the +" cursor. +function! s:CoffeeCompileWatchUpdate() + call s:CoffeeCompileSavePos() + call s:CoffeeCompileUpdate(1, '$') + call s:CoffeeCompileRestorePos() +endfunction + +" Peek at compiled CoffeeScript in a scratch buffer. We handle ranges like this +" to prevent the cursor from being moved (and its position saved) before the +" function is called. +function! s:CoffeeCompile(startline, endline, args) + " Don't compile the CoffeeCompile buffer. + if bufnr('%') == s:coffee_compile_buf + return + endif + + " Parse arguments. + let watch = a:args =~ '\' + let unwatch = a:args =~ '\' + let size = str2nr(matchstr(a:args, '\<\d\+\>')) + + " Determine default split direction. + if exists("g:coffee_compile_vert") + let vert = 1 + else + let vert = a:args =~ '\' + endif + + " Remove any watch listeners. + silent! autocmd! CoffeeCompileAuWatch + + " If just unwatching, don't compile. + if unwatch + let s:coffee_compile_watch = 0 + return + endif + + if watch + let s:coffee_compile_watch = 1 + endif + + call s:CoffeeCompileSavePos() + + " Build the CoffeeCompile buffer if it doesn't exist. + if s:coffee_compile_buf == -1 + let src_win = bufwinnr(s:coffee_compile_src_buf) + + " Create the new window and resize it. + if vert + let width = size ? size : winwidth(src_win) / 2 + + vertical new + exec 'vertical resize' width + else + " Try to guess the compiled output's height. + let height = size ? size : min([winheight(src_win) / 2, + \ a:endline - a:startline + 2]) + + botright new + exec 'resize' height + endif + + " Set up scratch buffer. + setlocal bufhidden=wipe buftype=nofile + setlocal nobuflisted nomodifiable noswapfile nowrap + + autocmd BufWipeout call s:CoffeeCompileClose() + nnoremap q :hide + + " Save the cursor position on each buffer switch. + augroup CoffeeCompileAuPos + autocmd BufEnter,BufLeave * call s:CoffeeCompileSavePos() + augroup END + + let s:coffee_compile_buf = bufnr('%') + let s:coffee_compile_win = bufwinnr(s:coffee_compile_buf) + endif + + " Go back to the source buffer and do the initial compile. + call s:CoffeeCompileRestorePos() + + if s:coffee_compile_watch + call s:CoffeeCompileWatchUpdate() + + augroup CoffeeCompileAuWatch + autocmd InsertLeave call s:CoffeeCompileWatchUpdate() + augroup END + else + call s:CoffeeCompileUpdate(a:startline, a:endline) + endif +endfunction + +" Complete arguments for the CoffeeCompile command. +function! s:CoffeeCompileComplete(arg, cmdline, cursor) + let args = ['unwatch', 'vertical', 'watch'] + + if !len(a:arg) + return args + endif + + let match = '^' . a:arg + + for arg in args + if arg =~ match + return [arg] + endif + endfor +endfunction + +" Don't let new windows overwrite the CoffeeCompile variables. +if !exists("s:coffee_compile_buf") + call s:CoffeeCompileResetVars() +endif + +" Peek at compiled CoffeeScript. +command! -range=% -bar -nargs=* -complete=customlist,s:CoffeeCompileComplete +\ CoffeeCompile call s:CoffeeCompile(, , ) +" Run some CoffeeScript. +command! -range=% -bar CoffeeRun ,:w !coffee -s diff --git a/vim/indent/coffee.vim b/vim/indent/coffee.vim new file mode 100755 index 0000000..a798cfc --- /dev/null +++ b/vim/indent/coffee.vim @@ -0,0 +1,328 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +if exists("b:did_indent") + finish +endif + +let b:did_indent = 1 + +setlocal autoindent +setlocal indentexpr=GetCoffeeIndent(v:lnum) +" Make sure GetCoffeeIndent is run when these are typed so they can be +" indented or outdented. +setlocal indentkeys+=0],0),0.,=else,=when,=catch,=finally + +" Only define the function once. +if exists("*GetCoffeeIndent") + finish +endif + +" Keywords to indent after +let s:INDENT_AFTER_KEYWORD = '^\%(if\|unless\|else\|for\|while\|until\|' +\ . 'loop\|switch\|when\|try\|catch\|finally\|' +\ . 'class\)\>' + +" Operators to indent after +let s:INDENT_AFTER_OPERATOR = '\%([([{:=]\|[-=]>\)$' + +" Keywords and operators that continue a line +let s:CONTINUATION = '\<\%(is\|isnt\|and\|or\)\>$' +\ . '\|' +\ . '\%(-\@\|\*\|/\@' + +" A compound assignment like `... = if ...` +let s:COMPOUND_ASSIGNMENT = '[:=]\s*\%(if\|unless\|for\|while\|until\|' +\ . 'switch\|try\|class\)\>' + +" A postfix condition like `return ... if ...`. +let s:POSTFIX_CONDITION = '\S\s\+\zs\<\%(if\|unless\)\>' + +" A single-line else statement like `else ...` but not `else if ... +let s:SINGLE_LINE_ELSE = '^else\s\+\%(\<\%(if\|unless\)\>\)\@!' + +" Max lines to look back for a match +let s:MAX_LOOKBACK = 50 + +" Syntax names for strings +let s:SYNTAX_STRING = 'coffee\%(String\|AssignString\|Embed\|Regex\|Heregex\|' +\ . 'Heredoc\)' + +" Syntax names for comments +let s:SYNTAX_COMMENT = 'coffee\%(Comment\|BlockComment\|HeregexComment\)' + +" Syntax names for strings and comments +let s:SYNTAX_STRING_COMMENT = s:SYNTAX_STRING . '\|' . s:SYNTAX_COMMENT + +" Get the linked syntax name of a character. +function! s:SyntaxName(linenum, col) + return synIDattr(synID(a:linenum, a:col, 1), 'name') +endfunction + +" Check if a character is in a comment. +function! s:IsComment(linenum, col) + return s:SyntaxName(a:linenum, a:col) =~ s:SYNTAX_COMMENT +endfunction + +" Check if a character is in a string. +function! s:IsString(linenum, col) + return s:SyntaxName(a:linenum, a:col) =~ s:SYNTAX_STRING +endfunction + +" Check if a character is in a comment or string. +function! s:IsCommentOrString(linenum, col) + return s:SyntaxName(a:linenum, a:col) =~ s:SYNTAX_STRING_COMMENT +endfunction + +" Check if a whole line is a comment. +function! s:IsCommentLine(linenum) + " Check the first non-whitespace character. + return s:IsComment(a:linenum, indent(a:linenum) + 1) +endfunction + +" Repeatedly search a line for a regex until one is found outside a string or +" comment. +function! s:SmartSearch(linenum, regex) + " Start at the first column. + let col = 0 + + " Search until there are no more matches, unless a good match is found. + while 1 + call cursor(a:linenum, col + 1) + let [_, col] = searchpos(a:regex, 'cn', a:linenum) + + " No more matches. + if !col + break + endif + + if !s:IsCommentOrString(a:linenum, col) + return 1 + endif + endwhile + + " No good match found. + return 0 +endfunction + +" Skip a match if it's in a comment or string, is a single-line statement that +" isn't adjacent, or is a postfix condition. +function! s:ShouldSkip(startlinenum, linenum, col) + if s:IsCommentOrString(a:linenum, a:col) + return 1 + endif + + " Check for a single-line statement that isn't adjacent. + if s:SmartSearch(a:linenum, '\') && a:startlinenum - a:linenum > 1 + return 1 + endif + + if s:SmartSearch(a:linenum, s:POSTFIX_CONDITION) && + \ !s:SmartSearch(a:linenum, s:COMPOUND_ASSIGNMENT) + return 1 + endif + + return 0 +endfunction + +" Find the farthest line to look back to, capped to line 1 (zero and negative +" numbers cause bad things). +function! s:MaxLookback(startlinenum) + return max([1, a:startlinenum - s:MAX_LOOKBACK]) +endfunction + +" Get the skip expression for searchpair(). +function! s:SkipExpr(startlinenum) + return "s:ShouldSkip(" . a:startlinenum . ", line('.'), col('.'))" +endfunction + +" Search for pairs of text. +function! s:SearchPair(start, end) + " The cursor must be in the first column for regexes to match. + call cursor(0, 1) + + let startlinenum = line('.') + + " Don't need the W flag since MaxLookback caps the search to line 1. + return searchpair(a:start, '', a:end, 'bcn', + \ s:SkipExpr(startlinenum), + \ s:MaxLookback(startlinenum)) +endfunction + +" Try to find a previous matching line. +function! s:GetMatch(curline) + let firstchar = a:curline[0] + + if firstchar == '}' + return s:SearchPair('{', '}') + elseif firstchar == ')' + return s:SearchPair('(', ')') + elseif firstchar == ']' + return s:SearchPair('\[', '\]') + elseif a:curline =~ '^else\>' + return s:SearchPair('\<\%(if\|unless\|when\)\>', '\') + elseif a:curline =~ '^catch\>' + return s:SearchPair('\', '\') + elseif a:curline =~ '^finally\>' + return s:SearchPair('\', '\') + endif + + return 0 +endfunction + +" Get the nearest previous line that isn't a comment. +function! s:GetPrevNormalLine(startlinenum) + let curlinenum = a:startlinenum + + while curlinenum > 0 + let curlinenum = prevnonblank(curlinenum - 1) + + if !s:IsCommentLine(curlinenum) + return curlinenum + endif + endwhile + + return 0 +endfunction + +" Try to find a comment in a line. +function! s:FindComment(linenum) + let col = 0 + + while 1 + call cursor(a:linenum, col + 1) + let [_, col] = searchpos('#', 'cn', a:linenum) + + if !col + break + endif + + if s:IsComment(a:linenum, col) + return col + endif + endwhile + + return 0 +endfunction + +" Get a line without comments or surrounding whitespace. +function! s:GetTrimmedLine(linenum) + let comment = s:FindComment(a:linenum) + let line = getline(a:linenum) + + if comment + " Subtract 1 to get to the column before the comment and another 1 for + " zero-based indexing. + let line = line[:comment - 2] + endif + + return substitute(substitute(line, '^\s\+', '', ''), + \ '\s\+$', '', '') +endfunction + +function! s:GetCoffeeIndent(curlinenum) + let prevlinenum = s:GetPrevNormalLine(a:curlinenum) + + " Don't do anything if there's no previous line. + if !prevlinenum + return -1 + endif + + let curline = s:GetTrimmedLine(a:curlinenum) + + " Try to find a previous matching statement. This handles outdenting. + let matchlinenum = s:GetMatch(curline) + + if matchlinenum + return indent(matchlinenum) + endif + + " Try to find a matching `when`. + if curline =~ '^when\>' && !s:SmartSearch(prevlinenum, '\') + let linenum = a:curlinenum + + while linenum > 0 + let linenum = s:GetPrevNormalLine(linenum) + + if getline(linenum) =~ '^\s*when\>' + return indent(linenum) + endif + endwhile + + return -1 + endif + + let prevline = s:GetTrimmedLine(prevlinenum) + let previndent = indent(prevlinenum) + + " Always indent after these operators. + if prevline =~ s:INDENT_AFTER_OPERATOR + return previndent + &shiftwidth + endif + + " Indent after a continuation if it's the first. + if prevline =~ s:CONTINUATION + let prevprevlinenum = s:GetPrevNormalLine(prevlinenum) + + " If the continuation is the first in the file, don't run the other checks. + if !prevprevlinenum + return previndent + &shiftwidth + endif + + let prevprevline = s:GetTrimmedLine(prevprevlinenum) + + if prevprevline !~ s:CONTINUATION && prevprevline !~ s:CONTINUATION_BLOCK + return previndent + &shiftwidth + endif + + return -1 + endif + + " Indent after these keywords and compound assignments if they aren't a + " single-line statement. + if prevline =~ s:INDENT_AFTER_KEYWORD || prevline =~ s:COMPOUND_ASSIGNMENT + if !s:SmartSearch(prevlinenum, '\') && prevline !~ s:SINGLE_LINE_ELSE + return previndent + &shiftwidth + endif + + return -1 + endif + + " Indent a dot access if it's the first. + if curline =~ s:DOT_ACCESS && prevline !~ s:DOT_ACCESS + return previndent + &shiftwidth + endif + + " Outdent after these keywords if they don't have a postfix condition or are + " a single-line statement. + if prevline =~ s:OUTDENT_AFTER + if !s:SmartSearch(prevlinenum, s:POSTFIX_CONDITION) || + \ s:SmartSearch(prevlinenum, '\') + return previndent - &shiftwidth + endif + endif + + " No indenting or outdenting is needed. + return -1 +endfunction + +" Wrap s:GetCoffeeIndent to keep the cursor position. +function! GetCoffeeIndent(curlinenum) + let oldcursor = getpos('.') + let indent = s:GetCoffeeIndent(a:curlinenum) + call setpos('.', oldcursor) + + return indent +endfunction diff --git a/vim/syntax/coffee.vim b/vim/syntax/coffee.vim new file mode 100755 index 0000000..c324435 --- /dev/null +++ b/vim/syntax/coffee.vim @@ -0,0 +1,236 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +" Bail if our syntax is already loaded. +if exists('b:current_syntax') && b:current_syntax == 'coffee' + finish +endif + +" Include JavaScript for coffeeEmbed. +syn include @coffeeJS syntax/javascript.vim + +" Highlight long strings. +syn sync minlines=100 + +" CoffeeScript identifiers can have dollar signs. +setlocal isident+=$ + +" These are `matches` instead of `keywords` because vim's highlighting +" priority for keywords is higher than matches. This causes keywords to be +" highlighted inside matches, even if a match says it shouldn't contain them -- +" like with coffeeAssign and coffeeDot. +syn match coffeeStatement /\<\%(return\|break\|continue\|throw\)\>/ display +hi def link coffeeStatement Statement + +syn match coffeeRepeat /\<\%(for\|while\|until\|loop\)\>/ display +hi def link coffeeRepeat Repeat + +syn match coffeeConditional /\<\%(if\|else\|unless\|switch\|when\|then\)\>/ +\ display +hi def link coffeeConditional Conditional + +syn match coffeeException /\<\%(try\|catch\|finally\)\>/ display +hi def link coffeeException Exception + +syn match coffeeKeyword /\<\%(new\|in\|of\|by\|and\|or\|not\|is\|isnt\|class\|extends\|super\|do\)\>/ +\ display +" The `own` keyword is only a keyword after `for`. +syn match coffeeKeyword /\/ contained containedin=coffeeRepeat +\ display +hi def link coffeeKeyword Keyword + +syn match coffeeOperator /\<\%(instanceof\|typeof\|delete\)\>/ display +hi def link coffeeOperator Operator + +" The first case matches symbol operators only if they have an operand before. +syn match coffeeExtendedOp /\%(\S\s*\)\@<=[+\-*/%&|\^=!<>?.]\+\|[-=]>\|--\|++\|::/ +\ display +syn match coffeeExtendedOp /\%(and\|or\)=/ display +hi def link coffeeExtendedOp coffeeOperator + +" This is separate from `coffeeExtendedOp` to help differentiate commas from +" dots. +syn match coffeeSpecialOp /[,;]/ display +hi def link coffeeSpecialOp SpecialChar + +syn match coffeeBoolean /\<\%(true\|on\|yes\|false\|off\|no\)\>/ display +hi def link coffeeBoolean Boolean + +syn match coffeeGlobal /\<\%(null\|undefined\)\>/ display +hi def link coffeeGlobal Type + +" A special variable +syn match coffeeSpecialVar /\<\%(this\|prototype\|arguments\)\>/ display +" An @-variable +syn match coffeeSpecialVar /@\%(\I\i*\)\?/ display +hi def link coffeeSpecialVar Special + +" A class-like name that starts with a capital letter +syn match coffeeObject /\<\u\w*\>/ display +hi def link coffeeObject Structure + +" A constant-like name in SCREAMING_CAPS +syn match coffeeConstant /\<\u[A-Z0-9_]\+\>/ display +hi def link coffeeConstant Constant + +" A variable name +syn cluster coffeeIdentifier contains=coffeeSpecialVar,coffeeObject, +\ coffeeConstant + +" A non-interpolated string +syn cluster coffeeBasicString contains=@Spell,coffeeEscape +" An interpolated string +syn cluster coffeeInterpString contains=@coffeeBasicString,coffeeInterp + +" Regular strings +syn region coffeeString start=/"/ skip=/\\\\\|\\"/ end=/"/ +\ contains=@coffeeInterpString +syn region coffeeString start=/'/ skip=/\\\\\|\\'/ end=/'/ +\ contains=@coffeeBasicString +hi def link coffeeString String + +" A integer, including a leading plus or minus +syn match coffeeNumber /\i\@/ display +hi def link coffeeNumber Number + +" A floating-point number, including a leading plus or minus +syn match coffeeFloat /\i\@/ + \ display + hi def link coffeeReservedError Error +endif + +" This is separate from `coffeeExtendedOp` since assignments require it. +syn match coffeeAssignOp /:/ contained display +hi def link coffeeAssignOp coffeeOperator + +" Strings used in string assignments, which can't have interpolations +syn region coffeeAssignString start=/"/ skip=/\\\\\|\\"/ end=/"/ contained +\ contains=@coffeeBasicString +syn region coffeeAssignString start=/'/ skip=/\\\\\|\\'/ end=/'/ contained +\ contains=@coffeeBasicString +hi def link coffeeAssignString String + +" A normal object assignment +syn match coffeeObjAssign /@\?\I\i*\s*:\@/ contains=@coffeeTop containedin=ALLBUT,@ecoRegions keepend +syn region ecoExpression matchgroup=ecoDelimiter start=/<%[=\-]/ end=/%>/ contains=@coffeeTop containedin=ALLBUT,@ecoRegions keepend +syn region ecoComment matchgroup=ecoComment start=/<%#/ end=/%>/ contains=@coffeeTodo,@Spell containedin=ALLBUT,@ecoRegions keepend + +" eco features not in coffeescript proper +syn keyword ecoEnd end containedin=@ecoRegions +syn match ecoIndentColon /\s+\w+:/ containedin=@ecoRegions + +" Define the default highlighting. + +hi def link ecoDelimiter Delimiter +hi def link ecoComment Comment +hi def link ecoEnd coffeeConditional +hi def link ecoIndentColon None + +let b:current_syntax = 'eco' + +" vim: nowrap sw=2 sts=2 ts=8: diff --git a/vimrc b/vimrc index 9602790..e958ccc 100644 --- a/vimrc +++ b/vimrc @@ -41,6 +41,7 @@ if has("autocmd") au FileType ruby setlocal ts=2 sw=2 sts=2 au FileType eruby setlocal ts=2 sw=2 sts=2 au FileType htmldjango setlocal ts=2 sw=2 sts=2 + au FileType coffee setlocal ts=2 sw=2 sts=2 " text files au BufRead,BufNewFile *.txt setlocal filetype=text @@ -78,7 +79,6 @@ endif " noremap :source ~/.vimrc -noremap :call RunSpec() " NERDTree noremap :NERDTreeToggle -- cgit v1.2.3