1//go:build tools
2
3// For unexpand the 4 spaces that the typescript compiler outputs into tabs.
4// Not all unexpand commands implement the -t flag (openbsd).
5package main
6
7import (
8 "bufio"
9 "flag"
10 "fmt"
11 "io"
12 "log"
13 "os"
14)
15
16func xcheckf(err error, format string, args ...any) {
17 if err != nil {
18 log.Fatalf("%s: %s", fmt.Sprintf(format, args...), err)
19 }
20}
21
22func main() {
23 log.SetFlags(0)
24 var width int
25 flag.IntVar(&width, "t", 8, "tab width")
26 flag.Parse()
27 flag.Usage = func() {
28 log.Print("usage: unexpand [-t tabwidth] < input.spaces >output.tabs")
29 flag.PrintDefaults()
30 os.Exit(2)
31 }
32 if flag.NArg() != 0 {
33 flag.Usage()
34 }
35 if width <= 0 {
36 flag.Usage()
37 }
38
39 r := bufio.NewReader(os.Stdin)
40 w := bufio.NewWriter(os.Stdout)
41
42 nspace := 0
43 start := true
44
45 flush := func() {
46 for ; nspace > 0; nspace-- {
47 err := w.WriteByte(' ')
48 xcheckf(err, "write")
49 }
50 }
51 write := func(b byte) {
52 err := w.WriteByte(b)
53 xcheckf(err, "write")
54 }
55
56 for {
57 b, err := r.ReadByte()
58 if err == io.EOF {
59 break
60 }
61 xcheckf(err, "read")
62
63 if start && b == ' ' {
64 nspace++
65 if nspace == width {
66 write('\t')
67 nspace = 0
68 }
69 } else {
70 flush()
71 write(b)
72 start = b == '\n'
73 }
74 }
75 flush()
76 err := w.Flush()
77 xcheckf(err, "flush output")
78}
79