id:zetamatta さんがfilter2を速攻で実装してくれた。id:zetamatta++
で、前回のコードに微妙にバグがあったのとNYAOS 3000更新に伴い書き直してみた。
まず、前回の奴は無駄に suffix の拡張子まで展開していたんだけど、この展開は alias や suffix 自体の展開前にやらないと意味がない。一方、PATHEXT の展開は alias の後にやらないとダメ。なので、両者を別々に書くことに。
修正
function nyaos.filter(cmdline) cmdline = cmdline:gsub('^%S+', function(cmd) if cmd:match('%.') then return false end local path='.;' .. os.getenv('PATH') local cmdl=cmd:lower() local variation={} for key,val in pairs(nyaos.suffix) do variation[ cmdl .. '.' .. key:lower() ] = true end for path1 in path:gmatch('[^;]+') do for fname in nyaos.dir(path1) do if variation[ fname:lower() ] then return fname end end end end) return cmdline end function nyaos.filter2(cmdline) cmdline = cmdline:gsub('^%S+', function(cmd) if cmd:match('%.') then return false end local path='.;' .. os.getenv('PATH') local cmdl=cmd:lower() local variation={} for ext in os.getenv('PATHEXT'):gmatch('[^;]+') do variation[ cmdl .. ext:lower() ] = true end for path1 in path:gmatch('[^;]+') do for fname in nyaos.dir(path1) do if variation[ fname:lower() ] then return fname end end end end) return cmdline end
filter を分けた以外の前回との違いは、
- gsub のパターンを '^%S+' に修正
- path:gmatch のパターンを '[^;]+' に修正
- ext を :lower() してなかったのを修正
- nyaos.suffix を pairs() で回すように
最初の3つは単純にバグで、手元の最新版では直ってたんだけど、ブログに貼る時に古いバージョンを貼ってしまったらしいorz
改善
で、似たようなコードが並んでるとまとめたくなるのがプログラマ。あまりにも酷いので改善を試みた。この辺りから完全に無駄な作業。
function keys(t) local keylist = {} for k in pairs(t) do table.insert(keylist, k) end local i = 0 return function() i = i + 1 return keylist[i] end end function addext(exts, mid) mid = mid or '' return function(cmd) if cmd:match('%.') then return false end local variation={} local cmdl=cmd:lower() for ext, _ in exts do variation[ cmdl .. mid .. ext:lower() ] = true end local path='.;' .. os.getenv('PATH') for path1 in path:gmatch('[^;]+') do for fname in nyaos.dir(path1) do if variation[ fname:lower() ] then return fname end end end end end function nyaos.filter2(cmdline) return cmdline:gsub('^%S+', addext(os.getenv('PATHEXT'):gmatch('[^;]+'))) end function nyaos.filter(cmdline) return cmdline:gsub('^%S+', addext(keys(nyaos.suffix), '.')) end
改善したはずだけどできあがったコードもそれなりに酷い。
まず、pairs() が多値を返しやがるので関数のパラメータとして一般化しづらい。素直にイテレータ関数作ってくれればいいのに…。
仕方なく keys() とかいう怪しい関数を作ってみた。最初は以下のようにしてみたんだけど上手くいかんかった。よくわかってない。
function keys(t) local next, t, i = pairs(t) local value = nil return function() i, value = next(t, i) return value end end
更に改善
改善と言うか改悪と言うか。私は実は filter に、
- %(...) を lua コードとして解釈して実行結果で置き換える
- $(...) をコマンドとして解釈して実行結果で置き換える
と言うのも使いもしないのに入れていたんだけど、これらをスマートに挿入したくなったので filter の値をテーブルで置き換えてみることにした。
function hooks(t) return setmetatable(t or {}, { __call = function(self, cmdline) for k, v in pairs(self) do cmdline = v(cmdline) end return cmdline end }) end
こんな感じのを用意して、
nyaos.filter = hooks() function nyaos.filter.ext(cmdline) return cmdline:gsub('^%S+', addext(keys(nyaos.suffix), '.')) end function nyaos.filter.luacode(cmdline) return cmdline:gsub('%%(%b())', function(m) local status, result = pcall( loadstring('return '..m) ) if status then return result end print('Ignore invalid Lua expression: '..m) end) end function nyaos.filter.command(cmdline) return cmdline:gsub('$(%b())', function(m) return nyaos.eval(m:sub(2,-2)) end) end
こんな風にすればフィルタを追加しやすい!(TODO: 順序の制御)
…が、しかし。filter は呼ばれなかったorz
うーん、filter の値が関数か調べてから呼んでるのだろうか。残念。素直に 1 つの関数に書きます。