Skip to content

Commit

Permalink
Merge branch 'PeterRincker'
Browse files Browse the repository at this point in the history
  • Loading branch information
jpalardy committed Apr 19, 2012
2 parents df172a7 + 83bd0b0 commit fd2e84c
Show file tree
Hide file tree
Showing 2 changed files with 269 additions and 37 deletions.
150 changes: 150 additions & 0 deletions doc/slime.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
*slime.txt* Grab some text and "send" it to a GNU Screen / tmux session.

Author: Jonathan Palardy *slime-author*
License: Same terms as Vim itself (see |license|)

This plugin is only available if 'compatible' is not set.

==============================================================================
*slime*
Grab some text and "send" it to a GNU Screen / tmux session.

VIM ---(text)---> screen / tmux~

Presumably, your screen contains something interesting like, say, a Clojure
REPL. But if it can receive typed text, it can receive it from vim-slime.

The reason you're doing this? Because you want the benefits of a REPL and the
benefits of using Vim (familiar environment, syntax highlighting, persistence,
...).

1. Usage |slime-usage|
2. Screen Configuration |slime-screen|
3. Tmux Configuration |slime-tmux|
4. Slime Configuration |slime-configuration|
5. Slime Requirements |slime-requirements|

==============================================================================
1. Slime Usage *slime-usage*

*CTRL-C_CTRL-C* *<c-c><c-c>*
<c-c><c-c> Send the current paragraph text to screen/tmux. Slime
will prompt for configuration if slime is not
configured for the current buffer.

*v_CTRL-C_CTRL-C* *v_<c-c><c-c>*
{Visual}<c-c><c-c> Send highlighted text to screen/tmux.

*CTRL-C_v* *<c-c>v*
*:SlimeConfig*
<c-c>v Setup slime to use screen or tmux. You will be
:SlimeConfig prompted for information regarding how to target
screen or tmux. See |slime-screen| or |slime-tmux| for
more information.

*:SlimeSend*
:<range>SlimeSend Send a [range] of lines to screen or tmux. If no range
is provided the current line is sent.


==============================================================================
2. Screen Configuration *slime-screen*

By default, GNU Screen is assumed, you don't have to do anything. If you want
to be explicit, you can add this line to your |.vimrc|:
>
let g:slime_target = "screen"
<
When you invoke vim-slime for the first time (see below), you will be prompted
for more configuration.

Screen session name~

This is what you put in the -S flag, or one of the line of "screen -ls".

Screen window name~

This is the window number or name, zero-based.

==============================================================================
3. Tmux Configuration *slime-tmux*

Tmux is not the default, to use it you will have to add this line to your
|.vimrc|:
>
let g:slime_target = "tmux"
<
When you invoke vim-slime for the first time (see below), you will be prompted
for more configuration.

Tmux socket name~

This is what you put in the -L flag, it will be "default" if you didn't put
anything.

Tmux target pane~

A tmux pane can be targeted with any of the following values:
- ":" means current window, current pane (a reasonable default)
- ":i" means the ith window, current pane
- ":i.j" means the ith window, jth pane
- "%i" means i refers the pane's unique id

To get a list of all the available pane execute the following:
>
tmux list-panes -a
<

==============================================================================
4. Slime Configuration *slime-configuration*

Global Variables~
*g:slime_target*
g:slime_target Set to either "screen" (default) or "tmux".

*g:slime_no_mappings*
g:slime_no_mappings Set to non zero value to disable the default mappings.

Mappings~

Slime's default mappings can be overridden by setting up mappings in your
|.vimrc| like so:
>
xmap <leader>s <Plug>SlimeRegionSend
nmap <leader>s <Plug>SlimeParagraphSend
<

The following special plugin mappings are provided by slime:

Used by the default mappings:
<Plug>SlimeRegionSend Send {visual} text. Use |xmap|.
<Plug>SlimeParagraphSend Send a paragraph. Use |nmap|.
<Plug>SlimeConfig Call |:SlimeConfig|. Use |nmap|.

Optional mappings:
<Plug>SlimeLineSend Send {count} line(s). Use |nmap|.
<Plug>SlimeMotionSend Send {motion}. Use |nmap|.

Disabling a mapping is as simple as creating a mapping that does not exist,
for example:
>
nmap <Plug>NoSlimeParagraphSend <Plug>SlimeParagraphSend
<

To use vim like mappings instead of emacs keybindings use the following:
>
let g:slime_no_mappings = 1
xmap <leader>s <Plug>SlimeRegionSend
nmap <leader>s <Plug>SlimeMotionSend
nmap <leader>ss <Plug>SlimeLineSend
<

==============================================================================
5. Slime Requirements *slime-requirements*

Slime requires either screen or tmux to be available and executable. Awk is
used for completion of screen sessions.

==============================================================================

vim:tw=78:ts=8:ft=help:norl:
156 changes: 119 additions & 37 deletions plugin/slime.vim
Original file line number Diff line number Diff line change
@@ -1,52 +1,35 @@
if exists('g:loaded_slime') || &cp || v:version < 700
finish
endif
let g:loaded_slime = 1

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Configuration
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

if !exists('g:slime_send_key')
let g:slime_send_key = '<C-c><C-c>'
endif

if !exists('g:slime_config_key')
let g:slime_config_key = '<C-c>v'
endif

if !exists("g:slime_target")
let g:slime_target = "screen"
end

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Setup key bindings
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
execute 'vmap ' . g:slime_send_key . " \"ry:call <SID>SlimeSend(@r)<CR>"
execute 'nmap ' . g:slime_send_key . " vip" . g:slime_send_key
execute 'nmap ' . g:slime_config_key . " :call <SID>SlimeConfig()<CR>"

if exists('g:slime_loaded')
finish
endif
let g:slime_loaded = 1


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Screen
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

function! s:ScreenSend(config, text)
let escaped_text = s:_EscapeText(a:text)
call system("screen -S " . a:config["sessionname"] . " -p " . a:config["windowname"] . " -X stuff " . escaped_text)
call system("screen -S " . shellescape(a:config["sessionname"]) . " -p " . shellescape(a:config["windowname"]) . " -X readreg a -", a:text)
call system("screen -S " . shellescape(a:config["sessionname"]) . " -p " . shellescape(a:config["windowname"]) . " -X paste a")
endfunction

" Leave this function exposed as it's called outside the plugin context
function! ScreenSessionNames(A,L,P)
function! s:ScreenSessionNames(A,L,P)
return system("screen -ls | awk '/Attached/ {print $1}'")
endfunction

function! s:ScreenConfig()
function! s:ScreenConfig() abort
if !exists("b:slime_config")
let b:slime_config = {"sessionname": "", "windowname": "0"}
end

let b:slime_config["sessionname"] = input("screen session name: ", b:slime_config["sessionname"], "custom,ScreenSessionNames")
let b:slime_config["sessionname"] = input("screen session name: ", b:slime_config["sessionname"], "custom,<SNR>" . s:SID() . "_ScreenSessionNames")
let b:slime_config["windowname"] = input("screen window name: ", b:slime_config["windowname"])
endfunction

Expand All @@ -55,24 +38,35 @@ endfunction
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

function! s:TmuxSend(config, text)
let escaped_text = s:_EscapeText(a:text)
call system("tmux -L " . a:config["socket_name"] . " set-buffer " . escaped_text)
call system("tmux -L " . a:config["socket_name"] . " paste-buffer -t " . a:config["target_pane"])
call system("tmux -L " . shellescape(a:config["socket_name"]) . " load-buffer -", a:text)
call system("tmux -L " . shellescape(a:config["socket_name"]) . " paste-buffer -t " . shellescape(a:config["target_pane"]))
endfunction

function! s:TmuxConfig()
function! s:TmuxPaneNames(A,L,P)
let format = '#{pane_id} #{session_name}:#{window_index}.#{pane_index} #{window_name}#{?window_active, (active),}'
return system("tmux -L " . shellescape(b:slime_config['socket_name']) . " list-panes -a -F " . shellescape(format))
endfunction

function! s:TmuxConfig() abort
if !exists("b:slime_config")
let b:slime_config = {"socket_name": "default", "target_pane": ":"}
let b:slime_config = { "socket_name": "default", "target_pane": ":"}
end

let b:slime_config["socket_name"] = input("tmux socket name: ", b:slime_config["socket_name"])
let b:slime_config["target_pane"] = input("tmux target pane: ", b:slime_config["target_pane"])
let b:slime_config["target_pane"] = input("tmux target pane: ", b:slime_config["target_pane"], "custom,<SNR>" . s:SID() . "_TmuxPaneNames")
if b:slime_config["target_pane"] =~ '\s\+'
let b:slime_config["target_pane"] = split(b:slime_config["target_pane"])[0]
endif
endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Helpers
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

function! s:SID()
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
endfun

function! s:_EscapeText(text)
let transformed_text = a:text

Expand All @@ -83,7 +77,58 @@ function! s:_EscapeText(text)
end
end

return substitute(shellescape(transformed_text), "\\\\\\n", "\n", "g")
return transformed_text
endfunction

function! s:SlimeSendOp(type, ...) abort
if !exists("b:slime_config")
call s:SlimeDispatch('Config')
end

let sel_save = &selection
let &selection = "inclusive"
let rv = getreg('"')
let rt = getregtype('"')

if a:0 " Invoked from Visual mode, use '< and '> marks.
silent exe "normal! `<" . a:type . '`>y'
elseif a:type == 'line'
silent exe "normal! '[V']y"
elseif a:type == 'block'
silent exe "normal! `[\<C-V>`]\y"
else
silent exe "normal! `[v`]y"
endif

call setreg('"', @", 'V')
call s:SlimeSend(@")

let &selection = sel_save
call setreg('"', rv, rt)
endfunction

function! s:SlimeSendRange() range abort
if !exists("b:slime_config")
call s:SlimeDispatch('Config')
end

let rv = getreg('"')
let rt = getregtype('"')
sil exe a:firstline . ',' . a:lastline . 'yank'
call s:SlimeSend(@")
call setreg('"', rv, rt)
endfunction

function! s:SlimeSendLines(count) abort
if !exists("b:slime_config")
call s:SlimeDispatch('Config')
end

let rv = getreg('"')
let rt = getregtype('"')
exe "norm! " . a:count . "yy"
call s:SlimeSend(@")
call setreg('"', rv, rt)
endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Expand All @@ -92,17 +137,54 @@ endfunction

function! s:SlimeSend(text)
if !exists("b:slime_config")
call s:SlimeDispatch('Config')
let msg = "Slime is not configured for this buffer. Please run :SlimeConfig"
echohl ErrorMsg
echoerr msg
echohl None
let v:errmsg = 'slime: ' . msg
throw v:errmsg
end
call s:SlimeDispatch('Send', b:slime_config, a:text)
let transformed_text = s:_EscapeText(a:text)
call s:SlimeDispatch('Send', b:slime_config, transformed_text)
endfunction

function! s:SlimeConfig()
function! s:SlimeConfig() abort
call inputsave()
call s:SlimeDispatch('Config')
call inputrestore()
endfunction

" delegation
function! s:SlimeDispatch(name, ...)
let target = substitute(tolower(g:slime_target), '\(.\)', '\u\1', '') " Capitalize
return call("s:" . target . a:name, a:000)
endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Setup key bindings
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

command -bar -nargs=0 SlimeConfig call s:SlimeConfig()
command -range -bar -nargs=0 SlimeSend <line1>,<line2>call s:SlimeSendRange()

noremap <SID>Operator :<c-u>set opfunc=<SID>SlimeSendOp<cr>g@
noremap <unique> <script> <silent> <Plug>SlimeRegionSend :<c-u>call <SID>SlimeSendOp(visualmode(), 1)<cr>
noremap <unique> <script> <silent> <Plug>SlimeLineSend :<c-u>call <SID>SlimeSendLines(v:count1)<cr>
noremap <unique> <script> <silent> <Plug>SlimeMotionSend <SID>Operator
noremap <unique> <script> <silent> <Plug>SlimeParagraphSend <SID>Operatorip
noremap <unique> <script> <silent> <Plug>SlimeConfig :<c-u>SlimeConfig<cr>
if !exists("g:slime_no_mappings") || !g:slime_no_mappings
if !hasmapto('<Plug>SlimeRegionSend', 'x')
xmap <c-c><c-c> <Plug>SlimeRegionSend
endif

if !hasmapto('<Plug>SlimeParagraphSend', 'n')
nmap <c-c><c-c> <Plug>SlimeParagraphSend
endif

if !hasmapto('<Plug>SlimeConfig', 'n')
nmap <c-c>v <Plug>SlimeConfig
endif
endif

0 comments on commit fd2e84c

Please sign in to comment.