lazygit.go

  1// Package lazygit provides a dialog component for embedding lazygit in the TUI.
  2package lazygit
  3
  4import (
  5	"context"
  6	"fmt"
  7	"image/color"
  8	"os"
  9
 10	"github.com/charmbracelet/crush/internal/terminal"
 11	"github.com/charmbracelet/crush/internal/tui/components/dialogs"
 12	"github.com/charmbracelet/crush/internal/tui/components/dialogs/termdialog"
 13	"github.com/charmbracelet/crush/internal/tui/styles"
 14)
 15
 16// DialogID is the unique identifier for the lazygit dialog.
 17const DialogID dialogs.DialogID = "lazygit"
 18
 19// NewDialog creates a new lazygit dialog. The context controls the lifetime
 20// of the lazygit process - when cancelled, the process will be killed.
 21func NewDialog(ctx context.Context, workingDir string) *termdialog.Dialog {
 22	configFile := createThemedConfig()
 23
 24	cmd := terminal.PrepareCmd(
 25		ctx,
 26		"lazygit",
 27		nil,
 28		workingDir,
 29		[]string{"LG_CONFIG_FILE=" + configFile},
 30	)
 31
 32	return termdialog.New(termdialog.Config{
 33		ID:         DialogID,
 34		Title:      "Lazygit",
 35		LoadingMsg: "Starting lazygit...",
 36		Term:       terminal.New(terminal.Config{Context: ctx, Cmd: cmd}),
 37		OnClose: func() {
 38			if configFile != "" {
 39				_ = os.Remove(configFile)
 40			}
 41		},
 42	})
 43}
 44
 45// colorToHex converts a color.Color to a hex string.
 46func colorToHex(c color.Color) string {
 47	r, g, b, _ := c.RGBA()
 48	return fmt.Sprintf("#%02x%02x%02x", r>>8, g>>8, b>>8)
 49}
 50
 51// createThemedConfig creates a temporary lazygit config file with Crush theme.
 52// Theme mappings align with Crush's UX patterns:
 53// - Borders: BorderFocus (purple) for active, Border (gray) for inactive
 54// - Selection: Primary (purple) background matches app's TextSelected style
 55// - Status: Success (green), Error (red), Info (blue), Warning (orange)
 56func createThemedConfig() string {
 57	t := styles.CurrentTheme()
 58
 59	config := fmt.Sprintf(`gui:
 60  border: rounded
 61  showFileTree: true
 62  showRandomTip: false
 63  showCommandLog: false
 64  showBottomLine: true
 65  showPanelJumps: false
 66  nerdFontsVersion: ""
 67  showFileIcons: false
 68  theme:
 69    activeBorderColor:
 70      - "%s"
 71      - bold
 72    inactiveBorderColor:
 73      - "%s"
 74    searchingActiveBorderColor:
 75      - "%s"
 76      - bold
 77    optionsTextColor:
 78      - "%s"
 79    selectedLineBgColor:
 80      - "%s"
 81    inactiveViewSelectedLineBgColor:
 82      - "%s"
 83    cherryPickedCommitFgColor:
 84      - "%s"
 85    cherryPickedCommitBgColor:
 86      - "%s"
 87    markedBaseCommitFgColor:
 88      - "%s"
 89    markedBaseCommitBgColor:
 90      - "%s"
 91    unstagedChangesColor:
 92      - "%s"
 93    defaultFgColor:
 94      - default
 95`,
 96		colorToHex(t.BorderFocus),
 97		colorToHex(t.FgMuted),
 98		colorToHex(t.Info),
 99		colorToHex(t.FgMuted),
100		colorToHex(t.Primary),
101		colorToHex(t.BgSubtle),
102		colorToHex(t.Success),
103		colorToHex(t.BgSubtle),
104		colorToHex(t.Info),
105		colorToHex(t.BgSubtle),
106		colorToHex(t.Error),
107	)
108
109	f, err := os.CreateTemp("", "crush-lazygit-*.yml")
110	if err != nil {
111		return ""
112	}
113	defer f.Close()
114
115	_, _ = f.WriteString(config)
116	return f.Name()
117}