forked from rhysd/notes-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcategory.go
More file actions
146 lines (123 loc) · 3.47 KB
/
category.go
File metadata and controls
146 lines (123 loc) · 3.47 KB
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package notes
import (
"os"
"path/filepath"
"strings"
"github.com/pkg/errors"
)
// CategoryCollectMode customizes the behavior of how to collect categories
type CategoryCollectMode uint
const (
// OnlyFirstCategory is a flag to stop collecting categories earlier. If this flag is included
// in mode parameter of CollectCategories(), it collects only first category and only first
// note and stops finding anymore.
OnlyFirstCategory CategoryCollectMode = 1 << iota
)
// Category represents a category directory which contains some notes
type Category struct {
// Path is a path to the category directory
Path string
// Name is a name of category
Name string
// NotePaths are paths to notes of the category
NotePaths []string
}
// Notes returns all Note instances which belong to the category
func (cat *Category) Notes(c *Config) ([]*Note, error) {
notes := make([]*Note, 0, len(cat.NotePaths))
for _, p := range cat.NotePaths {
n, err := LoadNote(p, c)
if err != nil {
return nil, err
}
notes = append(notes, n)
}
return notes, nil
}
// Categories is a map from category name to Category instance
type Categories map[string]*Category
// Names returns all category names as slice
func (cats Categories) Names() []string {
ss := make([]string, 0, len(cats))
for n := range cats {
ss = append(ss, n)
}
return ss
}
// Notes returns all Note instances which belong to the categories
func (cats Categories) Notes(cfg *Config) ([]*Note, error) {
numNotes := 0
for _, c := range cats {
numNotes += len(c.NotePaths)
}
notes := make([]*Note, 0, numNotes)
for _, c := range cats {
for _, p := range c.NotePaths {
n, err := LoadNote(p, cfg)
if err != nil {
return nil, err
}
notes = append(notes, n)
}
}
return notes, nil
}
// CollectCategories collects all categories under home by default. The behavior of collecting categories
// can be customized with mode parameter. Default mode value is 0 (nothing specified).
func CollectCategories(cfg *Config, mode CategoryCollectMode) (Categories, error) {
cats := Categories(map[string]*Category{})
fs, err := os.ReadDir(cfg.HomePath)
if err != nil {
return nil, errors.Wrap(err, "Cannot read home")
}
stopWalking := false
for _, f := range fs {
name := f.Name()
if !f.IsDir() || strings.HasPrefix(name, ".") {
continue
}
root := filepath.Join(cfg.HomePath, name)
if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if stopWalking {
return filepath.SkipDir
}
if err != nil {
return err
}
path = normPathNFD(path)
name := info.Name()
if info.IsDir() {
if strings.HasPrefix(name, ".") {
return filepath.SkipDir
}
rel := strings.TrimPrefix(path, cfg.HomePath)
n := strings.TrimPrefix(filepath.ToSlash(rel), "/")
cats[n] = &Category{Name: n, Path: path}
return nil
}
if strings.HasPrefix(name, ".") || !strings.HasSuffix(name, ".md") {
return nil
}
rel := strings.TrimPrefix(filepath.Dir(path), cfg.HomePath)
cat := cats[strings.TrimPrefix(filepath.ToSlash(rel), "/")]
cat.NotePaths = append(cat.NotePaths, path)
if mode&OnlyFirstCategory != 0 {
stopWalking = true
return filepath.SkipDir
}
return nil
}); err != nil {
return nil, errors.Wrapf(err, "Cannot walk on directory for category %q", name)
}
if stopWalking {
break
}
}
// Remove category which has no note
for n, c := range cats {
if len(c.NotePaths) == 0 {
delete(cats, n)
}
}
return cats, nil
}