// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later package lowmemjson import ( "git.lukeshu.com/go/lowmemjson/internal/jsonparse" ) type reEncodeIndent struct { out reEncoderModule // String to use to indent. // // Newlines are emitted *between* top-level values; a newline // is not emitted after the *last* top-level value. Indent string // String to put before indents. Prefix string // state lastNonSpace jsonparse.RuneType lastNonSpaceNonEOF jsonparse.RuneType curIndent int } var _ reEncoderModule = (*reEncodeIndent)(nil) func (enc *reEncodeIndent) PopWriteBarrier() { enc.lastNonSpace = enc.lastNonSpaceNonEOF enc.out.PopWriteBarrier() } func (enc *reEncodeIndent) HandleRune(c rune, t jsonparse.RuneType, escape BackslashEscapeMode, stackSize int) error { // emit newlines between top-level values if enc.lastNonSpace == jsonparse.RuneTypeEOF && t != jsonparse.RuneTypeSpace { if err := enc.out.HandleRune('\n', jsonparse.RuneTypeSpace, 0, 0); err != nil { return err } } // indent switch t { case jsonparse.RuneTypeSpace: // let us manage whitespace, don't pass it through return nil case jsonparse.RuneTypeObjectEnd, jsonparse.RuneTypeArrayEnd: enc.curIndent-- switch enc.lastNonSpace { case jsonparse.RuneTypeObjectBeg, jsonparse.RuneTypeArrayBeg: // collapse default: if err := enc.emitNlIndent(stackSize + 1); err != nil { return err } } default: switch enc.lastNonSpace { case jsonparse.RuneTypeObjectBeg, jsonparse.RuneTypeObjectComma, jsonparse.RuneTypeArrayBeg, jsonparse.RuneTypeArrayComma: if err := enc.emitNlIndent(stackSize); err != nil { return err } case jsonparse.RuneTypeObjectColon: if err := enc.out.HandleRune(' ', jsonparse.RuneTypeSpace, 0, stackSize); err != nil { return err } } switch t { case jsonparse.RuneTypeObjectBeg, jsonparse.RuneTypeArrayBeg: enc.curIndent++ } } if t != jsonparse.RuneTypeSpace { enc.lastNonSpace = t if t != jsonparse.RuneTypeEOF { enc.lastNonSpaceNonEOF = t } } return enc.out.HandleRune(c, t, escape, stackSize) } func (enc *reEncodeIndent) emitNlIndent(stackSize int) error { if err := enc.out.HandleRune('\n', jsonparse.RuneTypeSpace, 0, stackSize); err != nil { return err } for _, c := range enc.Prefix { if err := enc.out.HandleRune(c, jsonparse.RuneTypeSpace, 0, stackSize); err != nil { return err } } for i := 0; i < enc.curIndent; i++ { for _, c := range enc.Indent { if err := enc.out.HandleRune(c, jsonparse.RuneTypeSpace, 0, stackSize); err != nil { return err } } } return nil }