+type retabReader struct {
+ scanner *bufio.Scanner
+ buffer []byte
+ toSpaces bool
+ tabsize int
+}
+
+func newRetabReader(from io.Reader, enc encoding.Encoding, autoretab bool, toSpaces bool, tabsize int) io.Reader {
+ if !autoretab {
+ return from
+ }
+ r := new(retabReader)
+ r.scanner = bufio.NewScanner(bufio.NewReader(transform.NewReader(from, enc.NewDecoder())))
+ r.toSpaces = toSpaces
+ r.tabsize = tabsize
+ return r
+}
+
+func (r *retabReader) fillBuffer(required int) error {
+ for len(r.buffer) < required {
+ if r.scanner.Scan() {
+ line := retabLine([]byte(r.scanner.Text()), r.toSpaces, r.tabsize)
+
+ r.buffer = append(r.buffer, line...)
+ r.buffer = append(r.buffer, "\n"...)
+ } else {
+ if err := r.scanner.Err(); err != nil {
+ return err
+ } else {
+ return io.EOF
+ }
+ break
+ }
+ }
+
+ return nil
+}
+
+func (r *retabReader) Read(into []byte) (n int, err error) {
+ err = r.fillBuffer(len(into))
+ n = copy(into, r.buffer)
+
+ r.buffer = r.buffer[n:]
+ return
+}
+
+func retabLine(l []byte, toSpaces bool, tabsize int) []byte {
+ ws := util.GetLeadingWhitespace(l)
+ if len(ws) != 0 {
+ if toSpaces {
+ ws = bytes.ReplaceAll(ws, []byte{'\t'}, bytes.Repeat([]byte{' '}, tabsize))
+ } else {
+ ws = bytes.ReplaceAll(ws, bytes.Repeat([]byte{' '}, tabsize), []byte{'\t'})
+ }
+ }
+
+ l = bytes.TrimLeft(l, " \t")
+ return append(ws, l...)
+}
+