diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..351ae11 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: mattn # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/Makefile b/Makefile deleted file mode 100644 index 603a2fa..0000000 --- a/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all : gist-vim.zip - -remove-zip: - -rm doc/tags - -rm gist-vim.zip - -gist-vim.zip: remove-zip - zip -r gist-vim.zip autoload plugin doc - -release: gist-vim.zip - vimup update-script gist.vim diff --git a/README.mkd b/README.md similarity index 53% rename from README.mkd rename to README.md index c80b575..06f049f 100644 --- a/README.mkd +++ b/README.md @@ -1,8 +1,8 @@ -### Gist.vim +# Gist.vim This is a vimscript for creating gists (http://gist.github.com). -For the latest version please see https://github.com/mattn/gist-vim. +For the latest version please see https://github.com/mattn/vim-gist. ## Usage: @@ -48,8 +48,8 @@ For the latest version please see https://github.com/mattn/gist-vim. - Post/Edit with the description " (you need to have opened the gist buffer first). > - :Gist -s something - :Gist -e -s something + :Gist -s something + :Gist -e -s something - Delete the gist (you need to have opened the gist buffer first). Password authentication is needed. @@ -60,7 +60,7 @@ For the latest version please see https://github.com/mattn/gist-vim. Password authentication is needed. :Gist -f - + - Star the gist (you need to have opened the gist buffer first). Password authentication is needed. @@ -87,6 +87,10 @@ For the latest version please see https://github.com/mattn/gist-vim. :Gist -l mattn +- Specify the number of gists listed: + + :Gist -l -n 100 + - List everyone's gists. :Gist -la @@ -95,6 +99,40 @@ For the latest version please see https://github.com/mattn/gist-vim. :Gist -ls +- Open the gist on browser after you post or update it. + + :Gist -b + +## List Feature + +- Useful mappings on the gist-listing buffer: + - Both `o` or `Enter` open the gist file in a new buffer, and close the + vim-gist listing one. + - `b` opens the gist file in a browser; this is necessary because + `Shift-Enter` (as was originally) only works for GUI vim. + - `y` copies the contents of the selected gist to the clipboard, and + closes the vim-gist buffer. + - `p` pastes the contents of the selected gist to the buffer from where + vim-gist was called, and closes the vim-gist buffer. + - Hitting `Escape` or `Tab` at the vim-gist buffer closes it. + +- Gist listing has fixed-length columns now, more amenable to eye inspection. + Every line on the gist-listing buffer contains the gist id, name and + description, in that order. Columns are now padded and truncated to offer a + faster browsing, in the following way: + - The gist id string is fixed at 32 characters. + - The length (in characters) of the name of the gist is fixed and + can be set by the user using, for example: + + `let g:gistvim_namelength = 20` + + The default value for `gistvim_namelength` is 30. If the gist (file)name + exceeds that length, it is truncated to the specified length. + - Finally, the gist description is truncated in length to fit the remaining + of the line, avoiding wrapped lines that mess up the table layout. + - Note that the gist listing buffer now does not show the field 'code' + (not sure what that did in the first place). + ## Tips: If you set g:gist_clip_command, gist.vim will copy the gist code with option @@ -133,24 +171,30 @@ On windows, this should work with your user settings. If you want to show your private gists with ":Gist -l": let g:gist_show_privates = 1 - + If you want your gist to be private by default: - let g:gist_private = 1 + let g:gist_post_private = 1 + +If you want your gist to be anonymous by default: -If you get problems when creating gists try: + let g:gist_post_anonymous = 1 - :Gist --abandon +If you want to manipulate multiple files in a gist: -You need to either set global git config + let g:gist_get_multiplefile = 1 + +If you want to use on GitHub Enterprise: + + let g:gist_api_url = 'http://your-github-enterprise-domain/api/v3' + +You need to either set global git config: $ git config --global github.user Username -## Requirements: +If you want to list more than 30 gists per page (maximum is 100): -- curl command (http://curl.haxx.se/) -- webapi-vim (https://github.com/mattn/webapi-vim) -- and if you want to use your git profile, the git command-line client. + let g:gist_per_page_limit = 100 ## License: @@ -183,38 +227,63 @@ Copy it to your plugin directory. gist.vim will create a curl cookie-jar file in your runtimepath. - rtp: + - autoload/gist.vim - plugin/gist.vim - - cookies/github If you want to uninstall gist.vim, remember to also remove `~/.gist-vim`. -## Setup: +You need to install webapi-vim also: + + http://www.vim.org/scripts/script.php?script_id=4019 + +If you want to use latest one: + + https://github.com/mattn/webapi-vim + +### Install with [Vundle](https://github.com/gmarik/vundle) -This plugin uses github API v3. Setting value is stored in `~/.gist.vim`. -gist-vim have two ways to access APIs. +Add the following lines to your `.vimrc`. -### Basic Auth + Bundle 'mattn/webapi-vim' + Bundle 'mattn/vim-gist' -Require github user ID and password. This is easy but not secure. +Now restart Vim and run `:BundleInstall`. -### OAuth2 +### Install with [NeoBundle](https://github.com/Shougo/neobundle.vim) -1. Register your application. +Add the following line to your `.vimrc`. -Note that you must set `Callback URL` as same as following. + NeoBundle 'mattn/vim-gist', {'depends': 'mattn/webapi-vim'} + +## Requirements: + +- curl command (http://curl.haxx.se/) +- webapi-vim (https://github.com/mattn/webapi-vim) +- and if you want to use your git profile, the git command-line client. + +## Setup: -https://github.com/settings/applications/new +This plugin supports both basic and two-factor authentication using GitHub +API v3. The plugin stores its credentials in `~/.gist-vim`. -fill like following +First, you need to set your GitHub username in git's global configuration: -![](http://mattn.github.com/gist-vim/static/image/setting1.png) + $ git config --global github.user -2. Start `:Gist -l` +Then vim-gist will ask for your password in order to create an access +token. If you have two-factor authentication enabled, vim-gist will also +prompt you to enter the two-factor key you receive. -You'll see some prompts. fill ClientID/CilentSecret. Then you can see browser show up. +NOTE: +If you want you can set it directly to `g:github_user` and `g:gist_token`. -![](http://mattn.github.com/gist-vim/static/image/setting2.png) +Whichever type of authentication you use, your GitHub password will not be +stored, only a OAuth access token produced specifically for vim-gist. The +token is stored in `~/.gist-vim`. If you stop using the plugin, you can +easily remove this file. To revoke the associated GitHub token, go to the +list of ["Authorized applications" on GitHub's "Account Settings" +page][uas]. -This is a PIN code. +[uas]: https://github.com/settings/applications -Copy this value and paste to prompt `PIN:`. +**Note:** the username is optional if you only send anonymous gists. diff --git a/autoload/gist.vim b/autoload/gist.vim index 9fb26e2..1b9f04a 100644 --- a/autoload/gist.vim +++ b/autoload/gist.vim @@ -1,185 +1,185 @@ "============================================================================= " File: gist.vim " Author: Yasuhiro Matsumoto -" Last Change: 31-Mar-2012. -" Version: 6.0 -" WebPage: http://github.com/mattn/gist-vim +" Last Change: 10-Oct-2016. +" Version: 7.3 +" WebPage: http://github.com/mattn/vim-gist " License: BSD -" Usage: -" -" :Gist -" post current buffer to gist, using default privicy option -" (see g:gist_post_private) -" -" :'<,'>Gist -" post selected text to gist., using default privicy option -" This applies to all permutations listed below (except multi) -" (see g:gist_show_private) -" -" :Gist -p -" create a private gist -" -" :Gist -P -" create a public gist -" (only relevant if you've set gists to be private by default) -" -" :Gist -P -" post whole text to gist as public -" This is only relevant if you've set gists to be private by default -" :Gist -a -" create a gist anonymously -" -" :Gist -m -" create a gist with all open buffers -" -" :Gist -e -" edit the gist. (you need to have opend the gist buffer first) -" you can update the gist with :w command on gist buffer -" -" :Gist -d -" delete the gist. (you need to have opend the gist buffer first) -" password authentication is needed -" -" :Gist -f -" fork the gist. (you need to have opend the gist buffer first) -" password authentication is needed -" -" :Gist -e foo.js -" edit the gist with name 'foo.js'. (you need to have opend the gist buffer first) -" -" :Gist XXXXX -" get gist XXXXX -" -" :Gist -c XXXXX -" get gist XXXXX and add to clipboard -" -" :Gist -l -" list your public gists -" -" :Gist -l mattn -" list gists from mattn -" -" :Gist -la -" list all your (public and private) gists -" -" Tips: -" * if set g:gist_clip_command, gist.vim will copy the gist code -" with option '-c'. -" -" # mac -" let g:gist_clip_command = 'pbcopy' -" -" # linux -" let g:gist_clip_command = 'xclip -selection clipboard' -" -" # others(cygwin?) -" let g:gist_clip_command = 'putclip' -" -" * if you want to detect filetype from gist's filename... -" -" # detect filetype if vim failed auto-detection. -" let g:gist_detect_filetype = 1 -" -" # detect filetype always. -" let g:gist_detect_filetype = 2 -" -" * if you want to open browser after the post... -" -" let g:gist_open_browser_after_post = 1 -" -" * if you want to change the browser... -" -" let g:gist_browser_command = 'w3m %URL%' -" -" or -" -" let g:gist_browser_command = 'opera %URL% &' -" -" on windows, should work with original setting. -" -" * if you want to show your private gists with ':Gist -l' -" -" let g:gist_show_privates = 1 -" -" * if don't you want to copy URL of the post... -" -" let g:gist_put_url_to_clipboard_after_post = 0 -" -" or if you want to copy URL and add linefeed at the last of URL, -" -" let g:gist_put_url_to_clipboard_after_post = 2 -" -" default value is 1. -" -let s:save_cpo = &cpo -set cpo&vim +let s:save_cpo = &cpoptions +set cpoptions&vim + +if exists('g:gist_disabled') && g:gist_disabled == 1 + function! gist#Gist(...) abort + endfunction + finish +endif -function! s:get_browser_command() +if !exists('g:github_user') && !executable('git') + echohl ErrorMsg | echomsg 'Gist: require ''git'' command' | echohl None + finish +endif + +if !executable('curl') + echohl ErrorMsg | echomsg 'Gist: require ''curl'' command' | echohl None + finish +endif + +if globpath(&rtp, 'autoload/webapi/http.vim') ==# '' + echohl ErrorMsg | echomsg 'Gist: require ''webapi'', install https://github.com/mattn/webapi-vim' | echohl None + finish +else + call webapi#json#true() +endif + +let s:gist_token_file = expand(get(g:, 'gist_token_file', '~/.gist-vim')) +let s:system = function(get(g:, 'webapi#system_function', 'system')) + +if !exists('g:github_user') + let g:github_user = substitute(s:system('git config --get github.user'), "\n", '', '') + if strlen(g:github_user) == 0 + let g:github_user = $GITHUB_USER + end +endif + +if !exists('g:gist_api_url') + let g:gist_api_url = substitute(s:system('git config --get github.apiurl'), "\n", '', '') + if strlen(g:gist_api_url) == 0 + let g:gist_api_url = 'https://api.github.com/' + end + if exists('g:github_api_url') && !exists('g:gist_shutup_issue154') + if matchstr(g:gist_api_url, 'https\?://\zs[^/]\+\ze') != matchstr(g:github_api_url, 'https\?://\zs[^/]\+\ze') + echohl WarningMsg + echo '--- Warning ---' + echo 'It seems that you set different URIs for github_api_url/gist_api_url.' + echo 'If you want to remove this message: let g:gist_shutup_issue154 = 1' + echohl None + if confirm('Continue?', '&Yes\n&No') != 1 + let g:gist_disabled = 1 + finish + endif + redraw! + endif + endif +endif +if g:gist_api_url !~# '/$' + let g:gist_api_url .= '/' +endif + +if !exists('g:gist_update_on_write') + let g:gist_update_on_write = 1 +endif + +function! s:get_browser_command() abort let gist_browser_command = get(g:, 'gist_browser_command', '') - if gist_browser_command == '' + if gist_browser_command ==# '' if has('win32') || has('win64') - let gist_browser_command = "!start rundll32 url.dll,FileProtocolHandler %URL%" - elseif has('mac') - let gist_browser_command = "open %URL%" + let gist_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%' + elseif has('mac') || has('macunix') || has('gui_macvim') || system('uname') =~? '^darwin' + let gist_browser_command = 'open %URL%' elseif executable('xdg-open') - let gist_browser_command = "xdg-open %URL%" + let gist_browser_command = 'xdg-open %URL%' elseif executable('firefox') - let gist_browser_command = "firefox %URL% &" + let gist_browser_command = 'firefox %URL% &' else - let gist_browser_command = "" + let gist_browser_command = '' endif endif return gist_browser_command endfunction -function! s:open_browser(url) - let cmd = substitute(s:get_browser_command(), '%URL%', '\=a:url', 'g') +function! s:open_browser(url) abort + let cmd = s:get_browser_command() if len(cmd) == 0 + redraw echohl WarningMsg - echo "It seems that you don't have general web browser. Open URL below." + echo 'It seems that you don''t have general web browser. Open URL below.' echohl None + echo a:url return endif - if cmd =~ '^!' + let quote = &shellxquote == '"' ? "'" : '"' + if cmd =~# '^!' + let cmd = substitute(cmd, '%URL%', '\=quote.a:url.quote', 'g') silent! exec cmd - elseif cmd =~ '^:[A-Z]' + elseif cmd =~# '^:[A-Z]' + let cmd = substitute(cmd, '%URL%', '\=a:url', 'g') exec cmd else + let cmd = substitute(cmd, '%URL%', '\=quote.a:url.quote', 'g') call system(cmd) endif endfunction -function! s:shellwords(str) +function! s:shellwords(str) abort let words = split(a:str, '\%(\([^ \t\''"]\+\)\|''\([^\'']*\)''\|"\(\%([^\"\\]\|\\.\)*\)"\)\zs\s*\ze') let words = map(words, 'substitute(v:val, ''\\\([\\ ]\)'', ''\1'', "g")') let words = map(words, 'matchstr(v:val, ''^\%\("\zs\(.*\)\ze"\|''''\zs\(.*\)\ze''''\|.*\)$'')') return words endfunction -function! s:format_gist(gist) +function! s:truncate(str, num) + let mx_first = '^\(.\)\(.*\)$' + let str = a:str + let ret = '' + let width = 0 + while 1 + let char = substitute(str, mx_first, '\1', '') + let cells = strdisplaywidth(char) + if cells == 0 || width + cells > a:num + break + endif + let width = width + cells + let ret .= char + let str = substitute(str, mx_first, '\2', '') + endwhile + while width + 1 <= a:num + let ret .= ' ' + let width = width + 1 + endwhile + return ret +endfunction + +function! s:format_gist(gist) abort let files = sort(keys(a:gist.files)) + if empty(files) + return '' + endif let file = a:gist.files[files[0]] - if has_key(file, "content") + let name = file.filename + if has_key(file, 'content') let code = file.content let code = "\n".join(map(split(code, "\n"), '" ".v:val'), "\n") else - let code = "" + let code = '' endif - return printf("gist: %s %s%s", a:gist.id, type(a:gist.description)==0?"": a:gist.description, code) + let desc = type(a:gist.description)==0 || a:gist.description ==# '' ? '' : a:gist.description + let name = substitute(name, '[\r\n\t]', ' ', 'g') + let name = substitute(name, ' ', ' ', 'g') + let desc = substitute(desc, '[\r\n\t]', ' ', 'g') + let desc = substitute(desc, ' ', ' ', 'g') + " Display a nice formatted (and truncated if needed) table of gists on screen + " Calculate field lengths for gist-listing formatting on screen + redir =>a |exe 'sil sign place buffer='.bufnr('')|redir end + let signlist = split(a, '\n') + let width = winwidth(0) - ((&number||&relativenumber) ? &numberwidth : 0) - &foldcolumn - (len(signlist) > 2 ? 2 : 0) + let idlen = 33 + let namelen = get(g:, 'gist_namelength', 30) + let desclen = width - (idlen + namelen + 10) + return printf('gist: %s %s %s', s:truncate(a:gist.id, idlen), s:truncate(name, namelen), s:truncate(desc, desclen)) endfunction -" Note: A colon in the file name has side effects on Windows due to NTFS Alternate Data Streams; avoid it. +" Note: A colon in the file name has side effects on Windows due to NTFS Alternate Data Streams; avoid it. let s:bufprefix = 'gist' . (has('unix') ? ':' : '_') -function! s:GistList(gistls, page) - if a:gistls == '-all' - let url = 'https://api.github.com/gists/public' - elseif get(g:, 'gist_show_privates', 0) && a:gistls == 'starred' - let url = 'https://api.github.com/gists/starred' - elseif get(g:, 'gist_show_privates') && a:gistls == 'mine' - let url = 'https://api.github.com/gists' +function! s:GistList(gistls, page, pagelimit) abort + if a:gistls ==# '-all' + let url = g:gist_api_url.'gists/public' + elseif get(g:, 'gist_show_privates', 0) && a:gistls ==# 'starred' + let url = g:gist_api_url.'gists/starred' + elseif get(g:, 'gist_show_privates') && a:gistls ==# 'mine' + let url = g:gist_api_url.'gists' else - let url = 'https://api.github.com/users/'.a:gistls.'/gists' + let url = g:gist_api_url.'users/'.a:gistls.'/gists' endif let winnum = bufwinnr(bufnr(s:bufprefix.a:gistls)) if winnum != -1 @@ -188,11 +188,19 @@ function! s:GistList(gistls, page) endif setlocal modifiable else - exec 'silent noautocmd split' s:bufprefix.a:gistls + if get(g:, 'gist_list_vsplit', 0) + exec 'silent noautocmd vsplit +set\ winfixwidth ' s:bufprefix.a:gistls + elseif get(g:, 'gist_list_rightbelow', 0) + exec 'silent noautocmd rightbelow 5 split +set\ winfixheight ' s:bufprefix.a:gistls + else + exec 'silent noautocmd split' s:bufprefix.a:gistls + endif endif + + let url = url . '?per_page=' . a:pagelimit if a:page > 1 let oldlines = getline(0, line('$')) - let url = url . '?page=' . a:page + let url = url . '&page=' . a:page endif setlocal modifiable @@ -201,15 +209,32 @@ function! s:GistList(gistls, page) silent %d _ redraw | echon 'Listing gists... ' - let res = http#get(url, '', { "Authorization": s:GetAuthHeader() }) + let auth = s:GistGetAuthHeader() + if len(auth) == 0 + bw! + redraw + echohl ErrorMsg | echomsg v:errmsg | echohl None + return + endif + let res = webapi#http#get(url, '', { 'Authorization': auth }) if v:shell_error != 0 bw! redraw echohl ErrorMsg | echomsg 'Gists not found' | echohl None return endif + let content = webapi#json#decode(res.content) + if type(content) == 4 && has_key(content, 'message') && len(content.message) + bw! + redraw + echohl ErrorMsg | echomsg content.message | echohl None + if content.message ==# 'Bad credentials' + call delete(s:gist_token_file) + endif + return + endif - let lines = map(json#decode(res.content), 's:format_gist(v:val)') + let lines = map(filter(content, '!empty(v:val.files)'), 's:format_gist(v:val)') call setline(1, split(join(lines, "\n"), "\n")) $put='more...' @@ -217,10 +242,17 @@ function! s:GistList(gistls, page) let b:gistls = a:gistls let b:page = a:page setlocal buftype=nofile bufhidden=hide noswapfile + setlocal cursorline setlocal nomodified setlocal nomodifiable syntax match SpecialKey /^gist:/he=e-1 + syntax match Title /^gist: \S\+/hs=s+5 contains=ALL nnoremap :call GistListAction(0) + nnoremap o :call GistListAction(0) + nnoremap b :call GistListAction(1) + nnoremap y :call GistListAction(2) + nnoremap p :call GistListAction(3) + nnoremap :bw nnoremap :call GistListAction(1) cal cursor(1+len(oldlines),1) @@ -228,177 +260,387 @@ function! s:GistList(gistls, page) redraw | echo '' endfunction -function! s:GistGetFileName(gistid) - let res = http#get('https://api.github.com/gists/'.a:gistid, '', { "Authorization": s:GetAuthHeader() }) - let gist = json#decode(res.content) - return sort(keys(gist.files))[0] +function! gist#list_recursively(user, ...) abort + let use_cache = get(a:000, 0, 1) + let limit = get(a:000, 1, -1) + let verbose = get(a:000, 2, 1) + if a:user ==# 'mine' + let url = g:gist_api_url . 'gists' + elseif a:user ==# 'starred' + let url = g:gist_api_url . 'gists/starred' + else + let url = g:gist_api_url.'users/'.a:user.'/gists' + endif + + let auth = s:GistGetAuthHeader() + if len(auth) == 0 + " anonymous user cannot get gists to prevent infinite recursive loading + return [] + endif + + if use_cache && exists('g:gist_list_recursively_cache') + if has_key(g:gist_list_recursively_cache, a:user) + return webapi#json#decode(g:gist_list_recursively_cache[a:user]) + endif + endif + + let page = 1 + let gists = [] + let lastpage = -1 + + function! s:get_lastpage(res) abort + let links = split(a:res.header[match(a:res.header, 'Link')], ',') + let link = links[match(links, 'rel=[''"]last[''"]')] + let page = str2nr(matchlist(link, '\%(page=\)\(\d\+\)')[1]) + return page + endfunction + + if verbose > 0 + redraw | echon 'Loading gists...' + endif + + while limit == -1 || page <= limit + let res = webapi#http#get(url.'?page='.page, '', {'Authorization': auth}) + if limit == -1 + " update limit to the last page + let limit = s:get_lastpage(res) + endif + if verbose > 0 + redraw | echon 'Loading gists... ' . page . '/' . limit . ' pages has loaded.' + endif + let gists = gists + webapi#json#decode(res.content) + let page = page + 1 + endwhile + let g:gist_list_recursively_cache = get(g:, 'gist_list_recursively_cache', {}) + let g:gist_list_recursively_cache[a:user] = webapi#json#encode(gists) + return gists +endfunction + +function! gist#list(user, ...) abort + let page = get(a:000, 0, 0) + if a:user ==# '-all' + let url = g:gist_api_url.'gists/public' + elseif get(g:, 'gist_show_privates', 0) && a:user ==# 'starred' + let url = g:gist_api_url.'gists/starred' + elseif get(g:, 'gist_show_privates') && a:user ==# 'mine' + let url = g:gist_api_url.'gists' + else + let url = g:gist_api_url.'users/'.a:user.'/gists' + endif + + let auth = s:GistGetAuthHeader() + if len(auth) == 0 + return [] + endif + let res = webapi#http#get(url, '', { 'Authorization': auth }) + return webapi#json#decode(res.content) endfunction -function! s:GistDetectFiletype(gistid) - let res = http#get('https://api.github.com/gists/'.a:gistid, '', { "Authorization": s:GetAuthHeader() }) - let gist = json#decode(res.content) +function! s:GistGetFileName(gistid) abort + let auth = s:GistGetAuthHeader() + if len(auth) == 0 + return '' + endif + let res = webapi#http#get(g:gist_api_url.'gists/'.a:gistid, '', { 'Authorization': auth }) + let gist = webapi#json#decode(res.content) + if has_key(gist, 'files') + return sort(keys(gist.files))[0] + endif + return '' +endfunction + +function! s:GistDetectFiletype(gistid) abort + let auth = s:GistGetAuthHeader() + if len(auth) == 0 + return '' + endif + let res = webapi#http#get(g:gist_api_url.'gists/'.a:gistid, '', { 'Authorization': auth }) + let gist = webapi#json#decode(res.content) let filename = sort(keys(gist.files))[0] let ext = fnamemodify(filename, ':e') if has_key(s:extmap, ext) let type = s:extmap[ext] else - let type = get(gist.files[filename], "type", "text") + let type = get(gist.files[filename], 'type', 'text') endif - silent! exec "setlocal ft=".tolower(type) + silent! exec 'setlocal ft='.tolower(type) endfunction -function! s:GistWrite(fname) +function! s:GistWrite(fname) abort if substitute(a:fname, '\\', '/', 'g') == expand("%:p:gs@\\@/@") - Gist -e + if g:gist_update_on_write != 2 || v:cmdbang + Gist -e + else + echohl ErrorMsg | echomsg 'Please type ":w!" to update a gist.' | echohl None + endif else - exe "w".(v:cmdbang ? "!" : "") fnameescape(v:cmdarg) fnameescape(a:fname) - silent! exe "file" fnameescape(a:fname) + exe 'w'.(v:cmdbang ? '!' : '') fnameescape(v:cmdarg) fnameescape(a:fname) + silent! exe 'file' fnameescape(a:fname) silent! au! BufWriteCmd endif endfunction -function! s:GistGet(gistid, clipboard) - let winnum = bufwinnr(bufnr(s:bufprefix.a:gistid)) - if winnum != -1 - if winnum != bufwinnr('%') - exe winnum 'wincmd w' - endif - setlocal modifiable - else - exec 'silent noautocmd split' s:bufprefix.a:gistid - endif - let old_undolevels = &undolevels - set undolevels=-1 - filetype detect - silent %d _ - let res = http#get('https://api.github.com/gists/'.a:gistid, '', { "Authorization": s:GetAuthHeader() }) - let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*') - if status =~ '^2' - call writefile(split(res.content, "\n"), "myjson.js") +function! s:GistGet(gistid, clipboard) abort + redraw | echon 'Getting gist... ' + let res = webapi#http#get(g:gist_api_url.'gists/'.a:gistid, '', { 'Authorization': s:GistGetAuthHeader() }) + if res.status =~# '^2' try - let gist = json#decode(res.content) - let filename = sort(keys(gist.files))[0] - let content = gist.files[filename].content - call setline(1, split(content, "\n")) - let b:gist = { - \ "filename": filename, - \ "id": gist.id, - \ "description": gist.description, - \ "private": gist.public =~ 'true', - \} + let gist = webapi#json#decode(res.content) catch - let &undolevels = old_undolevels - bw! redraw - echohl ErrorMsg | echomsg 'Gist contains binary' | echohl None + echohl ErrorMsg | echomsg 'Gist seems to be broken' | echohl None return endtry + if get(g:, 'gist_get_multiplefile', 0) != 0 + let num_file = len(keys(gist.files)) + else + let num_file = 1 + endif + redraw + if num_file > len(keys(gist.files)) + echohl ErrorMsg | echomsg 'Gist not found' | echohl None + return + endif + augroup GistWrite + au! + augroup END + for n in range(num_file) + try + let old_undolevels = &undolevels + let filename = sort(keys(gist.files))[n] + + let winnum = bufwinnr(bufnr(s:bufprefix.a:gistid.'/'.filename)) + if winnum != -1 + if winnum != bufwinnr('%') + exe winnum 'wincmd w' + endif + setlocal modifiable + else + if num_file == 1 + if get(g:, 'gist_edit_with_buffers', 0) + let found = -1 + for wnr in range(1, winnr('$')) + let bnr = winbufnr(wnr) + if bnr != -1 && !empty(getbufvar(bnr, 'gist')) + let found = wnr + break + endif + endfor + if found != -1 + exe found 'wincmd w' + setlocal modifiable + else + if get(g:, 'gist_list_vsplit', 0) + exec 'silent noautocmd rightbelow vnew' + else + exec 'silent noautocmd rightbelow new' + endif + endif + else + silent only! + if get(g:, 'gist_list_vsplit', 0) + exec 'silent noautocmd rightbelow vnew' + else + exec 'silent noautocmd rightbelow new' + endif + endif + else + if get(g:, 'gist_list_vsplit', 0) + exec 'silent noautocmd rightbelow vnew' + else + exec 'silent noautocmd rightbelow new' + endif + endif + setlocal noswapfile + silent exec 'noautocmd file' s:bufprefix.a:gistid.'/'.fnameescape(filename) + endif + set undolevels=-1 + filetype detect + silent %d _ + + let content = gist.files[filename].content + call setline(1, split(content, "\n")) + let b:gist = { + \ 'filename': filename, + \ 'id': gist.id, + \ 'description': gist.description, + \ 'private': gist.public =~# 'true', + \} + catch + let &undolevels = old_undolevels + bw! + redraw + echohl ErrorMsg | echomsg 'Gist contains binary' | echohl None + return + endtry + let &undolevels = old_undolevels + setlocal buftype=acwrite bufhidden=hide noswapfile + setlocal nomodified + doau StdinReadPost,BufRead,BufReadPost + let gist_detect_filetype = get(g:, 'gist_detect_filetype', 0) + if (&ft ==# '' && gist_detect_filetype == 1) || gist_detect_filetype == 2 + call s:GistDetectFiletype(a:gistid) + endif + if a:clipboard + if exists('g:gist_clip_command') + exec 'silent w !'.g:gist_clip_command + elseif has('clipboard') + silent! %yank + + else + %yank + endif + endif + 1 + augroup GistWrite + au! BufWriteCmd call s:GistWrite(expand("")) + augroup END + endfor else - let &undolevels = old_undolevels bw! redraw echohl ErrorMsg | echomsg 'Gist not found' | echohl None return endif - let &undolevels = old_undolevels - setlocal buftype=acwrite bufhidden=delete noswapfile - setlocal nomodified - doau StdinReadPost - let gist_detect_filetype = get(g:, 'gist_detect_filetype', 0) - if (&ft == '' && gist_detect_filetype == 1) || gist_detect_filetype == 2 - call s:GistDetectFiletype(a:gistid) - endif - if a:clipboard - if exists('g:gist_clip_command') - exec 'silent w !'.g:gist_clip_command - elseif has('clipboard') - silent! %yank + - else - %yank - endif - endif - 1 - au! BufWriteCmd call s:GistWrite(expand("")) endfunction -function! s:GistListAction(shift) +function! s:GistListAction(mode) abort let line = getline('.') let mx = '^gist:\s*\zs\(\w\+\)\ze.*' if line =~# mx let gistid = matchstr(line, mx) - if a:shift - call s:open_browser("https://gist.github.com/" . gistid) - else + if a:mode == 1 + call s:open_browser('https://gist.github.com/' . gistid) + elseif a:mode == 0 call s:GistGet(gistid, 0) + wincmd w + bw + elseif a:mode == 2 + call s:GistGet(gistid, 1) + " TODO close with buffe rname + bdelete + bdelete + elseif a:mode == 3 + call s:GistGet(gistid, 1) + " TODO close with buffe rname + bdelete + bdelete + normal! "+p endif return endif if line =~# '^more\.\.\.$' - call s:GistList(b:gistls, b:page+1) + call s:GistList(b:gistls, b:page+1, g:gist_per_page_limit) return endif endfunction -function! s:GistUpdate(content, gistid, gistnm, desc) - let gist = { "id": a:gistid, "files" : {}, "description": "","public": function('json#true') } - if a:desc != ' ' | let gist["description"] = a:desc | endif - if has('b:gist') && b:gist.private | let gist["public"] = function('json#false') | endif - let filename = a:gistnm - if exists('b:gistnm') > 0 - let filename = b:gistnm - elseif len(a:gistnm) == 0 - let filename = s:GistGetFileName(a:gistid) - endif - if len(filename) == 0 - let filename = s:get_current_filename(1) +function! s:GistUpdate(content, gistid, gistnm, desc) abort + let gist = { 'id': a:gistid, 'files' : {}, 'description': '','public': function('webapi#json#true') } + if exists('b:gist') + if has_key(b:gist, 'filename') && len(a:gistnm) > 0 + let gist.files[b:gist.filename] = { 'content': '', 'filename': b:gist.filename } + let b:gist.filename = a:gistnm + endif + if has_key(b:gist, 'private') && b:gist.private | let gist['public'] = function('webapi#json#false') | endif + if has_key(b:gist, 'description') | let gist['description'] = b:gist.description | endif + if has_key(b:gist, 'filename') | let filename = b:gist.filename | endif + else + let filename = a:gistnm + if len(filename) == 0 | let filename = s:GistGetFileName(a:gistid) | endif + if len(filename) == 0 | let filename = s:get_current_filename(1) | endif endif - let gist.files[filename] = { "content": a:content, "filename": filename } - redraw | echon 'Posting it to gist... ' - let res = http#post('https://api.github.com/gists/' . a:gistid, - \ json#encode(gist), { "Authorization": s:GetAuthHeader() }) - let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*') - if status =~ '^2' - let obj = json#decode(res.content) - let loc = obj["html_url"] + let auth = s:GistGetAuthHeader() + if len(auth) == 0 redraw - echomsg 'Done: '.loc - let b:gist = {"id": a:gistid, "filename": filename} + echohl ErrorMsg | echomsg v:errmsg | echohl None + return + endif + + " Update description + " If no new description specified, keep the old description + if a:desc !=# ' ' + let gist['description'] = a:desc + else + let res = webapi#http#get(g:gist_api_url.'gists/'.a:gistid, '', { 'Authorization': auth }) + if res.status =~# '^2' + let old_gist = webapi#json#decode(res.content) + let gist['description'] = old_gist.description + endif + endif + + let gist.files[filename] = { 'content': a:content, 'filename': filename } + + redraw | echon 'Updating gist... ' + let res = webapi#http#post(g:gist_api_url.'gists/' . a:gistid, + \ webapi#json#encode(gist), { + \ 'Authorization': auth, + \ 'Content-Type': 'application/json', + \}) + if res.status =~# '^2' + let obj = webapi#json#decode(res.content) + let loc = obj['html_url'] + let b:gist = {'id': a:gistid, 'filename': filename} + setlocal nomodified + redraw | echomsg 'Done: '.loc else let loc = '' - let status = matchstr(status, '^\d\+\s*\zs.*') - echohl ErrorMsg | echomsg 'Post failed: '.status | echohl None + echohl ErrorMsg | echomsg 'Post failed: ' . res.message | echohl None endif return loc endfunction -function! s:GistDelete(gistid) - redraw | echon 'Deleting to gist... ' - let res = http#post('https://api.github.com/gists/'.a:gistid, '', { "Authorization": s:GetAuthHeader() }, 'DELETE') - let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*') - if status =~ '^2' +function! s:GistDelete(gistid) abort + let auth = s:GistGetAuthHeader() + if len(auth) == 0 + redraw + echohl ErrorMsg | echomsg v:errmsg | echohl None + return + endif + + redraw | echon 'Deleting gist... ' + let res = webapi#http#post(g:gist_api_url.'gists/'.a:gistid, '', { + \ 'Authorization': auth, + \ 'Content-Type': 'application/json', + \}, 'DELETE') + if res.status =~# '^2' + if exists('b:gist') + unlet b:gist + endif redraw | echomsg 'Done: ' - unlet b:gist else - let status = matchstr(status, '^\d\+\s*\zs.*') - echohl ErrorMsg | echomsg 'Delete failed: '.status | echohl None + echohl ErrorMsg | echomsg 'Delete failed: ' . res.message | echohl None endif endfunction -function! s:get_current_filename(no) +function! s:get_current_filename(no) abort let filename = expand('%:t') - if len(filename) == 0 && &ft != '' - let pair = filter(items(s:extmap), 'v:val[1] == "ruby"') + if len(filename) == 0 && &ft !=# '' + let pair = filter(items(s:extmap), 'v:val[1] == &ft') if len(pair) > 0 let filename = printf('gistfile%d%s', a:no, pair[0][0]) endif endif - if filename == '' + if filename ==# '' let filename = printf('gistfile%d.txt', a:no) endif return filename endfunction +function! s:update_GistID(id) abort + let view = winsaveview() + normal! gg + let ret = 0 + if search('\:\s*$') + let line = getline('.') + let line = substitute(line, '\s\+$', '', 'g') + call setline('.', line . ' ' . a:id) + let ret = 1 + endif + call winrestview(view) + return ret +endfunction + " GistPost function: " Post new gist to github " @@ -406,94 +648,110 @@ endfunction " it will just update it. " -- by c9s " -" embedded gist url format: -" -" Gist: https://gist.github.com/123123 -" " embedded gist id format: " " GistID: 123123 " -function! s:GistPost(content, private, desc, anonymous) - let gist = { "files" : {}, "description": "","public": function('json#true') } - if a:desc != ' ' | let gist["description"] = a:desc | endif - if a:private | let gist["public"] = function('json#false') | endif +function! s:GistPost(content, private, desc, anonymous) abort + let gist = { 'files' : {}, 'description': '','public': function('webapi#json#true') } + if a:desc !=# ' ' | let gist['description'] = a:desc | endif + if a:private | let gist['public'] = function('webapi#json#false') | endif let filename = s:get_current_filename(1) - let gist.files[filename] = { "content": a:content, "filename": filename } + let gist.files[filename] = { 'content': a:content, 'filename': filename } + + let header = {'Content-Type': 'application/json'} + if !a:anonymous + let auth = s:GistGetAuthHeader() + if len(auth) == 0 + redraw + echohl ErrorMsg | echomsg v:errmsg | echohl None + return + endif + let header['Authorization'] = auth + endif redraw | echon 'Posting it to gist... ' - let auth = a:anonymous ? {} : { "Authorization": s:GetAuthHeader() } - let res = http#post('https://api.github.com/gists', json#encode(gist), auth) - let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*') - if status =~ '^2' - let obj = json#decode(res.content) - let loc = obj["html_url"] - redraw - echomsg 'Done: '.loc + let res = webapi#http#post(g:gist_api_url.'gists', webapi#json#encode(gist), header) + if res.status =~# '^2' + let obj = webapi#json#decode(res.content) + let loc = obj['html_url'] let b:gist = { - \ "filename": filename, - \ "id": matchstr(loc, '[^/]\+$'), - \ "description": gist['description'], - \ "private": a:private, + \ 'filename': filename, + \ 'id': matchstr(loc, '[^/]\+$'), + \ 'description': gist['description'], + \ 'private': a:private, \} + if s:update_GistID(b:gist['id']) + Gist -e + endif + redraw | echomsg 'Done: '.loc else let loc = '' - let status = matchstr(status, '^\d\+\s*\zs.*') - echohl ErrorMsg | echomsg 'Post failed: '.status | echohl None + echohl ErrorMsg | echomsg 'Post failed: '. res.message | echohl None endif return loc endfunction -function! s:GistPostBuffers(private, desc, anonymous) - let bufnrs = range(1, bufnr("$")) +function! s:GistPostBuffers(private, desc, anonymous) abort + let bufnrs = range(1, bufnr('$')) let bn = bufnr('%') let query = [] - let gist = { "files" : {}, "description": "","public": function('json#true') } - if a:desc != ' ' | let gist["description"] = a:desc | endif - if a:private | let gist["public"] = function('json#false') | endif + let gist = { 'files' : {}, 'description': '','public': function('webapi#json#true') } + if a:desc !=# ' ' | let gist['description'] = a:desc | endif + if a:private | let gist['public'] = function('webapi#json#false') | endif let index = 1 for bufnr in bufnrs if !bufexists(bufnr) || buflisted(bufnr) == 0 continue endif - echo "Creating gist content".index."... " - silent! exec "buffer!" bufnr + echo 'Creating gist content'.index.'... ' + silent! exec 'buffer!' bufnr let content = join(getline(1, line('$')), "\n") let filename = s:get_current_filename(index) - let gist.files[filename] = { "content": content, "filename": filename } + let gist.files[filename] = { 'content': content, 'filename': filename } let index = index + 1 endfor - silent! exec "buffer!" bn + silent! exec 'buffer!' bn + + let header = {'Content-Type': 'application/json'} + if !a:anonymous + let auth = s:GistGetAuthHeader() + if len(auth) == 0 + redraw + echohl ErrorMsg | echomsg v:errmsg | echohl None + return + endif + let header['Authorization'] = auth + endif redraw | echon 'Posting it to gist... ' - let auth = a:anonymous ? {} : { "Authorization": s:GetAuthHeader() } - let res = http#post('https://api.github.com/gists', json#encode(gist), auth) - let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*') - if status =~ '^2' - let obj = json#decode(res.content) - let loc = obj["html_url"] - redraw - echomsg 'Done: '.loc - let b:gist = {"id": matchstr(loc, '[^/]\+$'), "filename": filename, "private": a:private} + let res = webapi#http#post(g:gist_api_url.'gists', webapi#json#encode(gist), header) + if res.status =~# '^2' + let obj = webapi#json#decode(res.content) + let loc = obj['html_url'] + let b:gist = { + \ 'filename': filename, + \ 'id': matchstr(loc, '[^/]\+$'), + \ 'description': gist['description'], + \ 'private': a:private, + \} + if s:update_GistID(b:gist['id']) + Gist -e + endif + redraw | echomsg 'Done: '.loc else let loc = '' - let status = matchstr(status, '^\d\+\s*\zs.*') - echohl ErrorMsg | echomsg 'Post failed: '.status | echohl None + echohl ErrorMsg | echomsg 'Post failed: ' . res.message | echohl None endif return loc endfunction -function! gist#Gist(count, line1, line2, ...) +function! gist#Gist(count, bang, line1, line2, ...) abort redraw - if !exists('g:github_user') - let g:github_user = substitute(system('git config --global github.user'), "\n", '', '') - if strlen(g:github_user) == 0 - let g:github_user = $GITHUB_USER - end - endif - let bufname = bufname("%") + let bufname = bufname('%') + " find GistID: in content , then we should just update let gistid = '' let gistls = '' let gistnm = '' @@ -503,102 +761,170 @@ function! gist#Gist(count, line1, line2, ...) let clipboard = 0 let deletepost = 0 let editpost = 0 - let anonymous = 0 + let anonymous = get(g:, 'gist_post_anonymous', 0) + let openbrowser = 0 + let setpagelimit = 0 + let pagelimit = g:gist_per_page_limit let listmx = '^\%(-l\|--list\)\s*\([^\s]\+\)\?$' - let bufnamemx = '^' . s:bufprefix .'\zs\([0-9a-f]\+\)\ze$' + let bufnamemx = '^' . s:bufprefix .'\(\zs[0-9a-f]\+\ze\|\zs[0-9a-f]\+\ze[/\\].*\)$' + if strlen(g:github_user) == 0 && anonymous == 0 + echohl ErrorMsg | echomsg 'You have not configured a Github account. Read '':help gist-setup''.' | echohl None + return + endif + if a:bang == '!' + let gistidbuf = '' + elseif bufname =~# bufnamemx + let gistidbuf = matchstr(bufname, bufnamemx) + elseif exists('b:gist') && has_key(b:gist, 'id') + let gistidbuf = b:gist['id'] + else + let gistidbuf = matchstr(join(getline(a:line1, a:line2), "\n"), 'GistID:\s*\zs\w\+') + endif let args = (a:0 > 0) ? s:shellwords(a:1) : [] for arg in args - if arg =~ '^\(-la\|--listall\)$\C' + if arg =~# '^\(-h\|--help\)$\C' + help :Gist + return + elseif arg =~# '^\(-g\|--git\)$\C' && gistidbuf !=# '' && g:gist_api_url ==# 'https://api.github.com/' && has_key(b:, 'gist') && has_key(b:gist, 'id') + echo printf('git clone git@github.com:%s', b:gist['id']) + return + elseif arg =~# '^\(-G\|--gitclone\)$\C' && gistidbuf !=# '' && g:gist_api_url ==# 'https://api.github.com/' && has_key(b:, 'gist') && has_key(b:gist, 'id') + exe '!' printf('git clone git@github.com:%s', b:gist['id']) + return + elseif setpagelimit == 1 + let setpagelimit = 0 + let pagelimit = str2nr(arg) + if pagelimit < 1 || pagelimit > 100 + echohl ErrorMsg | echomsg 'Page limit should be between 1 and 100: '.arg | echohl None + unlet args + return 0 + endif + elseif arg =~# '^\(-la\|--listall\)$\C' let gistls = '-all' - elseif arg =~ '^\(-ls\|--liststar\)$\C' + elseif arg =~# '^\(-ls\|--liststar\)$\C' let gistls = 'starred' - elseif arg =~ '^\(-l\|--list\)$\C' + elseif arg =~# '^\(-l\|--list\)$\C' if get(g:, 'gist_show_privates') let gistls = 'mine' else let gistls = g:github_user endif - elseif arg =~ '^\(-m\|--multibuffer\)$\C' + elseif arg =~# '^\(-m\|--multibuffer\)$\C' let multibuffer = 1 - elseif arg =~ '^\(-p\|--private\)$\C' + elseif arg =~# '^\(-p\|--private\)$\C' let private = 1 - elseif arg =~ '^\(-P\|--public\)$\C' + elseif arg =~# '^\(-P\|--public\)$\C' let private = 0 - elseif arg =~ '^\(-a\|--anonymous\)$\C' + elseif arg =~# '^\(-a\|--anonymous\)$\C' let anonymous = 1 - elseif arg =~ '^\(-s\|--description\)$\C' + elseif arg =~# '^\(-s\|--description\)$\C' let gistdesc = '' - elseif arg =~ '^\(-c\|--clipboard\)$\C' + elseif arg =~# '^\(-c\|--clipboard\)$\C' let clipboard = 1 - elseif arg =~ '^\(-d\|--delete\)$\C' && bufname =~ bufnamemx + elseif arg =~# '^--rawurl$\C' && gistidbuf !=# '' && g:gist_api_url ==# 'https://api.github.com/' + let gistid = gistidbuf + echo 'https://gist.github.com/raw/'.gistid + return + elseif arg =~# '^\(-d\|--delete\)$\C' && gistidbuf !=# '' + let gistid = gistidbuf let deletepost = 1 - let gistid = matchstr(bufname, bufnamemx) - elseif arg =~ '^\(-e\|--edit\)$\C' && bufname =~ bufnamemx + elseif arg =~# '^\(-e\|--edit\)$\C' + if gistidbuf !=# '' + let gistid = gistidbuf + endif let editpost = 1 - let gistid = matchstr(bufname, bufnamemx) - elseif arg =~ '^\(+1\|--star\)$\C' && bufname =~ bufnamemx - let gistid = matchstr(bufname, bufnamemx) - let res = http#post('https://api.github.com/gists/'.gistid.'/star', '', { "Authorization": s:GetAuthHeader() }, 'PUT') - let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*') - if status =~ '^2' - echomsg "Stared" gistid + elseif arg =~# '^\(+1\|--star\)$\C' && gistidbuf !=# '' + let auth = s:GistGetAuthHeader() + if len(auth) == 0 + echohl ErrorMsg | echomsg v:errmsg | echohl None else - echohl ErrorMsg | echomsg 'Star failed' | echohl None + let gistid = gistidbuf + let res = webapi#http#post(g:gist_api_url.'gists/'.gistid.'/star', '', { 'Authorization': auth }, 'PUT') + if res.status =~# '^2' + echomsg 'Starred' gistid + else + echohl ErrorMsg | echomsg 'Star failed' | echohl None + endif endif return - elseif arg =~ '^\(-1\|--unstar\)$\C' && bufname =~ bufnamemx - let gistid = matchstr(bufname, bufnamemx) - let res = http#post('https://api.github.com/gists/'.gistid.'/star', '', { "Authorization": s:GetAuthHeader() }, 'DELETE') - if status =~ '^2' - echomsg "Unstared" gistid + elseif arg =~# '^\(-1\|--unstar\)$\C' && gistidbuf !=# '' + let auth = s:GistGetAuthHeader() + if len(auth) == 0 + echohl ErrorMsg | echomsg v:errmsg | echohl None else - echohl ErrorMsg | echomsg 'Unstar failed' | echohl None + let gistid = gistidbuf + let res = webapi#http#post(g:gist_api_url.'gists/'.gistid.'/star', '', { 'Authorization': auth }, 'DELETE') + if res.status =~# '^2' + echomsg 'Unstarred' gistid + else + echohl ErrorMsg | echomsg 'Unstar failed' | echohl None + endif endif return - elseif arg =~ '^\(-f\|--fork\)$\C' && bufname =~ bufnamemx - let gistid = matchstr(bufname, bufnamemx) - let res = http#post('https://api.github.com/gists/'.gistid.'/fork', '', { "Authorization": s:GetAuthHeader() }) - let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*') - if status =~ '^2' - let obj = json#decode(res.content) - let gistid = obj["id"] - else - echohl ErrorMsg | echomsg 'Fork failed' | echohl None + elseif arg =~# '^\(-f\|--fork\)$\C' && gistidbuf !=# '' + let auth = s:GistGetAuthHeader() + if len(auth) == 0 + echohl ErrorMsg | echomsg v:errmsg | echohl None return + else + let gistid = gistidbuf + let res = webapi#http#post(g:gist_api_url.'gists/'.gistid.'/fork', '', { 'Authorization': auth }) + if res.status =~# '^2' + let obj = webapi#json#decode(res.content) + let gistid = obj['id'] + else + echohl ErrorMsg | echomsg 'Fork failed' | echohl None + return + endif + endif + elseif arg =~# '^\(-b\|--browser\)$\C' + let openbrowser = 1 + elseif arg =~# '^\(-n\|--per-page\)$\C' + if len(gistls) > 0 + let setpagelimit = 1 + else + echohl ErrorMsg | echomsg 'Page limit can be set only for list commands'.arg | echohl None + unlet args + return 0 endif - elseif arg !~ '^-' && len(gistnm) == 0 - if gistdesc != ' ' + elseif arg !~# '^-' && len(gistnm) == 0 + if gistdesc !=# ' ' let gistdesc = matchstr(arg, '^\s*\zs.*\ze\s*$') elseif editpost == 1 || deletepost == 1 let gistnm = arg - elseif len(gistls) > 0 && arg != '^\w\+$\C' + elseif len(gistls) > 0 && arg !=# '^\w\+$\C' let gistls = arg - elseif arg =~ '^[0-9a-z]\+$\C' + elseif arg =~# '^[0-9a-z]\+$\C' let gistid = arg else - echohl ErrorMsg | echomsg 'Invalid arguments' | echohl None + echohl ErrorMsg | echomsg 'Invalid arguments: '.arg | echohl None unlet args return 0 endif elseif len(arg) > 0 - echohl ErrorMsg | echomsg 'Invalid arguments' | echohl None + echohl ErrorMsg | echomsg 'Invalid arguments: '.arg | echohl None unlet args return 0 endif endfor unlet args - "echo "gistid=".gistid - "echo "gistls=".gistls - "echo "gistnm=".gistnm - "echo "gistdesc=".gistdesc - "echo "private=".private - "echo "clipboard=".clipboard - "echo "editpost=".editpost - "echo "deletepost=".deletepost + "echom "gistid=".gistid + "echom "gistls=".gistls + "echom "gistnm=".gistnm + "echom "gistdesc=".gistdesc + "echom "private=".private + "echom "clipboard=".clipboard + "echom "editpost=".editpost + "echom "deletepost=".deletepost + + if gistidbuf !=# '' && gistid ==# '' && editpost == 0 && deletepost == 0 && anonymous == 0 + let editpost = 1 + let gistid = gistidbuf + endif if len(gistls) > 0 - call s:GistList(gistls, 1) + call s:GistList(gistls, 1, pagelimit) elseif len(gistid) > 0 && editpost == 0 && deletepost == 0 call s:GistGet(gistid, clipboard) else @@ -626,21 +952,21 @@ function! gist#Gist(count, line1, line2, ...) silent! normal! gv endif endif - if len(url) > 0 - if get(g:, 'gist_open_browser_after_post', 0) == 1 + if type(url) == 1 && len(url) > 0 + if get(g:, 'gist_open_browser_after_post', 0) == 1 || openbrowser call s:open_browser(url) endif let gist_put_url_to_clipboard_after_post = get(g:, 'gist_put_url_to_clipboard_after_post', 1) - if gist_put_url_to_clipboard_after_post > 0 + if gist_put_url_to_clipboard_after_post > 0 || clipboard if gist_put_url_to_clipboard_after_post == 2 let url = url . "\n" endif if exists('g:gist_clip_command') call system(g:gist_clip_command, url) - elseif has('unix') && !has('xterm_clipboard') - let @" = url - else + elseif has('clipboard') let @+ = url + else + let @" = url endif endif endif @@ -648,11 +974,17 @@ function! gist#Gist(count, line1, line2, ...) return 1 endfunction -function! s:GetAuthHeader() - let auth = "" - let configfile = expand('~/.gist-vim') - if filereadable(configfile) - let str = join(readfile(configfile), "") +function! s:GistGetAuthHeader() abort + if get(g:, 'gist_use_password_in_gitconfig', 0) != 0 + let password = substitute(system('git config --get github.password'), "\n", '', '') + if password =~# '^!' | let password = system(password[1:]) | endif + return printf('basic %s', webapi#base64#b64encode(g:github_user.':'.password)) + endif + let auth = '' + if !empty(get(g:, 'gist_token', $GITHUB_TOKEN)) + let auth = 'token ' . get(g:, 'gist_token', $GITHUB_TOKEN) + elseif filereadable(s:gist_token_file) + let str = join(readfile(s:gist_token_file), '') if type(str) == 1 let auth = str endif @@ -661,184 +993,191 @@ function! s:GetAuthHeader() return auth endif + redraw echohl WarningMsg - echo 'Gist.vim need autholization to github API. This settings are stored in "~/.gist-vim". If you want to revoke, do "rm ~/.gist-vim".' - echohl ErrorMsg - echo 'Note to do "chmod 600 ~/.gist-vim" after this settings.' + echo 'Gist.vim requires authorization to use the GitHub API. These settings are stored in "~/.gist-vim". If you want to revoke, do "rm ~/.gist-vim".' echohl None - let api = inputlist(['Which API:', '1. basic auth', '2. oauth2']) - if api == 1 - if !exists('g:github_user') - let g:github_user = substitute(system('git config --global github.user'), "\n", '', '') - if strlen(g:github_user) == 0 - let g:github_user = $GITHUB_USER - end + let password = inputsecret('GitHub Password for '.g:github_user.':') + if len(password) == 0 + let v:errmsg = 'Canceled' + return '' + endif + let note = 'Gist.vim on '.hostname().' '.strftime('%Y/%m/%d-%H:%M:%S') + let note_url = 'http://www.vim.org/scripts/script.php?script_id=2423' + let insecureSecret = printf('basic %s', webapi#base64#b64encode(g:github_user.':'.password)) + let res = webapi#http#post(g:gist_api_url.'authorizations', webapi#json#encode({ + \ 'scopes' : ['gist'], + \ 'note' : note, + \ 'note_url' : note_url, + \}), { + \ 'Content-Type' : 'application/json', + \ 'Authorization' : insecureSecret, + \}) + let h = filter(res.header, 'stridx(v:val, "X-GitHub-OTP:") == 0') + if len(h) + let otp = inputsecret('OTP:') + if len(otp) == 0 + let v:errmsg = 'Canceled' + return '' + endif + let res = webapi#http#post(g:gist_api_url.'authorizations', webapi#json#encode({ + \ 'scopes' : ['gist'], + \ 'note' : note, + \ 'note_url' : note_url, + \}), { + \ 'Content-Type' : 'application/json', + \ 'Authorization' : insecureSecret, + \ 'X-GitHub-OTP' : otp, + \}) + endif + let authorization = webapi#json#decode(res.content) + if has_key(authorization, 'token') + let secret = printf('token %s', authorization.token) + call writefile([secret], s:gist_token_file) + if !(has('win32') || has('win64')) + call system('chmod go= '.s:gist_token_file) endif - redraw | echo "\r" - let password = inputsecret("Password:") - let secret = printf("basic %s", base64#b64encode(g:github_user.":".password)) - call writefile([secret], configfile) - return secret - elseif api == 2 - let auth_url = "https://github.com/login/oauth/authorize" - let access_token_url = "https://github.com/login/oauth/access_token" - redraw | echo "\r" - let client_id = input("ClientID: ") - redraw | echo "\r" - let client_secret = input("ClientSecret: ") - let url = auth_url."?scope=gist&client_id=".client_id - call s:open_browser(url) - - let pin = input("PIN: ") - redraw | echo '' - let res = http#post(access_token_url, {"client_id": client_id, "code": pin, "client_secret": client_secret}) + elseif has_key(authorization, 'message') let secret = '' - for item in split(res.content, '&') - let token = split(item, '=') - if len(token) == 2 && token[0] == 'access_token' - let secret = printf("token %s", http#decodeURI(token[1])) - break - endif - endfor - call writefile([secret], configfile) - return secret + let v:errmsg = authorization.message endif - return "" + return secret endfunction -let s:extmap = { -\".adb": "ada", -\".ahk": "ahk", -\".arc": "arc", -\".as": "actionscript", -\".asm": "asm", -\".asp": "asp", -\".aw": "php", -\".b": "b", -\".bat": "bat", -\".befunge": "befunge", -\".bmx": "bmx", -\".boo": "boo", -\".c-objdump": "c-objdump", -\".c": "c", -\".cfg": "cfg", -\".cfm": "cfm", -\".ck": "ck", -\".cl": "cl", -\".clj": "clj", -\".cmake": "cmake", -\".coffee": "coffee", -\".cpp": "cpp", -\".cppobjdump": "cppobjdump", -\".cs": "csharp", -\".css": "css", -\".cw": "cw", -\".d-objdump": "d-objdump", -\".d": "d", -\".darcspatch": "darcspatch", -\".diff": "diff", -\".duby": "duby", -\".dylan": "dylan", -\".e": "e", -\".ebuild": "ebuild", -\".eclass": "eclass", -\".el": "lisp", -\".erb": "erb", -\".erl": "erlang", -\".f90": "f90", -\".factor": "factor", -\".feature": "feature", -\".fs": "fs", -\".fy": "fy", -\".go": "go", -\".groovy": "groovy", -\".gs": "gs", -\".gsp": "gsp", -\".haml": "haml", -\".hs": "haskell", -\".html": "html", -\".hx": "hx", -\".ik": "ik", -\".ino": "ino", -\".io": "io", -\".j": "j", -\".java": "java", -\".js": "javascript", -\".json": "json", -\".jsp": "jsp", -\".kid": "kid", -\".lhs": "lhs", -\".lisp": "lisp", -\".ll": "ll", -\".lua": "lua", -\".ly": "ly", -\".m": "objc", -\".mak": "mak", -\".man": "man", -\".mao": "mao", -\".matlab": "matlab", -\".md": "md", -\".minid": "minid", -\".ml": "ml", -\".moo": "moo", -\".mu": "mu", -\".mustache": "mustache", -\".mxt": "mxt", -\".myt": "myt", -\".n": "n", -\".nim": "nim", -\".nu": "nu", -\".numpy": "numpy", -\".objdump": "objdump", -\".ooc": "ooc", -\".parrot": "parrot", -\".pas": "pas", -\".pasm": "pasm", -\".pd": "pd", -\".phtml": "phtml", -\".pir": "pir", -\".pl": "perl", -\".po": "po", -\".py": "python", -\".pytb": "pytb", -\".pyx": "pyx", -\".r": "r", -\".raw": "raw", -\".rb": "ruby", -\".rhtml": "rhtml", -\".rkt": "rkt", -\".rs": "rs", -\".rst": "rst", -\".s": "s", -\".sass": "sass", -\".sc": "sc", -\".scala": "scala", -\".scm": "scheme", -\".scpt": "scpt", -\".scss": "scss", -\".self": "self", -\".sh": "sh", -\".sml": "sml", -\".sql": "sql", -\".st": "smalltalk", -\".tcl": "tcl", -\".tcsh": "tcsh", -\".tex": "tex", -\".textile": "textile", -\".tpl": "smarty", -\".twig": "twig", -\".txt" : "text", -\".v": "verilog", -\".vala": "vala", -\".vb": "vbnet", -\".vhd": "vhdl", -\".vim": "vim", -\".weechatlog": "weechatlog", -\".xml": "xml", -\".xq": "xquery", -\".xs": "xs", -\".yml": "yaml", -\} +let s:extmap = extend({ +\'.adb': 'ada', +\'.ahk': 'ahk', +\'.arc': 'arc', +\'.as': 'actionscript', +\'.asm': 'asm', +\'.asp': 'asp', +\'.aw': 'php', +\'.b': 'b', +\'.bat': 'bat', +\'.befunge': 'befunge', +\'.bmx': 'bmx', +\'.boo': 'boo', +\'.c-objdump': 'c-objdump', +\'.c': 'c', +\'.cfg': 'cfg', +\'.cfm': 'cfm', +\'.ck': 'ck', +\'.cl': 'cl', +\'.clj': 'clj', +\'.cmake': 'cmake', +\'.coffee': 'coffee', +\'.cpp': 'cpp', +\'.cppobjdump': 'cppobjdump', +\'.cs': 'csharp', +\'.css': 'css', +\'.cw': 'cw', +\'.d-objdump': 'd-objdump', +\'.d': 'd', +\'.darcspatch': 'darcspatch', +\'.diff': 'diff', +\'.duby': 'duby', +\'.dylan': 'dylan', +\'.e': 'e', +\'.ebuild': 'ebuild', +\'.eclass': 'eclass', +\'.el': 'lisp', +\'.erb': 'erb', +\'.erl': 'erlang', +\'.f90': 'f90', +\'.factor': 'factor', +\'.feature': 'feature', +\'.fs': 'fs', +\'.fy': 'fy', +\'.go': 'go', +\'.groovy': 'groovy', +\'.gs': 'gs', +\'.gsp': 'gsp', +\'.haml': 'haml', +\'.hs': 'haskell', +\'.html': 'html', +\'.hx': 'hx', +\'.ik': 'ik', +\'.ino': 'ino', +\'.io': 'io', +\'.j': 'j', +\'.java': 'java', +\'.js': 'javascript', +\'.json': 'json', +\'.jsp': 'jsp', +\'.kid': 'kid', +\'.lhs': 'lhs', +\'.lisp': 'lisp', +\'.ll': 'll', +\'.lua': 'lua', +\'.ly': 'ly', +\'.m': 'objc', +\'.mak': 'mak', +\'.man': 'man', +\'.mao': 'mao', +\'.matlab': 'matlab', +\'.md': 'markdown', +\'.minid': 'minid', +\'.ml': 'ml', +\'.moo': 'moo', +\'.mu': 'mu', +\'.mustache': 'mustache', +\'.mxt': 'mxt', +\'.myt': 'myt', +\'.n': 'n', +\'.nim': 'nim', +\'.nu': 'nu', +\'.numpy': 'numpy', +\'.objdump': 'objdump', +\'.ooc': 'ooc', +\'.parrot': 'parrot', +\'.pas': 'pas', +\'.pasm': 'pasm', +\'.pd': 'pd', +\'.phtml': 'phtml', +\'.pir': 'pir', +\'.pl': 'perl', +\'.po': 'po', +\'.py': 'python', +\'.pytb': 'pytb', +\'.pyx': 'pyx', +\'.r': 'r', +\'.raw': 'raw', +\'.rb': 'ruby', +\'.rhtml': 'rhtml', +\'.rkt': 'rkt', +\'.rs': 'rs', +\'.rst': 'rst', +\'.s': 's', +\'.sass': 'sass', +\'.sc': 'sc', +\'.scala': 'scala', +\'.scm': 'scheme', +\'.scpt': 'scpt', +\'.scss': 'scss', +\'.self': 'self', +\'.sh': 'sh', +\'.sml': 'sml', +\'.sql': 'sql', +\'.st': 'smalltalk', +\'.swift': 'swift', +\'.tcl': 'tcl', +\'.tcsh': 'tcsh', +\'.tex': 'tex', +\'.textile': 'textile', +\'.tpl': 'smarty', +\'.twig': 'twig', +\'.txt' : 'text', +\'.v': 'verilog', +\'.vala': 'vala', +\'.vb': 'vbnet', +\'.vhd': 'vhdl', +\'.vim': 'vim', +\'.weechatlog': 'weechatlog', +\'.xml': 'xml', +\'.xq': 'xquery', +\'.xs': 'xs', +\'.yml': 'yaml', +\}, get(g:, 'gist_extmap', {})) let &cpo = s:save_cpo unlet s:save_cpo diff --git a/doc/gist-vim.txt b/doc/gist-vim.txt index fe868ce..6074aba 100644 --- a/doc/gist-vim.txt +++ b/doc/gist-vim.txt @@ -1,24 +1,25 @@ *Gist.vim* Vimscript for creating gists (http://gist.github.com) -Usage |gist-vim-usage| -Tips |gist-vim-tips| -Requirements |gist-vim-requirements| -License |gist-vim-license| -Install |gist-vim-install| -Setup |gist-vim-setup| +Usage |vim-gist-usage| +Tips |vim-gist-tips| +License |vim-gist-license| +Install |vim-gist-install| +Requirements |vim-gist-requirements| +Setup |vim-gist-setup| +FAQ |vim-gist-faq| -This is a vimscript for creating gists (http://gist.github.com) +This is a vimscript for creating gists (http://gist.github.com) -For the latest version please see https://github.com/mattn/gist-vim. +For the latest version please see https://github.com/mattn/vim-gist. ============================================================================== -USAGE *:Gist* *gist-vim-usage* +USAGE *:Gist* *vim-gist-usage* - Post current buffer to gist, using default privacy option. > :Gist < -- Post selected text to gist, using defualt privacy option. +- Post selected text to gist, using default privacy option. This applies to all permutations listed below (except multi). > :'<,'>Gist @@ -26,11 +27,13 @@ USAGE *:Gist* *gist-vim-usage* - Create a private gist. > :Gist -p + :Gist --private < - Create a public gist. (Only relevant if you've set gists to be private by default.) > :Gist -P + :Gist --public < - Post whole text to gist as public. This is only relevant if you've set gists to be private by default. @@ -40,15 +43,18 @@ USAGE *:Gist* *gist-vim-usage* - Create a gist anonymously. > :Gist -a + :Gist --anonymous < - Create a gist with all open buffers. > :Gist -m + :Gist --multibuffer < - Edit the gist (you need to have opened the gist buffer first). You can update the gist with the {:w} command within the gist buffer. > :Gist -e + :Gist --edit < - Edit the gist with name "foo.js" (you need to have opened the gist buffer first). > @@ -59,18 +65,21 @@ USAGE *:Gist* *gist-vim-usage* first). > :Gist -s something + :Gist --description something :Gist -e -s something < - Delete the gist (you need to have opened the gist buffer first). Password authentication is needed. > :Gist -d + :Gist --delete < - Fork the gist (you need to have opened the gist buffer first). Password authentication is needed. > :Gist -f -< + :Gist --fork +< - Star the gist (you need to have opened the gist buffer first). Password authentication is needed. > @@ -92,6 +101,9 @@ USAGE *:Gist* *gist-vim-usage* - List your public gists. > :Gist -l + :Gist --list + :Gist -l -n 100 + :Gist --list --per-page 100 < - List gists from user "mattn". > @@ -100,13 +112,38 @@ USAGE *:Gist* *gist-vim-usage* - List everyone's gists. > :Gist -la + :Gist --listall < - List gists from your starred gists. > :Gist -ls + :Gist --liststar + +- While the gist list is visible, the following mappings apply: + + - 'o' or 'Enter' will open the selected gist file in a new buffer + and close the vim-gist listing split. + - 'b' will open the selected gist file in a browser. If you are in + GUI vim you can also achieve this by pressing 'Shift-Enter'. + - 'y' will copy the contents of the selected gist to the clipboard, + and close the vim-gist listing split. + - 'p' will (copy and) paste the contents of the selected gist to the + buffer from which vim-gist was called, and close the vim-gist + listing split. + - 'Esc' will close the vim-gist listing split without performing any + further action. + +- Open the gist on browser after you post or update it. +> + :Gist -b + :Gist --browser +< +- Post as new gist after editing on the buffer. +> + :Gist! < ============================================================================== -TIPS *gist-vim-tips* +TIPS *vim-gist-tips* If you set "g:gist_clip_command", gist.vim will copy the gist code with option "-c". @@ -142,30 +179,86 @@ If you want to show your private gists with ":Gist -l": > let g:gist_show_privates = 1 < -You need to either set global git config -> - $ git config --global github.user Username +If you want your gist to be private by default: > + + let g:gist_post_private = 1 < -============================================================================== -REQUIREMENTS *gist-vim-requirements* +If you want your gist to be anonymous by default: > - - curl command (http://curl.haxx.se/) - - webapi-vim (https://github.com/mattn/webapi-vim) - - and, if you want to use your git profile, the git command-line client. + let g:gist_post_anonymous = 1 +< +If you want to edit all files for gists containing more than one: > + + let g:gist_get_multiplefile = 1 +< +If you want to use on GitHub Enterprise: > + + let g:gist_api_url = 'http://your-github-enterprise-domain/api/v3' +< +If you want to open gist with current editing buffers: > + + let g:gist_edit_with_buffers = 1 + +If you want to open gist list/buffer as vertical split: > + + let g:gist_list_vsplit = 1 + +If you want to list more than 30 gists per page (maximum is 100): + + let g:gist_per_page_limit = 100 + +If you want to modify filetype for the file on github, or add mapping of +filetype/file-extension: > + + let g:gist_extmap = { ".swift": "swift" } +< + key is file-extension, value is filetype. + +If you want to update a gist, embed > + + GistID: xxxxx +> +in your local file, then call > + + :Gist + +The vim-gist listing split lists gists ids, names (filenames) as well as +their description. This is done following a table layout, with fixed space +for each column. For offering quick browsing, vim-gist will truncate all +output exceeding the available horizontal space, assuring that every gist +listed only takes one line on the table. Although the gist id field width is +fixed internally, the user can define the length of the (file)name field on +the vim-gist listing. This can be done by the following declaration: + + let g:gist_namelength = 20 + +Note that the default value for gist_namelength is 30. Again, if the gist +(file)name exceeds the specified number of characters, it will be truncated. + +If you want to update a gist when only |:w!|: > + + " :w and :w! update a gist. + let g:gist_update_on_write = 1 + + " Only :w! updates a gist. + let g:gist_update_on_write = 2 +> +All other values are treated as 1. +This variable's value is 1 by default. ============================================================================== -LICENSE *gist-vim-license* +LICENSE *vim-gist-license* Copyright 2010 by Yasuhiro Matsumoto modification, are permitted provided that the following conditions are met: - + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS @@ -180,50 +273,77 @@ LICENSE *gist-vim-license* OF THE POSSIBILITY OF SUCH DAMAGE. ============================================================================== -INSTALL *gist-vim-install* - -Copy gist.vim to your plugin directory. +INSTALL *vim-gist-install* -gist.vim will create a curl cookie-jar file in your runtimepath. +Copy following files into your plugin directory. rtp: + - autoload/gist.vim - plugin/gist.vim - - cookies/github -If you want to uninstall gist.vim, remember to also remove "cookies/github". +If you want to uninstall gist.vim, remember to also remove `~/.gist-vim`. -============================================================================== -SETUP *gist-vim-setup* +You need to install webapi-vim also: -This plugin uses github API v3. Setting value is stored in `~/.gist.vim`. -gist-vim have two ways to access APIs. + http://www.vim.org/scripts/script.php?script_id=4019 -|BasicAuth| +If you want to use latest one: - Require github user ID and password. This is easy but not secure. + https://github.com/mattn/webapi-vim -|OAuth2| +============================================================================== +REQUIREMENTS *vim-gist-requirements* - 1. Register your application. + - curl command (http://curl.haxx.se/) + - webapi-vim (https://github.com/mattn/webapi-vim) + - and, if you want to use your git profile, the git command-line client. - Note that you must set `Callback URL` as same as following. +============================================================================== +SETUP *vim-gist-setup* - https://github.com/settings/applications/new +This plugin uses GitHub API v3. The authentication value is stored in `~/.gist-vim`. +vim-gist provides two ways to authenticate against the GitHub APIs. - fill like following +First, you need to set your GitHub username in global git config: +> + $ git config --global github.user Username +< +Then, gist.vim will ask for your password to create an authorization when you +first use it. The password is not stored and only the OAuth access token will +be kept for later use. You can revoke the token at any time from the list of +"Authorized applications" on GitHub's "Account Settings" page. +(https://github.com/settings/applications) + +If you have two-factor authentication enabled on GitHub, you'll see the message +"Must specify two-factor authentication OTP code." In this case, you need to +create a "Personal Access Token" on GitHub's "Developer settings" page +(https://github.com/settings/tokens) with the gist scope and place it in a file +named ~/.gist-vim like this: +> + token xxxxx +< +If you happen to have your password already written in ~/.gitconfig like +below: +> + [github] + password = xxxxx +< +Then, add following into your ~/.vimrc +> + let g:gist_use_password_in_gitconfig = 1 +< +This is not secure at all, so strongly discouraged. - Callback URL should be http://mattn.github.com/gist-vim - If you don't want to point this site, use URL parameter 'code' as PIN. +NOTE: the username is optional if you only send anonymous gists. - 2. Start `:Gist -l` +============================================================================== +FAQ *vim-gist-faq* - You'll see some prompts. fill ClientID/CilentSecret. Then you can see - browser show up. - If you set Callback URL above, you can see PIN code. - Copy this value and paste to prompt `PIN:`. +Q. :Gist returns a Forbidden error +A. Try deleting ~/.gist-vim and authenticating again. ============================================================================== -THANKS *gist-vim-thanks* +THANKS *vim-gist-thanks* AD7six Bruno Bigras @@ -239,5 +359,6 @@ THANKS *gist-vim-thanks* steve tyru Will Gray + netj vim:tw=78:ts=8:ft=help:norl: diff --git a/gist.vim.vimup b/gist.vim.vimup deleted file mode 100644 index edb9bc8..0000000 --- a/gist.vim.vimup +++ /dev/null @@ -1,270 +0,0 @@ -script_name: Gist.vim -script_id: '2423' -script_type: utility -script_package: gist-vim.zip -script_version: '5.9' -required_vim_version: '7.0' -summary: vimscript for gist - -detailed_description: | - This is vimscript for gist (http://gist.github.com) - - Usage: - - :Gist - post whole text to gist. - - :'<,'>Gist - post selected text to gist. - - :Gist -p - post whole text to gist with private. - if you got empty gist list, try :Gist --abandon - - :Gist -a - post whole text to gist with anonymous. - - :Gist -m - post multi buffer to gist. - - :Gist -e - edit the gist. (shoud be work on gist buffer) - you can update the gist with :w command on gist buffer. - - :Gist -e foo.js - edit the gist with name 'foo.js'. (shoud be work on gist buffer) - - :Gist -d - delete the gist. (should be work on gist buffer) - password authentication is needed. - - :Gist -f - fork the gist. (should be work on gist buffer) - password authentication is needed. - - :Gist XXXXX - get gist XXXXX. - - :Gist -c XXXXX. - get gist XXXXX and put to clipboard. - - :Gist -l - list gists from mine. - - :Gist -la - list gists from all. - - Tips: - if set g:gist_clip_command, gist.vim will copy the gist code - with option '-c'. - - # mac - let g:gist_clip_command = 'pbcopy' - - # linux - let g:gist_clip_command = 'xclip -selection clipboard' - - # others(cygwin?) - let g:gist_clip_command = 'putclip' - - if you want to detect filetype from filename... - - let g:gist_detect_filetype = 1 - - if you want to open browser after the post... - - let g:gist_open_browser_after_post = 1 - - if you want to change the browser... - - let g:gist_browser_command = 'w3m %URL%' - - or - - let g:gist_browser_command = 'opera %URL% &' - - on windows, should work with original setting. - - Require: - curl command (http://curl.haxx.se/) - and if you want to use profile of git, it require git command. - -install_details: | - copy it to your plugin directory. - - gist.vim leave cookie-jar file into runtimepath. - - rtp: - plugin/gist.vim - cookies/github - - if you want to uninstall gist.vim, you have better to remove 'cookies/github'. - - for using gist.vim, you should install git. or set g:github_user and g:github_token into your vimrc. - note that g:github_token is NOT a your password. - - how get your token. - 1. login to github. - 2. click "Account Settings" - 3. click "Account Admin" - 4. you'll see it at following of 'API Token'. - -versions: -- '5.9': | - This is an upgrade for Gist.vim: add support anonymous post. fixed many bugs. - -- '5.8': | - This is an upgrade for Gist.vim: add support for description. you can post description using -s option. - -- '5.7': | - This is an upgrade for Gist.vim: post with filetype more cleverly. - -- '5.6': | - This is an upgrade for Gist.vim: fix '--abandon'. - -- '5.5': | - This is an upgrade for Gist.vim: fix: forgot to upload autoload/gist.vim. - -- '5.4': | - This is an upgrade for Gist.vim: fix: does not work correctly with blockwize selection. - -- '5.3': | - This is an upgrade for Gist.vim: upd: support autoload. - -- '5.2': | - This is an upgrade for Gist.vim: add: support block-wise selection. - -- '5.1': | - This is an upgrade for Gist.vim: fix: can't update privates. - -- '5.0': | - This is an upgrade for Gist.vim: follow update of gist.github.com - -- '4.9': | - fix: don't add new line after "Done: xxx". - fix: show WHY FAILED' when failed to post. - add: support for :OpenBrowser. - add: new option 'gist_curl_options'. - -- '4.8': | - This is an upgrade for Gist.vim: fix: can't open private gist with ":Gist XXXXX". - -- '4.7': | - This is an upgrade for Gist.vim: fix: filetype detection. - -- '4.6': | - This is an upgrade for Gist.vim: fix: strange cookies folder. - -- '4.5': | - This is an upgrade for Gist.vim: fix: use gist_clip_command for copying URL to clipboard. this fix strange behavior on Mac OSX. - -- '4.4': | - This is an upgrade for Gist.vim: fix: gist is now only using https. - -- '4.3': | - This is an upgrade for Gist.vim: add new option '-f' for fork. - -- '4.2': | - This is an upgrade for Gist.vim: fixed code for login. - -- '4.1': | - This is an upgrade for Gist.vim: fixed code cleanup. - -- '4.0': | - This is an upgrade for Gist.vim: fixed deleting gist, listing privates. - -- '3.9': | - This is an upgrade for Gist.vim: fixed :w handler in gist buffer. - -- '3.8': | - This is an upgrade for Gist.vim: 'more...' on gist list. - -- '3.7': | - This is an upgrade for Gist.vim: fix problem that break "gist list" window at twice. - -- '3.6': | - This is an upgrade for Gist.vim: fix filetype detection for 'vimscript'. - -- '3.5': | - This is an upgrade for Gist.vim: fix filetype detection. - -- '3.4': | - This is an upgrade for Gist.vim: use '+' register on unix only if built with 'xterm_clipboard'. and some bug fixes. - -- '3.3': | - This is an upgrade for Gist.vim: fix problem that append empty line when getting gist. - -- '3.2': | - This is an upgrade for Gist.vim: added Gist header to recognize the gist. added script type header for Vimana. - -- '3.1': | - This is an upgrade for Gist.vim: fix checking redirect url. - -- '3.0': | - This is an upgrade for Gist.vim: fix for official changes(private button name was changed). - -- '2.9': | - This is an upgrade for Gist.vim: fix for official changes(private button name was changed). - -- '2.8': | - This is an upgrade for Gist.vim: be able to post multi buffer. currently updating or showing not supported. and ':Gist -d' delete the gist. - -- '2.7': | - This is an upgrade for Gist.vim: be able to write the gist to local file with ':w foo.txt'. - -- '2.6': | - This is an upgrade for Gist.vim: fixed problem that does not work 'Gist XXXX'. - -- '2.5': | - This is an upgrade for Gist.vim: use existing buffer when open the list or gist. - -- '2.4': | - This is an upgrade for Gist.vim: show error message when no any github settings. - -- '2.3': | - This is an upgrade for Gist.vim: added :w BufWriteCmd for GistUpdate. - -- '2.2': | - This is an upgrade for Gist.vim: fixed a bug for anonymous post. and new option '-a' for anonymous post. - -- '2.1': | - This is an upgrade for Gist.vim: support changing gist filename. - -- '2.0': | - This is an upgrade for Gist.vim: bugfix for listing gists in specified user. - -- '1.9': | - This is an upgrade for Gist.vim: added support editing the gist. and bits bug fix. - -- '1.8': | - This is an upgrade for Gist.vim: added new option g:gist_open_browser_after_post/g:gist_browser_command to open posted gist. - -- '1.7': | - This is an upgrade for Gist.vim: now changed argument for putting clipboard as ':Gist -c XXXXX'. - -- '1.6': | - This is an upgrade for Gist.vim: add gist's author in gist list. - -- '1.5': | - This is an upgrade for Gist.vim: oops. bugfix for auto-detection. - -- '1.4': | - This is an upgrade for Gist.vim: bugfix for auto-detection. - -- '1.3': | - This is an upgrade for Gist.vim: more auto-detection for filetype. - -- '1.2': | - This is an upgrade for Gist.vim: added new option for detect filetype from filename. - -- '1.1': | - This is an upgrade for Gist.vim: calling StdinReadPost. - -- '1.0': | - This is an upgrade for Gist.vim: treat literal "-" as part of username. - -- '0.9': | - This is an upgrade for Gist.vim: added new option 'g:gist_clip_command' that copy the gist code. - -# __END__ -# vim: filetype=yaml diff --git a/plugin/gist.vim b/plugin/gist.vim index e94687c..46956a1 100644 --- a/plugin/gist.vim +++ b/plugin/gist.vim @@ -1,26 +1,24 @@ "============================================================================= " File: gist.vim " Author: Yasuhiro Matsumoto -" WebPage: http://github.com/mattn/gist-vim +" WebPage: http://github.com/mattn/vim-gist " License: BSD " GetLatestVimScripts: 2423 1 :AutoInstall: gist.vim " script type: plugin -if &cp || (exists('g:loaded_gist_vim') && g:loaded_gist_vim) +if &compatible || (exists('g:loaded_gist_vim') && g:loaded_gist_vim) finish endif let g:loaded_gist_vim = 1 -if !exists('g:github_user') && !executable('git') - echohl ErrorMsg | echomsg "Gist: require 'git' command" | echohl None - finish -endif - -if !executable('curl') - echohl ErrorMsg | echomsg "Gist: require 'curl' command" | echohl None - finish -endif +function! s:CompleteArgs(arg_lead,cmdline,cursor_pos) + return filter(copy(["-p", "-P", "-a", "-m", "-e", "-s", "-d", "+1", "-1", "-f", "-c", "-l", "-la", "-ls", "-b", "-n", + \ "--listall", "--liststar", "--list", "--multibuffer", "--private", "--public", "--anonymous", "--description", "--clipboard", + \ "--rawurl", "--delete", "--edit", "--star", "--unstar", "--fork", "--browser", "--per-page" + \ ]), 'stridx(v:val, a:arg_lead)==0') +endfunction -command! -nargs=? -range=% Gist :call gist#Gist(, , , ) +let g:gist_per_page_limit = get(g:, 'gist_per_page_limit', 30) +command! -nargs=? -range=% -bang -complete=customlist,s:CompleteArgs Gist :call gist#Gist(, "", , , ) " vim:set et: