git履歴の先頭に、後から「空commit」を割り込ませる

本件を実行する前に git clone でバックアップを取っておきましょう

あらかじめ、全commitの履歴を cherry-pick するスクリプトを作成しておく

git log --pretty="format:%H" | gawk '/./{ line[i++]=$0 } END{ while(--i >= 0){ print "git cherry-pick ",line[i]} }' > pick.sh
  • /./ はEOF付近にできがちな空行を排除するためのもの
  • tac を使った方が短くなるが、git for Windows の MSYS には tac が入っていないようなので、gawk だけ済ます

これを実行すると、pick.sh が作成される

git cherry-pick ae733b6a64bba949af88276ade162b551d7ced1d
git cherry-pick b7e8e845b979bf60a94520692ce627f471d3a356
git cherry-pick 0bc25ff7d5a7fff24b898373aa5c2dbe8fa0a557
git cherry-pick edeb710e551c12ded01968d766856e3dd6fdc279
 :(略)

最初のcommitの直後に移動する。

git checkout ae733b6a64bba949af88276ade162b551d7ced1d

この状態で新ブランチtmpを作成する

git branch tmp
git checkout tmp

新ブランチ tmp には最初のcommitだけが残っているので、これを削除する。

git update-ref -d HEAD
git reset --hard

空ブランチを作成する。

git commit -m "null" --allow-empty

他の commit を全部復元する

sh pick.sh | more

masterブランチと、新ブランチtmp と入れ替える

git branch -m master old_master
git branch -m tmp master

Ok.

参考文献

【ポエム】NYAGOS 2017年ふりかえり

Nihongo Yet Another GOing Shell についての駄文です。関心ある方に読んでいただければと


Luaデータ共有との戦い

完全に改善した!(← うさんくさい)

  • 4.0
    • 全コマンド(=goroutine~スレッド)で 1-Lua インスタンスを共有
    • データ共有に問題はなかったが、クラッシュ多発
  • 4.1
    • コマンドごとに Lua インスタンスを分離 ⇒ 動作が安定
    • 反面、グローバルとコマンド間でのデータ交換が不便に
      • テーブルshare[]以外の変数・関数が、相互参照不能に
  • 4.2 [New!]
    • Luaインスタンス作成時に、親のグローバル変数・関数を、子にフルコピー
      • 通称「なんちゃってfork
    • ローカル変数や、クロージャーから参照される変数は複写できない
    • 子で設定したデータは、親や兄弟コマンドからは見えない
      • fork を持つ UNIX/bin/sh でも、同じ現象が発生する(fork と同じ)
      • share[] の出番は減ったが、まだ必要

foreach・ブロック-if

念願の foreach ・ブロック-if を手に入れたぞ

f:id:zetamatta:20180105001334p:plain

if /i "%PROCESSOR_ARCHITECTURE%" == "AMD64" then
    set "PATH+=%USERPROFILE%\Share\bin64"
end
  • 今のところ nyaos-3000互換系(endifもendのエイリアスとして使える)
    • CMD.EXE のように、丸括弧を使う構文に合わせたいが、丸括弧の構文解析は難しい(まだ俺には)
  • _nyagos(バッチ風) と .nyagos(Lua)、設定ファイルが複数あっても混乱するだけかも
    • また、迷いが出てきた > Lua 一本でゆくか、バッチ構文併用でゆくか

gawkPowerShell

はんぶん、ざつだん

  • gawk にうまくコマンドを引き渡せない」という問題はその後発生していない
    • そもそも俺が使ってないからかな!
    • gawk が使える CSV って、要素に改行とかカンマ含められないから…(震え声)
  • PowerShell をよく使うようになった
    • CSVだけでなく、Excelの読み書きも出来るしな!
    • -ExecutionPolicy RemoteSigned」が面倒。エイリアスできるが、スクリプトだけ手軽に他人に渡しにくい
    • Write-Output 、画面幅単位で勝手に改行コードを出すの、なんとかなりませんか!([System.Console]::WriteLine でも使えと申すか?)
  • ビルドスクリプトを「バッチ埋め込み型PowerShell」にした
    • 事実上、なんでもできる
    • make get-lua64 とか make get-lua32 ⇒ lua53.dll をダウンロードできるよ
    • go-versioninfo.exe がなければ、自動的にダウンロードッ

バージョン・ブランチ・配布管理

一人開発なので、手間暇をかけすぎても、報われない。バランス大切

4.2 より

  • 安定版(master)は「バイナリ」配布する
  • 開発版(develop)は、開発ブランチを別途設けるだけで、いちいちバイナリ配布しない
  • 双方共通の不具合が出たら、まず安定版で修正し、それをdevelopへmergeする

    • rebase すると、github緑化詐欺になりそうだったから
  • 一人開発の場合、手間暇と品質のバランス的に、この方式が一番かも

    • 過去、他のツールで開発版もバイナリを出していたが、結構たいへんだった
    • 挑戦的な改変をきちんとわけて、安定版もいつでも公開しやすくなった

新たな組み込みエンジンの模索

別のツール(expect for Command Prompt)開発で、GopherLua を試用

  • これまで使わなかった理由
    • パターンマッチ機能が正規表現になっている
    • 外部のLua用のライブラリが使えない
  • 現在:使わない理由があまりない
    • Lua本家互換のパターンマッチになっている(ように見える)
    • そもそも、外部のLuaライブラリ、ほとんど使ってない

少しずつ lua53.dll 依存コードの集約を進めているが、量がまだ多いため、GopherLua 切り替えはまだそうとう先に


ユーザの利用スタイルの多様性を全て追えない

  • 「画面幅が大きいと、画面が乱れる」

    • MS-API の画面サイズを保持する変数のサイズが signed short
      • うっかり掛け算をそのまますると 32767 を超えてしまい、オーバーフロー。
      • Ctrl-L で画面を奇麗に消しきれない状況に
    • ユーザには画面幅が多いという自覚がない。開発者は普段80桁でやってるから、ターミナルの問題に見えてしまう
    • NYAGOS 4.2.2_2 にて解消
  • 「start が動かない」

    • 「%PATH% をたどってくれない」という意味だが、分からなかった。
    • CMD.EXE の start は %PATH% を追いかけていたのかー(「start ‘which COMMANDNAME‘」とかやってたから気づかなかった)
    • NYAGOS 4.2.3_1 で解消

その他

  • go-bindata は非推奨のムードなので、使用をやめた

    • nyagos.d/ 以下を内蔵していたが、大して起動時間短縮に結び付いていなかった
  • UTF8 と ANSI (日本語環境ならSJIS)の混在は「 UTF8 として妥当ならUTF8、アウトなら ANSI」という安直な方法で案外OK

  • その他の自作 UNIX 風コマンド(diskfree、diskused)を組み込み

2018年への抱負

> らいねん、かんがえる! <

つまり、続くと?

まともな foreach が使えるようになります

次のバージョンから、環境変数の置換構文を組み合わせれば、下記のようなことができます。

$ foreach i *.go ; echo move %i% %i:go=goo% ; end
move bindata.go bindata.goo
move builtinfunc.go builtinfunc.goo
move complete_lua.go complete_lua.goo
move complete_var.go complete_var.goo
move loadscr.go loadscr.goo
move lua.go lua.goo
move lua_bindkey.go lua_bindkey.goo
move lua_cmd.go lua_cmd.goo
move nyagos.go nyagoos.goo
move option.go option.goo
move prompt.go prompt.goo
move stream.go stream.goo

諸般の事情で、環境変数の置換のタイミングが、 CMD.EXE や /bin/sh と違っていてアレですが、まぁ、便利なので、気にしないことにしましょう。

ソース的には、まだ master ブランチに入ってなくて、develop ブランチの方になります。

NYAGOS、かんたん設定

NYAGOS、かんたん設定 Windows向け拡張コマンドラインシェル:NYAGOS (Nihongo Yet Another GOing Shell) の個人設定はホームディレクトリに .nyagos というテキストファイル(Luaスクリプト)を作成して行います。

Windows の場合ホームディレクトリは一般に C:\Users\(ユーザ名) というフォルダーです。環境変数 HOME に別のフォルダーを定義しておけば、そちらへ変更することも可能です。

なお、メモ帳などで .nyagos という名前で保存しようとすると、勝手に .nyagos.txt という名前に変えられてしまいます。一旦、.nyagos.txt で保存してから、後からエクスプローラーで .nyagos. 等とわざと末尾に余分の . をつけた形にリネームしてください。末尾の .エクスプローラーに対して「拡張子が無い」ということを明示するためのものです。リネーム後に再表示させると、末尾の . が取れているのが分かると思います。

環境変数の設定

環境変数は設定ファイル .nyagos の中で、nyagos.env.変数名 という名前の変数に定義を代入することで設定できます。

たとえば PATH に C:\bin を加えたい時は

nyagos.env.path = nyagos.env.path .. ";C:\\bin"

と .nyagos に記入してください。Lua言語では「..」(ピリオド二つ)が文字列の連結の演算子です。\ は文字列の中なので \ とエスケープします。

なお、NYAGOS の紹介記事で set { ... } という記法を紹介しているものがありますが、これも間違いではありません。set は nyagos.exe と隣接したフォルダー nyagos.d の中の aliasandset.luaというアドオンファイルの中で定義されている便利関数です。

エイリアス(別名)の定義

エイリアス.nyagos の中でnyagos.alias.エイリアス名 という名前の変数に定義を代入することで設定できます。

たとえば「ls -l」を「ll」でも実行できるようにするには

nyagos.alias.ll = 'ls -l $*'

などと .nyagos の中に記載します。$*エイリアスに渡された引数を全て引用するという意味です。他に第一引数の $1,第二引数の $2 …などもあります。(これらのマクロがない場合は自動で勝手に末尾に $* があるとみなされます)

エイリアスは文字列で設定するだけでなく、Lua の関数にリンクさせることもできます。

nyagos.alias.printarg = function(args)
    for i=1,#args do
        print(args[i])
    end
end
% printarg x y a d
x
y
a
d

NYAGOS にはいろいろな機能がありますが、とりあえず環境変数の変更やエイリアスなどが使えれば、必要最小限のカスタマイズはできると思います。

vimとバッチファイルでtwitter と mstdn.jp にコマンドプロンプトから同時投稿する

dondon.cmd を実行すると vim が起動する。

  • 投稿したい時は「:eq
  • キャンセルする時は「:cq」か、ゼロバイトにしてから「:eq

dondon.cmd

@echo off
setlocal
set "DON=%TEMP%\don.txt"
type nul > "%DON%"
vim -c "e ++enc=utf8" "%DON%"
if errorlevel 1 exit /b
for %%I in (%DON%) do set "SIZE=%%~zI"
if %SIZE% LEQ 3 exit /b
twty -ff "%DON%"
mstdn toot -ff "%DON%"
endlocal

ここ近年、Go で作った UNIX っぽい Windows のツール

ANSI/UTF8自動判別と書いているは行単位で判断しているので、混在しててもだいたい大丈夫

神Excel にテキストファイルを流し込むスクリプト書いたよー

godexcel.cmd C3 AA30 tmp.xls ./GodExcel.cmd

という感じで実行すると、神 Excel「tmp.xls」の C3~AA30 の領域に、自分自身(GodExcel.cmd) の内容を展開して

f:id:zetamatta:20171123225106p:plain

という感じになる。

GodExcel.cmd

@set args=%*
@powershell "iex( (@('','','')+(cat '%~f0'|select -skip 3))-join[char]10)"
@exit /b %ERRORLEVEL%

$std_cell_width = 1.50

function Split-LikeShell($s){
    $rx = [regex]'"[^"]*"'
    while( $true ){
        $m = $rx.Match($s)
        if( -not $m.Success ){
            break
        }
        $left = $s.SubString(0,$m.Index)
        $right = $s.SubString($m.Index+$m.Length)
        $mid = (($m.Value -replace " ",[char]1) -replace '"','')
        $s = $left + $mid + $right
    }
    ($s -split " ") | ForEach-Object{ $_ -replace [char]1," " }
}

$args = (Split-LikeShell $env:args)

function Conv-RC($str){
    $i = 0
    $str = $str.ToUpper()
    $col = 0
    while( $i -lt $str.Length ){
        $index = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".IndexOf($str.substring($i,1))
        if( $index -lt 0 ){
            break
        }
        $col = $col * 26 + ($index+1)
        $i++
    }
    $row = 0
    while( $i -lt $str.Length ){
        $index = "0123456789".IndexOf($str.substring($i,1))
        if( $index -lt 0 ){
            break
        }
        $row = $row * 10 + $index
        $i++
    }
    return @($row,$col)
}

$left = 1
$top = 3
$right = 200
$bottom = 200

if( $args.Length -lt 2 ){
    Write-Output `
        "Usage: godexcel.ps1 [LeftTop] [RightBottom] ExcelFile TextFile..."
    exit
}

if( $args.Length -ge 1 -and $args[0] -match "^[A-Za-z]+[0-9]+$" ){
    $rc = Conv-RC($args[0])
    $top = $rc[0]
    $left = $rc[1]
    $args = $args[1..($args.Length-1)]
    if( $args.Length -ge 1 -and $args[0] -match "^[A-Za-z]+[0-9]+$" ){
        $rc = Conv-RC($args[0])
        $bottom = $rc[0]
        $right = $rc[1]
        $args = $args[1..($args.Length-1)]
    }
}

$excel = New-Object -ComObject Excel.Application
$cellwidth = @{}

try{
    $excel.Visible = $true
    
    $filename = [System.IO.Path]::GetFullPath($args[0])
    [System.Console]::WriteLine("Excel=$filename")
    if( Test-Path $args[0] ){
        $book = $excel.WorkBooks.Open($filename)
        $new = $false
    }else{
        $book = $excel.WorkBooks.Add()
        $new = $true
    }
    $sheet = $book.ActiveSheet

    $row = $top
    for($i = 1 ; $i -lt $args.Length ; $i++){
        Get-Content $args[1] |
        ForEach-Object {
            if( $row -le $bottom ){
                $count = $_.Length
                $col = $left
                for($j=0 ; $j -lt $count ; $j++){
                    if( $col -gt $right ){
                        $col = $left
                        $row++
                    }
                    if( $new -and -not $cellwidth.ContainsKey($col) ){
                        $sheet.Columns($col).ColumnWidth = $std_cell_width
                        $cellwidth[$col] = $true
                    }
                    $sheet.Cells.Item($row,$col) = $_.substring($j,1)
                    $col++
                }
                while( $col -le $right ){
                    $sheet.Cells.Item($row,$col) = ""
                    $col++
                }
                $row++
            }
        }
    }
    if( $new ){
        $book.SaveAs($filename)
    }
}finally{
    $excel.Quit()
}

# vim:set ft=ps1: