From c90760c2850f8e03d9a98dd11d6dc29c12b33230 Mon Sep 17 00:00:00 2001 From: Mark McGranaghan Date: Sat, 29 Sep 2012 13:18:39 -0700 Subject: [PATCH] golit progress --- style/book.css | 144 ++++++++++++++++------------------- style/golit.html | 193 +++++++++++++++++++++++++++++++++++++++++++++++ tool/generate.go | 9 ++- 3 files changed, 263 insertions(+), 83 deletions(-) create mode 100644 style/golit.html diff --git a/style/book.css b/style/book.css index e06f120..2eca62e 100644 --- a/style/book.css +++ b/style/book.css @@ -1,9 +1,55 @@ +/* Reset */ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} body { - font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +/* Typography and Layout */ +body { + font-family: 'Book Antiqua'; font-size: 15px; line-height: 20px; color: #252519; - margin: 0; padding: 0; + margin: 0; + padding: 0; } a { color: #261a3b; @@ -12,119 +58,59 @@ a { color: #261a3b; } p { - margin: 0 0 15px 0; + margin: 0 0 20px 0; } h1, h2, h3, h4, h5, h6 { - margin: 0px 0 15px 0; + margin: 0px 0 20px 0; } - h1 { - margin-top: 40px; + h2 { + margin-top: 40px; + font-size: 40px; + line-height: 40px; } -hr { - border: 0 none; - border-top: 1px solid #e5e5ee; - height: 1px; - margin: 20px 0; -} #container { position: relative; } #background { position: fixed; - top: 0; left: 525px; right: 0; bottom: 0; + top: 0; left: 455px; right: 0; bottom: 0; background: #f5f5ff; border-left: 1px solid #e5e5ee; z-index: -1; } -#jump_to, #jump_page { - background: white; - -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; - -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; - font: 10px Arial; - text-transform: uppercase; - cursor: pointer; - text-align: right; -} -#jump_to, #jump_wrapper { - position: fixed; - right: 0; top: 0; - padding: 5px 10px; -} - #jump_wrapper { - padding: 0; - display: none; - } - #jump_to:hover #jump_wrapper { - display: block; - } - #jump_page { - padding: 5px 0 3px; - margin: 0 0 25px 25px; - } - #jump_page .source { - display: block; - padding: 5px 10px; - text-decoration: none; - border-top: 1px solid #eee; - } - #jump_page .source:hover { - background: #f5f5ff; - } - #jump_page .source:first-child { - } table td { border: 0; outline: 0; } - td.docs, th.docs { + td.docs { max-width: 350px; min-width: 350px; - min-height: 5px; - padding: 10px 25px 1px 50px; - overflow-x: hidden; + min-height: 5px; /* ? */ + padding: 0px 30px 0px 60px; + overflow-x: hidden; /* ? */ vertical-align: top; text-align: left; } - .docs pre { - margin: 15px 0 15px; - padding-left: 15px; - } .docs p tt, .docs p code { background: #f8f8ff; border: 1px solid #dedede; - font-size: 12px; padding: 0 0.2em; } - .pilwrap { - position: relative; - } - .pilcrow { - font: 12px Arial; - text-decoration: none; - color: #454545; - position: absolute; - top: 3px; left: -20px; - padding: 1px 2px; - opacity: 0; - -webkit-transition: opacity 0.2s linear; - } - td.docs:hover .pilcrow { - opacity: 1; - } - td.code, th.code { - padding: 14px 15px 16px 25px; + td.code { + padding: 0px 20px 0px 30px; width: 100%; vertical-align: top; background: #f5f5ff; border-left: 1px solid #e5e5ee; } pre, tt, code { - font-size: 12px; line-height: 18px; - font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; + font-size: 14px; + line-height: 18px; + font-family: Menlo; margin: 0; padding: 0; } - +/* Syntax Highlighting */ td.linenos { background-color: #f0f0f0; padding-right: 10px; } span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } body .hll { background-color: #ffffcc } diff --git a/style/golit.html b/style/golit.html new file mode 100644 index 0000000..272b587 --- /dev/null +++ b/style/golit.html @@ -0,0 +1,193 @@ + + + + + + Page Title + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + +

Line Filters

+
///
+  
+
+

Generate literate-programming style HTML +documentation form Go source files.

+
package main
+
+import (
+    "fmt"
+    "io/ioutil"
+    "os"
+    "os/exec"
+    "regexp"
+    "strings"
+)
+  
+
+

Recognize doc lines, extract their comment prefixes.

+
var docsPat = regexp.MustCompile("^\\s*\\/\\/\\s")
+  
+
+

Abort on non-nil errors.

+
func check(err error) {
+    if err != nil {
+        panic(err)
+    }
+}
+  
+
+

For docs and code rendering: pipe source data +through binary at path with given argv, return +the output.

+
func pipedCmd(path string, argv []string, source string) string {
+    cmd := exec.Command(path, argv...)
+    in, err := cmd.StdinPipe()
+    check(err)
+    out, err := cmd.StdoutPipe()
+    check(err)
+    err = cmd.Start()
+    check(err)
+    in.Write([]byte(source))
+    check(err)
+    err = in.Close()
+    check(err)
+    bytes, err := ioutil.ReadAll(out)
+    check(err)
+    err = cmd.Wait()
+    check(err)
+    return string(bytes)
+}
+  
+
+

We'll break the code into {docs, code} pairs, +and then render those text segments before +including them in the HTML doc.

+
type segment struct {
+    docs, code, docsRendered, codeRendered string
+}
+
+func main() {  
+
+

Accept exactly 1 argument - the input filename.

+
    if len(os.Args) != 2 {
+        fmt.Fprintln(os.Stderr, "Usage: tool/generate input.go > output.html")
+        os.Exit(1)
+    }
+  
+
+

Ensure that we have markdown and pygmentize, +binaries, remember their paths.

+
    markdownPath, err := exec.LookPath("markdown")
+    check(err)
+    pygmentizePath, err := exec.LookPath("pygmentize")
+    check(err)
+  
+
+

Read the source file in, split into lines.

+
    sourceBytes, err := ioutil.ReadFile(os.Args[1])
+    check(err)
+    lines := strings.Split(string(sourceBytes), "\n")
+  
+
+

Group lines into docs/code segments.

+
    segments := []*segment{}
+    segments = append(segments, &segment{code: "", docs: ""})
+    lastLine := ""
+    for _, line := range lines {
+        head := segments[len(segments)-1]  
+
+

Doc line - trim off the comment markers.

+
        if (line == "" && lastLine == "docs") || docsPat.MatchString(line) {
+            trimLine := docsPat.ReplaceAllString(line, "")
+            if !(lastLine == "code" && head.docs != "") {
+                head.docs = head.docs + "\n" + trimLine
+            } else {
+                segments = append(segments, &segment{docs: trimLine, code: ""})
+            }
+            lastLine = "docs"  
+
+

Code line - preserve all whitespace.

+
        } else {
+            if !(lastLine == "docs" && head.code != "") {
+                head.code = head.code + "\n" + line
+            } else {
+                segments = append(segments, &segment{docs: "", code: line})
+            }
+            lastLine = "code"
+        }
+    }
+  
+
+

Render docs via markdown and code via +pygmentize in each segment.

+
    for _, seg := range segments {
+        seg.docsRendered = pipedCmd(markdownPath, []string{}, seg.docs)
+        seg.codeRendered = pipedCmd(pygmentizePath, []string{"-l", "go", "-f", "html"}, seg.code + "  ")
+    }
+  
+
+

Print HTML header.

+
    fmt.Print(`
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-eqiv="content-type" content="text/html;charset=utf-8">
+    <title>Page Title</title>
+    <link rel=stylesheet href="book.css">
+  </head>
+  <body>
+    <div id="container">
+      <div id="background"></div>
+      <table cellspacing="0" cellpadding="0">
+        <thead>
+          <tr><td class=docs></td><td class=code></td></tr>
+        </thead>
+        <tbody>`)
+  
+
+

Print HTML docs/code segments.

+
    for _, seg := range segments {
+        fmt.Printf("<tr><td class=docs>%s</td><td class=code>%s</td></tr>\n", seg.docsRendered, seg.codeRendered)
+    }
+  
+
+

Print HTML footer.

+
    fmt.Print(`
+        </tbody>
+      </table>
+    </div>
+  </body>
+</html>
+`)
+}
+  
+
+
+
+ + diff --git a/tool/generate.go b/tool/generate.go index 4628a35..83cef8c 100644 --- a/tool/generate.go +++ b/tool/generate.go @@ -1,6 +1,7 @@ -// ## golit +// ## Line Filters +/// -// Generate literate-programming style HTTML +// Generate literate-programming style HTML // documentation form Go source files. package main @@ -99,10 +100,10 @@ func main() { } // Render docs via `markdown` and code via - // `pygmentize`in each segment. + // `pygmentize` in each segment. for _, seg := range segments { seg.docsRendered = pipedCmd(markdownPath, []string{}, seg.docs) - seg.codeRendered = pipedCmd(pygmentizePath, []string{"-l", "go", "-f", "html"}, seg.code) + seg.codeRendered = pipedCmd(pygmentizePath, []string{"-l", "go", "-f", "html"}, seg.code + " ") } // Print HTML header.