Changeset 6199

Show
Ignore:
Timestamp:
02/05/08 04:31:52 (6 years ago)
Author:
todesking
Message:

lang/vim/hatena: エントリのパース機能を追加、ログイン/更新関数の公開、win環境において取得エントリにごみがまざるのを抑制。

Location:
lang/vim/hatena
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • lang/vim/hatena

  • lang/vim/hatena/plugin/hatena.vim

    r3774 r6199  
    102102let g:hatena_edit_command = 'edit!' 
    103103 
    104 let s:curl_cmd = 'curl -k' 
     104let s:curl_cmd = 'curl -k --silent' 
    105105if exists('g:chalice_curl_options') " http://d.hatena.ne.jp/smeghead/20070709/hatenavim 
    106106  let s:curl_cmd = s:curl_cmd . ' ' . g:chalice_curl_options 
     
    128128        let hatena_user = g:hatena_user 
    129129    endif 
    130  
     130        return HatenaLogin(hatena_user) 
     131endfunction 
     132 
     133"TODO: この関数をグローバルにするセキュリティリスクについて考察 
     134function! HatenaLogin(user) 
     135        let hatena_user=a:user 
    131136    let [base_url, user] = s:GetBaseURLAndUser(hatena_user) 
    132137 
     
    149154                endif 
    150155                if reply_header !~? 'Location:' 
    151                         echo 'ログインしてます' 
    152                         return [base_url, user, cookie_file] 
    153                 else 
    154                         call delete(cookie_file) 
    155                 endif 
     156            echo 'ログインしてます' 
     157            return [base_url, user, cookie_file] 
     158        else 
     159            call delete(cookie_file) 
     160        endif 
    156161    endif 
    157162 
     
    197202    endif 
    198203 
     204        if !len(date) 
     205                echo 'キャンセルしました' 
     206                return 
     207        endif 
     208 
    199209    " 20051124, 2005-11-24, 11/24, 24 といった日付を認識 
    200210    let pat = '\%(\%(\(\d\d\d\d\)[/-]\=\)\=\(\d\d\)[/-]\=\)\=\(\d\d\)' 
     
    215225    if !strlen(month) | let month = strftime('%m') | endif 
    216226 
    217     " 編集ページを取得 
    218     let content = system(s:curl_cmd . ' "' . base_url . user . '/edit?date=' . year . month . day . '" -b "' . cookie_file . '"') 
    219     if base_url =~ 'g.hatena' 
    220         let content = iconv(content, 'utf-8', &enc) 
    221         let fenc = 'utf-8' 
    222     else 
    223         let content = iconv(content, 'euc-jp', &enc) 
    224         let fenc = 'euc-jp' 
    225     endif 
     227        let content = HatenaLoadContent(base_url,user,year,month,day,cookie_file) 
    226228 
    227229    " セッション(編集バッファ)を作成 
     
    230232    set filetype=hatena 
    231233    setlocal noswapfile 
    232     let &fileencoding = fenc 
    233     let b:rkm = matchstr(content, 'name="rkm"\s*value="\zs[^"]*\ze"') 
     234    let &fileencoding = content['fenc'] 
     235    let b:rkm = content['rkm'] 
    234236 
    235237    if !strlen(b:rkm) 
     
    245247    let b:month = month 
    246248    let b:day   = day 
    247     let diary_title = matchstr(content, '<title>\zs.\{-}\ze</title>') 
    248     let day_title   = matchstr(content, '<input .\{-}name="title" .\{-}value="\zs.\{-}\ze"') 
    249     let timestamp   = matchstr(content, 'name="timestamp"\s*value="\zs[^"]*\ze"') 
    250     let body        = s:HtmlUnescape(matchstr(content, '<textarea.\{-}name="body"[^>]*>\zs.\{-}\ze</textarea>')) 
    251249    let b:trivial   = g:hatena_always_trivial 
    252     let b:diary_title   = diary_title 
    253     let b:day_title     = day_title 
    254     let b:timestamp     = timestamp 
     250    let b:diary_title   = content['diary_title'] 
     251    let b:day_title     = content['day_title'] 
     252    let b:timestamp     = content['timestamp'] 
    255253    let b:prev_titlestring = &titlestring 
    256254 
    257     autocmd BufWritePost <buffer> call s:HatenaUpdate() | autocmd! BufWritePost <buffer> 
     255    autocmd BufWritePost <buffer> call s:HatenaUpdate() | set readonly |let &titlestring = b:prev_titlestring | bdelete 
    258256    autocmd WinLeave <buffer> let &titlestring = b:prev_titlestring 
    259257    autocmd WinEnter <buffer> let &titlestring = b:diary_title . ' ' . b:year . '-' . b:month . '-' . b:day . ' [' . b:hatena_login_info[1] . ']' 
     
    262260    let nopaste = !&paste    
    263261    set paste 
    264     execute 'normal i' . body 
     262    execute 'normal i' . content['body'] 
    265263    if nopaste 
    266264        set nopaste 
    267265    endif 
    268  
     266        set nomodified 
     267endfunction 
     268 
     269"指定先から一日分のエントリを取得。 
     270"return: dictionary { 
     271"       diary_title, day_title, timestamp, rkm, body, fenc 
     272"} 
     273function! HatenaLoadContent(base_url,user,year,month,day,cookie_file) 
     274    " 編集ページを取得 
     275    let content = system(s:curl_cmd . ' "' . a:base_url . a:user . '/edit?date=' . a:year.a:month.a:day . '" -b "' . a:cookie_file . '"') 
     276    if a:base_url =~ 'g.hatena' 
     277        let content = iconv(content, 'utf-8', &enc) 
     278        let fenc = 'utf-8' 
     279    else 
     280        let content = iconv(content, 'euc-jp', &enc) 
     281        let fenc = 'euc-jp' 
     282    endif 
     283        let result=s:HatenaParseContent(content) 
     284        let result['fenc']=fenc 
     285        let result['year']=a:year 
     286        let result['month']=a:month 
     287        let result['day']=a:day 
     288        return result 
     289endfunction 
     290 
     291function! s:HatenaParseContent(content) 
     292    let diary_title = matchstr(a:content, '<title>\zs.\{-}\ze</title>') 
     293    let day_title   = matchstr(a:content, '<input .\{-}name="title" .\{-}value="\zs.\{-}\ze"') 
     294    let timestamp   = matchstr(a:content, 'name="timestamp"\s*value="\zs[^"]*\ze"') 
     295    let rkm         = matchstr(a:content, 'name="rkm"\s*value="\zs[^"]*\ze"') 
     296    let body        = s:HtmlUnescape(matchstr(a:content, '<textarea.\{-}name="body"[^>]*>\zs.\{-}\ze</textarea>')) 
     297        let result={} 
     298        let result['diary_title']=diary_title 
     299        let result['day_title']=day_title 
     300        let result['timestamp']=timestamp 
     301        let result['rkm']=rkm 
     302        let result['body']=body 
     303        return result 
    269304endfunction 
    270305 
     
    286321    let [base_url, user, cookie_file] = b:hatena_login_info 
    287322 
    288     " まずは全消去 
    289     let post_data = ' -F mode=enter' 
    290                     \ . ' -F year=' . b:year . ' -F month=' . b:month . ' -F day=' . b:day 
    291                     \ . ' -F rkm=' . b:rkm 
    292                     \ . ' -F body= -F title=' 
    293     call system(s:curl_cmd . ' ' . base_url . user . '/edit -b "' . cookie_file . '"' . post_data) 
    294  
    295323    if a:0 > 0 
    296324        let b:day_title = a:1 
     
    302330        write 
    303331    endif 
     332 
    304333    let body_file = expand('%') 
    305  
     334        let diary={'timestamp':b:timestamp, 'rkm':b:rkm, 'year':b:year, 'month':b:month, 'day':b:day, 'day_title':b:day_title} 
     335 
     336        let result=HatenaPost(base_url,user,cookie_file,diary,body_file) 
     337 
     338    echo '更新しました' 
     339endfunction 
     340 
     341function! HatenaPost(base_url,user,cookie_file,diary,body_file) 
     342        if a:body_file == "" 
     343                let body_file=tempname() 
     344                execute 'new '.body_file 
     345                call append(0,a:diary['body']) 
     346                write 
     347                hide 
     348                let &modified=0 
     349                "bdelete 
     350        else 
     351                let body_file=a:body_file 
     352        endif 
     353    " まずは全消去 
    306354    let post_data = ' -F mode=enter' 
    307                     \ . ' -F timestamp=' . b:timestamp . ' -F rkm=' . b:rkm 
    308                     \ . ' -F year=' . b:year . ' -F month=' . b:month . ' -F day=' . b:day 
    309                     \ . ' -F date=' . b:year . b:month . b:day 
     355                    \ . ' -F year=' . a:diary.year . ' -F month=' . a:diary.month . ' -F day=' . a:diary.day 
     356                    \ . ' -F rkm=' . a:diary.rkm 
     357                    \ . ' -F body= -F title=' 
     358    call system(s:curl_cmd . ' ' . a:base_url . a:user . '/edit -b "' . a:cookie_file . '"' . post_data) 
     359 
     360    " ポスト 
     361    let post_data = ' -F mode=enter' 
     362                    \ . ' -F timestamp=' . a:diary['timestamp'] . ' -F rkm=' . a:diary['rkm'] 
     363                    \ . ' -F year=' . a:diary['year'] . ' -F month=' . a:diary['month'] . ' -F day=' . a:diary['day'] 
     364                    \ . ' -F date=' . a:diary['year'].a:diary['month'].a:diary['day'] 
    310365                    \ . ' -F "body=<' . body_file . '"' 
    311                     \ . ' -F image= -F title=' . b:day_title 
    312  
    313     " ポスト 
    314     let result = system(s:curl_cmd . ' ' . base_url . user . '/edit -b "' . cookie_file . '"' . post_data . ' -D -') 
    315  
    316     echo '更新しました' 
     366                    \ . ' -F image= -F title=' . a:diary['day_title'] 
     367    return system(s:curl_cmd . ' ' . a:base_url . a:user . '/edit -b "' . a:cookie_file . '"' . post_data . ' -D -') 
    317368endfunction 
    318369 
     
    350401endfunction 
    351402 
     403"returns array of dictionaries. 
     404"[entry1,entry2,...] 
     405"each item is 
     406"{ 'eid':entry-id, 'title':title, 'body':body } 
     407" TODO: タイトルのない冒頭部 
     408function! HatenaParseEntries(body) 
     409        new 
     410        if type(a:body)==type('') 
     411                let body=split(a:body,"",1) 
     412        else "expect is list 
     413                let body=a:body 
     414        endif 
     415        call append(0,body) 
     416        call cursor(1,1) 
     417        let l:es=[] 
     418        let l:e=s:FindNextEntry() 
     419        while l:e 
     420                let l:next_e=s:FindNextEntry() 
     421                call add(l:es,[l:e,next_e?next_e-1:line('$')]) 
     422                let l:e=l:next_e 
     423        endwhile 
     424        let l:result=[] 
     425        for [l:st,l:ed] in l:es 
     426                call add(result,HatenaParseEnrty(getline(l:st),getline(l:st+1,l:ed))) 
     427        endfor 
     428        let &modified=0 
     429        close 
     430        return l:result 
     431endfunction      
     432 
     433function! HatenaParseEnrty(title,body) 
     434        let [eid,title]=matchlist(a:title,'^\*\%(\(\%(\w\|-\)\+\)\*\)\?\(.*\)$')[1:2] 
     435        let body=a:body 
     436        return {'eid':eid, 'title':title, 'body':body} 
     437endfunction 
     438 
     439"エントリのリストを文字列に直す HatenaParseEntriesの逆 
     440"諸般の事情(appendの仕様?)により、各行を要素に持つリストを返す。 
     441function! HatenaExpandEntries(entries) 
     442        new 
     443        for e in a:entries 
     444                call append(line('$'),'*'.e['eid'].'*'.e['title']) 
     445                call append(line('$'),e['body']) 
     446        endfor 
     447        execute '1delete' 
     448        let result=getline(1,'$') 
     449        let &modified=0 
     450        bdelete 
     451        return result 
     452endfunction 
     453 
     454"カーソル位置以降のエントリを探す 
     455function! s:FindNextEntry() 
     456        while 1 
     457                "skip super pre 
     458                if search('^>|\w*|$','ce',line('.')) 
     459                        if !search('^||<$','ce') "broken spre 
     460                                return 0 
     461                        endif 
     462                endif 
     463                "find next entry 
     464                let entry=search('^\*\(\%(\w\|-\)\+\)\*\(.*\)$','ce',line('.')) 
     465                if entry || line('.') >= line('$') 
     466                        call cursor(line('.')+1,1) 
     467                        return entry 
     468                endif 
     469                call cursor(line('.')+1,1) 
     470        endwhile 
     471endfunction 
     472 
    352473" }}} 
    353474" ===========================