Compare commits

..

No commits in common. "master" and "preload" have entirely different histories.

7 changed files with 196 additions and 496 deletions

View File

@ -4,13 +4,16 @@ There's a REPL in fireplace, but you probably wouldn't have noticed if I hadn't
told you. Such is the way with fireplace.vim. By the way, this plugin is for
Clojure.
Fireplace.vim used to be called foreplay.vim, but it was renamed so Java
developers wouldn't have to speak in hushed tones.
## Installation
First, set up [cider-nrepl][]. (If you skip this step, fireplace.vim will
make do with eval, which mostly works.) Next, fireplace.vim doesn't provide
indenting or syntax highlighting, so you'll want [a set of Clojure runtime
files](https://github.com/guns/vim-clojure-static) if you're on a version of
Vim earlier than 7.4. You might also want [salve.vim][] for assorted
Vim earlier than 7.4. You might also want [leiningen.vim][] for assorted
static project support.
If you don't have a preferred installation method, I recommend
@ -38,16 +41,16 @@ one automatically. ClojureScript support is just as seamless with
The only external dependency is that you have either a Vim with Python support
compiled in, or `python` in your path.
Oh, and if you don't have an nREPL connection, installing [salve.vim][]
Oh, and if you don't have an nREPL connection, installing [leiningen.vim][]
lets it fall back to using `java clojure.main` for some of the basics, using a
class path based on your Leiningen config. It's a bit slow, but a two-second
delay is vastly preferable to being forced out of my flow for a single
command, in my book.
class path based on your Leiningen or Maven config. It's a bit slow, but a
two-second delay is vastly preferable to being forced out of my flow for a
single command, in my book.
[cider-nrepl]: https://github.com/clojure-emacs/cider-nrepl
[Piggieback]: https://github.com/cemerick/piggieback
[classpath.vim]: https://github.com/tpope/vim-classpath
[salve.vim]: https://github.com/tpope/vim-salve
[leiningen.vim]: https://github.com/tpope/vim-leiningen
### Not quite a REPL
@ -108,13 +111,12 @@ Because why not? It works in the quasi-REPL too.
> Why does it take so long for Vim to startup?
That's either [classpath.vim][] or [salve.vim][].
That's either [classpath.vim][] or [leiningen.vim][].
## Self-Promotion
Like fireplace.vim? Follow the repository on
[GitHub](https://github.com/tpope/vim-fireplace) and vote for it on
[vim.org](http://www.vim.org/scripts/script.php?script_id=4978). And if
[GitHub](https://github.com/tpope/vim-fireplace). And if
you're feeling especially charitable, follow [tpope](http://tpo.pe/) on
[Twitter](http://twitter.com/tpope) and
[GitHub](https://github.com/tpope).

View File

@ -1,4 +1,4 @@
" Location: autoload/nrepl/fireplace.vim
" Fireplace nREPL session
if exists("g:autoloaded_fireplace_nrepl")
finish
@ -34,24 +34,14 @@ function! fireplace#nrepl#for(transport) abort
let client.transport = a:transport
let client.session = client.process({'op': 'clone', 'session': 0})['new-session']
let client.describe = client.process({'op': 'describe', 'verbose?': 1})
if get(client.describe.versions.nrepl, 'major', -1) == 0 &&
if client.describe.versions.nrepl.major == 0 &&
\ client.describe.versions.nrepl.minor < 2
throw 'nREPL: 0.2.0 or higher required'
endif
" Handle boot, which sets a fake.class.path entry
let response = client.process({'op': 'eval', 'code':
\ '[(System/getProperty "path.separator") (System/getProperty "fake.class.path")]', 'session': ''})
let cpath = response.value[-1][5:-2]
if cpath !=# 'nil'
let cpath = eval(cpath)
if !empty(cpath)
let client._path = split(cpath, response.value[-1][2])
endif
endif
if !has_key(client, '_path') && client.has_op('classpath')
if client.has_op('classpath')
let response = client.message({'op': 'classpath'})[0]
if type(get(response, 'classpath')) == type([])
let client._path = response.classpath
if type(get(response, 'value')) == type([])
let client._path = response.value
endif
endif
if !has_key(client, '_path')
@ -157,16 +147,13 @@ function! s:nrepl_eval(expr, ...) dict abort
endif
try
let response = self.process(msg)
finally
if !exists('response')
let session = get(msg, 'session', self.session)
if !empty(session)
call self.message({'op': 'interrupt', 'session': session, 'interrupt-id': msg.id}, 'ignore')
catch /^Vim:Interrupt$/
if has_key(msg, 'session')
call self.message({'op': 'interrupt', 'session': msg.session, 'interrupt-id': msg.id}, 'ignore')
endif
throw 'Clojure: Interrupt'
endif
endtry
if has_key(response, 'ns') && empty(get(options, 'ns'))
if has_key(response, 'ns') && !has_key(options, 'ns')
let self.ns = response.ns
endif
@ -182,23 +169,13 @@ endfunction
function! s:extract_last_stacktrace(nrepl, session) abort
if a:nrepl.has_op('stacktrace')
let stacktrace = a:nrepl.message({'op': 'stacktrace', 'session': a:session})
if len(stacktrace) > 0 && has_key(stacktrace[0], 'stacktrace')
let stacktrace = stacktrace[0].stacktrace
endif
call filter(stacktrace, 'has_key(v:val, "file")')
let stacktrace = filter(a:nrepl.message({'op': 'stacktrace', 'session': a:session}), 'has_key(v:val, "file")')
if !empty(stacktrace)
return map(stacktrace, 'v:val.class.".".v:val.method."(".v:val.file.":".v:val.line.")"')
endif
endif
let format_st = '(symbol (str "\n\b" (apply str (interleave (repeat "\n") (map str (.getStackTrace *e)))) "\n\b\n"))'
let response = a:nrepl.process({'op': 'eval', 'code': '['.format_st.' *3 *2 *1]', 'ns': 'user', 'session': a:session})
try
let stacktrace = split(get(split(response.value[0], "\n\b\n"), 1, ""), "\n")
catch
throw string(response)
endtry
let stacktrace = split(get(split(a:nrepl.process({'op': 'eval', 'code': '['.format_st.' *3 *2 *1]', 'ns': 'user', 'session': a:session}).value[0], "\n\b\n"), 1, ""), "\n")
call a:nrepl.message({'op': 'eval', 'code': '(*1 1)', 'ns': 'user', 'session': a:session})
call a:nrepl.message({'op': 'eval', 'code': '(*2 2)', 'ns': 'user', 'session': a:session})
call a:nrepl.message({'op': 'eval', 'code': '(*3 3)', 'ns': 'user', 'session': a:session})
@ -213,9 +190,6 @@ function! s:nrepl_prepare(msg) dict abort
if !has_key(msg, 'id')
let msg.id = fireplace#nrepl#next_id()
endif
if empty(get(msg, 'ns', 1))
unlet msg.ns
endif
if empty(get(msg, 'session', 1))
unlet msg.session
elseif !has_key(msg, 'session')
@ -224,15 +198,12 @@ function! s:nrepl_prepare(msg) dict abort
return msg
endfunction
function! fireplace#nrepl#callback(body, type, callback) abort
try
function! fireplace#nrepl#callback(body, type, fn)
let response = {'body': a:body, 'type': a:type}
if has_key(g:fireplace_nrepl_sessions, get(a:body, 'session'))
let response.session = g:fireplace_nrepl_sessions[a:body.session]
endif
call call(a:callback[0], [response] + a:callback[1:-1])
catch
endtry
call call(a:fn, [response])
endfunction
function! s:nrepl_call(msg, ...) dict abort

View File

@ -1,4 +1,5 @@
" Location: autoload/nrepl/fireplace_connection.vim
" autoload/nrepl/fireplace_connection.vim
" Maintainer: Tim Pope <http://tpo.pe/>
if exists("g:autoloaded_nrepl_fireplace_connection") || &cp
finish
@ -21,11 +22,7 @@ function! fireplace#nrepl_connection#bencode(value) abort
elseif type(a:value) == type([])
return 'l'.join(map(copy(a:value),'fireplace#nrepl_connection#bencode(v:val)'),'').'e'
elseif type(a:value) == type({})
return 'd'.join(map(
\ sort(keys(a:value)),
\ 'fireplace#nrepl_connection#bencode(v:val) . ' .
\ 'fireplace#nrepl_connection#bencode(a:value[v:val])'
\ ),'').'e'
return 'd'.join(values(map(copy(a:value),'fireplace#nrepl_connection#bencode(v:key).fireplace#nrepl_connection#bencode(v:val)')),'').'e'
else
throw "Can't bencode ".string(a:value)
endif
@ -109,7 +106,7 @@ function! s:nrepl_transport_call(msg, terms, sels, ...) dict abort
if !a:0
return response
elseif a:1 !=# 'ignore'
return map(response, 'fireplace#nrepl#callback(v:val, "synchronous", a:000)')
return map(response, 'fireplace#nrepl#callback(v:val, "synchronous", a:1)')
endif
endfunction

9
compiler/lein.vim Normal file
View File

@ -0,0 +1,9 @@
" Vim compiler file
if exists("current_compiler")
finish
endif
let current_compiler = "lein"
CompilerSet makeprg=lein
CompilerSet errorformat=%+G

View File

@ -1,4 +1,4 @@
*fireplace.txt* Clojure REPL support
*fireplace.txt* Clojure REPL tease
Author: Tim Pope <http://tpo.pe/>
License: Same terms as Vim itself (see |license|)
@ -123,12 +123,7 @@ stack trace is loaded into the |location-list|. Use |:lopen| to view it.
:RunTests [ns] [...] Call clojure.test/run-tests on the given namespaces
and load the results into the quickfix list.
:[range]RunTests Call clojure.test/test-var on the var defined at or
above the specicied line and load the results into the
quickfix list. Typically invoked as :.RunTests to run
the test under the cursor.
:0RunTests [pattern] Call clojure.test/run-all-tests with the given pattern
:RunTests! [pattern] Call clojure.test/run-all-tests with the given pattern
and load the results into the quickfix list.
*fireplace-cp*
@ -159,10 +154,6 @@ c1mm Macroexpand the innermost form at the cursor once.
*fireplace-cqp*
cqp Bring up a prompt for code to eval/print.
*fireplace-cqq*
cqq Bring up a |command-line-window| with innermost form
at the cursor prepopulated.
*fireplace-cqc*
cqc Bring up a |command-line-window| for code to
eval/print. Equivalent to cqp<C-F>i.

View File

@ -1,7 +1,5 @@
" fireplace.vim - Clojure REPL support
" fireplace.vim - Clojure REPL tease
" Maintainer: Tim Pope <http://tpo.pe/>
" Version: 1.1
" GetLatestVimScripts: 4978 1 :AutoInstall: fireplace.vim
if exists("g:loaded_fireplace") || v:version < 700 || &cp
finish
@ -41,8 +39,6 @@ function! fireplace#jar_contents(path) abort
if !exists('s:zipinfo')
if executable('zipinfo')
let s:zipinfo = 'zipinfo -1 '
elseif executable('jar')
let s:zipinfo = 'jar tf '
elseif executable('python')
let s:zipinfo = 'python -c '.shellescape('import zipfile, sys; print chr(10).join(zipfile.ZipFile(sys.argv[1]).namelist())').' '
else
@ -83,64 +79,6 @@ function! fireplace#ns_complete(A, L, P) abort
return filter(map(matches, 's:to_ns(v:val)'), 'a:A ==# "" || a:A ==# v:val[0 : strlen(a:A)-1]')
endfunction
let s:short_types = {
\ 'function': 'f',
\ 'macro': 'm',
\ 'var': 'v',
\ 'special-form': 's',
\ 'class': 'c',
\ 'keyword': 'k',
\ 'local': 'l',
\ 'namespace': 'n',
\ 'field': 'i',
\ 'method': 'f',
\ 'static-field': 'i',
\ 'static-method': 'f',
\ 'resource': 'r'
\ }
function! s:candidate(val) abort
let type = get(a:val, 'type', '')
let arglists = get(a:val, 'arglists', [])
return {
\ 'word': get(a:val, 'candidate'),
\ 'kind': get(s:short_types, type, type),
\ 'info': get(a:val, 'doc', ''),
\ 'menu': empty(arglists) ? '' : '(' . join(arglists, ' ') . ')'
\ }
endfunction
function! s:get_complete_context() abort
" Find toplevel form
" If cursor is on start parenthesis we don't want to find the form
" If cursor is on end parenthesis we want to find the form
let [line1, col1] = searchpairpos('(', '', ')', 'Wrnb', g:fireplace#skip)
let [line2, col2] = searchpairpos('(', '', ')', 'Wrnc', g:fireplace#skip)
if (line1 == 0 && col1 == 0) || (line2 == 0 && col2 == 0)
return ""
endif
if line1 == line2
let expr = getline(line1)[col1-1 : col2-1]
else
let expr = getline(line1)[col1-1 : -1] . ' '
\ . join(getline(line1+1, line2-1), ' ')
\ . getline(line2)[0 : col2-1]
endif
" Calculate the position of cursor inside the expr
if line1 == line('.')
let p = col('.') - col1
else
let p = strlen(getline(line1)[col1-1 : -1])
\ + strlen(join(getline(line1 + 1, line('.') - 1), ' '))
\ + col('.')
endif
return strpart(expr, 0, p) . '__prefix__' . strpart(expr, p)
endfunction
function! fireplace#omnicomplete(findstart, base) abort
if a:findstart
let line = getline('.')[0 : col('.')-2]
@ -149,21 +87,12 @@ function! fireplace#omnicomplete(findstart, base) abort
try
if fireplace#op_available('complete')
let response = fireplace#message({
\ 'op': 'complete',
\ 'symbol': a:base,
\ 'extra-metadata': ['arglists', 'doc'],
\ 'context': s:get_complete_context()
\ })
let trans = '{"word": (v:val =~# ''[./]'' ? "" : matchstr(a:base, ''^.\+/'')) . v:val}'
let value = get(response[0], 'value', get(response[0], 'completions'))
if type(value) == type([])
if type(get(value, 0)) == type({})
return map(value, 's:candidate(v:val)')
elseif type(get(value, 0)) == type([])
return map(value[0], trans)
elseif type(get(value, 0)) == type('')
return map(value, trans)
let response = fireplace#message({'op': 'complete', 'symbol': a:base})
if type(get(response[0], 'value')) == type([])
if type(get(response[0].value, 0)) == type([])
return map(response[0].value[0], '{"word": v:val}')
elseif type(get(response[0].value, 0)) == type('')
return map(response[0].value, '{"word": v:val}')
else
return []
endif
@ -219,6 +148,10 @@ if !exists('s:repls')
let s:repl_portfiles = {}
endif
function! s:repl.user_ns() abort
return 'user'
endfunction
function! s:repl.path() dict abort
return self.connection.path()
endfunction
@ -232,6 +165,16 @@ function! s:conn_try(connection, function, ...) abort
endtry
endfunction
function! s:repl.eval(expr, options) dict abort
if has_key(a:options, 'ns') && a:options.ns !=# self.user_ns()
let error = self.preload(a:options.ns)
if !empty(error)
return error
endif
endif
return s:conn_try(self.connection, 'eval', a:expr, a:options)
endfunction
function! s:repl.message(payload, ...) dict abort
if has_key(a:payload, 'ns') && a:payload.ns !=# self.user_ns()
let ignored_error = self.preload(a:payload.ns)
@ -277,19 +220,15 @@ function! s:repl.piggieback(arg, ...) abort
let connection = s:conn_try(self.connection, 'clone')
if empty(a:arg)
let arg = '(cljs.repl.rhino/repl-env)'
let arg = ''
elseif a:arg =~# '^\d\{1,5}$'
let replns = 'weasel.repl.websocket'
if has_key(connection.eval("(require '" . replns . ")"), 'ex')
let replns = 'cljs.repl.browser'
call connection.eval("(require '" . replns . ")")
endif
call connection.eval("(require 'cljs.repl.browser)")
let port = matchstr(a:arg, '^\d\{1,5}$')
let arg = '('.replns.'/repl-env :port '.port.')'
let arg = ' :repl-env (cljs.repl.browser/repl-env :port '.port.')'
else
let arg = a:arg
let arg = ' :repl-env ' . a:arg
endif
let response = connection.eval('(cemerick.piggieback/cljs-repl'.' '.arg.')')
let response = connection.eval('(cemerick.piggieback/cljs-repl'.arg.')')
if empty(get(response, 'ex'))
call insert(self.piggiebacks, extend({'connection': connection}, deepcopy(s:piggieback)))
@ -311,20 +250,6 @@ function! s:piggieback.eval(expr, options) abort
return call(s:repl.eval, [a:expr, options], self)
endfunction
function! s:repl.user_ns() abort
return 'user'
endfunction
function! s:repl.eval(expr, options) dict abort
if has_key(a:options, 'ns') && a:options.ns !=# self.user_ns()
let error = self.preload(a:options.ns)
if !empty(error)
return error
endif
endif
return s:conn_try(self.connection, 'eval', a:expr, a:options)
endfunction
function! s:register_connection(conn, ...) abort
call insert(s:repls, extend({'connection': a:conn, 'piggiebacks': []}, deepcopy(s:repl)))
if a:0 && a:1 !=# ''
@ -347,11 +272,10 @@ function! fireplace#register_port_file(portfile, ...) abort
endif
if empty(old) && getfsize(a:portfile) > 0
let port = matchstr(readfile(a:portfile, 'b', 1)[0], '\d\+')
let s:repl_portfiles[a:portfile] = {'time': getftime(a:portfile)}
try
let conn = fireplace#nrepl_connection#open(port)
let s:repl_portfiles[a:portfile] = {
\ 'time': getftime(a:portfile),
\ 'connection': conn}
let s:repl_portfiles[a:portfile].connection = conn
call s:register_connection(conn, a:0 ? a:1 : '')
return conn
catch /^nREPL Connection Error:/
@ -386,7 +310,7 @@ function! fireplace#input_host_port() abort
endfunction
function! s:protos() abort
return map(split(globpath(&runtimepath, 'autoload/fireplace/*_connection.vim'), "\n"), 'fnamemodify(v:val, ":t")[0:-16]')
return map(split(globpath(&runtimepath, 'autoload/*/fireplace_connection.vim'), "\n"), 'fnamemodify(v:val, ":h:t")')
endfunction
function! s:connect_complete(A, L, P) abort
@ -411,8 +335,6 @@ endfunction
function! s:Connect(...) abort
if (a:0 ? a:1 : '') =~# '^\w\+://'
let [proto, arg] = split(a:1, '://')
elseif (a:0 ? a:1 : '') =~# '^\%([[:alnum:].-]\+:\)\=\d\+$'
let [proto, arg] = ['nrepl', a:1]
elseif a:0
return 'echoerr '.string('Usage: :Connect proto://...')
else
@ -427,10 +349,10 @@ function! s:Connect(...) abort
redraw!
echo ':Connect'
echo 'Protocol> '.proto
let arg = fireplace#{proto}_connection#prompt()
let arg = {proto}#fireplace_connection#prompt()
endif
try
let connection = fireplace#{proto}_connection#open(arg)
let connection = {proto}#fireplace_connection#open(arg)
catch /.*/
return 'echoerr '.string(v:exception)
endtry
@ -454,10 +376,8 @@ endfunction
augroup fireplace_connect
autocmd!
autocmd FileType clojure command! -buffer -bar -complete=customlist,s:connect_complete -nargs=*
\ Connect FireplaceConnect <args>
autocmd FileType clojure command! -buffer -bang -complete=customlist,fireplace#eval_complete -nargs=*
\ Piggieback call s:piggieback(<q-args>, <bang>0)
autocmd FileType clojure command! -bar -complete=customlist,s:connect_complete -nargs=* Connect :FireplaceConnect <args>
autocmd FileType clojure command! -complete=customlist,fireplace#eval_complete -bang -nargs=* Piggieback :call s:piggieback(<q-args>, <bang>0)
augroup END
" Section: Java runner
@ -543,41 +463,6 @@ let s:oneoff.piggieback = s:oneoff.message
" Section: Client
function! s:buffer_path(...) abort
let buffer = a:0 ? a:1 : s:buf()
if getbufvar(buffer, '&buftype') =~# '^no'
return ''
endif
let path = substitute(fnamemodify(bufname(buffer), ':p'), '\C^zipfile:\(.*\)::', '\1/', '')
for dir in fireplace#path(buffer)
if dir !=# '' && path[0 : strlen(dir)-1] ==# dir && path[strlen(dir)] =~# '[\/]'
return path[strlen(dir)+1:-1]
endif
endfor
return ''
endfunction
function! fireplace#ns(...) abort
let buffer = a:0 ? a:1 : s:buf()
if !empty(getbufvar(buffer, 'fireplace_ns'))
return getbufvar(buffer, 'fireplace_ns')
endif
let head = getbufline(buffer, 1, 500)
let blank = '^\s*\%(;.*\)\=$'
call filter(head, 'v:val !~# blank')
let keyword_group = '[A-Za-z0-9_?*!+/=<>.-]'
let lines = join(head[0:49], ' ')
let lines = substitute(lines, '"\%(\\.\|[^"]\)*"\|\\.', '', 'g')
let lines = substitute(lines, '\^\={[^{}]*}', '', '')
let lines = substitute(lines, '\^:'.keyword_group.'\+', '', 'g')
let ns = matchstr(lines, '\C^(\s*\%(in-ns\s*''\|ns\s\+\)\zs'.keyword_group.'\+\ze')
if ns !=# ''
return ns
endif
let path = s:buffer_path(buffer)
return s:to_ns(path ==# '' ? fireplace#client(buffer).user_ns() : path)
endfunction
function! s:buf() abort
if exists('s:input')
return s:input
@ -631,7 +516,7 @@ function! fireplace#platform(...) abort
let portfile = findfile('.nrepl-port', '.;')
if !empty(portfile)
call fireplace#register_port_file(portfile, fnamemodify(portfile, ':p:h'))
call fireplace#register_port_file(portfile, fnamemodify(portfile, ':h'))
endif
silent doautocmd User FireplacePreConnect
@ -651,7 +536,7 @@ function! fireplace#platform(...) abort
endif
endfor
let path = s:path_extract(getbufvar(buf, '&path'))
if !empty(path) && fnamemodify(bufname(buf), ':e') =~# '^clj[cx]\=$'
if !empty(path) && fnamemodify(bufname(buf), ':e') =~# '^cljx\=$'
return extend({'_path': path, 'nr': bufnr(buf)}, s:oneoff)
endif
throw 'Fireplace: :Connect to a REPL or install classpath.vim'
@ -667,7 +552,7 @@ function! fireplace#client(...) abort
if empty(client.piggiebacks)
let result = client.piggieback('')
if has_key(result, 'ex')
throw 'Fireplace: '.result.ex
return result
endif
endif
return client.piggiebacks[0]
@ -802,14 +687,6 @@ function! fireplace#session_eval(expr, ...) abort
endif
endif
try
silent doautocmd User FireplaceEvalPost
catch
echohl ErrorMSG
echomsg v:exception
echohl NONE
endtry
call s:output_response(response)
if get(response, 'ex', '') !=# ''
@ -872,10 +749,6 @@ function! fireplace#evalparse(expr, ...) abort
throw err
endfunction
function! fireplace#query(expr, ...) abort
return fireplace#evalparse(a:expr, a:0 ? a:1 : {})
endfunction
" Section: Quickfix
function! s:qfmassage(line, path) abort
@ -926,7 +799,7 @@ augroup END
" Section: Eval
let fireplace#skip = 'synIDattr(synID(line("."),col("."),1),"name") =~? "comment\\|string\\|char\\|regexp"'
let fireplace#skip = 'synIDattr(synID(line("."),col("."),1),"name") =~? "comment\\|string\\|char"'
function! s:opfunc(type) abort
let sel_save = &selection
@ -963,11 +836,7 @@ function! s:opfunc(type) abort
silent exe "normal! `[v`]y"
endif
redraw
if fireplace#client().user_ns() ==# 'user'
return repeat("\n", line("'<")-1) . repeat(" ", col("'<")-1) . @@
else
return @@
endif
finally
let @@ = reg_save
let &selection = sel_save
@ -1168,7 +1037,7 @@ xnoremap <silent> <Plug>FireplaceMacroExpand :<C-U>call <SID>macroexpandop(visu
nnoremap <silent> <Plug>FireplaceCountMacroExpand :<C-U>call <SID>macroexpandop(v:count)<CR>
nnoremap <silent> <Plug>Fireplace1MacroExpand :<C-U>set opfunc=<SID>macroexpand1op<CR>g@
xnoremap <silent> <Plug>Fireplace1MacroExpand :<C-U>call <SID>macroexpand1op(visualmode())<CR>
nnoremap <silent> <Plug>FireplaceCount1MacroExpand :<C-U>call <SID>macroexpand1op(v:count)<CR>
nnoremap <silent> <Plug>Fireplace1MacroExpand :<C-U>call <SID>macroexpand1op(v:count)<CR>
nnoremap <silent> <Plug>FireplaceEdit :<C-U>set opfunc=<SID>editop<CR>g@
xnoremap <silent> <Plug>FireplaceEdit :<C-U>call <SID>editop(visualmode())<CR>
@ -1199,12 +1068,10 @@ function! s:Last(bang, count) abort
return ''
endfunction
function! s:set_up_eval() abort
function! s:setup_eval() abort
command! -buffer -bang -range=0 -nargs=? -complete=customlist,fireplace#eval_complete Eval :exe s:Eval(<bang>0, <line1>, <line2>, <count>, <q-args>)
command! -buffer -bang -bar -count=1 Last exe s:Last(<bang>0, <count>)
if get(g:, 'fireplace_no_maps') | return | endif
nmap <buffer> cp <Plug>FireplacePrint
nmap <buffer> cpp <Plug>FireplaceCountPrint
@ -1225,7 +1092,7 @@ function! s:set_up_eval() abort
map! <buffer> <C-R>( <Plug>FireplaceRecall
endfunction
function! s:set_up_historical() abort
function! s:setup_historical() abort
setlocal readonly nomodifiable
nnoremap <buffer><silent>q :bdelete<CR>
endfunction
@ -1240,9 +1107,9 @@ endfunction
augroup fireplace_eval
autocmd!
autocmd FileType clojure call s:set_up_eval()
autocmd FileType clojure call s:setup_eval()
autocmd BufReadPost * if has_key(s:qffiles, expand('<amatch>:p')) |
\ call s:set_up_historical() |
\ call s:setup_historical() |
\ endif
autocmd CmdWinEnter @ if exists('s:input') | call s:cmdwinenter() | endif
autocmd CmdWinLeave @ if exists('s:input') | call s:cmdwinleave() | endif
@ -1270,16 +1137,14 @@ function! s:Require(bang, echo, ns) abort
endtry
endfunction
function! s:set_up_require() abort
function! s:setup_require() abort
command! -buffer -bar -bang -complete=customlist,fireplace#ns_complete -nargs=? Require :exe s:Require(<bang>0, 1, <q-args>)
if get(g:, 'fireplace_no_maps') | return | endif
nnoremap <silent><buffer> cpr :<C-R>=expand('%:e') ==# 'cljs' ? 'Require' : 'RunTests'<CR><CR>
nnoremap <silent><buffer> cpr :if expand('%:e') ==# 'cljs'<Bar>Require<Bar>else<Bar>RunTests<Bar>endif<CR>
endfunction
augroup fireplace_require
autocmd!
autocmd FileType clojure call s:set_up_require()
autocmd FileType clojure call s:setup_require()
augroup END
" Section: Go to source
@ -1289,8 +1154,6 @@ function! fireplace#info(symbol) abort
let response = fireplace#message({'op': 'info', 'symbol': a:symbol})[0]
if type(get(response, 'value')) == type({})
return response.value
elseif has_key(response, 'file')
return response
endif
endif
let cmd =
@ -1349,22 +1212,23 @@ nnoremap <silent> <Plug>FireplaceDjump :<C-U>exe <SID>Edit('edit', expand('<cwor
nnoremap <silent> <Plug>FireplaceDsplit :<C-U>exe <SID>Edit('split', expand('<cword>'))<CR>
nnoremap <silent> <Plug>FireplaceDtabjump :<C-U>exe <SID>Edit('tabedit', expand('<cword>'))<CR>
function! s:set_up_source() abort
setlocal define=^\\s*(def\\w*
command! -bar -buffer -nargs=1 -complete=customlist,fireplace#eval_complete Djump :exe s:Edit('edit', <q-args>)
command! -bar -buffer -nargs=1 -complete=customlist,fireplace#eval_complete Dsplit :exe s:Edit('split', <q-args>)
if get(g:, 'fireplace_no_maps') | return | endif
nmap <buffer> [<C-D> <Plug>FireplaceDjump
nmap <buffer> ]<C-D> <Plug>FireplaceDjump
nmap <buffer> <C-W><C-D> <Plug>FireplaceDsplit
nmap <buffer> <C-W>d <Plug>FireplaceDsplit
nmap <buffer> <C-W>gd <Plug>FireplaceDtabjump
endfunction
augroup fireplace_source
autocmd!
autocmd FileType clojure call s:set_up_source()
autocmd FileType clojure setlocal includeexpr=tr(v:fname,'.-','/_')
autocmd FileType clojure
\ if expand('%:e') ==# 'cljs' |
\ setlocal suffixesadd=.cljs,.cljx,.clj,.java |
\ else |
\ setlocal suffixesadd=.clj,.cljx,.cljs,.java |
\ endif
autocmd FileType clojure setlocal define=^\\s*(def\\w*
autocmd FileType clojure command! -bar -buffer -nargs=1 -complete=customlist,fireplace#eval_complete Djump :exe s:Edit('edit', <q-args>)
autocmd FileType clojure command! -bar -buffer -nargs=1 -complete=customlist,fireplace#eval_complete Dsplit :exe s:Edit('split', <q-args>)
autocmd FileType clojure nmap <buffer> [<C-D> <Plug>FireplaceDjump
autocmd FileType clojure nmap <buffer> ]<C-D> <Plug>FireplaceDjump
autocmd FileType clojure nmap <buffer> <C-W><C-D> <Plug>FireplaceDsplit
autocmd FileType clojure nmap <buffer> <C-W>d <Plug>FireplaceDsplit
autocmd FileType clojure nmap <buffer> <C-W>gd <Plug>FireplaceDtabjump
augroup END
" Section: Go to file
@ -1374,7 +1238,7 @@ function! fireplace#findfile(path) abort
if a:path !~# '/'
let path = tr(a:path, '.-', '/_')
else
let path = substitute(a:path, '^/', '', '')
let path = substitute(a:path, '^/', '')
endif
let resource = fireplace#findresource(path, fireplace#path(), 0, &suffixesadd)
if !empty(resource)
@ -1387,171 +1251,74 @@ function! fireplace#findfile(path) abort
return ''
endfunction
let s:iskeyword = '[[:alnum:]_=?!#$%&*+|./<>:-]'
let s:token = '^\%(#"\%(\\\@<!\%(\\\\\)*\\"\|[^"]\)*"\|"\%(\\.\|[^"]\)*"\|[[:space:],]\+\|\%(;\|#!\)[^'."\n".']*\|\~@\|#[[:punct:]]\|'.s:iskeyword.'\+\|\\\%(space\|tab\|newline\|return\|.\)\|.\)'
function! s:read_token(str, pos) abort
let pos = a:pos
let match = ' '
while match =~# '^[[:space:],;]'
let match = matchstr(a:str, s:token, pos)
let pos += len(match)
endwhile
if empty(match)
throw 'fireplace: Clojure parse error'
endif
return [match, pos]
endfunction
function! s:read(str, pos) abort
let [token, pos] = s:read_token(a:str, a:pos)
if token =~# '^#\=[[{(]'
let list = []
while index([')', ']', '}', ''], get(list, -1)) < 0
unlet token
let [token, pos] = s:read(a:str, pos)
call add(list, token)
endwhile
call remove(list, -1)
return [list, pos]
elseif token ==# '#_'
let pos = s:read(a:str, pos)[1]
return s:read(a:str, pos)
else
return [token, pos]
endif
endfunction
function! s:ns(...) abort
let buffer = a:0 ? a:1 : s:buf()
let head = getbufline(buffer, 1, 1000)
let blank = '^\s*\%(;.*\)\=$'
call filter(head, 'v:val !~# blank')
let keyword_group = '[A-Za-z0-9_?*!+/=<>.-]'
let lines = join(head, "\n")
let match = matchstr(lines, '\C^(\s*ns\s\+.*')
if len(match)
function! s:GF(cmd, file) abort
if a:file =~# '^[^/]*/[^/.]*$' && a:file =~# '^\k\+$'
let [file, jump] = split(a:file, "/")
if file !~# '\.'
try
return s:read(match, 0)[0]
catch /^fireplace: Clojure parse error$/
let file = fireplace#evalparse('((ns-aliases *ns*) '.s:qsym(file).' '.s:qsym(file).')')
catch /^Clojure:/
endtry
endif
return []
endfunction
function! fireplace#resolve_alias(name) abort
if a:name =~# '\.'
return a:name
endif
let _ = {}
for refs in filter(copy(s:ns()), 'type(v:val) == type([])')
if a:name =~# '^\u' && get(refs, 0) is# ':import'
for _.ref in refs
if type(_.ref) == type([]) && index(_.ref, a:name) > 0
return _.ref[0] . '.' . a:name
elseif type(_.ref) == type('') && _.ref =~# '\.'.a:name.'$'
return _.ref
endif
endfor
endif
if get(refs, 0) is# ':require'
for _.ref in refs
if type(_.ref) == type([])
let i = index(_.ref, ':as')
if i > 0 && get(_.ref, i+1) ==# a:name
return _.ref[0]
endif
for nref in filter(copy(_.ref), 'type(v:val) == type([])')
let i = index(nref, ':as')
if i > 0 && get(nref, i+1) ==# a:name
return _.ref[0].'.'.nref[0]
endif
endfor
endif
endfor
endif
endfor
return a:name
endfunction
function! fireplace#cfile() abort
let file = expand('<cfile>')
if file =~# '^\w[[:alnum:]_/]*$' &&
\ synIDattr(synID(line("."),col("."),1),"name") =~# 'String'
let file = substitute(expand('%:p'), '[^\/:]*$', '', '').file
elseif file =~# '^[^/]*/[^/.]*$' && file =~# '^\k\+$'
let [file, jump] = split(file, "/")
let file = fireplace#resolve_alias(file)
if file !~# '\.' && fireplace#op_available('info')
let res = fireplace#message({'op': 'info', 'symbol': file})
let file = get(get(res, 0, {}), 'ns', file)
endif
let file = tr(file, '.-', '/_')
elseif file =~# '^\w[[:alnum:].-]*$'
let file = tr(fireplace#resolve_alias(file), '.-', '/_')
endif
if exists('jump')
return '+sil!dj\ ' . jump . ' ' . fnameescape(file)
else
return fnameescape(file)
let file = a:file
endif
endfunction
function! s:Find(find, edit) abort
let cfile = fireplace#cfile()
let prefix = matchstr(cfile, '^\%(+\%(\\.\|\S\)*\s\+\)')
let file = fireplace#findfile(expand(strpart(cfile, len(prefix))))
if file =~# '^zipfile:'
let setpath = 'let\ &l:path=getbufvar('.bufnr('').",'&path')"
if prefix =~# '^+[^+]'
let prefix = substitute(prefix, '+', '\="+".setpath."\\|"', '')
else
let prefix = '+'.setpath.' '.prefix
endif
endif
if len(file)
return (len(a:edit) ? a:edit . ' ' : '') . prefix . fnameescape(file)
else
return len(a:find) ? a:find . ' ' . cfile : "\<C-R>\<C-P>"
endif
endfunction
nnoremap <silent> <Plug>FireplaceEditFile :<C-U>exe <SID>Find('find','edit')<CR>
nnoremap <silent> <Plug>FireplaceSplitFile :<C-U>exe <SID>Find('sfind','split')<CR>
nnoremap <silent> <Plug>FireplaceTabeditFile :<C-U>exe <SID>Find('tabfind','tabedit')<CR>
function! s:set_up_go_to_file() abort
if expand('%:e') ==# 'cljs'
setlocal suffixesadd=.cljs,.cljc,.cljx,.clj,.java
else
setlocal suffixesadd=.clj,.cljc,.cljx,.cljs,.java
endif
cmap <buffer><script><expr> <Plug><cfile> substitute(fireplace#cfile(),'^$',"\022\006",'')
cmap <buffer><script><expr> <Plug><cpath> <SID>Find('','')
if get(g:, 'fireplace_no_maps') | return | endif
cmap <buffer> <C-R><C-F> <Plug><cfile>
cmap <buffer> <C-R><C-P> <Plug><cpath>
if empty(mapcheck('gf', 'n'))
nmap <buffer> gf <Plug>FireplaceEditFile
endif
if empty(mapcheck('<C-W>f', 'n'))
nmap <buffer> <C-W>f <Plug>FireplaceSplitFile
endif
if empty(mapcheck('<C-W><C-F>', 'n'))
nmap <buffer> <C-W><C-F> <Plug>FireplaceSplitFile
endif
if empty(mapcheck('<C-W>gf', 'n'))
nmap <buffer> <C-W>gf <Plug>FireplaceTabeditFile
let file = fireplace#findfile(file)
if file ==# ''
let v:errmsg = "Couldn't find file for ".a:file
return 'echoerr v:errmsg'
endif
return a:cmd .
\ (exists('jump') ? ' +sil!\ djump\ ' . jump : '') .
\ ' ' . fnameescape(file) .
\ '| let &l:path = ' . string(&l:path)
endfunction
augroup fireplace_go_to_file
autocmd!
autocmd FileType clojure call s:set_up_go_to_file()
autocmd FileType clojure nnoremap <silent><buffer> gf :<C-U>exe <SID>GF('edit', expand('<cfile>'))<CR>
autocmd FileType clojure nnoremap <silent><buffer> <C-W>f :<C-U>exe <SID>GF('split', expand('<cfile>'))<CR>
autocmd FileType clojure nnoremap <silent><buffer> <C-W><C-F> :<C-U>exe <SID>GF('split', expand('<cfile>'))<CR>
autocmd FileType clojure nnoremap <silent><buffer> <C-W>gf :<C-U>exe <SID>GF('tabedit', expand('<cfile>'))<CR>
augroup END
" Section: Documentation
function! s:buffer_path(...) abort
let buffer = a:0 ? a:1 : s:buf()
if getbufvar(buffer, '&buftype') =~# '^no'
return ''
endif
let path = substitute(fnamemodify(bufname(buffer), ':p'), '\C^zipfile:\(.*\)::', '\1/', '')
for dir in fireplace#path(buffer)
if dir !=# '' && path[0 : strlen(dir)-1] ==# dir && path[strlen(dir)] =~# '[\/]'
return path[strlen(dir)+1:-1]
endif
endfor
return ''
endfunction
function! fireplace#ns(...) abort
let buffer = a:0 ? a:1 : s:buf()
if !empty(getbufvar(buffer, 'fireplace_ns'))
return getbufvar(buffer, 'fireplace_ns')
endif
let head = getbufline(buffer, 1, 500)
let blank = '^\s*\%(;.*\)\=$'
call filter(head, 'v:val !~# blank')
let keyword_group = '[A-Za-z0-9_?*!+/=<>.-]'
let lines = join(head[0:49], ' ')
let lines = substitute(lines, '"\%(\\.\|[^"]\)*"\|\\.', '', 'g')
let lines = substitute(lines, '\^\={[^{}]*}', '', '')
let lines = substitute(lines, '\^:'.keyword_group.'\+', '', 'g')
let ns = matchstr(lines, '\C^(\s*\%(in-ns\s*''\|ns\s\+\)\zs'.keyword_group.'\+\ze')
if ns !=# ''
return ns
endif
let path = s:buffer_path(buffer)
return s:to_ns(path ==# '' ? fireplace#client(buffer).user_ns() : path)
endfunction
function! s:Lookup(ns, macro, arg) abort
try
let response = s:eval('('.a:ns.'/'.a:macro.' '.a:arg.')', {'session': 0})
@ -1594,7 +1361,7 @@ endfunction
function! s:K() abort
let word = expand('<cword>')
let java_candidate = matchstr(word, '^\%(\w\+\.\)*\u\l[[:alnum:]$]*\ze\%(\.\|\/\w\+\)\=$')
let java_candidate = matchstr(word, '^\%(\w\+\.\)*\u\l\w*\ze\%(\.\|\/\w\+\)\=$')
if java_candidate !=# ''
return 'Javadoc '.java_candidate
else
@ -1605,37 +1372,30 @@ endfunction
nnoremap <Plug>FireplaceK :<C-R>=<SID>K()<CR><CR>
nnoremap <Plug>FireplaceSource :Source <C-R><C-W><CR>
function! s:set_up_doc() abort
command! -buffer -nargs=1 FindDoc :exe s:Lookup('clojure.repl', 'find-doc', printf('#"%s"', <q-args>))
command! -buffer -bar -nargs=1 Javadoc :exe s:Lookup('clojure.java.javadoc', 'javadoc', <q-args>)
command! -buffer -bar -nargs=1 -complete=customlist,fireplace#eval_complete Doc :exe s:Doc(<q-args>)
command! -buffer -bar -nargs=1 -complete=customlist,fireplace#eval_complete Source :exe s:Lookup('clojure.repl', 'source', <q-args>)
setlocal keywordprg=:Doc
if get(g:, 'fireplace_no_maps') | return | endif
if empty(mapcheck('K', 'n'))
nmap <buffer> K <Plug>FireplaceK
endif
nmap <buffer> [d <Plug>FireplaceSource
nmap <buffer> ]d <Plug>FireplaceSource
endfunction
augroup fireplace_doc
autocmd!
autocmd FileType clojure call s:set_up_doc()
autocmd FileType clojure setlocal keywordprg=:Doc |
\ if empty(mapcheck('K', 'n')) |
\ nmap <buffer> K <Plug>FireplaceK|
\ endif
autocmd FileType clojure nmap <buffer> [d <Plug>FireplaceSource
autocmd FileType clojure nmap <buffer> ]d <Plug>FireplaceSource
autocmd FileType clojure command! -buffer -nargs=1 FindDoc :exe s:Lookup('clojure.repl', 'find-doc', printf('#"%s"', <q-args>))
autocmd FileType clojure command! -buffer -bar -nargs=1 Javadoc :exe s:Lookup('clojure.java.javadoc', 'javadoc', <q-args>)
autocmd FileType clojure command! -buffer -bar -nargs=1 -complete=customlist,fireplace#eval_complete Doc :exe s:Doc(<q-args>)
autocmd FileType clojure command! -buffer -bar -nargs=1 -complete=customlist,fireplace#eval_complete Source :exe s:Lookup('clojure.repl', 'source', <q-args>)
augroup END
" Section: Tests
function! fireplace#capture_test_run(expr, ...) abort
let expr = '(try'
\ . ' (require ''clojure.test)'
let expr = '(require ''clojure.test) '
\ . '(try '
\ . '(binding [clojure.test/report (fn [m]'
\ . ' (case (:type m)'
\ . ' (:fail :error)'
\ . ' (let [{file :file line :line test :name} (meta (last clojure.test/*testing-vars*))]'
\ . ' (clojure.test/with-test-out'
\ . ' (clojure.test/inc-report-counter (:type m))'
\ . ' (println (clojure.string/join "\t" [file line (name (:type m)) test]))'
\ . ' (when (seq clojure.test/*testing-contexts*) (println (clojure.test/testing-contexts-str)))'
\ . ' (when-let [message (:message m)] (println message))'
@ -1652,7 +1412,7 @@ function! fireplace#capture_test_run(expr, ...) abort
call setqflist(fireplace#quickfix_for(get(response, 'stacktrace', [])))
return s:output_response(response)
endif
for line in split(response.out, "\r\\=\n")
for line in split(response.out, "\n")
if line =~# '\t.*\t.*\t'
let entry = {'text': line}
let [resource, lnum, type, name] = split(line, "\t", 1)
@ -1686,57 +1446,27 @@ function! fireplace#capture_test_run(expr, ...) abort
endfor
endfunction
function! s:RunTests(bang, count, ...) abort
function! s:RunTests(bang, ...) abort
if &autowrite || &autowriteall
silent! wall
endif
if a:count < 0
let pre = ''
if a:0
let expr = ['(clojure.test/run-all-tests #"'.join(a:000, '|').'")']
if a:bang && a:0
let expr = '(clojure.test/run-all-tests #"'.join(a:000, '|').'")'
elseif a:bang
let expr = '(clojure.test/run-all-tests)'
else
let expr = ['(clojure.test/run-all-tests)']
let reqs = map(copy(a:000), '"''".v:val')
let pre = '(clojure.core/require '.join(empty(a:000) ? ["'".fireplace#ns()] : reqs, ' ').' :reload) '
let expr = join(['(clojure.test/run-tests'] + reqs, ' ').')'
endif
else
if a:0 && a:000 !=# [fireplace#ns()]
let args = a:000
else
let args = [fireplace#ns()]
if a:count
let pattern = '^\s*(def\k*\s\+\(\h\k*\)'
let line = search(pattern, 'bcWn')
if line
let args[0] .= '/' . matchlist(getline(line), pattern)[1]
endif
endif
endif
let reqs = map(copy(args), '"''".v:val')
let pre = '(clojure.core/require '.substitute(join(reqs, ' '), '/\k\+', '', 'g').' :reload) '
let expr = []
let vars = filter(copy(reqs), 'v:val =~# "/"')
let nses = filter(copy(reqs), 'v:val !~# "/"')
if len(vars) == 1
call add(expr, '(clojure.test/test-vars [#' . vars[0] . '])')
elseif !empty(vars)
call add(expr, join(['(clojure.test/test-vars'] + map(vars, '"#".v:val'), ' ').')')
endif
if !empty(nses)
call add(expr, join(['(clojure.test/run-tests'] + nses, ' ').')')
endif
endif
call fireplace#capture_test_run(join(expr, ' '), pre)
echo join(expr, ' ')
call fireplace#capture_test_run(expr, pre)
echo expr
endfunction
function! s:set_up_tests() abort
command! -buffer -bar -bang -range=0 -nargs=*
\ -complete=customlist,fireplace#ns_complete RunTests
\ call s:RunTests(<bang>0, <line1> == 0 ? -1 : <count>, <f-args>)
command! -buffer -bang -nargs=* RunAllTests
\ call s:RunTests(<bang>0, -1, <f-args>)
endfunction
augroup fireplace_tests
augroup fireplace_command
autocmd!
autocmd FileType clojure call s:set_up_tests()
autocmd FileType clojure command! -buffer -bar -bang -nargs=*
\ -complete=customlist,fireplace#ns_complete RunTests
\ call s:RunTests(<bang>0, <f-args>)
augroup END

View File

@ -1,13 +1,13 @@
" Location: plugin/fireplace/zip.vim
" fireplace/zip.vim: zip.vim monkey patch to allow access from quickfix
" Maintainer: Tim Pope <http://tpo.pe>
if exists("g:loaded_zip") || &cp || v:version >= 704
if exists("g:loaded_zip") || &cp
finish
endif
runtime! autoload/zip.vim
" Patched to allow loading from the quickfix list. The version that ships
" with Vim 7.4 already has this change.
" Copied and pasted verbatim from autoload/zip.vim.
fun! zip#Read(fname,mode)
" call Dfunc("zip#Read(fname<".a:fname.">,mode=".a:mode.")")