m/fzf
1
0
mirror of https://github.com/junegunn/fzf.git synced 2025-11-15 06:43:47 -05:00

Compare commits

...

7 Commits

Author SHA1 Message Date
Junegunn Choi
1bc223d4b3 0.15.2 2016-09-25 22:20:43 +09:00
Junegunn Choi
bef405bfa5 Ignore VT100-related escape codes 2016-09-25 19:03:08 +09:00
Junegunn Choi
0612074abe Support high intensity colors
Close #671
2016-09-25 18:11:35 +09:00
Junegunn Choi
3bf51d8362 Merge pull request #670 from maverickwoo/fix-668
[bash-completion] Fix #668
2016-09-25 05:15:24 +09:00
Maverick Woo
2c8479a7c5 Fix #668
Handle uppercase letters in program names. This also deals with `-` and
`.`, both of which are quite common in program names, e.g., `xdg-open`
and `foo.sh`.
2016-09-24 15:39:13 -04:00
Junegunn Choi
8c8b5b313e Add preview-page-up and preview-page-down actions 2016-09-25 04:12:44 +09:00
Junegunn Choi
66d55fd893 Make preview windows scrollable
Close #669

You can use your mouse or binadble preview-up and preview-down actions
to scroll the content of the preview window.

    fzf --preview 'highlight -O ansi {}' --bind alt-j:preview-down,alt-k:preview-up
2016-09-25 02:02:00 +09:00
9 changed files with 106 additions and 20 deletions

View File

@@ -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

View File

@@ -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=

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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