Golang で Windows 用のエイリアスツールをつくった

Golang の勉強も兼ねて、alauncher という Windows 用エイリアスツールをつくってみました。

- [stakiran/alauncher](https://github.com/stakiran/alauncher)

本記事では alauncher の紹介と、今回学んだこと(Golang ネタ)についてまとめます。

# デモ
まずはじめに、alauncher を使ってどんなエイリアスがつくれるのかを軽く紹介します。

## GIF
簡単な GIF をつくってみました。

登場するのは pushd のエイリアス pd、popd のエイリアス pb、cd .. のエイリアス b、explorer . のエイリアス here、exit のエイリアス qq です。

![190718_alauncher_demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191170/249643e9-d6cb-bafe-93c4-1bd18eb95d5d.gif)

## pushd を pd、popd を pb、cd .. を b で実行する
よく使うディレクトリ移動をエイリアスで楽にしてみました。

pd で pushd

```
$ cd
c:\work

$ pd dir1\dir2\dir3
c:\work\dir1\dir2\dir3

$ cd
c:\work\dir1\dir2\dir3
```

pb で popd

```
$ cd 
c:\work\dir1\dir2\dir3

$ pb
c:\work

$ cd
c:\work
```

b で一段上がる

```
$ cd
c:\work\dir1\dir2\dir3\dir4\dir5

$ b
c:\work\dir1\dir2\dir3\dir4\dir5
  VVV
c:\work\dir1\dir2\dir3\dir4

$ b
c:\work\dir1\dir2\dir3\dir4
  VVV
c:\work\dir1\dir2\dir3

$ b
c:\work\dir1\dir2\dir3
  VVV
c:\work\dir1\dir2

$ b
c:\work\dir1\dir2
  VVV
c:\work\dir1

$ cd
c:\work\dir1
```

## qq でコンソールを終了する
終了するときに exit と打つのはちょっと打ちづらいので、qq で終了できるようにしてみました。

```
$ qq
```

## e xxx.md で愛用エディタで xxx.md を開く
私は秀丸エディタを使っているのですが、秀丸エディタはコマンドラインでは実行できるようになっていません。なので、実行できるようにします。

ここではエイリアスとして hidemaru, hide, e の三つを登録してます。どれを使っても秀丸エディタで開けます。

```
$ hidemaru xxx.md

$ hide xxx.md

$ e xxx.md
```

私は hide を使ってます。

## here でカレントディレクトリを Explorer で開く
「あー、今いるディレクトリをフォルダウィンドウで開きたいなー」ということがたまにあります。here というエイリアスで行えるようにしてみました。

```
$ cd
C:\Users\XXXXXXXX

$ here
```

これで C:\Users\XXXXXXXX が Explorer で開きます。

## Google 日本語入力のプロパティを googleja で開く
言語バーは邪魔なので普段非表示にしているのですが、そうすると困るが「IME のプロパティを見たい」ときです。いちいちバーを再表示するのは面倒。

幸いにも Google 日本語入力には、プロパティ画面を開くコマンドラインがあるので、そのエイリアス googleja をつくることで簡単に開けるようにしました。

```
$ googleja
```

## a でカレントディレクトリ直下をインクリメンタルサーチして cd する
ちょっとした応用例です。

[peco](https://github.com/peco/peco) を使って「カレントディレクトリ直下をインクリメンタルサーチして cd する」ことを実現します。事前に peco のインストールが必要です(ここでは取り上げません)。

```
$ cd
c:\Windows

$ a
<<< peco が立ち上がるのでインクリメンタルサーチします >>>
<<< ここでは「32」で「system32」を絞り込んだとします >>>
c:\Windows\System32

$ cd
c:\Windows\System32
```

# デモを実現する設定ファイル
上記のデモを実現する設定ファイルは、たとえば以下のようになります。

※outdir には PATH の通ったディレクトリを指定します。

(2019/08/01 追記) b.bat のエイリアス設定が正しく動作しなかったのを修正しました。alauncher v0.1.0 が必要です。

```ini
[_options]
outdir=D:\bin1\PATH\alancher

[_variables]
myeditor=C:\Program Files\Hidemaru\Hidemaru.exe

[pd]
rawbin=pushd %* & cd
disable=setlocal

[pb]
rawbin=popd & cd
disable=setlocal

[b]
rawbin=echo %cd%%n%echo %s%VVV%s%%n%cd ..%n%echo %cd%
disable=setlocal

[qq]
rawbin=exit

[pp]
rawbin=prompt $$%s%
disable=setlocal

[hidemaru]
bin=%myeditor%
prm=%*
alias=hide,e

[here]
rawbin=explorer .

[googleja]
rawbin=start "" "C:\Program Files\Google\Google Japanese Input\GoogleIMEJaTool.exe" --mode=config_dialog

[a]
rawbin=for /f "usebackq delims=" %%a in (`dir /ad /b ^| peco --select-1`) do pushd %%a & cd
disable=setlocal
```

# あらためて alauncher とは
alauncher は Windows 用のエイリアス作成ツールです。

C:\Users\XXXXXXXX\.ala.ini という単一 INI ファイルにエイリアス設定を書き、alauncher コマンドを実行してビルドすることでエイリアスを配置する、というものです。

## 使い方
インストール方法や細かい初期設定などは [GitHub の README](https://github.com/stakiran/alauncher) を見ていただくとして、ここでは簡単に。

※環境変数 PATH の知識と Go 言語のインストールが必要です(go get 使ってます。まだ配布用 Zip などは用意してません)

```
$ alauncher
初回起動時は C:\Users\XXXXXXXX\.ala.ini が作成される。

$ alauncher -edit
.ala.ini が開かれるので編集する。

$ alauncher
.ala.ini がビルドされてエイリアスが配置される。
```

これでどこからでもエイリアスを実行できるようになります。

ちなみに `alauncher` だとちょっと長いので、`ala` のようなエイリアスをつくるのが楽です。

```
[ala]
rawbin=alauncher %*
```

## 特徴
- 管理しやすい(エイリアスを単一 INI ファイルで管理できる)
- きめ細やかな設定
  - pushd のように呼び出し元への波及が必要なときのための `disable=setlocal` パラメータ
  - 複数のエイリアスを一度に設定できる `alias=` パラメータ
  - エイリアス実行時のディレクトリを制御する `dir=` パラメータ
  - 煩雑なコマンドラインをそのままエイリアスにする `rawbin=` パラメータ
- 独自変数を定義できる

## Q&A

### なぜこのようなツールをつくった？
以下のような理由や事情が組み合わさったのだと思います。

- Linux の alias コマンドが羨ましい
- 一応エイリアスの仕組みは実現していたが、PATH 通したフォルダに手作業でバッチファイルを置いており、もうちょっと楽したい
- Go 言語の練習がてら何かつくりたい
- Windows でエイリアスツールって既存は無さそう（？）だし、つくったらかっこよさそうじゃない？
- go get で気軽にバイナリが配置されるエコシステムが素敵で、これを用いて何かつくってみたいと思った

### doskey コマンドは使わないの？
あまり柔軟に書けそうではなかったのでやめました。

### .bashrc みたいな仕組みはないの？
Windows には無いと思います(？)。

やるとしたら、レジストリの HKEY_CURRENT_USER\Software\Microsoft\Command Processor キーの AutoRun エントリにバッチファイルを指定して、その中で doskey を連ねるくらいでしょうか。

# alauncher の仕組み
alauncher がどうやってエイリアスを実現しているか、その仕組みについて書きます。

一言で言えば、PATH の通ったディレクトリに(エイリアスを実現する)バッチファイルを置いているだけです。

いくつか例を挙げます。

## 例1: pushd のエイリアス pd
```
[pd]
rawbin=pushd %* & cd
disable=setlocal
```

以下のような pd.bat になります。

```
@echo off



pushd %* & cd
```

## 例2: cd .. のエイリアス b

```
[b]
rawbin=echo %cd%%n%echo %s%VVV%s%%n%cd ..%n%echo %cd%
disable=setlocal
```

以下のような b.bat になります。

```
@echo off



echo %cd%
echo  VVV
cd ..
echo %cd%
```

(2019/08/01 追記) ちなみに `rawbin=echo %cd% & echo %s%VVV%s% & cd .. & echo %cd%` のようなワンライナーだと正しく動きません。

これは `cd ..` の後の `%cd%` が、`cd ..` した後
のカレントディレクトリになっていないためです。(推測ですが)バッチファイルの %cd% の反映が行単位になっているのではないかと思います。

なので v0.1.0 にて、意図的に複数行定義を行える変数 `%n%` を追加しました。

# Golang を使ってみて

## なぜ Golang を使い始めたか
- 普段は Python を使っているが以下問題があった → Golang なら解消できそう
  - 性能がちょっと遅い
  - バイナリ化が大変
- 個人的にマンネリ化してたので新しい言語を学んでみたかった

## 良いところ
比較的後発なだけあって良いとこどりという感じで、全体的に使いやすいと思いました。

- コンパイルしただけでつまらないエラー(型違い)がわかるのが快適
- 静的型付けでありながら推論が働くのでコーディングが楽
- go run を使えばインタプリタみたくその場で実行できる
  - 少なくとも 1KL 未満のソースならスクリプトみたいに軽く実行できる
- **ビルドしてバイナリ化するのが楽**
  - Python では cx_Freeze を使うなどかなり苦労してました……
- バイナリの処理が高速
- `go get (GitHub RepoのURL)` で気軽にインストールできる
- go fmt で整形を統一できる
- go test で unittest を実行できる(xxxx_test.go 内の TestXXXX 関数が実行される)
- 命名が言語としてルール化されていて迷うことがない
  - CamelCase が基本で、非公開は camelCase、公開は CamelCase など、
- ライブラリが豊富
- ドキュメントも(英語が読めるなら)豊富
- 複数行文字列や switch-case 構文など、かゆいところに地味に手が届く感じ

## 苦戦したところ・慣れなかったところ
- クラスの概念が無い(struct、レシーバなどで工夫する必要あり)
- `[]string{}` など、(動的型付けに比べると)記法が少し煩雑で、最初はよく戸惑う
- 文字列を slice するのに rune しなきゃいけないのがちょっと面倒(Python2 を思い出す)
- 命名として snake_case が使えないところ(snake_case大好きマンなので心理的抵抗感が強かった)
- ファイル Write 時の改行コードが LF のみ(Windows マンで CRLF マンなので辛い)

# おわりに
自分が必要とするツールを開発するのは楽しいですね。Golang は言語的に書きやすく、go コマンドや GitHub まわりとの連携などの仕組み周りも快適で、書いてて気持ちよかったです。今後もどんどん使っていきたい所存。

……とまあ淡々と書いてますが、Golang についてはまだまださっぱりぱーだと思うので、アドバイスなどありましたらぜひ！