" Vimball Archiver by Charles E. Campbell, Jr., Ph.D. UseVimball finish plugin/twitvim.vim [[[1 1073 " ============================================================== " TwitVim - Post to Twitter from Vim " Based on Twitter Vim script by Travis Jeffery " " Version: 0.2.19 " License: Vim license. See :help license " Language: Vim script " Maintainer: Po Shan Cheah " Created: March 28, 2008 " Last updated: July 11, 2008 " " GetLatestVimScripts: 2204 1 twitvim.vim " ============================================================== " Load this module only once. if exists('loaded_twitvim') finish endif let loaded_twitvim = 1 " Avoid side-effects from cpoptions setting. let s:save_cpo = &cpo set cpo&vim let s:proxy = "" let s:login = "" " If true, disable the Perl code that simplifies and localizes Twitter " timestamps. if !exists('g:twitvim_disable_simple_time') let g:twitvim_disable_simple_time = 0 endif " The extended character limit is 246. Twitter will display a tweet longer than " 140 characters in truncated form with a link to the full tweet. If that is " undesirable, set s:char_limit to 140. let s:char_limit = 246 " Allow the user to override the API root, e.g. for identi.ca, which offers a " Twitter-compatible API. function! s:get_api_root() return exists('g:twitvim_api_root') ? g:twitvim_api_root : "http://twitter.com" endfunction function! s:get_config_proxy() " Get proxy setting from twitvim_proxy in .vimrc or _vimrc. " Format is proxysite:proxyport let s:proxy = exists('g:twitvim_proxy') ? '-x "'.g:twitvim_proxy.'"': "" " If twitvim_proxy_login exists, use that as the proxy login. " Format is proxyuser:proxypassword " If twitvim_proxy_login_b64 exists, use that instead. This is the proxy " user:password in base64 encoding. if exists('g:twitvim_proxy_login_b64') let s:proxy .= ' -H "Proxy-Authorization: Basic '.g:twitvim_proxy_login_b64.'"' else let s:proxy .= exists('g:twitvim_proxy_login') ? ' -U "'.g:twitvim_proxy_login.'"' : '' endif endfunction " Get user-config variables twitvim_proxy and twitvim_login. function! s:get_config() call s:get_config_proxy() " Get Twitter login info from twitvim_login in .vimrc or _vimrc. " Format is username:password " If twitvim_login_b64 exists, use that instead. This is the user:password " in base64 encoding. if exists('g:twitvim_login_b64') let s:login = '-H "Authorization: Basic '.g:twitvim_login_b64.'"' elseif exists('g:twitvim_login') && g:twitvim_login != '' let s:login = '-u "'.g:twitvim_login.'"' else " Beep and error-highlight execute "normal \" redraw echohl ErrorMsg echomsg 'Twitter login not set.' \ 'Please add to .vimrc: let twitvim_login="USER:PASS"' echohl None return -1 endif return 0 endfunction " === XML helper functions === " Get the content of the n'th element in a series of elements. function! s:xml_get_nth(xmlstr, elem, n) let matchres = matchlist(a:xmlstr, '<'.a:elem.'>\(.\{-}\)', -1, a:n) return matchres == [] ? "" : matchres[1] endfunction " Get the content of the specified element. function! s:xml_get_element(xmlstr, elem) return s:xml_get_nth(a:xmlstr, a:elem, 1) endfunction " Remove any number of the specified element from the string. Used for removing " sub-elements so that you can parse the remaining elements safely. function! s:xml_remove_elements(xmlstr, elem) return substitute(a:xmlstr, '<'.a:elem.'>.\{-}', '', "g") endfunction " === End of XML helper functions === " === Perl time string parser === if has('perl') && !g:twitvim_disable_simple_time function s:def_perl_time_funcs() perl <import; require POSIX; POSIX->import(qw(strftime)); }; if ($@) { # Play it safe and disable this feature if modules fail to load. VIM::DoCommand('let g:twitvim_disable_simple_time = 1'); } # Convert abbreviated month name to month number. sub twitvim_conv_month { my $monthstr = shift; my @months = qw(jan feb mar apr may jun jul aug sep oct nov dec); for my $mon (0..11) { $months[$mon] eq lc($monthstr) and return $mon; } undef; } # Parse time string in Twitter RSS or Summize Atom format. sub twitvim_parse_time { my $timestr = shift; # This timestamp format is used by Twitter in timelines. if ($timestr =~ /^\w+,\s+(\d+)\s+(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+\+0000$/) { my $mon = twitvim_conv_month($2); defined $mon or return undef; return timegm($6, $5, $4, $1, $mon, $3); } # This timestamp format is used by Twitter in response to an update. elsif ($timestr =~ /^\w+\s+(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+\+0000\s+(\d+)$/) { my $mon = twitvim_conv_month($1); defined $mon or return undef; return timegm($5, $4, $3, $2, $mon, $6); } # This timestamp format is used by Summize. elsif ($timestr =~ /^(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)Z$/) { return timegm($6, $5, $4, $3, $2 - 1, $1); } else { return undef; } } # Convert the Twitter timestamp to local time and simplify it. sub twitvim_new_time { my $timestr = shift; my $time = twitvim_parse_time($timestr); defined $time ? strftime("%I:%M %p %b %d, %Y", localtime($time)) : $timestr; } EOF endfunction call s:def_perl_time_funcs() " Wrapper for the Twitter timestamp converter. function s:perl_time(timestr) execute 'perl VIM::DoCommand("let newtime = \"".twitvim_new_time("'.a:timestr.'")."\"")' return newtime endfunction endif " Simplify the time string. Do this only if the Perl interface is enabled and " if we have not disabled the feature. function s:time_filter(timestr) let s = a:timestr if has('perl') && !g:twitvim_disable_simple_time let s = s:perl_time(s) endif return s endfunction " === End of Perl time string parser === " Add update to Twitter buffer if public, friends, or user timeline. function! s:add_update(output) if s:twit_buftype == "public" || s:twit_buftype == "friends" || s:twit_buftype == "user" " Parse the output from the Twitter update call. let date = s:time_filter(s:xml_get_element(a:output, 'created_at')) let text = s:xml_get_element(a:output, 'text') let name = s:xml_get_element(a:output, 'screen_name') if text == "" return endif let twit_bufnr = bufwinnr('^'.s:twit_winname.'$') if twit_bufnr > 0 execute twit_bufnr . "wincmd w" call append(2, name.': '.s:convert_entity(text).' |'.date.'|') normal 1G wincmd p endif endif endfunction " URL-encode a string. function! s:url_encode(str) return substitute(a:str, '[^a-zA-Z_-]', '\=printf("%%%02X", char2nr(submatch(0)))', 'g') endfunction " Common code to post a message to Twitter. function! s:post_twitter(mesg) " Get user-config variables twitvim_proxy and twitvim_login. " We get these variables every time before posting to Twitter so that the " user can change them on the fly. let rc = s:get_config() if rc < 0 return -1 endif let mesg = a:mesg " Remove trailing newline. You see that when you visual-select an entire " line. Don't let it count towards the tweet length. let mesg = substitute(mesg, '\n$', '', "") " Convert internal newlines to spaces. let mesg = substitute(mesg, '\n', ' ', "g") " Check tweet length. Note that the tweet length should be checked before " URL-encoding the special characters because URL-encoding increases the " string length. if strlen(mesg) > s:char_limit redraw echohl WarningMsg echo "Your tweet has" strlen(mesg) - s:char_limit "too many characters. It was not sent." echohl None elseif strlen(mesg) < 1 redraw echohl WarningMsg echo "Your tweet was empty. It was not sent." echohl None else redraw echo "Sending update to Twitter..." let output = system("curl -s ".s:proxy." ".s:login.' -d status="'.s:url_encode(mesg).'" '.s:get_api_root()."/statuses/update.xml?source=twitvim") if v:shell_error != 0 redraw echohl ErrorMsg echomsg "Error posting your tweet. Result code: ".v:shell_error echomsg "Output:" echomsg output echohl None else call s:add_update(output) redraw echo "Your tweet was sent. You used" strlen(mesg) "characters." endif endif endfunction " Prompt user for tweet and then post it. " If initstr is given, use that as the initial input. function! s:CmdLine_Twitter(initstr) " Do this here too to check for twitvim_login. This is to avoid having the " user type in the message only to be told that his configuration is " incomplete. let rc = s:get_config() if rc < 0 return -1 endif call inputsave() let mesg = input("Your Twitter: ", a:initstr) call inputrestore() call s:post_twitter(mesg) endfunction " Extract the user name from a line in the timeline. function! s:get_user_name(line) let matchres = matchlist(a:line, '^\(\w\+\):') return matchres != [] ? matchres[1] : "" endfunction " This is for a local mapping in the timeline. Start an @-reply on the command " line to the author of the tweet on the current line. function! s:Quick_Reply() let username = s:get_user_name(getline('.')) if username != "" call s:CmdLine_Twitter('@'.username.' ') endif endfunction " This is for a local mapping in the timeline. Start a direct message on the " command line to the author of the tweet on the current line. function! s:Quick_DM() let username = s:get_user_name(getline('.')) if username != "" call s:CmdLine_Twitter('d '.username.' ') endif endfunction " Prompt user for tweet. if !exists(":PosttoTwitter") command PosttoTwitter :call CmdLine_Twitter('') endif nnoremenu Plugin.TwitVim.Post\ from\ cmdline :call CmdLine_Twitter('') " Post current line to Twitter. if !exists(":CPosttoTwitter") command CPosttoTwitter :call post_twitter(getline('.')) endif nnoremenu Plugin.TwitVim.Post\ current\ line :call post_twitter(getline('.')) " Post entire buffer to Twitter. if !exists(":BPosttoTwitter") command BPosttoTwitter :call post_twitter(join(getline(1, "$"))) endif " Post visual selection to Twitter. noremap Visual y:call post_twitter(@") noremap