]> Sergey Matveev's repositories - sgblog.git/blobdiff - cmd/sgblog/gopher.go
Topics support
[sgblog.git] / cmd / sgblog / gopher.go
index 3cc50e1a62d978a5422bb34c784f95233c9df7a6..86fb5692d81ea055c8b16cf98aac7979007c267e 100644 (file)
@@ -40,21 +40,25 @@ import (
 const (
        TmplGopherMenu = `{{$CR := printf "\r"}}{{$CRLF := printf "\r\n" -}}
 {{- define "domainPort" }}     {{.GopherDomain}}       70{{end}}{{$Cfg := .Cfg -}}
-i{{.Cfg.Title}} ({{.Offset}}-{{.OffsetNext}})  err{{template "domainPort" .Cfg}}{{$CRLF -}}
+i{{.Cfg.Title}} {{if .Topic}}(topic: {{.Topic}}) {{end}}({{.Offset}}-{{.OffsetNext}})  err{{template "domainPort" .Cfg}}{{$CRLF -}}
 {{- if .Cfg.AboutURL}}hAbout   URL:{{.Cfg.AboutURL}}{{template "domainPort" .Cfg}}{{$CRLF}}{{end -}}
-{{- if .Offset}}1Prev  offset/{{.OffsetPrev}}{{template "domainPort" .Cfg}}{{$CRLF}}{{end -}}
-{{- if not .LogEnded}}1Next    offset/{{.OffsetNext}}{{template "domainPort" .Cfg}}{{$CRLF}}{{end -}}
+{{- if .Offset}}1Prev  {{if .Topic}}{{.Topic}}/{{end}}offset/{{.OffsetPrev}}{{template "domainPort" .Cfg}}{{$CRLF}}{{end -}}
+{{- if not .LogEnded}}1Next    {{if .Topic}}{{.Topic}}/{{end}}offset/{{.OffsetNext}}{{template "domainPort" .Cfg}}{{$CRLF}}{{end -}}
 {{- $datePrev := "0001-01-01" -}}
 {{- range .Entries -}}
 {{- $dateCur := .Commit.Author.When.Format "2006-01-02" -}}
 {{- if ne $dateCur $datePrev}}{{$datePrev = $dateCur}}
 i{{$dateCur}}  err{{template "domainPort" $Cfg}}{{$CR}}{{end}}
-0[{{.Commit.Author.When.Format "15:04"}}] {{.Title}} ({{.LinesNum}}L){{with .CommentsNum}} ({{.}}C){{end}}     /{{.Commit.Hash.String}}{{template "domainPort" $Cfg}}{{$CR}}{{end}}
+0[{{.Commit.Author.When.Format "15:04"}}] {{.Title}} ({{.LinesNum}}L){{with .CommentsNum}} ({{.}}C){{end}}{{if .Topics}}{{range .Topics}} {{.}}{{end}}{{end}}  /{{.Commit.Hash.String}}{{template "domainPort" $Cfg}}{{$CR}}{{end}}
+{{range .Topics}}
+1Topic: {{.}}  {{.}}/offset/0{{template "domainPort" $Cfg}}{{$CR}}{{end}}
 iGenerated by: SGBlog {{.Version}}     err{{template "domainPort" .Cfg}}{{$CR}}
 .{{$CRLF}}`
        TmplGopherEntry = `What: {{.Commit.Hash.String}}
 When: {{.When}}
 ------------------------------------------------------------------------
+{{if .Topics}}Topics:{{range .Topics}} {{.}}{{end}}{{end}}
+------------------------------------------------------------------------
 {{.Commit.Message -}}
 {{- if .Note}}
 ------------------------------------------------------------------------
@@ -78,6 +82,7 @@ type TableMenuEntry struct {
        Title       string
        LinesNum    int
        CommentsNum int
+       Topics      []string
 }
 
 func serveGopher() {
@@ -115,8 +120,47 @@ func serveGopher() {
        if selector == "" {
                selector = "offset/0"
        }
-       if strings.HasPrefix(selector, "offset/") {
-               offset, err := strconv.Atoi(selector[len("offset/"):])
+       selectorParts := strings.Split(selector, "/")
+       if strings.HasPrefix(selector, "URL:") {
+               selector = selector[len("URL:"):]
+               fmt.Printf(`<html>
+<head>
+       <meta http-equiv="Refresh" content="1; url=%s" />
+       <title>Redirect to non-gopher URL</title>
+</head>
+<body>
+Redirecting to <a href="%s">%s</a>...
+</body>
+</html>
+`, selector, selector, selector)
+       } else if sha1DigestRe.MatchString(selector) {
+               commit, err := repo.CommitObject(plumbing.NewHash(selector[1:]))
+               if err != nil {
+                       log.Fatalln(err)
+               }
+               tmpl := template.Must(template.New("entry").Parse(TmplGopherEntry))
+               err = tmpl.Execute(os.Stdout, struct {
+                       Commit   *object.Commit
+                       When     string
+                       Cfg      *Cfg
+                       Note     string
+                       Comments []string
+                       Topics   []string
+                       Version  string
+               }{
+                       Commit:   commit,
+                       When:     commit.Author.When.Format(sgblog.WhenFmt),
+                       Cfg:      cfg,
+                       Note:     string(getNote(notesTree, commit.Hash)),
+                       Comments: parseComments(getNote(commentsTree, commit.Hash)),
+                       Topics:   parseTopics(getNote(topicsTree, commit.Hash)),
+                       Version:  sgblog.Version,
+               })
+               if err != nil {
+                       log.Fatalln(err)
+               }
+       } else if selectorParts[len(selectorParts)-2] == "offset" {
+               offset, err := strconv.Atoi(selectorParts[len(selectorParts)-1])
                if err != nil {
                        log.Fatalln(err)
                }
@@ -124,15 +168,42 @@ func serveGopher() {
                if err != nil {
                        log.Fatalln(err)
                }
-               for i := 0; i < offset; i++ {
-                       if _, err = repoLog.Next(); err != nil {
-                               break
+               topicsCache, err := getTopicsCache(cfg, repoLog)
+               if err != nil {
+                       log.Fatalln(err)
+               }
+               repoLog, err = repo.Log(&git.LogOptions{From: *headHash})
+               if err != nil {
+                       log.Fatalln(err)
+               }
+
+               var topic string
+               if len(selectorParts) == 3 {
+                       topic = selectorParts[0]
+               }
+               var commits CommitIterNext
+               if topic == "" {
+                       for i := 0; i < offset; i++ {
+                               if _, err = repoLog.Next(); err != nil {
+                                       break
+                               }
                        }
+                       commits = repoLog
+               } else {
+                       hashes := topicsCache[topic]
+                       if hashes == nil {
+                               log.Fatalln(errors.New("no posts with that topic"))
+                       }
+                       if len(hashes) > offset {
+                               hashes = hashes[offset:]
+                       }
+                       commits = &HashesIter{hashes}
                }
+
                logEnded := false
                entries := make([]TableMenuEntry, 0, PageEntries)
                for i := 0; i < PageEntries; i++ {
-                       commit, err := repoLog.Next()
+                       commit, err := commits.Next()
                        if err != nil {
                                logEnded = true
                                break
@@ -143,65 +214,38 @@ func serveGopher() {
                                Title:       lines[0],
                                LinesNum:    len(lines) - 2,
                                CommentsNum: len(parseComments(getNote(commentsTree, commit.Hash))),
+                               Topics:      parseTopics(getNote(topicsTree, commit.Hash)),
                        })
                }
                tmpl := template.Must(template.New("menu").Parse(TmplGopherMenu))
+               offsetPrev := offset - PageEntries
+               if offsetPrev < 0 {
+                       offsetPrev = 0
+               }
                err = tmpl.Execute(os.Stdout, struct {
                        Cfg        *Cfg
+                       Topic      string
                        Offset     int
                        OffsetPrev int
                        OffsetNext int
                        LogEnded   bool
                        Entries    []TableMenuEntry
+                       Topics     []string
                        Version    string
                }{
                        Cfg:        cfg,
+                       Topic:      topic,
                        Offset:     offset,
-                       OffsetPrev: offset - PageEntries,
+                       OffsetPrev: offsetPrev,
                        OffsetNext: offset + PageEntries,
                        LogEnded:   logEnded,
                        Entries:    entries,
+                       Topics:     topicsCache.Topics(),
                        Version:    sgblog.Version,
                })
                if err != nil {
                        log.Fatalln(err)
                }
-       } else if strings.HasPrefix(selector, "URL:") {
-               selector = selector[len("URL:"):]
-               fmt.Printf(`<html>
-<head>
-       <meta http-equiv="Refresh" content="1; url=%s" />
-       <title>Redirect to non-gopher URL</title>
-</head>
-<body>
-Redirecting to <a href="%s">%s</a>...
-</body>
-</html>
-`, selector, selector, selector)
-       } else if sha1DigestRe.MatchString(selector) {
-               commit, err := repo.CommitObject(plumbing.NewHash(selector[1:]))
-               if err != nil {
-                       log.Fatalln(err)
-               }
-               tmpl := template.Must(template.New("entry").Parse(TmplGopherEntry))
-               err = tmpl.Execute(os.Stdout, struct {
-                       Commit   *object.Commit
-                       When     string
-                       Cfg      *Cfg
-                       Note     string
-                       Comments []string
-                       Version  string
-               }{
-                       Commit:   commit,
-                       When:     commit.Author.When.Format(sgblog.WhenFmt),
-                       Cfg:      cfg,
-                       Note:     string(getNote(notesTree, commit.Hash)),
-                       Comments: parseComments(getNote(commentsTree, commit.Hash)),
-                       Version:  sgblog.Version,
-               })
-               if err != nil {
-                       log.Fatalln(err)
-               }
        } else {
                log.Fatalln(errors.New("unknown selector"))
        }