VimエディタでもアニメーションGIFが再生したい!

と、いうことで簡単にやってみました。

[必要なもの]

[動作]


こんな感じ。
基本的には mattn さんのやつと同じ仕組です。
gif データを convert で xpm に変換して1つずつ描画しているだけですね。
ぶっちゃけ結構無理やりやっているのでそんなにパフォーマンスは良くないです。
48x48 ぐらいのサイズであれば割とスムーズにアニメーションが再生されると思います。
(アニメーション数が多くても初期化が遅いだけで再生自体はそれほど問題にならないはず、多分。


あとそのままだと半角で縦長になってしまうので2文字ずつ表示させるようにしています。
両端の " も conceal で消そうとしたんですが、うまく設定できなかったので断念。
これは消したかったんだけどなぁ。

[おまけ]

こちらの gif ファイルを再生させるとこんな感じになります。


若干もっさりしている気がしますが、ちゃんと再生出来ていますね。
ちなみにこの gif ファイルだとアニメーション数が多いので、表示されるまでにだいぶ時間がかかります。

[ソースコード]

let g:xpm_output_directory = $TEMP
let g:xpm_wait_ms = 10


function! s:write(data)
    let i = 0
    for line in a:data
        call setline(i, line)
        let i += 1
    endfor
endfunction

function! XpmFileSorter(...)
    return
\       len(a:1) > len(a:2) ? 1
\     : len(a:1) < len(a:2) ? -1
\     : a:1 == a:2 ? 0
\     : a:1 >  a:2 ? 1
\     : a:1 <  a:2 ? -1
\     : 0
endfunction

function! s:gif_to_xpm(gif)
    let name = fnamemodify(a:gif, ":t:r")
    let output_dir = g:xpm_output_directory."/".name
    let output = output_dir."/".name

    if !isdirectory(output_dir)
        call mkdir(output_dir)
        call system("convert ".a:gif. " " . output.".xpm")
    endif
    return sort(split(glob(output."-*"), "\n"), function("XpmFileSorter"))
endfunction

function! s:twice_line(line)
    return join(eval(join(map(split(a:line, '\ze.'), "v:key != 0 && v:key != len(a:line)-1 && v:key != len(a:line)-2 ? [v:val, v:val] : [v:val]"), "+")), "")
endfunction


function! s:gif_animation(file)
    if !executable("convert")
        echoerr "Please install convert"
        return
    endif
    if !filereadable(a:file)
        echoerr "Not Fount ".a:file
        return
    endif
    if !isdirectory(g:xpm_output_directory)
        echoerr "Invalid g:xpm_output_directory : " . g:xpm_output_directory
        return
    endif

    let gif = a:file
    let xpms = map(s:gif_to_xpm(gif), "readfile(v:val)")
    let images = map(map(copy(xpms), "v:val[index(v:val, '/* pixels */') : len(v:val)-2]"), "map(copy(v:val), 's:twice_line(v:val)')")
    let images_num = len(images)

    setlocal conceallevel=2
    setlocal concealcursor=n
    highlight clear Visual
    highlight clear Cursor
    
    let i = 0
    while 1
        call s:write(xpms[i % images_num])
        set ft=xpm
        syntax match XPM_INV /,/ transparent conceal
        syntax match XPM_INV2 /"/ transparent conceal
        silent %d _
        call s:write(images[i % images_num])
        normal! G
        redraw
        if g:xpm_wait_ms
            execute "sleep" g:xpm_wait_ms."ms"
        endif
        let i += 1
    endwhile
endfunction

command! -nargs=1 -complete=file
\   GifAnimationTab 
\   tabnew | call s:gif_animation(<q-args>)