2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CLI上でインタラクティブに電卓が叩けるツール「dntk」を書きました

Last updated at Posted at 2018-06-10

これ is なに

Go言語で書かれた軽量で鮮やかな見た目でインタラクティブに電卓が叩けるCLIアプリです。
https://github.com/nnao45/dntk
dntk-demo01.gif
最大のポイントはpecoのようなインタラクティブなインプットが可能なアプリな所であり、1文字1文字計算していくので楽しく電卓を叩ける所にあります。入れた入力はdeleteキーやbackspaceキーで消せますし、消してる最中もインタラクティブに計算します(これは頑張った😓✌️)
またGNU bcという標準的なツールのラッパーですので、多くのLinux/UNIX/BSD/Mac上で動作が可能です👍

終了するときは、qEnterEscCtrl + cです、

各種インストール方法

Mac

$ brew install nnao45/dntk/dntk

Linux

$ wget https://github.com/nnao45/dntk/releases/download/{最新のバージョン}/dntk-linux-amd64-{最新のバージョン}.tar.gz
$ tar xvfz dntk-linux-amd64-{最新のバージョン}.tar.gz

zplug

$ zplug 'nnao45/dntk', as:command, from:gh-r

なんで作ったの?

僕が欲しかったから作った。

んですけど、それだと話が終わってしまうのでそれっぽく書きます。

bcコマンドが、

$ bc -q                                                    
123 * 2
246

と無機質なアウトプットで寂しいなと思ったのと、
これがインタラクティブにダララララララララと表示されたら格好良く無いですか!?!?!?!?!???と思い作りました✌️(適当)
dntk-demo-qiita.gif

またデザインはbash等でCtrl + rを打った時の、

$ #Ctrl + rを打つ
(reverse-i-search)`':

が好きだったのでそれに近しいデザインにするよう設計しました。

GNU bcとシンタックスが同じ

dntk最大の特徴として、GNU bcの資源を全て使う事にあります(ラッパーしてるからね😜)

足し算

$ dntk
(dntk): 123 + 456 = 579

引き算

$ dntk
(dntk): 987 - 543 = 444

掛け算

$ dntk
(dntk): 345 * 984 = 339480

割り算

$ dntk
(dntk): 999 / 67 = 14.9104477611

デフォルトで小数点以下10位切り捨てですが、もちろん--scaleオプションで桁数は指定できます

$ dntk --scale 20
(dntk): 999 / 67 = 14.91044776119402985074

べき乗計算

$ dntk
(dntk): 2 ^ 2 ^ 2 ^ 2 = 65536

各種関数も対応

a(123)のような関数入力に対応していて、しかも入力補助機能も搭載しております。
dntk-demo02.gif

a(123)と打つのに、普通は

a
(
1
2
3
)

と打たないといけない所、

a
1
2
3
Enter

で入力が出来るようにしてあります。
意外とこれだけでも相当入力が簡単になるのがわかるかも。。。?

function command detail
(x) ( Simple round bracket
sin(x) s Sin of trigonometric function
cos(x) c Cosin of trigonometric function
atan(x) a Tangent of inverse trigonometric function
log(x) l Logarithm function
exp(x) e Exponential function
j(n,x) j The n-order Bessel function

(これもbcをラッパーしてるからってのはそうなんだけど、それもあるからただ乗っかっただけだと悔しいので入力補助機能も入れてみました)

他にもエイリアス張ったりとかの機能がありますが、残りはREADMEをご覧ください。

ちょこっとだけ実装の話

いつもながら実装の話はいいやって人はここでご静聴いただきありがとうございました😆
もし需要があれば詳しく書きますが、まぁ長くなってもなと思いますので、ちょっとだけ。

termbox-goを使わない選択

こういう事がやりたいときはtermbox-goが大変便利なのですが今回、僕がやりたかったのはbash等でCtrl + rを打った時の、

$ #Ctrl + rを打つ
(reverse-i-search)`':

のこれでした。これを実現するためには、ターミナル画面全てを別の仮想端末に飛ばしてしまうような仕様は合っていなく、あいにく使っておりません。かなり僕の中でも挑戦でしたが、**しかしこれがとんでも無い沼でした。。。。**以下の問題は、termbox-goを使ってさえいれば簡単に解決します。。。。笑

キー入力

一番最初につまづいた所はキー入力対応でした。
キー入力したものをインタラクティブに処理するためには、一旦標準入力で受けたキーを全てハンドリングしてなにかしらのバッファに詰めておいた物を操作する流れにしなければいけません。

しかし、そもそもキー入力を受け取る事自体大変でした。

まずそもそもgoが標準入力をキー操作から受け取る際には、io.EOFを受け取った時点で読み込みを終了する仕様なので、あれ、そもそも無理なんじゃ無いかという所でスタートしました。
これは仕方ないので以下の無理やりシェルコマンドで標準入力を特殊なインプット形式でハンドリングする事で可能としています。

	// disable input buffering
	exec.Command("stty", "-F", "/dev/tty", "cbreak", "min", "1").Run()
	// delete \n
	exec.Command("stty", "-F", "/dev/tty", "erase", "\n").Run()
	// do not display entered characters on the screen
	exec.Command("stty", "-F", "/dev/tty", "-echo").Run()
	// restore the echoing state when exiting
	defer exec.Command("stty", "-F", "/dev/tty", "echo").Run()

ポイントは1-2行目で、これを入れる事で/dev/ttyからの入力をバッファリングする機能を無効にしてしまいます。これにより、1文字ずつ入力が終了するような仕様にしてしまいます。

特殊な事をさせたいキー入力を読み取る

例えばEnterキーとかdeleteキーとかそういう特殊な事をさせたいキーに対して、とても困りました。
数字や英語はとにかく全部もらったバイト列ごと突っ込んであとでstringにでも変えてやればいいのですが、Enterキーとかdeleteキーとかはそうにもいきません。さらにキー入力で入れるバイト列はASCIIコードなのでただ数字が入ってるだけでも無いのでハンドリングが難しいので、ここでgoの魔力を借ります。goはキー入力に対し、なぜかstringに変える際にラッパーの経緯により[123]のようなASCIIの後ろの2文字3文字の数字だけを表示させる謎仕様です。
これを利用して、受け取ったキー入力をハンドリングさせています。

➗0問題

dntkではこの数学界のタブーについてはnilと表示させています。
普通こんなもの入力されたら、とっととpanicでもexitでもしておけばよいのですが、そう、dntkはインタラクティブに計算していくので、例えば以下のような、

$ dntk
(dntk): dntk): 999 / 0.000067 = 14910447.7611940298

をやりたいときどうしても、

$ dntk
(dntk): dntk): 999 / 0

の瞬間ができてしまいます。これでpanicなんて起こしてたら小数点以下の割り算ができないポンコツ電卓になってしまいます、困りました😓

そこで、dntkはGNU bcコマンドが数学的エラーを起こした時のみ標準エラー入力を出力する事に注目して、bcコマンドの標準出力と標準エラー出力をハンドリングし、標準エラー入力になにかしら出力されたときはnilと表示するだけ、という対策をとりました。

終わりに

なかなかカッコいい仕上がりになったかなと思っていますが、バグなどまだあるかと思うので、何かあればissueをお待ちしております🐶

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?