diff options
author | Junegunn Choi <junegunn.c@gmail.com> | 2021-03-13 02:24:37 +0900 |
---|---|---|
committer | Junegunn Choi <junegunn.c@gmail.com> | 2021-03-13 02:26:41 +0900 |
commit | 1b08f43f82af507165ec773922f4793da3cd9b4b (patch) | |
tree | 7c553c96917437a5953d0901e1151eeefe4e7858 /src | |
parent | b24a2e2fdcf15b3d0d353795f4bfa3d0b0fc06e6 (diff) |
Advanced preview scroll offset expression to better support fixed header
Diffstat (limited to 'src')
-rw-r--r-- | src/options.go | 8 | ||||
-rw-r--r-- | src/options_test.go | 6 | ||||
-rw-r--r-- | src/terminal.go | 52 |
3 files changed, 29 insertions, 37 deletions
diff --git a/src/options.go b/src/options.go index 29c90373..8d0afe06 100644 --- a/src/options.go +++ b/src/options.go @@ -84,7 +84,7 @@ const usage = `usage: fzf [options] [up|down|left|right][:SIZE[%]] [:[no]wrap][:[no]cycle][:[no]follow][:[no]hidden] [:rounded|sharp|noborder] - [:+SCROLL[-OFFSET]][:~HEADER_LINES] + [:+SCROLL[OFFSETS][/DENOM]][:~HEADER_LINES] [:default] Scripting @@ -1078,7 +1078,7 @@ func parseInfoStyle(str string) infoStyle { func parsePreviewWindow(opts *previewOpts, input string) { tokens := strings.Split(input, ":") sizeRegex := regexp.MustCompile("^[0-9]+%?$") - offsetRegex := regexp.MustCompile("^\\+([0-9]+|{-?[0-9]+})(-[0-9]+|-/[1-9][0-9]*)?$") + offsetRegex := regexp.MustCompile(`^(\+{-?[0-9]+})?([+-][0-9]+)*(-?/[1-9][0-9]*)?$`) headerRegex := regexp.MustCompile("^~(0|[1-9][0-9]*)$") for _, token := range tokens { switch token { @@ -1121,7 +1121,7 @@ func parsePreviewWindow(opts *previewOpts, input string) { } else if sizeRegex.MatchString(token) { opts.size = parseSize(token, 99, "window size") } else if offsetRegex.MatchString(token) { - opts.scroll = token[1:] + opts.scroll = token } else { errorExit("invalid preview window option: " + token) } @@ -1368,7 +1368,7 @@ func parseOptions(opts *Options, allArgs []string) { opts.Preview.command = "" case "--preview-window": parsePreviewWindow(&opts.Preview, - nextString(allArgs, &i, "preview window layout required: [up|down|left|right][:SIZE[%]][:rounded|sharp|noborder][:wrap][:cycle][:hidden][:+SCROLL[-OFFSET]][:~HEADER_LINES][:default]")) + nextString(allArgs, &i, "preview window layout required: [up|down|left|right][:SIZE[%]][:rounded|sharp|noborder][:wrap][:cycle][:hidden][:+SCROLL[OFFSETS][/DENOM]][:~HEADER_LINES][:default]")) case "--height": opts.Height = parseHeight(nextString(allArgs, &i, "height required: HEIGHT[%]")) case "--min-height": diff --git a/src/options_test.go b/src/options_test.go index 791b55d4..ce135413 100644 --- a/src/options_test.go +++ b/src/options_test.go @@ -389,18 +389,18 @@ func TestPreviewOpts(t *testing.T) { opts.Preview.hidden == true && opts.Preview.wrap == true && opts.Preview.position == posLeft && - opts.Preview.scroll == "{1}-/2" && + opts.Preview.scroll == "+{1}-/2" && opts.Preview.size.percent == false && opts.Preview.size.size == 15) { t.Error(opts.Preview) } - opts = optsFor("--preview-window=up:15:wrap:hidden:+{1}-/2", "--preview-window=down", "--preview-window=cycle") + opts = optsFor("--preview-window=up:15:wrap:hidden:+{1}+3-1-2/2", "--preview-window=down", "--preview-window=cycle") if !(opts.Preview.command == "" && opts.Preview.hidden == true && opts.Preview.wrap == true && opts.Preview.cycle == true && opts.Preview.position == posDown && - opts.Preview.scroll == "{1}-/2" && + opts.Preview.scroll == "+{1}+3-1-2/2" && opts.Preview.size.percent == false && opts.Preview.size.size == 15) { t.Error(opts.Preview.size.size) diff --git a/src/terminal.go b/src/terminal.go index 9fa11212..53a32769 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -22,8 +22,9 @@ import ( // import "github.com/pkg/profile" var placeholder *regexp.Regexp -var numericPrefix *regexp.Regexp var whiteSuffix *regexp.Regexp +var offsetComponentRegex *regexp.Regexp +var offsetTrimCharsRegex *regexp.Regexp var activeTempFiles []string const ellipsis string = ".." @@ -31,8 +32,9 @@ const clearCode string = "\x1b[2J" func init() { placeholder = regexp.MustCompile(`\\?(?:{[+sf]*[0-9,-.]*}|{q}|{\+?f?nf?})`) - numericPrefix = regexp.MustCompile(`^[[:punct:]]*([0-9]+)`) whiteSuffix = regexp.MustCompile(`\s*$`) + offsetComponentRegex = regexp.MustCompile(`([+-][0-9]+)|(-?/[1-9][0-9]*)`) + offsetTrimCharsRegex = regexp.MustCompile(`[^0-9/+-]`) activeTempFiles = []string{} } @@ -1591,43 +1593,33 @@ func (t *Terminal) replacePlaceholder(template string, forcePlus bool, input str template, t.ansi, t.delimiter, t.printsep, forcePlus, input, list) } -// Ascii to positive integer -func atopi(s string) int { - matches := numericPrefix.FindStringSubmatch(s) - if len(matches) < 2 { - return 0 - } - n, e := strconv.Atoi(matches[1]) - if e != nil || n < 1 { - return 0 - } - return n -} - func (t *Terminal) evaluateScrollOffset(list []*Item, height int) int { - offsetExpr := t.replacePlaceholder(t.previewOpts.scroll, false, "", list) - nums := strings.Split(offsetExpr, "-") - switch len(nums) { - case 0: - return 0 - case 1, 2: - base := atopi(nums[0]) - if base == 0 { + offsetExpr := offsetTrimCharsRegex.ReplaceAllString( + t.replacePlaceholder(t.previewOpts.scroll, false, "", list), "") + + atoi := func(s string) int { + n, e := strconv.Atoi(s) + if e != nil { return 0 - } else if len(nums) == 1 { - return base - 1 } - if nums[1][0] == '/' { - denom := atopi(nums[1][1:]) + return n + } + + base := -1 + for _, component := range offsetComponentRegex.FindAllString(offsetExpr, -1) { + if strings.HasPrefix(component, "-/") { + component = component[1:] + } + if component[0] == '/' { + denom := atoi(component[1:]) if denom == 0 { return base } return base - height/denom } - return base - atopi(nums[1]) - 1 - default: - return 0 + base += atoi(component) } + return base } func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, printsep string, forcePlus bool, query string, allItems []*Item) string { |