123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- " Language: CoffeeScript
- " Maintainer: Mick Koch <mick@kochm.co>
- " URL: http://github.com/kchmck/vim-coffee-script
- " License: WTFPL
-
- if exists('b:did_ftplugin')
- finish
- endif
-
- let b:did_ftplugin = 1
- call coffee#CoffeeSetUpVariables()
-
- setlocal formatoptions-=t formatoptions+=croql
- setlocal comments=:# commentstring=#\ %s
- setlocal omnifunc=javascriptcomplete#CompleteJS
- setlocal suffixesadd+=coffee
-
- " 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
-
- " Switch to the window for buf.
- function! s:SwitchWindow(buf)
- exec bufwinnr(a:buf) 'wincmd w'
- endfunction
-
- " 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()
- " Switch to the source buffer if not already in it.
- silent! call s:SwitchWindow(b:coffee_src_buf)
- call s:CoffeeCompileResetVars()
- endfunction
-
- function! s:CoffeeWatchClose()
- silent! call s:SwitchWindow(b:coffee_src_buf)
- silent! autocmd! CoffeeAuWatch * <buffer>
- call s:CoffeeWatchResetVars()
- endfunction
-
- 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
-
- " Pipe lines into coffee.
- let output = system(g:coffee_compiler .
- \ ' -scb' .
- \ ' ' . b:coffee_litcoffee .
- \ ' 2>&1', input)
-
- " Paste output into output buffer.
- call s:ScratchBufUpdate(a:buf, output)
-
- " 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
- 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 a:args =~ '\<watch\>'
- echoerr 'CoffeeCompile watch is deprecated! Please use CoffeeWatch instead'
- sleep 5
- call s:CoffeeWatch(a:args)
- return
- endif
-
- " 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')
- return
- endif
-
- " Build the output buffer if it doesn't exist.
- if bufwinnr(b:coffee_compile_buf) == -1
- let src = bufnr('%')
-
- let vert = exists('g:coffee_compile_vert') || a:args =~ '\<vert\%[ical]\>'
- let size = str2nr(matchstr(a:args, '\<\d\+\>'))
-
- " Build the output buffer and save the source bufnr.
- let buf = s:ScratchBufBuild(src, vert, size)
- let b:coffee_src_buf = src
-
- " 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 output buffer.
- autocmd BufLeave <buffer> let b:coffee_compile_pos = getpos('.')
-
- " Run user-defined commands on new buffer.
- silent doautocmd CoffeeBufNew User CoffeeCompile
-
- " 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
-
- " 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)
-
- " 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
- let input = join(getline(a:startline, a:endline), "\n")
-
- if !len(input)
- return
- endif
-
- 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
- " to the quickfix list.
- function! s:CoffeeLint(startline, endline, bang, args)
- let input = join(getline(a:startline, a:endline), "\n")
-
- if !len(input)
- return
- endif
-
- let output = system(g:coffee_linter .
- \ ' -s --reporter csv' .
- \ ' ' . b:coffee_litcoffee .
- \ ' ' . g:coffee_lint_options .
- \ ' ' . a:args .
- \ ' 2>&1', input)
-
- " 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, '^stdin,\(\d\+\),\d*,\(error\|warn\),\(.\+\)$')
-
- " Ignore unmatched lines.
- if !len(match)
- continue
- endif
-
- " 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')
-
- " If not given a bang, jump to first error.
- if !len(a:bang)
- silent! cc 1
- endif
- endfunction
-
- " 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
-
- if !exists('b:coffee_watch_buf')
- call s:CoffeeWatchResetVars()
- endif
-
- if !exists('b:coffee_run_buf')
- call s:CoffeeRunResetVars()
- endif
-
- command! -buffer -range=% -bar -nargs=* -complete=customlist,s:CoffeeComplete
- \ CoffeeCompile call s:CoffeeCompile(<line1>, <line2>, <q-args>)
- command! -buffer -bar -nargs=* -complete=customlist,s:CoffeeComplete
- \ CoffeeWatch call s:CoffeeWatch(<q-args>)
- command! -buffer -range=% -bar -nargs=* CoffeeRun
- \ call s:CoffeeRun(<line1>, <line2>, <q-args>)
- command! -buffer -range=% -bang -bar -nargs=* CoffeeLint
- \ call s:CoffeeLint(<line1>, <line2>, <q-bang>, <q-args>)
|