blob: c838d4f986faf68ee849ed2765b20b8af19c6c66 [file] [log] [blame]
Abhay Kumara61c5222025-11-10 07:32:50 +00001package termutil
2
3import (
4 "errors"
5 "os"
6 "os/signal"
7 "sync"
8)
9
10var echoLocked bool
11var echoLockMutex sync.Mutex
12var errLocked = errors.New("terminal locked")
13var autoTerminate = true
14
15// AutoTerminate enables or disables automatic terminate signal catching.
16// It's needed to restore the terminal state after the pool was used.
17// By default, it's enabled.
18func AutoTerminate(enable bool) {
19 echoLockMutex.Lock()
20 defer echoLockMutex.Unlock()
21 autoTerminate = enable
22}
23
24// RawModeOn switches terminal to raw mode
25func RawModeOn() (quit chan struct{}, err error) {
26 echoLockMutex.Lock()
27 defer echoLockMutex.Unlock()
28 if echoLocked {
29 err = errLocked
30 return
31 }
32 if err = lockEcho(); err != nil {
33 return
34 }
35 echoLocked = true
36 quit = make(chan struct{}, 1)
37 go catchTerminate(quit)
38 return
39}
40
41// RawModeOff restore previous terminal state
42func RawModeOff() (err error) {
43 echoLockMutex.Lock()
44 defer echoLockMutex.Unlock()
45 if !echoLocked {
46 return
47 }
48 if err = unlockEcho(); err != nil {
49 return
50 }
51 echoLocked = false
52 return
53}
54
55// listen exit signals and restore terminal state
56func catchTerminate(quit chan struct{}) {
57 sig := make(chan os.Signal, 1)
58 if autoTerminate {
59 signal.Notify(sig, unlockSignals...)
60 defer signal.Stop(sig)
61 }
62 select {
63 case <-quit:
64 RawModeOff()
65 case <-sig:
66 RawModeOff()
67 }
68}