" pastie.vim: Vim plugin for pastie.caboo.se " Maintainer: Tim Pope " URL: http://www.vim.org/scripts/script.php?script_id=1624 " GetLatestVimScripts: 1624 1 " $Id: pastie.vim,v 1.14 2007-10-15 16:09:24 tpope Exp $ " Installation: " Place in ~/.vim/plugin or vimfiles/plugin " A working ruby install is required (Vim interface not necessary). " Usage: " :Pastie creates a new paste (example arguments shown below). Use :w to save " it by posting it to the server (the parser used is derived from the Vim " filetype). This updates the filename and stores the new url in the primary " selection/clipboard when successful. :Pastie! creates a paste, saves, and " closes the buffer, except when loading an existing paste. " :Pastie Create a paste from all open windows " :Pastie! Create a paste from all open windows and paste it " :1,10Pastie Create a paste from the specified range " :%Pastie Use the entire current file to create a new paste " :Pastie foo.txt bar.txt Create a paste from foo.txt and bar.txt " :Pastie! foo.txt Paste directly from foo.txt " :Pastie a Create a paste from the "a register " :Pastie @ Create a paste from the default (unnamed) register " :Pastie * Create a paste from the primary selection/clipboard " :Pastie _ Create a new, blank paste " :768Pastie Load existing paste 768 " :0Pastie Load the newest paste " :Pastie http://pastie.caboo.se/768 Load existing paste 768 " :Pastie http://pastie.caboo.se/123456?key=... Use login from pastie bot " Regardless of the command used, on the first write, this script will create " a new paste, and on subsequent writes, it will update the existing paste. " If a bang is passed to a command that load an existing paste (:768), the " first write will update as well. If the loaded paste was not created in the " same vim session, or with an account extracted from your Firefox cookies, " updates will almost certainly silently fail. (Advanced users can muck " around with g:pastie_session_id if desired). " As hinted at earlier, pastie.vim will snoop around in your Firefox cookies, " and use an account cookie if one is found. The only way to create one of " these account cookies is by talking to pastie on IRC. " At the shell you can directly create a new pastie with a command like " $ vim +Pastie " or, assuming no other plugins conflict " $ vim +Pa " And, to read an existing paste " $ vim +768Pa " You could even paste a file directly " $ vim '+Pa!~/.irbrc' +q " You can even edit a pastie URL directly, but this is not recommended because " netrw can sometimes interfere. " Lines ending in #!! will be sent as lines beginning with !!. This alternate " format is easier to read and is less likely to interfere with code " execution. In Vim 7 highlighting is done with :2match (use ":2match none" " to disable it) and in previous versions, :match (use ":match none" to " disable). " " Known Issues: " URL sometimes disappears with the bang (:Pastie!) variant. You can still " retrieve it from the clipboard. if exists("g:loaded_pastie") || &cp finish endif let g:loaded_pastie = 1 augroup pastie autocmd! autocmd BufReadPre http://pastie.caboo.se/*[0-9]?key=* call s:extractcookies(expand("")) autocmd BufReadPost http://pastie.caboo.se/*[0-9]?key=* call s:PastieSwapout(expand("")) autocmd BufReadPost http://pastie.caboo.se/*[0-9] call s:PastieSwapout(expand("")) autocmd BufReadPost http://pastie.caboo.se/pastes/*[0-9]/download call s:PastieRead(expand("")) autocmd BufReadPost http://pastie.caboo.se/*[0-9].* call s:PastieRead(expand("")) autocmd BufWriteCmd http://pastie.caboo.se/pastes/*[0-9]/download call s:PastieWrite(expand("")) autocmd BufWriteCmd http://pastie.caboo.se/*[0-9].* call s:PastieWrite(expand("")) autocmd BufWriteCmd http://pastie.caboo.se/pastes/ call s:PastieWrite(expand("")) augroup END let s:domain = "pastie.caboo.se" let s:dl_suffix = ".txt" " Used only for :file if !exists("g:pastie_destination") if version >= 700 let g:pastie_destination = 'tab' else let g:pastie_destination = 'window' endif "let g:pastie_destination = 'buffer' endif command! -bar -bang -nargs=* -range=0 -complete=file Pastie :call s:Pastie(0,,,,) function! s:Pastie(bang,line1,line2,count,...) if exists(":tab") let tabnr = tabpagenr() endif let newfile = "http://".s:domain."/pastes/" let loggedin = 0 let ft = &ft let num = 0 if a:0 == 0 && a:count == a:line1 && a:count > line('$') let num = a:count elseif a:0 == 0 && a:line1 == 0 && a:line2 == 0 let num = s:latestid() if num == 0 return s:error("Could not determine latest paste") endif elseif !a:count && a:0 == 1 if a:1 == '*' let numcheck = @* elseif a:1 == '+' let numcheck = @+ elseif a:1 == '@' let numcheck = @@ else let numcheck = a:1 endif let numcheck = substitute(numcheck,'\n\+$','','') let numcheck = substitute(numcheck,'^\n\+','','g') if numcheck =~ '\n' let numcheck = '' endif if numcheck =~ '^\d\d+$' let num = numcheck elseif numcheck =~ '\%(^\|/\)\d\+?key=\x\{8,\}' if exists("b:pastie_fake_login") unlet b:pastie_fake_login else call s:extractcookies('/'.matchstr(numcheck,'\%(^\|/\)\zs\d\+?.*')) endif if exists("g:pastie_account") let loggedin = 1 endif let num = matchstr(numcheck,'\%(^\|/\)\zs\d\+\ze?') elseif numcheck =~ '\%(^\|^/\|^http://.*\)\d\+\%([/?]\|$\)' let num = matchstr(numcheck,'\%(^\|/\)\zs\d\+') endif endif if num call s:newwindow() let file = "http://".s:domain."/".num.s:dl_suffix silent exe 'doautocmd BufReadPre '.file silent exe 'read !ruby -rnet/http -e "r = Net::HTTP.get_response(\%{'.s:domain.'}, \%{/pastes/'.num.'/download}); if r.code == \%{200} then print r.body else exit 10+r.code.to_i/100 end"' if v:shell_error && v:shell_error != 14 && v:shell_error !=15 return s:error("Something went wrong: shell returned ".v:shell_error) else let err = v:shell_error silent exe "file ".file 1d_ set nomodified call s:dobufreadpost() if err if loggedin let b:pastie_update = 1 else echohl WarningMsg echo "Warning: Failed to retrieve existing paste" echohl None endif endif "call s:PastieRead(file) if a:bang " Instead of saving an identical paste, take ! to mean "do not " create a new paste on first save" let b:pastie_update = 1 endif return endif elseif a:0 == 0 && !a:count && a:bang && expand("%") =~ '^http://'.s:domain.'/\d\+' " If the :Pastie! form is used in an existing paste, switch to " updating instead of creating. "echohl Question echo "Will update, not create" echohl None let b:pastie_update = 1 return elseif a:0 == 1 && !a:count && a:1 =~ '^[&?]\x\{32,\}' " Set session id with :Pastie&deadbeefcafebabe let g:pastie_session_id = strpart(a:1,1) elseif a:0 == 1 && !a:count && (a:1 == '&' || a:1 == '?') " Extract session id with :Pastie& call s:cookies() if exists("g:pastie_session_id") echo g:pastie_session_id "silent! let @* = g:pastie_session_id endif elseif a:0 == 0 && !a:count && a:line1 let ft = 'conf' let sum = "" let cnt = 0 let keep = @" windo let tmp = s:grabwin() | if tmp != "" | let cnt = cnt + 1 | let sum = sum . tmp | end let sum = substitute(sum,'\n\+$',"\n",'') if cnt == 1 let ft = matchstr(sum,'^##.\{-\} \[\zs\w*\ze\]') if ft != "" let sum = substitute(sum,'^##.\{-\} \[\w*\]\n','','') endif endif call s:newwindow() silent exe "file ".newfile "silent exe "doautocmd BufReadPre ".newfile if sum != "" let @" = sum silent $put 1d _ endif if ft == 'plaintext' "set ft=conf elseif ft != '' && sum != "" let &ft = ft endif let @" = keep call s:dobufreadpost() else let keep = @" let args = "" if a:0 > 0 && a:1 =~ '^[-"@0-9a-zA-Z:.%#*+~_/]$' let i = 1 let register = a:1 else let i = 0 let register = "" endif while i < a:0 let i = i+1 if strlen(a:{i}) let file = fnamemodify(expand(a:{i}),':~:.') let args = args . file . "\n" endif endwhile let range = "" if a:count silent exe a:line1.",".a:line2."yank" let range = @" let @" = keep endif call s:newwindow() silent exe "file ".newfile "silent exe "doautocmd BufReadPre ".newfile if range != "" let &ft = ft let @" = range silent $put endif if register != '' && register != '_' "exe "let regvalue = @".register silent exe "$put ".(register =~ '^[@"]$' ? '' : register) endif while args != '' let file = matchstr(args,'^.\{-\}\ze\n') let args = substitute(args,'^.\{-\}\n','','') let @" = "## ".file." [".s:parser(file)."]\n" if a:0 != 1 || a:count silent $put else if s:parser(file) !~ '^\%(plaintext\)\=$' let &ft = s:parser(file) endif endif silent exe "$read ".substitute(file,' ','\ ','g') endwhile let @" = keep 1d_ call s:dobufreadpost() if (a:0 + (a:count > 0)) > 1 set ft=conf endif endif 1 call s:afterload() if a:bang write let name = bufname('%') " TODO: re-echo the URL in a way that doesn't disappear. Stupid Vim. silent! bdel if exists("tabnr") silent exe "norm! ".tabnr."gt" endif endif endfunction function! s:dobufreadpost() if expand("%") =~ '/\d\+\.\@!' silent exe "doautocmd BufReadPost ".expand("%") else silent exe "doautocmd BufNewFile ".expand("%") endif endfunction function! s:PastieSwapout(file) if a:file =~ '?key=' let b:pastie_fake_login = 1 endif exe "Pastie ".a:file endfunction function! s:PastieRead(file) let lnum = line(".") silent %s/^!!\(.*\)/\1 #!!/e exe lnum set nomodified let num = matchstr(a:file,'/\@= 700 2match pastieHighlight /^!!\s*.*\|^.\{-\}\ze\s*#!!\s*$/ else match pastieHighlight /^!!\s*.*\|^.\{-\}\ze\s*#!!\s*$/ endif else hi def link pastieHighlight Search syn match pastieHighlight '^.\{-\}\ze\s*#!!\s*$' nextgroup=pastieIgnore skipwhite syn region pastieHighlight start='^!!\s*' end='$' contains=pastieNonText endif syn match pastieIgnore '#!!\ze\s*$' containedin=rubyComment,rubyString syn match pastieNonText '^!!' containedin=rubyString endfunction function! s:PastieWrite(file) let parser=s:parser(&ft) let tmp = tempname() let num = matchstr(a:file,'/\@ %{'.s:cookies().'}})}; print obj[%{Location}].to_s+%{ }+obj[%{Set-Cookie}].to_s' let result = system('ruby -rnet/http -e "'.rubycmd.'"') let redirect = matchstr(result,'^[^ ]*') let cookies = matchstr(result,'^[^ ]* \zs.*') call s:extractcookiesfromheader(cookies) call delete(tmp) if redirect =~ '^\w\+://' set nomodified let b:pastie_update = 1 "silent! let @+ = result silent! let @* = redirect silent exe "file ".redirect.s:dl_suffix " TODO: make a proper status message echo '"'.redirect.'" written' silent exe "doautocmd BufWritePost ".redirect.s:dl_suffix else if redirect == '' let redirect = "Could not post to ".url endif let redirect = substitute(redirect,'^-e:1:\s*','','') call s:error(redirect) endif endfunction function! s:error(msg) echohl Error echo a:msg echohl NONE let v:errmsg = a:msg endfunction function! s:parser(type) " Accepts a filename, extension, or vim filetype let type = tolower(substitute(a:type,'.*\.','','')) if type =~ '^\%(x\=html\|php\|asp\w*\)$' return 'html' elseif type =~ '^\%(eruby\|erb\|rhtml\)$' return 'rhtml' elseif type =~ '^\%(ruby\|rb\|rake\|rxml\|builder\|rjs\|mab\|irbrc\)' return 'ruby' elseif type == 'js' || type == 'javascript' return 'javascript' elseif type == 'c' || type == 'cpp' return 'c' elseif type == 'diff' || type == 'sql' return type else return 'plaintext' endif endfunction function! s:grabwin() let ft = (&ft == '' ? expand("%:e") : &ft) let top = "## ".expand("%:~:.")." [".s:parser(ft)."]\n" let keep = @" silent %yank let file = @" let @" = keep if file == "" || file == "\n" return "" else return top.file."\n" endif endfunction function! s:cookies() if exists("g:pastie_session_id") let cookies = "_pastie_session_id=".g:pastie_session_id else call s:extractcookies('/') if !exists("g:pastie_session_id") if !exists("s:session_warning") echohl WarningMsg echo "Warning: could not extract session id" let s:session_warning = 1 echohl NONE endif let cookies = "" else let cookies = "_pastie_session_id=".g:pastie_session_id endif endif if !exists("g:pastie_account") let rubycmd = '%w(~/.mozilla/firefox ~/.firefox/default ~/.phoenix/default ~/Application\ Data/Mozilla/Firefox/Profiles ~/Library/Application\ Support/Firefox/Profiles)' let rubycmd = rubycmd . '.each {|dir| Dir[File.join(File.expand_path(dir),%{*})].select {|p| File.exists?(File.join(p,%{cookies.txt}))}.each {|p| File.open(File.join(p,%{cookies.txt})).each_line { |l| a=l.split(9.chr); puts [a[4],a[6]].join(%{ }) if a[0] =~ /pastie\.caboo\.se#{36.chr}/ && Time.now.to_i < a[4].to_i && a[5] == %{account} }}}' let output = '' let output = system('ruby -e "'.rubycmd.'"') if output =~ '\n' && output !~ '-e:' let output = substitute(output,'\n.*','','') let g:pastie_account = matchstr(output,' \zs.*') let g:pastie_account_expires = matchstr(output,'.\{-\}\ze ') else let g:pastie_account = '' endif endif if exists("g:pastie_account") && g:pastie_account != "" " You cannot set this arbitrarily, it must be a valid cookie let cookies = cookies . (cookies == "" ? "" : "; ") let cookies = cookies . 'account='.substitute(g:pastie_account,':','%3A','g') endif return cookies endfunction function! s:extractcookies(path) let path = substitute(a:path,'\c^http://'.s:domain,'','') if path !~ '^/' let path = '/'.path endif let cookie = system('ruby -rnet/http -e "print Net::HTTP.get_response(%{'.s:domain.'},%{'.path.'})[%{Set-Cookie}]"') if exists("g:pastie_debug") let g:pastie_cookies_path = path let g:pastie_cookies = cookie endif return s:extractcookiesfromheader(cookie) endfunction function! s:extractcookiesfromheader(cookie) let cookie = a:cookie if cookie !~ '-e:' let session_id = matchstr(cookie,'\<_pastie_session_id=\zs.\{-\}\ze\%([;,]\|$\)') let account = matchstr(cookie,'\View})[1]"') endfunction function! s:urlencode(str) " Vim 6.2, how did we ever live with you? return substitute(substitute(a:str,"[\001-\037%&?=\\\\]",'\="%".printf("%02X",char2nr(submatch(0)))','g'),' ','%20','g') endfunction function! s:newwindow() if !(&modified) && (expand("%") == '' || (version >= 700 && winnr("$") == 1 && tabpagenr("$") == 1)) enew else if g:pastie_destination == 'tab' tabnew elseif g:pastie_destination == 'window' new else enew endif endif setlocal noswapfile endfunction " vim:set sw=4 sts=4 et: