diff options
Diffstat (limited to 'prettyFormat.go')
| -rw-r--r-- | prettyFormat.go | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/prettyFormat.go b/prettyFormat.go new file mode 100644 index 0000000..e898929 --- /dev/null +++ b/prettyFormat.go @@ -0,0 +1,131 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "go.wit.com/lib/protobuf/chatpb" +) + +const termWidth = 120 // The target width for the formatted output boxes. + +// prettyFormatChat is the main entry point to print a detailed view of a Chat topic. +func prettyFormatChat(chat *chatpb.Chat) { + fmt.Printf("\n========================================================\n") + fmt.Printf("== Chat Topic: %s (UUID: %s)\n", chat.GetChatName(), chat.GetUuid()) + fmt.Printf("========================================================\n\n") + + // Since content files are relative, we need a path to a log file. + // We can reconstruct the config path using the same logic as ConfigSave/ConfigLoad. + logDir := os.Getenv("GEMINI_HOME") + if logDir == "" { + homeDir, _ := os.UserHomeDir() + logDir = filepath.Join(homeDir, ".config/gemini") + } + + for _, entry := range chat.GetEntries() { + author := entry.GetFrom().String() + var formattedTime string + if ctime := entry.GetCtime(); ctime != nil { + t := ctime.AsTime() + formattedTime = t.Format("2006-01-02 15:04:05") + } else { + formattedTime = "No Timestamp" + } + + var content string + if contentFile := entry.GetContentFile(); contentFile != "" { + contentPath := filepath.Join(logDir, contentFile) + contentBytes, err := os.ReadFile(contentPath) + if err != nil { + content = fmt.Sprintf("--- ERROR: Could not read content file %s: %v ---", contentPath, err) + } else { + content = string(contentBytes) + } + } else { + content = entry.GetContent() + } + + if content != "" { + fmt.Printf("✦ %s (%s):\n%s\n", author, formattedTime, strings.TrimSpace(content)) + } + + if table := entry.GetTable(); table != nil { + printTable(table) + } + for _, toolCall := range entry.GetToolCalls() { + printToolCallBox(toolCall) + } + if snippets := entry.GetSnippets(); snippets != nil { + for _, snippet := range snippets { + printCodeSnippet(snippet, logDir) + } + } + fmt.Println() + } +} + +func printTable(table *chatpb.Table) { + if table == nil || len(table.GetRows()) == 0 { + return + } + fmt.Println("┌─[ Table Data ]──────────────────────────────────────────") + for _, row := range table.GetRows() { + fmt.Printf("│ %s\n", strings.Join(row.GetFields(), " │ ")) + } + fmt.Printf("└─────────────────────────────────────────────────────────\n\n") +} + +func printCodeSnippet(snippet *chatpb.CodeSnippet, logDir string) { + snippetPath := filepath.Join(logDir, snippet.GetFilename()) + codeBytes, err := os.ReadFile(snippetPath) + if err != nil { + fmt.Printf("┌─[ ERROR: Could not read snippet file %s ]─\n\n", snippetPath) + return + } + code := string(codeBytes) + language := filepath.Base(snippet.GetFilename()) + fmt.Printf("┌─[ Code Snippet: %s ]──────────────────────────────────\n", language) + for _, line := range strings.Split(strings.TrimSpace(code), "\n") { + fmt.Printf("│ %s\n", line) + } + fmt.Printf("└─────────────────────────────────────────────────────────\n\n") +} + +func printToolCallBox(tc *chatpb.ToolCall) { + boxWidth := termWidth - 2 + fmt.Printf(" ╭%s╮\n", strings.Repeat("─", boxWidth)) + header := fmt.Sprintf(" ✔ %s %s (%s)", tc.GetName(), tc.GetInput(), tc.GetDescription()) + printWrappedLine(header, boxWidth) + printEmptyLine(boxWidth) + if stdout := tc.GetOutputStdout(); stdout != "" { + for _, line := range strings.Split(stdout, "\n") { + printWrappedLine(" "+line, boxWidth) + } + } + if stderr := tc.GetOutputStderr(); stderr != "" { + for _, line := range strings.Split(stderr, "\n") { + printWrappedLine(" "+line, boxWidth) + } + } + printEmptyLine(boxWidth) + fmt.Printf(" ╰%s╯\n", strings.Repeat("─", boxWidth)) +} + +func printWrappedLine(text string, width int) { + if len(text) == 0 { + printEmptyLine(width) + return + } + for len(text) > width { + fmt.Printf(" │ %-*s │\n", width, text[:width]) + text = text[width:] + } + fmt.Printf(" │ %-*s │\n", width, text) +} + +func printEmptyLine(width int) { + fmt.Printf(" │ %*s │\n", width, "") +} |
