-
Notifications
You must be signed in to change notification settings - Fork 29
/
gow_misc.go
139 lines (117 loc) · 3.3 KB
/
gow_misc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package main
import (
"io"
"os"
"path/filepath"
"regexp"
"strings"
"syscall"
"github.com/mitranim/gg"
)
const (
// These names reflect standard naming and meaning.
// Reference: https://en.wikipedia.org/wiki/Ascii.
// See our re-interpretation below.
ASCII_END_OF_TEXT = 3 // ^C
ASCII_BACKSPACE = 8 // ^H
ASCII_FILE_SEPARATOR = 28 // ^\
ASCII_DEVICE_CONTROL_2 = 18 // ^R
ASCII_DEVICE_CONTROL_4 = 20 // ^T
ASCII_UNIT_SEPARATOR = 31 // ^- or ^?
ASCII_DELETE = 127 // ^H on MacOS
// These names reflect our re-interpretation of standard codes.
CODE_INTERRUPT = ASCII_END_OF_TEXT
CODE_QUIT = ASCII_FILE_SEPARATOR
CODE_RESTART = ASCII_DEVICE_CONTROL_2
CODE_STOP = ASCII_DEVICE_CONTROL_4
CODE_PRINT_COMMAND = ASCII_UNIT_SEPARATOR
CODE_PRINT_HELP = ASCII_BACKSPACE
CODE_PRINT_HELP_MACOS = ASCII_DELETE
)
const HOTKEY_HELP = `Control codes / hotkeys:
3 ^C Kill subprocess with SIGINT. Repeat within 1s to kill gow.
18 ^R Kill subprocess with SIGTERM, restart.
20 ^T Kill subprocess with SIGTERM. Repeat within 1s to kill gow.
28 ^\ Kill subprocess with SIGQUIT. Repeat within 1s to kill gow.
31 ^- or ^? Print currently running command.
8 ^H Print this help.
127 ^H (MacOS) Print this help.`
var (
FD_TERM = syscall.Stdin
KILL_SIGS = []syscall.Signal{syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM}
KILL_SIGS_OS = gg.Map(KILL_SIGS, toOsSignal[syscall.Signal])
KILL_SIG_SET = gg.SetOf(KILL_SIGS...)
RE_WORD = regexp.MustCompile(`^\w+$`)
PATH_SEP = string([]rune{os.PathSeparator})
REP_SINGLE_MULTI = strings.NewReplacer(
`\r\n`, gg.Newline,
`\r`, gg.Newline,
`\n`, gg.Newline,
)
)
/*
Making `.main` private reduces the chance of accidental cyclic walking by
reflection tools such as pretty printers.
*/
type Mained struct{ main *Main }
func (self *Mained) Init(val *Main) { self.main = val }
func (self *Mained) Main() *Main { return self.main }
/*
Implemented by `notify.EventInfo`.
Path must be an absolute filesystem path.
*/
type FsEvent interface{ Path() string }
// Implemented by `WatchNotify`.
type Watcher interface {
Init(*Main)
Deinit()
Run()
}
func commaSplit(val string) []string {
if len(val) <= 0 {
return nil
}
return strings.Split(val, `,`)
}
func cleanExtension(val string) string {
ext := filepath.Ext(val)
if len(ext) > 0 && ext[0] == '.' {
return ext[1:]
}
return ext
}
func validateExtension(val string) {
if !RE_WORD.MatchString(val) {
panic(gg.Errf(`invalid extension %q`, val))
}
}
func toAbsPath(val string) string {
if !filepath.IsAbs(val) {
val = filepath.Join(cwd, val)
}
return filepath.Clean(val)
}
func toDirPath(val string) string {
if val == `` || strings.HasSuffix(val, PATH_SEP) {
return val
}
return val + PATH_SEP
}
func toAbsDirPath(val string) string { return toDirPath(toAbsPath(val)) }
func toOsSignal[A os.Signal](src A) os.Signal { return src }
func recLog() {
val := recover()
if val != nil {
log.Println(val)
}
}
func withNewline[A ~string](val A) A {
if gg.HasNewlineSuffix(val) {
return val
}
return val + A(gg.Newline)
}
func writeByte[A io.Writer](tar A, char byte) (int, error) {
buf := [1]byte{char}
return tar.Write(gg.NoEscUnsafe(&buf)[:])
}