all repos

clerk @ 6fdb9097048e212574439fb0da84d0c94aa7e01b

missing tooling for ledger/hledger

clerk/format.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
formatter, 17 hours ago
1
package main
2
3
import (
4
	"bytes"
5
	"flag"
6
	"fmt"
7
	"io"
8
	"os"
9
10
	"olexsmir.xyz/clerk/journal"
11
	"olexsmir.xyz/clerk/journal/printer"
12
)
13
14
func runFormat(args []string) {
15
	fs := flag.NewFlagSet("format", flag.ExitOnError)
16
	write := fs.Bool("w", false, "Write result back to file instead of stdout")
17
	diff := fs.Bool("d", false, "Display diffs instead of rewriting files")
18
	check := fs.Bool("check", false, "Exit code 0 if already formatted, 1 otherwise")
19
	fs.Usage = func() {
20
		fmt.Fprintf(os.Stderr, "Usage: clerk format [flags] [path ...]\n")
21
		fs.PrintDefaults()
22
	}
23
	fs.Parse(args)
24
25
	paths := fs.Args()
26
27
	// Read from stdin if no paths given
28
	if len(paths) == 0 {
29
		src, err := io.ReadAll(os.Stdin)
30
		if err != nil {
31
			fmt.Fprintf(os.Stderr, "error reading stdin: %v\n", err)
32
			os.Exit(1)
33
		}
34
35
		pf, err := journal.NewLoader().LoadBytes("stdin", src)
36
		if err != nil {
37
			fmt.Fprintf(os.Stderr, "parse error: %v\n", err)
38
			os.Exit(1)
39
		}
40
41
		var buf bytes.Buffer
42
		if err := printer.Fprint(&buf, pf.Ast); err != nil {
43
			fmt.Fprintf(os.Stderr, "format error: %v\n", err)
44
			os.Exit(1)
45
		}
46
47
		if *check {
48
			if bytes.Equal(src, buf.Bytes()) {
49
				os.Exit(0)
50
			}
51
			os.Exit(1)
52
		}
53
		os.Stdout.Write(buf.Bytes())
54
		return
55
	}
56
57
	// Process each file
58
	exitCode := 0
59
	for _, path := range paths {
60
		info, err := os.Stat(path)
61
		if err != nil {
62
			fmt.Fprintf(os.Stderr, "error: %s: %v\n", path, err)
63
			exitCode = 1
64
			continue
65
		}
66
		if info.IsDir() {
67
			fmt.Fprintf(os.Stderr, "error: %s: can only format files, not directories\n", path)
68
			exitCode = 1
69
			continue
70
		}
71
72
		src, err := os.ReadFile(path)
73
		if err != nil {
74
			fmt.Fprintf(os.Stderr, "error: %s: %v\n", path, err)
75
			exitCode = 1
76
			continue
77
		}
78
79
		pf, err := journal.NewLoader().LoadBytes(path, src)
80
		if err != nil {
81
			fmt.Fprintf(os.Stderr, "error: %s: %v\n", path, err)
82
			exitCode = 1
83
			continue
84
		}
85
86
		var buf bytes.Buffer
87
		if err := printer.Fprint(&buf, pf.Ast); err != nil {
88
			fmt.Fprintf(os.Stderr, "error: %s: %v\n", path, err)
89
			exitCode = 1
90
			continue
91
		}
92
93
		formatted := buf.Bytes()
94
95
		if *check {
96
			if !bytes.Equal(src, formatted) {
97
				fmt.Fprintf(os.Stderr, "%s: not formatted\n", path)
98
				exitCode = 1
99
			}
100
			continue
101
		}
102
103
		if *diff {
104
			diffLines(path, src, formatted)
105
			continue
106
		}
107
108
		if *write {
109
			if err := os.WriteFile(path, formatted, 0o644); err != nil {
110
				fmt.Fprintf(os.Stderr, "error: %s: %v\n", path, err)
111
				exitCode = 1
112
			}
113
		} else {
114
			os.Stdout.Write(formatted)
115
		}
116
	}
117
118
	os.Exit(exitCode)
119
}
120
121
func diffLines(path string, src, formatted []byte) {
122
	// simple diff display
123
	if bytes.Equal(src, formatted) {
124
		return
125
	}
126
	fmt.Fprintf(os.Stderr, "--- %s\n+++ %s\n", path, path)
127
	// TODO: proper line-by-line diff
128
}