@@ -10,6 +10,7 @@ import (
"os"
"path/filepath"
"strconv"
+ "strings"
tea "github.com/charmbracelet/bubbletea/v2"
"github.com/charmbracelet/colorprofile"
@@ -21,6 +22,7 @@ import (
"github.com/charmbracelet/crush/internal/version"
"github.com/charmbracelet/fang"
"github.com/charmbracelet/lipgloss/v2"
+ uv "github.com/charmbracelet/ultraviolet"
"github.com/charmbracelet/x/exp/charmtone"
"github.com/charmbracelet/x/term"
"github.com/spf13/cobra"
@@ -81,8 +83,13 @@ crush -y
event.AppInitialized()
// Set up the TUI.
+ var env uv.Environ = os.Environ()
+ ui := tui.New(app)
+ ui.QueryVersion = shouldQueryTerminalVersion(env)
+
program := tea.NewProgram(
- tui.New(app),
+ ui,
+ tea.WithEnvironment(env),
tea.WithContext(cmd.Context()),
tea.WithFilter(tui.MouseEventFilter)) // Filter mouse events based on focus state
@@ -250,3 +257,17 @@ func createDotCrushDir(dir string) error {
return nil
}
+
+func shouldQueryTerminalVersion(env uv.Environ) bool {
+ termType := env.Getenv("TERM")
+ termProg, okTermProg := env.LookupEnv("TERM_PROGRAM")
+ _, okSSHTTY := env.LookupEnv("SSH_TTY")
+ return (!okTermProg && !okSSHTTY) ||
+ (!strings.Contains(termProg, "Apple") && !okSSHTTY) ||
+ // Terminals that do support XTVERSION.
+ strings.Contains(termType, "ghostty") ||
+ strings.Contains(termType, "wezterm") ||
+ strings.Contains(termType, "alacritty") ||
+ strings.Contains(termType, "kitty") ||
+ strings.Contains(termType, "rio")
+}
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"math/rand"
+ "slices"
"strings"
"time"
@@ -72,6 +73,14 @@ type appModel struct {
// Chat Page Specific
selectedSessionID string // The ID of the currently selected session
+
+ // sendProgressBar instructs the TUI to send progress bar updates to the
+ // terminal.
+ sendProgressBar bool
+
+ // QueryVersion instructs the TUI to query for the terminal version when it
+ // starts.
+ QueryVersion bool
}
// Init initializes the application model and returns initial commands.
@@ -88,6 +97,9 @@ func (a appModel) Init() tea.Cmd {
cmd = a.status.Init()
cmds = append(cmds, cmd)
+ if a.QueryVersion {
+ cmds = append(cmds, tea.RequestTerminalVersion)
+ }
return tea.Batch(cmds...)
}
@@ -99,6 +111,18 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
a.isConfigured = config.HasInitialDataConfig()
switch msg := msg.(type) {
+ case tea.EnvMsg:
+ // Is this Windows Terminal?
+ if !a.sendProgressBar {
+ a.sendProgressBar = slices.Contains(msg, "WT_SESSION")
+ }
+ case tea.TerminalVersionMsg:
+ termVersion := strings.ToLower(string(msg))
+ // Only enable progress bar for the following terminals.
+ if !a.sendProgressBar {
+ a.sendProgressBar = strings.Contains(termVersion, "ghostty")
+ }
+ return a, nil
case tea.KeyboardEnhancementsMsg:
for id, page := range a.pages {
m, pageCmd := page.Update(msg)
@@ -555,7 +579,7 @@ func (a *appModel) View() tea.View {
view.MouseMode = tea.MouseModeCellMotion
view.AltScreen = true
- if a.app != nil && a.app.AgentCoordinator != nil && a.app.AgentCoordinator.IsBusy() {
+ if a.sendProgressBar && a.app != nil && a.app.AgentCoordinator != nil && a.app.AgentCoordinator.IsBusy() {
// HACK: use a random percentage to prevent ghostty from hiding it
// after a timeout.
view.ProgressBar = tea.NewProgressBar(tea.ProgressBarIndeterminate, rand.Intn(100))
@@ -564,7 +588,7 @@ func (a *appModel) View() tea.View {
}
// New creates and initializes a new TUI application model.
-func New(app *app.App) tea.Model {
+func New(app *app.App) *appModel {
chatPage := chat.New(app)
keyMap := DefaultKeyMap()
keyMap.pageBindings = chatPage.Bindings()