https://go.dev/doc/modules/layout This also enables us to later import just the db interaction part say to the gemini capsule backend go project.
141 lines
3.7 KiB
Go
141 lines
3.7 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"
|
|
)
|
|
|
|
// TODO: add edit command
|
|
// func EditPostCMD(config *gemlog.Config) tea.Cmd {}
|
|
|
|
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)}
|
|
}
|
|
|
|
// Load initial content from template file
|
|
initialContent, err := os.ReadFile("templates/default_post.gmi")
|
|
if err != nil {
|
|
tmpFile.Close()
|
|
os.Remove(tmpFile.Name())
|
|
return ErrorMsg{fmt.Errorf("failed to read template file: %w", err)}
|
|
}
|
|
|
|
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.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 struct {
|
|
Title string `yaml:"title"`
|
|
Date string `yaml:"date"`
|
|
Slug string `yaml:"slug"`
|
|
Tags string `yaml:"tags"`
|
|
}
|
|
|
|
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
|
|
}
|