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