246 lines
6.8 KiB
Go
246 lines
6.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"path/filepath"
|
|
"os"
|
|
|
|
"github.com/charmbracelet/bubbles/list"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
// Styles
|
|
var (
|
|
titleStyle = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color("#7D56F4")).
|
|
MarginLeft(2)
|
|
|
|
selectedStyle = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color("#7D56F4"))
|
|
|
|
installedBadge = lipgloss.NewStyle().
|
|
Bold(true).
|
|
Foreground(lipgloss.Color("#04B575")).
|
|
Render(" [INSTALLED]")
|
|
)
|
|
|
|
// serverItem implementiert list.Item für Bubbletea
|
|
type serverItem struct {
|
|
server LSPServer
|
|
installed bool
|
|
}
|
|
|
|
func (i serverItem) FilterValue() string {
|
|
return i.server.Name
|
|
}
|
|
|
|
func (i serverItem) Title() string {
|
|
title := i.server.Name
|
|
if i.installed {
|
|
title += installedBadge
|
|
}
|
|
return title
|
|
}
|
|
|
|
func (i serverItem) Description() string {
|
|
return fmt.Sprintf("%s | Languages: %s",
|
|
i.server.Description,
|
|
strings.Join(i.server.Languages, ", "))
|
|
}
|
|
|
|
// Model für die Bubbletea-Anwendung
|
|
type model struct {
|
|
list list.Model
|
|
registry *Registry
|
|
installer *Installer
|
|
status string
|
|
quitting bool
|
|
}
|
|
|
|
// installMsg wird nach erfolgreicher Installation gesendet
|
|
type installMsg struct {
|
|
server LSPServer
|
|
err error
|
|
}
|
|
|
|
// updateMsg wird nach Registry-Update gesendet
|
|
type updateMsg struct {
|
|
registry *Registry
|
|
err error
|
|
}
|
|
|
|
// Init initialisiert das Model
|
|
func (m model) Init() tea.Cmd {
|
|
return nil
|
|
}
|
|
|
|
// Update behandelt Nachrichten und aktualisiert das Model
|
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
case "ctrl+c", "q":
|
|
m.quitting = true
|
|
return m, tea.Quit
|
|
|
|
case "u":
|
|
// Registry aktualisieren (force update)
|
|
m.status = "Updating registry from Mason..."
|
|
return m, func() tea.Msg {
|
|
registry, err := LoadRegistryFromMason()
|
|
return updateMsg{registry: registry, err: err}
|
|
}
|
|
|
|
case "enter":
|
|
// Server installieren/deinstallieren
|
|
selectedItem := m.list.SelectedItem().(serverItem)
|
|
|
|
if selectedItem.installed {
|
|
// Deinstallieren
|
|
m.status = fmt.Sprintf("Uninstalling %s...", selectedItem.server.Name)
|
|
return m, func() tea.Msg {
|
|
err := m.installer.Uninstall(selectedItem.server)
|
|
return installMsg{server: selectedItem.server, err: err}
|
|
}
|
|
} else {
|
|
// Installieren
|
|
m.status = fmt.Sprintf("Installing %s...", selectedItem.server.Name)
|
|
return m, func() tea.Msg {
|
|
err := m.installer.Install(selectedItem.server)
|
|
return installMsg{server: selectedItem.server, err: err}
|
|
}
|
|
}
|
|
|
|
case "i":
|
|
// Info anzeigen
|
|
selectedItem := m.list.SelectedItem().(serverItem)
|
|
m.status = fmt.Sprintf("Server: %s | Homepage: %s | License: %s | Type: %s",
|
|
selectedItem.server.Name,
|
|
selectedItem.server.Homepage,
|
|
selectedItem.server.License,
|
|
selectedItem.server.InstallType)
|
|
return m, nil
|
|
}
|
|
|
|
case installMsg:
|
|
// Installation abgeschlossen
|
|
if msg.err != nil {
|
|
m.status = fmt.Sprintf("❌ Error: %v", msg.err)
|
|
} else {
|
|
m.status = fmt.Sprintf("✅ Successfully installed %s", msg.server.Name)
|
|
}
|
|
|
|
// Liste aktualisieren
|
|
items := m.buildListItems()
|
|
m.list.SetItems(items)
|
|
|
|
return m, nil
|
|
|
|
case updateMsg:
|
|
// Registry-Update abgeschlossen
|
|
if msg.err != nil {
|
|
m.status = fmt.Sprintf("❌ Registry update failed: %v", msg.err)
|
|
} else {
|
|
m.registry = msg.registry
|
|
m.status = fmt.Sprintf("✅ Registry updated with %d LSP servers", len(msg.registry.Servers))
|
|
// Liste aktualisieren
|
|
items := m.buildListItems()
|
|
m.list.SetItems(items)
|
|
}
|
|
return m, nil
|
|
|
|
case tea.WindowSizeMsg:
|
|
m.list.SetWidth(msg.Width)
|
|
m.list.SetHeight(msg.Height - 5)
|
|
return m, nil
|
|
}
|
|
|
|
var cmd tea.Cmd
|
|
m.list, cmd = m.list.Update(msg)
|
|
return m, cmd
|
|
}
|
|
|
|
// View rendert die UI
|
|
func (m model) View() string {
|
|
if m.quitting {
|
|
return "Goodbye! 👋\n"
|
|
}
|
|
|
|
header := titleStyle.Render("🚀 LSP Server Manager (Mason Registry)")
|
|
|
|
helpText := lipgloss.NewStyle().
|
|
Foreground(lipgloss.Color("#626262")).
|
|
Render("\nEnter: Install/Uninstall | i: Info | u: Update Registry | q: Quit | /: Filter")
|
|
|
|
statusBar := ""
|
|
if m.status != "" {
|
|
statusBar = "\n" + lipgloss.NewStyle().
|
|
Foreground(lipgloss.Color("#7D56F4")).
|
|
Render(m.status)
|
|
}
|
|
|
|
return fmt.Sprintf("%s\n\n%s%s%s\n",
|
|
header,
|
|
m.list.View(),
|
|
statusBar,
|
|
helpText)
|
|
}
|
|
|
|
// buildListItems erstellt die Liste der Server-Items
|
|
func (m *model) buildListItems() []list.Item {
|
|
items := make([]list.Item, len(m.registry.Servers))
|
|
|
|
for i, server := range m.registry.Servers {
|
|
items[i] = serverItem{
|
|
server: server,
|
|
installed: m.installer.IsInstalled(server),
|
|
}
|
|
}
|
|
|
|
return items
|
|
}
|
|
|
|
// Hauptfunktion
|
|
func main() {
|
|
// Registry laden - verwende "mason" um von GitHub zu laden
|
|
// oder einen Dateipfad für lokale registry.json
|
|
registry, err := LoadRegistry("mason")
|
|
if err != nil {
|
|
fmt.Printf("Error loading registry: %v\n", err)
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Loaded %d LSP servers from registry\n\n", len(registry.Servers))
|
|
|
|
// Installer erstellen
|
|
homeDir, _ := os.UserHomeDir()
|
|
installDir := filepath.Join(homeDir, ".lsp-manager")
|
|
installer := NewInstaller(installDir)
|
|
installer.PrintPathInstructions()
|
|
|
|
// Liste erstellen
|
|
delegate := list.NewDefaultDelegate()
|
|
delegate.Styles.SelectedTitle = selectedStyle
|
|
delegate.Styles.SelectedDesc = selectedStyle
|
|
|
|
initialModel := model{
|
|
registry: registry,
|
|
installer: installer,
|
|
}
|
|
|
|
items := initialModel.buildListItems()
|
|
initialModel.list = list.New(items, delegate, 0, 0)
|
|
initialModel.list.Title = "Available LSP Servers"
|
|
initialModel.list.SetFilteringEnabled(true)
|
|
|
|
// Bubbletea-Programm starten
|
|
p := tea.NewProgram(initialModel, tea.WithAltScreen())
|
|
if _, err := p.Run(); err != nil {
|
|
fmt.Printf("Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|