Quantcast
Channel: Vimタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 5608

あなたがサイヤ人の時、Vimはスーパーサイヤエディタになる

$
0
0

人はスーパーサイヤ人に憧れるものです、しかし現実ではなれる人は限られています、日夜修行していつかスーパーサイヤ人になれる日を夢見るのもいいですが、ここでは変わりにVimにスーパーサイヤエディタになってもらいます。

そんなプラグインを作りました。

kuririn-no-kotoka.vim

image.png

wordijp/kuririn-no-kotoka.vim(GitHub)
インストール方法や使い方はREADME.mdに記載しています。
※動作確認はWindowsのみで行っているため、Linunx/Macでの確認ができていません

デモ

このプラグインはこちらの動画(Youtube)を見ながら作成しています。

あなたがサイヤ人ならクリリンを殺された怒りでVimがスーパーサイヤエディタへと覚醒します
demo.gif
デモでは音が出ませんが、シュインシュインの効果音も出ています。

あなたがへたれ王子なら恐怖のあまりガタガタ震えます
demo_prince.gif

苦労した点

スーパーサイヤ人らしさ

特徴といえば「逆立った髪」「金色のエフェクト」「シュインシュイン」だと思います。
このうち、「逆立った髪」はエディタで何が逆立つのか分からなかったので却下、「金色のエフェクト」はカラースキームをリアルタイムに変更しようとしたら編集に支障が出るレベルで遅いので却下。
最終的に、金色っぽいカラースキームに変更後、「シュインシュイン」だけ発生させてスーパーサイヤエディタっぽくするようにしました、見辛くてもいけないのでカラースキームも「golden.vim」という名前が金色なもので妥協しました。

技術的な話

以下は今回のプラグインを作成した際の技術的な話です、読み飛ばしてもらっても構いません。

利用したVim8の新機能

exepath

あなたがサイヤ人か、はたまたへたれ王子なのかの判定に利用しています。
それぞれの専用ディレクトリへパスを通したあと、ユーザー名コマンドを作成し、exepathで取得したフルパスに「saiyajin」か「prince」が含まれているかで判定しています。

kuririn-no-kotoka.vim
`-- autoload
    |-- kuririn_no_kotoka.vim # princeとsaiyajinへパスを通す
    |-- prince
    `-- saiyajin
        `-- wordi             # 作成されたユーザー名コマンド

タイマー(Timer)

タイマーはアニメーション処理で利用しています、Vimがスーパーサイヤエディタになるには、いくつかの過程を経る必要があるため、それらをアニメーションで処理しています。

アニメーション処理用の関数はこちらです

kuririno_no_kotoka.vim
" 一定間隔で指定回数funcを読んだあと、最後にnext_funcを呼ぶfunction!s:regist_animate(interval, max_count, func, next_func) abort
  " クロージャ動作をさせるバインドletl:Func =a:func
  letl:Next_func =a:next_func
  letl:max_count =a:max_count
  letl:interval =a:interval
  letl:count=1  " ループコールバックfunction!s:regist_animate_internal_loop(local, timer) abort
    calla:local.Func()" max_count回数呼ばれるifa:local.max_count ==0      " 無限ループreturnendifleta:local.count+=1ifa:local.count>a:local.max_count
      call timer_stop(a:timer)calls:regist_animate_internal_next(a:local.Next_func)endifendfunctioncall timer_start(a:interval,function('s:regist_animate_internal_loop', [l:]), {'repeat': -1})  " 終了時コールバックfunction!s:regist_animate_internal_next(next_func) abort
    letl:Next_func =a:next_func

    function!s:regist_animate_internal_next_internal(local, timer) abort
      calla:local.Next_func()" max_count回数後に呼ばれるendfunction    " NOTE : 非同期でa:local.Next_funcを呼び出し、ループコールバック関数の使用中を解除するcall timer_start(0,function('s:regist_animate_internal_next_internal', [l:]), {'repeat': 1})endfunctionendfunction

この関数を利用して、過程を経てスーパーサイヤエディタになります。

過程は、Stateパターン(のようなもの)で実装しています。
※解説用にシンプルにしています。

regist_animateの利用サンプル
" Phase 1function!s:phase_1() abort
  letl:foo ='local'function!s:phase_1_loop(local) abort
    " ここにアニメーション処理を書く
    echo a:local.foo
  endfunctionfunction!s:phase_1_done() abort
    " 次のPhaseへcalls:phase_2()endfunction  " 50ms間隔でloop関数を40回実行後、done関数を呼び出すcalls:regist_animate(50,40,function('s:phase_1_loop', [l:]),function('s:phase_1_done'))endfunction" ----------------------------------" Phase 2function!s:phase_2() abort
  function!s:phase_2_loop() abort
    " ここにアニメーション処理を書くendfunctionfunction!s:phase_2_loop2() abort
    " ここにアニメーション処理を書くendfunctionletl:remain =0function!s:phase_2_done(local) abort
    leta:local.remain -=1ifa:local.remain <=0      " no-op : 最終Phaseなので何もしないendifendfunction  " アニメーションを合成するcalls:regist_animate(50,40,function('s:phase_2_loop'),function('s:phase_2_done', [l:]))letl:remain +=1  " 異なるFPSでもOKcalls:regist_animate(100,20,function('s:phase_2_loop2'),function('s:phase_2_done', [l:]))letl:remain +=1endfunction

アニメーションは合成が出来ます、今回のプラグインではセリフと震えを合成しています、アニメーションをそれぞれの専用関数に実装して合成すると、FPSの違いを考慮しながら実装する手間がなくなり楽に実装できました。

作ってみた感想

ウインドウの振動を表現するために乱数が欲しいなと思いました!
https://github.com/vim-jp/issues/issues/983

おわりに

悟空が「クリリンのことかー!」と叫ぶのはスーパーサイヤ人になったあとなんですが、勢いがあるので気にしないことにしました。


Viewing all articles
Browse latest Browse all 5608

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>