on main help sign in
wip: api key
commit7e36fcf283890ccbef8472df25a3e17f50a4b530 authorKujtim Hoxha <kujtimii.h@gmail.com> dateMon 7 Jul 2025, 14:29 (1 year ago) parent849c8fe
4 files changed+104−5
internal/config/config.go+1−1 internal/config/init.go+1−1 internal/config/load.go+14−3 internal/tui/components/dialogs/models/apikey.go+88
internal/config/config.go+1−1
@@ -299,7 +299,7 @@ func UpdatePreferredModel(modelType SelectedModelType, model SelectedModel) erro
299299}
300300
301301func (c *Config) SetConfigField(key string, value any) error {
302− configPath := globalConfigData()
302+ configPath := GlobalConfigData()
303303 // read the data
304304 data, err := os.ReadFile(configPath)
305305 if err != nil {
internal/config/init.go+1−1
@@ -105,7 +105,7 @@ func MarkProjectInitialized() error {
105105}
106106
107107func HasInitialDataConfig() bool {
108− cfgPath := globalConfigData()
108+ cfgPath := GlobalConfigData()
109109 if _, err := os.Stat(cfgPath); err != nil {
110110 return false
111111 }
internal/config/load.go+14−3
@@ -37,7 +37,7 @@ func Load(workingDir string, debug bool) (*Config, error) {
3737 // uses default config paths
3838 configPaths := []string{
3939 globalConfig(),
40− globalConfigData(),
40+ GlobalConfigData(),
4141 filepath.Join(workingDir, fmt.Sprintf("%s.json", appName)),
4242 filepath.Join(workingDir, fmt.Sprintf(".%s.json", appName)),
4343 }
@@ -510,9 +510,9 @@ func globalConfig() string {
510510 return filepath.Join(os.Getenv("HOME"), ".config", appName, fmt.Sprintf("%s.json", appName))
511511}
512512
513−// globalConfigData returns the path to the main data directory for the application.
513+// GlobalConfigData returns the path to the main data directory for the application.
514514// this config is used when the app overrides configurations instead of updating the global config.
515−func globalConfigData() string {
515+func GlobalConfigData() string {
516516 xdgDataHome := os.Getenv("XDG_DATA_HOME")
517517 if xdgDataHome != "" {
518518 return filepath.Join(xdgDataHome, appName, fmt.Sprintf("%s.json", appName))
@@ -531,3 +531,14 @@ func globalConfigData() string {
531531
532532 return filepath.Join(os.Getenv("HOME"), ".local", "share", appName, fmt.Sprintf("%s.json", appName))
533533}
534+
535+func HomeDir() string {
536+ homeDir := os.Getenv("HOME")
537+ if homeDir == "" {
538+ homeDir = os.Getenv("USERPROFILE") // For Windows compatibility
539+ }
540+ if homeDir == "" {
541+ homeDir = os.Getenv("HOMEPATH") // Fallback for some environments
542+ }
543+ return homeDir
544+}
internal/tui/components/dialogs/models/apikey.gonew file+88
@@ -0,0 +1,88 @@
1+package models
2+
3+import (
4+ "fmt"
5+ "strings"
6+
7+ "github.com/charmbracelet/bubbles/v2/textinput"
8+ tea "github.com/charmbracelet/bubbletea/v2"
9+ "github.com/charmbracelet/crush/internal/config"
10+ "github.com/charmbracelet/crush/internal/tui/styles"
11+ "github.com/charmbracelet/lipgloss/v2"
12+)
13+
14+type APIKeyInput struct {
15+ input textinput.Model
16+ width int
17+ height int
18+}
19+
20+func NewAPIKeyInput() *APIKeyInput {
21+ t := styles.CurrentTheme()
22+
23+ ti := textinput.New()
24+ ti.Placeholder = "Enter your API key..."
25+ ti.SetWidth(50)
26+ ti.SetVirtualCursor(false)
27+ ti.Prompt = "> "
28+ ti.SetStyles(t.S().TextInput)
29+ ti.Focus()
30+
31+ return &APIKeyInput{
32+ input: ti,
33+ width: 60,
34+ }
35+}
36+
37+func (a *APIKeyInput) Init() tea.Cmd {
38+ return textinput.Blink
39+}
40+
41+func (a *APIKeyInput) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
42+ switch msg := msg.(type) {
43+ case tea.WindowSizeMsg:
44+ a.width = msg.Width
45+ a.height = msg.Height
46+ }
47+
48+ var cmd tea.Cmd
49+ a.input, cmd = a.input.Update(msg)
50+ return a, cmd
51+}
52+
53+func (a *APIKeyInput) View() tea.View {
54+ t := styles.CurrentTheme()
55+
56+ title := t.S().Base.
57+ Foreground(t.Secondary).
58+ Bold(true).
59+ Render("Enter your Anthropic API Key")
60+
61+ inputView := a.input.View()
62+
63+ dataPath := config.GlobalConfigData()
64+ dataPath = strings.Replace(dataPath, config.HomeDir(), "~", 1)
65+ helpText := t.S().Muted.
66+ Render(fmt.Sprintf("This will be written to the global configuration: %s", dataPath))
67+
68+ content := lipgloss.JoinVertical(
69+ lipgloss.Left,
70+ title,
71+ "",
72+ inputView,
73+ "",
74+ helpText,
75+ )
76+
77+ view := tea.NewView(content)
78+ cursor := a.input.Cursor()
79+ if cursor != nil {
80+ cursor.Y += 2 // Adjust for title and spacing
81+ }
82+ view.SetCursor(cursor)
83+ return view
84+}
85+
86+func (a *APIKeyInput) Value() string {
87+ return a.input.Value()
88+}