nyagosで誤ったコマンドの訂正をしてみる
zshではあるらしいコマンドの訂正機能ですが、
nyagosにはコマンドが見つからなかった時に実行されるフックがあるので、
これで実装できるんじゃないかなぁと思ってやってみました。
訂正候補を作る
僕自身あんまり賢い子じゃないので、作られる候補リストもあんまり賢くありません。
だいたいコマンドをミスる時って、
右手と左手のレーシングとか、人差し指と中指のレーシングとか
だと思ったので、隣り合った1文字が入れ替わるケースを訂正するようにしました。
たとえば、naygos
とtypoした場合の訂正候補は以下になります。
- anygos
- nyagos
- nagyos
- nayogs
- naygso
で、この候補リストをwhich
で探して見つかったらユーザーに確認を求めることにしました。
(たとえ候補が1つしかなくても、いきなり実行しちゃったら怖いことが起こりそうだったので…)
完成したものがこちらになります
ソースコード
.nyagos
---------------------------------
-- コマンドが見つからなかった時実行されるフック
nyagos.on_command_not_found = function(args)
local cand = {}
for i, e in pairs(makeCandidates(args[0])) do
if (nyagos.which(e)) then
table.insert(cand, e)
end
end
if (#cand > 0) then
print('もしかして...')
for i, e in pairs(cand) do
print('\027[32;;1m' .. i .. '\027[;;0m : ' .. e)
end
local index = getIndex()
if #cand < index then
print(index .. ': Invalid index')
elseif 0 < index then
print(cand[index] .. ' ' .. table.concat(args, ' '))
nyagos.exec(cand[index] .. ' ' .. table.concat(args, ' '))
end
return true
end
return false
end
---------------------------------
-- 候補リストを作る
function makeCandidates(src)
local result = {}
local tbl = {}
for p, c in utf8.codes(src) do
table.insert(tbl, utf8.char(c))
end
for i = 1, string.len(src) - 1 do
local tmp = table.pack(table.unpack(tbl))
table.insert(tmp, i+2, tmp[i])
table.remove(tmp, i)
table.insert(result, table.concat(tmp))
end
return result
end
---------------------------------
-- 末尾から改行を取り除く
function chomp(src)
return string.gsub(src, "[\r\n]+$", "")
end
---------------------------------
-- キーボード入力から数字を取得
GETINDEX_NO_INPUT = -1
GETINDEX_ABORT = -2
function getIndex()
io.write('> ')
local index = GETINDEX_NO_INPUT -- 戻り値
local charcnt = 0
local stridx = io.read()
if stridx ~= nil and (stridx ~= '') then
index = tonumber(chomp(stridx):match('^%d+$')) or GETINDEX_NO_INPUT
end
return index
end
既知の問題
- ヒストリに残るのは間違ったコマンド。訂正後のコマンドではない
- zshのはもっともっと賢いらしい(キーボード上で隣あったアルファベットも候補かな?)
2.についてはmakeCandidates()
を改善すれば、いい感じになるかもね!