7 "charm.land/lipgloss/v2"
8 "github.com/charmbracelet/crush/internal/app"
9 "github.com/charmbracelet/crush/internal/lsp"
10 "github.com/charmbracelet/crush/internal/ui/common"
11 "github.com/charmbracelet/crush/internal/ui/styles"
12 "github.com/charmbracelet/x/powernap/pkg/lsp/protocol"
15// LSPInfo wraps LSP client information with diagnostic counts by severity.
18 Diagnostics map[protocol.DiagnosticSeverity]int
21// lspInfo renders the LSP status section showing active LSP clients and their
23func (m *UI) lspInfo(width, maxItems int, isSection bool) string {
27 for _, state := range m.lspStates {
28 client, ok := m.com.App.LSPClients.Get(state.Name)
32 lspErrs := map[protocol.DiagnosticSeverity]int{
33 protocol.SeverityError: 0,
34 protocol.SeverityWarning: 0,
35 protocol.SeverityHint: 0,
36 protocol.SeverityInformation: 0,
39 for _, diagnostics := range client.GetDiagnostics() {
40 for _, diagnostic := range diagnostics {
41 if severity, ok := lspErrs[diagnostic.Severity]; ok {
42 lspErrs[diagnostic.Severity] = severity + 1
47 lsps = append(lsps, LSPInfo{LSPClientInfo: state, Diagnostics: lspErrs})
49 title := t.Subtle.Render("LSPs")
51 title = common.Section(t, title, width)
53 list := t.Subtle.Render("None")
55 list = lspList(t, lsps, width, maxItems)
58 return lipgloss.NewStyle().Width(width).Render(fmt.Sprintf("%s\n\n%s", title, list))
61// lspDiagnostics formats diagnostic counts with appropriate icons and colors.
62func lspDiagnostics(t *styles.Styles, diagnostics map[protocol.DiagnosticSeverity]int) string {
64 if diagnostics[protocol.SeverityError] > 0 {
65 errs = append(errs, t.LSP.ErrorDiagnostic.Render(fmt.Sprintf("%s %d", styles.ErrorIcon, diagnostics[protocol.SeverityError])))
67 if diagnostics[protocol.SeverityWarning] > 0 {
68 errs = append(errs, t.LSP.WarningDiagnostic.Render(fmt.Sprintf("%s %d", styles.WarningIcon, diagnostics[protocol.SeverityWarning])))
70 if diagnostics[protocol.SeverityHint] > 0 {
71 errs = append(errs, t.LSP.HintDiagnostic.Render(fmt.Sprintf("%s %d", styles.HintIcon, diagnostics[protocol.SeverityHint])))
73 if diagnostics[protocol.SeverityInformation] > 0 {
74 errs = append(errs, t.LSP.InfoDiagnostic.Render(fmt.Sprintf("%s %d", styles.InfoIcon, diagnostics[protocol.SeverityInformation])))
76 return strings.Join(errs, " ")
79// lspList renders a list of LSP clients with their status and diagnostics,
80// truncating to maxItems if needed.
81func lspList(t *styles.Styles, lsps []LSPInfo, width, maxItems int) string {
82 var renderedLsps []string
83 for _, l := range lsps {
86 var description string
87 var diagnostics string
89 case lsp.StateStarting:
90 icon = t.ItemBusyIcon.String()
91 description = t.Subtle.Render("starting...")
93 icon = t.ItemOnlineIcon.String()
94 diagnostics = lspDiagnostics(t, l.Diagnostics)
96 icon = t.ItemErrorIcon.String()
97 description = t.Subtle.Render("error")
99 description = t.Subtle.Render(fmt.Sprintf("error: %s", l.Error.Error()))
101 case lsp.StateDisabled:
102 icon = t.ItemOfflineIcon.Foreground(t.Muted.GetBackground()).String()
103 description = t.Subtle.Render("inactive")
105 icon = t.ItemOfflineIcon.String()
107 renderedLsps = append(renderedLsps, common.Status(t, common.StatusOpts{
110 Description: description,
111 ExtraContent: diagnostics,
115 if len(renderedLsps) > maxItems {
116 visibleItems := renderedLsps[:maxItems-1]
117 remaining := len(renderedLsps) - maxItems
118 visibleItems = append(visibleItems, t.Subtle.Render(fmt.Sprintf("…and %d more", remaining)))
119 return lipgloss.JoinVertical(lipgloss.Left, visibleItems...)
121 return lipgloss.JoinVertical(lipgloss.Left, renderedLsps...)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list