From: Sergey Matveev Date: Sun, 26 Jul 2020 22:48:17 +0000 (+0300) Subject: Use templates for code simplicity X-Git-Tag: v0.7.0^0 X-Git-Url: http://www.git.stargrave.org/?p=sgblog.git;a=commitdiff_plain;h=236718b29541b104d68cb2a95693a99529ffa7dc Use templates for code simplicity --- diff --git a/cmd/sgblog/gopher.go b/cmd/sgblog/gopher.go index 1e3eb72..d8e4fe4 100644 --- a/cmd/sgblog/gopher.go +++ b/cmd/sgblog/gopher.go @@ -19,7 +19,6 @@ package main import ( "bufio" - "bytes" "encoding/json" "errors" "fmt" @@ -29,20 +28,54 @@ import ( "os" "strconv" "strings" - "time" + "text/template" "github.com/hjson/hjson-go" "go.stargrave.org/sgblog" "gopkg.in/src-d/go-git.v4" "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/plumbing/object" ) -const CRLF = "\r\n" - -var DashLine = strings.Repeat("-", 72) +const ( + TmplGopherMenu = `{{$Cfg := .Cfg}}{{$CR := .CR}}i{{.Cfg.Title}} ({{.Offset}}-{{.OffsetNext}}) err {{.Cfg.GopherDomain}} 70{{.CR}} +{{if .Cfg.AboutURL}}hAbout URL:{{.Cfg.AboutURL}} {{.Cfg.GopherDomain}} 70{{.CR}}{{end}} +{{if .Offset}}1Prev offset/{{.OffsetPrev}} {{.Cfg.GopherDomain}} 70{{.CR}}{{end}} +{{if not .LogEnded}}1Next offset/{{.OffsetNext}} {{.Cfg.GopherDomain}} 70{{.CR}}{{end -}} +{{- $yearPrev := 0}}{{$monthPrev := 0}}{{$dayPrev := 0 -}} +{{- range .Entries }}{{$yearCur := .Commit.Author.When.Year}}{{$monthCur := .Commit.Author.When.Month}}{{$dayCur := .Commit.Author.When.Day -}} +{{- if or (ne $dayCur $dayPrev) (ne $monthCur $monthPrev) (ne $yearCur $yearPrev)}}{{$dayPrev = $dayCur}}{{$monthPrev = $monthCur}}{{$yearPrev = $yearCur}} +i{{$yearCur | printf "%04d"}}-{{$monthCur | printf "%02d"}}-{{$dayCur | printf "%02d"}} err {{$Cfg.GopherDomain}} 70{{$CR}}{{end}} +0[{{.Commit.Author.When.Hour | printf "%02d"}}:{{.Commit.Author.When.Minute | printf "%02d"}}] {{.Title}} ({{.LinesNum}}L){{if .CommentsNum}} ({{.CommentsNum}}C){{end}} /{{.Commit.Hash.String}} {{$Cfg.GopherDomain}} 70{{$CR}}{{end}} +iGenerated by: SGBlog {{.Version}} err {{.Cfg.GopherDomain}} 70{{.CR}} +.{{.CR}} +` + TmplGopherEntry = `What: {{.Commit.Hash.String}} +When: {{.When}} +------------------------------------------------------------------------ +{{.Commit.Message -}} +{{- if .Note}} +------------------------------------------------------------------------ +Note: +{{.Note}}{{end -}} +{{- if .Cfg.CommentsEmail}} +------------------------------------------------------------------------ +leave comment: mailto:{{.Cfg.CommentsEmail}}?subject={{.Commit.Hash.String}} +{{end}}{{range $idx, $comment := .Comments}} +------------------------------------------------------------------------ +comment {{$idx}}: +{{$comment}} +{{end}} +------------------------------------------------------------------------ +Generated by: SGBlog {{.Version}} +` +) -func makeI(cfg *Cfg, value string) string { - return strings.Join([]string{"i" + value, "err", cfg.GopherDomain, "70", CRLF}, "\t") +type TableMenuEntry struct { + Commit *object.Commit + Title string + LinesNum int + CommentsNum int } func serveGopher() { @@ -89,79 +122,50 @@ func serveGopher() { if err != nil { log.Fatalln(err) } - commitN := 0 for i := 0; i < offset; i++ { if _, err = repoLog.Next(); err != nil { break } - commitN++ } - logEnded := false - var menu bytes.Buffer - var yearPrev int - var monthPrev time.Month - var dayPrev int + entries := make([]TableMenuEntry, 0, PageEntries) for i := 0; i < PageEntries; i++ { commit, err := repoLog.Next() if err != nil { logEnded = true break } - yearCur, monthCur, dayCur := commit.Author.When.Date() - if dayCur != dayPrev || monthCur != monthPrev || yearCur != yearPrev { - menu.WriteString(makeI(cfg, fmt.Sprintf( - "%04d-%02d-%02d", yearCur, monthCur, dayCur, - ))) - yearPrev, monthPrev, dayPrev = yearCur, monthCur, dayCur - } - commitN++ lines := msgSplit(commit.Message) - var commentsValue string - if l := len(parseComments(getNote(commentsTree, commit.Hash))); l > 0 { - commentsValue = fmt.Sprintf(" (%dC)", l) - } - menu.WriteString(fmt.Sprintf( - "0[%02d:%02d] %s (%dL)%s\t/%s\t%s\t%d%s", - commit.Author.When.Hour(), - commit.Author.When.Minute(), - lines[0], - len(lines)-2, - commentsValue, - commit.Hash.String(), - cfg.GopherDomain, 70, CRLF, - )) - } - - fmt.Print(makeI(cfg, fmt.Sprintf("%s (%d-%d)", cfg.Title, offset, offset+PageEntries))) - if cfg.AboutURL != "" { - fmt.Printf( - "hAbout\tURL:%s\t%s\t%d%s", - cfg.AboutURL, - cfg.GopherDomain, 70, CRLF, - ) + entries = append(entries, TableMenuEntry{ + Commit: commit, + Title: lines[0], + LinesNum: len(lines) - 2, + CommentsNum: len(parseComments(getNote(commentsTree, commit.Hash))), + }) } - if offset > 0 { - offsetPrev := offset - PageEntries - if offsetPrev < 0 { - offsetPrev = 0 - } - fmt.Printf( - "1Prev\toffset/%d\t%s\t%d%s", - offsetPrev, - cfg.GopherDomain, 70, CRLF, - ) - } - if !logEnded { - fmt.Printf( - "1Next\toffset/%d\t%s\t%d%s", - offset+PageEntries, - cfg.GopherDomain, 70, CRLF, - ) + tmpl := template.Must(template.New("menu").Parse(TmplGopherMenu)) + err = tmpl.Execute(os.Stdout, struct { + Cfg *Cfg + Offset int + OffsetPrev int + OffsetNext int + LogEnded bool + Entries []TableMenuEntry + Version string + CR string + }{ + Cfg: cfg, + Offset: offset, + OffsetPrev: offset - PageEntries, + OffsetNext: offset + PageEntries, + LogEnded: logEnded, + Entries: entries, + Version: sgblog.Version, + CR: "\r", + }) + if err != nil { + log.Fatalln(err) } - fmt.Print(menu.String()) - fmt.Printf(makeI(cfg, "Generated by: SGBlog "+sgblog.Version)) - fmt.Print("." + CRLF) } else if strings.HasPrefix(selector, "URL:") { selector = selector[len("URL:"):] fmt.Printf(` @@ -179,29 +183,25 @@ Redirecting to %s... if err != nil { log.Fatalln(err) } - fmt.Printf( - "What: %s\nWhen: %s\n%s\n%s", - commit.Hash.String(), - commit.Author.When.Format(sgblog.WhenFmt), - DashLine, - commit.Message, - ) - notesRaw := getNote(notesTree, commit.Hash) - if len(notesRaw) > 0 { - fmt.Printf("%s\nNote:\n%s\n", DashLine, string(notesRaw)) - } - if cfg.CommentsEmail != "" { - fmt.Printf( - "%s\nleave comment: mailto:%s?subject=%s\n", - DashLine, - cfg.CommentsEmail, - commit.Hash.String(), - ) - } - for i, comment := range parseComments(getNote(commentsTree, commit.Hash)) { - fmt.Printf("%s\ncomment %d:\n%s\n", DashLine, i, comment) + 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) } - fmt.Printf("%s\nGenerated by: SGBlog %s\n", DashLine, sgblog.Version) } else { log.Fatalln(errors.New("unknown selector")) } diff --git a/cmd/sgblog/http.go b/cmd/sgblog/http.go index a4ad671..0c09f2b 100644 --- a/cmd/sgblog/http.go +++ b/cmd/sgblog/http.go @@ -35,7 +35,7 @@ import ( "os" "strconv" "strings" - "time" + "text/template" "github.com/hjson/hjson-go" "go.stargrave.org/sgblog" @@ -49,11 +49,106 @@ import ( const ( AtomPostsFeed = "feed.atom" AtomCommentsFeed = "comments.atom" + TmplHTMLIndex = ` + + + + {{.Cfg.Title}} ({{.Offset}}-{{.OffsetNext}}) + {{if .Cfg.CSS}}{{end}} + {{if .Cfg.Webmaster}}{{end -}} + {{- range .Cfg.GitURLs}} + {{end}} + + + {{if .CommentsEnabled}}{{end}} + {{if .Offset}}{{end}} + {{if not .LogEnded}}{{end}} + + +{{if .Cfg.AboutURL}}[about]{{end}} +{{block "links" .}} +{{if .Offset}}[prev]{{end}} +{{if not .LogEnded}}[next]{{end}} +{{end}} +{{- $Cfg := .Cfg -}} +{{- $yearPrev := 0 -}} +{{- $monthPrev := 0 -}} +{{- $dayPrev := 0}} + + + + + + +{{range .Entries -}} +{{- $yearCur := .Commit.Author.When.Year -}} +{{- $monthCur := .Commit.Author.When.Month -}} +{{- $dayCur := .Commit.Author.When.Day -}} +{{- if or (ne $dayCur $dayPrev) (ne $monthCur $monthPrev) (ne $yearCur $yearPrev) -}} + +{{- $dayPrev = $dayCur}}{{$monthPrev = $monthCur}}{{$yearPrev = $yearCur -}} +{{- end -}} + + + + + + + + +{{- end}}
NWhenTitleLCLinked to
{{$yearCur | printf "%04d"}}-{{$monthCur | printf "%02d"}}-{{$dayCur | printf "%02d"}}
{{.Num}}{{.Commit.Author.When.Hour | printf "%02d" -}}:{{- .Commit.Author.When.Minute | printf "%02d"}}{{.Title}}{{.LinesNum}}{{if .CommentsNum}}{{.CommentsNum}}{{else}} {{end}}{{range .DomainURLs}} {{.}} {{end}}
+{{template "links" .}} + + +` + TmplHTMLEntry = `{{$Cfg := .Cfg}} + + + + {{.Title}} ({{.When}}) + {{if .Cfg.CSS}}{{end}} + {{if .Cfg.Webmaster}}{{end -}} + {{- range .Cfg.GitURLs}} + {{end}} + + + {{if .Parent}}{{end}} + + +{{if .Cfg.AboutURL}}[about]{{end}} +[index] +{{if .Parent}}[prev]{{end}} +[{{.When}}] +[{{.Commit.Hash.String}}] + +
+

{{.Title}}

+
+{{range .Lines}}{{. | lineURLize $Cfg.URLPrefix}}
+{{end}}
+
+ +{{if .NoteLines}}Note:
+{{range .NoteLines}}{{. | lineURLize $Cfg.URLPrefix}}
+{{end}}
+
{{end}} + +{{if .Cfg.CommentsEmail}}[leave comment]{{end}} + +
{{range $idx, $comment := .Comments}} +
comment {{$idx}}:
+
+{{range $comment.HeaderLines}}{{.}}
+{{end}}{{range $comment.BodyLines}}{{. | lineURLize $Cfg.URLPrefix}}
+{{end}}
+{{end}}
+ + + +` ) var ( - defaultLinks = []string{} - renderableSchemes = map[string]struct{}{ "ftp": struct{}{}, "gopher": struct{}{}, @@ -64,8 +159,18 @@ var ( ) type TableEntry struct { - commit *object.Commit - commentsRaw []byte + Commit *object.Commit + CommentsRaw []byte + Num int + Title string + LinesNum int + CommentsNum int + DomainURLs []string +} + +type CommentEntry struct { + HeaderLines []string + BodyLines []string } func makeA(href, text string) string { @@ -92,13 +197,15 @@ func lineURLize(urlPrefix, line string) string { cols[i] = makeA(col, col) continue } - cols[i] = sha1DigestRe.ReplaceAllString(col, makeA( - urlPrefix+"/$1", "$1", - )) + cols[i] = sha1DigestRe.ReplaceAllString(col, makeA(urlPrefix+"/$1", "$1")) } return strings.Join(cols, " ") } +func lineURLizeInTemplate(urlPrefix, line interface{}) string { + return lineURLize(urlPrefix.(string), line.(string)) +} + func startHeader(etag hash.Hash, gziped bool) string { lines := []string{ "Content-Type: text/html; charset=UTF-8", @@ -112,21 +219,6 @@ func startHeader(etag hash.Hash, gziped bool) string { return strings.Join(lines, "\n") } -func startHTML(title string, additional []string) string { - return fmt.Sprintf(` - - - - %s - %s - - -`, - sgblog.Version, title, - strings.Join(append(defaultLinks, additional...), "\n "), - ) -} - func makeErr(err error) { fmt.Print("Content-Type: text/plain; charset=UTF-8\n\n") fmt.Println(err) @@ -182,43 +274,32 @@ func serveHTTP() { if err != nil { panic(err) } - etagHash.Write([]byte("SGBLOG")) - etagHash.Write([]byte(sgblog.Version)) - etagHash.Write([]byte(cfg.GitPath)) - etagHash.Write([]byte(cfg.Branch)) - etagHash.Write([]byte(cfg.Title)) - etagHash.Write([]byte(cfg.URLPrefix)) - etagHash.Write([]byte(cfg.AtomBaseURL)) - etagHash.Write([]byte(cfg.AtomId)) - etagHash.Write([]byte(cfg.AtomAuthor)) - - etagHashForWeb := [][]byte{} - if cfg.CSS != "" { - defaultLinks = append(defaultLinks, ``) - etagHashForWeb = append(etagHashForWeb, []byte(cfg.CSS)) - } - if cfg.Webmaster != "" { - defaultLinks = append(defaultLinks, ``) - etagHashForWeb = append(etagHashForWeb, []byte(cfg.Webmaster)) + for _, s := range []string{ + "SGBLOG", + sgblog.Version, + cfg.GitPath, + cfg.Branch, + cfg.Title, + cfg.URLPrefix, + cfg.AtomBaseURL, + cfg.AtomId, + cfg.AtomAuthor, + } { + if _, err = etagHash.Write([]byte(s)); err != nil { + panic(err) + } } - if cfg.AboutURL != "" { - etagHashForWeb = append(etagHashForWeb, []byte(cfg.AboutURL)) + etagHashForWeb := []string{ + cfg.CSS, + cfg.Webmaster, + cfg.AboutURL, + cfg.CommentsNotesRef, + cfg.CommentsEmail, } for _, gitURL := range cfg.GitURLs { - defaultLinks = append(defaultLinks, ``) - etagHashForWeb = append(etagHashForWeb, []byte(gitURL)) - } - if cfg.CommentsNotesRef != "" { - etagHashForWeb = append(etagHashForWeb, []byte(cfg.CommentsNotesRef)) - } - if cfg.CommentsEmail != "" { - etagHashForWeb = append(etagHashForWeb, []byte(cfg.CommentsEmail)) + etagHashForWeb = append(etagHashForWeb, gitURL) } - defaultLinks = append(defaultLinks, ``) - atomPostsURL := cfg.AtomBaseURL + cfg.URLPrefix + "/" + AtomPostsFeed - atomCommentsURL := cfg.AtomBaseURL + cfg.URLPrefix + "/" + AtomCommentsFeed - headHash, err := initRepo(cfg) if err != nil { makeErr(err) @@ -283,7 +364,7 @@ func serveHTTP() { entries := make([]TableEntry, 0, PageEntries) logEnded := false for _, data := range etagHashForWeb { - etagHash.Write(data) + etagHash.Write([]byte(data)) } etagHash.Write([]byte("INDEX")) for i := 0; i < PageEntries; i++ { @@ -295,96 +376,57 @@ func serveHTTP() { etagHash.Write(commit.Hash[:]) commentsRaw := getNote(commentsTree, commit.Hash) etagHash.Write(commentsRaw) - entries = append(entries, TableEntry{commit, commentsRaw}) + entries = append(entries, TableEntry{ + Commit: commit, + CommentsRaw: commentsRaw, + }) } checkETag(etagHash) - var table bytes.Buffer - table.WriteString( - "\n" + - "" + - "" + - "" + - `` + - `` + - "\n") - var yearPrev int - var monthPrev time.Month - var dayPrev int - for _, entry := range entries { - yearCur, monthCur, dayCur := entry.commit.Author.When.Date() - if dayCur != dayPrev || monthCur != monthPrev || yearCur != yearPrev { - table.WriteString(fmt.Sprintf( - "\n", - yearCur, monthCur, dayCur, - )) - yearPrev, monthPrev, dayPrev = yearCur, monthCur, dayCur - } + for i, entry := range entries { commitN++ - lines := msgSplit(entry.commit.Message) - domains := []string{} + entry.Num = commitN + lines := msgSplit(entry.Commit.Message) + entry.Title = lines[0] + entry.LinesNum = len(lines) - 2 for _, line := range lines[2:] { - if u := urlParse(line); u == nil { + u := urlParse(line) + if u == nil { break - } else { - domains = append(domains, makeA(line, u.Host)) } + entry.DomainURLs = append(entry.DomainURLs, makeA(line, u.Host)) } - var commentsValue string - if l := len(parseComments(entry.commentsRaw)); l > 0 { - commentsValue = strconv.Itoa(l) - } else { - commentsValue = " " - } - table.WriteString(fmt.Sprintf( - ""+ - ""+ - ""+ - "\n", - commitN, - entry.commit.Author.When.Hour(), - entry.commit.Author.When.Minute(), - makeA(cfg.URLPrefix+"/"+entry.commit.Hash.String(), lines[0]), - len(lines)-2, - commentsValue, - strings.Join(domains, " "), - )) + entry.CommentsNum = len(parseComments(entry.CommentsRaw)) + entries[i] = entry } - table.WriteString("
NWhenTitleLCLinked to
%04d-%02d-%02d
%d%02d:%02d%s%d%s%s
") - - var href string - links := []string{``} - var refs bytes.Buffer - if commentsTree != nil { - links = append(links, ``) - } - if offset > 0 { - if offsetPrev := offset - PageEntries; offsetPrev > 0 { - href = cfg.URLPrefix + "/?offset=" + strconv.Itoa(offsetPrev) - } else { - href = cfg.URLPrefix + "/" - } - links = append(links, ``) - refs.WriteString("\n" + makeA(href, "[prev]")) - } - if !logEnded { - href = cfg.URLPrefix + "/?offset=" + strconv.Itoa(offset+PageEntries) - links = append(links, ``) - refs.WriteString("\n" + makeA(href, "[next]")) - } - + tmpl := template.Must(template.New("index").Parse(TmplHTMLIndex)) os.Stdout.Write([]byte(startHeader(etagHash, gzipWriter != nil))) - out.Write([]byte(startHTML( - fmt.Sprintf("%s (%d-%d)", cfg.Title, offset, offset+PageEntries), - links, - ))) - if cfg.AboutURL != "" { - out.Write([]byte(fmt.Sprintf("[%s]", makeA(cfg.AboutURL, "about")))) + err = tmpl.Execute(out, struct { + Version string + Cfg *Cfg + CommentsEnabled bool + AtomPostsFeed string + AtomCommentsFeed string + Offset int + OffsetPrev int + OffsetNext int + LogEnded bool + Entries []TableEntry + }{ + Version: sgblog.Version, + Cfg: cfg, + CommentsEnabled: commentsTree != nil, + AtomPostsFeed: AtomPostsFeed, + AtomCommentsFeed: AtomCommentsFeed, + Offset: offset, + OffsetPrev: offset - PageEntries, + OffsetNext: offset + PageEntries, + LogEnded: logEnded, + Entries: entries, + }) + if err != nil { + makeErr(err) } - out.Write(refs.Bytes()) - out.Write(table.Bytes()) - out.Write(refs.Bytes()) - out.Write([]byte("\n")) } else if pathInfo == "/"+AtomPostsFeed { commit, err := repo.CommitObject(*headHash) if err != nil { @@ -397,8 +439,11 @@ func serveHTTP() { Title: cfg.Title, ID: cfg.AtomId, Updated: atom.Time(commit.Author.When), - Link: []atom.Link{{Rel: "self", Href: atomPostsURL}}, - Author: &atom.Person{Name: cfg.AtomAuthor}, + Link: []atom.Link{{ + Rel: "self", + Href: cfg.AtomBaseURL + cfg.URLPrefix + "/" + AtomPostsFeed, + }}, + Author: &atom.Person{Name: cfg.AtomAuthor}, } repoLog, err := repo.Log(&git.LogOptions{From: *headHash}) if err != nil { @@ -450,8 +495,11 @@ func serveHTTP() { Title: cfg.Title + " comments", ID: "urn:uuid:" + bytes2uuid(idHasher.Sum(nil)), Updated: atom.Time(commit.Author.When), - Link: []atom.Link{{Rel: "self", Href: atomCommentsURL}}, - Author: &atom.Person{Name: cfg.AtomAuthor}, + Link: []atom.Link{{ + Rel: "self", + Href: cfg.AtomBaseURL + cfg.URLPrefix + "/" + AtomCommentsFeed, + }}, + Author: &atom.Person{Name: cfg.AtomAuthor}, } repoLog, err := repo.Log(&git.LogOptions{From: commentsRef.Hash()}) if err != nil { @@ -490,11 +538,10 @@ func serveHTTP() { idHasher.Write(commit.Hash[:]) idHasher.Write([]byte(commentN)) feed.Entry = append(feed.Entry, &atom.Entry{ - Title: strings.Join([]string{ - "Comment ", commentN, - " for \"", msgSplit(commit.Message)[0], - "\" by ", from, - }, ""), + Title: fmt.Sprintf( + "Comment %s for \"%s\" by %s", + commentN, msgSplit(commit.Message)[0], from, + ), Author: &atom.Person{Name: from}, ID: "urn:uuid:" + bytes2uuid(idHasher.Sum(nil)), Link: []atom.Link{{ @@ -524,11 +571,11 @@ func serveHTTP() { makeErr(err) } for _, data := range etagHashForWeb { - etagHash.Write(data) + etagHash.Write([]byte(data)) } etagHash.Write([]byte("ENTRY")) etagHash.Write(commit.Hash[:]) - atomCommentsURL = strings.Join([]string{ + atomCommentsURL := strings.Join([]string{ cfg.AtomBaseURL, cfg.URLPrefix, "/", commit.Hash.String(), "/", AtomCommentsFeed, }, "") @@ -583,10 +630,7 @@ func serveHTTP() { idHasher.Write(commit.Hash[:]) idHasher.Write([]byte(comment.n)) feed.Entry = append(feed.Entry, &atom.Entry{ - Title: strings.Join([]string{ - "Comment", comment.n, - "by", comment.from, - }, " "), + Title: fmt.Sprintf("Comment %s by %s", comment.n, comment.from), Author: &atom.Person{Name: comment.from}, ID: "urn:uuid:" + bytes2uuid(idHasher.Sum(nil)), Link: []atom.Link{{ @@ -616,64 +660,55 @@ func serveHTTP() { notesRaw := getNote(notesTree, commit.Hash) etagHash.Write(notesRaw) checkETag(etagHash) + lines := msgSplit(commit.Message) title := lines[0] when := commit.Author.When.Format(sgblog.WhenFmt) - os.Stdout.Write([]byte(startHeader(etagHash, gzipWriter != nil))) - links := []string{``} var parent string if len(commit.ParentHashes) > 0 { parent = commit.ParentHashes[0].String() - links = append(links, ``) - } - out.Write([]byte(startHTML(fmt.Sprintf("%s (%s)", title, when), links))) - if cfg.AboutURL != "" { - out.Write([]byte(fmt.Sprintf("[%s]\n", makeA(cfg.AboutURL, "about")))) - } - out.Write([]byte(fmt.Sprintf("[%s]\n", makeA(cfg.URLPrefix+"/", "index")))) - if parent != "" { - out.Write([]byte(fmt.Sprintf("[%s]\n", makeA(cfg.URLPrefix+"/"+parent, "prev")))) } - out.Write([]byte(fmt.Sprintf( - "[%s]\n"+ - "[%s]\n"+ - "
\n

%s

\n
\n",
-			when, commit.Hash.String(), title,
-		)))
-		for _, line := range lines[2:] {
-			out.Write([]byte(lineURLize(cfg.URLPrefix, line) + "\n"))
+		commentsParsed := parseComments(commentsRaw)
+		comments := make([]CommentEntry, 0, len(commentsParsed))
+		for _, comment := range commentsParsed {
+			lines := strings.Split(comment, "\n")
+			comments = append(comments, CommentEntry{lines[:3], lines[3:]})
 		}
-		out.Write([]byte("
\n
\n")) + var notesLines []string if len(notesRaw) > 0 { - out.Write([]byte("Note:
\n"))
-			for _, line := range strings.Split(string(notesRaw), "\n") {
-				out.Write([]byte(lineURLize(cfg.URLPrefix, line) + "\n"))
-			}
-			out.Write([]byte("
\n
\n")) - } - if cfg.CommentsEmail != "" { - out.Write([]byte("[" + makeA( - "mailto:"+cfg.CommentsEmail+"?subject="+commit.Hash.String(), - "leave comment", - ) + "]\n")) + notesLines = strings.Split(string(notesRaw), "\n") } - out.Write([]byte("
\n")) - for i, comment := range parseComments(commentsRaw) { - out.Write([]byte(fmt.Sprintf( - "
comment %d:"+ - "
\n
\n",
-				i, i, i,
-			)))
-			lines = strings.Split(comment, "\n")
-			for _, line := range lines[:3] {
-				out.Write([]byte(line + "\n"))
-			}
-			for _, line := range lines[3:] {
-				out.Write([]byte(lineURLize(cfg.URLPrefix, line) + "\n"))
-			}
-			out.Write([]byte("
\n")) + + tmpl := template.New("entry") + tmpl = tmpl.Funcs(template.FuncMap{"lineURLize": lineURLizeInTemplate}) + tmpl = template.Must(tmpl.Parse(TmplHTMLEntry)) + os.Stdout.Write([]byte(startHeader(etagHash, gzipWriter != nil))) + err = tmpl.Execute(out, struct { + Version string + Cfg *Cfg + Title string + When string + AtomCommentsURL string + Parent string + Commit *object.Commit + Lines []string + NoteLines []string + Comments []CommentEntry + }{ + Version: sgblog.Version, + Cfg: cfg, + Title: title, + When: when, + AtomCommentsURL: atomCommentsURL, + Parent: parent, + Commit: commit, + Lines: lines[2:], + NoteLines: notesLines, + Comments: comments, + }) + if err != nil { + makeErr(err) } - out.Write([]byte("
\n")) } else { makeErr(errors.New("unknown URL action")) } diff --git a/common.go b/common.go index 64133be..f0558f1 100644 --- a/common.go +++ b/common.go @@ -2,6 +2,6 @@ package sgblog const ( - Version = "0.6.5" + Version = "0.7.0" WhenFmt = "2006-01-02 15:04:05Z07:00" )