gist.vim 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. "=============================================================================
  2. " File: gist.vim
  3. " Author: Yasuhiro Matsumoto <mattn.jp@gmail.com>
  4. " Last Change: 18-Apr-2011.
  5. " Version: 4.9
  6. " WebPage: http://github.com/mattn/gist-vim
  7. " License: BSD
  8. " Usage:
  9. "
  10. " :Gist
  11. " post current buffer to gist, using default privicy option
  12. " (see g:gist_private)
  13. "
  14. " :'<,'>Gist
  15. " post selected text to gist., using default privicy option
  16. " This applies to all permutations listed below (except multi)
  17. " (see g:gist_private)
  18. "
  19. " :Gist -p
  20. " create a private gist
  21. "
  22. " :Gist -P
  23. " create a public gist
  24. " (only relevant if you've set gists to be private by default)
  25. "
  26. " :Gist -P
  27. " post whole text to gist as public
  28. " This is only relevant if you've set gists to be private by default
  29. " :Gist -a
  30. " create a gist anonymously
  31. "
  32. " :Gist -m
  33. " create a gist with all open buffers
  34. "
  35. " :Gist -e
  36. " edit the gist. (you need to have opend the gist buffer first)
  37. " you can update the gist with :w command on gist buffer
  38. "
  39. " :Gist -d
  40. " delete the gist. (you need to have opend the gist buffer first)
  41. " password authentication is needed
  42. "
  43. " :Gist -f
  44. " fork the gist. (you need to have opend the gist buffer first)
  45. " password authentication is needed
  46. "
  47. " :Gist -e foo.js
  48. " edit the gist with name 'foo.js'. (you need to have opend the gist buffer first)
  49. "
  50. " :Gist XXXXX
  51. " get gist XXXXX
  52. "
  53. " :Gist -c XXXXX
  54. " get gist XXXXX and add to clipboard
  55. "
  56. " :Gist -l
  57. " list your public gists
  58. "
  59. " :Gist -l mattn
  60. " list gists from mattn
  61. "
  62. " :Gist -la
  63. " list all your (public and private) gists
  64. "
  65. " Tips:
  66. " * if set g:gist_clip_command, gist.vim will copy the gist code
  67. " with option '-c'.
  68. "
  69. " # mac
  70. " let g:gist_clip_command = 'pbcopy'
  71. "
  72. " # linux
  73. " let g:gist_clip_command = 'xclip -selection clipboard'
  74. "
  75. " # others(cygwin?)
  76. " let g:gist_clip_command = 'putclip'
  77. "
  78. " * if you want to detect filetype from gist's filename...
  79. "
  80. " # detect filetype if vim failed auto-detection.
  81. " let g:gist_detect_filetype = 1
  82. "
  83. " # detect filetype always.
  84. " let g:gist_detect_filetype = 2
  85. "
  86. " * if you want to open browser after the post...
  87. "
  88. " let g:gist_open_browser_after_post = 1
  89. "
  90. " * if you want to change the browser...
  91. "
  92. " let g:gist_browser_command = 'w3m %URL%'
  93. "
  94. " or
  95. "
  96. " let g:gist_browser_command = 'opera %URL% &'
  97. "
  98. " on windows, should work with original setting.
  99. "
  100. " * if you want to show your private gists with ':Gist -l'
  101. "
  102. " let g:gist_show_privates = 1
  103. "
  104. " * if don't you want to copy URL of the post...
  105. "
  106. " let g:gist_put_url_to_clipboard_after_post = 0
  107. "
  108. " or if you want to copy URL and add linefeed at the last of URL,
  109. "
  110. " let g:gist_put_url_to_clipboard_after_post = 2
  111. "
  112. " default value is 1.
  113. "
  114. " Thanks:
  115. " MATSUU Takuto:
  116. " removed carriage return
  117. " gist_browser_command enhancement
  118. " edit support
  119. "
  120. " GetLatestVimScripts: 2423 1 :AutoInstall: gist.vim
  121. " script type: plugin
  122. if &cp || (exists('g:loaded_gist_vim') && g:loaded_gist_vim)
  123. finish
  124. endif
  125. let g:loaded_gist_vim = 1
  126. if (!exists('g:github_user') || !exists('g:github_token')) && !executable('git')
  127. echoerr "Gist: require 'git' command"
  128. finish
  129. endif
  130. if !executable('curl')
  131. echoerr "Gist: require 'curl' command"
  132. finish
  133. endif
  134. if !exists('g:gist_open_browser_after_post')
  135. let g:gist_open_browser_after_post = 0
  136. endif
  137. if !exists('g:gist_put_url_to_clipboard_after_post')
  138. let g:gist_put_url_to_clipboard_after_post = 1
  139. endif
  140. if !exists('g:gist_curl_options')
  141. let g:gist_curl_options = ""
  142. endif
  143. if !exists('g:gist_browser_command')
  144. if has('win32')
  145. let g:gist_browser_command = "!start rundll32 url.dll,FileProtocolHandler %URL%"
  146. elseif has('mac')
  147. let g:gist_browser_command = "open %URL%"
  148. elseif executable('xdg-open')
  149. let g:gist_browser_command = "xdg-open %URL%"
  150. else
  151. let g:gist_browser_command = "firefox %URL% &"
  152. endif
  153. endif
  154. if !exists('g:gist_detect_filetype')
  155. let g:gist_detect_filetype = 0
  156. endif
  157. if !exists('g:gist_private')
  158. let g:gist_private = 0
  159. endif
  160. if !exists('g:gist_show_privates')
  161. let g:gist_show_privates = 0
  162. endif
  163. if !exists('g:gist_cookie_dir')
  164. let g:gist_cookie_dir = substitute(expand('<sfile>:p:h'), '[/\\]plugin$', '', '').'/cookies'
  165. endif
  166. function! s:nr2hex(nr)
  167. let n = a:nr
  168. let r = ""
  169. while n
  170. let r = '0123456789ABCDEF'[n % 16] . r
  171. let n = n / 16
  172. endwhile
  173. return r
  174. endfunction
  175. function! s:encodeURIComponent(instr)
  176. let instr = iconv(a:instr, &enc, "utf-8")
  177. let len = strlen(instr)
  178. let i = 0
  179. let outstr = ''
  180. while i < len
  181. let ch = instr[i]
  182. if ch =~# '[0-9A-Za-z-._~!''()*]'
  183. let outstr = outstr . ch
  184. elseif ch == ' '
  185. let outstr = outstr . '+'
  186. else
  187. let outstr = outstr . '%' . substitute('0' . s:nr2hex(char2nr(ch)), '^.*\(..\)$', '\1', '')
  188. endif
  189. let i = i + 1
  190. endwhile
  191. return outstr
  192. endfunction
  193. " Note: A colon in the file name has side effects on Windows due to NTFS Alternate Data Streams; avoid it.
  194. let s:bufprefix = 'gist' . (has('unix') ? ':' : '_')
  195. function! s:GistList(user, token, gistls, page)
  196. if a:gistls == '-all'
  197. let url = 'https://gist.github.com/gists'
  198. elseif g:gist_show_privates && a:gistls == a:user
  199. let url = 'https://gist.github.com/mine'
  200. else
  201. let url = 'https://gist.github.com/'.a:gistls
  202. endif
  203. let winnum = bufwinnr(bufnr(s:bufprefix.a:gistls))
  204. if winnum != -1
  205. if winnum != bufwinnr('%')
  206. exe "normal \<c-w>".winnum."w"
  207. endif
  208. setlocal modifiable
  209. else
  210. exec 'silent split' s:bufprefix.a:gistls
  211. endif
  212. if a:page > 1
  213. let oldlines = getline(0, line('$'))
  214. let url = url . '?page=' . a:page
  215. endif
  216. setlocal foldmethod=manual
  217. let oldlines = []
  218. if g:gist_show_privates
  219. echon 'Login to gist... '
  220. silent %d _
  221. let res = s:GistGetPage(url, a:user, '', '-L')
  222. silent put =res.content
  223. else
  224. silent %d _
  225. exec 'silent r! curl -s '.g:gist_curl_options.' '.url
  226. endif
  227. silent normal! ggdd
  228. silent! %s/>/>\r/g
  229. silent! %s/</\r</g
  230. silent! %g/<pre/,/<\/pre/join!
  231. silent! %g/<span class="date"/,/<\/span/join
  232. silent! %g/^<span class="date"/s/> */>/g
  233. silent! %v/^\(gist:\|<pre>\|<span class="date">\)/d _
  234. silent! %s/<div[^>]*>/\r /g
  235. silent! %s/<\/pre>/\r/g
  236. silent! %g/^gist:/,/<span class="date"/join
  237. silent! %s/<[^>]\+>//g
  238. silent! %s/\r//g
  239. silent! %s/&nbsp;/ /g
  240. silent! %s/&quot;/"/g
  241. silent! %s/&amp;/\&/g
  242. silent! %s/&gt;/>/g
  243. silent! %s/&lt;/</g
  244. silent! %s/&#\(\d\d\);/\=nr2char(submatch(1))/g
  245. silent! %g/^gist: /s/ //g
  246. call append(0, oldlines)
  247. normal! Gomore...
  248. let b:user = a:user
  249. let b:token = a:token
  250. let b:gistls = a:gistls
  251. let b:page = a:page
  252. setlocal buftype=nofile bufhidden=hide noswapfile
  253. setlocal nomodified
  254. syntax match SpecialKey /^gist:/he=e-1
  255. exec 'nnoremap <silent> <buffer> <cr> :call <SID>GistListAction()<cr>'
  256. cal cursor(1+len(oldlines),1)
  257. setlocal foldmethod=expr
  258. setlocal foldexpr=getline(v:lnum)=~'^\\(gist:\\\|more\\)'?'>1':'='
  259. setlocal foldtext=getline(v:foldstart)
  260. endfunction
  261. function! s:GistGetFileName(gistid)
  262. let url = 'https://gist.github.com/'.a:gistid
  263. let res = system('curl -s '.g:gist_curl_options.' '.url)
  264. let res = substitute(res, '^.*<a href="/raw/[^"]\+/\([^"]\+\)".*$', '\1', '')
  265. if res =~ '/'
  266. return ''
  267. else
  268. return res
  269. endif
  270. endfunction
  271. function! s:GistDetectFiletype(gistid)
  272. let url = 'https://gist.github.com/'.a:gistid
  273. let mx = '^.*<div class=".\{-}type-\([^"]\+\)">.*$'
  274. let res = system('curl -s '.g:gist_curl_options.' '.url)
  275. let res = substitute(matchstr(res, mx), mx, '\1', '')
  276. let res = substitute(res, '.*\(\.[^\.]\+\)$', '\1', '')
  277. let res = substitute(res, '-', '', 'g')
  278. " TODO: more filetype detection that is specified in html.
  279. if res == 'bat' | let res = 'dosbatch' | endif
  280. if res == 'as' | let res = 'actionscript' | endif
  281. if res == 'bash' | let res = 'sh' | endif
  282. if res == 'cl' | let res = 'lisp' | endif
  283. if res == 'rb' | let res = 'ruby' | endif
  284. if res == 'viml' | let res = 'vim' | endif
  285. if res == 'plain' || res == 'text' | let res = '' | endif
  286. if res =~ '^\.'
  287. silent! exec "doau BufRead *".res
  288. else
  289. silent! exec "setlocal ft=".tolower(res)
  290. endif
  291. endfunction
  292. function! s:GistWrite(fname)
  293. if substitute(a:fname, '\\', '/', 'g') == expand("%:p:gs@\\@/@")
  294. Gist -e
  295. else
  296. exe "w".(v:cmdbang ? "!" : "")." ".fnameescape(v:cmdarg)." ".fnameescape(a:fname)
  297. endif
  298. endfunction
  299. function! s:GistGet(user, token, gistid, clipboard)
  300. let url = 'https://gist.github.com/'.a:gistid.'.txt'
  301. let winnum = bufwinnr(bufnr(s:bufprefix.a:gistid))
  302. if winnum != -1
  303. if winnum != bufwinnr('%')
  304. exe "normal \<c-w>".winnum."w"
  305. endif
  306. setlocal modifiable
  307. else
  308. exec 'silent split' s:bufprefix.a:gistid
  309. endif
  310. filetype detect
  311. silent %d _
  312. exec 'silent 0r! curl -s '.g:gist_curl_options.' '.url
  313. normal! Gd_
  314. setlocal buftype=acwrite bufhidden=delete noswapfile
  315. setlocal nomodified
  316. doau StdinReadPost <buffer>
  317. if (&ft == '' && g:gist_detect_filetype == 1) || g:gist_detect_filetype == 2
  318. call s:GistDetectFiletype(a:gistid)
  319. endif
  320. if a:clipboard
  321. if exists('g:gist_clip_command')
  322. exec 'silent w !'.g:gist_clip_command
  323. else
  324. normal! gg"+yG
  325. endif
  326. endif
  327. normal! gg
  328. au! BufWriteCmd <buffer> call s:GistWrite(expand("<amatch>"))
  329. endfunction
  330. function! s:GistListAction()
  331. let line = getline('.')
  332. let mx = '^gist:\(\w\+\).*'
  333. if line =~# mx
  334. let gistid = substitute(line, mx, '\1', '')
  335. call s:GistGet(g:github_user, g:github_token, gistid, 0)
  336. return
  337. endif
  338. if line =~# '^more\.\.\.$'
  339. normal! dd
  340. call s:GistList(b:user, b:token, b:gistls, b:page+1)
  341. return
  342. endif
  343. endfunction
  344. function! s:GistUpdate(user, token, content, gistid, gistnm)
  345. if len(a:gistnm) == 0
  346. let name = s:GistGetFileName(a:gistid)
  347. else
  348. let name = a:gistnm
  349. endif
  350. let namemx = '^[^.]\+\(.\+\)$'
  351. let ext = ''
  352. if name =~ namemx
  353. let ext = substitute(name, namemx, '\1', '')
  354. endif
  355. let query = [
  356. \ '_method=put',
  357. \ 'file_ext[gistfile1%s]=%s',
  358. \ 'file_name[gistfile1%s]=%s',
  359. \ 'file_contents[gistfile1%s]=%s',
  360. \ 'login=%s',
  361. \ 'token=%s',
  362. \ ]
  363. let squery = printf(join(query, '&'),
  364. \ s:encodeURIComponent(ext), s:encodeURIComponent(ext),
  365. \ s:encodeURIComponent(ext), s:encodeURIComponent(name),
  366. \ s:encodeURIComponent(ext), s:encodeURIComponent(a:content),
  367. \ s:encodeURIComponent(a:user),
  368. \ s:encodeURIComponent(a:token))
  369. unlet query
  370. let file = tempname()
  371. call writefile([squery], file)
  372. echon 'Updating it to gist... '
  373. let quote = &shellxquote == '"' ? "'" : '"'
  374. let url = 'https://gist.github.com/gists/'.a:gistid
  375. let res = system('curl -i '.g:gist_curl_options.' -d @'.quote.file.quote.' '.url)
  376. call delete(file)
  377. let headers = split(res, '\(\r\?\n\|\r\n\?\)')
  378. let location = matchstr(headers, '^Location: ')
  379. let location = substitute(location, '^[^:]\+: ', '', '')
  380. if len(location) > 0 && location =~ '^\(http\|https\):\/\/gist\.github\.com\/'
  381. setlocal nomodified
  382. redraw
  383. echo 'Done: '.location
  384. else
  385. let message = matchstr(headers, '^Status: ')
  386. let message = substitute(message, '^[^:]\+: [0-9]\+ ', '', '')
  387. echoerr 'Edit failed: '.message
  388. endif
  389. return location
  390. endfunction
  391. function! s:GistGetPage(url, user, param, opt)
  392. if !isdirectory(g:gist_cookie_dir)
  393. call mkdir(g:gist_cookie_dir, 'p')
  394. endif
  395. let cookie_file = g:gist_cookie_dir.'/github'
  396. if len(a:url) == 0
  397. call delete(cookie_file)
  398. return
  399. endif
  400. let quote = &shellxquote == '"' ? "'" : '"'
  401. if !filereadable(cookie_file)
  402. let password = inputsecret('Password:')
  403. if len(password) == 0
  404. echo 'Canceled'
  405. return
  406. endif
  407. let url = 'https://gist.github.com/login?return_to=gist'
  408. let res = system('curl -L -s '.g:gist_curl_options.' -c '.quote.cookie_file.quote.' '.quote.url.quote)
  409. let token = substitute(res, '^.* name="authenticity_token" type="hidden" value="\([^"]\+\)".*$', '\1', '')
  410. let query = [
  411. \ 'authenticity_token=%s',
  412. \ 'login=%s',
  413. \ 'password=%s',
  414. \ 'return_to=gist',
  415. \ 'commit=Log+in',
  416. \ ]
  417. let squery = printf(join(query, '&'),
  418. \ s:encodeURIComponent(token),
  419. \ s:encodeURIComponent(a:user),
  420. \ s:encodeURIComponent(password))
  421. unlet query
  422. let file = tempname()
  423. let command = 'curl -s '.g:gist_curl_options.' -i'
  424. let command .= ' -b '.quote.cookie_file.quote
  425. let command .= ' -c '.quote.cookie_file.quote
  426. let command .= ' '.quote.'https://gist.github.com/session'.quote
  427. let command .= ' -d @' . quote.file.quote
  428. call writefile([squery], file)
  429. let res = system(command)
  430. call delete(file)
  431. let res = matchstr(split(res, '\(\r\?\n\|\r\n\?\)'), '^Location: ')
  432. let res = substitute(res, '^[^:]\+: ', '', '')
  433. if len(res) == 0
  434. call delete(cookie_file)
  435. return ''
  436. endif
  437. endif
  438. let command = 'curl -s '.g:gist_curl_options.' -i '.a:opt
  439. if len(a:param)
  440. let command .= ' -d '.quote.a:param.quote
  441. endif
  442. let command .= ' -b '.quote.cookie_file.quote
  443. let command .= ' '.quote.a:url.quote
  444. let res = iconv(system(command), "utf-8", &encoding)
  445. let pos = stridx(res, "\r\n\r\n")
  446. if pos != -1
  447. let content = res[pos+4:]
  448. else
  449. let pos = stridx(res, "\n\n")
  450. let content = res[pos+2:]
  451. endif
  452. return {
  453. \ "header" : split(res[0:pos], '\r\?\n'),
  454. \ "content" : content
  455. \}
  456. endfunction
  457. function! s:GistDelete(user, token, gistid)
  458. echon 'Deleting gist... '
  459. let res = s:GistGetPage('https://gist.github.com/'.a:gistid, a:user, '', '')
  460. if (!len(res))
  461. echoerr 'Wrong password? no response received from github trying to delete ' . a:gistid
  462. return
  463. endif
  464. let mx = '^.* name="authenticity_token" type="hidden" value="\([^"]\+\)".*$'
  465. let token = substitute(matchstr(res.content, mx), mx, '\1', '')
  466. if len(token) > 0
  467. let res = s:GistGetPage('https://gist.github.com/delete/'.a:gistid, a:user, '_method=delete&authenticity_token='.token, '')
  468. if len(res.content) > 0
  469. redraw
  470. echo 'Done: '
  471. else
  472. let message = matchstr(res.header, '^Status: ')
  473. let message = substitute(message, '^[^:]\+: [0-9]\+ ', '', '')
  474. echoerr 'Delete failed: '.message
  475. endif
  476. else
  477. echoerr 'Delete failed'
  478. endif
  479. endfunction
  480. " GistPost function:
  481. " Post new gist to github
  482. "
  483. " if there is an embedded gist url or gist id in your file,
  484. " it will just update it.
  485. " -- by c9s
  486. "
  487. " embedded gist url format:
  488. "
  489. " Gist: https://gist.github.com/123123
  490. "
  491. " embedded gist id format:
  492. "
  493. " GistID: 123123
  494. "
  495. function! s:GistPost(user, token, content, private)
  496. " find GistID: in content, then we should just update
  497. for l in split(a:content, "\n")
  498. if l =~ '\<GistID:'
  499. let gistid = matchstr(l, 'GistID:\s*[0-9a-z]\+')
  500. if strlen(gistid) == 0
  501. echohl WarningMsg | echo "GistID error" | echohl None
  502. return
  503. endif
  504. echo "Found GistID: " . gistid
  505. cal s:GistUpdate(a:user, a:token, a:content, gistid, '')
  506. return
  507. elseif l =~ '\<Gist:'
  508. let gistid = matchstr(l, 'Gist:\s*https://gist.github.com/[0-9a-z]\+')
  509. if strlen(gistid) == 0
  510. echohl WarningMsg | echo "GistID error" | echohl None
  511. return
  512. endif
  513. echo "Found GistID: " . gistid
  514. cal s:GistUpdate(a:user, a:token, a:content, gistid, '')
  515. return
  516. endif
  517. endfor
  518. let ext = expand('%:e')
  519. let ext = len(ext) ? '.'.ext : ''
  520. let name = expand('%:t')
  521. let query = [
  522. \ 'file_ext[gistfile1]=%s',
  523. \ 'file_name[gistfile1]=%s',
  524. \ 'file_contents[gistfile1]=%s',
  525. \ ]
  526. if len(a:user) > 0 && len(a:token) > 0
  527. call add(query, 'login=%s')
  528. call add(query, 'token=%s')
  529. else
  530. call add(query, '%.0s%.0s')
  531. endif
  532. if a:private
  533. call add(query, 'action_button=private')
  534. endif
  535. let squery = printf(join(query, '&'),
  536. \ s:encodeURIComponent(ext),
  537. \ s:encodeURIComponent(name),
  538. \ s:encodeURIComponent(a:content),
  539. \ s:encodeURIComponent(a:user),
  540. \ s:encodeURIComponent(a:token))
  541. unlet query
  542. let file = tempname()
  543. call writefile([squery], file)
  544. echon 'Posting it to gist... '
  545. let quote = &shellxquote == '"' ? "'" : '"'
  546. let url = 'https://gist.github.com/gists'
  547. let res = system('curl -i '.g:gist_curl_options.' -d @'.quote.file.quote.' '.url)
  548. call delete(file)
  549. let headers = split(res, '\(\r\?\n\|\r\n\?\)')
  550. let location = matchstr(headers, '^Location: ')
  551. let location = substitute(location, '^[^:]\+: ', '', '')
  552. if len(location) > 0 && location =~ '^\(http\|https\):\/\/gist\.github\.com\/'
  553. redraw
  554. echo 'Done: '.location
  555. else
  556. let message = matchstr(headers, '^Status: ')
  557. let message = substitute(message, '^[^:]\+: [0-9]\+ ', '', '')
  558. echoerr 'Post failed: '.message
  559. endif
  560. return location
  561. endfunction
  562. function! s:GistPostBuffers(user, token, private)
  563. let bufnrs = range(1, bufnr("$"))
  564. let bn = bufnr('%')
  565. let query = []
  566. if len(a:user) > 0 && len(a:token) > 0
  567. call add(query, 'login=%s')
  568. call add(query, 'token=%s')
  569. else
  570. call add(query, '%.0s%.0s')
  571. endif
  572. if a:private
  573. call add(query, 'action_button=private')
  574. endif
  575. let squery = printf(join(query, "&"),
  576. \ s:encodeURIComponent(a:user),
  577. \ s:encodeURIComponent(a:token)) . '&'
  578. let query = [
  579. \ 'file_ext[gistfile]=%s',
  580. \ 'file_name[gistfile]=%s',
  581. \ 'file_contents[gistfile]=%s',
  582. \ ]
  583. let format = join(query, "&") . '&'
  584. let index = 1
  585. for bufnr in bufnrs
  586. if !bufexists(bufnr) || buflisted(bufnr) == 0
  587. continue
  588. endif
  589. echo "Creating gist content".index."... "
  590. silent! exec "buffer! ".bufnr
  591. let content = join(getline(1, line('$')), "\n")
  592. let ext = expand('%:e')
  593. let ext = len(ext) ? '.'.ext : ''
  594. let name = expand('%:t')
  595. let squery .= printf(substitute(format, 'gistfile', 'gistfile'.index, 'g'),
  596. \ s:encodeURIComponent(ext),
  597. \ s:encodeURIComponent(name),
  598. \ s:encodeURIComponent(content))
  599. let index = index + 1
  600. endfor
  601. silent! exec "buffer! ".bn
  602. let file = tempname()
  603. call writefile([squery], file)
  604. echo "Posting it to gist... "
  605. let quote = &shellxquote == '"' ? "'" : '"'
  606. let url = 'https://gist.github.com/gists'
  607. let res = system('curl -i '.g:gist_curl_options.' -d @'.quote.file.quote.' '.url)
  608. call delete(file)
  609. let res = matchstr(split(res, '\(\r\?\n\|\r\n\?\)'), '^Location: ')
  610. let res = substitute(res, '^.*: ', '', '')
  611. if len(res) > 0 && res =~ '^\(http\|https\):\/\/gist\.github\.com\/'
  612. redraw
  613. echo 'Done: '.res
  614. else
  615. echoerr 'Post failed'
  616. endif
  617. return res
  618. endfunction
  619. function! Gist(line1, line2, ...)
  620. if !exists('g:github_user')
  621. let g:github_user = substitute(system('git config --global github.user'), "\n", '', '')
  622. if strlen(g:github_user) == 0
  623. let g:github_user = $GITHUB_USER
  624. end
  625. endif
  626. if !exists('g:github_token')
  627. let g:github_token = substitute(system('git config --global github.token'), "\n", '', '')
  628. if strlen(g:github_token) == 0
  629. let g:github_token = $GITHUB_TOKEN
  630. end
  631. endif
  632. if strlen(g:github_user) == 0 || strlen(g:github_token) == 0
  633. echoerr "You have no setting for github."
  634. echohl WarningMsg
  635. echo "git config --global github.user your-name"
  636. echo "git config --global github.token your-token"
  637. echo "or set g:github_user and g:github_token in your vimrc"
  638. echo "or set shell env vars GITHUB_USER and GITHUB_TOKEN"
  639. echohl None
  640. return 0
  641. end
  642. let bufname = bufname("%")
  643. let user = g:github_user
  644. let token = g:github_token
  645. let gistid = ''
  646. let gistls = ''
  647. let gistnm = ''
  648. let private = g:gist_private
  649. let multibuffer = 0
  650. let clipboard = 0
  651. let deletepost = 0
  652. let editpost = 0
  653. let listmx = '^\(-l\|--list\)\s*\([^\s]\+\)\?$'
  654. let bufnamemx = '^' . s:bufprefix .'\([0-9a-f]\+\)$'
  655. let args = (a:0 > 0) ? split(a:1, ' ') : []
  656. for arg in args
  657. if arg =~ '^\(-la\|--listall\)$\C'
  658. let gistls = '-all'
  659. elseif arg =~ '^\(-l\|--list\)$\C'
  660. if g:gist_show_privates
  661. let gistls = 'mine'
  662. else
  663. let gistls = g:github_user
  664. endif
  665. elseif arg == '--abandon\C'
  666. call s:GistGetPage('', '', '', '')
  667. return
  668. elseif arg =~ '^\(-m\|--multibuffer\)$\C'
  669. let multibuffer = 1
  670. elseif arg =~ '^\(-p\|--private\)$\C'
  671. let private = 1
  672. elseif arg =~ '^\(-P\|--public\)$\C'
  673. let private = 0
  674. elseif arg =~ '^\(-a\|--anonymous\)$\C'
  675. let user = ''
  676. let token = ''
  677. elseif arg =~ '^\(-c\|--clipboard\)$\C'
  678. let clipboard = 1
  679. elseif arg =~ '^\(-d\|--delete\)$\C' && bufname =~ bufnamemx
  680. let deletepost = 1
  681. let gistid = substitute(bufname, bufnamemx, '\1', '')
  682. elseif arg =~ '^\(-e\|--edit\)$\C' && bufname =~ bufnamemx
  683. let editpost = 1
  684. let gistid = substitute(bufname, bufnamemx, '\1', '')
  685. elseif arg =~ '^\(-f\|--fork\)$\C' && bufname =~ bufnamemx
  686. let gistid = substitute(bufname, bufnamemx, '\1', '')
  687. let res = s:GistGetPage("https://gist.github.com/fork/".gistid, g:github_user, '', '')
  688. let loc = filter(res.header, 'v:val =~ "^Location:"')[0]
  689. let loc = substitute(loc, '^[^:]\+: ', '', '')
  690. let mx = '^https://gist.github.com/\([0-9a-z]\+\)$'
  691. if loc =~ mx
  692. let gistid = substitute(loc, mx, '\1', '')
  693. else
  694. echoerr 'Fork failed'
  695. return
  696. endif
  697. elseif arg !~ '^-' && len(gistnm) == 0
  698. if editpost == 1 || deletepost == 1
  699. let gistnm = arg
  700. elseif len(gistls) > 0 && arg != '^\w\+$\C'
  701. let gistls = arg
  702. elseif arg =~ '^[0-9a-z]\+$\C'
  703. let gistid = arg
  704. else
  705. echoerr 'Invalid arguments'
  706. unlet args
  707. return 0
  708. endif
  709. elseif len(arg) > 0
  710. echoerr 'Invalid arguments'
  711. unlet args
  712. return 0
  713. endif
  714. endfor
  715. unlet args
  716. "echo "gistid=".gistid
  717. "echo "gistls=".gistls
  718. "echo "gistnm=".gistnm
  719. "echo "private=".private
  720. "echo "clipboard=".clipboard
  721. "echo "editpost=".editpost
  722. "echo "deletepost=".deletepost
  723. if len(gistls) > 0
  724. call s:GistList(user, token, gistls, 1)
  725. elseif len(gistid) > 0 && editpost == 0 && deletepost == 0
  726. call s:GistGet(user, token, gistid, clipboard)
  727. else
  728. let url = ''
  729. if multibuffer == 1
  730. let url = s:GistPostBuffers(user, token, private)
  731. else
  732. let content = join(getline(a:line1, a:line2), "\n")
  733. if editpost == 1
  734. let url = s:GistUpdate(user, token, content, gistid, gistnm)
  735. elseif deletepost == 1
  736. call s:GistDelete(user, token, gistid)
  737. else
  738. let url = s:GistPost(user, token, content, private)
  739. endif
  740. endif
  741. if len(url) > 0
  742. if g:gist_open_browser_after_post
  743. let cmd = substitute(g:gist_browser_command, '%URL%', url, 'g')
  744. if cmd =~ '^!'
  745. silent! exec cmd
  746. elseif cmd =~ '^:[A-Z]'
  747. exec cmd
  748. else
  749. call system(cmd)
  750. endif
  751. endif
  752. if g:gist_put_url_to_clipboard_after_post > 0
  753. if g:gist_put_url_to_clipboard_after_post == 2
  754. let url = url . "\n"
  755. endif
  756. if exists('g:gist_clip_command')
  757. call system(g:gist_clip_command, url)
  758. elseif has('unix') && !has('xterm_clipboard')
  759. let @" = url
  760. else
  761. let @+ = url
  762. endif
  763. endif
  764. endif
  765. endif
  766. return 1
  767. endfunction
  768. command! -nargs=? -range=% Gist :call Gist(<line1>, <line2>, <f-args>)
  769. " vim:set et: