<commit_before>package readline

import (
	"bytes"
	"context"
	"fmt"
	"strings"
	"unicode"

	"github.com/mattn/go-colorable"
	"github.com/zetamatta/go-box"
)

var Console = colorable.NewColorableStdout()

var hasCache = map[rune]struct{}{}

func PutRune(ch rune) {
	if _, ok := hasCache[ch]; ok {
		fmt.Fprintf(Console, "%c", ch)
	} else {
		pre_x, pre_y := box.GetLocate()
		fmt.Fprintf(Console, "%c", ch)
		post_x, post_y := box.GetLocate()
		if post_y == pre_y && post_x > pre_x {
			hasCache[ch] = struct{}{}
			SetCharWidth(ch, post_x-pre_x)
		}
	}
}

func PutRunes(ch rune, n int) {
	if n <= 0 {
		return
	}
	PutRune(ch)
	for i := 1; i < n; i++ {
		fmt.Fprintf(Console, "%c", ch)
	}
}

func Backspace(n int) {
	if n > 1 {
		fmt.Fprintf(Console, "\x1B[%dC", n)
	} else if n == 1 {
		fmt.Fprint(Console, "\b")
	}
}

func Eraseline() {
	fmt.Fprint(Console, "\x1B[0K")
}

const FORBIDDEN_WIDTH = 3 // = lastcolumn(1) and FULLWIDTHCHAR-SIZE(2)

type Buffer struct {
	*Editor
	Buffer         []rune
	Length         int
	Unicode        rune
	Keycode        uint16
	ShiftState     uint32
	ViewStart      int
	TermWidth      int // == TopColumn + ViewWidth + FORBIDDEN_WIDTH
	TopColumn      int // == width of Prompt
	HistoryPointer int
	Context        context.Context
}

func (this *Buffer) ViewWidth() int {
	return this.TermWidth - this.TopColumn - FORBIDDEN_WIDTH<commit_msg>fix ANSI escape code for cursor backward<commit_after>package readline

import (
	"bytes"
	"context"
	"fmt"
	"strings"
	"unicode"

	"github.com/mattn/go-colorable"
	"github.com/zetamatta/go-box"
)

var Console = colorable.NewColorableStdout()

var hasCache = map[rune]struct{}{}

func PutRune(ch rune) {
	if _, ok := hasCache[ch]; ok {
		fmt.Fprintf(Console, "%c", ch)
	} else {
		pre_x, pre_y := box.GetLocate()
		fmt.Fprintf(Console, "%c", ch)
		post_x, post_y := box.GetLocate()
		if post_y == pre_y && post_x > pre_x {
			hasCache[ch] = struct{}{}
			SetCharWidth(ch, post_x-pre_x)
		}
	}
}

func PutRunes(ch rune, n int) {
	if n <= 0 {
		return
	}
	PutRune(ch)
	for i := 1; i < n; i++ {
		fmt.Fprintf(Console, "%c", ch)
	}
}

func Backspace(n int) {
	if n > 1 {
		fmt.Fprintf(Console, "\x1B[%dD", n)
	} else if n == 1 {
		fmt.Fprint(Console, "\b")
	}
}

func Eraseline() {
	fmt.Fprint(Console, "\x1B[0K")
}

const FORBIDDEN_WIDTH = 3 // = lastcolumn(1) and FULLWIDTHCHAR-SIZE(2)

type Buffer struct {
	*Editor
	Buffer         []rune
	Length         int
	Unicode        rune
	Keycode        uint16
	ShiftState     uint32
	ViewStart      int
	TermWidth      int // == TopColumn + ViewWidth + FORBIDDEN_WIDTH
	TopColumn      int // == width of Prompt
	HistoryPointer int
	Context        context.Context
}

func (this *Buffer) ViewWidth() int {
	return this.TermWidth - this.TopColumn - FORBIDDEN_WIDTH
{'fraction_non_alphanumeric': 0.1446563512054696, 'fraction_numerical': 0.010075566750629723, 'mean_word_length': 3.0822320117474304, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6915625', 'n_tokens_mistral': 1176, 'n_tokens_neox': 1125, 'n_words': 261}