標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

Go Modules 使用時に「他人のレポジトリに来てるマージされてないプルリク」の影響を予め検証する

自分のプロダクトが依存しているパッケージ T についてプルリクエストが来ているようですが、まだマージされていません。

その修正の影響がどの程度こちらに影響にあるかあらかじめ検証したいと思いますが、go.mod にその修正をどう書くのが正解か、よくわかりません。

とりあえず

  • go.mod から T の参照行を一旦消す
  • 自分のレポジトリの直下に、ローカルにプルリクエストの元 fork のコピーを置いて、./t みたいに参照できるようにする)
  • go.mod に「replace github.com/某M大先生/T => ./t」とローカルを見るように書く
  • go build

で、一応、ローカルにおいた t の方を参照してくれてはいるようです。

本当は、プルリクのfork を直接 go.mod で指定できればいいんですが…go.mod での「ブランチ指定」って、どうすりゃいいんでしょう?

ネットワークドライブを維持したまま、管理者モードに昇格したコマンドプロンプトを起動する

setlocal
call :"%1"
endlocal
exit /b

:"install"
    powershell "start-process -FilePath 'cmd.exe' -ArgumentList ('/s /c '+[char]34+((get-wmiobject win32_networkconnection | %%{ 'net use '+$_.LocalName+' '+[char]34+$_.RemoteName+[char]34 }) -join ' & ') + ' & ' + [char]34 + '%~dpnx0' + [char]34 + ' _install' + [char]34) -verb 'runas'"
    exit /b

:"_install"
    cd /D "%~dp0"
    pause
    exit /b

ユーザは make install を実行する。UAC ダイアログが表示されるので「はい」を選択すると、管理者モードで :"_install" ラベル以降が実行される。この時、通常モードのドライブレターは管理者モードでも継承されている。

Windows のコンソールと、Unicode のサロゲートペアとゼロ幅文字

(2019.03.20 追記:Windows7Chrome では Unicode の合字が表示されないので、合字を画像に変えました)

👨‍👩 という文字を nyagos に貼り付けると、文字化けするだけでなく、カーソル位置もおかしくなるという問題

これは2つ問題がある

  • 👨‍👩 という文字が合字である
    • 1コードポイントではなくて、「👨(U+1F468)」+ゼロ幅接合子(U+200D)+ 「👩(U+1F469)」という3コードポイントからなっている
    • nyagos は合字を想定していない
    • ゼロ幅接合子の単体の桁数は0桁である点は、go-runewidth で把握できている
  • 👨と👩各文字ともサロゲートペアで表現される
    • Windowsコマンドプロンプトサロゲートペアな Unicode の出力をサポートしていない
      • そもそもコンソールバッファのひとマスが16bitしか確保されていないんだよな
    • 実際に出力すると1文字なのに2文字と認識されたり、カーソル位置がおかしくなってしまう。
    • フォントが足りる・足りないの問題ではない

ということで「サロゲートペアな文字」も「ゼロ幅文字」もきちんと表示するのは無理とわかったので、nyagos の一行入力では <UUUUU> みたいな形で表現するようにした。^I とかと同じ扱いで、表示上は5桁になっているがバックスペース1回で削除できるし、コマンドに出力する時は元の文字に直して出力される (一応、この動作は --output-surrogate-pair というオプションで抑制する(=そのまま表示するようにする)ことが出来るようにはしておいた)

将来的にこういった文字もコマンドプロンプトで表示できるといいんですが。絵文字が使えないというのはさびしいので…(というか、将来、実用上も困るシーンが出てきそう)

本件、ご協力いただいた tsuyoshicho さん、ありがとうございました。

nyagos と文字の幅問題

文字の幅については nyagos において頭が痛い問題です。

mattn/go-runewidth でカーソルを戻す時に発行するバックスペースの個数を算出しています。ですが、Windows のコンソールでの実際の文字幅は Unicode の規格のものと微妙に違うので、文字によってはカーソル位置が狂ってしまうという問題が発生します。

以前は文字が出力する度にカーソル位置を計測して文字幅を記録するような対応をしていたのですが、速度的に不利であるので、現在は無効にしています。(仮想マシン内ではコンソールがすごく遅くなる時があるので、速度を下げる要因を少しでも減らしたかったんですね。これをやると出力のバッファリングもやりにくくなるので)

また、Linux 対応に伴って、せっかく入力は mattn/go-tty 、出力は mattn/go-colorable と I/O を外出しているわけですので、あまり直接コンソールを触るのははばかられるというのもありました。 (まぁ、場合分けすればいいだけの話なのですが)

ということで、理想的な解決案不在のまま、文字幅問題はずっと先送りしているという状況です。Windowsのコンソールでの文字幅の決定ルールが明確に分かれば、問題は綺麗に片付くのですがね…マイクロソフトの人、教えてくれないかなぁ…

ホームディレクトリ以下にある空白入りのファイル名の補完は難儀だなぁ

~\Share\Program Files というパスを補完する場合を考えよう。

bash だと ~/Share/Program\ Files と補完する。 UNIX だとワード単位で独立した引数としてコマンドに引き渡されるので「/home/USERNAME/Share/Program Files」をそのまま引き渡すことができる。

だが、Windows の場合、以下のような問題があるため、UNIX のようなことはできない

  • \ディレクトリ区切り記号と認識されるので、エスケープ記号として使うことはできない
  • Windows では全引数が1文字列として引き渡されるので、空白をそのままわたすと、パラメータ区切りと誤認されてしまう

結果、引数全体を二重引用符で囲むのが妥当となる。

が、ここで ~ が問題となってくる。~ を二重引用符の中に入れるとまずいのだ。~ が %USERPROFILE% への置換対象外になってしまうのだ。

というわけで、現在の nyagos では苦肉の策として ~"\Share\Program Files" へ変換している(nyaos 3000 では ~\"Share\Program Files" だったが、\" だと \ が二重引用符のエスケープと読めてしまうので、やめたのだ)

なんだか、かっこわるいなぁ。

一案として、Windowsエスケープ文字である ^ を使って ~/Share/Program^ Files とするのも考えたが… すべてのコマンドが^ を理解してくれるとも限らんのよね。くまったなぁ

Lua のかわりに anko を組み込んだ anko-nyagos を作ってみました。

nyagos は lua53.dll → GopherLua への切り替えの際、組み込み言語のインターフェイスをある分離して、切り替えられるようにしたのですが、それを利用して、mattn 先生が開発された、Go製スクリプト言語 anko を組み込んだ anko-nyagos を試験的に作成してみました。

今のところできるのは下記だけです。

  • 起動時に、anko-nyagos.exe と同じフォルダーの nyagos.ank を実行する
  • コマンドとしては以下を使えるようにする
    • alias("エイリアス名",実行関数)エイリアスを anko の関数で定義する
    • alias("エイリアス名","コマンド定義")エイリアスの置換テキストを定義する
    • サンプルにあったのと同じ println()

エイリアス用関数は、こんな感じ

func f(args){
    for s in args{
        println(s)
    }
}

alias("foo",f)

これを nyagos.ank に記すと、「foo 1 2 3」で「1」「2」「3」と表示されます。

さて、この anko-nyagos.exe 、エイリアスしか実装していないのに、ファイルサイズが 4,807,168 バイトと結構なサイズになってしまいました。オリジナル nyagos.exe は 4,818,944 バイトです。重複していたり、使っていないコードが多いからというのもありますが、まだ Lua・anko 両方とも組み込みとかは考えない方がよいかもしれません。

(追記)

anko からコールバック関数(エイリアス関数本体)を Go 言語側に引き渡す時、どういう型で来るか、anko のドキュメントやソースを見ても分からなかったのですが、安直に

func ankoAlias(name string, f interface{}) {
    switch code := f.(type) {
    case string:
        alias.Table[name] = alias.New(code)
    default:
        println(reflect.TypeOf(f).String())
    }
}

とやって、型を表示させてみたらわかりました。vm.Func でした。これを anko のソースで検索してみたところ、次のような型のようです。

type Func func(args ...reflect.Value) (reflect.Value, error)

というわけで、現在はこんな感じになっています。

func ankoAlias(name string, f interface{}) {
    switch code := f.(type) {
    case string:
        alias.Table[name] = alias.New(code)
    case vm.Func:
        alias.Table[name] = &ankoFunc{f: code}
    default:
        println(reflect.TypeOf(f).String())
    }
}

以上

最近(4.4)の nyagos の方向性

  • ビルドバッチ(make.cmd)でかすぎ。簡略化する
  • ソース、どこから読んだらいいか分からん。整理する
  • 残イシュー多すぎ。はよ片付けろ
  • CMD.EXE依存エイリアス撲滅(mklinkren)

  • セマンティックバージョニング対応は 4.5 以降から。具体的には 4.5.x_y を v5.x.y に格上げする

  • Lisp対応は迷ってる。サブパッケージを共用する、別パッケージにした方がよいかもしれない

  • GitHubのMSアカウントがひそかに作ってる Go製Lua5.3 は注目してるけど、まだExperimentalなんで様子見。だけど Lua が 5.1 なのは不満なので、あげられるならあげたい

  • 情報発信大切。本件ブログに転載する。github だと英語も併記することにしてるので、どうしてもフットワークが下がる