Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: real cursor in textinput #727

Merged
merged 3 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,6 @@ func New(items []Item, delegate ItemDelegate, width, height int) Model {

filterInput := textinput.New()
filterInput.Prompt = "Filter: "
filterInput.PromptStyle = styles.FilterPrompt
filterInput.Cursor.Style = styles.FilterCursor
filterInput.CharLimit = 64
filterInput.Focus()

Expand Down
19 changes: 10 additions & 9 deletions list/style.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package list

import (
"github.com/charmbracelet/bubbles/v2/textinput"
"github.com/charmbracelet/lipgloss/v2"
)

Expand All @@ -12,11 +13,10 @@ const (
// Styles contains style definitions for this list component. By default, these
// values are generated by DefaultStyles.
type Styles struct {
TitleBar lipgloss.Style
Title lipgloss.Style
Spinner lipgloss.Style
FilterPrompt lipgloss.Style
FilterCursor lipgloss.Style
TitleBar lipgloss.Style
Title lipgloss.Style
Spinner lipgloss.Style
Filter textinput.Styles

// Default styling for matched characters in a filter. This can be
// overridden by delegates.
Expand Down Expand Up @@ -57,11 +57,12 @@ func DefaultStyles(isDark bool) (s Styles) {
s.Spinner = lipgloss.NewStyle().
Foreground(lightDark(lipgloss.Color("#8E8E8E"), lipgloss.Color("#747373")))

s.FilterPrompt = lipgloss.NewStyle().
prompt := lipgloss.NewStyle().
Foreground(lightDark(lipgloss.Color("#04B575"), lipgloss.Color("#ECFD65")))

s.FilterCursor = lipgloss.NewStyle().
Foreground(lightDark(lipgloss.Color("#EE6FF8"), lipgloss.Color("#EE6FF8")))
s.Filter = textinput.DefaultStyles(isDark)
s.Filter.Cursor.Color = lightDark(lipgloss.Color("#EE6FF8"), lipgloss.Color("#EE6FF8"))
s.Filter.Blurred.Prompt = prompt
s.Filter.Focused.Prompt = prompt

s.DefaultFilterCharacterMatch = lipgloss.NewStyle().Underline(true)

Expand Down
11 changes: 3 additions & 8 deletions textarea/textarea.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,15 +413,10 @@

// By default, the blink speed of the cursor is set to a default
// internally.
if m.Styles.Cursor.BlinkSpeed > 0 {
m.virtualCursor.BlinkSpeed = m.Styles.Cursor.BlinkSpeed
}

if !m.VirtualCursor {
m.virtualCursor.SetMode(cursor.CursorHide)
return
}
if m.Styles.Cursor.Blink {
if m.Styles.Cursor.BlinkSpeed > 0 {
m.virtualCursor.BlinkSpeed = m.Styles.Cursor.BlinkSpeed
}
m.virtualCursor.SetMode(cursor.CursorBlink)
return
}
Expand Down Expand Up @@ -948,8 +943,8 @@
// repositionView repositions the view of the viewport based on the defined
// scrolling behavior.
func (m *Model) repositionView() {
min := m.viewport.YOffset

Check failure on line 946 in textarea/textarea.go

View workflow job for this annotation

GitHub Actions / lint / lint (ubuntu-latest)

redefines-builtin-id: redefinition of the built-in function min (revive)

Check failure on line 946 in textarea/textarea.go

View workflow job for this annotation

GitHub Actions / lint / lint (ubuntu-latest)

redefines-builtin-id: redefinition of the built-in function min (revive)
max := min + m.viewport.Height() - 1

Check failure on line 947 in textarea/textarea.go

View workflow job for this annotation

GitHub Actions / lint / lint (ubuntu-latest)

redefines-builtin-id: redefinition of the built-in function max (revive)

Check failure on line 947 in textarea/textarea.go

View workflow job for this annotation

GitHub Actions / lint / lint (ubuntu-latest)

redefines-builtin-id: redefinition of the built-in function max (revive)

if row := m.cursorLineNumber(); row < min {
m.viewport.LineUp(min - row)
Expand Down Expand Up @@ -1224,7 +1219,7 @@
displayLine++

var ln string
if m.ShowLineNumbers { //nolint:nestif

Check failure on line 1222 in textarea/textarea.go

View workflow job for this annotation

GitHub Actions / lint / lint-soft (ubuntu-latest)

directive `//nolint:nestif` is unused for linter "nestif" (nolintlint)

Check failure on line 1222 in textarea/textarea.go

View workflow job for this annotation

GitHub Actions / lint / lint-soft (ubuntu-latest)

directive `//nolint:nestif` is unused for linter "nestif" (nolintlint)

Check failure on line 1222 in textarea/textarea.go

View workflow job for this annotation

GitHub Actions / lint / lint-soft (macos-latest)

directive `//nolint:nestif` is unused for linter "nestif" (nolintlint)

Check failure on line 1222 in textarea/textarea.go

View workflow job for this annotation

GitHub Actions / lint / lint-soft (windows-latest)

directive `//nolint:nestif` is unused for linter "nestif" (nolintlint)

Check failure on line 1222 in textarea/textarea.go

View workflow job for this annotation

GitHub Actions / lint / lint-soft (macos-latest)

directive `//nolint:nestif` is unused for linter "nestif" (nolintlint)

Check failure on line 1222 in textarea/textarea.go

View workflow job for this annotation

GitHub Actions / lint / lint-soft (windows-latest)

directive `//nolint:nestif` is unused for linter "nestif" (nolintlint)
if wl == 0 { // normal line
isCursorLine := m.row == l
s.WriteString(m.lineNumberView(l+1, isCursorLine))
Expand Down
96 changes: 96 additions & 0 deletions textinput/styles.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package textinput

import (
"image/color"
"time"

tea "github.com/charmbracelet/bubbletea/v2"
"github.com/charmbracelet/lipgloss/v2"
)

// DefaultStyles returns the default styles for focused and blurred states for
// the textarea.
func DefaultStyles(isDark bool) Styles {
lightDark := lipgloss.LightDark(isDark)

var s Styles
s.Focused = StyleState{
Placeholder: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
Suggestion: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
Prompt: lipgloss.NewStyle().Foreground(lipgloss.Color("7")),
Text: lipgloss.NewStyle(),
}
s.Blurred = StyleState{
Placeholder: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
Suggestion: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
Prompt: lipgloss.NewStyle().Foreground(lipgloss.Color("7")),
Text: lipgloss.NewStyle().Foreground(lightDark(lipgloss.Color("245"), lipgloss.Color("7"))),
}
s.Cursor = CursorStyle{
Color: lipgloss.Color("7"),
Shape: tea.CursorBlock,
Blink: true,
}
return s
}

// DefaultLightStyles returns the default styles for a light background.
func DefaultLightStyles() Styles {
return DefaultStyles(false)
}

// DefaultDarkStyles returns the default styles for a dark background.
func DefaultDarkStyles() Styles {
return DefaultStyles(true)
}

// Styles are the styles for the textarea, separated into focused and blurred
// states. The appropriate styles will be chosen based on the focus state of
// the textarea.
type Styles struct {
Focused StyleState
Blurred StyleState
Cursor CursorStyle
}

// StyleState that will be applied to the text area.
//
// StyleState can be applied to focused and unfocused states to change the styles
// depending on the focus state.
//
// For an introduction to styling with Lip Gloss see:
// https://github.com/charmbracelet/lipgloss
type StyleState struct {
Text lipgloss.Style
Placeholder lipgloss.Style
Suggestion lipgloss.Style
Prompt lipgloss.Style
}

// CursorStyle is the style for real and virtual cursors.
type CursorStyle struct {
// Style styles the cursor block.
//
// For real cursors, the foreground color set here will be used as the
// cursor color.
Color color.Color

// Shape is the cursor shape. The following shapes are available:
//
// - tea.CursorBlock
// - tea.CursorUnderline
// - tea.CursorBar
//
// This is only used for real cursors.
Shape tea.CursorShape

// CursorBlink determines whether or not the cursor should blink.
Blink bool

// BlinkSpeed is the speed at which the virtual cursor blinks. This has no
// effect on real cursors as well as no effect if the cursor is set not to
// [CursorBlink].
//
// By default, the blink speed is set to about 500ms.
BlinkSpeed time.Duration
}
Loading
Loading