mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-15 06:43:47 -05:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1bc223d4b3 | ||
|
|
bef405bfa5 | ||
|
|
0612074abe | ||
|
|
3bf51d8362 | ||
|
|
2c8479a7c5 | ||
|
|
8c8b5b313e | ||
|
|
66d55fd893 |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,6 +1,17 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
0.15.2
|
||||||
|
------
|
||||||
|
- Preview window is now scrollable
|
||||||
|
- With mouse scroll or with bindable actions
|
||||||
|
- `preview-up`
|
||||||
|
- `preview-down`
|
||||||
|
- `preview-page-up`
|
||||||
|
- `preview-page-down`
|
||||||
|
- Updated ANSI processor to support high intensity colors and ignore
|
||||||
|
some VT100-related escape sequences
|
||||||
|
|
||||||
0.15.1
|
0.15.1
|
||||||
------
|
------
|
||||||
- Fixed panic when the pattern occurs after 2^15-th column
|
- Fixed panic when the pattern occurs after 2^15-th column
|
||||||
|
|||||||
4
install
4
install
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
[[ "$@" =~ --pre ]] && version=0.15.1 pre=1 ||
|
[[ "$@" =~ --pre ]] && version=0.15.2 pre=1 ||
|
||||||
version=0.15.1 pre=0
|
version=0.15.2 pre=0
|
||||||
|
|
||||||
auto_completion=
|
auto_completion=
|
||||||
key_bindings=
|
key_bindings=
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf-tmux 1 "Sep 2016" "fzf 0.15.1" "fzf-tmux - open fzf in tmux split pane"
|
.TH fzf-tmux 1 "Sep 2016" "fzf 0.15.2" "fzf-tmux - open fzf in tmux split pane"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf-tmux - open fzf in tmux split pane
|
fzf-tmux - open fzf in tmux split pane
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf 1 "Sep 2016" "fzf 0.15.1" "fzf - a command-line fuzzy finder"
|
.TH fzf 1 "Sep 2016" "fzf 0.15.2" "fzf - a command-line fuzzy finder"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf - a command-line fuzzy finder
|
fzf - a command-line fuzzy finder
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ fi
|
|||||||
|
|
||||||
_fzf_orig_completion_filter() {
|
_fzf_orig_completion_filter() {
|
||||||
sed 's/^\(.*-F\) *\([^ ]*\).* \([^ ]*\)$/export _fzf_orig_completion_\3="\1 %s \3 #\2";/' |
|
sed 's/^\(.*-F\) *\([^ ]*\).* \([^ ]*\)$/export _fzf_orig_completion_\3="\1 %s \3 #\2";/' |
|
||||||
awk -F= '{gsub(/[^a-z0-9_= ;]/, "_", $1); print $1"="$2}'
|
awk -F= '{gsub(/[^A-Za-z0-9_= ;]/, "_", $1); print $1"="$2}'
|
||||||
}
|
}
|
||||||
|
|
||||||
_fzf_opts_completion() {
|
_fzf_opts_completion() {
|
||||||
@@ -117,7 +117,7 @@ _fzf_handle_dynamic_completion() {
|
|||||||
__fzf_generic_path_completion() {
|
__fzf_generic_path_completion() {
|
||||||
local cur base dir leftover matches trigger cmd fzf
|
local cur base dir leftover matches trigger cmd fzf
|
||||||
[ "${FZF_TMUX:-1}" != 0 ] && fzf="fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%}" || fzf="fzf"
|
[ "${FZF_TMUX:-1}" != 0 ] && fzf="fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%}" || fzf="fzf"
|
||||||
cmd=$(echo "${COMP_WORDS[0]}" | sed 's/[^a-z0-9_=]/_/g')
|
cmd="${COMP_WORDS[0]//[^A-Za-z0-9_=]/_}"
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
@@ -162,7 +162,7 @@ _fzf_complete() {
|
|||||||
type -t "$post" > /dev/null 2>&1 || post=cat
|
type -t "$post" > /dev/null 2>&1 || post=cat
|
||||||
[ "${FZF_TMUX:-1}" != 0 ] && fzf="fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%}" || fzf="fzf"
|
[ "${FZF_TMUX:-1}" != 0 ] && fzf="fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%}" || fzf="fzf"
|
||||||
|
|
||||||
cmd=$(echo "${COMP_WORDS[0]}" | sed 's/[^a-z0-9_=]/_/g')
|
cmd="${COMP_WORDS[0]//[^A-Za-z0-9_=]/_}"
|
||||||
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
if [[ "$cur" == *"$trigger" ]]; then
|
if [[ "$cur" == *"$trigger" ]]; then
|
||||||
@@ -277,7 +277,7 @@ _fzf_defc() {
|
|||||||
cmd="$1"
|
cmd="$1"
|
||||||
func="$2"
|
func="$2"
|
||||||
opts="$3"
|
opts="$3"
|
||||||
orig_var="_fzf_orig_completion_$cmd"
|
orig_var="_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}"
|
||||||
orig="${!orig_var}"
|
orig="${!orig_var}"
|
||||||
if [ -n "$orig" ]; then
|
if [ -n "$orig" ]; then
|
||||||
printf -v def "$orig" "$func"
|
printf -v def "$orig" "$func"
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func (s *ansiState) equals(t *ansiState) bool {
|
|||||||
var ansiRegex *regexp.Regexp
|
var ansiRegex *regexp.Regexp
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
ansiRegex = regexp.MustCompile("\x1b\\[[0-9;]*[mK]")
|
ansiRegex = regexp.MustCompile("\x1b.[0-9;]*.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractColor(str string, state *ansiState, proc func(string, *ansiState) bool) (string, *[]ansiOffset, *ansiState) {
|
func extractColor(str string, state *ansiState, proc func(string, *ansiState) bool) (string, *[]ansiOffset, *ansiState) {
|
||||||
@@ -98,7 +98,7 @@ func interpretCode(ansiCode string, prevState *ansiState) *ansiState {
|
|||||||
} else {
|
} else {
|
||||||
state = &ansiState{prevState.fg, prevState.bg, prevState.bold}
|
state = &ansiState{prevState.fg, prevState.bg, prevState.bold}
|
||||||
}
|
}
|
||||||
if ansiCode[len(ansiCode)-1] == 'K' {
|
if ansiCode[1] != '[' || ansiCode[len(ansiCode)-1] != 'm' {
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +140,10 @@ func interpretCode(ansiCode string, prevState *ansiState) *ansiState {
|
|||||||
state.fg = num - 30
|
state.fg = num - 30
|
||||||
} else if num >= 40 && num <= 47 {
|
} else if num >= 40 && num <= 47 {
|
||||||
state.bg = num - 40
|
state.bg = num - 40
|
||||||
|
} else if num >= 90 && num <= 97 {
|
||||||
|
state.fg = num - 90 + 8
|
||||||
|
} else if num >= 100 && num <= 107 {
|
||||||
|
state.bg = num - 100 + 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Current version
|
// Current version
|
||||||
version = "0.15.1"
|
version = "0.15.2"
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
coordinatorDelayMax time.Duration = 100 * time.Millisecond
|
coordinatorDelayMax time.Duration = 100 * time.Millisecond
|
||||||
|
|||||||
@@ -663,6 +663,14 @@ func parseKeymap(keymap map[int]actionType, execmap map[int]string, str string)
|
|||||||
keymap[key] = actTogglePreview
|
keymap[key] = actTogglePreview
|
||||||
case "toggle-sort":
|
case "toggle-sort":
|
||||||
keymap[key] = actToggleSort
|
keymap[key] = actToggleSort
|
||||||
|
case "preview-up":
|
||||||
|
keymap[key] = actPreviewUp
|
||||||
|
case "preview-down":
|
||||||
|
keymap[key] = actPreviewDown
|
||||||
|
case "preview-page-up":
|
||||||
|
keymap[key] = actPreviewPageUp
|
||||||
|
case "preview-page-down":
|
||||||
|
keymap[key] = actPreviewPageDown
|
||||||
default:
|
default:
|
||||||
if isExecuteAction(actLower) {
|
if isExecuteAction(actLower) {
|
||||||
var offset int
|
var offset int
|
||||||
|
|||||||
@@ -28,6 +28,13 @@ const (
|
|||||||
jumpAcceptEnabled
|
jumpAcceptEnabled
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type previewer struct {
|
||||||
|
text string
|
||||||
|
lines int
|
||||||
|
offset int
|
||||||
|
enabled bool
|
||||||
|
}
|
||||||
|
|
||||||
// Terminal represents terminal input/output
|
// Terminal represents terminal input/output
|
||||||
type Terminal struct {
|
type Terminal struct {
|
||||||
initDelay time.Duration
|
initDelay time.Duration
|
||||||
@@ -68,8 +75,7 @@ type Terminal struct {
|
|||||||
selected map[int32]selectedItem
|
selected map[int32]selectedItem
|
||||||
reqBox *util.EventBox
|
reqBox *util.EventBox
|
||||||
preview previewOpts
|
preview previewOpts
|
||||||
previewing bool
|
previewer previewer
|
||||||
previewTxt string
|
|
||||||
previewBox *util.EventBox
|
previewBox *util.EventBox
|
||||||
eventBox *util.EventBox
|
eventBox *util.EventBox
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
@@ -119,6 +125,7 @@ const (
|
|||||||
reqPrintQuery
|
reqPrintQuery
|
||||||
reqPreviewEnqueue
|
reqPreviewEnqueue
|
||||||
reqPreviewDisplay
|
reqPreviewDisplay
|
||||||
|
reqPreviewRefresh
|
||||||
reqQuit
|
reqQuit
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -165,6 +172,10 @@ const (
|
|||||||
actPrintQuery
|
actPrintQuery
|
||||||
actToggleSort
|
actToggleSort
|
||||||
actTogglePreview
|
actTogglePreview
|
||||||
|
actPreviewUp
|
||||||
|
actPreviewDown
|
||||||
|
actPreviewPageUp
|
||||||
|
actPreviewPageDown
|
||||||
actPreviousHistory
|
actPreviousHistory
|
||||||
actNextHistory
|
actNextHistory
|
||||||
actExecute
|
actExecute
|
||||||
@@ -275,8 +286,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
|||||||
selected: make(map[int32]selectedItem),
|
selected: make(map[int32]selectedItem),
|
||||||
reqBox: util.NewEventBox(),
|
reqBox: util.NewEventBox(),
|
||||||
preview: opts.Preview,
|
preview: opts.Preview,
|
||||||
previewing: previewBox != nil && !opts.Preview.hidden,
|
previewer: previewer{"", 0, 0, previewBox != nil && !opts.Preview.hidden},
|
||||||
previewTxt: "",
|
|
||||||
previewBox: previewBox,
|
previewBox: previewBox,
|
||||||
eventBox: eventBox,
|
eventBox: eventBox,
|
||||||
mutex: sync.Mutex{},
|
mutex: sync.Mutex{},
|
||||||
@@ -772,9 +782,35 @@ func (t *Terminal) printHighlighted(result *Result, bold bool, col1 int, col2 in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func numLinesMax(str string, max int) int {
|
||||||
|
lines := 0
|
||||||
|
for lines < max {
|
||||||
|
idx := strings.Index(str, "\n")
|
||||||
|
if idx < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
str = str[idx+1:]
|
||||||
|
lines++
|
||||||
|
}
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Terminal) printPreview() {
|
func (t *Terminal) printPreview() {
|
||||||
t.pwindow.Erase()
|
t.pwindow.Erase()
|
||||||
extractColor(t.previewTxt, nil, func(str string, ansi *ansiState) bool {
|
skip := t.previewer.offset
|
||||||
|
extractColor(t.previewer.text, nil, func(str string, ansi *ansiState) bool {
|
||||||
|
if skip > 0 {
|
||||||
|
newlines := numLinesMax(str, skip)
|
||||||
|
if skip <= newlines {
|
||||||
|
for i := 0; i < skip; i++ {
|
||||||
|
str = str[strings.Index(str, "\n")+1:]
|
||||||
|
}
|
||||||
|
skip = 0
|
||||||
|
} else {
|
||||||
|
skip -= newlines
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
if ansi != nil && ansi.colored() {
|
if ansi != nil && ansi.colored() {
|
||||||
return t.pwindow.CFill(str, ansi.fg, ansi.bg, ansi.bold)
|
return t.pwindow.CFill(str, ansi.fg, ansi.bg, ansi.bold)
|
||||||
}
|
}
|
||||||
@@ -891,7 +927,7 @@ func (t *Terminal) hasPreviewWindow() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) isPreviewEnabled() bool {
|
func (t *Terminal) isPreviewEnabled() bool {
|
||||||
return t.previewBox != nil && t.previewing
|
return t.previewBox != nil && t.previewer.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) current() string {
|
func (t *Terminal) current() string {
|
||||||
@@ -1033,7 +1069,11 @@ func (t *Terminal) Loop() {
|
|||||||
}
|
}
|
||||||
exit(exitNoMatch)
|
exit(exitNoMatch)
|
||||||
case reqPreviewDisplay:
|
case reqPreviewDisplay:
|
||||||
t.previewTxt = value.(string)
|
t.previewer.text = value.(string)
|
||||||
|
t.previewer.lines = strings.Count(t.previewer.text, "\n")
|
||||||
|
t.previewer.offset = 0
|
||||||
|
t.printPreview()
|
||||||
|
case reqPreviewRefresh:
|
||||||
t.printPreview()
|
t.printPreview()
|
||||||
case reqPrintQuery:
|
case reqPrintQuery:
|
||||||
C.Close()
|
C.Close()
|
||||||
@@ -1085,6 +1125,11 @@ func (t *Terminal) Loop() {
|
|||||||
req(reqInfo)
|
req(reqInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
scrollPreview := func(amount int) {
|
||||||
|
t.previewer.offset = util.Constrain(
|
||||||
|
t.previewer.offset+amount, 0, t.previewer.lines-t.pwindow.Height)
|
||||||
|
req(reqPreviewRefresh)
|
||||||
|
}
|
||||||
for key, ret := range t.expect {
|
for key, ret := range t.expect {
|
||||||
if keyMatch(key, event) {
|
if keyMatch(key, event) {
|
||||||
t.pressed = ret
|
t.pressed = ret
|
||||||
@@ -1118,10 +1163,10 @@ func (t *Terminal) Loop() {
|
|||||||
return false
|
return false
|
||||||
case actTogglePreview:
|
case actTogglePreview:
|
||||||
if t.hasPreviewWindow() {
|
if t.hasPreviewWindow() {
|
||||||
t.previewing = !t.previewing
|
t.previewer.enabled = !t.previewer.enabled
|
||||||
t.resizeWindows()
|
t.resizeWindows()
|
||||||
cnt := t.merger.Length()
|
cnt := t.merger.Length()
|
||||||
if t.previewing && cnt > 0 && cnt > t.cy {
|
if t.previewer.enabled && cnt > 0 && cnt > t.cy {
|
||||||
t.previewBox.Set(reqPreviewEnqueue, previewRequest{true, t.current()})
|
t.previewBox.Set(reqPreviewEnqueue, previewRequest{true, t.current()})
|
||||||
}
|
}
|
||||||
req(reqList, reqInfo)
|
req(reqList, reqInfo)
|
||||||
@@ -1131,6 +1176,22 @@ func (t *Terminal) Loop() {
|
|||||||
t.eventBox.Set(EvtSearchNew, t.sort)
|
t.eventBox.Set(EvtSearchNew, t.sort)
|
||||||
t.mutex.Unlock()
|
t.mutex.Unlock()
|
||||||
return false
|
return false
|
||||||
|
case actPreviewUp:
|
||||||
|
if t.isPreviewEnabled() {
|
||||||
|
scrollPreview(-1)
|
||||||
|
}
|
||||||
|
case actPreviewDown:
|
||||||
|
if t.isPreviewEnabled() {
|
||||||
|
scrollPreview(1)
|
||||||
|
}
|
||||||
|
case actPreviewPageUp:
|
||||||
|
if t.isPreviewEnabled() {
|
||||||
|
scrollPreview(-t.pwindow.Height)
|
||||||
|
}
|
||||||
|
case actPreviewPageDown:
|
||||||
|
if t.isPreviewEnabled() {
|
||||||
|
scrollPreview(t.pwindow.Height)
|
||||||
|
}
|
||||||
case actBeginningOfLine:
|
case actBeginningOfLine:
|
||||||
t.cx = 0
|
t.cx = 0
|
||||||
case actBackwardChar:
|
case actBackwardChar:
|
||||||
@@ -1299,6 +1360,8 @@ func (t *Terminal) Loop() {
|
|||||||
}
|
}
|
||||||
t.vmove(me.S)
|
t.vmove(me.S)
|
||||||
req(reqList)
|
req(reqList)
|
||||||
|
} else if t.isPreviewEnabled() && t.pwindow.Enclose(my, mx) {
|
||||||
|
scrollPreview(-me.S)
|
||||||
}
|
}
|
||||||
} else if t.window.Enclose(my, mx) {
|
} else if t.window.Enclose(my, mx) {
|
||||||
mx -= t.window.Left
|
mx -= t.window.Left
|
||||||
|
|||||||
Reference in New Issue
Block a user