diff --git a/src/actiontype_string.go b/src/actiontype_string.go index bd141fde..d238dd49 100644 --- a/src/actiontype_string.go +++ b/src/actiontype_string.go @@ -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) { diff --git a/src/options.go b/src/options.go index 2fd6f821..153b9105 100644 --- a/src/options.go +++ b/src/options.go @@ -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 } diff --git a/src/terminal.go b/src/terminal.go index 898d34c7..b9296e0b 100644 --- a/src/terminal.go +++ b/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