org/internal/parser/writer.go

132 lines
3 KiB
Go

package parser
import (
"bufio"
"fmt"
"os"
"strings"
"github.com/rwejlgaard/org/internal/model"
)
// Save writes the org file back to disk
func Save(orgFile *model.OrgFile) error {
file, err := os.Create(orgFile.Path)
if err != nil {
return err
}
defer file.Close()
writer := bufio.NewWriter(file)
defer writer.Flush()
for _, item := range orgFile.Items {
if err := writeItem(writer, item); err != nil {
return err
}
}
return nil
}
// writeItem recursively writes an item and its children
func writeItem(writer *bufio.Writer, item *model.Item) error {
// Write heading
stars := strings.Repeat("*", item.Level)
line := stars
if item.State != model.StateNone {
line += " " + string(item.State)
}
if item.Priority != model.PriorityNone {
line += " [#" + string(item.Priority) + "]"
}
line += " " + item.Title + "\n"
if _, err := writer.WriteString(line); err != nil {
return err
}
// Write scheduling info if not already in notes
hasScheduled := false
hasDeadline := false
hasLogbook := false
hasProperties := false
for _, note := range item.Notes {
if strings.Contains(note, "SCHEDULED:") {
hasScheduled = true
}
if strings.Contains(note, "DEADLINE:") {
hasDeadline = true
}
if strings.Contains(note, ":LOGBOOK:") {
hasLogbook = true
}
if strings.Contains(note, ":PROPERTIES:") {
hasProperties = true
}
}
if item.Scheduled != nil && !hasScheduled {
scheduledLine := fmt.Sprintf("SCHEDULED: <%s>\n", FormatOrgDate(*item.Scheduled))
if _, err := writer.WriteString(scheduledLine); err != nil {
return err
}
}
if item.Deadline != nil && !hasDeadline {
deadlineLine := fmt.Sprintf("DEADLINE: <%s>\n", FormatOrgDate(*item.Deadline))
if _, err := writer.WriteString(deadlineLine); err != nil {
return err
}
}
// Write effort in :PROPERTIES: drawer if not already in notes
if item.Effort != "" && !hasProperties {
if _, err := writer.WriteString(":PROPERTIES:\n"); err != nil {
return err
}
effortLine := fmt.Sprintf(":EFFORT: %s\n", item.Effort)
if _, err := writer.WriteString(effortLine); err != nil {
return err
}
if _, err := writer.WriteString(":END:\n"); err != nil {
return err
}
}
// Write clock entries in :LOGBOOK: drawer if not already in notes
if len(item.ClockEntries) > 0 && !hasLogbook {
if _, err := writer.WriteString(":LOGBOOK:\n"); err != nil {
return err
}
for _, entry := range item.ClockEntries {
clockLine := fmt.Sprintf("CLOCK: [%s]", formatClockTimestamp(entry.Start))
if entry.End != nil {
clockLine += fmt.Sprintf("--[%s]", formatClockTimestamp(*entry.End))
}
clockLine += "\n"
if _, err := writer.WriteString(clockLine); err != nil {
return err
}
}
if _, err := writer.WriteString(":END:\n"); err != nil {
return err
}
}
// Write notes
for _, note := range item.Notes {
if _, err := writer.WriteString(note + "\n"); err != nil {
return err
}
}
// Write children
for _, child := range item.Children {
if err := writeItem(writer, child); err != nil {
return err
}
}
return nil
}