func (m *TextInputModel) deleteAfterCursor() bool {
	m.value = m.value[:m.pos]
	return m.setCursor(len(m.value))
}
deleteAfterCursor deletes all text after the cursor. Returns whether or not
the cursor blink should be reset. If input is masked delete everything after
the cursor so as not to reveal word breaks in the masked input.
package tuiutil
import (
	"context"
	"strings"
	"sync"
	"time"
	"unicode"
	"github.com/atotto/clipboard"
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
	rw "github.com/mattn/go-runewidth"
)
const DefaultBlinkSpeed = time.Millisecond * 530
var (
	Ascii  bool
	lastID int
	idMtx  sync.Mutex
)
func nextID() int {
	idMtx.Lock()
	defer idMtx.Unlock()
	lastID++
	return lastID
}
type initialBlinkMsg struct{}
type blinkMsg struct {
	id  int
	tag int
}
type blinkCanceled struct{}
type pasteMsg string
type pasteErrMsg struct{ error }
type EchoMode int
const (
	EchoNormal EchoMode = iota
	EchoPassword
	EchoNone
)
type blinkCtx struct {
	ctx    context.Context
	cancel context.CancelFunc
}
type CursorMode int
const (
	CursorBlink CursorMode = iota
	CursorStatic
	CursorHide
)
func (c CursorMode) String() string {
	return [...]string{
		"blink",
		"static",
		"hidden",
	}[c]
}
type TextInputModel struct {
	Err error
	Prompt        string
	Placeholder   string
	BlinkSpeed    time.Duration
	EchoMode      EchoMode
	EchoCharacter rune
	PromptStyle      lipgloss.Style
	TextStyle        lipgloss.Style
	BackgroundStyle  lipgloss.Style
	PlaceholderStyle lipgloss.Style
	CursorStyle      lipgloss.Style
	CharLimit int
	Width int
	id int
	blinkTag int
	value []rune
	Focus bool
	blink bool
	pos int
	Offset      int
	OffsetRight int
	blinkCtx *blinkCtx
	cursorMode CursorMode
}
func NewModel() TextInputModel {
	m := TextInputModel{
		Prompt:           "> ",
		BlinkSpeed:       DefaultBlinkSpeed,
		EchoCharacter:    '*',
		CharLimit:        0,
		PlaceholderStyle: lipgloss.NewStyle(),
		id:         nextID(),
		value:      nil,
		Focus:      false,
		blink:      true,
		pos:        0,
		cursorMode: CursorBlink,
		blinkCtx: &blinkCtx{
			ctx: context.Background(),
		},
	}
	if !Ascii {
		m.PlaceholderStyle = m.PlaceholderStyle.Foreground(lipgloss.Color("240"))
	}
	return m
}
func (m *TextInputModel) SetValue(s string) {
	runes := []rune(s)
	if m.CharLimit > 0 && len(runes) > m.CharLimit {
		m.value = runes[:m.CharLimit]
	} else {
		m.value = runes
	}
	if m.pos == 0 || m.pos > len(m.value) {
		m.setCursor(len(m.value))
	}
	m.handleOverflow()
}
func (m TextInputModel) Value() string {
	return string(m.value)
}
func (m TextInputModel) Cursor() int {
	return m.pos
}
func (m *TextInputModel) SetCursor(pos int) {
	m.setCursor(pos)
}
func (m *TextInputModel) setCursor(pos int) bool {
	m.pos = Clamp(pos, 0, len(m.value))
	m.handleOverflow()
	m.blink = m.cursorMode == CursorHide
	return m.cursorMode == CursorBlink
}
func (m *TextInputModel) CursorStart() {
	m.cursorStart()
}
func (m *TextInputModel) cursorStart() bool {
	return m.setCursor(0)
}
func (m *TextInputModel) CursorEnd() {
	m.cursorEnd()
}
func (m TextInputModel) CursorMode() CursorMode {
	return m.cursorMode
}
func (m *TextInputModel) SetCursorMode(mode CursorMode) tea.Cmd {
	m.cursorMode = mode
	m.blink = m.cursorMode == CursorHide || !m.Focus
	if mode == CursorBlink {
		return Blink
	}
	return nil
}
func (m *TextInputModel) cursorEnd() bool {
	return m.setCursor(len(m.value))
}
func (m TextInputModel) Focused() bool {
	return m.Focus
}
func (m *TextInputModel) FocusCommand() tea.Cmd {
	m.Focus = true
	m.blink = m.cursorMode == CursorHide  
	if m.cursorMode == CursorBlink && m.Focus {
		return m.blinkCmd()
	}
	return nil
}
func (m *TextInputModel) Blur() {
	m.Focus = false
	m.blink = true
}
func (m *TextInputModel) Reset() bool {
	m.value = nil
	return m.setCursor(0)
}
func (m *TextInputModel) handlePaste(v string) bool {
	paste := []rune(v)
	var availSpace int
	if m.CharLimit > 0 {
		availSpace = m.CharLimit - len(m.value)
	}
	if m.CharLimit > 0 && availSpace <= 0 {
		return false
	}
	if m.CharLimit > 0 && availSpace < len(paste) {
		paste = paste[:len(paste)-availSpace]
	}
	head := m.value[:m.pos]
	tailSrc := m.value[m.pos:]
	tail := make([]rune, len(tailSrc))
	copy(tail, tailSrc)
	for _, r := range paste {
		head = append(head, r)
		m.pos++
		if m.CharLimit > 0 {
			availSpace--
			if availSpace <= 0 {
				break
			}
		}
	}
	m.value = append(head, tail...)
	return m.setCursor(m.pos)
}
func (m *TextInputModel) handleOverflow() {
	if m.Width <= 0 || rw.StringWidth(string(m.value)) <= m.Width {
		m.Offset = 0
		m.OffsetRight = len(m.value)
		return
	}
	m.OffsetRight = min(m.OffsetRight, len(m.value))
	if m.pos < m.Offset {
		m.Offset = m.pos
		w := 0
		i := 0
		runes := m.value[m.Offset:]
		for i < len(runes) && w <= m.Width {
			w += rw.RuneWidth(runes[i])
			if w <= m.Width+1 {
				i++
			}
		}
		m.OffsetRight = m.Offset + i
	} else if m.pos >= m.OffsetRight {
		m.OffsetRight = m.pos
		w := 0
		runes := m.value[:m.OffsetRight]
		i := len(runes) - 1
		for i > 0 && w < m.Width {
			w += rw.RuneWidth(runes[i])
			if w <= m.Width {
				i--
			}
		}
		m.Offset = m.OffsetRight - (len(runes) - 1 - i)
	}
}
func (m *TextInputModel) deleteBeforeCursor() bool {
	m.value = m.value[m.pos:]
	m.Offset = 0
	return m.setCursor(0)
}