dedentLines finds the shortest leading whitespace of every line in data and then removes it from every line. When tabWidth is positive, leading tabs are converted to spaces first.
(data string, tabWidth int)
| 113 | // dedentLines finds the shortest leading whitespace of every line in data and then removes it from every line. |
| 114 | // When tabWidth is positive, leading tabs are converted to spaces first. |
| 115 | func dedentLines(data string, tabWidth int) string { |
| 116 | if len(data) < 1 { |
| 117 | return "" |
| 118 | } |
| 119 | |
| 120 | var lines = make([]string, 0, 20) |
| 121 | var lowest, highest string |
| 122 | |
| 123 | for line := range strings.Lines(data) { |
| 124 | tabs := leadingTabs.FindString(line) |
| 125 | |
| 126 | // Replace any leading tabs with spaces when tabWidth is positive. |
| 127 | // NOTE: [strings.Repeat] has a fast-path for spaces. |
| 128 | if need := tabWidth * len(tabs); need > 0 { |
| 129 | line = strings.Repeat(" ", need) + line[len(tabs):] |
| 130 | } |
| 131 | |
| 132 | switch { |
| 133 | case lowest == "", highest == "": |
| 134 | lowest, highest = line, line |
| 135 | |
| 136 | case len(strings.TrimSpace(line)) > 0: |
| 137 | lowest = min(lowest, line) |
| 138 | highest = max(highest, line) |
| 139 | } |
| 140 | |
| 141 | lines = append(lines, line) |
| 142 | } |
| 143 | |
| 144 | // This treats one tab the same as one space. |
| 145 | // That is, it expects all lines to be indented using spaces or using tabs; not both. |
| 146 | if width := func() int { |
| 147 | for i := range lowest { |
| 148 | if (lowest[i] != ' ' && lowest[i] != '\t') || lowest[i] != highest[i] { |
| 149 | return i |
| 150 | } |
| 151 | } |
| 152 | return len(lowest) |
| 153 | }(); width > 0 { |
| 154 | for i := range lines { |
| 155 | if len(lines[i]) > width { |
| 156 | lines[i] = lines[i][width:] |
| 157 | } else { |
| 158 | lines[i] = "\n" |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | return strings.TrimSuffix(strings.Join(lines, ""), "\n") + "\n" |
| 164 | } |
no outgoing calls