Skip to content

Commit

Permalink
Ensure that textinputs can only receive their own blink messages
Browse files Browse the repository at this point in the history
  • Loading branch information
meowgorithm committed Jun 2, 2021
1 parent 10962af commit d06aa4a
Showing 1 changed file with 69 additions and 8 deletions.
77 changes: 69 additions & 8 deletions textinput/textinput.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package textinput
import (
"context"
"strings"
"sync"
"time"
"unicode"

Expand All @@ -14,11 +15,35 @@ import (

const defaultBlinkSpeed = time.Millisecond * 530

// blinkMsg and blinkCanceled are used to manage cursor blinking.
type blinkMsg struct{}
// Internal ID management for text inputs. Necessary for blink integrity when
// multiple text inputs are involved.
var (
lastID int
idMtx sync.Mutex
)

// Return the next ID we should use on the Model.
func nextID() int {
idMtx.Lock()
defer idMtx.Unlock()
lastID++
return lastID
}

// initialBlinkMsg initializes cursor blinking.
type initialBlinkMsg struct{}

// blinkMsg signals that the cursor should blink. It contains metadata that
// allows us to tell if the blink message is the one we're expecting.
type blinkMsg struct {
id int
tag int
}

// blinkCanceled is sent when a blink operation is canceled.
type blinkCanceled struct{}

// Messages for clipboard events.
// Internal messages for clipboard operations.
type pasteMsg string
type pasteErrMsg struct{ error }

Expand Down Expand Up @@ -96,6 +121,12 @@ type Model struct {
// viewport. If 0 or less this setting is ignored.
Width int

// The ID of this Model as it relates to other textinput Models.
id int

// The ID of the blink message we're expecting to receive.
blinkTag int

// Underlying text value.
value []rune

Expand Down Expand Up @@ -130,6 +161,7 @@ func NewModel() Model {
CharLimit: 0,
PlaceholderStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),

id: nextID(),
value: nil,
focus: false,
blink: true,
Expand Down Expand Up @@ -221,7 +253,7 @@ func (m *Model) SetCursorMode(mode CursorMode) tea.Cmd {
}

// cursorEnd moves the cursor to the end of the input field and returns whether
// or not
// the cursor should blink should reset.
func (m *Model) cursorEnd() bool {
return m.setCursor(len(m.value))
}
Expand Down Expand Up @@ -258,7 +290,7 @@ func (m *Model) Reset() bool {
}

// handle a clipboard paste event, if supported. Returns whether or not the
// cursor blink should be reset.
// cursor blink should reset.
func (m *Model) handlePaste(v string) bool {
paste := []rune(v)

Expand Down Expand Up @@ -599,7 +631,30 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
}
}

case initialBlinkMsg:
// We accept all initialBlinkMsgs genrated by the Blink command.

if m.cursorMode != CursorBlink || !m.focus {
return m, nil
}

cmd := m.blinkCmd()
return m, cmd

case blinkMsg:
// We're choosy about whether to accept blinkMsgs so that our cursor
// only exactly when it should.

// Is this model blinkable?
if m.cursorMode != CursorBlink || !m.focus {
return m, nil
}

// Were we expecting this blink message?
if msg.id != m.id || msg.tag != m.blinkTag {
return m, nil
}

var cmd tea.Cmd
if m.cursorMode == CursorBlink {
m.blink = !m.blink
Expand Down Expand Up @@ -690,27 +745,33 @@ func (m Model) cursorView(v string) string {
}

// blinkCmd is an internal command used to manage cursor blinking.
func (m Model) blinkCmd() tea.Cmd {
func (m *Model) blinkCmd() tea.Cmd {
if m.cursorMode != CursorBlink {
return nil
}

if m.blinkCtx != nil && m.blinkCtx.cancel != nil {
m.blinkCtx.cancel()
}

ctx, cancel := context.WithTimeout(m.blinkCtx.ctx, m.BlinkSpeed)
m.blinkCtx.cancel = cancel

m.blinkTag++

return func() tea.Msg {
defer cancel()
<-ctx.Done()
if ctx.Err() == context.DeadlineExceeded {
return blinkMsg{}
return blinkMsg{id: m.id, tag: m.blinkTag}
}
return blinkCanceled{}
}
}

// Blink is a command used to initialize cursor blinking.
func Blink() tea.Msg {
return blinkMsg{}
return initialBlinkMsg{}
}

// Paste is a command for pasting from the clipboard into the text input.
Expand Down

0 comments on commit d06aa4a

Please sign in to comment.