diff options
Diffstat (limited to '.vim/plugin/pastie.vim')
-rw-r--r-- | .vim/plugin/pastie.vim | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/.vim/plugin/pastie.vim b/.vim/plugin/pastie.vim new file mode 100644 index 0000000..b001508 --- /dev/null +++ b/.vim/plugin/pastie.vim @@ -0,0 +1,537 @@ +" pastie.vim: Vim plugin for pastie.caboo.se +" Maintainer: Tim Pope <vimNOSPAM@tpope.info> +" URL: http://www.vim.org/scripts/script.php?script_id=1624 +" GetLatestVimScripts: 1624 1 +" $Id: pastie.vim,v 1.15 2007-12-13 16:44:26 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("<amatch>")) + autocmd BufReadPost http://pastie.caboo.se/*[0-9]?key=* call s:PastieSwapout(expand("<amatch>")) + autocmd BufReadPost http://pastie.caboo.se/*[0-9] call s:PastieSwapout(expand("<amatch>")) + autocmd BufReadPost http://pastie.caboo.se/pastes/*[0-9]/download call s:PastieRead(expand("<amatch>")) + autocmd BufReadPost http://pastie.caboo.se/*[0-9].* call s:PastieRead(expand("<amatch>")) + autocmd BufWriteCmd http://pastie.caboo.se/pastes/*[0-9]/download call s:PastieWrite(expand("<amatch>")) + autocmd BufWriteCmd http://pastie.caboo.se/*[0-9].* call s:PastieWrite(expand("<amatch>")) + autocmd BufWriteCmd http://pastie.caboo.se/pastes/ call s:PastieWrite(expand("<amatch>")) +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(<bang>0,<line1>,<line2>,<count>,<f-args>) + +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' || ft == 'plain_text' + "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 + let &ft = s:filetype(file) + 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,'/\@<!/\zs\d\+') + let url = "http://".s:domain."/pastes/".num + "let url = substitute(a:file,'\c/\%(download/\=\|text/\=\)\=$','','') + let url = url."/download" + let result = system('ruby -rnet/http -e "puts Net::HTTP.get_response(URI.parse(%{'.url.'}))[%{Content-Disposition}]"') + let fn = matchstr(result,'filename="\zs.*\ze"') + let &ft = s:filetype(fn) + if &ft =~ '^\%(html\|ruby\)$' && getline(1).getline(2).getline(3) =~ '<%' + set ft=eruby + endif + call s:afterload() +endfunction + +function! s:afterload() + set commentstring=%s\ #!! " + hi def link pastieIgnore Ignore + hi def link pastieNonText NonText + if exists(":match") + hi def link pastieHighlight MatchParen + if version >= 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,'/\@<!/\zs\d\+') + if num == '' + let num = 'pastes' + endif + if exists("b:pastie_update") && s:cookies() != '' && num != "" + let url = "/pastes/".num + let method = "_method=put&" + else + let url = "/pastes" + let method = "" + endif + if exists("b:pastie_display_name") + let pdn = "&paste[display_name]=".s:urlencode(b:pastie_display_name) + elseif exists("g:pastie_display_name") + let pdn = "&paste[display_name]=".s:urlencode(g:pastie_display_name) + else + let pdn = "" + endif + silent exe "write ".tmp + let result = "" + let rubycmd = 'obj = Net::HTTP.start(%{'.s:domain.'}){|h|h.post(%{'.url.'}, %q{'.method.'paste[parser]='.parser.pdn.'&paste[authorization]=burger&paste[key]=&paste[body]=} + File.read(%q{'.tmp.'}).gsub(/^(.*?) *#\!\! *#{36.chr}/,%{!\!}+92.chr+%{1}).gsub(/[^a-zA-Z0-9_.-]/n) {|s| %{%%%02x} % s[0]},{%{Cookie} => %{'.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:filetype(type) + " Accepts a filename, extension, pastie parser, or vim filetype + let type = tolower(substitute(a:type,'.*\.','','')) + if type =~ '^\%(x\=html\|asp\w*\)$' + return 'html' + elseif type =~ '^\%(eruby\|erb\|rhtml\)$' + return 'eruby' + elseif type =~ '^\%(ruby\|ruby_on_rails\|rb\|rake\|builder\|rjs\|irbrc\)' + return 'ruby' + elseif type == 'js' || type == 'javascript' + return 'javascript' + elseif type == 'c' || type == 'cpp' || type == 'c++' + return 'cpp' + elseif type =~ '^\%(css\|diff\|java\|php\|python\|sql\|sh\|shell-unix-generic\)$' + return type + else + return '' + endif +endfunction + +function! s:parser(type) + let type = s:filetype(a:type) + if type == 'text' || type == '' + return 'plain_text' + elseif type == 'eruby' + return 'html_rails' + elseif type == 'ruby' + return 'ruby_on_rails' + elseif type == 'sh' + return 'shell-unix-generic' + elseif type == 'cpp' + return 'c++' + else + return type + 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,'\<account=\zs.\{-\}\ze\%([;,]\|$\)') + if session_id != "" + let g:pastie_session_id = session_id + endif + if account != "" + let g:pastie_account = account + let time = matchstr(cookie,'\<[Ee]xpires=\zs\w\w\w,.\{-\}\ze\%([;,]\|$\)') + if time != "" + let g:pastie_account_expires = system('ruby -e "print Time.parse(%{'.time.'}).to_i"') + endif + endif + endif +endfunction + +function! s:latestid() + return system('ruby -rnet/http -e "print Net::HTTP.get_response(URI.parse(%{http://'.s:domain.'/all})).body.match(%r{<a href=.http://'.s:domain.'/(\d+).>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: |