Permalink
Browse files

Merge branch 'PeterRincker'

  • Loading branch information...
2 parents df172a7 + 83bd0b0 commit fd2e84ce90320978b14ed1a284ecbd48c3e64f2a @jpalardy jpalardy committed Apr 19, 2012
Showing with 269 additions and 37 deletions.
  1. +150 −0 doc/slime.txt
  2. +119 −37 plugin/slime.vim
View
@@ -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:
View
@@ -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
@@ -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
@@ -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
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
@@ -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.