204 lines
5.6 KiB
Go
204 lines
5.6 KiB
Go
package ui
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"time"
|
|
|
|
gemlog "git.travisshears.com/travisshears/gemlog-cli/gemlog"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
type Frontmatter struct {
|
|
Title string `yaml:"title"`
|
|
Date string `yaml:"date"`
|
|
Slug string `yaml:"slug"`
|
|
// Tags []string `yaml:"tags"`
|
|
}
|
|
|
|
// TODO: add edit command
|
|
func EditPostCMD(config *gemlog.Config, id string, rev string) tea.Cmd {
|
|
return func() tea.Msg {
|
|
gemlogEntry, err := gemlog.ReadGemlogEntry(config, id)
|
|
if err != nil {
|
|
return ErrorMsg{fmt.Errorf("failed to read gemlog entry: %w", err)}
|
|
}
|
|
|
|
// Create a temporary file
|
|
tmpFile, err := os.CreateTemp("/tmp", "gemlog-*.md")
|
|
if err != nil {
|
|
return ErrorMsg{fmt.Errorf("failed to create temporary file: %w", err)}
|
|
}
|
|
|
|
frontmatter := Frontmatter{
|
|
Title: gemlogEntry.Title,
|
|
Date: gemlogEntry.Date.Format("2006-01-02"),
|
|
Slug: gemlogEntry.Slug,
|
|
// Tags: []string{}, // or nil if empty is ok
|
|
}
|
|
yamlData, err := yaml.Marshal(&frontmatter)
|
|
if err != nil {
|
|
return ErrorMsg{fmt.Errorf("failed to marshal frontmatter: %w", err)}
|
|
}
|
|
|
|
initialContent := append(yamlData, []byte("---\n"+gemlogEntry.Gemtxt)...)
|
|
|
|
if _, err := tmpFile.Write(initialContent); err != nil {
|
|
tmpFile.Close()
|
|
os.Remove(tmpFile.Name())
|
|
return ErrorMsg{fmt.Errorf("failed to write initial content: %w", err)}
|
|
}
|
|
tmpFile.Close()
|
|
|
|
// Get the editor from environment variable, default to vim
|
|
editor := os.Getenv("EDITOR")
|
|
if editor == "" {
|
|
editor = "vim"
|
|
}
|
|
|
|
// Create the command to open the editor with the temp file
|
|
c := exec.Command(editor, tmpFile.Name()) //nolint:gosec
|
|
|
|
// Return tea.ExecProcess which will suspend the TUI and run the editor
|
|
return tea.ExecProcess(c, func(err error) tea.Msg {
|
|
defer os.Remove(tmpFile.Name()) // Clean up the temp file
|
|
|
|
if err != nil {
|
|
return ErrorMsg{fmt.Errorf("editor command failed: %w", err)}
|
|
}
|
|
|
|
// Read the contents of the file after editing
|
|
content, readErr := os.ReadFile(tmpFile.Name())
|
|
if readErr != nil {
|
|
return ErrorMsg{fmt.Errorf("failed to read file contents: %w", readErr)}
|
|
}
|
|
|
|
gemlogEntry, err := parsePost(string(content))
|
|
if err != nil {
|
|
return ErrorMsg{fmt.Errorf("failed to parse post: %w", err)}
|
|
}
|
|
if err := gemlog.UpdateGemlogEntry(config, &gemlogEntry, id, rev); err != nil {
|
|
return ErrorMsg{fmt.Errorf("failed to save gemlog entry: %w", err)}
|
|
}
|
|
|
|
// Return success with the content
|
|
return Notification(fmt.Sprintf("Post updated: \ngemini://travisshears.com/gemlog/%s\n\n", gemlogEntry.Slug))
|
|
})()
|
|
}
|
|
|
|
}
|
|
|
|
func WritePostCMD(config *gemlog.Config) tea.Cmd {
|
|
return func() tea.Msg {
|
|
// Create a temporary file
|
|
tmpFile, err := os.CreateTemp("/tmp", "gemlog-*.md")
|
|
if err != nil {
|
|
return ErrorMsg{fmt.Errorf("failed to create temporary file: %w", err)}
|
|
}
|
|
|
|
if _, err := tmpFile.Write([]byte(defaultTemplate)); err != nil {
|
|
tmpFile.Close()
|
|
os.Remove(tmpFile.Name())
|
|
return ErrorMsg{fmt.Errorf("failed to write initial content: %w", err)}
|
|
}
|
|
tmpFile.Close()
|
|
|
|
// Get the editor from environment variable, default to vim
|
|
editor := os.Getenv("EDITOR")
|
|
if editor == "" {
|
|
editor = "vim"
|
|
}
|
|
|
|
// Create the command to open the editor with the temp file
|
|
c := exec.Command(editor, tmpFile.Name()) //nolint:gosec
|
|
|
|
// Return tea.ExecProcess which will suspend the TUI and run the editor
|
|
return tea.ExecProcess(c, func(err error) tea.Msg {
|
|
defer os.Remove(tmpFile.Name()) // Clean up the temp file
|
|
|
|
if err != nil {
|
|
return ErrorMsg{fmt.Errorf("editor command failed: %w", err)}
|
|
}
|
|
|
|
// Read the contents of the file after editing
|
|
content, readErr := os.ReadFile(tmpFile.Name())
|
|
if readErr != nil {
|
|
return ErrorMsg{fmt.Errorf("failed to read file contents: %w", readErr)}
|
|
}
|
|
|
|
gemlogEntry, err := parsePost(string(content))
|
|
if err != nil {
|
|
return ErrorMsg{fmt.Errorf("failed to parse post: %w", err)}
|
|
}
|
|
if err := gemlog.SaveGemlogEntry(config, &gemlogEntry); err != nil {
|
|
return ErrorMsg{fmt.Errorf("failed to save gemlog entry: %w", err)}
|
|
}
|
|
|
|
// Return success with the content
|
|
return Notification(fmt.Sprintf("Post created: \ngemini://travisshears.com/gemlog/%s\n\n", gemlogEntry.Slug))
|
|
})()
|
|
}
|
|
}
|
|
|
|
func parsePost(post string) (gemlog.GemlogEntry, error) {
|
|
// split post on new lines
|
|
lines := strings.Split(post, "\n")
|
|
|
|
// Find the separator line "---"
|
|
separatorIndex := -1
|
|
for i, line := range lines {
|
|
if strings.TrimSpace(line) == "---" {
|
|
separatorIndex = i
|
|
break
|
|
}
|
|
}
|
|
|
|
if separatorIndex == -1 {
|
|
return gemlog.GemlogEntry{}, fmt.Errorf("no frontmatter separator '---' found")
|
|
}
|
|
|
|
// Extract frontmatter and body
|
|
frontmatterLines := lines[:separatorIndex]
|
|
bodyLines := lines[separatorIndex+1:]
|
|
|
|
// Parse frontmatter YAML
|
|
frontmatterYAML := strings.Join(frontmatterLines, "\n")
|
|
|
|
var frontmatter Frontmatter
|
|
|
|
if err := yaml.Unmarshal([]byte(frontmatterYAML), &frontmatter); err != nil {
|
|
return gemlog.GemlogEntry{}, fmt.Errorf("failed to parse frontmatter: %w", err)
|
|
}
|
|
|
|
// Parse date
|
|
date, err := time.Parse("2006-01-02", strings.TrimSpace(frontmatter.Date))
|
|
if err != nil {
|
|
return gemlog.GemlogEntry{}, fmt.Errorf("failed to parse date: %w", err)
|
|
}
|
|
|
|
// Parse tags (comma-separated)
|
|
// var tags []string
|
|
// if frontmatter.Tags != "" {
|
|
// tagParts := strings.Split(frontmatter.Tags, ",")
|
|
// for _, tag := range tagParts {
|
|
// trimmed := strings.TrimSpace(tag)
|
|
// if trimmed != "" {
|
|
// tags = append(tags, trimmed)
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// Join body lines
|
|
body := strings.Join(bodyLines, "\n")
|
|
|
|
return gemlog.GemlogEntry{
|
|
Title: frontmatter.Title,
|
|
Date: date,
|
|
Slug: frontmatter.Slug,
|
|
// Tags: tags,
|
|
Gemtxt: body,
|
|
}, nil
|
|
}
|