2025-10-15 10:12:44 +03:00

212 lines
3.9 KiB
Go

package printer
import (
"strings"
"unicode/utf8"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/stringutil"
)
var _ EmitTextWriter = &textWriter{}
type textWriter struct {
newLine string
builder strings.Builder
lastWritten string
indent int
lineStart bool
lineCount int
linePos int
hasTrailingCommentState bool
}
func (w *textWriter) Clear() {
*w = textWriter{newLine: w.newLine, lineStart: true}
}
func (w *textWriter) DecreaseIndent() {
w.indent--
}
func (w *textWriter) GetColumn() int {
if w.lineStart {
return w.indent * 4
}
return w.builder.Len() - w.linePos
}
func (w *textWriter) GetIndent() int {
return w.indent
}
func (w *textWriter) GetLine() int {
return w.lineCount
}
func (w *textWriter) String() string {
return w.builder.String()
}
func (w *textWriter) GetTextPos() int {
return w.builder.Len()
}
func (w textWriter) HasTrailingComment() bool {
return w.hasTrailingCommentState
}
func (w *textWriter) HasTrailingWhitespace() bool {
if w.builder.Len() == 0 {
return false
}
ch, _ := utf8.DecodeLastRuneInString(w.lastWritten)
if ch == utf8.RuneError {
return false
}
return stringutil.IsWhiteSpaceLike(ch)
}
func (w *textWriter) IncreaseIndent() {
w.indent++
}
func (w *textWriter) IsAtStartOfLine() bool {
return w.lineStart
}
func (w *textWriter) RawWrite(s string) {
if s != "" {
w.builder.WriteString(s)
w.lastWritten = s
w.updateLineCountAndPosFor(s)
w.hasTrailingCommentState = false
}
}
func (w *textWriter) updateLineCountAndPosFor(s string) {
var count int
var lastLineStart core.TextPos
for lineStart := range core.ComputeECMALineStartsSeq(s) {
count++
lastLineStart = lineStart
}
if count > 1 {
w.lineCount += count - 1
curLen := w.builder.Len()
w.linePos = curLen - len(s) + int(lastLineStart)
w.lineStart = (w.linePos - curLen) == 0
return
}
w.lineStart = false
}
func getIndentString(indent int) string {
switch indent {
case 0:
return ""
case 1:
return " "
default:
// TODO: This is cached in tsc - should it be cached here?
return strings.Repeat(" ", indent)
}
}
func (w *textWriter) writeText(s string) {
if s != "" {
if w.lineStart {
w.builder.WriteString(getIndentString(w.indent))
w.lineStart = false
}
w.builder.WriteString(s)
w.lastWritten = s
w.updateLineCountAndPosFor(s)
}
}
func (w *textWriter) Write(s string) {
if s != "" {
w.hasTrailingCommentState = false
}
w.writeText(s)
}
func (w *textWriter) WriteComment(text string) {
if text != "" {
w.hasTrailingCommentState = true
}
w.writeText(text)
}
func (w *textWriter) WriteKeyword(text string) {
w.Write(text)
}
func (w *textWriter) writeLineRaw() {
w.builder.WriteString(w.newLine)
w.lastWritten = w.newLine
w.lineCount++
w.linePos = w.builder.Len()
w.lineStart = true
w.hasTrailingCommentState = false
}
func (w *textWriter) WriteLine() {
if !w.lineStart {
w.writeLineRaw()
}
}
func (w *textWriter) WriteLineForce(force bool) {
if !w.lineStart || force {
w.writeLineRaw()
}
}
func (w *textWriter) WriteLiteral(s string) {
w.Write(s)
}
func (w *textWriter) WriteOperator(text string) {
w.Write(text)
}
func (w *textWriter) WriteParameter(text string) {
w.Write(text)
}
func (w *textWriter) WriteProperty(text string) {
w.Write(text)
}
func (w *textWriter) WritePunctuation(text string) {
w.Write(text)
}
func (w *textWriter) WriteSpace(text string) {
w.Write(text)
}
func (w *textWriter) WriteStringLiteral(text string) {
w.Write(text)
}
func (w *textWriter) WriteSymbol(text string, symbol *ast.Symbol) {
w.Write(text)
}
func (w *textWriter) WriteTrailingSemicolon(text string) {
w.Write(text)
}
func NewTextWriter(newLine string) EmitTextWriter {
var w textWriter
w.newLine = newLine
w.Clear()
return &w
}