250621.4 · 247d168af6fabcc322f54ad366f4fb45f781137b
Terminate running background transform on exit
Close #4422
reading declarations
@@ -9,6 +9,7 @@ import ( "math" "net" "os"+ "os/exec" "os/signal" "regexp" "sort"@@ -377,6 +378,7 @@ type Terminal struct { version int64 revision revision bgVersion int64+ runningCmds *util.ConcurrentSet[*exec.Cmd] reqBox *util.EventBox initialPreviewOpts previewOpts previewOpts previewOpts@@ -1030,6 +1032,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor proxyScript: opts.ProxyScript, merger: EmptyMerger(revision{}), selected: make(map[int32]selectedItem),+ runningCmds: util.NewConcurrentSet[*exec.Cmd](), reqBox: util.NewEventBox(), initialPreviewOpts: opts.Preview, previewOpts: opts.Preview,@@ -4377,6 +4380,7 @@ func (t *Terminal) captureAsync(a action, firstLineOnly bool, callback func(stri reader := bufio.NewReader(out) var output string if err := cmd.Start(); err == nil {+ t.runningCmds.Add(cmd) if firstLineOnly { output, _ = reader.ReadString('\n') output = strings.TrimRight(output, "\r\n")@@ -4385,6 +4389,7 @@ func (t *Terminal) captureAsync(a action, firstLineOnly bool, callback func(stri output = string(bytes) } cmd.Wait()+ t.runningCmds.Remove(cmd) } t.callbackChan <- versionedCallback{version, func() { callback(output) }} }@@ -5053,6 +5058,9 @@ func (t *Terminal) Loop() error { if code <= ExitNoMatch && t.history != nil { t.history.append(string(t.input)) }+ t.runningCmds.ForEach(func(cmd *exec.Cmd) {+ util.KillCommand(cmd)+ }) running = false t.mutex.Unlock() }
@@ -0,0 +1,39 @@+package util++import "sync"++// ConcurrentSet is a thread-safe set implementation.+type ConcurrentSet[T comparable] struct {+ lock sync.RWMutex+ items map[T]struct{}+}++// NewConcurrentSet creates a new ConcurrentSet.+func NewConcurrentSet[T comparable]() *ConcurrentSet[T] {+ return &ConcurrentSet[T]{+ items: make(map[T]struct{}),+ }+}++// Add adds an item to the set.+func (s *ConcurrentSet[T]) Add(item T) {+ s.lock.Lock()+ defer s.lock.Unlock()+ s.items[item] = struct{}{}+}++// Remove removes an item from the set.+func (s *ConcurrentSet[T]) Remove(item T) {+ s.lock.Lock()+ defer s.lock.Unlock()+ delete(s.items, item)+}++// ForEach iterates over each item in the set and applies the provided function.+func (s *ConcurrentSet[T]) ForEach(fn func(item T)) {+ s.lock.RLock()+ defer s.lock.RUnlock()+ for item := range s.items {+ fn(item)+ }+}