1
0
mirror of https://github.com/amix/vimrc synced 2025-06-23 06:35:01 +08:00

Updated all the plugins. Removed powerline. Added vim-airline (replacement for powerline). Added vim-fugitive.

This commit is contained in:
amix
2013-11-16 19:45:48 +00:00
parent 351979d3e0
commit 86f4456be1
239 changed files with 14942 additions and 8068 deletions

View File

@ -2,7 +2,7 @@ REF = HEAD
VERSION = $(shell git describe --always $(REF))
ARCHIVE = vim-coffee-script-$(VERSION).zip
ARCHIVE_DIRS = after compiler doc ftdetect ftplugin indent syntax
ARCHIVE_DIRS = after autoload compiler doc ftdetect ftplugin indent syntax
# Don't do anything by default.
all:

View File

@ -1,226 +1,555 @@
This project adds [CoffeeScript] support to the vim editor. It handles syntax,
indenting, compiling, and more. Also included is support for CoffeeScript in
Haml and HTML.
This project adds [CoffeeScript] support to vim. It covers syntax, indenting,
compiling, and more.
![Screenshot](http://i.imgur.com/eUBvm.png)
![Screenshot](http://i.imgur.com/j1BhpZQ.png)
[CoffeeScript]: http://jashkenas.github.com/coffee-script/
[CoffeeScript]: http://coffeescript.org/
### Install from a Zipball
## Table of Contents
This is the quickest way to get things running.
- Installation
- [Requirements](#requirements)
- [Install using Pathogen](#install-using-pathogen)
- [Install using Vundle](#install-using-vundle)
- [Install from a Zip File](#install-from-a-zip-file)
- Coffee Commands
- [Compile to JavaScript](#compile-to-javascript)
- [Compile CoffeeScript Snippets](#coffeecompile-compile-coffeescript-snippets)
- [Live Preview Compiling](#coffeewatch-live-preview-compiling)
- [Run CoffeeScript Snippets](#coffeerun-run-coffeescript-snippets)
- [Lint your CoffeeScript](#coffeelint-lint-your-coffeescript)
- Extras
- [Literate CoffeeScript](#literate-coffeescript)
- [CoffeeScript in HTML](#coffeescript-in-html)
- [CoffeeScript in Haml](#coffeescript-in-haml)
- Configuration
- [Custom Autocmds](#custom-autocmds)
- [Configuration Variables](#configuration-variables)
- [Configure Syntax Highlighting](#configure-syntax-highlighting)
- [Tune Vim for CoffeeScript](#tune-vim-for-coffeescript)
1. Download the latest zipball from [vim.org][zipball-vim] or
[github][zipball-github]. The latest version on github is under Download
Packages (don't use the Download buttons.)
## Requirements
2. Extract the archive into `~/.vim/`:
- vim 7.4 or later
- coffee 1.2.0 or later
unzip -od ~/.vim vim-coffee-script-HASH.zip
## Install using Pathogen
These steps are also used to update the plugin.
This project uses rolling releases based on git commits, so pathogen is a
natural fit for it. If you're already using pathogen, you can skip to step 4.
[zipball-vim]: http://www.vim.org/scripts/script.php?script_id=3590
[zipball-github]: https://github.com/kchmck/vim-coffee-script/downloads
1. Install [pathogen.vim] into `~/.vim/autoload/` (see [pathogen's
readme][install-pathogen] for more information.)
### Install with Pathogen
[pathogen.vim]: http://www.vim.org/scripts/script.php?script_id=2332
[install-pathogen]: https://github.com/tpope/vim-pathogen#installation
Since this plugin has rolling versions based on git commits, using pathogen and
git is the preferred way to install. The plugin ends up contained in its own
directory and updates are just a `git pull` away.
2. Enable pathogen in your vimrc. Here's a bare-minimum vimrc that enables
all the features of `vim-coffee-script`:
1. Install tpope's [pathogen] into `~/.vim/autoload/` and add this line to your
`vimrc`:
```vim
call pathogen#infect()
syntax enable
filetype plugin indent on
```
call pathogen#infect()
If you already have a vimrc built up, just make sure it contains these calls,
in this order.
To get the all the features of this plugin, make sure you also have a
`filetype plugin indent on` line in there.
3. Create the directory `~/.vim/bundle/`:
[pathogen]: http://www.vim.org/scripts/script.php?script_id=2332
mkdir ~/.vim/bundle
2. Create and change into `~/.vim/bundle/`:
4. Clone the `vim-coffee-script` repo into `~/.vim/bundle/`:
$ mkdir ~/.vim/bundle
$ cd ~/.vim/bundle
git clone https://github.com/kchmck/vim-coffee-script.git ~/.vim/bundle/vim-coffee-script/
3. Make a clone of the `vim-coffee-script` repository:
$ git clone https://github.com/kchmck/vim-coffee-script.git
#### Updating
Updating takes two steps:
1. Change into `~/.vim/bundle/vim-coffee-script/`:
$ cd ~/.vim/bundle/vim-coffee-script
cd ~/.vim/bundle/vim-coffee-script
2. Pull in the latest changes:
$ git pull
git pull
### CoffeeMake: Compile the Current File
## Install using Vundle
The `CoffeeMake` command compiles the current file and parses any errors:
1. [Install Vundle] into `~/.vim/bundle/`.
![CoffeeMake](http://i.imgur.com/cr9xI.png)
[Install Vundle]: https://github.com/gmarik/vundle#quick-start
The full signature of the command is:
2. Configure your vimrc for Vundle. Here's a bare-minimum vimrc that enables all
the features of `vim-coffee-script`:
:[silent] CoffeeMake[!] [COFFEE-OPTIONS]...
By default, `CoffeeMake` shows all compiler output and jumps to the first line
reported as an error by `coffee`:
```vim
set nocompatible
filetype off
:CoffeeMake
set rtp+=~/.vim/bundle/vundle/
call vundle#rc()
Compiler output can be hidden with `silent`:
Bundle 'kchmck/vim-coffee-script'
:silent CoffeeMake
syntax enable
filetype plugin indent on
```
Line-jumping can be turned off by adding a bang:
If you're adding Vundle to a built-up vimrc, just make sure all these calls
are in there and that they occur in this order.
:CoffeeMake!
3. Open vim and run `:BundleInstall`.
Options given to `CoffeeMake` are passed along to `coffee`:
To update, open vim and run `:BundleInstall!` (notice the bang!)
:CoffeeMake --bare
## Install from a Zip File
`CoffeeMake` can be manually loaded for a file with:
1. Download the latest zip file from [vim.org][zip].
2. Extract the archive into `~/.vim/`:
unzip -od ~/.vim/ ARCHIVE.zip
This should create the files `~/.vim/autoload/coffee.vim`,
`~/.vim/compiler/coffee.vim`, etc.
You can update the plugin using the same steps.
[zip]: http://www.vim.org/scripts/script.php?script_id=3590
## Compile to JavaScript
A `coffee` wrapper for use with `:make` is enabled automatically for coffee
files if no other compiler is loaded. To enable it manually, run
:compiler coffee
#### Recompile on write
The `:make` command is then configured to use the `coffee` compiler and
recognize its errors. I've included a quick reference here but be sure to check
out [`:help :make`][make] for a full reference of the command.
To recompile a file when it's written, add an `autocmd` like this to your
`vimrc`:
![make](http://i.imgur.com/scUXmxR.png)
au BufWritePost *.coffee silent CoffeeMake!
![make Result](http://i.imgur.com/eGIjEdn.png)
All of the customizations above can be used, too. This one compiles silently
and with the `-b` option, but shows any errors:
[make]: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#:make_makeprg
au BufWritePost *.coffee silent CoffeeMake! -b | cwindow | redraw!
Consider the full signature of a `:make` call as
:[silent] make[!] [COFFEE-OPTIONS]...
By default `:make` shows all compiler output and jumps to the first line
reported as an error. Compiler output can be hidden with a leading `:silent`:
:silent make
Line-jumping can be turned off by adding a bang:
:make!
`COFFEE-OPTIONS` given to `:make` are passed along to `coffee` (see also
[`coffee_make_options`](#coffee_make_options)):
:make --bare --output /some/dir
See the [full table of options](http://coffeescript.org/#usage) for a
list of all the options that `coffee` recognizes.
*Configuration*: [`coffee_compiler`](#coffee_compiler),
[`coffee_make_options`](#coffee_make_options)
#### The quickfix window
Compiler errors are added to the [quickfix] list by `:make`, but the quickfix
window isn't automatically shown. The [`:cwindow`][cwindow] command will pop up
the quickfix window if there are any errors:
:make
:cwindow
This is usually the desired behavior, so you may want to add an autocmd to your
vimrc to do this automatically:
autocmd QuickFixCmdPost * nested cwindow | redraw!
The `redraw!` command is needed to fix a redrawing quirk in terminal vim, but
can removed for gVim.
#### Default compiler options
[quickfix]: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#quickfix
[cwindow]: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#:cwindow
The `CoffeeMake` command passes any options in the `coffee_make_options`
variable along to the compiler. You can use this to set default options:
#### Recompile on write
let coffee_make_options = '--bare'
To recompile a file when it's written, add a `BufWritePost` autocmd to your
vimrc:
#### Path to compiler
autocmd BufWritePost *.coffee silent make!
To change the compiler used by `CoffeeMake` and `CoffeeCompile`, set
`coffee_compiler` to the full path of an executable or the filename of one
in your `$PATH`:
#### Cake and Cakefiles
let coffee_compiler = '/usr/bin/coffee'
A `cake` compiler is also available with the call
This option is set to `coffee` by default.
:compiler cake
### CoffeeCompile: Compile Snippets of CoffeeScript
You can then use `:make` as above to run your Cakefile and capture any `coffee`
errors:
The `CoffeeCompile` command shows how the current file or a snippet of
CoffeeScript is compiled to JavaScript. The full signature of the command is:
:silent make build
:[RANGE] CoffeeCompile [watch|unwatch] [vert[ical]] [WINDOW-SIZE]
It runs within the current directory, so make sure you're in the directory of
your Cakefile before calling it.
Calling `CoffeeCompile` without a range compiles the whole file:
*Configuration*: [`coffee_cake`](#coffee_cake),
[`coffee_cake_options`](#coffee_cake_options)
![CoffeeCompile](http://i.imgur.com/KJfSZ.png)
## CoffeeCompile: Compile CoffeeScript Snippets
Calling `CoffeeCompile` with a range, like in visual mode, compiles the selected
snippet of CoffeeScript:
CoffeeCompile shows how the current file or a snippet of CoffeeScript is
compiled to JavaScript.
![CoffeeCompile Snippet](http://i.imgur.com/mbaUA.png)
:[RANGE] CoffeeCompile [vert[ical]] [WINDOW-SIZE]
![Compiled Snippet](http://i.imgur.com/Ocjuc.png)
Calling `:CoffeeCompile` without a range compiles the whole file:
This scratch buffer can be quickly closed by hitting the `q` key.
![CoffeeCompile](http://i.imgur.com/0zFG0l0.png)
Using `vert` splits the CoffeeCompile buffer vertically instead of horizontally:
![CoffeeCompile Result](http://i.imgur.com/bpiAxaa.png)
Calling it with a range, like in visual mode, compiles only the selected snippet
of CoffeeScript:
![CoffeeCompile Snippet](http://i.imgur.com/x3OT3Ay.png)
![Compiled Snippet](http://i.imgur.com/J02j4T8.png)
Each file gets its own CoffeeCompile buffer, and the same buffer is used for all
future calls of `:CoffeeCompile` on that file. It can be quickly closed by
hitting `q` in normal mode.
Using `vert` opens the CoffeeCompile buffer vertically instead of horizontally
(see also [`coffee_compile_vert`](#coffee_compile_vert)):
:CoffeeCompile vert
Set the `coffee_compile_vert` variable to split the buffer vertically by
default:
let coffee_compile_vert = 1
The initial size of the CoffeeCompile buffer can be given as a number:
By default the CoffeeCompile buffer splits the source buffer in half, but this
can be overridden by passing in a `WINDOW-SIZE`:
:CoffeeCompile 4
#### Watch (live preview) mode
*Configuration*: [`coffee_compiler`](#coffee_compiler`),
[`coffee_compile_vert`](#coffee_compile_vert)
Watch mode is like the Try CoffeeScript preview box on the CoffeeScript
homepage:
#### Quick syntax checking
![Watch Mode](http://i.imgur.com/M6l1j.png)
If compiling a snippet results in a compiler error, CoffeeCompile adds that
error to the [quickfix] list.
![Watch Mode](http://i.imgur.com/qtNmU.png)
[quickfix]: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#quickfix
Writing some code and then exiting insert mode automatically updates the
compiled JavaScript buffer.
![Syntax Checking](http://i.imgur.com/RC8accF.png)
Use `watch` to start watching a buffer (`vert` is also recommended):
![Syntax Checking Result](http://i.imgur.com/gi1ON75.png)
:CoffeeCompile watch vert
You can use this to quickly check the syntax of a snippet.
After making some changes in insert mode, hit escape and the CoffeeScript will
be recompiled. Changes made outside of insert mode don't trigger this recompile,
but calling `CoffeeCompile` will compile these changes without any bad effects.
## CoffeeWatch: Live Preview Compiling
To get synchronized scrolling of a CoffeeScript and CoffeeCompile buffer, set
`scrollbind` on each:
CoffeeWatch emulates using the Try CoffeeScript preview box on the [CoffeeScript
homepage][CoffeeScript].
![CoffeeWatch](http://i.imgur.com/TRHdIMG.png)
![CoffeeWatch Result](http://i.imgur.com/rJbOeeS.png)
CoffeeWatch takes the same options as CoffeeCompile:
:CoffeeWatch [vert[ical]] [WINDOW-SIZE]
After a source buffer is watched, leaving insert mode or saving the file fires
off a recompile of the CoffeeScript:
![Insert Mode](http://i.imgur.com/SBVcf4k.png)
![Recompile](http://i.imgur.com/pbPMog7.png)
You can force recompilation by calling `:CoffeeWatch`.
To get synchronized scrolling of the source buffer and CoffeeWatch buffer, set
[`'scrollbind'`](http://vimdoc.sourceforge.net/htmldoc/options.html#'scrollbind')
on each:
:setl scrollbind
Use `unwatch` to stop watching a buffer:
*Configuration*: [`coffee_compiler`](#coffee_compiler),
[`coffee_watch_vert`](#coffee_watch_vert)
:CoffeeCompile unwatch
## CoffeeRun: Run CoffeeScript Snippets
### CoffeeLint: Lint your CoffeeScript
CoffeeRun compiles the current file or selected snippet and runs the resulting
JavaScript.
The `CoffeeLint` command runs [coffeelint](http://www.coffeelint.org/) (version
0.4.0 or later required) on the current file and parses any errors:
![CoffeeRun](http://i.imgur.com/YSkHUuQ.png)
:[RANGE] CoffeeLint[!] [COFFEELINT-OPTIONS]
![CoffeeRun Output](http://i.imgur.com/wZQbggN.png)
Use it like `CoffeeMake`.
The command has two forms:
![CoffeeLint](http://i.imgur.com/dlxF7.png)
:CoffeeRun [PROGRAM-OPTIONS]...
#### Default coffeelint options
This form applies when no `RANGE` is given or when the given range is `1,$`
(first line to last line). It allows passing `PROGRAM-OPTIONS` to your compiled
program. The filename is passed directly to `coffee` so you must save the file
for your changes to take effect.
Options in `coffee_lint_options` are passed along to `coffeelint`:
:RANGE CoffeeRun [COFFEE-OPTIONS]...
This form applies with all other ranges. It compiles and runs the lines within
the given `RANGE` and any extra `COFFEE-OPTIONS` are passed to `coffee`.
*Configuration*: [`coffee_compiler`](#coffee_compiler),
[`coffee_run_vert`](#coffee_run_vert)
## CoffeeLint: Lint your CoffeeScript
CoffeeLint runs [coffeelint](http://www.coffeelint.org/) (version 0.5.7 or later
required) on the current file and adds any issues to the [quickfix] list.
![CoffeeLint](http://i.imgur.com/UN8Nr5N.png)
![CoffeeLint Result](http://i.imgur.com/9hSIj3W.png)
:[RANGE] CoffeeLint[!] [COFFEELINT-OPTIONS]... [ | cwindow]
If a `RANGE` is given, only those lines are piped to `coffeelint`. Options given
in `COFFEELINT-OPTIONS` are passed to `coffeelint` (see also
[`coffee_lint_options`](#coffee_lint_options)):
:CoffeeLint -f lint.json
It behaves very similar to `:make`, described [above](#compile-to-javascript).
:CoffeeLint! | cwindow
*Configuration*: [`coffee_linter`](#coffee_linter),
[`coffee_lint_options`](#coffee_lint_options)
## Literate CoffeeScript
Literate CoffeeScript syntax and indent support is provided by
[vim-literate-coffeescript]. The `Coffee` commands detect when they're running
on a litcoffee file and pass the `--literate` flag to their respective tools,
but at this time the commands are not automatically loaded when a litcoffee file
is opened.
[vim-literate-coffeescript]: https://github.com/mintplant/vim-literate-coffeescript
To load them, run
runtime ftplugin/coffee.vim
while inside a litcoffee buffer. To do this automatically, add
autocmd FileType litcoffee runtime ftplugin/coffee.vim
to your vimrc.
## CoffeeScript in HTML
CoffeeScript is highlighted and indented within
```html
<script type="text/coffeescript">
</script>
```
blocks in html files.
## CoffeeScript in Haml
CoffeeScript is highlighted within the `:coffeescript` filter in haml files:
```haml
:coffeescript
console.log "hullo"
```
At this time, coffee indenting doesn't work in these blocks.
## Custom Autocmds
You can [define commands][autocmd-explain] to be ran automatically on these
custom events.
In all cases, the name of the command running the event (`CoffeeCompile`,
`CoffeeWatch`, or `CoffeeRun`) is matched by the [`{pat}`][autocmd] argument.
You can match all commands with a `*` or only specific commands by separating
them with a comma: `CoffeeCompile,CoffeeWatch`.
[autocmd-explain]: http://vimdoc.sourceforge.net/htmldoc/usr_40.html#40.3
[autocmd]: http://vimdoc.sourceforge.net/htmldoc/autocmd.html#:autocmd
#### CoffeeBufNew
CoffeeBufNew is ran when a new scratch buffer is created. It's called from the
new buffer, so it can be used to do additional set up.
```vim
augroup CoffeeBufNew
autocmd User * set wrap
augroup END
```
*Used By*: CoffeeCompile, CoffeeWatch, CoffeeRun
#### CoffeeBufUpdate
CoffeeBufUpdate is ran when a scratch buffer is updated with output from
`coffee`. It's called from the scratch buffer, so it can be used to alter the
compiled output.
```vim
" Switch back to the source buffer after updating.
augroup CoffeeBufUpdate
autocmd User CoffeeCompile,CoffeeRun exec bufwinnr(b:coffee_src_buf) 'wincmd w'
augroup END
```
For example, to strip off the "Generated by" comment on the first line, put this
in your vimrc:
```vim
function! s:RemoveGeneratedBy()
" If there was an error compiling, there's no comment to remove.
if v:shell_error
return
endif
" Save cursor position.
let pos = getpos('.')
" Remove first line.
set modifiable
1 delete _
set nomodifiable
" Restore cursor position.
call setpos('.', pos)
endfunction
augroup CoffeeBufUpdate
autocmd User CoffeeCompile,CoffeeWatch call s:RemoveGeneratedBy()
augroup END
```
*Used By*: CoffeeCompile, CoffeeWatch, CoffeeRun
## Configuration Variables
This is the full list of configuration variables available, with example
settings and default values. Use these in your vimrc to control the default
behavior.
#### coffee\_indent\_keep\_current
By default, the indent function matches the indent of the previous line if it
doesn't find a reason to indent or outdent. To change this behavior so it
instead keeps the [current indent of the cursor][98], use
let coffee_indent_keep_current = 1
[98]: https://github.com/kchmck/vim-coffee-script/pull/98
*Default*: `unlet coffee_indent_keep_current`
Note that if you change this after a coffee file has been loaded, you'll have to
reload the indent script for the change to take effect:
unlet b:did_indent | runtime indent/coffee.vim
#### coffee\_compiler
Path to the `coffee` executable used by the `Coffee` commands:
let coffee_compiler = '/usr/bin/coffee'
*Default*: `'coffee'` (search `$PATH` for executable)
#### coffee\_make\_options
Options to pass to `coffee` with `:make`:
let coffee_make_options = '--bare'
*Default*: `''` (nothing)
Note that `coffee_make_options` is embedded into `'makeprg'`, so `:compiler
coffee` must be ran after changing `coffee_make_options` for the changes to take
effect.
#### coffee\_cake
Path to the `cake` executable:
let coffee_cake = '/opt/bin/cake'
*Default*: `'cake'` (search `$PATH` for executable)
#### coffee\_cake\_options
Options to pass to `cake` with `:make`:
let coffee_cake_options = 'build'
*Default*: `''` (nothing)
#### coffee\_linter
Path to the `coffeelint` executable:
let coffee_linter = '/opt/bin/coffeelint'
*Default*: `'coffeelint'` (search `$PATH` for executable)
#### coffee\_lint\_options
Options to pass to `coffeelint`:
let coffee_lint_options = '-f lint.json'
#### Path to `coffeelint`
*Default*: `''` (nothing)
Use the `coffee_linter` option to set a different path to the `coffeelint`
executable:
#### coffee\_compile\_vert
let coffee_linter = '/usr/bin/coffeelint'
Open the CoffeeCompile buffer with a vertical split instead of a horizontal
one:
This option is set to `coffeelint` by default.
let coffee_compile_vert = 1
### CoffeeRun: Run some CoffeeScript
*Default*: `unlet coffee_compile_vert`
The `CoffeeRun` command compiles the current file or selected snippet and runs
the resulting JavaScript. Output is shown at the bottom of the screen:
#### coffee\_watch\_vert
![CoffeeRun](http://i.imgur.com/7hwSy.png)
Open the CoffeeWatch buffer with a vertical split instead of a horizontal
one:
![CoffeeRun Output](http://i.imgur.com/WNWvC.png)
let coffee_watch_vert = 1
### Configure Syntax Highlighting
*Default*: `unlet coffee_watch_vert`
Add these lines to your `vimrc` to disable the relevant syntax group.
#### coffee\_run\_vert
Open the CoffeeRun buffer with a vertical split instead of a horizontal
one:
let coffee_run_vert = 1
*Default*: `unlet coffee_run_vert`
## Configure Syntax Highlighting
Add these lines to your vimrc to disable the relevant syntax group.
#### Disable trailing whitespace error
@ -231,7 +560,7 @@ with:
#### Disable trailing semicolon error
Trailing semicolons are also considered an error (for help transitioning from
Trailing semicolons are considered an error (for help transitioning from
JavaScript.) This can be disabled with:
hi link coffeeSemicolonError NONE
@ -243,7 +572,7 @@ they're not allowed in CoffeeScript. This can be disabled with:
hi link coffeeReservedError NONE
### Tune Vim for CoffeeScript
## Tune Vim for CoffeeScript
Changing these core settings can make vim more CoffeeScript friendly.
@ -251,20 +580,20 @@ Changing these core settings can make vim more CoffeeScript friendly.
Folding by indentation works well for CoffeeScript functions and classes:
![Folding](http://i.imgur.com/Y0rDC.png)
![Folding](http://i.imgur.com/gDgUBdO.png)
To fold by indentation in CoffeeScript files, add this line to your `vimrc`:
To fold by indentation in CoffeeScript files, add this line to your vimrc:
au BufNewFile,BufReadPost *.coffee setl foldmethod=indent nofoldenable
autocmd BufNewFile,BufReadPost *.coffee setl foldmethod=indent nofoldenable
With this, folding is disabled by default but can be quickly toggled per-file
by hitting `zi`. To enable folding by default, remove `nofoldenable`:
au BufNewFile,BufReadPost *.coffee setl foldmethod=indent
autocmd BufNewFile,BufReadPost *.coffee setl foldmethod=indent
#### Two-space indentation
To get standard two-space indentation in CoffeeScript files, add this line to
your `vimrc`:
your vimrc:
au BufNewFile,BufReadPost *.coffee setl shiftwidth=2 expandtab
autocmd BufNewFile,BufReadPost *.coffee setl shiftwidth=2 expandtab

View File

@ -0,0 +1,33 @@
" Language: CoffeeScript
" Maintainer: Mick Koch <kchmck@gmail.com>
" URL: http://github.com/kchmck/vim-coffee-script
" License: WTFPL
" Load the coffee and html indent functions.
silent! unlet b:did_indent
runtime indent/coffee.vim
let s:coffeeIndentExpr = &l:indentexpr
" Load html last so it can overwrite coffee settings.
silent! unlet b:did_indent
runtime indent/html.vim
let s:htmlIndentExpr = &l:indentexpr
" Inject our wrapper indent function.
setlocal indentexpr=GetCoffeeHtmlIndent(v:lnum)
function! GetCoffeeHtmlIndent(curlinenum)
" See if we're inside a coffeescript block.
let scriptlnum = searchpair('<script [^>]*type="text/coffeescript"[^>]*>', '',
\ '</script>', 'bWn')
let prevlnum = prevnonblank(a:curlinenum)
" If we're in the script block and the previous line isn't the script tag
" itself, use coffee indenting.
if scriptlnum && scriptlnum != prevlnum
exec 'return ' s:coffeeIndentExpr
endif
" Otherwise use html indenting.
exec 'return ' s:htmlIndentExpr
endfunction

View File

@ -6,4 +6,8 @@
" 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*\):coffee\z(script\)*\s*$" end="^\%(\z1 \| *$\)\@!" contains=@hamlCoffeeScript,hamlInterpolation keepend
syn region hamlCoffeescriptFilter matchgroup=hamlFilter
\ start="^\z(\s*\):coffee\z(script\)\?\s*$"
\ end="^\%(\z1 \| *$\)\@!"
\ contains=@hamlCoffeeScript,hamlInterpolation
\ keepend

View File

@ -5,7 +5,7 @@
" Syntax highlighting for text/coffeescript script tags
syn include @htmlCoffeeScript syntax/coffee.vim
syn region coffeeScript start=+<script [^>]*type *=[^>]*text/coffeescript[^>]*>+
\ end=+</script>+me=s-1 keepend
syn region coffeeScript start=#<script [^>]*type="text/coffeescript"[^>]*>#
\ end=#</script>#me=s-1 keepend
\ contains=@htmlCoffeeScript,htmlScriptTag,@htmlPreproc
\ containedin=htmlHead

View File

@ -0,0 +1,54 @@
" Language: CoffeeScript
" Maintainer: Mick Koch <kchmck@gmail.com>
" URL: http://github.com/kchmck/vim-coffee-script
" License: WTFPL
" Set up some common global/buffer variables.
function! coffee#CoffeeSetUpVariables()
" Path to coffee executable
if !exists('g:coffee_compiler')
let g:coffee_compiler = 'coffee'
endif
" Options passed to coffee with make
if !exists('g:coffee_make_options')
let g:coffee_make_options = ''
endif
" Path to cake executable
if !exists('g:coffee_cake')
let g:coffee_cake = 'cake'
endif
" Extra options passed to cake
if !exists('g:coffee_cake_options')
let g:coffee_cake_options = ''
endif
" Path to coffeelint executable
if !exists('g:coffee_linter')
let g:coffee_linter = 'coffeelint'
endif
" Options passed to CoffeeLint
if !exists('g:coffee_lint_options')
let g:coffee_lint_options = ''
endif
" Pass the litcoffee flag to tools in this buffer if a litcoffee file is open.
" Let the variable be overwritten so it can be updated if a different filetype
" is set.
if &filetype == 'litcoffee'
let b:coffee_litcoffee = '--literate'
else
let b:coffee_litcoffee = ''
endif
endfunction
function! coffee#CoffeeSetUpErrorFormat()
CompilerSet errorformat=Error:\ In\ %f\\,\ %m\ on\ line\ %l,
\Error:\ In\ %f\\,\ Parse\ error\ on\ line\ %l:\ %m,
\SyntaxError:\ In\ %f\\,\ %m,
\%f:%l:%c:\ error:\ %m,
\%-G%.%#
endfunction

View File

@ -0,0 +1,15 @@
" Language: CoffeeScript
" Maintainer: Mick Koch <kchmck@gmail.com>
" URL: http://github.com/kchmck/vim-coffee-script
" License: WTFPL
if exists('current_compiler')
finish
endif
let current_compiler = 'cake'
call coffee#CoffeeSetUpVariables()
exec 'CompilerSet makeprg=' . escape(g:coffee_cake . ' ' .
\ g:coffee_cake_options . ' $*', ' ')
call coffee#CoffeeSetUpErrorFormat()

View File

@ -13,27 +13,22 @@
if exists('current_compiler')
finish
else
let current_compiler = 'coffee'
endif
let current_compiler = 'coffee'
call coffee#CoffeeSetUpVariables()
" Pattern to check if coffee is the compiler
let s:pat = '^' . current_compiler
" Path to CoffeeScript compiler
if !exists('coffee_compiler')
let coffee_compiler = 'coffee'
endif
" Extra options passed to CoffeeMake
if !exists('coffee_make_options')
let coffee_make_options = ''
endif
" Get a `makeprg` for the current filename.
function! s:GetMakePrg()
return g:coffee_compiler . ' -c ' . g:coffee_make_options . ' $* '
\ . fnameescape(expand('%'))
return g:coffee_compiler .
\ ' -c' .
\ ' ' . b:coffee_litcoffee .
\ ' ' . g:coffee_make_options .
\ ' $*' .
\ ' ' . fnameescape(expand('%'))
endfunction
" Set `makeprg` and return 1 if coffee is still the compiler, else return 0.
@ -50,16 +45,21 @@ function! s:SetMakePrg()
endfunction
" Set a dummy compiler so we can check whether to set locally or globally.
CompilerSet makeprg=coffee
exec 'CompilerSet makeprg=' . current_compiler
" Then actually set the compiler.
call s:SetMakePrg()
call coffee#CoffeeSetUpErrorFormat()
CompilerSet errorformat=Error:\ In\ %f\\,\ %m\ on\ line\ %l,
\Error:\ In\ %f\\,\ Parse\ error\ on\ line\ %l:\ %m,
\SyntaxError:\ In\ %f\\,\ %m,
\%-G%.%#
function! s:CoffeeMakeDeprecated(bang, args)
echoerr 'CoffeeMake is deprecated! Please use :make instead, its behavior ' .
\ 'is identical.'
sleep 5
exec 'make' . a:bang a:args
endfunction
" Compile the current file.
command! -bang -bar -nargs=* CoffeeMake make<bang> <args>
command! -bang -bar -nargs=* CoffeeMake
\ call s:CoffeeMakeDeprecated(<q-bang>, <q-args>)
" Set `makeprg` on rename since we embed the filename in the setting.
augroup CoffeeUpdateMakePrg

View File

@ -1,143 +1,4 @@
*coffee-script.txt* For Vim version 7.3
=============================================================================
Author: Mick Koch <kchmck@gmail.com> *coffee-script-author*
License: WTFPL (see |coffee-script-license|)
=============================================================================
CONTENTS *coffee-script-contents*
|coffee-script-introduction| Introduction and Feature Summary
|coffee-script-commands| Commands
|coffee-script-settings| Settings
|compiler-coffee-script| Compiler
{Vi does not have any of this}
=============================================================================
INTRODUCTION *coffee-script*
*coffee-script-introduction*
This plugin adds support for CoffeeScript syntax, indenting, and compiling.
Also included is an eco syntax and support for CoffeeScript in Haml and HTML.
COMMANDS *coffee-script-commands*
*:CoffeeMake*
:CoffeeMake[!] {opts} Wrapper around |:make| that also passes options in
|g:coffee_make_options| to the compiler. Use |:silent|
to hide compiler output. See |:make| for more
information about [!] and other helpful commands.
*:CoffeeCompile*
:[range]CoffeeCompile [vertical] [{win-size}]
Shows how the current file or [range] is compiled
to JavaScript. [vertical] (or vert) splits the
compile buffer vertically instead of horizontally, and
{win-size} sets the initial size of the buffer. It can
be closed quickly with the "q" key.
:CoffeeCompile {watch} [vertical] [{win-size}]
The watch mode of :CoffeeCompile emulates the "Try
CoffeeScript" live preview on the CoffeeScript web
site. After making changes to the source file,
exiting insert mode will cause the preview buffer to
update automatically. {watch} should be given as
"watch" or "unwatch," where the latter will stop the
automatic updating. [vertical] is recommended, and
'scrollbind' is useful.
*:CoffeeLint*
:[range]CoffeeLint[!] {opts}
Run {coffeelint} on the current file and add any
errors to the quickfix list. The first error is jumped
to if [!] isn't given. Options in
|g:coffee_lint_options| and {opts} are passed along to
{coffeelint}. Although the whole file is linted, if a
[range] is given, only errors within those lines will
be considered.
*:CoffeeRun*
:[range]CoffeeRun Compiles the file or [range] and runs the resulting
JavaScript, displaying the output.
SETTINGS *coffee-script-settings*
You can configure plugin behavior using global variables and syntax commands
in your |vimrc|.
Global Settings~
*g:coffee_compiler*
Set the path to the compiler used by |CoffeeMake| and |CoffeeCompile| (it's
{coffee} by default.)
>
let coffee_compiler = '/usr/bin/coffee'
<
*g:coffee_make_options*
Set default options |CoffeeMake| should pass to the compiler.
>
let coffee_make_options = '--bare'
<
*g:coffee_compile_vert*
Split the CoffeeCompile buffer vertically by default.
>
let coffee_compile_vert = 1
<
*g:coffee_linter*
Set the path to the {coffeelint} executable (it's {coffeelint} by default.)
>
let coffee_linter = '/usr/bin/coffeelint'
<
*g:coffee_lint_options*
Set default options |CoffeeLint| should pass to {coffeelint}.
>
let coffee_lint_options = '-f lint.json'
<
Syntax Highlighting~
*ft-coffee-script-syntax*
Trailing whitespace is highlighted as an error by default. This can be
disabled with:
>
hi link coffeeSpaceError NONE
Trailing semicolons are also considered an error (for help transitioning from
JavaScript.) This can be disabled with:
>
hi link coffeeSemicolonError NONE
Reserved words like {function} and {var} are highlighted where they're not
allowed in CoffeeScript. This can be disabled with:
>
hi link coffeeReservedError NONE
COMPILER *compiler-coffee-script*
A CoffeeScript compiler is provided as a wrapper around {coffee} and can be
loaded with;
>
compiler coffee
This is done automatically when a CoffeeScript file is opened if no other
compiler is loaded.
=============================================================================
LICENSE *coffee-script-license*
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2010 to 2012 Mick Koch <kchmck@gmail.com>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
Please see the project readme for up-to-date docs:
https://github.com/kchmck/vim-coffee-script
vim:tw=78:ts=8:ft=help:norl:

View File

@ -1 +0,0 @@
autocmd BufNewFile,BufRead *.eco set filetype=eco

View File

@ -3,261 +3,402 @@
" URL: http://github.com/kchmck/vim-coffee-script
" License: WTFPL
if exists("b:did_ftplugin")
if exists('b:did_ftplugin')
finish
endif
let b:did_ftplugin = 1
call coffee#CoffeeSetUpVariables()
setlocal formatoptions-=t formatoptions+=croql
setlocal comments=:#
setlocal commentstring=#\ %s
setlocal comments=:# commentstring=#\ %s
setlocal omnifunc=javascriptcomplete#CompleteJS
" Enable CoffeeMake if it won't overwrite any settings.
" Create custom augroups.
augroup CoffeeBufUpdate | augroup END
augroup CoffeeBufNew | augroup END
" Enable coffee compiler if a compiler isn't set already.
if !len(&l:makeprg)
compiler coffee
endif
" Check here too in case the compiler above isn't loaded.
if !exists('coffee_compiler')
let coffee_compiler = 'coffee'
endif
" Path to coffeelint executable
if !exists('coffee_linter')
let coffee_linter = 'coffeelint'
endif
" Options passed to CoffeeLint
if !exists('coffee_lint_options')
let coffee_lint_options = ''
endif
" Reset the CoffeeCompile variables for the current buffer.
function! s:CoffeeCompileResetVars()
" Compiled output buffer
let b:coffee_compile_buf = -1
let b:coffee_compile_pos = []
" If CoffeeCompile is watching a buffer
let b:coffee_compile_watch = 0
" Switch to the window for buf.
function! s:SwitchWindow(buf)
exec bufwinnr(a:buf) 'wincmd w'
endfunction
" Clean things up in the source buffer.
" Create a new scratch buffer and return the bufnr of it. After the function
" returns, vim remains in the scratch buffer so more set up can be done.
function! s:ScratchBufBuild(src, vert, size)
if a:size <= 0
if a:vert
let size = winwidth(bufwinnr(a:src)) / 2
else
let size = winheight(bufwinnr(a:src)) / 2
endif
endif
if a:vert
vertical belowright new
exec 'vertical resize' size
else
belowright new
exec 'resize' size
endif
setlocal bufhidden=wipe buftype=nofile nobuflisted noswapfile nomodifiable
nnoremap <buffer> <silent> q :hide<CR>
return bufnr('%')
endfunction
" Replace buffer contents with text and delete the last empty line.
function! s:ScratchBufUpdate(buf, text)
" Move to the scratch buffer.
call s:SwitchWindow(a:buf)
" Double check we're in the scratch buffer before overwriting.
if bufnr('%') != a:buf
throw 'unable to change to scratch buffer'
endif
setlocal modifiable
silent exec '% delete _'
silent put! =a:text
silent exec '$ delete _'
setlocal nomodifiable
endfunction
" Parse the output of coffee into a qflist entry for src buffer.
function! s:ParseCoffeeError(output, src, startline)
" Coffee error is always on first line?
let match = matchlist(a:output,
\ '^\(\f\+\|\[stdin\]\):\(\d\):\(\d\): error: \(.\{-}\)' . "\n")
if !len(match)
return
endif
" Consider the line number from coffee as relative and add it to the beginning
" line number of the range the command was called on, then subtract one for
" zero-based relativity.
call setqflist([{'bufnr': a:src, 'lnum': a:startline + str2nr(match[2]) - 1,
\ 'type': 'E', 'col': str2nr(match[3]), 'text': match[4]}], 'r')
endfunction
" Reset source buffer variables.
function! s:CoffeeCompileResetVars()
" Variables defined in source buffer:
" b:coffee_compile_buf: bufnr of output buffer
" Variables defined in output buffer:
" b:coffee_src_buf: bufnr of source buffer
" b:coffee_compile_pos: previous cursor position in output buffer
let b:coffee_compile_buf = -1
endfunction
function! s:CoffeeWatchResetVars()
" Variables defined in source buffer:
" b:coffee_watch_buf: bufnr of output buffer
" Variables defined in output buffer:
" b:coffee_src_buf: bufnr of source buffer
" b:coffee_watch_pos: previous cursor position in output buffer
let b:coffee_watch_buf = -1
endfunction
function! s:CoffeeRunResetVars()
" Variables defined in CoffeeRun source buffer:
" b:coffee_run_buf: bufnr of output buffer
" Variables defined in CoffeeRun output buffer:
" b:coffee_src_buf: bufnr of source buffer
" b:coffee_run_pos: previous cursor position in output buffer
let b:coffee_run_buf = -1
endfunction
" Clean things up in the source buffers.
function! s:CoffeeCompileClose()
exec bufwinnr(b:coffee_compile_src_buf) 'wincmd w'
silent! autocmd! CoffeeCompileAuWatch * <buffer>
" Switch to the source buffer if not already in it.
silent! call s:SwitchWindow(b:coffee_src_buf)
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")
function! s:CoffeeWatchClose()
silent! call s:SwitchWindow(b:coffee_src_buf)
silent! autocmd! CoffeeAuWatch * <buffer>
call s:CoffeeWatchResetVars()
endfunction
" Move to the CoffeeCompile buffer.
exec bufwinnr(b:coffee_compile_buf) 'wincmd w'
function! s:CoffeeRunClose()
silent! call s:SwitchWindow(b:coffee_src_buf)
call s:CoffeeRunResetVars()
endfunction
" Compile the lines between startline and endline and put the result into buf.
function! s:CoffeeCompileToBuf(buf, startline, endline)
let src = bufnr('%')
let input = join(getline(a:startline, a:endline), "\n")
" Coffee doesn't like empty input.
if !len(input)
" Function should still return within output buffer.
call s:SwitchWindow(a:buf)
return
endif
" Compile input.
let output = system(g:coffee_compiler . ' -scb 2>&1', input)
" Pipe lines into coffee.
let output = system(g:coffee_compiler .
\ ' -scb' .
\ ' ' . b:coffee_litcoffee .
\ ' 2>&1', input)
" Be sure we're in the CoffeeCompile buffer before overwriting.
if exists('b:coffee_compile_buf')
echoerr 'CoffeeCompile buffers are messed up'
return
endif
" Paste output into output buffer.
call s:ScratchBufUpdate(a:buf, output)
" 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.
" Highlight as JavaScript if there were no compile errors.
if v:shell_error
call s:ParseCoffeeError(output, src, a:startline)
setlocal filetype=
else
" Clear the quickfix list.
call setqflist([], 'r')
setlocal filetype=javascript
endif
call setpos('.', b:coffee_compile_pos)
endfunction
" Update the CoffeeCompile buffer with the whole source buffer.
function! s:CoffeeCompileWatchUpdate()
call s:CoffeeCompileUpdate(1, '$')
exec bufwinnr(b:coffee_compile_src_buf) 'wincmd w'
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)
if !executable(g:coffee_compiler)
echoerr "Can't find CoffeeScript compiler `" . g:coffee_compiler . "`"
if a:args =~ '\<watch\>'
echoerr 'CoffeeCompile watch is deprecated! Please use CoffeeWatch instead'
sleep 5
call s:CoffeeWatch(a:args)
return
endif
" If in the CoffeeCompile buffer, switch back to the source buffer and
" continue.
" Switch to the source buffer if not already in it.
silent! call s:SwitchWindow(b:coffee_src_buf)
" Bail if not in source buffer.
if !exists('b:coffee_compile_buf')
exec bufwinnr(b:coffee_compile_src_buf) 'wincmd w'
endif
" Parse arguments.
let watch = a:args =~ '\<watch\>'
let unwatch = a:args =~ '\<unwatch\>'
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 =~ '\<vert\%[ical]\>'
endif
" Remove any watch listeners.
silent! autocmd! CoffeeCompileAuWatch * <buffer>
" If just unwatching, don't compile.
if unwatch
let b:coffee_compile_watch = 0
return
endif
if watch
let b:coffee_compile_watch = 1
endif
" Build the CoffeeCompile buffer if it doesn't exist.
" Build the output buffer if it doesn't exist.
if bufwinnr(b:coffee_compile_buf) == -1
let src_buf = bufnr('%')
let src_win = bufwinnr(src_buf)
let src = bufnr('%')
" Create the new window and resize it.
if vert
let width = size ? size : winwidth(src_win) / 2
let vert = exists('g:coffee_compile_vert') || a:args =~ '\<vert\%[ical]\>'
let size = str2nr(matchstr(a:args, '\<\d\+\>'))
belowright 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])
" Build the output buffer and save the source bufnr.
let buf = s:ScratchBufBuild(src, vert, size)
let b:coffee_src_buf = src
belowright new
exec 'resize' height
endif
" We're now in the scratch buffer, so set it up.
setlocal bufhidden=wipe buftype=nofile
setlocal nobuflisted nomodifiable noswapfile nowrap
" Set the buffer name.
exec 'silent! file [CoffeeCompile ' . src . ']'
" Clean up the source buffer when the output buffer is closed.
autocmd BufWipeout <buffer> call s:CoffeeCompileClose()
" Save the cursor when leaving the CoffeeCompile buffer.
" Save the cursor when leaving the output buffer.
autocmd BufLeave <buffer> let b:coffee_compile_pos = getpos('.')
nnoremap <buffer> <silent> q :hide<CR>
" Run user-defined commands on new buffer.
silent doautocmd CoffeeBufNew User CoffeeCompile
let b:coffee_compile_src_buf = src_buf
let buf = bufnr('%')
" Go back to the source buffer and set it up.
exec bufwinnr(b:coffee_compile_src_buf) 'wincmd w'
" Switch back to the source buffer and save the output bufnr. This also
" triggers BufLeave above.
call s:SwitchWindow(src)
let b:coffee_compile_buf = buf
endif
if b:coffee_compile_watch
call s:CoffeeCompileWatchUpdate()
" Fill the scratch buffer.
call s:CoffeeCompileToBuf(b:coffee_compile_buf, a:startline, a:endline)
" Reset cursor to previous position.
call setpos('.', b:coffee_compile_pos)
augroup CoffeeCompileAuWatch
autocmd InsertLeave <buffer> call s:CoffeeCompileWatchUpdate()
augroup END
" Run any user-defined commands on the scratch buffer.
silent doautocmd CoffeeBufUpdate User CoffeeCompile
endfunction
" Update the scratch buffer and switch back to the source buffer.
function! s:CoffeeWatchUpdate()
call s:CoffeeCompileToBuf(b:coffee_watch_buf, 1, '$')
call setpos('.', b:coffee_watch_pos)
silent doautocmd CoffeeBufUpdate User CoffeeWatch
call s:SwitchWindow(b:coffee_src_buf)
endfunction
" Continually compile a source buffer.
function! s:CoffeeWatch(args)
silent! call s:SwitchWindow(b:coffee_src_buf)
if !exists('b:coffee_watch_buf')
return
endif
if bufwinnr(b:coffee_watch_buf) == -1
let src = bufnr('%')
let vert = exists('g:coffee_watch_vert') || a:args =~ '\<vert\%[ical]\>'
let size = str2nr(matchstr(a:args, '\<\d\+\>'))
let buf = s:ScratchBufBuild(src, vert, size)
let b:coffee_src_buf = src
exec 'silent! file [CoffeeWatch ' . src . ']'
autocmd BufWipeout <buffer> call s:CoffeeWatchClose()
autocmd BufLeave <buffer> let b:coffee_watch_pos = getpos('.')
silent doautocmd CoffeeBufNew User CoffeeWatch
call s:SwitchWindow(src)
let b:coffee_watch_buf = buf
endif
" Make sure only one watch autocmd is defined on this buffer.
silent! autocmd! CoffeeAuWatch * <buffer>
augroup CoffeeAuWatch
autocmd InsertLeave <buffer> call s:CoffeeWatchUpdate()
autocmd BufWritePost <buffer> call s:CoffeeWatchUpdate()
augroup END
call s:CoffeeWatchUpdate()
endfunction
" Run a snippet of CoffeeScript between startline and endline.
function! s:CoffeeRun(startline, endline, args)
silent! call s:SwitchWindow(b:coffee_src_buf)
if !exists('b:coffee_run_buf')
return
endif
if bufwinnr(b:coffee_run_buf) == -1
let src = bufnr('%')
let buf = s:ScratchBufBuild(src, exists('g:coffee_run_vert'), 0)
let b:coffee_src_buf = src
exec 'silent! file [CoffeeRun ' . src . ']'
autocmd BufWipeout <buffer> call s:CoffeeRunClose()
autocmd BufLeave <buffer> let b:coffee_run_pos = getpos('.')
silent doautocmd CoffeeBufNew User CoffeeRun
call s:SwitchWindow(src)
let b:coffee_run_buf = buf
endif
if a:startline == 1 && a:endline == line('$')
let output = system(g:coffee_compiler .
\ ' ' . b:coffee_litcoffee .
\ ' ' . fnameescape(expand('%')) .
\ ' ' . a:args)
else
call s:CoffeeCompileUpdate(a:startline, a:endline)
endif
endfunction
let input = join(getline(a:startline, a:endline), "\n")
" 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]
if !len(input)
return
endif
endfor
let output = system(g:coffee_compiler .
\ ' -s' .
\ ' ' . b:coffee_litcoffee .
\ ' ' . a:args, input)
endif
call s:ScratchBufUpdate(b:coffee_run_buf, output)
call setpos('.', b:coffee_run_pos)
silent doautocmd CoffeeBufUpdate User CoffeeRun
endfunction
" Run coffeelint on a file, and add any errors between @startline and @endline
" Run coffeelint on a file, and add any errors between startline and endline
" to the quickfix list.
function! s:CoffeeLint(startline, endline, bang, args)
if !executable(g:coffee_linter)
echoerr "Can't find CoffeeScript linter `" . g:coffee_linter . "`"
let input = join(getline(a:startline, a:endline), "\n")
if !len(input)
return
endif
let filename = expand('%')
let output = system(g:coffee_linter .
\ ' -s --csv' .
\ ' ' . b:coffee_litcoffee .
\ ' ' . g:coffee_lint_options .
\ ' ' . a:args .
\ ' 2>&1', input)
if !len(filename)
echoerr 'CoffeeLint must be ran on a saved file'
return
endif
let lines = split(system(g:coffee_linter . ' --csv ' . g:coffee_lint_options .
\ ' ' . a:args . ' ' . filename . ' 2>&1'), '\n')
" Convert output into an array and strip off the csv header.
let lines = split(output, "\n")[1:]
let buf = bufnr('%')
let qflist = []
for line in lines
let match = matchlist(line, '\f\+,\(\d\+\),error,\(.\+\)')
let match = matchlist(line, '^stdin,\(\d\+\),\d*,\(error\|warn\),\(.\+\)$')
" Ignore invalid lines.
" Ignore unmatched lines.
if !len(match)
continue
endif
let lnum = str2nr(match[1])
" Don't add the error if it's not in the range.
if lnum < a:startline || lnum > a:endline
continue
endif
let text = match[2]
call add(qflist, {'bufnr': bufnr('%'), 'lnum': lnum, 'text': text})
" The 'type' will result in either 'E' or 'W'.
call add(qflist, {'bufnr': buf, 'lnum': a:startline + str2nr(match[1]) - 1,
\ 'type': toupper(match[2][0]), 'text': match[3]})
endfor
" Replace the quicklist with our items.
call setqflist(qflist, 'r')
" Don't jump if there's a bang.
" If not given a bang, jump to first error.
if !len(a:bang)
silent! cc 1
endif
endfunction
" Don't overwrite the CoffeeCompile variables.
" Complete arguments for Coffee* commands.
function! s:CoffeeComplete(cmd, cmdline, cursor)
let args = ['vertical']
" If no partial command, return all possibilities.
if !len(a:cmd)
return args
endif
let pat = '^' . a:cmd
for arg in args
if arg =~ pat
return [arg]
endif
endfor
endfunction
" Set initial state variables if they don't exist
if !exists('b:coffee_compile_buf')
call s:CoffeeCompileResetVars()
endif
" Peek at compiled CoffeeScript.
command! -range=% -bar -nargs=* -complete=customlist,s:CoffeeCompileComplete
if !exists('b:coffee_watch_buf')
call s:CoffeeWatchResetVars()
endif
if !exists('b:coffee_run_buf')
call s:CoffeeRunResetVars()
endif
command! -range=% -bar -nargs=* -complete=customlist,s:CoffeeComplete
\ CoffeeCompile call s:CoffeeCompile(<line1>, <line2>, <q-args>)
" Run some CoffeeScript.
command! -range=% -bar CoffeeRun <line1>,<line2>:w !coffee -s
" Run coffeelint on the file.
command! -bar -nargs=* -complete=customlist,s:CoffeeComplete
\ CoffeeWatch call s:CoffeeWatch(<q-args>)
command! -range=% -bar -nargs=* CoffeeRun
\ call s:CoffeeRun(<line1>, <line2>, <q-args>)
command! -range=% -bang -bar -nargs=* CoffeeLint
\ call s:CoffeeLint(<line1>, <line2>, '<bang>', <q-args>)
\ call s:CoffeeLint(<line1>, <line2>, <q-bang>, <q-args>)

View File

@ -3,7 +3,7 @@
" URL: http://github.com/kchmck/vim-coffee-script
" License: WTFPL
if exists("b:did_indent")
if exists('b:did_indent')
finish
endif
@ -15,43 +15,76 @@ setlocal indentexpr=GetCoffeeIndent(v:lnum)
" indented or outdented.
setlocal indentkeys+=0],0),0.,=else,=when,=catch,=finally
" If no indenting or outdenting is needed, either keep the indent of the cursor
" (use autoindent) or match the indent of the previous line.
if exists('g:coffee_indent_keep_current')
let s:DEFAULT_LEVEL = '-1'
else
let s:DEFAULT_LEVEL = 'indent(prevnlnum)'
endif
" Only define the function once.
if exists("*GetCoffeeIndent")
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\)\>'
" Keywords that begin a block
let s:BEGIN_BLOCK_KEYWORD = '\C^\%(if\|unless\|else\|for\|while\|until\|'
\ . 'loop\|switch\|when\|try\|catch\|finally\|'
\ . 'class\)\>\%(\s*:\)\@!'
" Operators to indent after
let s:INDENT_AFTER_OPERATOR = '\%([([{:=]\|[-=]>\)$'
" An expression that uses the result of a statement
let s:COMPOUND_EXPRESSION = '\C\%([^-]-\|[^+]+\|[^/]/\|[:=*%&|^<>]\)\s*'
\ . '\%(if\|unless\|for\|while\|until\|loop\|switch\|'
\ . 'try\|class\)\>'
" Keywords and operators that continue a line
let s:CONTINUATION = '\<\%(is\|isnt\|and\|or\)\>$'
\ . '\|'
\ . '\%(-\@<!-\|+\@<!+\|<\|[-=]\@<!>\|\*\|/\@<!/\|%\||\|'
\ . '&\|,\|\.\@<!\.\)$'
" Combine the two above
let s:BEGIN_BLOCK = s:BEGIN_BLOCK_KEYWORD . '\|' . s:COMPOUND_EXPRESSION
" Operators that block continuation indenting
let s:CONTINUATION_BLOCK = '[([{:=]$'
" Operators that begin a block but also count as a continuation
let s:BEGIN_BLOCK_OP = '[([{:=]$'
" Begins a function block
let s:FUNCTION = '[-=]>$'
" Operators that continue a line onto the next line
let s:CONTINUATION_OP = '\C\%(\<\%(is\|isnt\|and\|or\)\>\|'
\ . '[^-]-\|[^+]+\|[^-=]>\|[^.]\.\|[<*/%&|^,]\)$'
" Ancestor operators that prevent continuation indenting
let s:CONTINUATION = s:CONTINUATION_OP . '\|' . s:BEGIN_BLOCK_OP
" A closing bracket by itself on a line followed by a continuation
let s:BRACKET_CONTINUATION = '^\s*[}\])]\s*' . s:CONTINUATION_OP
" A continuation dot access
let s:DOT_ACCESS = '^\.'
" Keywords to outdent after
let s:OUTDENT_AFTER = '^\%(return\|break\|continue\|throw\)\>'
" Keywords that break out of a block
let s:BREAK_BLOCK_OP = '\C^\%(return\|break\|continue\|throw\)\>'
" A compound assignment like `... = if ...`
let s:COMPOUND_ASSIGNMENT = '[:=]\s*\%(if\|unless\|for\|while\|until\|'
\ . 'switch\|try\|class\)\>'
" A condition attached to the end of a statement
let s:POSTFIX_CONDITION = '\C\S\s\+\zs\<\%(if\|unless\|when\|while\|until\)\>'
" A postfix condition like `return ... if ...`.
let s:POSTFIX_CONDITION = '\S\s\+\zs\<\%(if\|unless\)\>'
" A then contained in brackets
let s:CONTAINED_THEN = '\C[(\[].\{-}\<then\>.\{-\}[)\]]'
" A single line else statement like `else ...` but not `else if ...`
let s:SINGLE_LINE_ELSE = '^else\s\+\%(\<\%(if\|unless\)\>\)\@!'
" An else with a condition attached
let s:ELSE_COND = '\C^\s*else\s\+\<\%(if\|unless\)\>'
" A single-line else statement (without a condition attached)
let s:SINGLE_LINE_ELSE = '\C^else\s\+\%(\<\%(if\|unless\)\>\)\@!'
" Pairs of starting and ending keywords, with an initial pattern to match
let s:KEYWORD_PAIRS = [
\ ['\C^else\>', '\C\<\%(if\|unless\|when\|else\s\+\%(if\|unless\)\)\>',
\ '\C\<else\>'],
\ ['\C^catch\>', '\C\<try\>', '\C\<catch\>'],
\ ['\C^finally\>', '\C\<try\>', '\C\<finally\>']
\]
" Pairs of starting and ending brackets
let s:BRACKET_PAIRS = {']': '\[', '}': '{', ')': '('}
" Max lines to look back for a match
let s:MAX_LOOKBACK = 50
@ -66,286 +99,330 @@ 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
" Compatibility code for shiftwidth() as recommended by the docs, but modified
" so there isn't as much of a penalty if shiftwidth() exists.
if exists('*shiftwidth')
let s:ShiftWidth = function('shiftwidth')
else
function! s:ShiftWidth()
return &shiftwidth
endfunction
endif
" Get the linked syntax name of a character.
function! s:SyntaxName(linenum, col)
return synIDattr(synID(a:linenum, a:col, 1), 'name')
function! s:SyntaxName(lnum, col)
return synIDattr(synID(a:lnum, 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
function! s:IsComment(lnum, col)
return s:SyntaxName(a:lnum, 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
function! s:IsString(lnum, col)
return s:SyntaxName(a:lnum, 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)
function! s:IsCommentOrString(lnum, col)
return s:SyntaxName(a:lnum, a:col) =~ s:SYNTAX_STRING_COMMENT
endfunction
" 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
function! s:SearchCode(lnum, regex)
" Start at the first column and look for an initial match (including at the
" cursor.)
call cursor(a:lnum, 1)
let pos = search(a:regex, 'c', a:lnum)
" 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)
while pos
if !s:IsCommentOrString(a:lnum, col('.'))
return 1
endif
" Move to the match and continue searching (don't accept matches at the
" cursor.)
let pos = search(a:regex, '', a:lnum)
endwhile
" No good match found.
return 0
endfunction
" Check if a match should be skipped.
function! s:ShouldSkip(startlinenum, linenum, col)
" Skip if in a comment or string.
if s:IsCommentOrString(a:linenum, a:col)
return 1
endif
" Search for the nearest previous line that isn't a comment.
function! s:GetPrevNormalLine(startlnum)
let curlnum = a:startlnum
" Skip if a single line statement that isn't adjacent.
if s:SmartSearch(a:linenum, '\<then\>') && a:startlinenum - a:linenum > 1
return 1
endif
while curlnum
let curlnum = prevnonblank(curlnum - 1)
" Skip if a postfix condition.
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\)\>', '\<else\>')
elseif a:curline =~ '^catch\>'
return s:SearchPair('\<try\>', '\<catch\>')
elseif a:curline =~ '^finally\>'
return s:SearchPair('\<try\>', '\<finally\>')
endif
return 0
endfunction
" Get the nearest previous line that isn't a comment.
function! s:GetPrevNormalLine(startlinenum)
let curlinenum = a:startlinenum
while curlinenum
let curlinenum = prevnonblank(curlinenum - 1)
if !s:IsCommentLine(curlinenum)
return curlinenum
" Return the line if the first non-whitespace character isn't a comment.
if !s:IsComment(curlnum, indent(curlnum) + 1)
return curlnum
endif
endwhile
return 0
endfunction
" Try to find a comment in a line.
function! s:FindComment(linenum)
call cursor(a:linenum, 0)
function! s:SearchPair(startlnum, lookback, skip, open, close)
" Go to the first column so a:close will be matched even if it's at the
" beginning of the line.
call cursor(a:startlnum, 1)
return searchpair(a:open, '', a:close, 'bnW', a:skip, max([1, a:lookback]))
endfunction
" Current column
let cur = 0
" Last column in the line
let end = col('$') - 1
" Skip if a match
" - is in a string or comment
" - is a single-line statement that isn't immediately
" adjacent
" - has a postfix condition and isn't an else statement or compound
" expression
function! s:ShouldSkip(startlnum, lnum, col)
return s:IsCommentOrString(a:lnum, a:col) ||
\ s:SearchCode(a:lnum, '\C\<then\>') && a:startlnum - a:lnum > 1 ||
\ s:SearchCode(a:lnum, s:POSTFIX_CONDITION) &&
\ getline(a:lnum) !~ s:ELSE_COND &&
\ !s:SearchCode(a:lnum, s:COMPOUND_EXPRESSION)
endfunction
while cur != end
call cursor(0, cur + 1)
let [_, cur] = searchpos('#', 'cn', a:linenum)
" Search for the nearest and farthest match for a keyword pair.
function! s:SearchMatchingKeyword(startlnum, open, close)
let skip = 's:ShouldSkip(' . a:startlnum . ", line('.'), line('.'))"
if !cur
" Search for the nearest match.
let nearestlnum = s:SearchPair(a:startlnum, a:startlnum - s:MAX_LOOKBACK,
\ skip, a:open, a:close)
if !nearestlnum
return []
endif
" Find the nearest previous line with indent less than or equal to startlnum.
let ind = indent(a:startlnum)
let lookback = s:GetPrevNormalLine(a:startlnum)
while lookback && indent(lookback) > ind
let lookback = s:GetPrevNormalLine(lookback)
endwhile
" Search for the farthest match. If there are no other matches, then the
" nearest match is also the farthest one.
let matchlnum = nearestlnum
while matchlnum
let lnum = matchlnum
let matchlnum = s:SearchPair(matchlnum, lookback, skip, a:open, a:close)
endwhile
return [nearestlnum, lnum]
endfunction
" Strip a line of a trailing comment and surrounding whitespace.
function! s:GetTrimmedLine(lnum)
" Try to find a comment starting at the first column.
call cursor(a:lnum, 1)
let pos = search('#', 'c', a:lnum)
" Keep searching until a comment is found or search returns 0.
while pos
if s:IsComment(a:lnum, col('.'))
break
endif
if s:IsComment(a:linenum, cur)
return cur
endif
let pos = search('#', '', a:lnum)
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
if !pos
" No comment was found so use the whole line.
let line = getline(a:lnum)
else
" Subtract 1 to get to the column before the comment and another 1 for
" zero-based indexing.
let line = line[:comment - 2]
" column indexing -> zero-based indexing.
let line = getline(a:lnum)[:col('.') - 2]
endif
return substitute(substitute(line, '^\s\+', '', ''),
\ '\s\+$', '', '')
endfunction
function! GetCoffeeIndent(curlinenum)
" Don't do anything if on the first line.
if a:curlinenum == 1
" Get the indent policy when no special rules are used.
function! s:GetDefaultPolicy(curlnum)
" Check whether equalprg is being ran on existing lines.
if strlen(getline(a:curlnum)) == indent(a:curlnum)
" If not indenting an existing line, use the default policy.
return s:DEFAULT_LEVEL
else
" Otherwise let autoindent determine what to do with an existing line.
return '-1'
endif
endfunction
function! GetCoffeeIndent(curlnum)
" Get the previous non-blank line (may be a comment.)
let prevlnum = prevnonblank(a:curlnum - 1)
" Bail if there's no code before.
if !prevlnum
return -1
endif
let prevlinenum = a:curlinenum - 1
" If continuing a comment, keep the indent level.
if s:IsCommentLine(prevlinenum)
return indent(prevlinenum)
" Bail if inside a multiline string.
if s:IsString(a:curlnum, 1)
let prevnlnum = prevlnum
exec 'return' s:GetDefaultPolicy(a:curlnum)
endif
let prevlinenum = s:GetPrevNormalLine(a:curlinenum)
" Get the code part of the current line.
let curline = s:GetTrimmedLine(a:curlnum)
" Get the previous non-comment line.
let prevnlnum = s:GetPrevNormalLine(a:curlnum)
" Don't do anything if there's no code before.
if !prevlinenum
return -1
" Check if the current line is the closing bracket in a bracket pair.
if has_key(s:BRACKET_PAIRS, curline[0])
" Search for a matching opening bracket.
let matchlnum = s:SearchPair(a:curlnum, a:curlnum - s:MAX_LOOKBACK,
\ "s:IsCommentOrString(line('.'), col('.'))",
\ s:BRACKET_PAIRS[curline[0]], curline[0])
if matchlnum
" Match the indent of the opening bracket.
return indent(matchlnum)
else
" No opening bracket found (bad syntax), so bail.
exec 'return' s:GetDefaultPolicy(a:curlnum)
endif
endif
" Indent based on the current line.
let curline = s:GetTrimmedLine(a:curlinenum)
" Check if the current line is the closing keyword in a keyword pair.
for pair in s:KEYWORD_PAIRS
if curline =~ pair[0]
" Find the nearest and farthest matches within the same indent level.
let matches = s:SearchMatchingKeyword(a:curlnum, pair[1], pair[2])
" Try to find a 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, '\<switch\>')
let linenum = a:curlinenum
while linenum
let linenum = s:GetPrevNormalLine(linenum)
if getline(linenum) =~ '^\s*when\>'
return indent(linenum)
if len(matches)
" Don't force indenting/outdenting as long as line is already lined up
" with a valid match
return max([min([indent(a:curlnum), indent(matches[0])]),
\ indent(matches[1])])
else
" No starting keyword found (bad syntax), so bail.
exec 'return' s:GetDefaultPolicy(a:curlnum)
endif
endif
endfor
" Check if the current line is a `when` and not the first in a switch block.
if curline =~ '\C^when\>' && !s:SearchCode(prevnlnum, '\C\<switch\>')
" Look back for a `when`.
while prevnlnum
if getline(prevnlnum) =~ '\C^\s*when\>'
" Indent to match the found `when`, but don't force indenting (for when
" indenting nested switch blocks.)
return min([indent(a:curlnum), indent(prevnlnum)])
endif
let prevnlnum = s:GetPrevNormalLine(prevnlnum)
endwhile
return -1
" No matching `when` found (bad syntax), so bail.
exec 'return' s:GetDefaultPolicy(a:curlnum)
endif
" Indent based on the previous line.
let prevline = s:GetTrimmedLine(prevlinenum)
let previndent = indent(prevlinenum)
" If the previous line is a comment, use its indentation, but don't force
" indenting.
if prevlnum != prevnlnum
return min([indent(a:curlnum), indent(prevlnum)])
endif
let prevline = s:GetTrimmedLine(prevnlnum)
" Always indent after these operators.
if prevline =~ s:INDENT_AFTER_OPERATOR
return previndent + &shiftwidth
if prevline =~ s:BEGIN_BLOCK_OP
return indent(prevnlnum) + s:ShiftWidth()
endif
" Indent after a continuation if it's the first.
if prevline =~ s:CONTINUATION
" If the line ends in a slash, make sure it isn't a regex.
if prevline =~ '/$'
" Move to the line so we can get the last column.
call cursor(prevlinenum)
if s:IsString(prevlinenum, col('$') - 1)
return -1
endif
" Indent if the previous line starts a function block, but don't force
" indenting if the line is non-blank (for empty function bodies.)
if prevline =~ s:FUNCTION
if strlen(getline(a:curlnum)) > indent(a:curlnum)
return min([indent(prevnlnum) + s:ShiftWidth(), indent(a:curlnum)])
else
return indent(prevnlnum) + s:ShiftWidth()
endif
let prevprevlinenum = s:GetPrevNormalLine(prevlinenum)
" If the continuation is the first in the file, there can't be others before
" it.
if !prevprevlinenum
return previndent + &shiftwidth
endif
let prevprevline = s:GetTrimmedLine(prevprevlinenum)
" Only indent after the first continuation.
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, '\<then\>') && prevline !~ s:SINGLE_LINE_ELSE
return previndent + &shiftwidth
" Check if continuation indenting is needed. If the line ends in a slash, make
" sure it isn't a regex.
if prevline =~ s:CONTINUATION_OP &&
\ !(prevline =~ '/$' && s:IsString(prevnlnum, col([prevnlnum, '$']) - 1))
" Don't indent if the continuation follows a closing bracket.
if prevline =~ s:BRACKET_CONTINUATION
exec 'return' s:GetDefaultPolicy(a:curlnum)
endif
return -1
let prevprevnlnum = s:GetPrevNormalLine(prevnlnum)
" Don't indent if not the first continuation.
if prevprevnlnum && s:GetTrimmedLine(prevprevnlnum) =~ s:CONTINUATION
exec 'return' s:GetDefaultPolicy(a:curlnum)
endif
" Continuation indenting seems to vary between programmers, so if the line
" is non-blank, don't override the indentation
if strlen(getline(a:curlnum)) > indent(a:curlnum)
exec 'return' s:GetDefaultPolicy(a:curlnum)
endif
" Otherwise indent a level.
return indent(prevnlnum) + s:ShiftWidth()
endif
" Check if the previous line starts with a keyword that begins a block.
if prevline =~ s:BEGIN_BLOCK
" Indent if the current line doesn't start with `then` and the previous line
" isn't a single-line statement.
if curline !~ '\C^\<then\>' && !s:SearchCode(prevnlnum, '\C\<then\>') &&
\ prevline !~ s:SINGLE_LINE_ELSE
return indent(prevnlnum) + s:ShiftWidth()
else
exec 'return' s:GetDefaultPolicy(a:curlnum)
endif
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, '\<then\>')
return previndent - &shiftwidth
if curline =~ s:DOT_ACCESS
if prevline !~ s:DOT_ACCESS
return indent(prevnlnum) + s:ShiftWidth()
else
exec 'return' s:GetDefaultPolicy(a:curlnum)
endif
endif
" If no indent or outdent is needed, keep the indent level of the previous
" line.
return previndent
" Outdent if a keyword breaks out of a block as long as it doesn't have a
" postfix condition (and the postfix condition isn't a single-line statement.)
if prevline =~ s:BREAK_BLOCK_OP
if !s:SearchCode(prevnlnum, s:POSTFIX_CONDITION) ||
\ s:SearchCode(prevnlnum, '\C\<then\>') &&
\ !s:SearchCode(prevnlnum, s:CONTAINED_THEN)
" Don't force indenting.
return min([indent(a:curlnum), indent(prevnlnum) - s:ShiftWidth()])
else
exec 'return' s:GetDefaultPolicy(a:curlnum)
endif
endif
" Check if inside brackets.
let matchlnum = s:SearchPair(a:curlnum, a:curlnum - s:MAX_LOOKBACK,
\ "s:IsCommentOrString(line('.'), col('.'))",
\ '\[\|(\|{', '\]\|)\|}')
" If inside brackets, indent relative to the brackets, but don't outdent an
" already indented line.
if matchlnum
return max([indent(a:curlnum), indent(matchlnum) + s:ShiftWidth()])
endif
" No special rules applied, so use the default policy.
exec 'return' s:GetDefaultPolicy(a:curlnum)
endfunction

View File

@ -10,12 +10,10 @@ endif
" Include JavaScript for coffeeEmbed.
syn include @coffeeJS syntax/javascript.vim
silent! unlet b:current_syntax
" Highlight long strings.
syn sync minlines=100
" CoffeeScript identifiers can have dollar signs.
setlocal isident+=$
syntax sync fromstart
" These are `matches` instead of `keywords` because vim's highlighting
" priority for keywords is higher than matches. This causes keywords to be
@ -66,7 +64,7 @@ syn match coffeeSpecialVar /\<\%(this\|prototype\|arguments\)\>/ display
hi def link coffeeSpecialVar Special
" An @-variable
syn match coffeeSpecialIdent /@\%(\I\i*\)\?/ display
syn match coffeeSpecialIdent /@\%(\%(\I\|\$\)\%(\i\|\$\)*\)\?/ display
hi def link coffeeSpecialIdent Identifier
" A class-like name that starts with a capital letter
@ -94,27 +92,27 @@ syn region coffeeString start=/'/ skip=/\\\\\|\\'/ end=/'/
hi def link coffeeString String
" A integer, including a leading plus or minus
syn match coffeeNumber /\i\@<![-+]\?\d\+\%([eE][+-]\?\d\+\)\?/ display
syn match coffeeNumber /\%(\i\|\$\)\@<![-+]\?\d\+\%([eE][+-]\?\d\+\)\?/ display
" A hex, binary, or octal number
syn match coffeeNumber /\<0[xX]\x\+\>/ display
syn match coffeeNumber /\<0[bB][01]\+\>/ display
syn match coffeeNumber /\<0[oO][0-7]\+\>/ display
syn match coffeeNumber /\<\%(Infinity\|NaN\)\>/ display
hi def link coffeeNumber Number
" A floating-point number, including a leading plus or minus
syn match coffeeFloat /\i\@<![-+]\?\d*\.\@<!\.\d\+\%([eE][+-]\?\d\+\)\?/
syn match coffeeFloat /\%(\i\|\$\)\@<![-+]\?\d*\.\@<!\.\d\+\%([eE][+-]\?\d\+\)\?/
\ display
hi def link coffeeFloat Float
" An error for reserved keywords
if !exists("coffee_no_reserved_words_error")
syn match coffeeReservedError /\<\%(case\|default\|function\|var\|void\|with\|const\|let\|enum\|export\|import\|native\|__hasProp\|__extends\|__slice\|__bind\|__indexOf\|implements\|interface\|let\|package\|private\|protected\|public\|static\|yield\)\>/
\ display
hi def link coffeeReservedError Error
endif
" An error for reserved keywords, taken from the RESERVED array:
" http://coffeescript.org/documentation/docs/lexer.html#section-67
syn match coffeeReservedError /\<\%(case\|default\|function\|var\|void\|with\|const\|let\|enum\|export\|import\|native\|__hasProp\|__extends\|__slice\|__bind\|__indexOf\|implements\|interface\|package\|private\|protected\|public\|static\|yield\)\>/
\ display
hi def link coffeeReservedError Error
" A normal object assignment
syn match coffeeObjAssign /@\?\I\i*\s*\ze::\@!/ contains=@coffeeIdentifier display
syn match coffeeObjAssign /@\?\%(\I\|\$\)\%(\i\|\$\)*\s*\ze::\@!/ contains=@coffeeIdentifier display
hi def link coffeeObjAssign Identifier
syn keyword coffeeTodo TODO FIXME XXX contained
@ -134,7 +132,7 @@ hi def link coffeeHeregexComment coffeeComment
" Embedded JavaScript
syn region coffeeEmbed matchgroup=coffeeEmbedDelim
\ start=/`/ skip=/\\\\\|\\`/ end=/`/
\ start=/`/ skip=/\\\\\|\\`/ end=/`/ keepend
\ contains=@coffeeJS
hi def link coffeeEmbedDelim Delimiter
@ -148,17 +146,23 @@ hi def link coffeeEscape SpecialChar
" A regex -- must not follow a parenthesis, number, or identifier, and must not
" be followed by a number
syn region coffeeRegex start=/\%(\%()\|\i\@<!\d\)\s*\|\i\)\@<!\/=\@!\s\@!/
\ skip=/\[[^\]]\{-}\/[^\]]\{-}\]/
\ end=/\/[gimy]\{,4}\d\@!/
\ oneline contains=@coffeeBasicString
syn region coffeeRegex start=#\%(\%()\|\%(\i\|\$\)\@<!\d\)\s*\|\i\)\@<!/=\@!\s\@!#
\ end=#/[gimy]\{,4}\d\@!#
\ oneline contains=@coffeeBasicString,coffeeRegexCharSet
syn region coffeeRegexCharSet start=/\[/ end=/]/ contained
\ contains=@coffeeBasicString
hi def link coffeeRegex String
hi def link coffeeRegexCharSet coffeeRegex
" A heregex
syn region coffeeHeregex start=/\/\/\// end=/\/\/\/[gimy]\{,4}/
\ contains=@coffeeInterpString,coffeeHeregexComment
syn region coffeeHeregex start=#///# end=#///[gimy]\{,4}#
\ contains=@coffeeInterpString,coffeeHeregexComment,
\ coffeeHeregexCharSet
\ fold
syn region coffeeHeregexCharSet start=/\[/ end=/]/ contained
\ contains=@coffeeInterpString
hi def link coffeeHeregex coffeeRegex
hi def link coffeeHeregexCharSet coffeeHeregex
" Heredoc strings
syn region coffeeHeredoc start=/"""/ end=/"""/ contains=@coffeeInterpString
@ -168,23 +172,19 @@ syn region coffeeHeredoc start=/'''/ end=/'''/ contains=@coffeeBasicString
hi def link coffeeHeredoc String
" An error for trailing whitespace, as long as the line isn't just whitespace
if !exists("coffee_no_trailing_space_error")
syn match coffeeSpaceError /\S\@<=\s\+$/ display
hi def link coffeeSpaceError Error
endif
syn match coffeeSpaceError /\S\@<=\s\+$/ display
hi def link coffeeSpaceError Error
" An error for trailing semicolons, for help transitioning from JavaScript
if !exists("coffee_no_trailing_semicolon_error")
syn match coffeeSemicolonError /;$/ display
hi def link coffeeSemicolonError Error
endif
syn match coffeeSemicolonError /;$/ display
hi def link coffeeSemicolonError Error
" Ignore reserved words in dot accesses.
syn match coffeeDotAccess /\.\@<!\.\s*\I\i*/he=s+1 contains=@coffeeIdentifier
syn match coffeeDotAccess /\.\@<!\.\s*\%(\I\|\$\)\%(\i\|\$\)*/he=s+1 contains=@coffeeIdentifier
hi def link coffeeDotAccess coffeeExtendedOp
" Ignore reserved words in prototype accesses.
syn match coffeeProtoAccess /::\s*\I\i*/he=s+2 contains=@coffeeIdentifier
syn match coffeeProtoAccess /::\s*\%(\I\|\$\)\%(\i\|\$\)*/he=s+2 contains=@coffeeIdentifier
hi def link coffeeProtoAccess coffeeExtendedOp
" This is required for interpolations to work.

View File

@ -1,62 +0,0 @@
" Vim syntax file
" Language: eco
" Maintainer: Jay Adkisson
" Mostly stolen from eruby.vim
if !exists("g:eco_default_subtype")
let g:eco_default_subtype = "html"
endif
if !exists("b:eco_subtype")
let s:lines = getline(1)."\n".getline(2)."\n".getline(3)."\n".getline(4)."\n".getline(5)."\n".getline("$")
let b:eco_subtype = matchstr(s:lines,'eco_subtype=\zs\w\+')
if b:eco_subtype == ''
let b:eco_subtype = matchstr(substitute(expand("%:t"),'\c\%(\.eco\)\+$','',''),'\.\zs\w\+$')
endif
if b:eco_subtype == 'rhtml'
let b:eco_subtype = 'html'
elseif b:eco_subtype == 'jst'
let b:eco_subtype = 'html'
elseif b:eco_subtype == 'rb'
let b:eco_subtype = 'ruby'
elseif b:eco_subtype == 'yml'
let b:eco_subtype = 'yaml'
elseif b:eco_subtype == 'js' || b:eco_subtype == 'json'
let b:eco_subtype = 'javascript'
elseif b:eco_subtype == 'txt'
" Conventional; not a real file type
let b:eco_subtype = 'text'
elseif b:eco_subtype == ''
if exists('b:current_syntax') && b:current_syntax != ''
let b:eco_subtype = b:current_syntax
else
let b:eco_subtype = g:eco_default_subtype
endif
endif
endif
if exists("b:eco_subtype") && b:eco_subtype != '' && b:eco_subtype != 'eco'
exec "runtime! syntax/".b:eco_subtype.".vim"
syn include @coffeeTop syntax/coffee.vim
endif
syn cluster ecoRegions contains=ecoBlock,ecoExpression,ecoComment
syn region ecoBlock matchgroup=ecoDelimiter start=/<%/ end=/%>/ 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:

View File

@ -1,12 +0,0 @@
<html>
<%# comment %>
<%# basic %>
<%- foo = "1" %>
<%# interpolation %>
<%= " == #{ ( -> "LOL" )() } == " %>
<%# interpolation with nested curlies %>
<%= " == #{ { a: 1, b: { c: 3, d: 4 } } } == " %>
</html>

View File

@ -0,0 +1,3 @@
:coffeescript
class Hello
# test