Commits

Steve Losh committed 429731d

Big refactoring.

  • Participants
  • Parent commits 2b5144b

Comments (0)

Files changed (2)

File doc/clam.txt

 When you close the buffer with :quit or something similar Clam will place your
 cursor back in the split you came from.
 
-You might want to set up your own mapping to make Clam easier to use.  The
+The :Clam command can take a range.  If given, the lines will be passed to the
+command on standard input.  For example, this will open a Clam output window
+with the contents of the current buffer sorted: >
+
+    :%Clam sort
+
+This will pipe the first ten lines of the file into the python command: >
+
+    :1,10Clam python
+
+To pipe visually selected text you can use the :ClamVisual command: >
+
+    :ClamVisual sort | uniq -c | sort -n
+
+When you've got some text visually selected and hit : to enter the command,
+Vim will add the '<,'> range by default.  You can backspace it out if you want
+(or use <c-u>), but you don't have to: ClamVisual will work fine with or
+without it.
+
+In other words, the following commands do the same thing: >
+
+    :ClamVisual wc -c
+    :'<,'>ClamVisual wc -c
+
+You might want to set up your own mappings to make Clam easier to use.  The
 author has something like this in his .vimrc: >
 
     nnoremap ! :Clam<space>
+    vnoremap ! :ClamVisual<space>
 
 That's Clam in a nutclamshell.
 
 ==============================================================================
 7. Changelog                                                   *ClamChangelog*
 
+v1.2.0
+    * Added support for ranges in the :Clam command.
+    * Added the :ClamVisual command.
 v1.1.0
     * Added the g:clam_autoreturn setting.
 v1.0.0

File plugin/clam.vim

 " ============================================================================
 " File:        clam.vim
-" Description: A simple little shell.
+" Description: A simple little shell plugin.
 " Maintainer:  Steve Losh <steve@stevelosh.com>
 " License:     MIT/X11
 " ============================================================================
 
 let loaded_clam = 1
 
-if !exists('g:clam_autoreturn') "{{{
+if !exists('g:clam_autoreturn') " {{{
     let g:clam_autoreturn = 1
 endif " }}}
 
 "}}}
-" Function {{{
+" Functions {{{
 
-function! s:Execlam(command)
-    " Build the actual command string to execute
-    let command = join(map(split(a:command), 'expand(v:val)'))
+function! s:GoToClamBuffer(command) " {{{
+    let buffer_name = fnameescape(a:command)
 
     " Find any already-open clam windows for this command.
-    let winnr = bufwinnr('^' . command . '$')
+    let winnr = bufwinnr('^' . buffer_name . '$')
 
     " Open the new window (or move to an existing one).
     if winnr < 0
-        silent! execute 'botright vnew ' . fnameescape(command)
+        silent! execute 'botright vnew ' . buffer_name
     else
         silent! execute winnr . 'wincmd w'
     endif
-
+endfunction " }}}
+function! s:ConfigureCurrentClamBuffer(command) " {{{
     " Set some basic options for the output window.
     setlocal buftype=nowrite bufhidden=wipe nobuflisted noswapfile nowrap nonumber
 
-    " Actually run the command, placing its output in the current window.
-    echo 'Executing: ' . command
-    silent! execute 'silent %!'. command
-
     if g:clam_autoreturn
         " When closing this buffer in any way (like :quit), jump back to the original window.
         silent! execute 'au BufUnload <buffer> execute bufwinnr(' . bufnr('#') . ') . ''wincmd w'''
     endif
 
     " Map <localleader>r to "refresh" the command (call it again).
-    silent! execute 'nnoremap <silent> <buffer> <localleader>r :call <SID>Execlam(''' . command . ''')<cr>'
+    silent! execute 'nnoremap <silent> <buffer> <localleader>r :call <SID>Execlam(''' . a:command . ''')<cr>'
 
     " Map <localleader>p to "pipe" the buffer into a new command.
     silent! execute 'nnoremap <buffer> <LocalLeader>p ggVG!'
     if exists("g:loaded_AnsiEscPlugin")
         silent! execute 'AnsiEsc'
     endif
+endfunction " }}}
+function! s:ReplaceCurrentBuffer(contents) " {{{
+    normal! ggdG
+    call append(0, split(a:contents, '\v\n'))
+endfunction " }}}
+
+function! s:ExeclamVisual(command) range " {{{
+    let old_z = @z
+
+    normal! gv"zy
+    call s:Execlam(a:command, @z)
+
+    let @z = old_z
+endfunction " }}}
+function! s:ExeclamNormal(ranged, l1, l2, command) " {{{
+    if a:ranged
+        let lines = getline(a:l1, a:l2)
+        let stdin = join(lines, "\n") . "\n"
+
+        call s:Execlam(a:command, stdin)
+    else
+        call s:Execlam(a:command)
+    endif
+endfunction " }}}
+function! s:Execlam(command, ...) " {{{
+    " Build the actual command string to execute
+    let command = join(map(split(a:command), 'expand(v:val)'))
+
+    " Run the command
+    echo 'Executing: ' . command
+
+    if a:0 == 0
+        let result = system(command)
+    elseif a:0 == 1
+        let result = system(command, a:1)
+    else
+        echom "Invalid number of arguments passed to Execlam()!"
+        return
+    endif
+
+    call s:GoToClamBuffer(command)
+    call s:ConfigureCurrentClamBuffer(command)
+
+    call s:ReplaceCurrentBuffer(result)
 
     silent! redraw
 
     echo 'Shell command executed: ' . command
-endfunction
+endfunction " }}}
 
 " }}}
 " Command {{{
 
-command! -complete=shellcmd -nargs=+ Clam call s:Execlam(<q-args>)
+command! -range=0 -complete=shellcmd -nargs=+ Clam call s:ExeclamNormal(<count>, <line1>, <line2>, <q-args>)
+command! -range=% -complete=shellcmd -nargs=+ ClamVisual call s:ExeclamVisual(<q-args>)
 
 " }}}