7
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

nyagosでヒストリ補完する

Last updated at Posted at 2014-10-16

※一部修正

ヒストリのリストの範囲外を参照してしまっている所がありましたので修正しました

-    for i = 0, hist_len do
+    for i = 1, hist_len do

nyagosには実装されていません

nyaos3000ではvzlike-previous-historyvzlike-next-historyのヒストリ補完がありましたが、
nyagosは「本体はコンパクトに、機能拡張はLuaで!」という設計思想のもと、これらのファンクションは実装されていません。
しかし、nyagosにはLuaで書いた機能をキーバインドに設定ためのインターフェイスnyagos.bindkey("キー名",function(this) ... end)があります。この機能を使うことでLuaスクリプトで実装しましょう。

nyaos3000のそれとの違い

nyaos3000のvzlike-previous-history, vzlike-next-historyは単語単位の補間という感じでしたが、
今回の実装はtcshの補完に近く、行単位の補完となっています。

また、補完元の検索ワードを判別するため、カーソル位置を元あった場所に戻しているので慣れるまで違和感があるかもしれません。
なお、補完元の検索ワードに日本語などのマルチバイト文字が入っているとズレていきますが、
そこは仕様ということでお願いします(補完先の文字列にマルチバイト文字が混じっている場合は大丈夫です)。

実装例

.nyagos
nyagos.bindkey("C_N",
    function(this)
        search_history(this, false)
    end
)

nyagos.bindkey("C_P",
    function(this)
        search_history(this, true)
    end
)

function search_history(this, is_prev)
    -- カーソル位置が一番左の場合は通常のnext/prev
    if this.pos == 1 then
        if is_prev == true then
            this:call("PREVIOUS_HISTORY")
        else
            this:call("NEXT_HISTORY")
        end
        this:call("BEGINNING_OF_LINE")
        return nil
    end

    -- 検索キーワード
    local search_string = this.text:sub(1, this.pos - 1)

    -- 重複を除いたhistoryリストの取得
    local history_uniq = {}
    local is_duplicated = false
    local hist_len = nyagos.gethistory()
    for i = 1, hist_len do
        local history
        -- 新しい履歴がリスト後ろに残るよう末尾からサーチ
        history = nyagos.gethistory(hist_len - i)
        for i, e in ipairs(history_uniq) do
            if history == e or history == search_string then
                is_duplicated = true
            end
        end
        if is_duplicated == false then
            if is_prev == true then
                table.insert(history_uniq, history)
            else
                table.insert(history_uniq, 1, history)
            end
        end
        is_duplicated = false
    end

    -- 入力と完全一致する履歴を探す
    -- 完全一致する履歴を起点にすることで
    -- (見かけ上)インクリメンタルな検索にする
    local hist_pos = 0
    for i, e in ipairs(history_uniq) do
        if e == this.text then
            hist_pos = i
            break
        end
    end

    -- 前方一致する履歴を探す
    local matched_string = nil
    for i = hist_pos + 1, #history_uniq do
        if history_uniq[i]:match('^' .. search_string .. '.*') then
            matched_string = history_uniq[i]
            break
        end
    end

    -- 見つかった履歴を出力
    -- 見つからなければ、検索キーワードを出力
    this:call("KILL_WHOLE_LINE")
    if (matched_string ~= nil) then
        this:insert(matched_string)
    else
        this:insert(search_string)
    end
    this:call("BEGINNING_OF_LINE")
    for i = 1, this.pos - 1 do
        this:call("FORWARD_CHAR")
    end
end
7
9
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
7
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?