ย้อนกลับการค้นหาประวัติด้วยนิพจน์ทั่วไป


10

ฉันกำลังมองหาเครื่องมือที่จะช่วยให้การค้นหาแบบย้อนกลับเพิ่มขึ้นด้วยการสนับสนุนการแสดงออกปกติอย่างง่าย ๆ (หรือเพียงแค่การแข่งขันหลายรายการ) ตัวอย่างเช่นหากฉันต้องการค้นหาคำสั่ง 'foo bar baz' ฉันสามารถทำสิ่งต่อไปนี้เพื่อค้นหาคำสั่งได้อย่างรวดเร็ว:

CRTL-R (เริ่มค้นหา) พิมพ์ 'foo' (จับคู่คำสั่งล่าสุดโดยใช้ foo) พิมพ์ 'foo | baz' ต่อไป (ตรงกับคำสั่งล่าสุดที่มีคำว่า 'foo' และ 'baz'

สิ่งนี้มีอยู่จริงหรือไม่? ถ้าไม่ฉันจะนำไปใช้กับตัวเองได้อย่างไร

คำตอบ:


4

วิดเจ็ตที่กำหนดเองhistory-incremental-multi-searchสำหรับzsh

ติดตั้ง

สร้างไดเรกทอรีและรวมไว้ในของคุณ$fpathตัวอย่างเช่นสำหรับฉันสร้างไดเรกทอรี~/.zsh/functionsและเส้นในของฉันfpath=($HOME/.zsh/functions $fpath).zshrc

ใส่ต่อไปนี้ในไฟล์ที่มีชื่อhistory-incremental-multi-searchในไดเรกทอรีนั้น

emulate -L zsh
setopt extended_glob

local oldbuffer=$BUFFER
local -i oldcursor=$CURSOR

local dir                # search direction
local chars              # input buffer
local -a words           # search terms
local -a found           # all history items that match first term
local -i hindex=$HISTNO  # current 
local -i lmatch          # last matched history item (for prev/next)

if [[ $WIDGET == *forward* ]]; then
    dir=fwd
else
    dir=bck
fi

function find-next {
    # split the input buffer on spaces to get search terms
    words=(${(s: :)chars})

    # if we have at least one search term
    if (( $#words )); then
        # get all keys of history items that match the first
        found=(${(k)history[(R)*$words[1]*]})
        if (( $#found )); then
            # search in widget direction by default
            # but accept exception in $1 for "prev match"
            search-${1:-$dir}
        else
            # no matches
            lmatch=$HISTNO
        fi
    else
        # no search terms
        lmatch=$HISTNO
        BUFFER=$oldbuffer
        CURSOR=$oldcursor
    fi
}

function search-fwd {
    # search forward through matches
    local -i i
    for (( i = $#found; i > 0; i-- )); do
        # but not before hindex as we're searching forward
        if [[ $found[$i] -gt $hindex ]]; then
            set-match $found[$i]
        fi
    done
}

function search-bck {
    # search backward through matches
    local -i i
    for (( i = 1; i <= $#found; i++ )); do
        # but not beyond hindex as we're searching backward
        if [[ $found[$i] -lt $hindex ]]; then
            set-match $found[$i]
        fi
    done
}

function set-match {
    # match history item against all terms and select it if successful
    local match=1
    local -i i
    for (( i = 2; i <= $#words; i++ )); do
        if [[ $history[$1] != *$words[$i]* ]]; then
            match=0
            break
        fi
    done
    if [[ $match -ne 0 ]]; then
        lmatch=$1
        BUFFER=$history[$1]
        CURSOR=$#BUFFER
        break
    fi
}

# display sub prompt
zle -R "${dir}-i-search-multi:"

# handle input keys
while read -k; do
    case $REPLY in
        # next
        $'\C-n' )
            hindex=$lmatch
            find-next
            ;;
        # prev
        $'\C-p' )
            hindex=$lmatch
            if [[ $dir == fwd ]]; then
                find-next bck
            else
                find-next fwd
            fi
            ;;
        # break
        $'\e' | $'\C-g' )
            BUFFER=$oldbuffer
            CURSOR=$oldcursor
            break
            ;;
        # accept
        $'\C-m' | $'\C-j' )
            if [[ $lmatch -eq $HISTNO ]]; then
                BUFFER=$oldbuffer
                CURSOR=$oldcursor
            else
                HISTNO=$lmatch
            fi
            break
            ;;
        # erase char
        $'\C-h' | $'\C-?' )
            chars=$chars[1,-2]
            hindex=$HISTNO
            find-next
            ;;
        # erase word
        $'\C-w' )
            if [[ $chars =~ \  ]]; then
                chars=${chars% *}
            else
                chars=
            fi
            hindex=$HISTNO
            find-next
            ;;
        # kill line
        $'\C-u' )
            chars=
            hindex=$HISTNO
            find-next
            ;;
        # add unhandled chars to buffer
        * )
            chars=${chars}${REPLY}
            hindex=$HISTNO
            find-next
            ;;
    esac

    zle -R "${dir}-i-search-multi: $words"
done

ใส่สิ่งนี้ในหรือแหล่งที่มาจาก.zshrc:

autoload -U history-incremental-multi-search

# make new widgets from function
zle -N history-incremental-multi-search-backward history-incremental-multi-search
zle -N history-incremental-multi-search-forward history-incremental-multi-search

# bind the widgets to keys
bindkey '^Xr' history-incremental-multi-search-backward
bindkey '^Xs' history-incremental-multi-search-forward

ใช้

ตอนนี้คุณควรจะสามารถเริ่มต้นการค้นหาที่เพิ่มย้อนหลังกับCtrl+X, rไปข้างหน้าด้วย,Ctrl+Xs

พิมพ์คำค้นหาของคุณคั่นด้วยช่องว่าง คีย์ต่อไปนี้พร้อมใช้งานเพื่อควบคุม:

  • ← Backspace: ลบอักขระ

  • Ctrl+W: ลบคำ

  • Ctrl+U: kill line

  • Ctrl+N: นัดต่อไป

  • Ctrl+P: การแข่งขันก่อนหน้า

  • Ctrl+G/ Esc: ยกเลิกการค้นหา

  • Enter: ยอมรับ

วิธีการแก้ปัญหานี้อาจจะง่ายขึ้นเล็กน้อย มันเป็นข้อพิสูจน์แนวคิดการใช้งานได้มากขึ้นพร้อมพื้นที่มากมายสำหรับการปรับปรุง


ขอบคุณที่สละเวลาเขียนคำตอบเหล่านี้มันช่วยฉันได้มาก ฉันหวังว่าผู้คนจะสะดุดกับสิ่งนี้มากขึ้นและพบว่ามีประโยชน์
drewrobb

6

คุณสามารถ grep ผ่านประวัติของคุณ:

history | egrep '(foo|baz)'

ฉันหวังว่าจะช่วย


0

สร้างคำตอบของ @ peth:

ตอนนี้ Zsh มาพร้อมกับhistory-incremental-pattern-search-backwardคุณไม่จำเป็นต้องกำหนดมันเอง เพียงเพิ่มการผูกคีย์ ฉันต้องการแทนที่^Rโดยเพิ่มบรรทัดต่อไปนี้ใน.zshrc:

bindkey '^R' history-incremental-pattern-search-backward

ตอนนี้คุณสามารถใช้โอเปอเรเตอร์glob (sic! not rexex) ในการค้นหาของคุณได้แล้ว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.