標準愚痴出力

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

vim 9.1 (stable) の scoop installer 用の暫定的な manifest を作った

vim の manifest は scoop-installer の Main bucket に登録されているが、ずっと vim 9.0 のままで、最新版の 9.1 にあがる様子が一向にない。マニフェスト: vim.json が参照しているページ: https://ftp.nluug.nl/pub/vim/pc/vim がずっと 9.0 のままだからだ。

vim 9.1 、入力モードでカーソルの形状がアンダーバー状に変わったり、なかなか良さそうだ。全部手作業でインストールしてもよいのだが、今後の更新やアンインストール時のことを考えると、きちんとパッケージ管理した形でインストールできた方が望ましい。

  • (案1)winget install vim.vim
    • C:\Program Files\vim\vim91 分、%PATH% 長くなって、いやん
    • 管理者権限が必要
  • (案2)nightly 版が GitHub Releases にあがっている
    • 比較的手軽に自動更新の manifest が作れる
    • stable ではない
    • 毎晩更新されるので、無駄に bucket のコミット数が増える

両方ともイマイチなので、make-scoop-manifest で自前で最新の stable版の manifest を作る方法を検討した。

今の make-scoop-manifest は GitHub の Releases しか見ないようになっているが、まずこれを普通のHTMLのページも見られるようにした1。これで、vim.org の Download ページ: https://www.vim.org/download.php のHTML からマニフェストを作ってみた。いつものように hymkor bucket 経由でインストール可能になっている。

scoop bucket add hymkor https://github.com/hymkor/scoop-bucket
scoop install vim-hogehoge

インストール時、あまり要らんことはさせたくなかったので、install.exe や uninstall.exe を呼び出さないなどの点で、Mainvim.json と違いがある。なぜ vim-hogehoge という名前かというと、Main版との違いが分かるような良い名前がなかったためだ。それならば、いっそのこと「雑に作ったもの」と分かるような名前でいいやと考えた。

なお、新make-scoop-manifest.exe は改造点が多過ぎるので、リリース・解説はもうちょっとだけ後にしたいと思う。

(追記:2024.03.18)

make-scoop-manifest の任意のHTMLをスキャンする新仕様だが、よく考えるとそのオプションの内容を検討するより、人間が目視でHTML を確認した方が早く、意味がなかったため、廃案とした。

繰り返し手動で更新するならば使いどころがあったかもしれないが、BucketTemplate を複製して使っている場合は GitHub Actions で自動更新できてしまうのだった。


  1. 他にもいろいろ機能追加が必要だったのだが、書き出すとキリがないので、今回は省略する。

1ファイルなスクリプトはインストール方法で、scoop よりcurl を案内した方がいいかも

hymkor/Download-Count.ps1: A PowerShell script that reports how many assets on GitHub's Releases page have been downloaded.

にあるとおり:

scoop bucket add hymkor https://github.com/hymkor/scoop-bucket
scoop install Download-Count.ps1

よりは

curl -O https://raw.githubusercontent.com/hymkor/Download-Count.ps1/master/Download-Count.ps1

というスクリプト単品をストレートにダウンロードしてもらう方が早くて良いかもしれない。

ただ、これだとダウンロードカウンターが回らないんだよなー

葛󠄀城市の「葛󠄀」の字

この動画で葛󠄀城市の「葛󠄀」の字がややこしいことになってしまったことを知った。

二つの字体があるんだなぁ

少なくとも現在のブラウザで表示分けが出来るのが幸いかな。

( しかし、フォントが小さいターミナルだとどっちか分かりづらい。最初「L人」が表示されてると思って拡大したら「ヒ」だったりすることもあったし )

rangefunc の練習:Yet Another Scanner

  • 既存のライブラリに bufio.Scanner があるが、改行をカットしてしまう
  • 改行を含めて読み取りたいときは (*bufio.Reader) ReadString('\n') を使う
    • EOF を検出した時の処理が面倒だが、雑に書くと最終行が失われてしまう

面倒なく、ありのままに読み込むコードを楽に書くための iterator を書いた

foo.go

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func readlines(r io.Reader) func(func(string, error) bool) {
    return func(yield func(string, error) bool) {
        var br *bufio.Reader
        if _br, ok := r.(*bufio.Reader); ok {
            br = _br
        } else {
            br = bufio.NewReader(r)
        }
        for {
            line, err := br.ReadString('\n')
            if err != nil && err != io.EOF {
                yield(line, err)
                return
            }
            if !yield(line, nil) {
                return
            }
            if err == io.EOF {
                return
            }
        }
    }
}
// 以上がライブラリコード
// 以下、使用例

func mains() error {
    for line, err := range readlines(os.Stdin) {
        if err != nil {
            return err
        }
        fmt.Print(line)
    }
    return nil
}

func main() {
    if err := mains(); err != nil {
        fmt.Fprintln(os.Stderr, err.Error())
        os.Exit(1)
    }
}

サンプルファイル foo.txt (制御コードが分かるよう、バイナリエディターのアウトプットで)

$ binview.exe  foo.txt
binview snapshot-windows-amd64 by go1.17.7
00000000 41 42 43 0D 0A 44 45 46 0D 0A 47 48 49          ABC←↓DEF←↓GHI
 [UTF8]  70='\x46'(1/1:U+0046) @ 7=0x7/13=0xD

実行結果:

[1] <DESKTOP-NPOTG52:~>
$ env GOEXPERIMENT=rangefunc go run foo.go < foo.txt
ABC
DEF
GHI[1] <DESKTOP-NPOTG52:~>
$

もう一つだけ、小さな optional パッケージを作った

以前:

というパッケージを作ったが、別の方式で、もう一つ作ってみた。

README にだいたい書いてあるけれども、go-minimal-optional では

type Value[T any] []T

と表現していた構造を

type Value[T any] struct {
    value T
    ok    bool
}

という安直な形で再実装してみた。メモリアローケーションが改善されるのではないかと期待してのことだが… 結果は

go-minimal-optional

BenchmarkIfSome-4       656701584                1.790 ns/op           0 B/op          0 allocs/op
BenchmarkIfNone-4       1000000000               0.7019 ns/op          0 B/op          0 allocs/op

go-tiny-optional

BenchmarkIfSome-4       675800485                1.787 ns/op           0 B/op          0 allocs/op
BenchmarkIfNone-4       1000000000               0.7008 ns/op          0 B/op          0 allocs/op

ほんの少しだけ速いけど、微粒子レベルの差にすぎず、あまり変わりませんねぇ。それよりも、allocation 回数がどっちでもゼロだったのに驚いた。Go の最適化がうまいこと効いていたみたい。

まぁ、これくらいなら、1.22 でなくとも「rangefunc もどき」が使える go-minimal-optional でいいかもしれませんねぇ。

URL をスクランブルする

とほほのJavaScriptリファレンス - とほほのWWW入門」を読みながら、URL文字列を前後ひっくりかえして、リンク元を検索しづらくする JavaScript を書いた (JavaScript を書くの、20年ぶりくらいかな?)

テキストボックスに適当な URL、たとえば:

を入力すると、ダイアログボックスで

というURL が提示される。この URL をクリックすると

次のURLへ移動します。問題なければクリックしてください。

https://twitter.com/elonmusk/status/1767108624038449405

というページを表示する。

なお、本ツールは怒られたら手動的に消滅する。

Go で適当な btree を検討していたけど、tidwall/btree がいいかもしれないなぁ

既存のメソッド Scan の仕様が range から呼ばれた関数の要求仕様にちょうどマッチしてた。

package main

import (
    "fmt"

    "github.com/tidwall/btree"
)

func main() {
    var users btree.Map[string, string]

    // add some users
    users.Set("user:4", "Andrea")
    users.Set("user:6", "Andy")
    users.Set("user:2", "Andy")
    users.Set("user:1", "Jane")
    users.Set("user:5", "Janet")
    users.Set("user:3", "Steve")

    // Iterate over the maps and print each user
    for key, value := range users.Scan {
        fmt.Printf("%s %s\n", key, value)
    }
}
$ env GOEXPERIMENT=rangefunc go run main.go
user:1 Jane
user:2 Andy
user:3 Steve
user:4 Andrea
user:5 Janet
user:6 Andy

tidwall さんは、transform というフィルターパッケージの開発者で、よいプロダクトをいろいろ作ってる人なので、もうこれでいいかなぁ感 ( これのSTAR数も前に確認した2022-04-30時点から、680→982 に増えてる )