mirror of
https://github.com/junegunn/fzf.git
synced 2026-08-15 20:28:04 +08:00
Implement asynchronous transform actions
Close #4418 Example: fzf --bind 'focus:&transform-header(sleep 2; date; echo {})'
This commit is contained in:
+55
-39
@@ -113,48 +113,64 @@ func _() {
|
|||||||
_ = x[actTransformPrompt-102]
|
_ = x[actTransformPrompt-102]
|
||||||
_ = x[actTransformQuery-103]
|
_ = x[actTransformQuery-103]
|
||||||
_ = x[actTransformSearch-104]
|
_ = x[actTransformSearch-104]
|
||||||
_ = x[actSearch-105]
|
_ = x[actAsyncTransform-105]
|
||||||
_ = x[actPreview-106]
|
_ = x[actAsyncTransformBorderLabel-106]
|
||||||
_ = x[actPreviewTop-107]
|
_ = x[actAsyncTransformGhost-107]
|
||||||
_ = x[actPreviewBottom-108]
|
_ = x[actAsyncTransformHeader-108]
|
||||||
_ = x[actPreviewUp-109]
|
_ = x[actAsyncTransformFooter-109]
|
||||||
_ = x[actPreviewDown-110]
|
_ = x[actAsyncTransformHeaderLabel-110]
|
||||||
_ = x[actPreviewPageUp-111]
|
_ = x[actAsyncTransformFooterLabel-111]
|
||||||
_ = x[actPreviewPageDown-112]
|
_ = x[actAsyncTransformInputLabel-112]
|
||||||
_ = x[actPreviewHalfPageUp-113]
|
_ = x[actAsyncTransformListLabel-113]
|
||||||
_ = x[actPreviewHalfPageDown-114]
|
_ = x[actAsyncTransformNth-114]
|
||||||
_ = x[actPrevHistory-115]
|
_ = x[actAsyncTransformPointer-115]
|
||||||
_ = x[actPrevSelected-116]
|
_ = x[actAsyncTransformPreviewLabel-116]
|
||||||
_ = x[actPrint-117]
|
_ = x[actAsyncTransformPrompt-117]
|
||||||
_ = x[actPut-118]
|
_ = x[actAsyncTransformQuery-118]
|
||||||
_ = x[actNextHistory-119]
|
_ = x[actAsyncTransformSearch-119]
|
||||||
_ = x[actNextSelected-120]
|
_ = x[actSearch-120]
|
||||||
_ = x[actExecute-121]
|
_ = x[actPreview-121]
|
||||||
_ = x[actExecuteSilent-122]
|
_ = x[actPreviewTop-122]
|
||||||
_ = x[actExecuteMulti-123]
|
_ = x[actPreviewBottom-123]
|
||||||
_ = x[actSigStop-124]
|
_ = x[actPreviewUp-124]
|
||||||
_ = x[actFirst-125]
|
_ = x[actPreviewDown-125]
|
||||||
_ = x[actLast-126]
|
_ = x[actPreviewPageUp-126]
|
||||||
_ = x[actReload-127]
|
_ = x[actPreviewPageDown-127]
|
||||||
_ = x[actReloadSync-128]
|
_ = x[actPreviewHalfPageUp-128]
|
||||||
_ = x[actDisableSearch-129]
|
_ = x[actPreviewHalfPageDown-129]
|
||||||
_ = x[actEnableSearch-130]
|
_ = x[actPrevHistory-130]
|
||||||
_ = x[actSelect-131]
|
_ = x[actPrevSelected-131]
|
||||||
_ = x[actDeselect-132]
|
_ = x[actPrint-132]
|
||||||
_ = x[actUnbind-133]
|
_ = x[actPut-133]
|
||||||
_ = x[actRebind-134]
|
_ = x[actNextHistory-134]
|
||||||
_ = x[actToggleBind-135]
|
_ = x[actNextSelected-135]
|
||||||
_ = x[actBecome-136]
|
_ = x[actExecute-136]
|
||||||
_ = x[actShowHeader-137]
|
_ = x[actExecuteSilent-137]
|
||||||
_ = x[actHideHeader-138]
|
_ = x[actExecuteMulti-138]
|
||||||
_ = x[actBell-139]
|
_ = x[actSigStop-139]
|
||||||
_ = x[actExclude-140]
|
_ = x[actFirst-140]
|
||||||
_ = x[actExcludeMulti-141]
|
_ = 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 {
|
func (i actionType) String() string {
|
||||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||||
|
|||||||
+32
-2
@@ -1435,9 +1435,9 @@ const (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
executeRegexp = regexp.MustCompile(
|
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("[,:]+")
|
splitRegexp = regexp.MustCompile("[,:]+")
|
||||||
actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+")
|
actionNameRegexp = regexp.MustCompile("(?i)^&?[a-z-]+")
|
||||||
}
|
}
|
||||||
|
|
||||||
func maskActionContents(action string) string {
|
func maskActionContents(action string) string {
|
||||||
@@ -1892,6 +1892,36 @@ func isExecuteAction(str string) actionType {
|
|||||||
return actTransformQuery
|
return actTransformQuery
|
||||||
case "transform-search":
|
case "transform-search":
|
||||||
return actTransformSearch
|
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":
|
case "search":
|
||||||
return actSearch
|
return actSearch
|
||||||
}
|
}
|
||||||
|
|||||||
+253
-155
@@ -388,6 +388,7 @@ type Terminal struct {
|
|||||||
startChan chan fitpad
|
startChan chan fitpad
|
||||||
killChan chan bool
|
killChan chan bool
|
||||||
serverInputChan chan []*action
|
serverInputChan chan []*action
|
||||||
|
callbackChan chan func()
|
||||||
keyChan chan tui.Event
|
keyChan chan tui.Event
|
||||||
eventChan chan tui.Event
|
eventChan chan tui.Event
|
||||||
slab *util.Slab
|
slab *util.Slab
|
||||||
@@ -489,6 +490,7 @@ const (
|
|||||||
actBackwardDeleteCharEof
|
actBackwardDeleteCharEof
|
||||||
actBackwardWord
|
actBackwardWord
|
||||||
actCancel
|
actCancel
|
||||||
|
|
||||||
actChangeBorderLabel
|
actChangeBorderLabel
|
||||||
actChangeGhost
|
actChangeGhost
|
||||||
actChangeHeader
|
actChangeHeader
|
||||||
@@ -505,6 +507,7 @@ const (
|
|||||||
actChangePreviewWindow
|
actChangePreviewWindow
|
||||||
actChangePrompt
|
actChangePrompt
|
||||||
actChangeQuery
|
actChangeQuery
|
||||||
|
|
||||||
actClearScreen
|
actClearScreen
|
||||||
actClearQuery
|
actClearQuery
|
||||||
actClearSelection
|
actClearSelection
|
||||||
@@ -561,6 +564,7 @@ const (
|
|||||||
actHidePreview
|
actHidePreview
|
||||||
actTogglePreview
|
actTogglePreview
|
||||||
actTogglePreviewWrap
|
actTogglePreviewWrap
|
||||||
|
|
||||||
actTransform
|
actTransform
|
||||||
actTransformBorderLabel
|
actTransformBorderLabel
|
||||||
actTransformGhost
|
actTransformGhost
|
||||||
@@ -576,6 +580,23 @@ const (
|
|||||||
actTransformPrompt
|
actTransformPrompt
|
||||||
actTransformQuery
|
actTransformQuery
|
||||||
actTransformSearch
|
actTransformSearch
|
||||||
|
|
||||||
|
actAsyncTransform
|
||||||
|
actAsyncTransformBorderLabel
|
||||||
|
actAsyncTransformGhost
|
||||||
|
actAsyncTransformHeader
|
||||||
|
actAsyncTransformFooter
|
||||||
|
actAsyncTransformHeaderLabel
|
||||||
|
actAsyncTransformFooterLabel
|
||||||
|
actAsyncTransformInputLabel
|
||||||
|
actAsyncTransformListLabel
|
||||||
|
actAsyncTransformNth
|
||||||
|
actAsyncTransformPointer
|
||||||
|
actAsyncTransformPreviewLabel
|
||||||
|
actAsyncTransformPrompt
|
||||||
|
actAsyncTransformQuery
|
||||||
|
actAsyncTransformSearch
|
||||||
|
|
||||||
actSearch
|
actSearch
|
||||||
actPreview
|
actPreview
|
||||||
actPreviewTop
|
actPreviewTop
|
||||||
@@ -613,6 +634,7 @@ const (
|
|||||||
actBell
|
actBell
|
||||||
actExclude
|
actExclude
|
||||||
actExcludeMulti
|
actExcludeMulti
|
||||||
|
actAsync
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a actionType) Name() string {
|
func (a actionType) Name() string {
|
||||||
@@ -623,10 +645,34 @@ func processExecution(action actionType) bool {
|
|||||||
switch action {
|
switch action {
|
||||||
case actTransform,
|
case actTransform,
|
||||||
actTransformBorderLabel,
|
actTransformBorderLabel,
|
||||||
|
actTransformGhost,
|
||||||
actTransformHeader,
|
actTransformHeader,
|
||||||
|
actTransformFooter,
|
||||||
|
actTransformHeaderLabel,
|
||||||
|
actTransformFooterLabel,
|
||||||
|
actTransformInputLabel,
|
||||||
|
actTransformListLabel,
|
||||||
|
actTransformNth,
|
||||||
|
actTransformPointer,
|
||||||
actTransformPreviewLabel,
|
actTransformPreviewLabel,
|
||||||
actTransformPrompt,
|
actTransformPrompt,
|
||||||
actTransformQuery,
|
actTransformQuery,
|
||||||
|
actTransformSearch,
|
||||||
|
actAsyncTransform,
|
||||||
|
actAsyncTransformBorderLabel,
|
||||||
|
actAsyncTransformGhost,
|
||||||
|
actAsyncTransformHeader,
|
||||||
|
actAsyncTransformFooter,
|
||||||
|
actAsyncTransformHeaderLabel,
|
||||||
|
actAsyncTransformFooterLabel,
|
||||||
|
actAsyncTransformInputLabel,
|
||||||
|
actAsyncTransformListLabel,
|
||||||
|
actAsyncTransformNth,
|
||||||
|
actAsyncTransformPointer,
|
||||||
|
actAsyncTransformPreviewLabel,
|
||||||
|
actAsyncTransformPrompt,
|
||||||
|
actAsyncTransformQuery,
|
||||||
|
actAsyncTransformSearch,
|
||||||
actPreview,
|
actPreview,
|
||||||
actChangePreview,
|
actChangePreview,
|
||||||
actRefreshPreview,
|
actRefreshPreview,
|
||||||
@@ -773,7 +819,7 @@ func mayTriggerPreview(opts *Options) bool {
|
|||||||
for _, actions := range opts.Keymap {
|
for _, actions := range opts.Keymap {
|
||||||
for _, action := range actions {
|
for _, action := range actions {
|
||||||
switch action.t {
|
switch action.t {
|
||||||
case actPreview, actChangePreview, actTransform:
|
case actPreview, actChangePreview, actTransform, actAsyncTransform:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -987,6 +1033,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
|||||||
startChan: make(chan fitpad, 1),
|
startChan: make(chan fitpad, 1),
|
||||||
killChan: make(chan bool),
|
killChan: make(chan bool),
|
||||||
serverInputChan: make(chan []*action, 100),
|
serverInputChan: make(chan []*action, 100),
|
||||||
|
callbackChan: make(chan func(), 100),
|
||||||
keyChan: make(chan tui.Event),
|
keyChan: make(chan tui.Event),
|
||||||
eventChan: make(chan tui.Event, 6), // start | (load + result + zero|one) | (focus) | (resize)
|
eventChan: make(chan tui.Event, 6), // start | (load + result + zero|one) | (focus) | (resize)
|
||||||
tui: renderer,
|
tui: renderer,
|
||||||
@@ -4291,6 +4338,32 @@ func (t *Terminal) captureLines(template string) string {
|
|||||||
return t.executeCommand(template, false, true, true, false, "")
|
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 {
|
func (t *Terminal) executeCommand(template string, forcePlus bool, background bool, capture bool, firstLineOnly bool, info string) string {
|
||||||
line := ""
|
line := ""
|
||||||
valid, list := t.buildPlusList(template, forcePlus)
|
valid, list := t.buildPlusList(template, forcePlus)
|
||||||
@@ -5089,11 +5162,27 @@ func (t *Terminal) Loop() error {
|
|||||||
barrier <- true
|
barrier <- true
|
||||||
needBarrier = false
|
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++ {
|
for loopIndex := int64(0); looping; loopIndex++ {
|
||||||
var newCommand *commandSpec
|
var newCommand *commandSpec
|
||||||
var newNth *[]Range
|
|
||||||
var reloadSync bool
|
var reloadSync bool
|
||||||
changed := false
|
events = []util.EventType{}
|
||||||
|
changed = false
|
||||||
|
newNth = nil
|
||||||
beof := false
|
beof := false
|
||||||
queryChanged := false
|
queryChanged := false
|
||||||
denylist := []int32{}
|
denylist := []int32{}
|
||||||
@@ -5110,6 +5199,7 @@ func (t *Terminal) Loop() error {
|
|||||||
|
|
||||||
var event tui.Event
|
var event tui.Event
|
||||||
actions := []*action{}
|
actions := []*action{}
|
||||||
|
callbacks := []func(){}
|
||||||
select {
|
select {
|
||||||
case event = <-t.keyChan:
|
case event = <-t.keyChan:
|
||||||
needBarrier = true
|
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()
|
t.mutex.Lock()
|
||||||
@@ -5155,15 +5259,6 @@ func (t *Terminal) Loop() error {
|
|||||||
previousInput := t.input
|
previousInput := t.input
|
||||||
previousCx := t.cx
|
previousCx := t.cx
|
||||||
t.lastKey = event.KeyName()
|
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) {
|
updatePreviewWindow := func(forcePreview bool) {
|
||||||
t.resizeWindows(forcePreview, false)
|
t.resizeWindows(forcePreview, false)
|
||||||
req(reqPrompt, reqList, reqInfo, reqHeader, reqFooter)
|
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
|
// 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'
|
// e.g. fzf --no-input --bind 'space:show-input+change-query(foo)+hide-input'
|
||||||
currentInput := t.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:
|
Action:
|
||||||
switch a.t {
|
switch a.t {
|
||||||
case actIgnore, actStart, actClick:
|
case actIgnore, actStart, actClick:
|
||||||
|
case actAsync:
|
||||||
|
for _, callback := range callbacks {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
case actBecome:
|
case actBecome:
|
||||||
valid, list := t.buildPlusList(a.a, false)
|
valid, list := t.buildPlusList(a.a, false)
|
||||||
if valid {
|
if valid {
|
||||||
@@ -5333,15 +5448,17 @@ func (t *Terminal) Loop() error {
|
|||||||
t.previewed.version = 0
|
t.previewed.version = 0
|
||||||
req(reqPreviewRefresh)
|
req(reqPreviewRefresh)
|
||||||
}
|
}
|
||||||
case actTransformPrompt:
|
case actTransformPrompt, actAsyncTransformPrompt:
|
||||||
prompt := t.captureLine(a.a)
|
capture(true, func(prompt string) {
|
||||||
t.promptString = prompt
|
t.promptString = prompt
|
||||||
t.prompt, t.promptLen = t.parsePrompt(prompt)
|
t.prompt, t.promptLen = t.parsePrompt(prompt)
|
||||||
req(reqPrompt)
|
req(reqPrompt)
|
||||||
case actTransformQuery:
|
})
|
||||||
query := t.captureLine(a.a)
|
case actTransformQuery, actAsyncTransformQuery:
|
||||||
t.input = []rune(query)
|
capture(true, func(query string) {
|
||||||
t.cx = len(t.input)
|
t.input = []rune(query)
|
||||||
|
t.cx = len(t.input)
|
||||||
|
})
|
||||||
case actToggleSort:
|
case actToggleSort:
|
||||||
t.sort = !t.sort
|
t.sort = !t.sort
|
||||||
changed = true
|
changed = true
|
||||||
@@ -5399,119 +5516,102 @@ func (t *Terminal) Loop() error {
|
|||||||
}
|
}
|
||||||
t.multi = multi
|
t.multi = multi
|
||||||
req(reqList, reqInfo)
|
req(reqList, reqInfo)
|
||||||
case actChangeNth, actTransformNth:
|
case actChangeNth, actTransformNth, actAsyncTransformNth:
|
||||||
expr := a.a
|
capture(true, func(expr string) {
|
||||||
if a.t == actTransformNth {
|
// Split nth expression
|
||||||
expr = t.captureLine(a.a)
|
tokens := strings.Split(expr, "|")
|
||||||
}
|
if nth, err := splitNth(tokens[0]); err == nil {
|
||||||
|
// Changed
|
||||||
// Split nth expression
|
newNth = &nth
|
||||||
tokens := strings.Split(expr, "|")
|
} else {
|
||||||
if nth, err := splitNth(tokens[0]); err == nil {
|
// The default
|
||||||
// Changed
|
newNth = &t.nth
|
||||||
newNth = &nth
|
}
|
||||||
} else {
|
// Cycle
|
||||||
// The default
|
if len(tokens) > 1 {
|
||||||
newNth = &t.nth
|
a.a = strings.Join(append(tokens[1:], tokens[0]), "|")
|
||||||
}
|
}
|
||||||
// Cycle
|
if !compareRanges(t.nthCurrent, *newNth) {
|
||||||
if len(tokens) > 1 {
|
changed = true
|
||||||
a.a = strings.Join(append(tokens[1:], tokens[0]), "|")
|
t.nthCurrent = *newNth
|
||||||
}
|
t.forceRerenderList()
|
||||||
if !compareRanges(t.nthCurrent, *newNth) {
|
}
|
||||||
changed = true
|
})
|
||||||
t.nthCurrent = *newNth
|
|
||||||
t.forceRerenderList()
|
|
||||||
}
|
|
||||||
case actChangeQuery:
|
case actChangeQuery:
|
||||||
t.input = []rune(a.a)
|
t.input = []rune(a.a)
|
||||||
t.cx = len(t.input)
|
t.cx = len(t.input)
|
||||||
case actChangeHeader, actTransformHeader:
|
case actChangeHeader, actTransformHeader, actAsyncTransformHeader:
|
||||||
header := a.a
|
capture(false, func(header string) {
|
||||||
if a.t == actTransformHeader {
|
if t.changeHeader(header) {
|
||||||
header = t.captureLines(a.a)
|
if t.headerWindow != nil {
|
||||||
}
|
// Need to resize header window
|
||||||
if t.changeHeader(header) {
|
req(reqFullRedraw)
|
||||||
if t.headerWindow != nil {
|
} else {
|
||||||
// Need to resize header window
|
req(reqHeader, reqList, reqPrompt, reqInfo)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
req(reqHeader)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
case actChangeFooter, actTransformFooter, actAsyncTransformFooter:
|
||||||
|
capture(false, func(footer string) {
|
||||||
|
if t.changeFooter(footer) {
|
||||||
req(reqFullRedraw)
|
req(reqFullRedraw)
|
||||||
} else {
|
} else {
|
||||||
req(reqHeader, reqList, reqPrompt, reqInfo)
|
req(reqFooter)
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
req(reqHeader)
|
case actChangeHeaderLabel, actTransformHeaderLabel, actAsyncTransformHeaderLabel:
|
||||||
}
|
capture(true, func(label string) {
|
||||||
case actChangeFooter, actTransformFooter:
|
t.headerLabelOpts.label = label
|
||||||
footer := a.a
|
t.headerLabel, t.headerLabelLen = t.ansiLabelPrinter(label, &tui.ColHeaderLabel, false)
|
||||||
if a.t == actTransformFooter {
|
req(reqRedrawHeaderLabel)
|
||||||
footer = t.captureLines(a.a)
|
})
|
||||||
}
|
case actChangeFooterLabel, actTransformFooterLabel, actAsyncTransformFooterLabel:
|
||||||
if t.changeFooter(footer) {
|
capture(true, func(label string) {
|
||||||
req(reqFullRedraw)
|
t.footerLabelOpts.label = label
|
||||||
} else {
|
t.footerLabel, t.footerLabelLen = t.ansiLabelPrinter(label, &tui.ColFooterLabel, false)
|
||||||
req(reqFooter)
|
req(reqRedrawFooterLabel)
|
||||||
}
|
})
|
||||||
case actChangeHeaderLabel, actTransformHeaderLabel:
|
case actChangeInputLabel, actTransformInputLabel, actAsyncTransformInputLabel:
|
||||||
label := a.a
|
capture(true, func(label string) {
|
||||||
if a.t == actTransformHeaderLabel {
|
t.inputLabelOpts.label = label
|
||||||
label = t.captureLine(a.a)
|
if t.inputBorder != nil {
|
||||||
}
|
t.inputLabel, t.inputLabelLen = t.ansiLabelPrinter(label, &tui.ColInputLabel, false)
|
||||||
t.headerLabelOpts.label = label
|
req(reqRedrawInputLabel)
|
||||||
t.headerLabel, t.headerLabelLen = t.ansiLabelPrinter(label, &tui.ColHeaderLabel, false)
|
}
|
||||||
req(reqRedrawHeaderLabel)
|
})
|
||||||
case actChangeFooterLabel, actTransformFooterLabel:
|
case actChangeListLabel, actTransformListLabel, actAsyncTransformListLabel:
|
||||||
label := a.a
|
capture(true, func(label string) {
|
||||||
if a.t == actTransformFooterLabel {
|
t.listLabelOpts.label = label
|
||||||
label = t.captureLine(a.a)
|
if t.wborder != nil {
|
||||||
}
|
t.listLabel, t.listLabelLen = t.ansiLabelPrinter(label, &tui.ColListLabel, false)
|
||||||
t.footerLabelOpts.label = label
|
req(reqRedrawListLabel)
|
||||||
t.footerLabel, t.footerLabelLen = t.ansiLabelPrinter(label, &tui.ColFooterLabel, false)
|
}
|
||||||
req(reqRedrawFooterLabel)
|
})
|
||||||
case actChangeInputLabel, actTransformInputLabel:
|
case actChangeBorderLabel, actTransformBorderLabel, actAsyncTransformBorderLabel:
|
||||||
label := a.a
|
capture(true, func(label string) {
|
||||||
if a.t == actTransformInputLabel {
|
t.borderLabelOpts.label = label
|
||||||
label = t.captureLine(a.a)
|
if t.border != nil {
|
||||||
}
|
t.borderLabel, t.borderLabelLen = t.ansiLabelPrinter(label, &tui.ColBorderLabel, false)
|
||||||
t.inputLabelOpts.label = label
|
req(reqRedrawBorderLabel)
|
||||||
if t.inputBorder != nil {
|
}
|
||||||
t.inputLabel, t.inputLabelLen = t.ansiLabelPrinter(label, &tui.ColInputLabel, false)
|
})
|
||||||
req(reqRedrawInputLabel)
|
case actChangePreviewLabel, actTransformPreviewLabel, actAsyncTransformPreviewLabel:
|
||||||
}
|
capture(true, func(label string) {
|
||||||
case actChangeListLabel, actTransformListLabel:
|
t.previewLabelOpts.label = label
|
||||||
label := a.a
|
if t.pborder != nil {
|
||||||
if a.t == actTransformListLabel {
|
t.previewLabel, t.previewLabelLen = t.ansiLabelPrinter(label, &tui.ColPreviewLabel, false)
|
||||||
label = t.captureLine(a.a)
|
req(reqRedrawPreviewLabel)
|
||||||
}
|
}
|
||||||
t.listLabelOpts.label = label
|
})
|
||||||
if t.wborder != nil {
|
case actTransform, actAsyncTransform:
|
||||||
t.listLabel, t.listLabelLen = t.ansiLabelPrinter(label, &tui.ColListLabel, false)
|
capture(false, func(body string) {
|
||||||
req(reqRedrawListLabel)
|
if actions, err := parseSingleActionList(strings.Trim(body, "\r\n")); err == nil {
|
||||||
}
|
// NOTE: We're not properly passing the return value here
|
||||||
case actChangeBorderLabel, actTransformBorderLabel:
|
doActions(actions)
|
||||||
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 actChangePrompt:
|
case actChangePrompt:
|
||||||
t.promptString = a.a
|
t.promptString = a.a
|
||||||
t.prompt, t.promptLen = t.parsePrompt(a.a)
|
t.prompt, t.promptLen = t.parsePrompt(a.a)
|
||||||
@@ -5933,10 +6033,12 @@ func (t *Terminal) Loop() error {
|
|||||||
override := []rune(a.a)
|
override := []rune(a.a)
|
||||||
t.inputOverride = &override
|
t.inputOverride = &override
|
||||||
changed = true
|
changed = true
|
||||||
case actTransformSearch:
|
case actTransformSearch, actAsyncTransformSearch:
|
||||||
override := []rune(t.captureLine(a.a))
|
capture(true, func(query string) {
|
||||||
t.inputOverride = &override
|
override := []rune(query)
|
||||||
changed = true
|
t.inputOverride = &override
|
||||||
|
changed = true
|
||||||
|
})
|
||||||
case actEnableSearch:
|
case actEnableSearch:
|
||||||
t.paused = false
|
t.paused = false
|
||||||
changed = true
|
changed = true
|
||||||
@@ -6276,30 +6378,26 @@ func (t *Terminal) Loop() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case actChangeGhost, actTransformGhost:
|
case actChangeGhost, actTransformGhost, actAsyncTransformGhost:
|
||||||
ghost := a.a
|
capture(true, func(ghost string) {
|
||||||
if a.t == actTransformGhost {
|
t.ghost = ghost
|
||||||
ghost = t.captureLine(a.a)
|
if len(t.input) == 0 {
|
||||||
}
|
req(reqPrompt)
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
t.pointer = pointer
|
})
|
||||||
t.pointerLen = length
|
case actChangePointer, actTransformPointer, actAsyncTransformPointer:
|
||||||
t.pointerEmpty = strings.Repeat(" ", t.pointerLen)
|
capture(true, func(pointer string) {
|
||||||
req(reqList)
|
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:
|
case actChangePreview:
|
||||||
if t.previewOpts.command != a.a {
|
if t.previewOpts.command != a.a {
|
||||||
t.previewOpts.command = a.a
|
t.previewOpts.command = a.a
|
||||||
|
|||||||
Reference in New Issue
Block a user