Neovimに移行したしせっかくなのでGoでプラグインを書いてみた
Google翻訳APIを使ってテキストを翻訳するプラグイン。
作ったあとにVim & Go界隈で著名なhaya14busaさんがほぼ同じプラグインを作ってることに気づきました。
neovim/go-clientを使っていてNeovimでしか動きません。
(python-clientの方だとNeovim/Vim8で手軽に両立するやり方がある模様)
プラグインのインストールにGoが必要です。
サンプルが手薄だったり実装の参考になりそうな他のプラグインがzchee/nvim-goくらいしかみつからなかった(とはいえめっちゃ参考になった)ので、わりとneovim/go-clientのコードとにらめっこしながら書きました。
苦労したところは、previewってどうやってつくるんだろう?とかvim的な知識の足りなさ。一体何をどうするのが正解なのか未だによく分からんです。
ちなみに自分の行き着いたpreviewの作り方は次のとおり。
silent pclose
- previewをとりあえず閉じる
silent pedit +set noswapfile buftype=nofile translated
- ファイルなしでpreviewを開く
wincmd P
- previewに移動する
- neovim/go-clientのメソッドを使って文字列をクリアして書き込む
wincmd p
- previewから抜ける
果たしてこれで合っているのか...?という気持ちですが、今のところ動いてるので良し。もしダメだったらpull-reqください。
あと誰かこの泥臭い部分を隠蔽するいい感じのラッパー作ってください!
おわり
Goだけで完結できるわけではない(vimのコマンドを直接叩いたりする)
それでもvim scriptを書くより敷居は低いし楽しい。
twitchtv/twirp を試した
gRPCのようなフレームワークで、違いはHTTP 1.1で動くこととJSONをサポートしてること。
インストール
protoc-gen-twirpの他にprotocとprotoc-gen-goも必要。
$ go get github.com/twitchtv/twirp/protoc-gen-twirp $ brew install protobuf $ go get github.com/golang/protobuf/protoc-gen-go
protoファイル
まずprotoファイルを書く。
$ mkdir proto
$ vi proto/hello.proto
syntax = "proto3"; package utahta.twirp.example.helloworld; option go_package = "helloworld"; service HellowWorld { rpc Hello(HelloReq) returns (HelloResp); } message HelloReq { string subject = 1; } message HelloResp { string test = 1; }
protocする
protoファイルからgoファイルをつくる。
$ mkdir helloworld $ protoc --proto_path=./proto --twirp_out=./helloworld --go_out=./helloworld ./proto/hello.proto $ ls helloworld hello.pb.go hello.twirp.go
サーバを書く
$ mkdir server
$ vi server/main.go
package main import ( "context" "fmt" "net/http" "github.com/utahta/twirp-example/helloworld" ) type Server struct{} func (s *Server) Hello(ctx context.Context, req *helloworld.HelloReq) (*helloworld.HelloResp, error) { return &helloworld.HelloResp{ Test: fmt.Sprintf("Subject: %s", req.Subject), }, nil } func main() { s := &Server{} handler := helloworld.NewHellowWorldServer(s, nil) http.ListenAndServe(":8881", handler) }
クライアントを書く
$ mkdir client
$ vi client/main.go
package main import ( "context" "fmt" "net/http" "github.com/utahta/twirp-example/helloworld" ) func main() { c := helloworld.NewHellowWorldProtobufClient("http://localhost:8881", http.DefaultClient) resp, err := c.Hello(context.Background(), &helloworld.HelloReq{Subject: "hello twirp"}) if err != nil { panic(err) } fmt.Printf("%#v\n", resp) }
最終的に次のようなディレクトリ構成になった。
. ├── client │ └── main.go ├── helloworld │ ├── hello.pb.go │ └── hello.twirp.go ├── proto │ └── hello.proto └── server └── main.go
実行する
まずサーバを実行。
$ go run server/main.go
次にクライアントを実行する。 すると結果が返ってくる。
$ go run client/main.go &helloworld.HelloResp{Test:"Subject: hello twirp"}
curlで実行する
JSONに対応しているのでcurlを使ってさくっとリクエストできる。
$ curl -H 'Content-Type:application/json' -X POST -d '{"subject":"hello curl"}' "http://127.0.0.1:8881/twirp/utahta.twirp.example.helloworld.HellowWorld/Hello"
雑感
シュッと書いたらProtocolBuffersとJSONで会話できるようになってすごい。便利。
学習コストの低さがなによりいい。
2018年にもなって xargs でハマった
BSD と GNU 版の挙動の違いにハマった。
以下、ミニマムに試した結果。
環境
BSD xargs: macOS 10.12.6
GNU xargs: ubuntu 18.04 xargs (GNU findutils) 4.7.0-git
同じ
BSD xargs
$ echo "a b c" | xargs -n1 a b c
GNU xargs
$ echo "a b c" | xargs -n1 a b c
異なる
BSD xargs
$ echo "a b c" | xargs -n1 -I {} echo {} a b c
GNU xargs
$ echo "a b c" | xargs -n1 -I {} echo {} a b c
このように異なるおかげで、a, b, c と1つずつ処理しているつもりが、GNU版では一度に処理されてしまって、意図しない動きになっていた。
macOS では動くのに CI で動かない状態だったので、気づくのにすこし時間がかかった。つらい。
man をみたところ、GNU版は、-I
を使うとセパレータが改行になるらしい。ヘー。
面倒くさくなったので、xargs を使わないように改修した。