概要
Go言語でJavaScriptを使ってオリジナルなコマンドシェルを作る シリーズの第4弾です。
Go言語で作られたアプリやあるライブラリのサンプルなどをこのJavaScript環境に統合することを考えます。アプリによっては出来なかったり、手直しが必要なものがあります。
もともとこのコマンドシェルを作ったの自分が使いたいものを一つのバイナリでかつJavaScriptをコマンド替わりに使おうということです。なので便利な既存のGo製のツールやサンプルを統合しましょう。
前提としてgo moduleで話を進めますので、depなどを使っている方には申し訳ありません。
統合するアプリ
事前準備
モジュール名をmyshell
とします。アプリのルートディレクトリもmyshell
とします。
> cd myshell
> go mod init myshell
go: creating new go.mod: module myshell
> mkdir cmd
いままで作成したmain.go
をmyshell/cmd/main.go
と配置します。
> cd cmd
> go run main.go
go: finding github.com/dop251/goja latest
go: finding golang.org/x/text/unicode/norm latest
go: finding golang.org/x/text/collate latest
go: finding golang.org/x/text/cases latest
go: finding golang.org/x/text/language latest
go: finding golang.org/x/text/unicode latest
> print(10)
10
undefined
> exit
となりまして無事コンパイルできました。
これまで作成したexcel
やweb
のソースを分けるときはには注意してください。main
パッケージで作成したのでjs.Runtime
にアクセスできましたが違うパッケージにするとアクセスできなくなります。
jidサンプルの統合
https://github.com/simeji/jid/blob/master/cmd/jid/jid.go
のソースを取り込みます。
取り込みますがJavaScriptとの相互使用はしません。あくまでコマンドとしてアプリの起動のみです。
当然アプリなのでmain
があるのでそのままではダメです。
まず、関数名などが被らないように固有のパッケージ名にします。今回はmyshell/myjid
というパッケージ名します。ダウンロードしたソースjid.go
はmyshell/myjid/jid.go
に配置します。
以下に変更したソースを示します。 //myjid
が付いている箇所が変更箇所です。os.exit
は全てreturn
にしました。flag.BoolVar
同じパラメータで一度しか実行できないので最初の起動のみにしました。このサンプルのJSONデータは標準入力でしたがJavaScriptからJSON文字列で渡すようにしました。*goja.Runtime
も渡せばJavaScriptと相互使用ができるでしょう。main
はMainJid
としました。
import "myshell/myjid"
func initialSetting() *jsRuntime {
rt.Set("jid",myjid.MainJid)
}
package myjid //myjid
import (
"flag"
"fmt"
"strings"
"github.com/simeji/jid"
)
const VERSION = "0.7.6"
var isJidExec = false //myjid
func MainJid(json string) { //myjid
//content := os.Stdin //myjid
content := strings.NewReader(json) //myjid
var qm bool
var help bool
var version bool
var mono bool
var pretty bool
qs := "."
if !isJidExec { //myjid
flag.BoolVar(&qm, "q", false, "Output query mode")
flag.BoolVar(&help, "h", false, "print a help")
flag.BoolVar(&help, "help", false, "print a help")
flag.BoolVar(&version, "version", false, "print the version and exit")
flag.BoolVar(&mono, "M", false, "monochrome output mode")
flag.BoolVar(&pretty, "p", false, "pretty print json result")
flag.Parse()
isJidExec = true //myjid
} //myjid
if help {
flag.Usage()
fmt.Println(getHelpString())
//os.Exit(0) //myjid
return //myjid
}
if version {
fmt.Println(fmt.Sprintf("jid version v%s", VERSION))
//os.Exit(0) //myjid
return //myjid
}
args := flag.Args()
if len(args) > 0 {
qs = args[0]
}
ea := &jid.EngineAttribute{
DefaultQuery: qs,
Monochrome: mono,
PrettyResult: pretty,
}
e, err := jid.NewEngine(content, ea)
if err != nil {
fmt.Println(err)
//os.Exit(1) //myjid
return //myjid
}
//os.Exit(run(e, qm)) //myjid
run(e, qm) //myjid
}
func run(e jid.EngineInterface, qm bool) int {
result := e.Run()
if result.GetError() != nil {
return 2
}
if qm {
fmt.Printf("%s", result.GetQueryString())
} else {
fmt.Printf("%s", result.GetContent())
}
return 0
}
func getHelpString() string {
return `
============ Load JSON from a file ==============
$ jid < file.json
============ With a JSON filter mode =============
TAB / CTRL-I
Show available items and choice them
CTRL-W
Delete from the cursor to the start of the word
CTRL-U
Delete whole query
CTRL-F / Right Arrow
Move cursor a character to the right
CTRL-B / Left Arrow
Move cursor a character to the left
CTRL-A
To the first character of the 'Filter'
CTRL-E
To the end of the 'Filter'
CTRL-J
Scroll json buffer 1 line downwards
CTRL-K
Scroll json buffer 1 line upwards
CTRL-G
Scroll json buffer to bottom
CTRL-T
Scroll json buffer to top
CTRL-N
Scroll json buffer 'Page Down'
CTRL-P
Scroll json buffer 'Page Up'
CTRL-L
Change view mode whole json or keys (only object)
ESC
Hide a candidate box
`
}
実行してみます。Windowsの場合はchcp 65001
にしてUTF-8にしてください。そうしないとjid
で日本語表示が乱れます。
chcp 65001
go run main.go
> doc = [
...> {a:1, b:"1111111"},
...> {a:2, b:"あいうえお"}
...> ]
[{"a":1,"b":"1111111"},{"a":2,"b":"あいうえお"}]
> json=JSON.stringify(doc)
[{"a":1,"b":"1111111"},{"a":2,"b":"あいうえお"}]
> jid(json)
doc変数はJavaScriptのオブジェクトなのでjid
には直接渡せませんのでJSON.stringify
で文字列にしてからjid
に渡します。jid
の画面に切り替わります。文字列を直接渡すときは必ずa
などの項目名は"a"
と引用符を付けてください。
[Filter]> .[
[
{
"a": 1,
"b": "1111111"
},
{
"a": 2,
"b": "あ い う え お "
}
]
[Filter]> .[1]
{
"a": 2,
"b": "あ い う え お "
}
[Filter]> .[1].b
"あ い う え お "
終了時にはCTRL+U
を押して初期状態に戻して.q
で終了します。あまり詳しくないので他の操作があるかもしれません。
termdashdemoデモを統合
パッケージはmyshell/mytermdash
とします。
https://github.com/mum4k/termdash/blob/master/termdashdemo/termdashdemo.go
をダウンロードしてmyshell/mytermdash/termdashdemo.go
と配置します。
これに関してはソースの量が多いので変更箇所のみ掲載します。
import "myshell/mytermdash"
func initialSetting() *jsRuntime {
rt.Set("dash",mytermdash.MainTermdash)
}
package main
// を以下に変更
package mytermdash
func main()
// を以下に変更
func MainTermdash()
これだけの変更で実行できます。
go run main.go
> dash()
以下の画面に切り替わります。ESC
を押せば終了します。中央のtext
やlinechart
などのボタンをマウスでクリックしてみてください。画面が変わります。
まとめ
パッケージを分けることによって関数や変数がバッティングしないようにします。そしてmain
を適当な名称に変更してJavaScriptに関係付けます。オリジナルのアプリがコマンドライン引数を必要とする場合はmain
の引数として渡すなりの工夫が必要になります。
いろいろなコマンドを作成したり、既存のアプリを統合したりして自分が使いやすいツールとして作成していきます。Go言語には有用なパッケージが多数存在しますのでどんなツールになるか楽しみです。
また、JavaScriptのRuntimeを複数作って切り替えることも考えていますが、使い道があるかは分かりません。
Go言語パッケージの一覧は下記が有用です。
次回の投稿はこのシリーズの最後として、最初の投稿に書いたgoja
の簡単な改造を説明します。