1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
package entry
import (
"errors"
"fmt"
"os"
"strings"
"time"
"codeberg.org/snonux/gos/internal/prompt"
"codeberg.org/snonux/gos/internal/timestamp"
)
type State int
const (
Unknown State = iota
Queued
Posted
)
func (s State) String() string {
switch s {
case Unknown:
return "unknown"
case Queued:
return "queued"
case Posted:
return "posted"
default:
panic(fmt.Sprintf("unknown state: %d", int(s)))
}
}
type Entry struct {
Path string
Time time.Time
State State
}
func (e Entry) String() string {
return fmt.Sprintf("Path:%s;Stamp:%s,State:%s",
e.Path, e.Time.Format(timestamp.Format), e.State)
}
var Zero = Entry{}
// filePath format: /foo/foobarbaz.something.here.txt.STAMP.{posted,queued}
func New(filePath string) (Entry, error) {
e := Entry{Path: filePath}
// We want to get the STAMP!
parts := strings.Split(filePath, ".")
if len(parts) < 4 {
return e, fmt.Errorf("not a valid entry path: %s", filePath)
}
switch parts[len(parts)-1] {
case "queued":
e.State = Queued
case "posted":
e.State = Posted
default:
return e, fmt.Errorf("can't parse state from path: %s", filePath)
}
var err error
if e.Time, err = timestamp.Parse(parts[len(parts)-2]); err != nil {
return e, err
}
if e.Time.Before(timestamp.OldestValidTime()) {
return e, fmt.Errorf("entry time does not seem legit, it is too old: %v", e.Time)
}
return e, nil
}
func (e Entry) Content() (string, error) {
bytes, err := os.ReadFile(e.Path)
if err != err {
return "", err
}
return strings.TrimSpace(string(bytes)), nil
}
func (e Entry) ContentWithLimit(sizeLimit int) (string, error) {
content, err := e.Content()
if err != nil {
return "", err
}
if len(content) > sizeLimit {
err := fmt.Errorf("entry content exceeds size limit: %d > %d: %v", len(content), sizeLimit, e)
if err2 := prompt.Acknowledge("You need to shorten the content as "+err.Error(), content); err2 != nil {
return "", errors.Join(err, err2)
}
if err2 := e.Edit(); err2 != nil {
return "", errors.Join(err, err2)
}
return e.ContentWithLimit(sizeLimit)
}
return content, nil
}
func (e *Entry) MarkPosted() error {
if e.State != Queued {
return errors.New("entry is not queued")
}
if e.State == Posted {
return errors.New("entry is already posted")
}
newPath, err := timestamp.UpdateInFilename(strings.TrimSuffix(e.Path, ".queued")+".posted", -2)
if err != nil {
return err
}
if err := os.Rename(e.Path, newPath); err != nil {
return err
}
e.State = Posted
return nil
}
func (e Entry) Edit() error {
if err := prompt.EditFile(e.Path); err != nil {
return err
}
return nil
}
|