lsp_manager/main.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)
}
}