mirror of
https://github.com/junegunn/fzf.git
synced 2026-02-07 02:11:13 +08:00
Implement asynchronous transform actions
Close #4418 Example: fzf --bind 'focus:&transform-header(sleep 2; date; echo {})'
This commit is contained in:
@@ -113,48 +113,64 @@ func _() {
|
||||
_ = x[actTransformPrompt-102]
|
||||
_ = x[actTransformQuery-103]
|
||||
_ = x[actTransformSearch-104]
|
||||
_ = x[actSearch-105]
|
||||
_ = x[actPreview-106]
|
||||
_ = x[actPreviewTop-107]
|
||||
_ = x[actPreviewBottom-108]
|
||||
_ = x[actPreviewUp-109]
|
||||
_ = x[actPreviewDown-110]
|
||||
_ = x[actPreviewPageUp-111]
|
||||
_ = x[actPreviewPageDown-112]
|
||||
_ = x[actPreviewHalfPageUp-113]
|
||||
_ = x[actPreviewHalfPageDown-114]
|
||||
_ = x[actPrevHistory-115]
|
||||
_ = x[actPrevSelected-116]
|
||||
_ = x[actPrint-117]
|
||||
_ = x[actPut-118]
|
||||
_ = x[actNextHistory-119]
|
||||
_ = x[actNextSelected-120]
|
||||
_ = x[actExecute-121]
|
||||
_ = x[actExecuteSilent-122]
|
||||
_ = x[actExecuteMulti-123]
|
||||
_ = x[actSigStop-124]
|
||||
_ = x[actFirst-125]
|
||||
_ = x[actLast-126]
|
||||
_ = x[actReload-127]
|
||||
_ = x[actReloadSync-128]
|
||||
_ = x[actDisableSearch-129]
|
||||
_ = x[actEnableSearch-130]
|
||||
_ = x[actSelect-131]
|
||||
_ = x[actDeselect-132]
|
||||
_ = x[actUnbind-133]
|
||||
_ = x[actRebind-134]
|
||||
_ = x[actToggleBind-135]
|
||||
_ = x[actBecome-136]
|
||||
_ = x[actShowHeader-137]
|
||||
_ = x[actHideHeader-138]
|
||||
_ = x[actBell-139]
|
||||
_ = x[actExclude-140]
|
||||
_ = x[actExcludeMulti-141]
|
||||
_ = x[actAsyncTransform-105]
|
||||
_ = x[actAsyncTransformBorderLabel-106]
|
||||
_ = x[actAsyncTransformGhost-107]
|
||||
_ = x[actAsyncTransformHeader-108]
|
||||
_ = x[actAsyncTransformFooter-109]
|
||||
_ = x[actAsyncTransformHeaderLabel-110]
|
||||
_ = x[actAsyncTransformFooterLabel-111]
|
||||
_ = x[actAsyncTransformInputLabel-112]
|
||||
_ = x[actAsyncTransformListLabel-113]
|
||||
_ = x[actAsyncTransformNth-114]
|
||||
_ = x[actAsyncTransformPointer-115]
|
||||
_ = x[actAsyncTransformPreviewLabel-116]
|
||||
_ = x[actAsyncTransformPrompt-117]
|
||||
_ = x[actAsyncTransformQuery-118]
|
||||
_ = x[actAsyncTransformSearch-119]
|
||||
_ = x[actSearch-120]
|
||||
_ = x[actPreview-121]
|
||||
_ = x[actPreviewTop-122]
|
||||
_ = x[actPreviewBottom-123]
|
||||
_ = x[actPreviewUp-124]
|
||||
_ = x[actPreviewDown-125]
|
||||
_ = x[actPreviewPageUp-126]
|
||||
_ = x[actPreviewPageDown-127]
|
||||
_ = x[actPreviewHalfPageUp-128]
|
||||
_ = x[actPreviewHalfPageDown-129]
|
||||
_ = x[actPrevHistory-130]
|
||||
_ = x[actPrevSelected-131]
|
||||
_ = x[actPrint-132]
|
||||
_ = x[actPut-133]
|
||||
_ = x[actNextHistory-134]
|
||||
_ = x[actNextSelected-135]
|
||||
_ = x[actExecute-136]
|
||||
_ = x[actExecuteSilent-137]
|
||||
_ = x[actExecuteMulti-138]
|
||||
_ = x[actSigStop-139]
|
||||
_ = x[actFirst-140]
|
||||
_ = x[actLast-141]
|
||||
_ = x[actReload-142]
|
||||
_ = x[actReloadSync-143]
|
||||
_ = x[actDisableSearch-144]
|
||||
_ = x[actEnableSearch-145]
|
||||
_ = x[actSelect-146]
|
||||
_ = x[actDeselect-147]
|
||||
_ = x[actUnbind-148]
|
||||
_ = x[actRebind-149]
|
||||
_ = x[actToggleBind-150]
|
||||
_ = x[actBecome-151]
|
||||
_ = x[actShowHeader-152]
|
||||
_ = x[actHideHeader-153]
|
||||
_ = x[actBell-154]
|
||||
_ = x[actExclude-155]
|
||||
_ = x[actExcludeMulti-156]
|
||||
_ = x[actAsync-157]
|
||||
}
|
||||
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMulti"
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactAsyncTransformactAsyncTransformBorderLabelactAsyncTransformGhostactAsyncTransformHeaderactAsyncTransformFooteractAsyncTransformHeaderLabelactAsyncTransformFooterLabelactAsyncTransformInputLabelactAsyncTransformListLabelactAsyncTransformNthactAsyncTransformPointeractAsyncTransformPreviewLabelactAsyncTransformPromptactAsyncTransformQueryactAsyncTransformSearchactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 249, 269, 283, 298, 313, 333, 353, 372, 390, 404, 416, 432, 448, 469, 491, 506, 520, 534, 547, 564, 572, 585, 601, 613, 621, 635, 649, 660, 671, 689, 706, 713, 732, 744, 758, 767, 782, 794, 807, 818, 829, 841, 855, 876, 891, 904, 922, 938, 953, 967, 979, 991, 1008, 1015, 1020, 1029, 1040, 1051, 1064, 1079, 1090, 1103, 1118, 1125, 1138, 1151, 1168, 1183, 1196, 1210, 1224, 1240, 1260, 1272, 1295, 1312, 1330, 1348, 1371, 1394, 1416, 1437, 1452, 1471, 1495, 1513, 1530, 1548, 1557, 1567, 1580, 1596, 1608, 1622, 1638, 1656, 1676, 1698, 1712, 1727, 1735, 1741, 1755, 1770, 1780, 1796, 1811, 1821, 1829, 1836, 1845, 1858, 1874, 1889, 1898, 1909, 1918, 1927, 1940, 1949, 1962, 1975, 1982, 1992, 2007}
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 249, 269, 283, 298, 313, 333, 353, 372, 390, 404, 416, 432, 448, 469, 491, 506, 520, 534, 547, 564, 572, 585, 601, 613, 621, 635, 649, 660, 671, 689, 706, 713, 732, 744, 758, 767, 782, 794, 807, 818, 829, 841, 855, 876, 891, 904, 922, 938, 953, 967, 979, 991, 1008, 1015, 1020, 1029, 1040, 1051, 1064, 1079, 1090, 1103, 1118, 1125, 1138, 1151, 1168, 1183, 1196, 1210, 1224, 1240, 1260, 1272, 1295, 1312, 1330, 1348, 1371, 1394, 1416, 1437, 1452, 1471, 1495, 1513, 1530, 1548, 1565, 1593, 1615, 1638, 1661, 1689, 1717, 1744, 1770, 1790, 1814, 1843, 1866, 1888, 1911, 1920, 1930, 1943, 1959, 1971, 1985, 2001, 2019, 2039, 2061, 2075, 2090, 2098, 2104, 2118, 2133, 2143, 2159, 2174, 2184, 2192, 2199, 2208, 2221, 2237, 2252, 2261, 2272, 2281, 2290, 2303, 2312, 2325, 2338, 2345, 2355, 2370, 2378}
|
||||
|
||||
func (i actionType) String() string {
|
||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||
|
||||
@@ -1435,9 +1435,9 @@ const (
|
||||
|
||||
func init() {
|
||||
executeRegexp = regexp.MustCompile(
|
||||
`(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:query|prompt|(?:border|list|preview|input|header|footer)-label|header|footer|search|nth|pointer|ghost)|transform|change-(?:preview-window|preview|multi)|(?:re|un|toggle-)bind|pos|put|print|search)`)
|
||||
`(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|&?transform)-(?:query|prompt|(?:border|list|preview|input|header|footer)-label|header|footer|search|nth|pointer|ghost)|&?transform|change-(?:preview-window|preview|multi)|(?:re|un|toggle-)bind|pos|put|print|search)`)
|
||||
splitRegexp = regexp.MustCompile("[,:]+")
|
||||
actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+")
|
||||
actionNameRegexp = regexp.MustCompile("(?i)^&?[a-z-]+")
|
||||
}
|
||||
|
||||
func maskActionContents(action string) string {
|
||||
@@ -1892,6 +1892,36 @@ func isExecuteAction(str string) actionType {
|
||||
return actTransformQuery
|
||||
case "transform-search":
|
||||
return actTransformSearch
|
||||
case "&transform":
|
||||
return actAsyncTransform
|
||||
case "&transform-list-label":
|
||||
return actAsyncTransformListLabel
|
||||
case "&transform-border-label":
|
||||
return actAsyncTransformBorderLabel
|
||||
case "&transform-preview-label":
|
||||
return actAsyncTransformPreviewLabel
|
||||
case "&transform-input-label":
|
||||
return actAsyncTransformInputLabel
|
||||
case "&transform-header-label":
|
||||
return actAsyncTransformHeaderLabel
|
||||
case "&transform-footer-label":
|
||||
return actAsyncTransformFooterLabel
|
||||
case "&transform-footer":
|
||||
return actAsyncTransformFooter
|
||||
case "&transform-header":
|
||||
return actAsyncTransformHeader
|
||||
case "&transform-ghost":
|
||||
return actAsyncTransformGhost
|
||||
case "&transform-nth":
|
||||
return actAsyncTransformNth
|
||||
case "&transform-pointer":
|
||||
return actAsyncTransformPointer
|
||||
case "&transform-prompt":
|
||||
return actAsyncTransformPrompt
|
||||
case "&transform-query":
|
||||
return actAsyncTransformQuery
|
||||
case "&transform-search":
|
||||
return actAsyncTransformSearch
|
||||
case "search":
|
||||
return actSearch
|
||||
}
|
||||
|
||||
408
src/terminal.go
408
src/terminal.go
@@ -388,6 +388,7 @@ type Terminal struct {
|
||||
startChan chan fitpad
|
||||
killChan chan bool
|
||||
serverInputChan chan []*action
|
||||
callbackChan chan func()
|
||||
keyChan chan tui.Event
|
||||
eventChan chan tui.Event
|
||||
slab *util.Slab
|
||||
@@ -489,6 +490,7 @@ const (
|
||||
actBackwardDeleteCharEof
|
||||
actBackwardWord
|
||||
actCancel
|
||||
|
||||
actChangeBorderLabel
|
||||
actChangeGhost
|
||||
actChangeHeader
|
||||
@@ -505,6 +507,7 @@ const (
|
||||
actChangePreviewWindow
|
||||
actChangePrompt
|
||||
actChangeQuery
|
||||
|
||||
actClearScreen
|
||||
actClearQuery
|
||||
actClearSelection
|
||||
@@ -561,6 +564,7 @@ const (
|
||||
actHidePreview
|
||||
actTogglePreview
|
||||
actTogglePreviewWrap
|
||||
|
||||
actTransform
|
||||
actTransformBorderLabel
|
||||
actTransformGhost
|
||||
@@ -576,6 +580,23 @@ const (
|
||||
actTransformPrompt
|
||||
actTransformQuery
|
||||
actTransformSearch
|
||||
|
||||
actAsyncTransform
|
||||
actAsyncTransformBorderLabel
|
||||
actAsyncTransformGhost
|
||||
actAsyncTransformHeader
|
||||
actAsyncTransformFooter
|
||||
actAsyncTransformHeaderLabel
|
||||
actAsyncTransformFooterLabel
|
||||
actAsyncTransformInputLabel
|
||||
actAsyncTransformListLabel
|
||||
actAsyncTransformNth
|
||||
actAsyncTransformPointer
|
||||
actAsyncTransformPreviewLabel
|
||||
actAsyncTransformPrompt
|
||||
actAsyncTransformQuery
|
||||
actAsyncTransformSearch
|
||||
|
||||
actSearch
|
||||
actPreview
|
||||
actPreviewTop
|
||||
@@ -613,6 +634,7 @@ const (
|
||||
actBell
|
||||
actExclude
|
||||
actExcludeMulti
|
||||
actAsync
|
||||
)
|
||||
|
||||
func (a actionType) Name() string {
|
||||
@@ -623,10 +645,34 @@ func processExecution(action actionType) bool {
|
||||
switch action {
|
||||
case actTransform,
|
||||
actTransformBorderLabel,
|
||||
actTransformGhost,
|
||||
actTransformHeader,
|
||||
actTransformFooter,
|
||||
actTransformHeaderLabel,
|
||||
actTransformFooterLabel,
|
||||
actTransformInputLabel,
|
||||
actTransformListLabel,
|
||||
actTransformNth,
|
||||
actTransformPointer,
|
||||
actTransformPreviewLabel,
|
||||
actTransformPrompt,
|
||||
actTransformQuery,
|
||||
actTransformSearch,
|
||||
actAsyncTransform,
|
||||
actAsyncTransformBorderLabel,
|
||||
actAsyncTransformGhost,
|
||||
actAsyncTransformHeader,
|
||||
actAsyncTransformFooter,
|
||||
actAsyncTransformHeaderLabel,
|
||||
actAsyncTransformFooterLabel,
|
||||
actAsyncTransformInputLabel,
|
||||
actAsyncTransformListLabel,
|
||||
actAsyncTransformNth,
|
||||
actAsyncTransformPointer,
|
||||
actAsyncTransformPreviewLabel,
|
||||
actAsyncTransformPrompt,
|
||||
actAsyncTransformQuery,
|
||||
actAsyncTransformSearch,
|
||||
actPreview,
|
||||
actChangePreview,
|
||||
actRefreshPreview,
|
||||
@@ -773,7 +819,7 @@ func mayTriggerPreview(opts *Options) bool {
|
||||
for _, actions := range opts.Keymap {
|
||||
for _, action := range actions {
|
||||
switch action.t {
|
||||
case actPreview, actChangePreview, actTransform:
|
||||
case actPreview, actChangePreview, actTransform, actAsyncTransform:
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -987,6 +1033,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
||||
startChan: make(chan fitpad, 1),
|
||||
killChan: make(chan bool),
|
||||
serverInputChan: make(chan []*action, 100),
|
||||
callbackChan: make(chan func(), 100),
|
||||
keyChan: make(chan tui.Event),
|
||||
eventChan: make(chan tui.Event, 6), // start | (load + result + zero|one) | (focus) | (resize)
|
||||
tui: renderer,
|
||||
@@ -4291,6 +4338,32 @@ func (t *Terminal) captureLines(template string) string {
|
||||
return t.executeCommand(template, false, true, true, false, "")
|
||||
}
|
||||
|
||||
func (t *Terminal) captureAsync(template string, firstLineOnly bool, callback func(string)) {
|
||||
_, list := t.buildPlusList(template, false)
|
||||
command, tempFiles := t.replacePlaceholder(template, false, string(t.input), list)
|
||||
go func() {
|
||||
cmd := t.executor.ExecCommand(command, false)
|
||||
cmd.Env = t.environ()
|
||||
|
||||
out, _ := cmd.StdoutPipe()
|
||||
reader := bufio.NewReader(out)
|
||||
var output string
|
||||
if err := cmd.Start(); err == nil {
|
||||
if firstLineOnly {
|
||||
output, _ = reader.ReadString('\n')
|
||||
output = strings.TrimRight(output, "\r\n")
|
||||
} else {
|
||||
bytes, _ := io.ReadAll(reader)
|
||||
output = string(bytes)
|
||||
}
|
||||
cmd.Wait()
|
||||
}
|
||||
removeFiles(tempFiles)
|
||||
|
||||
t.callbackChan <- func() { callback(output) }
|
||||
}()
|
||||
}
|
||||
|
||||
func (t *Terminal) executeCommand(template string, forcePlus bool, background bool, capture bool, firstLineOnly bool, info string) string {
|
||||
line := ""
|
||||
valid, list := t.buildPlusList(template, forcePlus)
|
||||
@@ -5089,11 +5162,27 @@ func (t *Terminal) Loop() error {
|
||||
barrier <- true
|
||||
needBarrier = false
|
||||
}
|
||||
|
||||
// These variables are defined outside the loop to be accessible from closures
|
||||
events := []util.EventType{}
|
||||
changed := false
|
||||
var newNth *[]Range
|
||||
req := func(evts ...util.EventType) {
|
||||
for _, event := range evts {
|
||||
events = append(events, event)
|
||||
if event == reqClose || event == reqQuit {
|
||||
looping = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The main event loop
|
||||
for loopIndex := int64(0); looping; loopIndex++ {
|
||||
var newCommand *commandSpec
|
||||
var newNth *[]Range
|
||||
var reloadSync bool
|
||||
changed := false
|
||||
events = []util.EventType{}
|
||||
changed = false
|
||||
newNth = nil
|
||||
beof := false
|
||||
queryChanged := false
|
||||
denylist := []int32{}
|
||||
@@ -5110,6 +5199,7 @@ func (t *Terminal) Loop() error {
|
||||
|
||||
var event tui.Event
|
||||
actions := []*action{}
|
||||
callbacks := []func(){}
|
||||
select {
|
||||
case event = <-t.keyChan:
|
||||
needBarrier = true
|
||||
@@ -5141,6 +5231,20 @@ func (t *Terminal) Loop() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
case callback := <-t.callbackChan:
|
||||
event = tui.Invalid.AsEvent()
|
||||
actions = append(actions, &action{t: actAsync})
|
||||
callbacks = append(callbacks, callback)
|
||||
DrainCallback:
|
||||
for {
|
||||
select {
|
||||
case callback = <-t.callbackChan:
|
||||
callbacks = append(callbacks, callback)
|
||||
continue DrainCallback
|
||||
default:
|
||||
break DrainCallback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.mutex.Lock()
|
||||
@@ -5155,15 +5259,6 @@ func (t *Terminal) Loop() error {
|
||||
previousInput := t.input
|
||||
previousCx := t.cx
|
||||
t.lastKey = event.KeyName()
|
||||
events := []util.EventType{}
|
||||
req := func(evts ...util.EventType) {
|
||||
for _, event := range evts {
|
||||
events = append(events, event)
|
||||
if event == reqClose || event == reqQuit {
|
||||
looping = false
|
||||
}
|
||||
}
|
||||
}
|
||||
updatePreviewWindow := func(forcePreview bool) {
|
||||
t.resizeWindows(forcePreview, false)
|
||||
req(reqPrompt, reqList, reqInfo, reqHeader, reqFooter)
|
||||
@@ -5238,9 +5333,29 @@ func (t *Terminal) Loop() error {
|
||||
// actions to allow changing the query even when the input is hidden
|
||||
// e.g. fzf --no-input --bind 'space:show-input+change-query(foo)+hide-input'
|
||||
currentInput := t.input
|
||||
capture := func(firstLineOnly bool, callback func(string)) {
|
||||
if a.t >= actAsyncTransform {
|
||||
// &transform-*
|
||||
t.captureAsync(a.a, firstLineOnly, callback)
|
||||
} else if a.t >= actTransform {
|
||||
// transform-*
|
||||
if firstLineOnly {
|
||||
callback(t.captureLine(a.a))
|
||||
} else {
|
||||
callback(t.captureLines(a.a))
|
||||
}
|
||||
} else {
|
||||
// change-*
|
||||
callback(a.a)
|
||||
}
|
||||
}
|
||||
Action:
|
||||
switch a.t {
|
||||
case actIgnore, actStart, actClick:
|
||||
case actAsync:
|
||||
for _, callback := range callbacks {
|
||||
callback()
|
||||
}
|
||||
case actBecome:
|
||||
valid, list := t.buildPlusList(a.a, false)
|
||||
if valid {
|
||||
@@ -5333,15 +5448,17 @@ func (t *Terminal) Loop() error {
|
||||
t.previewed.version = 0
|
||||
req(reqPreviewRefresh)
|
||||
}
|
||||
case actTransformPrompt:
|
||||
prompt := t.captureLine(a.a)
|
||||
t.promptString = prompt
|
||||
t.prompt, t.promptLen = t.parsePrompt(prompt)
|
||||
req(reqPrompt)
|
||||
case actTransformQuery:
|
||||
query := t.captureLine(a.a)
|
||||
t.input = []rune(query)
|
||||
t.cx = len(t.input)
|
||||
case actTransformPrompt, actAsyncTransformPrompt:
|
||||
capture(true, func(prompt string) {
|
||||
t.promptString = prompt
|
||||
t.prompt, t.promptLen = t.parsePrompt(prompt)
|
||||
req(reqPrompt)
|
||||
})
|
||||
case actTransformQuery, actAsyncTransformQuery:
|
||||
capture(true, func(query string) {
|
||||
t.input = []rune(query)
|
||||
t.cx = len(t.input)
|
||||
})
|
||||
case actToggleSort:
|
||||
t.sort = !t.sort
|
||||
changed = true
|
||||
@@ -5399,119 +5516,102 @@ func (t *Terminal) Loop() error {
|
||||
}
|
||||
t.multi = multi
|
||||
req(reqList, reqInfo)
|
||||
case actChangeNth, actTransformNth:
|
||||
expr := a.a
|
||||
if a.t == actTransformNth {
|
||||
expr = t.captureLine(a.a)
|
||||
}
|
||||
|
||||
// Split nth expression
|
||||
tokens := strings.Split(expr, "|")
|
||||
if nth, err := splitNth(tokens[0]); err == nil {
|
||||
// Changed
|
||||
newNth = &nth
|
||||
} else {
|
||||
// The default
|
||||
newNth = &t.nth
|
||||
}
|
||||
// Cycle
|
||||
if len(tokens) > 1 {
|
||||
a.a = strings.Join(append(tokens[1:], tokens[0]), "|")
|
||||
}
|
||||
if !compareRanges(t.nthCurrent, *newNth) {
|
||||
changed = true
|
||||
t.nthCurrent = *newNth
|
||||
t.forceRerenderList()
|
||||
}
|
||||
case actChangeNth, actTransformNth, actAsyncTransformNth:
|
||||
capture(true, func(expr string) {
|
||||
// Split nth expression
|
||||
tokens := strings.Split(expr, "|")
|
||||
if nth, err := splitNth(tokens[0]); err == nil {
|
||||
// Changed
|
||||
newNth = &nth
|
||||
} else {
|
||||
// The default
|
||||
newNth = &t.nth
|
||||
}
|
||||
// Cycle
|
||||
if len(tokens) > 1 {
|
||||
a.a = strings.Join(append(tokens[1:], tokens[0]), "|")
|
||||
}
|
||||
if !compareRanges(t.nthCurrent, *newNth) {
|
||||
changed = true
|
||||
t.nthCurrent = *newNth
|
||||
t.forceRerenderList()
|
||||
}
|
||||
})
|
||||
case actChangeQuery:
|
||||
t.input = []rune(a.a)
|
||||
t.cx = len(t.input)
|
||||
case actChangeHeader, actTransformHeader:
|
||||
header := a.a
|
||||
if a.t == actTransformHeader {
|
||||
header = t.captureLines(a.a)
|
||||
}
|
||||
if t.changeHeader(header) {
|
||||
if t.headerWindow != nil {
|
||||
// Need to resize header window
|
||||
case actChangeHeader, actTransformHeader, actAsyncTransformHeader:
|
||||
capture(false, func(header string) {
|
||||
if t.changeHeader(header) {
|
||||
if t.headerWindow != nil {
|
||||
// Need to resize header window
|
||||
req(reqFullRedraw)
|
||||
} else {
|
||||
req(reqHeader, reqList, reqPrompt, reqInfo)
|
||||
}
|
||||
} else {
|
||||
req(reqHeader)
|
||||
}
|
||||
})
|
||||
case actChangeFooter, actTransformFooter, actAsyncTransformFooter:
|
||||
capture(false, func(footer string) {
|
||||
if t.changeFooter(footer) {
|
||||
req(reqFullRedraw)
|
||||
} else {
|
||||
req(reqHeader, reqList, reqPrompt, reqInfo)
|
||||
req(reqFooter)
|
||||
}
|
||||
} else {
|
||||
req(reqHeader)
|
||||
}
|
||||
case actChangeFooter, actTransformFooter:
|
||||
footer := a.a
|
||||
if a.t == actTransformFooter {
|
||||
footer = t.captureLines(a.a)
|
||||
}
|
||||
if t.changeFooter(footer) {
|
||||
req(reqFullRedraw)
|
||||
} else {
|
||||
req(reqFooter)
|
||||
}
|
||||
case actChangeHeaderLabel, actTransformHeaderLabel:
|
||||
label := a.a
|
||||
if a.t == actTransformHeaderLabel {
|
||||
label = t.captureLine(a.a)
|
||||
}
|
||||
t.headerLabelOpts.label = label
|
||||
t.headerLabel, t.headerLabelLen = t.ansiLabelPrinter(label, &tui.ColHeaderLabel, false)
|
||||
req(reqRedrawHeaderLabel)
|
||||
case actChangeFooterLabel, actTransformFooterLabel:
|
||||
label := a.a
|
||||
if a.t == actTransformFooterLabel {
|
||||
label = t.captureLine(a.a)
|
||||
}
|
||||
t.footerLabelOpts.label = label
|
||||
t.footerLabel, t.footerLabelLen = t.ansiLabelPrinter(label, &tui.ColFooterLabel, false)
|
||||
req(reqRedrawFooterLabel)
|
||||
case actChangeInputLabel, actTransformInputLabel:
|
||||
label := a.a
|
||||
if a.t == actTransformInputLabel {
|
||||
label = t.captureLine(a.a)
|
||||
}
|
||||
t.inputLabelOpts.label = label
|
||||
if t.inputBorder != nil {
|
||||
t.inputLabel, t.inputLabelLen = t.ansiLabelPrinter(label, &tui.ColInputLabel, false)
|
||||
req(reqRedrawInputLabel)
|
||||
}
|
||||
case actChangeListLabel, actTransformListLabel:
|
||||
label := a.a
|
||||
if a.t == actTransformListLabel {
|
||||
label = t.captureLine(a.a)
|
||||
}
|
||||
t.listLabelOpts.label = label
|
||||
if t.wborder != nil {
|
||||
t.listLabel, t.listLabelLen = t.ansiLabelPrinter(label, &tui.ColListLabel, false)
|
||||
req(reqRedrawListLabel)
|
||||
}
|
||||
case actChangeBorderLabel, actTransformBorderLabel:
|
||||
label := a.a
|
||||
if a.t == actTransformBorderLabel {
|
||||
label = t.captureLine(a.a)
|
||||
}
|
||||
t.borderLabelOpts.label = label
|
||||
if t.border != nil {
|
||||
t.borderLabel, t.borderLabelLen = t.ansiLabelPrinter(label, &tui.ColBorderLabel, false)
|
||||
req(reqRedrawBorderLabel)
|
||||
}
|
||||
case actChangePreviewLabel, actTransformPreviewLabel:
|
||||
label := a.a
|
||||
if a.t == actTransformPreviewLabel {
|
||||
label = t.captureLine(a.a)
|
||||
}
|
||||
t.previewLabelOpts.label = label
|
||||
if t.pborder != nil {
|
||||
t.previewLabel, t.previewLabelLen = t.ansiLabelPrinter(label, &tui.ColPreviewLabel, false)
|
||||
req(reqRedrawPreviewLabel)
|
||||
}
|
||||
case actTransform:
|
||||
body := t.captureLines(a.a)
|
||||
if actions, err := parseSingleActionList(strings.Trim(body, "\r\n")); err == nil {
|
||||
return doActions(actions)
|
||||
}
|
||||
})
|
||||
case actChangeHeaderLabel, actTransformHeaderLabel, actAsyncTransformHeaderLabel:
|
||||
capture(true, func(label string) {
|
||||
t.headerLabelOpts.label = label
|
||||
t.headerLabel, t.headerLabelLen = t.ansiLabelPrinter(label, &tui.ColHeaderLabel, false)
|
||||
req(reqRedrawHeaderLabel)
|
||||
})
|
||||
case actChangeFooterLabel, actTransformFooterLabel, actAsyncTransformFooterLabel:
|
||||
capture(true, func(label string) {
|
||||
t.footerLabelOpts.label = label
|
||||
t.footerLabel, t.footerLabelLen = t.ansiLabelPrinter(label, &tui.ColFooterLabel, false)
|
||||
req(reqRedrawFooterLabel)
|
||||
})
|
||||
case actChangeInputLabel, actTransformInputLabel, actAsyncTransformInputLabel:
|
||||
capture(true, func(label string) {
|
||||
t.inputLabelOpts.label = label
|
||||
if t.inputBorder != nil {
|
||||
t.inputLabel, t.inputLabelLen = t.ansiLabelPrinter(label, &tui.ColInputLabel, false)
|
||||
req(reqRedrawInputLabel)
|
||||
}
|
||||
})
|
||||
case actChangeListLabel, actTransformListLabel, actAsyncTransformListLabel:
|
||||
capture(true, func(label string) {
|
||||
t.listLabelOpts.label = label
|
||||
if t.wborder != nil {
|
||||
t.listLabel, t.listLabelLen = t.ansiLabelPrinter(label, &tui.ColListLabel, false)
|
||||
req(reqRedrawListLabel)
|
||||
}
|
||||
})
|
||||
case actChangeBorderLabel, actTransformBorderLabel, actAsyncTransformBorderLabel:
|
||||
capture(true, func(label string) {
|
||||
t.borderLabelOpts.label = label
|
||||
if t.border != nil {
|
||||
t.borderLabel, t.borderLabelLen = t.ansiLabelPrinter(label, &tui.ColBorderLabel, false)
|
||||
req(reqRedrawBorderLabel)
|
||||
}
|
||||
})
|
||||
case actChangePreviewLabel, actTransformPreviewLabel, actAsyncTransformPreviewLabel:
|
||||
capture(true, func(label string) {
|
||||
t.previewLabelOpts.label = label
|
||||
if t.pborder != nil {
|
||||
t.previewLabel, t.previewLabelLen = t.ansiLabelPrinter(label, &tui.ColPreviewLabel, false)
|
||||
req(reqRedrawPreviewLabel)
|
||||
}
|
||||
})
|
||||
case actTransform, actAsyncTransform:
|
||||
capture(false, func(body string) {
|
||||
if actions, err := parseSingleActionList(strings.Trim(body, "\r\n")); err == nil {
|
||||
// NOTE: We're not properly passing the return value here
|
||||
doActions(actions)
|
||||
}
|
||||
})
|
||||
case actChangePrompt:
|
||||
t.promptString = a.a
|
||||
t.prompt, t.promptLen = t.parsePrompt(a.a)
|
||||
@@ -5933,10 +6033,12 @@ func (t *Terminal) Loop() error {
|
||||
override := []rune(a.a)
|
||||
t.inputOverride = &override
|
||||
changed = true
|
||||
case actTransformSearch:
|
||||
override := []rune(t.captureLine(a.a))
|
||||
t.inputOverride = &override
|
||||
changed = true
|
||||
case actTransformSearch, actAsyncTransformSearch:
|
||||
capture(true, func(query string) {
|
||||
override := []rune(query)
|
||||
t.inputOverride = &override
|
||||
changed = true
|
||||
})
|
||||
case actEnableSearch:
|
||||
t.paused = false
|
||||
changed = true
|
||||
@@ -6276,30 +6378,26 @@ func (t *Terminal) Loop() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
case actChangeGhost, actTransformGhost:
|
||||
ghost := a.a
|
||||
if a.t == actTransformGhost {
|
||||
ghost = t.captureLine(a.a)
|
||||
}
|
||||
t.ghost = ghost
|
||||
if len(t.input) == 0 {
|
||||
req(reqPrompt)
|
||||
}
|
||||
case actChangePointer, actTransformPointer:
|
||||
pointer := a.a
|
||||
if a.t == actTransformPointer {
|
||||
pointer = t.captureLine(a.a)
|
||||
}
|
||||
length := uniseg.StringWidth(pointer)
|
||||
if length <= 2 {
|
||||
if length != t.pointerLen {
|
||||
t.forceRerenderList()
|
||||
case actChangeGhost, actTransformGhost, actAsyncTransformGhost:
|
||||
capture(true, func(ghost string) {
|
||||
t.ghost = ghost
|
||||
if len(t.input) == 0 {
|
||||
req(reqPrompt)
|
||||
}
|
||||
t.pointer = pointer
|
||||
t.pointerLen = length
|
||||
t.pointerEmpty = strings.Repeat(" ", t.pointerLen)
|
||||
req(reqList)
|
||||
}
|
||||
})
|
||||
case actChangePointer, actTransformPointer, actAsyncTransformPointer:
|
||||
capture(true, func(pointer string) {
|
||||
length := uniseg.StringWidth(pointer)
|
||||
if length <= 2 {
|
||||
if length != t.pointerLen {
|
||||
t.forceRerenderList()
|
||||
}
|
||||
t.pointer = pointer
|
||||
t.pointerLen = length
|
||||
t.pointerEmpty = strings.Repeat(" ", t.pointerLen)
|
||||
req(reqList)
|
||||
}
|
||||
})
|
||||
case actChangePreview:
|
||||
if t.previewOpts.command != a.a {
|
||||
t.previewOpts.command = a.a
|
||||
|
||||
Reference in New Issue
Block a user