mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2025-02-02 03:58:30 +00:00
Make click-header export $FZF_CLICK_HEADER_{NTH,WORD}
This commit is contained in:
parent
c13228f346
commit
d6584543e9
12
CHANGELOG.md
12
CHANGELOG.md
@ -14,6 +14,18 @@ CHANGELOG
|
||||
--bind 'ctrl-r:reload(ps -ef)' --header 'Press CTRL-R to reload' \
|
||||
--header-lines-border bottom --no-list-border
|
||||
```
|
||||
- `click-header` event will also set `$FZF_CLICK_HEADER_WORD` and `$FZF_CLICK_HEADER_NTH`. You can use it to implement a clickable header that changes the search scope using the new `transform-nth` action.
|
||||
```sh
|
||||
# Click on the header line to limit search scope
|
||||
ps -ef | fzf --style full --layout reverse --header-lines 1 \
|
||||
--header-lines-border bottom --no-list-border \
|
||||
--color fg:dim,nth:regular \
|
||||
--bind 'click-header:transform-nth(
|
||||
echo $FZF_CLICK_HEADER_NTH
|
||||
)+transform-prompt(
|
||||
echo "$FZF_CLICK_HEADER_WORD> "
|
||||
)'
|
||||
```
|
||||
- Added `search(...)` and `transform-search(...)` action to trigger an fzf search with an arbitrary query string. This can be used to extend the search syntax of fzf. In the following example, fzf will use the first word of the query to trigger ripgrep search, and use the rest of the query to perform fzf search within the result.
|
||||
```sh
|
||||
TRANSFORMER='
|
||||
|
@ -1519,11 +1519,21 @@ e.g.
|
||||
|
||||
\fIclick\-header\fR
|
||||
.RS
|
||||
Triggered when a mouse click occurs within the header. Sets \fBFZF_CLICK_HEADER_LINE\fR and \fBFZF_CLICK_HEADER_COLUMN\fR environment variables starting from 1.
|
||||
Triggered when a mouse click occurs within the header. Sets
|
||||
\fBFZF_CLICK_HEADER_LINE\fR and \fBFZF_CLICK_HEADER_COLUMN\fR environment
|
||||
variables starting from 1. It optionally sets \fBFZF_CLICK_HEADER_WORD\fR and
|
||||
\fBFZF_CLICK_HEADER_NTH\fR if clicked on a word.
|
||||
|
||||
e.g.
|
||||
\fBprintf "head1\\nhead2" | fzf \-\-header\-lines=2 \-\-bind 'click\-header:transform\-prompt:printf ${FZF_CLICK_HEADER_LINE}x${FZF_CLICK_HEADER_COLUMN}'\fR
|
||||
|
||||
\fB# Click on the header line to limit search scope
|
||||
ps \-ef | fzf \-\-style full \-\-layout reverse \-\-header\-lines 1 \\
|
||||
\-\-header\-lines\-border bottom \-\-no\-list\-border \\
|
||||
\-\-color fg:dim,nth:regular \\
|
||||
\-\-bind 'click\-header:transform\-nth(
|
||||
echo $FZF_CLICK_HEADER_NTH
|
||||
)+transform\-prompt(
|
||||
echo "$FZF_CLICK_HEADER_WORD> "
|
||||
)'\fR
|
||||
.RE
|
||||
|
||||
.SS AVAILABLE ACTIONS:
|
||||
@ -1637,6 +1647,7 @@ A key or an event can be bound to one or more of the following actions.
|
||||
\fBtransform\-header\-label(...)\fR (transform header label using an external command)
|
||||
\fBtransform\-input\-label(...)\fR (transform input label using an external command)
|
||||
\fBtransform\-list\-label(...)\fR (transform list label using an external command)
|
||||
\fBtransform\-nth(...)\fR (transform nth using an external command)
|
||||
\fBtransform\-preview\-label(...)\fR (transform preview label using an external command)
|
||||
\fBtransform\-prompt(...)\fR (transform prompt string using an external command)
|
||||
\fBtransform\-query(...)\fR (transform query string using an external command)
|
||||
|
@ -93,51 +93,52 @@ func _() {
|
||||
_ = x[actTransformInputLabel-82]
|
||||
_ = x[actTransformHeader-83]
|
||||
_ = x[actTransformHeaderLabel-84]
|
||||
_ = x[actTransformPreviewLabel-85]
|
||||
_ = x[actTransformPrompt-86]
|
||||
_ = x[actTransformQuery-87]
|
||||
_ = x[actTransformSearch-88]
|
||||
_ = x[actSearch-89]
|
||||
_ = x[actPreview-90]
|
||||
_ = x[actChangePreview-91]
|
||||
_ = x[actChangePreviewWindow-92]
|
||||
_ = x[actPreviewTop-93]
|
||||
_ = x[actPreviewBottom-94]
|
||||
_ = x[actPreviewUp-95]
|
||||
_ = x[actPreviewDown-96]
|
||||
_ = x[actPreviewPageUp-97]
|
||||
_ = x[actPreviewPageDown-98]
|
||||
_ = x[actPreviewHalfPageUp-99]
|
||||
_ = x[actPreviewHalfPageDown-100]
|
||||
_ = x[actPrevHistory-101]
|
||||
_ = x[actPrevSelected-102]
|
||||
_ = x[actPrint-103]
|
||||
_ = x[actPut-104]
|
||||
_ = x[actNextHistory-105]
|
||||
_ = x[actNextSelected-106]
|
||||
_ = x[actExecute-107]
|
||||
_ = x[actExecuteSilent-108]
|
||||
_ = x[actExecuteMulti-109]
|
||||
_ = x[actSigStop-110]
|
||||
_ = x[actFirst-111]
|
||||
_ = x[actLast-112]
|
||||
_ = x[actReload-113]
|
||||
_ = x[actReloadSync-114]
|
||||
_ = x[actDisableSearch-115]
|
||||
_ = x[actEnableSearch-116]
|
||||
_ = x[actSelect-117]
|
||||
_ = x[actDeselect-118]
|
||||
_ = x[actUnbind-119]
|
||||
_ = x[actRebind-120]
|
||||
_ = x[actBecome-121]
|
||||
_ = x[actShowHeader-122]
|
||||
_ = x[actHideHeader-123]
|
||||
_ = x[actBell-124]
|
||||
_ = x[actTransformNth-85]
|
||||
_ = x[actTransformPreviewLabel-86]
|
||||
_ = x[actTransformPrompt-87]
|
||||
_ = x[actTransformQuery-88]
|
||||
_ = x[actTransformSearch-89]
|
||||
_ = x[actSearch-90]
|
||||
_ = x[actPreview-91]
|
||||
_ = x[actChangePreview-92]
|
||||
_ = x[actChangePreviewWindow-93]
|
||||
_ = x[actPreviewTop-94]
|
||||
_ = x[actPreviewBottom-95]
|
||||
_ = x[actPreviewUp-96]
|
||||
_ = x[actPreviewDown-97]
|
||||
_ = x[actPreviewPageUp-98]
|
||||
_ = x[actPreviewPageDown-99]
|
||||
_ = x[actPreviewHalfPageUp-100]
|
||||
_ = x[actPreviewHalfPageDown-101]
|
||||
_ = x[actPrevHistory-102]
|
||||
_ = x[actPrevSelected-103]
|
||||
_ = x[actPrint-104]
|
||||
_ = x[actPut-105]
|
||||
_ = x[actNextHistory-106]
|
||||
_ = x[actNextSelected-107]
|
||||
_ = x[actExecute-108]
|
||||
_ = x[actExecuteSilent-109]
|
||||
_ = x[actExecuteMulti-110]
|
||||
_ = x[actSigStop-111]
|
||||
_ = x[actFirst-112]
|
||||
_ = x[actLast-113]
|
||||
_ = x[actReload-114]
|
||||
_ = x[actReloadSync-115]
|
||||
_ = x[actDisableSearch-116]
|
||||
_ = x[actEnableSearch-117]
|
||||
_ = x[actSelect-118]
|
||||
_ = x[actDeselect-119]
|
||||
_ = x[actUnbind-120]
|
||||
_ = x[actRebind-121]
|
||||
_ = x[actBecome-122]
|
||||
_ = x[actShowHeader-123]
|
||||
_ = x[actHideHeader-124]
|
||||
_ = x[actBell-125]
|
||||
}
|
||||
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeListLabelactChangeInputLabelactChangeHeaderactChangeHeaderLabelactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactChangeNthactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformListLabelactTransformInputLabelactTransformHeaderactTransformHeaderLabelactTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactSearchactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactBecomeactShowHeaderactHideHeaderactBell"
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeListLabelactChangeInputLabelactChangeHeaderactChangeHeaderLabelactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactChangeNthactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformListLabelactTransformInputLabelactTransformHeaderactTransformHeaderLabelactTransformNthactTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactSearchactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactBecomeactShowHeaderactHideHeaderactBell"
|
||||
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 42, 50, 68, 76, 85, 102, 123, 138, 159, 183, 198, 207, 227, 245, 264, 279, 299, 313, 334, 349, 363, 375, 389, 402, 419, 427, 440, 456, 468, 476, 490, 504, 515, 526, 544, 561, 568, 587, 599, 613, 622, 637, 649, 662, 673, 684, 696, 710, 731, 746, 759, 777, 793, 808, 825, 832, 837, 846, 857, 868, 881, 896, 907, 920, 935, 942, 955, 968, 985, 1000, 1013, 1027, 1041, 1057, 1077, 1089, 1112, 1133, 1155, 1173, 1196, 1220, 1238, 1255, 1273, 1282, 1292, 1308, 1330, 1343, 1359, 1371, 1385, 1401, 1419, 1439, 1461, 1475, 1490, 1498, 1504, 1518, 1533, 1543, 1559, 1574, 1584, 1592, 1599, 1608, 1621, 1637, 1652, 1661, 1672, 1681, 1690, 1699, 1712, 1725, 1732}
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 42, 50, 68, 76, 85, 102, 123, 138, 159, 183, 198, 207, 227, 245, 264, 279, 299, 313, 334, 349, 363, 375, 389, 402, 419, 427, 440, 456, 468, 476, 490, 504, 515, 526, 544, 561, 568, 587, 599, 613, 622, 637, 649, 662, 673, 684, 696, 710, 731, 746, 759, 777, 793, 808, 825, 832, 837, 846, 857, 868, 881, 896, 907, 920, 935, 942, 955, 968, 985, 1000, 1013, 1027, 1041, 1057, 1077, 1089, 1112, 1133, 1155, 1173, 1196, 1211, 1235, 1253, 1270, 1288, 1297, 1307, 1323, 1345, 1358, 1374, 1386, 1400, 1416, 1434, 1454, 1476, 1490, 1505, 1513, 1519, 1533, 1548, 1558, 1574, 1589, 1599, 1607, 1614, 1623, 1636, 1652, 1667, 1676, 1687, 1696, 1705, 1714, 1727, 1740, 1747}
|
||||
|
||||
func (i actionType) String() string {
|
||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||
|
@ -1332,7 +1332,7 @@ const (
|
||||
|
||||
func init() {
|
||||
executeRegexp = regexp.MustCompile(
|
||||
`(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:query|prompt|(?:border|list|preview|input|header)-label|header|search)|transform|change-(?:preview-window|preview|multi|nth)|(?:re|un)bind|pos|put|print|search)`)
|
||||
`(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:query|prompt|(?:border|list|preview|input|header)-label|header|search|nth)|transform|change-(?:preview-window|preview|multi)|(?:re|un)bind|pos|put|print|search)`)
|
||||
splitRegexp = regexp.MustCompile("[,:]+")
|
||||
actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+")
|
||||
}
|
||||
@ -1740,6 +1740,8 @@ func isExecuteAction(str string) actionType {
|
||||
return actTransformHeaderLabel
|
||||
case "transform-header":
|
||||
return actTransformHeader
|
||||
case "transform-nth":
|
||||
return actTransformNth
|
||||
case "transform-prompt":
|
||||
return actTransformPrompt
|
||||
case "transform-query":
|
||||
|
@ -531,6 +531,7 @@ const (
|
||||
actTransformInputLabel
|
||||
actTransformHeader
|
||||
actTransformHeaderLabel
|
||||
actTransformNth
|
||||
actTransformPreviewLabel
|
||||
actTransformPrompt
|
||||
actTransformQuery
|
||||
@ -1065,6 +1066,7 @@ func (t *Terminal) environImpl(forPreview bool) []string {
|
||||
env = append(env, fmt.Sprintf("FZF_POS=%d", util.Min(t.merger.Length(), t.cy+1)))
|
||||
env = append(env, fmt.Sprintf("FZF_CLICK_HEADER_LINE=%d", t.clickHeaderLine))
|
||||
env = append(env, fmt.Sprintf("FZF_CLICK_HEADER_COLUMN=%d", t.clickHeaderColumn))
|
||||
env = t.addClickHeaderWord(env)
|
||||
|
||||
// Add preview environment variables if preview is enabled
|
||||
pwindowSize := t.pwindowSize()
|
||||
@ -1393,6 +1395,8 @@ func (t *Terminal) changeHeader(header string) bool {
|
||||
}
|
||||
needFullRedraw := len(t.header0) != len(lines)
|
||||
t.header0 = lines
|
||||
t.clickHeaderLine = 0
|
||||
t.clickHeaderColumn = 0
|
||||
return needFullRedraw
|
||||
}
|
||||
|
||||
@ -4089,6 +4093,64 @@ func (t *Terminal) currentIndex() int32 {
|
||||
return minItem.Index()
|
||||
}
|
||||
|
||||
func (t *Terminal) addClickHeaderWord(env []string) []string {
|
||||
/*
|
||||
* echo $'HL1\nHL2' | fzf --header-lines 3 --header $'H1\nH2' --header-lines-border --bind 'click-header:preview:env | grep FZF_CLICK'
|
||||
*
|
||||
* REVERSE DEFAULT
|
||||
* H1 1 1
|
||||
* H2 2 HL2 2
|
||||
* ------- HL1 3
|
||||
* HL1 3 -------
|
||||
* HL2 4 H1 4
|
||||
* 5 H2 5
|
||||
*/
|
||||
lineNum := t.clickHeaderLine - 1
|
||||
if lineNum < 0 {
|
||||
// Never clicked on the header
|
||||
return env
|
||||
}
|
||||
|
||||
var line string
|
||||
if t.layout == layoutReverse {
|
||||
if lineNum < len(t.header0) {
|
||||
line = t.header0[lineNum]
|
||||
} else if lineNum-len(t.header0) < len(t.header) {
|
||||
line = t.header[lineNum-len(t.header0)]
|
||||
}
|
||||
} else {
|
||||
// NOTE: t.header is padded with empty strings so that its size is equal to t.headerLines
|
||||
if lineNum < len(t.header) {
|
||||
line = t.header[len(t.header)-lineNum-1]
|
||||
} else if lineNum-len(t.header) < len(t.header0) {
|
||||
line = t.header0[lineNum-len(t.header)]
|
||||
}
|
||||
}
|
||||
if len(line) == 0 {
|
||||
return env
|
||||
}
|
||||
|
||||
colNum := t.clickHeaderColumn - 1
|
||||
words := Tokenize(line, t.delimiter)
|
||||
for idx, token := range words {
|
||||
prefixWidth := int(token.prefixLength)
|
||||
word := token.text.ToString()
|
||||
trimmed := strings.TrimSpace(word)
|
||||
trimWidth, _ := util.RunesWidth([]rune(trimmed), prefixWidth, t.tabstop, math.MaxInt32)
|
||||
|
||||
if colNum >= prefixWidth && colNum < prefixWidth+trimWidth {
|
||||
env = append(env, fmt.Sprintf("FZF_CLICK_HEADER_WORD=%s", trimmed))
|
||||
nth := fmt.Sprintf("FZF_CLICK_HEADER_NTH=%d", idx+1)
|
||||
if idx == len(words)-1 {
|
||||
nth += ".."
|
||||
}
|
||||
env = append(env, nth)
|
||||
return env
|
||||
}
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
// Loop is called to start Terminal I/O
|
||||
func (t *Terminal) Loop() error {
|
||||
// prof := profile.Start(profile.ProfilePath("/tmp/"))
|
||||
@ -4833,11 +4895,14 @@ func (t *Terminal) Loop() error {
|
||||
}
|
||||
t.multi = multi
|
||||
req(reqList, reqInfo)
|
||||
case actChangeNth:
|
||||
changed = true
|
||||
case actChangeNth, actTransformNth:
|
||||
expr := a.a
|
||||
if a.t == actTransformNth {
|
||||
expr = t.captureLine(a.a)
|
||||
}
|
||||
|
||||
// Split nth expression
|
||||
tokens := strings.Split(a.a, "|")
|
||||
tokens := strings.Split(expr, "|")
|
||||
if nth, err := splitNth(tokens[0]); err == nil {
|
||||
// Changed
|
||||
newNth = &nth
|
||||
@ -4845,12 +4910,15 @@ func (t *Terminal) Loop() error {
|
||||
// The default
|
||||
newNth = &t.nth
|
||||
}
|
||||
t.nthCurrent = *newNth
|
||||
// Cycle
|
||||
if len(tokens) > 1 {
|
||||
a.a = strings.Join(append(tokens[1:], tokens[0]), "|")
|
||||
}
|
||||
t.forceRerenderList()
|
||||
if !compareRanges(t.nthCurrent, *newNth) {
|
||||
changed = true
|
||||
t.nthCurrent = *newNth
|
||||
t.forceRerenderList()
|
||||
}
|
||||
case actChangeQuery:
|
||||
t.input = []rune(a.a)
|
||||
t.cx = len(t.input)
|
||||
|
@ -22,6 +22,18 @@ func (r Range) IsFull() bool {
|
||||
return r.begin == rangeEllipsis && r.end == rangeEllipsis
|
||||
}
|
||||
|
||||
func compareRanges(r1 []Range, r2 []Range) bool {
|
||||
if len(r1) != len(r2) {
|
||||
return false
|
||||
}
|
||||
for idx := range r1 {
|
||||
if r1[idx] != r2[idx] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func RangesToString(ranges []Range) string {
|
||||
strs := []string{}
|
||||
for _, r := range ranges {
|
||||
|
Loading…
x
Reference in New Issue
Block a user