-
Notifications
You must be signed in to change notification settings - Fork 845
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
(v2) Bubble Tea v2 #1118
Draft
aymanbagabas
wants to merge
330
commits into
main
Choose a base branch
from
v2-exp
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
(v2) Bubble Tea v2 #1118
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This adds the ability to use a custom renderer using a modified version of the existing `renderer` interface. This also keeps track of enabled capabilities and ensure they are turned off on program exit. It only turns off enabled capabilities rather. The new API looks like: ```go // Renderer is the interface for Bubble Tea renderers. type Renderer interface { // Close closes the renderer and flushes any remaining data. Close() error // Render renders a frame to the output. Render(string) error // SetOutput sets the output for the renderer. SetOutput(io.Writer) // Flush flushes the renderer's buffer to the output. Flush() error // InsertAbove inserts lines above the current frame. This only works in // inline mode. InsertAbove(string) error // Resize sets the size of the terminal. Resize(w int, h int) // Request a full re-render. Note that this will not trigger a render // immediately. Rather, this method causes the next render to be a full // Repaint. Because of this, it's safe to call this method multiple times // in succession. Repaint() // ClearScreen clear the terminal screen. This should always have the same // behavior as the "clear" command which is equivalent to `CSI 2 J` and // `CSI H`. ClearScreen() // SetMode sets a terminal mode on/off. The mode argument is an int // consisting of the mode identifier. // For example, to set alt-screen mode, you would call SetMode(1049, true). SetMode(mode int, on bool) // Mode returns whether the render has a mode enabled. // For example, to check if alt-screen mode is enabled, you would call // Mode(1049). Mode(mode int) bool } ``` --- This also introduces some performance gains by not writing unnecessary sequences on enable/disable terminal modes. For example, we always hide the cursor when the program runs, it doesn't make sense to write the sequence again when the model sends a `HideCursor` command, we already know it's hidden. Don't _always_ disable mouse if it wasn't enabled in the first place.
…#1099) Bumps [github.com/charmbracelet/x/ansi](https://github.com/charmbracelet/x) from 0.2.1 to 0.2.2. - [Release notes](https://github.com/charmbracelet/x/releases) - [Commits](charmbracelet/x@ansi/v0.2.1...ansi/v0.2.2) --- updated-dependencies: - dependency-name: github.com/charmbracelet/x/ansi dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Hack! This forces a bg/fg query on the default os.Stdout and os.Stdin before starting any bubbletea program. Otherwise, programs might hang before the query finishes. This is because at that point, the bubbletea already acquired the terminal os.Stdin and termenv cannot read from it. The termenv query timeout can be adjusted using `termenv.OSCTimeout`. Note that this will only work for the default IO i.e. os.Stdout and os.Stdin. docs: copyedits in Lip Gloss/Termenv workaround for clarity Co-authored-by: Christian Rocha <[email protected]>
* feat: add mode 2027 grapheme clustering stubs This adds the necessary stubs to make mode 2027 (grapheme clustering) work on Bubble Tea with renderers that support it. * fix: screen grapheme clustering tests
Use key and mouse interfaces to catch their respective types as an interface.
This replaces KeyMsg and MouseMsg with interfaces that catch their respective types. For example, both KeyPressMsg and KeyReleaseMsg implement KeyMsg. Same goes for MouseClickMsg, MouseReleaseMsg, etc, they all implement MouseMsg. This makes it possible to switch on the interface type to catch all events of the same input message type. New API: ```go // KeyMsg represents a key event. This can be either a key press or a key // release event. type KeyMsg interface { fmt.Stringer // Key returns the underlying key event. Key() Key } // Key represents a Key press or release event. It contains information about // the Key pressed, like the runes, the type of Key, and the modifiers pressed. // There are a couple general patterns you could use to check for key presses // or releases: // // // Switch on the string representation of the key (shorter) // switch msg := msg.(type) { // case KeyPressMsg: // switch msg.String() { // case "enter": // fmt.Println("you pressed enter!") // case "a": // fmt.Println("you pressed a!") // } // } // // // Switch on the key type (more foolproof) // switch msg := msg.(type) { // case KeyMsg: // // catch both KeyPressMsg and KeyReleaseMsg // switch key := msg.Key(); key.Code { // case KeyEnter: // fmt.Println("you pressed enter!") // default: // switch key.Text { // case "a": // fmt.Println("you pressed a!") // } // } // } // // Note that [Key.Text] will be empty for special keys like [KeyEnter], // [KeyTab], and for keys that don't represent printable characters like key // combos with modifier keys. In other words, [Key.Text] is populated only for // keys that represent printable characters shifted or unshifted (like 'a', // 'A', '1', '!', etc.). type Key struct { // Text contains the actual characters received. This usually the same as // [Key.Code]. When [Key.Text] is non-empty, it indicates that the key // pressed represents printable character(s). Text string // Mod represents modifier keys, like [ModCtrl], [ModAlt], and so on. Mod KeyMod // Code represents the key pressed. This is usually a special key like // [KeyTab], [KeyEnter], [KeyF1], or a printable character like 'a'. Code rune // ShiftedCode is the actual, shifted key pressed by the user. For example, // if the user presses shift+a, or caps lock is on, [Key.ShiftedCode] will // be 'A' and [Key.Code] will be 'a'. // // In the case of non-latin keyboards, like Arabic, [Key.ShiftedCode] is the // unshifted key on the keyboard. // // This is only available with the Kitty Keyboard Protocol or the Windows // Console API. ShiftedCode rune // BaseCode is the key pressed according to the standard PC-101 key layout. // On international keyboards, this is the key that would be pressed if the // keyboard was set to US PC-101 layout. // // For example, if the user presses 'q' on a French AZERTY keyboard, // [Key.BaseCode] will be 'q'. // // This is only available with the Kitty Keyboard Protocol or the Windows // Console API. BaseCode rune // IsRepeat indicates whether the key is being held down and sending events // repeatedly. // // This is only available with the Kitty Keyboard Protocol or the Windows // Console API. IsRepeat bool } // MouseMsg represents a mouse message. This is a generic mouse message that // can represent any kind of mouse event. type MouseMsg interface { fmt.Stringer // Mouse returns the underlying mouse event. Mouse() Mouse } // Mouse represents a Mouse message. Use [MouseMsg] to represent all mouse // messages. // // The X and Y coordinates are zero-based, with (0,0) being the upper left // corner of the terminal. // // // Catch all mouse events // switch msg := msg.(type) { // case MouseMsg: // m := msg.Mouse() // fmt.Println("Mouse event:", m.X, m.Y, m) // } // // // Only catch mouse click events // switch msg := msg.(type) { // case MouseClickMsg: // fmt.Println("Mouse click event:", msg.X, msg.Y, msg) // } type Mouse struct { X, Y int Button MouseButton Mod KeyMod } ``` TODO: update examples (in a separate PR)
This exports the following modes: - Kitty keyboard commands and options - Xterm modifyOtherKeys commands and options - Win32Input commands and options
Signed-off-by: Carlos Alexandro Becker <[email protected]>
Signed-off-by: Carlos Alexandro Becker <[email protected]>
This implements the new cursed ferocious renderer. This is based on the new `cellbuf.Screen` renderer. This renderer is more efficient and flexible than the previous renderer. The renderer controls the altscreen buffer and cursor visibility which means we don't need to do so in Bubble Tea. Instead, Bubble Tea can focus on the event loop and the application state. This also removes the experimental flags and changes the renderer interface to be more explicit about the methods that are available.
Signed-off-by: Carlos Alexandro Becker <[email protected]>
…sted and active enhancements (#1286) refactor: keyboard: expose type and track requested and active enhancements This change exposes the `KeyboardEnhancements` type and tracks requested and active enhancements in the `Program` struct. This change also renames the `KeyboardEnhancement` type to `KeyboardEnhancementOption` as well as`EnableKeyboardEnhancements` to `RequestKeyboardEnhancements`. Fixes: #1283
Send the environment variables used by the program to the program when it starts. This is done by sending an `EnvMsg` message to the program. Programs that need to access the environment variables can use this message type to get the values of the environment variables. This is useful when programs targeting remote sessions need to access environment variables that are set by the user or the shell.
…#1288) This adds a new message type, `RawMsg`, and a new command, `Raw`, that allows printing raw strings to the terminal without any intermediate processing.
This is ported from Textualize splash.py example.
* feat(examples): add space example to measure fps and performance This is a simple example that uses Lip Gloss and Bubble Tea to render a moving color gradient. * docs(example): add attribution to Orhun Parmaksız in space example * chore: remove fps stuff
* feat(examples): add doom-fire example * feat: add elapsed time to doom-fire example
This commit introduces a new `Frame` type that represents a single frame of the program's output. The `Frame` type contains the frame's content and cursor settings. The cursor settings include the cursor's position, style, blink, and visibility. It also removes the cursor commands from the `tea` package. The cursor commands are now part of the `Frame` type. The cursor commands were removed because they were not idiomatic and were not flexible enough to support additional cursor settings. Supersedes: #1293
This commit introduces a new `Frame` type that represents a single frame of the program's output. The `Frame` type contains the frame's content and cursor settings. The cursor settings include the cursor's position, style, blink, and visibility. It also removes the cursor commands from the `tea` package. The cursor commands are now part of the `Frame` type. The cursor commands were removed because they were not idiomatic and were not flexible enough to support additional cursor settings. API: ```go // Model contains the program's state as well as its core functions. type Model interface { // Init is the first function that will be called. It returns an optional // initial command. To not perform an initial command return nil. Init() (Model, Cmd) // Update is called when a message is received. Use it to inspect messages // and, in response, update the model and/or send a command. Update(Msg) (Model, Cmd) // View renders the program's UI, which is just a [fmt.Stringer]. The view // is rendered after every Update. // The main model can return a [Frame] to set the cursor position and // style. View() fmt.Stringer } // Cursor represents a cursor on the terminal screen. type Cursor struct { // Position is a [Position] that determines the cursor's position on the // screen relative to the top left corner of the frame. Position Position // Color is a [color.Color] that determines the cursor's color. Color color.Color // Shape is a [CursorShape] that determines the cursor's style. Shape CursorShape // Blink is a boolean that determines whether the cursor should blink. Blink bool } // NewCursor returns a new cursor with the default settings and the given // position. func NewCursor(x, y int) *Cursor { return &Cursor{ Position: Position{X: x, Y: y}, Color: nil, Shape: CursorBlock, Blink: true, } } // Frame represents a single frame of the program's output. type Frame struct { // Content contains the frame's content. This is the only required field. // It should be a string of text and ANSI escape codes. Content string // Cursor contains cursor settings for the frame. If nil, the cursor will // be hidden. Cursor *Cursor } // NewFrame creates a new frame with the given content. func NewFrame(content string) Frame { return Frame{Content: content} } // String implements the fmt.Stringer interface for [Frame]. func (f Frame) String() string { return f.Content } ``` Supersedes: #1293
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR will keep track of the changes upcoming in Bubble Tea v2
Init()
return the model