Skip to content

Commit 146795a

Browse files
committed
fix: resolve UI alignment bug and eliminate code duplication - Fix file tree width calculation for consistent vertical divider alignment - Add formatFileLine helper function for uniform spacing - Move getFileIcon to utils/ui.go to eliminate duplication - Ensure consistent 2-character width for all file list entries - Update both main.go and ui/filelist.go to use shared utility
1 parent 89b547d commit 146795a

3 files changed

Lines changed: 140 additions & 175 deletions

File tree

main.go

Lines changed: 1 addition & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ func (m model) formatDirectoryPreview(dirName string, files []utils.FileInfo, di
325325
icon = "📁"
326326
} else {
327327
// Get file icon based on extension
328-
icon = getFileIcon(file.Extension)
328+
icon = utils.GetFileIcon(file.Extension)
329329
}
330330

331331
result.WriteString(fmt.Sprintf(" %s %s", icon, file.Path))
@@ -343,72 +343,6 @@ func (m model) formatDirectoryPreview(dirName string, files []utils.FileInfo, di
343343
return result.String()
344344
}
345345

346-
// getFileIcon returns an appropriate icon for the file extension
347-
func getFileIcon(ext string) string {
348-
icons := map[string]string{
349-
// Programming languages
350-
".go": "🐹",
351-
".py": "🐍",
352-
".js": "📄",
353-
".ts": "📘",
354-
".jsx": "⚛️",
355-
".tsx": "⚛️",
356-
".rs": "🦀",
357-
".java": "☕",
358-
".c": "📄",
359-
".cpp": "📄",
360-
".cc": "📄",
361-
".h": "📄",
362-
".hpp": "📄",
363-
".cs": "🔷",
364-
".php": "🐘",
365-
".rb": "💎",
366-
".swift": "🍎",
367-
".kt": "📱",
368-
".scala": "⚖️",
369-
370-
// Documentation and markup
371-
".md": "📝",
372-
".markdown": "📝",
373-
".txt": "📄",
374-
".rst": "📜",
375-
376-
// Configuration files
377-
".json": "🔧",
378-
".yaml": "⚙️",
379-
".yml": "⚙️",
380-
".toml": "⚙️",
381-
".ini": "⚙️",
382-
".cfg": "⚙️",
383-
".conf": "⚙️",
384-
".env": "🌿",
385-
".properties": "⚙️",
386-
387-
// Data files
388-
".xml": "📋",
389-
".csv": "📊",
390-
".log": "📜",
391-
392-
// Shell and scripts
393-
".sh": "🐚",
394-
".bash": "🐚",
395-
".zsh": "🐚",
396-
".fish": "🐠",
397-
".ps1": "💻",
398-
".bat": "💻",
399-
".cmd": "💻",
400-
401-
// Executables
402-
".exe": "⚙️",
403-
".bin": "⚙️",
404-
}
405-
406-
if icon, exists := icons[ext]; exists {
407-
return icon
408-
}
409-
return "📄"
410-
}
411-
412346
// handleFileSelection processes file selection and starts summarization if appropriate
413347
func (m *model) handleFileSelection(selected *utils.FileInfo) tea.Cmd {
414348
if selected == nil {

ui/filelist.go

Lines changed: 37 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,10 @@ func (m FileListModel) View() string {
169169
for i := startIdx; i < endIdx; i++ {
170170
file := displayFiles[i]
171171

172-
// Cursor indicator
172+
// Cursor indicator (ensure consistent 2-character width)
173173
cursor := " "
174174
if m.cursor < len(m.files) && file.Path == m.files[m.cursor].Path {
175-
cursor = "> "
175+
cursor = "> " // Already 2 characters
176176
}
177177

178178
// File type indicator
@@ -184,23 +184,28 @@ func (m FileListModel) View() string {
184184
indicator = "📁"
185185
}
186186
} else {
187-
indicator = getFileIcon(file.Extension)
187+
indicator = utils.GetFileIcon(file.Extension)
188188
}
189189

190-
// Selection indicator
190+
// Selection indicator (ensure consistent 1-character width)
191191
selected := " "
192192
if file.Path == m.selected {
193-
selected = "✓"
193+
selected = "✓" // Single character
194194
}
195195

196196
// File name (truncate if too long)
197197
name := file.Path
198-
maxNameLength := m.width - 15 // Account for indicators and padding
198+
199+
// Calculate consistent width accounting for all components
200+
// cursor: 2 chars, brackets: 2 chars, selected: 1 char, space: 1 char, indicator: 2 chars, space: 1 char
201+
// Total fixed width: 9 characters
202+
maxNameLength := m.width - 9
199203
if maxNameLength > 0 && len(name) > maxNameLength {
200204
name = name[:maxNameLength-3] + "..."
201205
}
202206

203-
line := fmt.Sprintf("%s[%s] %s %s", cursor, selected, indicator, name)
207+
// Use helper function to ensure consistent width formatting
208+
line := formatFileLine(cursor, selected, indicator, name)
204209

205210
if m.cursor < len(m.files) && file.Path == m.files[m.cursor].Path {
206211
line = m.cursorStyle.Render(line)
@@ -225,107 +230,6 @@ func (m FileListModel) View() string {
225230
return m.baseStyle.Render(content)
226231
}
227232

228-
// getFileIcon returns an appropriate icon for the file extension
229-
func getFileIcon(ext string) string {
230-
icons := map[string]string{
231-
// Programming languages
232-
".go": "🐹",
233-
".py": "🐍",
234-
".js": "📄",
235-
".ts": "📘",
236-
".jsx": "⚛️",
237-
".tsx": "⚛️",
238-
".rs": "🦀",
239-
".java": "☕",
240-
".c": "📄",
241-
".cpp": "📄",
242-
".cc": "📄",
243-
".h": "📄",
244-
".hpp": "📄",
245-
".cs": "🔷",
246-
".php": "🐘",
247-
".rb": "💎",
248-
".swift": "🍎",
249-
".kt": "📱",
250-
".scala": "⚖️",
251-
252-
// Documentation and markup
253-
".md": "📝",
254-
".markdown": "📝",
255-
".txt": "📄",
256-
".rst": "📜",
257-
".tex": "📰",
258-
259-
// Configuration files
260-
".json": "🔧",
261-
".yaml": "⚙️",
262-
".yml": "⚙️",
263-
".toml": "⚙️",
264-
".ini": "⚙️",
265-
".cfg": "⚙️",
266-
".conf": "⚙️",
267-
".env": "🌿",
268-
".properties": "⚙️",
269-
270-
// Data files
271-
".xml": "📋",
272-
".csv": "📊",
273-
".log": "📜",
274-
".sql": "🗄️",
275-
276-
// Shell and scripts
277-
".sh": "🐚",
278-
".bash": "🐚",
279-
".zsh": "🐚",
280-
".fish": "🐠",
281-
".ps1": "💻",
282-
".bat": "💻",
283-
".cmd": "💻",
284-
285-
// Build and package files
286-
".dockerfile": "🐳",
287-
".makefile": "🔨",
288-
".gradle": "🐘",
289-
".pom": "📦",
290-
".package": "📦",
291-
292-
// Web and frontend
293-
".html": "🌐",
294-
".htm": "🌐",
295-
".css": "🎨",
296-
".scss": "🎨",
297-
".sass": "🎨",
298-
".less": "🎨",
299-
300-
// Images
301-
".png": "🖼️",
302-
".jpg": "🖼️",
303-
".jpeg": "🖼️",
304-
".gif": "🖼️",
305-
".svg": "🖼️",
306-
".ico": "🖼️",
307-
308-
// Archives
309-
".zip": "📦",
310-
".tar": "📦",
311-
".gz": "📦",
312-
".rar": "📦",
313-
".7z": "📦",
314-
315-
// Executables
316-
".exe": "⚙️",
317-
".bin": "⚙️",
318-
".deb": "📦",
319-
".rpm": "📦",
320-
".msi": "📦",
321-
}
322-
323-
if icon, exists := icons[ext]; exists {
324-
return icon
325-
}
326-
return "📄"
327-
}
328-
329233
// Helper functions for min/max
330234
func min(a, b int) int {
331235
if a < b {
@@ -340,3 +244,28 @@ func max(a, b int) int {
340244
}
341245
return b
342246
}
247+
248+
// formatFileLine ensures consistent width formatting for file list entries
249+
func formatFileLine(cursor, selected, indicator, name string) string {
250+
// Ensure cursor is exactly 2 characters
251+
if len(cursor) < 2 {
252+
cursor = cursor + strings.Repeat(" ", 2-len(cursor))
253+
} else if len(cursor) > 2 {
254+
cursor = cursor[:2]
255+
}
256+
257+
// Ensure selected is exactly 1 character
258+
if len(selected) < 1 {
259+
selected = " "
260+
} else if len(selected) > 1 {
261+
selected = selected[:1]
262+
}
263+
264+
// Ensure indicator has consistent spacing (add space if needed)
265+
indicatorWithSpace := indicator
266+
if len(indicator) < 2 {
267+
indicatorWithSpace = indicator + " "
268+
}
269+
270+
return fmt.Sprintf("%s[%s] %s %s", cursor, selected, indicatorWithSpace, name)
271+
}

utils/ui.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package utils
2+
3+
// GetFileIcon returns an appropriate icon for the file extension
4+
func GetFileIcon(ext string) string {
5+
icons := map[string]string{
6+
// Programming languages
7+
".go": "🐹",
8+
".py": "🐍",
9+
".js": "📄",
10+
".ts": "📘",
11+
".jsx": "⚛️",
12+
".tsx": "⚛️",
13+
".rs": "🦀",
14+
".java": "☕",
15+
".c": "📄",
16+
".cpp": "📄",
17+
".cc": "📄",
18+
".h": "📄",
19+
".hpp": "📄",
20+
".cs": "🔷",
21+
".php": "🐘",
22+
".rb": "💎",
23+
".swift": "🍎",
24+
".kt": "📱",
25+
".scala": "⚖️",
26+
27+
// Documentation and markup
28+
".md": "📝",
29+
".markdown": "📝",
30+
".txt": "📄",
31+
".rst": "📜",
32+
".tex": "📰",
33+
34+
// Configuration files
35+
".json": "🔧",
36+
".yaml": "⚙️",
37+
".yml": "⚙️",
38+
".toml": "⚙️",
39+
".ini": "⚙️",
40+
".cfg": "⚙️",
41+
".conf": "⚙️",
42+
".env": "🌿",
43+
".properties": "⚙️",
44+
45+
// Data files
46+
".xml": "📋",
47+
".csv": "📊",
48+
".log": "📜",
49+
".sql": "🗄️",
50+
51+
// Shell and scripts
52+
".sh": "🐚",
53+
".bash": "🐚",
54+
".zsh": "🐚",
55+
".fish": "🐠",
56+
".ps1": "💻",
57+
".bat": "💻",
58+
".cmd": "💻",
59+
60+
// Build and package files
61+
".dockerfile": "🐳",
62+
".makefile": "🔨",
63+
".gradle": "🐘",
64+
".pom": "📦",
65+
".package": "📦",
66+
67+
// Web and frontend
68+
".html": "🌐",
69+
".htm": "🌐",
70+
".css": "🎨",
71+
".scss": "🎨",
72+
".sass": "🎨",
73+
".less": "🎨",
74+
75+
// Images
76+
".png": "🖼️",
77+
".jpg": "🖼️",
78+
".jpeg": "🖼️",
79+
".gif": "🖼️",
80+
".svg": "🖼️",
81+
".ico": "🖼️",
82+
83+
// Archives
84+
".zip": "📦",
85+
".tar": "📦",
86+
".gz": "📦",
87+
".rar": "📦",
88+
".7z": "📦",
89+
90+
// Executables
91+
".exe": "⚙️",
92+
".bin": "⚙️",
93+
".deb": "📦",
94+
".rpm": "📦",
95+
".msi": "📦",
96+
}
97+
98+
if icon, exists := icons[ext]; exists {
99+
return icon
100+
}
101+
return "📄"
102+
}

0 commit comments

Comments
 (0)