author |
Steve Losh <steve@stevelosh.com> |
date |
Fri, 18 Aug 2017 12:10:38 -0400 |
parents |
c3167738abd5 |
children |
(none) |
" TODO:
" fix showmode awfulness
" Disassembly mapping
" error handling
" multi-packet messages
"
if !exists("g:ooze_connection")
let g:ooze_connection = 0
endif
let s:pending = ''
function! s:IsString(a) " {{{
return type(a:a) == 1
endfunction " }}}
function! s:GetString(msg, key, extra) " {{{
let val = get(a:msg, a:key)
if s:IsString(val)
return val . a:extra
else
return ''
endif
endfunction " }}}
let g:ooze_scratch_buffer_name = '__OozeScratch__'
let g:ooze_traceback_buffer_name = '__OozeTraceback__'
function! s:OpenOrGotoBuffer(name) " {{{
let existing_buffer = bufnr(a:name)
if existing_buffer == -1
" The buffer doesn't exist at all.
" Split and edit.
wincmd s
execute "edit " . a:name
else
" The buffer exists, now we look for a window.
let existing_window = bufwinnr(existing_buffer)
if existing_window == -1
" The window doesn't exist. Split and show the (existing) buffer.
execute "split +buffer" . existing_buffer
else
" The window exists. Are we already in it?
let current_window = winnr()
if current_window != existing_window
" We're not in it. Jump to it.
execute existing_window . "wincmd w"
else
" We're already where we need to be. Noop.
endif
endif
endif
endfunction " }}}
function! s:OpenOozeScratch(contents) " {{{
if bufname('%') != g:ooze_scratch_buffer_name
" Preserve the current window's package (lame hack)
if exists("b:ooze_buffer_package")
let package = b:ooze_buffer_package
else
let package = ""
endif
call s:OpenOrGotoBuffer(g:ooze_scratch_buffer_name)
if package != ""
let b:ooze_buffer_package = package
endif
endif
set filetype=lisp
setlocal foldlevel=99
setlocal buftype=nofile
setlocal bufhidden=hide
setlocal noswapfile
setlocal buflisted
" setlocal noreadonly
normal! gg"_dG
call append(0, a:contents)
normal! gg=G
" setlocal readonly
endfunction " }}}
function! s:DumpTraceback(frames) " {{{
let current = bufnr('%')
let bn = bufnr(g:ooze_traceback_buffer_name)
if bn == -1
execute "edit " . g:ooze_traceback_buffer_name
setlocal buftype=nofile
setlocal bufhidden=hide
setlocal noswapfile
setlocal buflisted
else
execute "buffer " . bn
endif
normal! gg"_dG
for frame in a:frames
let call_form = frame[0]
let file = frame[1]
let line = frame[2]
call append(line('$'), call_form . "\t" . file . "\t" . line)
endfor
normal! gg"_dd
set errorformat=%m\ %f\ %l,%m\ %f\
execute "cbuffer"
execute "buffer " . current
return 1
endfunction " }}}
function! s:HandleMacroexpand(msg) " {{{
let moutput = s:GetString(a:msg, 'macroexpand-1', "")
call s:OpenOozeScratch(split(moutput, "\n"))
endfunction " }}}
function! s:HandleStackTrace(msg) " {{{
call s:DumpTraceback(get(a:msg, 'stack-trace'))
let output = ''
let output .= s:GetString(a:msg, 'error', "\n\n")
let output .= s:GetString(a:msg, 'original', "\n\n")
if output != ''
echo substitute(output, '\n\+$', '', '')
endif
copen
endfunction " }}}
function! s:HandleMessage(msg) " {{{
if has_key(a:msg, 'macroexpand-1')
return s:HandleMacroexpand(a:msg)
endif
if has_key(a:msg, 'stack-trace')
return s:HandleStackTrace(a:msg)
endif
let output = ''
let output .= s:GetString(a:msg, 'stdout', "")
let output .= s:GetString(a:msg, 'stderr', "")
let output .= s:GetString(a:msg, 'value', "")
let output .= s:GetString(a:msg, 'function-arglist', "\n\n")
let output .= s:GetString(a:msg, 'function-docstring', "\n")
if output != ''
echo substitute(output, '\n\+$', '', '')
endif
endfunction " }}}
function! s:HandleData(data) " {{{
let s:pending .= a:data
try
let messages = bencode#BdecodeAll(s:pending)
catch /bencode.*truncated/
return
endtry
let s:pending = ''
for msg in messages
call s:HandleMessage(msg)
endfor
endfunction " }}}
" NeoVim job-handling {{{
silent! function s:JobHandler(job_id, data, event) " {{{
if a:event == 'stdout'
call s:HandleData(join(a:data, "\n"))
elseif a:event == 'stderr'
1
else
1
endif
endfunction " }}}
let s:callbacks = {
\ 'on_stdout': function('s:JobHandler'),
\ 'on_stderr': function('s:JobHandler'),
\ 'on_exit': function('s:JobHandler')
\ }
function! OozeSendMessage(msg)
if !g:ooze_connection
throw "Not connected!"
endif
try
call jobsend(g:ooze_connection, bencode#Bencode(a:msg))
catch /E900/
echo "Ooze connection died!"
let g:ooze_connection = 0
endtry
endfunction!
" }}}
function! s:FindPackage() " {{{
if !exists("b:ooze_buffer_package")
let view = winsaveview()
let result = ""
call cursor(1, 1)
if search('\v^\(in-package>\s*(\n\s*)?\k', 'c', 40)
normal! W
execute "normal v\<plug>(sexp_inner_element)"
let old_z = @z
normal! "zy
let result = @z
let b:ooze_buffer_package = result
let @z = old_z
endif
call winrestview(view)
return result
else
return b:ooze_buffer_package
endif
return ""
endfunction " }}}
function! OozeDisconnect() " {{{
if g:ooze_connection
call jobstop(g:ooze_connection)
let g:ooze_connection = 0
endif
endfunction " }}}
function! OozeConnectToPort(port) " {{{
if g:ooze_connection
call OozeDisconnect()
endif
let g:ooze_connection = jobstart(['nc', 'localhost', a:port], s:callbacks)
endfunction " }}}
function! OozeConnect() " {{{
call OozeConnectToPort('8675')
endfunction " }}}
function! OozeMacroexpand(form) " {{{
let msg = {"op": "macroexpand", "form": a:form}
let package = s:FindPackage()
if package != ""
let msg["in-package"] = package
endif
call OozeSendMessage(msg)
endfunction " }}}
function! OozeMacroexpandSelection() " {{{
let z = @z
normal! gv"zy
call OozeMacroexpand(@z)
let @z = z
endfunction " }}}
function! OozeDocument(symbol) " {{{
let msg = {"op": "documentation", "symbol": a:symbol}
let package = s:FindPackage()
if package != ""
let msg["in-package"] = package
endif
call OozeSendMessage(msg)
endfunction " }}}
function! OozeDocumentSelection() " {{{
let z = @z
normal! gv"zy
call OozeDocument(@z)
let @z = z
endfunction " }}}
function! OozeDocumentFormHead() " {{{
let view = winsaveview()
execute "normal v\<plug>(sexp_inner_list)o\<plug>(sexp_inner_element)"
call OozeDocumentSelection()
call winrestview(view)
endfunction " }}}
function! OozeArglist(symbol) " {{{
if !g:ooze_connection
return
endif
let msg = {"op": "arglist", "symbol": a:symbol}
let package = s:FindPackage()
if package != ""
let msg["in-package"] = package
endif
set noshowmode
call OozeSendMessage(msg)
endfunction " }}}
function! OozeArglistSelection() " {{{
let z = @z
normal! gv"zy
call OozeArglist(@z)
let @z = z
endfunction " }}}
function! OozeArglistFormHead() " {{{
let view = winsaveview()
let syntaxElement = synIDattr(synIDtrans(synID(line("."),col("."),1)),"name")
if syntaxElement == "Comment" || syntaxElement == "String"
" bail if we're in a comment or string
" TODO: make this suck less
else
execute "normal v\<plug>(sexp_inner_list)o\<plug>(sexp_inner_element)"
call OozeArglistSelection()
endif
call winrestview(view)
endfunction " }}}
function! OozeEval(code) " {{{
let msg = {"op": "eval", "code": a:code}
let package = s:FindPackage()
if package != ""
let msg["in-package"] = package
endif
call OozeSendMessage(msg)
endfunction " }}}
function! OozeEvalSelection() " {{{
let z = @z
normal! gv"zy
call OozeEval(@z)
let @z = z
endfunction " }}}
function! OozeLoad(path) " {{{
let msg = {"op": "load-file", "path": a:path}
call OozeSendMessage(msg)
endfunction " }}}
function! OozeLoadCurrent() " {{{
call OozeLoad(expand('%:p'))
endfunction " }}}
function! OozeSelectTopLevelForm() " {{{
execute "normal v\<Plug>(sexp_outer_top_list)"
endfunction " }}}
function! OozeHyperspec(symbol) " {{{
vnew
call termopen('clhs ' . a:symbol)
normal! a
endfunction " }}}
function! OozeHyperspecForm() " {{{
let view = winsaveview()
let z = @z
execute "normal v\<plug>(sexp_inner_element)o\<plug>(sexp_inner_element)"
normal! gv"zy
call OozeHyperspec(@z)
let @z = z
call winrestview(view)
endfunction " }}}
function! OozeSpaceMap() " {{{
if exists("b:ooze_vblock") || mode() == "R"
" Don't fuck with visual block mode or replace mode
return "\<space>"
else
return "\<space>\<esc>:\<c-u>call OozeArglistFormHead()\<cr>a"
endif
endfunction " }}}
function! OozeTrackVblock() " {{{
" end my life
let b:ooze_vblock = 1
return "I"
endfunction " }}}
function! OozeUntrackVblock() " {{{
" end my life
if exists("b:ooze_vblock")
unlet b:ooze_vblock
endif
endfunction " }}}
function! OozeMapKeys() " {{{
" [C]onnect and [K]ill
nnoremap <buffer> <localleader>C :call OozeConnect()<cr>
nnoremap <buffer> <localleader>K :call OozeDisconnect()<cr>
" [h]yperspec
nnoremap <buffer> <localleader>h :call OozeHyperspecForm()<cr>
nnoremap <buffer> <localleader>H :call OozeHyperspec(input("? "))<cr>
" [e]val ([f]orm)
nnoremap <buffer> <localleader>E :call OozeEval(input("? "))<cr>
vnoremap <buffer> <localleader>e :<c-u>call OozeEvalSelection()<cr>
nnoremap <buffer> <localleader>e mz:call OozeSelectTopLevelForm()<cr>:<c-u>call OozeEvalSelection()<cr>`z
nnoremap <buffer> <localleader>f mzvab:<c-u>call OozeEvalSelection()<cr>`z
" [M]anual and [D]ocument
nnoremap <buffer> <localleader>D :call OozeDocument(input("? "))<cr>
inoremap <buffer> <silent> <c-d> <c-o>:<c-u>call OozeDocumentFormHead()<cr>
nnoremap <buffer> M mzviw:<c-u>call OozeDocumentSelection()<cr>`z
" [m]acroexpand
nnoremap <buffer> <localleader>M :call OozeMacroexpand(input("? "))<cr>
nnoremap <buffer> <localleader>m mzvab:<c-u>call OozeMacroexpandSelection()<cr>`z
" [r]eload
nnoremap <buffer> <localleader>r :call OozeLoadCurrent()<cr>
" magic arglist shit
inoremap <buffer> <silent> <expr> <space> OozeSpaceMap()
vnoremap <buffer> <silent> <expr> I OozeTrackVblock()
augroup ooze_vblock
au!
autocmd InsertLeave <buffer> call OozeUntrackVblock()
augroup END
endfunction " }}}
augroup ooze_dev " {{{
au!
autocmd BufWritePost ooze.vim source %
augroup END " }}}
augroup ooze_showmode_save
au!
" We save showmode around insert mode because the arglist command needs
" to disable it.
au InsertEnter * :let g:ooze_save_showmode=&showmode
au InsertLeave * :let &showmode=g:ooze_save_showmode
au InsertLeave * :let &showmode=g:ooze_save_showmode
augroup END