github.com/tilt-dev/wat@v0.0.2-0.20180626175338-9349b638e250/cli/wat/utils.go (about) 1 package wat 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "os" 8 "time" 9 10 "github.com/mattn/go-isatty" 11 "github.com/pkg/term" 12 "github.com/windmilleng/wat/utils/slices" 13 ) 14 15 const AsciiLineFeed = 10 16 const AsciiEnter = 13 17 const AsciiEsc = 27 18 19 func TermBold(s string) string { 20 return fmt.Sprintf("\033[1m%s\033[0m", s) 21 } 22 23 func MustJson(obj interface{}) string { 24 b, err := json.Marshal(obj) 25 if err != nil { 26 panic(fmt.Sprintf("unexpected err %T: %+v, failed to jsonify: %v", obj, obj, err)) 27 } 28 return string(b) 29 } 30 31 // waitOnInterruptChar returns when: 32 // 1) the user types one of the interrupt chars, or 33 // 2) the context times out/cancels 34 // whichever comes first 35 func waitOnInterruptChar(ctx context.Context, interrupts []rune) error { 36 if !isatty.IsTerminal(os.Stdout.Fd()) { 37 return fmt.Errorf("No terminal available") 38 } 39 40 t, err := term.Open("/dev/tty", term.CBreakMode, term.ReadTimeout(200*time.Millisecond)) 41 if err != nil { 42 return nil 43 } 44 45 tearDown := createCleanup(func() { 46 t.Restore() 47 t.Close() 48 }) 49 defer tearDown() 50 51 // Keep polling until there is data on the terminal 52 for true { 53 if ctx.Err() != nil { 54 return ctx.Err() 55 } 56 57 // We set a read timeout on the open file descriptor, so this will block until 58 // we get data or there's a timeout. 59 bytes := make([]byte, 1) 60 n, _ := t.Read(bytes) 61 if n == 0 { 62 // We timed out! Try again on the next loop. 63 continue 64 } 65 66 r := rune(bytes[0]) 67 if containsRune(interrupts, r) { 68 return nil 69 } 70 } 71 72 return nil 73 } 74 75 // dedupeAgainst returns elements of array a not in array b (i.e. the difference: A - B) 76 func dedupeAgainst(a, b []string) (res []string) { 77 for _, elem := range a { 78 if !slices.Contains(b, elem) { 79 res = append(res, elem) 80 } 81 } 82 return res 83 } 84 85 func containsRune(runes []rune, v rune) bool { 86 for _, r := range runes { 87 if v == r { 88 return true 89 } 90 } 91 return false 92 }