vital-smtpを作った
Vim Advent Calendar 2014の7日目の記事です。 昨日は@katono123さんのVim script + Lua で rogue.vim を作った話でした。
以前unite-notmuchというメールを閲覧するプラグインを作ったのですが、 メールを送信する機能がないため、これと組み合わせて使うメール送信プラグインが欲しいと思っていました。
探してみると
などが見つかりましたが、これらは単体で使用するためのプラグインなので他のプラグインと組み合わせて使うには向いていないようです。
やはりVimでメールを送りたいという人がいないからなのか、これといったものが見つからなかったので自作してみることにしました。
他のプラグインと組み合わせて使うというと真っ先に思いつくのがvital.vimです。
少し前から気にはなっていたのですが(vital-overなど)、vital.vimは独自に外部モジュール作ることができるようなので今回はそれを試してみます。
1. vital外部モジュールの作成
作成するのはSMTPでメールを送信するvitalモジュールなのでプラグイン名は vital-smtp とします。
まずはプラグイン用のディレクトリ、 vital-smtp を作成します。
中身は本家vital.vimと同じでautoload配下に vital/__latest__ を配置すれば良いようです。
プラグイン本体はその配下に配置することになるので SMTP.vim を作成します。
vital-smtp └── autoload └── vital └── __latest__ └── SMTP.vim
完成したプラグインはこちらです。
pythonのsmtplibを利用してメールを送信する s:sendmail という関数があるだけの簡単なプラグインになりました。
function! s:sendmail(addr, user, password, from_addr, to_addrs, msg) " 省略 endfunction
2. vital外部モジュールの使い方
vitalの外部モジュールを作成したら次は実際にプラグインに組み込んでみることにします。
とりあえず確認用なので適当なディレクトリにサンプルプラグインを作ります。
$ mkdir vim-sendmail-example $ cd vim-sendmail-example/ $ mkdir autoload plugin $ vim plugin/sendmail_example.vim
組み込み方はvital-smtpがVimのruntimepathに通っていれば通常のvitalモジュールと同じようにVitalizeコマンドを実行するだけです。
:Vitalize --name=sendmail_example . SMTP
プラグイン内での呼び出し方も同様で、 import するだけで先ほど作成した関数を使うことができるようになります。
let s:SMTP = vital#of('sendmail_example').import('SMTP') " call s:SMTP.sendmail()が使えるようになる
完成したサンプルプラグインはこちらです。
:Sendmail コマンドを実行するとプロンプトに入力した内容でメールを送信します。
3. メール送信の確認
手っ取り早く使えそうなSMTPサーバが思いつかなかったのでローカルのメールサーバでサンプルプラグインの確認をします。
# pythonに付属しているデバッグ用サーバを起動する $ sudo python -m smtpd -c DebuggingServer localhost:10025
サーバが起動したらVimを立ち上げてサンプルプラグインの:Sendmailコマンドを実行します。
:Sendmail host: localhost<Enter> port: 10025<Enter> user: <Enter><Enter> password: <Enter> from: test@example.com<Enter> to: test@example.com<Enter> msg: test<Enter>
msgにtestと入力してEnterを押すとメールサーバのコンソールにVimから送ったメールが表示されました。
---------- MESSAGE FOLLOWS ---------- From: test@example.com To: test@example.com X-Peer: 127.0.0.1 test ------------ END MESSAGE ------------
4. テストの追加
順番は置いておいて、せっかくプラグインを作ったのでthincaさんのvim-themisを使ったテストを追加しておきます。
vital-smtp ├── autoload │ └── vital │ └── __latest__ │ └── SMTP.vim └── test └── SMTP.vim
テストはthemisコマンドに --runtimepath でvital-smtpに必要なプラグインを指定して実行します。
$ themis --runtimepath /tmp/vital.vim 1..9 ok 1 - SMTP test_import ok 2 - SMTP test_sendmail_success ok 3 - SMTP test_sendmail_success_without_starttls ok 4 - SMTP test_sendmail_success_without_login ok 5 - SMTP test_sendmail_failed_to_connect ok 6 - SMTP test_sendmail_failed_to_starttls ok 7 - SMTP test_sendmail_failed_to_login ok 8 - SMTP test_sendmail_failed_to_send ok 9 - SMTP test_sendmail_failed_to_quit # tests 9 # passes 9
5. ハマったところ
if_pyの例外
pythonで例外が発生するとコマンドラインにはpythonのTraceが表示されますが、
v:exception が常に 'Vim(python):Traceback (most recent call last):' になってしまうため、
Vim script内ではcatchできなくて困りました。
これが仕様なのかはよくわかりませんが、今回はif_py側で例外を捕捉したら文字列にしてVim script側に返す作りにしました。
if_pyを使った関数のテスト
pythonのsmtplib周りのテストにはメールサーバが必要なのですが、
例外を発生させるためのメールサーバを用意するのが面倒だったので
mockを使うことにしました。
ただテストが
- Vim script: テスト関数が呼ばれるとmockを使うためにpythonを呼び出す(テストスクリプト)
- python: mockでsmtplibの挙動を制御して外部モジュールを呼び出す(テストスクリプト)
- Vim script: 引数を受け取ってpythonに渡す(外部モジュール)
- python: smtplibを使ってメールを送信し、例外が発生したらVim scriptに返す(外部モジュール)
- Vim script: pythonで例外が発生していたらthrowする(外部モジュール)
- python: 外部モジュールで例外が発生していたら文字列にして返す(テストスクリプト)
- Vim script: 戻り値が期待通りか判定する(テストスクリプト)
と、Vim scriptとpythonを行ったり来たりでとても気持ち悪いものになってしまいました。
さて、目的のメール送信プラグインは作れたのでそのうちunite-notmuchにvital-smtpを組み込むなどしてメールを送信できるようにしたいと思います。
が、MIME関連の機能が足りないのでその前にvital-mimeが必要になるのかも...!?
それからテストをTravis CIで動かしたくてTravis CIにアカウントを作ってみたのですがローカルで全部通ったテストが大コケしたまま、 この記事を書いていたTokyo Vim#23がタイムアウト(スマブラタイム)してしまったので時間があるときに調べてみることにします。
明日は去年に引き続き@Linda_ppさんです。
スマブラでボコボコにされている様子。
そのあと本日発売のWii U版スマをブラした!
一回だけ奇跡の一位! pic.twitter.com/cKKYhaSOgM
— yoshiko (@yoshiko_pg) 2014, 12月 6
VimConf 2014に行ってきて
改めて思ったのは、
若手の勢いがすごい
ということ。
今回の発表者は多分ほとんどが自分と同年代かそれ以下だったはず。
参加者も懇親会でちょこちょこと話した感じだと若い/ビギナーな人が多かったし、
(凡人の自分と比べても仕方がないんだけど)みんな才能に溢れているように感じた。
他の勉強会にはほとんど行ったことがないからよくわからないけど
10年以上使われているとはいえ、プログラミング言語ではなく
ソフトウェアでこんなに素晴らしい若手が集まるのは本当に凄いと思う。
一利用者として今後のVimがとても楽しみだし期待しています。
って言ってるだけじゃなく、負けずに少しでも何かに貢献していきたいとは思うんけど
さてどうなることやら...
あ、各セッションの感想については小並感なので割愛で。
autorepeat.vim作った
犬Vimmerはf拡張プラグインを作る*1
↓
自分も犬Vimmerだ
↓
けどf系って実はあまり使っていない...
↓
ひとまずfにこだわらず横移動プラグインを考えてみよう
↓
1キーで自動的にカーソル移動が始まって好きなタイミングで止める、とかどうだろう?
↓
autorepeat.vim完成
結局1キーではできなかったのでトリガーを入力した後に
繰り返したい操作を続けて入力するという作りにしました。
具体的な使い方としてはvimrcに
nmap <Space>. <Plug>(autorepeat)
のような設定をし、
<Space>.
の後に繰り返したいノーマルモードコマンドを入力します。
" 例 <Space>.l
なお、今のところノーマルモードにしか対応していません。
繰り返しが始まるまでの時間は
g:autorepeat_timeout
に秒単位の数値、
繰り返し操作の間隔は
g:autorepeat_interval
に:sleepコマンドの引数と同様の文字列で指定することが可能です。
ちょっと使ってみた感じ、慣れないと使いこなすのは難しそう...
まだ微妙なプラグインを作ってしまったか。
Vimでメールを読む
前回のTokyoVim#19でunite-notmuchというプラグインを作りました。
このプラグインはnotmuchというコンソール上で動作するメールリーダーを使い、
Uniteのインターフェースから
- メールの表示
- メールの検索
- メールの未読/既読の切替
をすることができます。
なお、
- メールの受信
- メールの送信
はそもそもnotmuch本体が出来ないのでこのプラグインでも出来ません。
また、notmuchがWindowsでは使えないようなのでこのプラグインも使えません。
必要なソフト
- notmuch
- メールを受信するソフト
- offlineimap
- fetchmailなどでも可
メール環境の設定(offlineimap編)
- notmuchのインストール
# Mac OS X $ brew install notmuch # Linux(gentoo) $ sudo emerge notmuch
- notmuchの設定
$ vim ~/.notmuch-config
[database] # 絶対パスで指定する path=/Users/ユーザ名/Maildir #path=/home/ユーザ名/Maildir [user] name=アカウント名 primary_email=メールアドレス [new] tags=unread;inbox; ignore= [search] exclude_tags=deleted;spam; [maildir] synchronize_flags=true
- offlineimapのインストール
# Mac OS X $ brew install offlineimap # Linux(gentoo) $ sudo emerge offlineimap
- offlineimapの設定
$ vim ~/.offlineimaprc
[general] metadata = ~/.offlineimap accounts = アカウント設定名 [Account アカウント設定名] localrepository = ローカル設定名 remoterepository = リモート設定名 status_backend = sqlite postsynchook = notmuch new [Repository ローカル設定名] type = Maildir # notmuch-configのdatabaseで指定したパス localfolders = ~/Maildir/ [Repository リモート設定名] type = IMAP remotehost = メールサーバ remoteuser = アカウント名 remotepass = パスワード maxconnections = 1 folderfilter = lambda foldername: foldername in ['INBOX']
使い方(offlineimap編)
事前に
$ offlineimap
でメールを受信しておく必要があります。
いちいちコマンドを実行するのが面倒ならcronにでも仕込んでおけば良いらしいです。
メールを受信したらVimから以下のコマンドを実行します。
:Unite notmuch
フォルダ一覧画面では以下のアクションが実行可能です。
- フォルダを開く(open)
- フォルダ内のメールを既読にする(read)
- フォルダ内のメールを未読にする(unread) => TokyoVim#20で追加
- フォルダ内のメールを検索する(search) => TokyoVim#20で追加
フォルダを開いた後のメール一覧画面では以下のアクションが実行可能です。
- メールを開く(open)
- 選択したメールを既読にする(read)
- 選択したメールを未読にする(unread) => TokyoVim#20で追加
- メールをプレビューウィンドウで開く(preview) => TokyoVim#20で追加
興味がある人は使ってみてください。
TokyoVim#19に行ってきます
今日はTokyoVim#19です。
ゴールデンウィークで鈍ったVim力を鍛え直しましょう。
今年のゴールデンウィークは去年よりたくさん休んでしまい、
なんとその間にメールが4000通近くもたまってしまいました。
普段メーラーはWindows上のThunderbirdを使っていますが、
処理するのがさすがにしんどかったのでなんとかしたいです。
そこで思いついたのがVim上でメールを処理するという方法。
リモートからでもsshで繋いでコンソールから使うことができ、
就業時間の99%をVim上で過ごす人にはかなり便利そうです。
ただVim上で動くメーラーというのはGmail用ばかりで普通のメーラーは
なかなか良さそうなのがみつかりませんでした。
notmuch.vimというプラグインはあるものの、
- Vimの設定を勝手に変えるっぽい
- フォルダに大量のメールがあると固まる
など、ちょっとイマイチだったので今回のTokyoVimでは
このnotmuchをUniteあたりから使えるようにしてみたいと思います。
TokyoVim#18に行ってきた
TokyoVim#18に行ってきました。
今回の目標はdaisuzu/translategoogle.vim · GitHubのドキュメントを書くことだったので最初はgoogle/vimdoc · GitHubで書こうと色々試してみました。
が、LeafCage/vimhelpgenerator · GitHubの変数にあたる部分をうまく生成することができず、結局普通に書いてしまいました。
ただ、コードのコメントからドキュメントを自動生成するというのはメンテナンスがしやすそうなので今後のバージョンアップに期待したいです。
※見た感じgoogle/maktaba · GitHubのようなライブラリを対象にしているような気がしたので普通のプラグイン向けになるかはわかりませんが...
あとはプラグインに自分が使いそうなコマンドを追加したりとかしていたらあっという間に終わってしまいました。
終了後は懇親会に行き、他のVimmerと交流しながらVim Advent Calendar 2013 : ATNDの記事を書いたりしていました。
次回はちょろっと話に上がったハトクラをやりたいです。
Vimでマウスを使った矩形選択がしたい
Vim Advent Calendar 2013の133日目の記事です。
昨日、後輩(コンソールではVimを使っている)が
「矩形選択が楽なのでxyzzy使っています」
と言っていたので
- Alt + LeftMouse
- マウスドラッグで選択開始してCtrl + V
でVimでも同じようにできるよ。
と教えてあげました。
Vimでマウス...!?とか言われてしまいそうですが、
任意の範囲を選択したいときにはマウスが便利だと思います。
明日のVim Advent Calendarはどうも書く人がいないようですが、
きっと本日のTokyoVim#18に参加して進捗を出せた人が書いてくれると思います。
ちなみにこの記事はPC利用率100%のTokyoVim#18懇親会会場で書いています。