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
|
diff --git i/internal/bull/browse.go w/internal/bull/browse.go
index ea260e3..e207bfa 100644
--- i/internal/bull/browse.go
+++ w/internal/bull/browse.go
@@ -4,9 +4,12 @@ import (
"bytes"
"fmt"
"net/http"
+ "net/url"
+ "path"
"sort"
"strings"
"sync"
+ "time"
)
func (b *bullServer) browse(w http.ResponseWriter, r *http.Request) error {
@@ -31,8 +34,8 @@ func (b *bullServer) browse(w http.ResponseWriter, r *http.Request) error {
readg.Wait()
dir := r.FormValue("dir")
+ prefix := dir + "/"
if dir != "" {
- prefix := dir + "/"
filtered := make([]page, 0, len(pages))
for _, page := range pages {
if !strings.HasPrefix(page.FileName, prefix) {
@@ -77,6 +80,72 @@ func (b *bullServer) browse(w http.ResponseWriter, r *http.Request) error {
return fmt.Errorf("unknown ?sort parameter")
}
+ // collapse directory entries
+ seen := make(map[string]time.Time)
+ for _, pg := range pages {
+ pgdir := path.Dir(pg.PageName)
+ if pgdir == dir {
+ // do not hide any entries in the directory we are listing
+ continue
+ }
+ latest, ok := seen[pgdir]
+ if ok && latest.After(pg.ModTime) {
+ continue
+ }
+ seen[pgdir] = pg.ModTime
+ }
+ skip := func(rel string) (string, time.Time, bool) {
+ // Skip this directory if we have seen it or any of its parents.
+ var chomped string
+ for {
+ idx := strings.IndexByte(rel, '/')
+ if idx == -1 {
+ return "", time.Time{}, false
+ }
+ head := rel[:idx]
+ component := chomped + head
+ if latest, ok := seen[component]; ok {
+ return component, latest, true
+ }
+ chomped += head + "/"
+ rel = rel[idx+1:]
+ }
+ }
+ lines := make([]string, 0, len(pages))
+ for _, pg := range pages {
+ rel := strings.TrimPrefix(pg.PageName, prefix)
+ if strings.Contains(rel, "/") {
+ dir, latest, skip := skip(pg.PageName)
+ if skip && !latest.IsZero() {
+ // This is the first time we encounter a page within this
+ // directory, so produce an entry for the directory.
+ q := url.Values{
+ "dir": []string{dir},
+ "sort": []string{r.FormValue("sort")},
+ "sortorder": []string{sortorder},
+ }
+ target := (&url.URL{
+ Path: bullURLPrefix + "browse",
+ RawQuery: q.Encode(),
+ }).String()
+ line := fmt.Sprintf("| [%s/](%s) | %s |\n",
+ dir,
+ target,
+ latest.Format("2006-01-02 15:04:05 Z07:00"))
+ lines = append(lines, line)
+ seen[dir] = time.Time{} // still present, but printed
+ }
+ if skip {
+ continue
+ }
+ }
+
+ line := fmt.Sprintf("| [[%s]] | %s |\n",
+ pg.PageName,
+ pg.ModTime.Format("2006-01-02 15:04:05 Z07:00"))
+ lines = append(lines, line)
+ }
+
var buf bytes.Buffer
if dir != "" {
fmt.Fprintf(&buf, "# page browser: %s\n", dir)
@@ -86,10 +155,8 @@ func (b *bullServer) browse(w http.ResponseWriter, r *http.Request) error {
fmt.Fprintf(&buf, "| file name [↑](/_bull/browse?sort=pagename) [↓](/_bull/browse?sort=pagename&sortorder=desc) | last modified [↑](/_bull/browse?sort=modtime) [↓](/_bull/browse?sort=modtime&sortorder=desc) |\n")
fmt.Fprintf(&buf, "|-----------|---------------|\n")
// TODO: link to .. if dir != ""
- for _, pg := range pages {
- fmt.Fprintf(&buf, "| [[%s]] | %s |\n",
- pg.PageName,
- pg.ModTime.Format("2006-01-02 15:04:05 Z07:00"))
+ for _, line := range lines {
+ buf.Write([]byte(line))
}
return b.renderBullMarkdown(w, r, "browse", buf)
}
|