LoginSignup
6
6

More than 5 years have passed since last update.

もしかして nyagos ?

Posted at

nyagosで誤ったコマンドの訂正をしてみる

zshではあるらしいコマンドの訂正機能ですが、
nyagosにはコマンドが見つからなかった時に実行されるフックがあるので、
これで実装できるんじゃないかなぁと思ってやってみました。

訂正候補を作る

僕自身あんまり賢い子じゃないので、作られる候補リストもあんまり賢くありません。
だいたいコマンドをミスる時って、
右手と左手のレーシングとか、人差し指と中指のレーシングとか
だと思ったので、隣り合った1文字が入れ替わるケースを訂正するようにしました。
たとえば、naygosとtypoした場合の訂正候補は以下になります。

  • anygos
  • nyagos
  • nagyos
  • nayogs
  • naygso

で、この候補リストをwhichで探して見つかったらユーザーに確認を求めることにしました。
(たとえ候補が1つしかなくても、いきなり実行しちゃったら怖いことが起こりそうだったので…)

完成したものがこちらになります

snapshot-15-06-26-232751.png

 ソースコード

.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

既知の問題

  1. ヒストリに残るのは間違ったコマンド。訂正後のコマンドではない
  2. zshのはもっともっと賢いらしい(キーボード上で隣あったアルファベットも候補かな?)

2.についてはmakeCandidates()を改善すれば、いい感じになるかもね!

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6