fix(playback): Make playback independent of the filesystem

- Refactor the prettyFormat.go functions to render all content
  directly from the 'Content' fields of the protobuf messages.
- Remove all 'os.ReadFile' calls from the formatting logic.
- This ensures the 'playback' command is self-contained and works
  correctly on saved protobuf data where the original content files
  are no longer available.
This commit is contained in:
Castor Gemini 2025-08-22 03:36:54 -05:00 committed by Jeff Carr
parent 5b7e2daf65
commit 73bc0f73aa
1 changed files with 13 additions and 31 deletions

View File

@ -1,8 +1,13 @@
// This file contains functions for formatting and printing chat logs to the terminal.
// These functions operate exclusively on the in-memory protobuf data structures.
// They do NOT access the filesystem; all content (from content files, snippets, etc.)
// is expected to have been loaded into the 'Content' fields of the protobuf messages
// before these functions are called.
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
@ -17,14 +22,6 @@ func prettyFormatChat(chat *chatpb.Chat) {
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
@ -35,18 +32,8 @@ func prettyFormatChat(chat *chatpb.Chat) {
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()
}
// Use the in-memory Content field directly.
content := entry.GetContent()
if content != "" {
fmt.Printf("✦ %s (%s):\n%s\n", author, formattedTime, strings.TrimSpace(content))
@ -60,7 +47,7 @@ func prettyFormatChat(chat *chatpb.Chat) {
}
if snippets := entry.GetSnippets(); snippets != nil {
for _, snippet := range snippets {
printCodeSnippet(snippet, logDir)
printCodeSnippet(snippet)
}
}
fmt.Println()
@ -78,15 +65,10 @@ func printTable(table *chatpb.Table) {
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())
func printCodeSnippet(snippet *chatpb.CodeSnippet) {
// Use the in-memory Content field directly.
code := snippet.GetContent()
language := filepath.Base(snippet.GetFilename()) // Still useful for display
fmt.Printf("┌─[ Code Snippet: %s ]──────────────────────────────────\n", language)
for _, line := range strings.Split(strings.TrimSpace(code), "\n") {
fmt.Printf("│ %s\n", line)