@@ -56,51 +56,73 @@ func (m *UI) modelInfo(width int) string {
56 return common.ModelInfo(m.com.Styles, modelName, providerName, reasoningInfo, modelContext, width)
56 return common.ModelInfo(m.com.Styles, modelName, providerName, reasoningInfo, modelContext, width)
59−// getDynamicHeightLimits will give us the num of items to show in each section based on the hight
59+// getDynamicHeightLimits will give us the num of items to show in each section based on the height
60// some items are more important than others.
60// some items are more important than others.
61−func getDynamicHeightLimits(availableHeight int) (maxFiles, maxLSPs, maxMCPs int) {
61+func getDynamicHeightLimits(availableHeight, fileCount, lspCount, mcpCount, skillCount int) (maxFiles, maxLSPs, maxMCPs, maxSkills int) {
63− minItemsPerSection = 2
63+ minItemsPerSection = 2
64+ // Keep these high so dynamic layout uses available sidebar space
65+ // instead of hitting small hard limits.
64− defaultMaxFilesShown = 10
66+ defaultMaxFilesShown = 1000
65− defaultMaxLSPsShown = 8
67+ defaultMaxLSPsShown = 1000
66− defaultMaxMCPsShown = 8
68+ defaultMaxMCPsShown = 1000
69+ defaultMaxSkillsShown = 1000
67 minAvailableHeightLimit = 10
70 minAvailableHeightLimit = 10
70− // If we have very little space, use minimum values
71 if availableHeight < minAvailableHeightLimit {
73 if availableHeight < minAvailableHeightLimit {
72− return minItemsPerSection, minItemsPerSection, minItemsPerSection
74+ return minItemsPerSection, minItemsPerSection, minItemsPerSection, minItemsPerSection
75− // Distribute available height among the three sections
77+ maxFiles = minItemsPerSection
76− // Give priority to files, then LSPs, then MCPs
78+ maxLSPs = minItemsPerSection
77− totalSections := 3
79+ maxMCPs = minItemsPerSection
78− heightPerSection := availableHeight / totalSections
80+ maxSkills = minItemsPerSection
80− // Calculate limits for each section, ensuring minimums
82+ remainingHeight := max(0, availableHeight-(minItemsPerSection*4))
81− maxFiles = max(minItemsPerSection, min(defaultMaxFilesShown, heightPerSection))
83+
82− maxLSPs = max(minItemsPerSection, min(defaultMaxLSPsShown, heightPerSection))
84+ sectionValues := []*int{&maxFiles, &maxLSPs, &maxMCPs, &maxSkills}
83− maxMCPs = max(minItemsPerSection, min(defaultMaxMCPsShown, heightPerSection))
85+ sectionCaps := []int{defaultMaxFilesShown, defaultMaxLSPsShown, defaultMaxMCPsShown, defaultMaxSkillsShown}
84−
86+ sectionNeeds := []int{max(0, fileCount-maxFiles), max(0, lspCount-maxLSPs), max(0, mcpCount-maxMCPs), max(0, skillCount-maxSkills)}
85− // If we have extra space, give it to files first
87+
88+ for remainingHeight > 0 {
90+ for i, section := range sectionValues {
86− remainingHeight := availableHeight - (maxFiles + maxLSPs + maxMCPs)
91+ if remainingHeight == 0 {
87− if remainingHeight > 0 {
92+ break
88− extraForFiles := min(remainingHeight, defaultMaxFilesShown-maxFiles)
93+ }
89− maxFiles += extraForFiles
94+ if sectionNeeds[i] == 0 || *section >= sectionCaps[i] {
90− remainingHeight -= extraForFiles
95+ continue
97+ *section = *section + 1
92− if remainingHeight > 0 {
107+ for remainingHeight > 0 {
93− extraForLSPs := min(remainingHeight, defaultMaxLSPsShown-maxLSPs)
108+ allocated := false
94− maxLSPs += extraForLSPs
109+ for i, section := range sectionValues {
95− remainingHeight -= extraForLSPs
97− if remainingHeight > 0 {
110+ if remainingHeight == 0 {
98− maxMCPs += min(remainingHeight, defaultMaxMCPsShown-maxMCPs)
111+ break
113+ if *section >= sectionCaps[i] {
116+ *section = *section + 1
103− return maxFiles, maxLSPs, maxMCPs
125+ return maxFiles, maxLSPs, maxMCPs, maxSkills
106// sidebar renders the chat sidebar containing session title, working
128// sidebar renders the chat sidebar containing session title, working
@@ -142,11 +164,31 @@ func (m *UI) drawSidebar(scr uv.Screen, area uv.Rectangle) {
142 layout.Len(lipgloss.Height(sidebarHeader)),
164 layout.Len(lipgloss.Height(sidebarHeader)),
143 layout.Fill(1),
165 layout.Fill(1),
144 ).Split(m.layout.sidebar).Assign(new(image.Rectangle), &remainingHeightArea)
166 ).Split(m.layout.sidebar).Assign(new(image.Rectangle), &remainingHeightArea)
145− remainingHeight := remainingHeightArea.Dy() - 10
167+ remainingHeight := remainingHeightArea.Dy() - 6
169+ for _, f := range m.sessionFiles {
170+ if f.Additions == 0 && f.Deletions == 0 {
176+ lspsCount := len(m.lspStates)
179+ for _, mcpCfg := range m.com.Config().MCP.Sorted() {
180+ if _, ok := m.mcpStates[mcpCfg.Name]; ok {
185+ skillsCount := len(m.skillStatusItems())
146− maxFiles, maxLSPs, maxMCPs := getDynamicHeightLimits(remainingHeight)
187+ maxFiles, maxLSPs, maxMCPs, maxSkills := getDynamicHeightLimits(remainingHeight, filesCount, lspsCount, mcpsCount, skillsCount)
148 lspSection := m.lspInfo(width, maxLSPs, true)
189 lspSection := m.lspInfo(width, maxLSPs, true)
149 mcpSection := m.mcpInfo(width, maxMCPs, true)
190 mcpSection := m.mcpInfo(width, maxMCPs, true)
191+ skillsSection := m.skillsInfo(width, maxSkills, true)
150 filesSection := m.filesInfo(m.com.Workspace.WorkingDir(), width, maxFiles, true)
192 filesSection := m.filesInfo(m.com.Workspace.WorkingDir(), width, maxFiles, true)
152 uv.NewStyledString(
194 uv.NewStyledString(
@@ -162,6 +204,8 @@ func (m *UI) drawSidebar(scr uv.Screen, area uv.Rectangle) {
162 lspSection,
204 lspSection,
164 mcpSection,
206 mcpSection,
167 ).Draw(scr, area)
211 ).Draw(scr, area)