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