...
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 package heredoc
31
32 import (
33 "fmt"
34 "strings"
35 "unicode"
36 )
37
38 const maxInt = int(^uint(0) >> 1)
39
40
41 func Doc(raw string) string {
42 skipFirstLine := false
43 if len(raw) > 0 && raw[0] == '\n' {
44 raw = raw[1:]
45 } else {
46 skipFirstLine = true
47 }
48
49 lines := strings.Split(raw, "\n")
50
51 minIndentSize := getMinIndent(lines, skipFirstLine)
52 lines = removeIndentation(lines, minIndentSize, skipFirstLine)
53
54 return strings.Join(lines, "\n")
55 }
56
57
58 func getMinIndent(lines []string, skipFirstLine bool) int {
59 minIndentSize := maxInt
60
61 for i, line := range lines {
62 if i == 0 && skipFirstLine {
63 continue
64 }
65
66 indentSize := 0
67 for _, r := range []rune(line) {
68 if unicode.IsSpace(r) {
69 indentSize += 1
70 } else {
71 break
72 }
73 }
74
75 if len(line) == indentSize {
76 if i == len(lines)-1 && indentSize < minIndentSize {
77 lines[i] = ""
78 }
79 } else if indentSize < minIndentSize {
80 minIndentSize = indentSize
81 }
82 }
83 return minIndentSize
84 }
85
86
87
88 func removeIndentation(lines []string, n int, skipFirstLine bool) []string {
89 for i, line := range lines {
90 if i == 0 && skipFirstLine {
91 continue
92 }
93
94 if len(lines[i]) >= n {
95 lines[i] = line[n:]
96 }
97 }
98 return lines
99 }
100
101
102
103 func Docf(raw string, args ...interface{}) string {
104 return fmt.Sprintf(Doc(raw), args...)
105 }
106
View as plain text