はじめに
pecoを使ってみて、どう実装しているのか気になったのでソースコードを読み始めました。まだ読み始めたばかりなので、全然理解できていないのですが、pecoで使われているjessevdk/go-flagsを使ってみたので、それについて書きたいと思います。内容としては、お試しで実装して動かしたことと、読んだドキュメントの紹介になります。
実装
package main
import (
"fmt"
"github.com/jessevdk/go-flags"
)
type cmdOptions struct {
OptHelp bool `short:"h" long:"help"`
OptTTY string `long:"tty"`
OptQuery string `long:"query"`
OptRcfile string `long:"rcfile"`
OptNoIgnoreCase bool `long:"no-ignore-case"`
OptVersion bool `long:"version"`
OptBufferSize int `long:"buffer-size" short:"b"`
OptEnableNullSep bool `long:"null"`
OptInitialIndex int `long:"initial-index"`
OptInitialMatcher string `long:"initial-matcher"`
OptPrompt string `long:"prompt"`
}
func main() {
var err error
// fmt.Print("Start\n")
opts := &cmdOptions{}
p := flags.NewParser(opts, flags.PrintErrors)
args, err := p.Parse()
if err != nil {
fmt.Print("Error\n")
return
}
if 0 < len(args) {
fmt.Print(args[0] + "\n")
}
if opts.OptHelp {
fmt.Print("OptHelp\n")
}
if opts.OptVersion {
fmt.Print("OptVersion\n")
}
if opts.OptRcfile != "" {
fmt.Print("OptRcfile: " + opts.OptRcfile + "\n")
}
if opts.OptNoIgnoreCase {
fmt.Print("OptNoIgnoreCase\n")
}
if opts.OptInitialMatcher != "" {
fmt.Print("OptInitialMatcher: " + opts.OptInitialMatcher + "\n")
}
if opts.OptQuery != "" {
fmt.Print("OptQuery: " + opts.OptQuery + "\n")
}
if opts.OptPrompt != "" {
fmt.Print("OptPrompt: " + opts.OptPrompt + "\n")
}
// fmt.Print("End\n")
}
試し方
まず、パッケージが必要になると思いますので、次のコマンドを実行します。
$ go get github.com/jessevdk/go-flags
次に、実行ファイルを作成するために、次のコマンドを実行します。
$ go build sample.go
ここまでの作業で、ソースファイルと同じフォルダに実行ファイルが作成されたと思います。ここではsample
という実行ファイルが作成されると思います。あとは、いろいろなオプションで実行ファイルを実行するだけです。しかし、どんなオプションで実行すれば試せるのでしょうか?
どんなコマンドラインのオプションがこの実行ファイルにあるのか?
お試し実装の構造体の宣言のところなのですが、フィールドの宣言でバッククォートを使っています。これは未加工文字列リテラルで、バッククォート内の文字列シーケンスをそのまま使うものです。例えば、バックスラッシュをそのままバックスラッシュとして使います。
このバッククォートのところをよく見てみると、コマンドラインのオプションを定義しているように見えます。例えば、-h
や--help
というオプションを-p
と--print
にしたければ、次のようにソースファイルを編集すれば良さそうです。
- OptHelp bool `short:"h" long:"help"`
+ OptHelp bool `short:"p" long:"print"`
C++言語の構造体を想像していたので、こういうことができるとは思っていませんでした。ぐぐってみると、Go言語仕様翻訳(part5)に次のようにありました。
フィールドの宣言には、オプションで文字列リテラルを使ってタグを指定することができます。タグはそれが記述されているフィールド宣言の全フィールドの属性となります。タグはリフレクションインタフェースを使って参照できますが、それ以外は無視されます。
ここまでの話で、おそらく、どんなコマンドラインのオプションがこの実行ファイルにあるのか読み解くことができるようになったと思います。時間のある方は確認してみてください。。。
まとめ
Go言語を触りながら、clib の使い勝手にマジ感動したを思い出していました。github上にあるパッケージを手軽に利用できるというのは嬉しいですね。