Skip to content

Commit 9cd3d6b

Browse files
committed
refactor: Simplify file selection rendering and improve search functionality
Signed-off-by: Eden Reich <eden.reich@gmail.com>
1 parent 44c8d18 commit 9cd3d6b

File tree

1 file changed

+57
-38
lines changed

1 file changed

+57
-38
lines changed

internal/app/chat_application.go

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -265,47 +265,48 @@ func (app *ChatApplication) renderModelSelection() string {
265265
}
266266

267267
func (app *ChatApplication) renderFileSelection() string {
268-
allFiles, ok := app.state.Data["files"].([]string)
269-
if !ok || len(allFiles) == 0 {
268+
allFiles, searchQuery, selectedIndex := app.getFileSelectionState()
269+
if allFiles == nil {
270270
return "📁 No files found in current directory\n\nPress ESC to return to chat"
271271
}
272272

273-
searchQuery := ""
274-
if query, ok := app.state.Data["fileSearchQuery"].(string); ok {
275-
searchQuery = query
276-
}
273+
files := app.filterFiles(allFiles, searchQuery)
274+
selectedIndex = app.validateSelectedIndex(files, selectedIndex)
277275

278-
var files []string
279-
if searchQuery == "" {
280-
files = allFiles
281-
} else {
282-
for _, file := range allFiles {
283-
if strings.Contains(strings.ToLower(file), strings.ToLower(searchQuery)) {
284-
files = append(files, file)
285-
}
286-
}
287-
}
276+
var b strings.Builder
277+
app.renderFileSelectionHeader(&b, files, allFiles, searchQuery)
278+
app.renderFileSearchField(&b, searchQuery)
288279

289-
selectedIndex := 0
290-
if idx, ok := app.state.Data["fileSelectedIndex"].(int); ok {
291-
selectedIndex = idx
280+
if len(files) == 0 {
281+
return app.renderNoFilesFound(&b, searchQuery)
292282
}
293283

284+
app.renderFileList(&b, files, selectedIndex)
285+
app.renderFileSelectionFooter(&b, files)
286+
287+
return b.String()
288+
}
289+
290+
func (app *ChatApplication) validateSelectedIndex(files []string, selectedIndex int) int {
294291
if selectedIndex >= len(files) {
295292
selectedIndex = 0
296293
app.state.Data["fileSelectedIndex"] = 0
297294
}
295+
return selectedIndex
296+
}
298297

299-
var b strings.Builder
300-
theme := app.services.GetTheme()
301-
298+
func (app *ChatApplication) renderFileSelectionHeader(b *strings.Builder, files, allFiles []string, searchQuery string) {
302299
if searchQuery != "" {
303300
b.WriteString(fmt.Sprintf("📁 File Search - %d matches (of %d total files):\n", len(files), len(allFiles)))
304301
} else {
305302
b.WriteString(fmt.Sprintf("📁 Select a file to include in your message (%d files found):\n", len(files)))
306303
}
307304
b.WriteString(strings.Repeat("═", app.state.Width))
308305
b.WriteString("\n\n")
306+
}
307+
308+
func (app *ChatApplication) renderFileSearchField(b *strings.Builder, searchQuery string) {
309+
theme := app.services.GetTheme()
309310

310311
b.WriteString("🔍 Search: ")
311312
if searchQuery != "" {
@@ -314,23 +315,21 @@ func (app *ChatApplication) renderFileSelection() string {
314315
b.WriteString(fmt.Sprintf("%stype to filter files...%s│", theme.GetDimColor(), "\033[0m"))
315316
}
316317
b.WriteString("\n\n")
318+
}
317319

318-
if len(files) == 0 {
319-
b.WriteString(fmt.Sprintf("%sNo files match '%s'%s\n\n", theme.GetErrorColor(), searchQuery, "\033[0m"))
320-
helpText := "Type to search, BACKSPACE to clear search, ESC to cancel"
321-
b.WriteString(theme.GetDimColor() + helpText + "\033[0m")
322-
return b.String()
323-
}
320+
func (app *ChatApplication) renderNoFilesFound(b *strings.Builder, searchQuery string) string {
321+
theme := app.services.GetTheme()
322+
323+
fmt.Fprintf(b, "%sNo files match '%s'%s\n\n", theme.GetErrorColor(), searchQuery, "\033[0m")
324+
helpText := "Type to search, BACKSPACE to clear search, ESC to cancel"
325+
b.WriteString(theme.GetDimColor() + helpText + "\033[0m")
326+
return b.String()
327+
}
324328

329+
func (app *ChatApplication) renderFileList(b *strings.Builder, files []string, selectedIndex int) {
330+
theme := app.services.GetTheme()
325331
maxVisible := 12
326-
startIndex := 0
327-
if selectedIndex >= maxVisible {
328-
startIndex = selectedIndex - maxVisible + 1
329-
}
330-
endIndex := startIndex + maxVisible
331-
if endIndex > len(files) {
332-
endIndex = len(files)
333-
}
332+
startIndex, endIndex := app.calculateVisibleRange(len(files), selectedIndex, maxVisible)
334333

335334
for i := startIndex; i < endIndex; i++ {
336335
file := files[i]
@@ -340,19 +339,39 @@ func (app *ChatApplication) renderFileSelection() string {
340339
b.WriteString(fmt.Sprintf("%s %s%s\n", theme.GetDimColor(), file, "\033[0m"))
341340
}
342341
}
342+
}
343+
344+
func (app *ChatApplication) calculateVisibleRange(totalFiles, selectedIndex, maxVisible int) (int, int) {
345+
startIndex := 0
346+
if selectedIndex >= maxVisible {
347+
startIndex = selectedIndex - maxVisible + 1
348+
}
349+
endIndex := startIndex + maxVisible
350+
if endIndex > totalFiles {
351+
endIndex = totalFiles
352+
}
353+
return startIndex, endIndex
354+
}
355+
356+
func (app *ChatApplication) renderFileSelectionFooter(b *strings.Builder, files []string) {
357+
theme := app.services.GetTheme()
358+
maxVisible := 12
343359

344360
b.WriteString("\n")
345361

346362
if len(files) > maxVisible {
363+
selectedIndex := 0
364+
if idx, ok := app.state.Data["fileSelectedIndex"].(int); ok {
365+
selectedIndex = idx
366+
}
367+
startIndex, endIndex := app.calculateVisibleRange(len(files), selectedIndex, maxVisible)
347368
b.WriteString(fmt.Sprintf("%sShowing %d-%d of %d matches%s\n",
348369
theme.GetDimColor(), startIndex+1, endIndex, len(files), "\033[0m"))
349370
b.WriteString("\n")
350371
}
351372

352373
helpText := "Type to search, ↑↓ to navigate, ENTER to select, BACKSPACE to clear, ESC to cancel"
353374
b.WriteString(theme.GetDimColor() + helpText + "\033[0m")
354-
355-
return b.String()
356375
}
357376

358377
func (app *ChatApplication) renderApproval() string {

0 commit comments

Comments
 (0)