diff --git a/README.md b/README.md index d8c9c09..70f1cfc 100644 --- a/README.md +++ b/README.md @@ -3,17 +3,11 @@ Go by Example book source. -### Building Tools - -```console -$ tool/build -``` - -### Numbering +### Number'ing ```console $ mate tool/index.txt -$ tool/number +$ go run tool/number.go ``` @@ -22,3 +16,11 @@ $ tool/number ```console $ tool/gofmt ``` + + +### Golit'ing + +```console +$ go run tool/generate.go tool/generate > build/generate.html +$ open build/generate.html +``` diff --git a/style/generate.html b/style/generate.html deleted file mode 100644 index 9a86dae..0000000 --- a/style/generate.html +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - golit - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - -

golit

-
  
-
-

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")
-  
-
-

Recognize title prefixes, for titling web page.

-
var titlePat = regexp.MustCompile("^\\/\\/\\s##\\s")
-  
-
-

Abort on non-nil errors.

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

We'll implement Markdown rendering and Pygments syntax -highlighting by piping data through external programs. -This is a general helper for handling both cases.

-
func pipedCmd(binary string, argv []string, input string) string {
-    cmd := exec.Command(binary, argv...)
-    in, err := cmd.StdinPipe()
-    check(err)
-    out, err := cmd.StdoutPipe()
-    check(err)
-    err = cmd.Start()
-    check(err)
-    in.Write([]byte(input))
-    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. -Special case the header to go in its own segment.

-
    segments := []*segment{}
-    segments = append(segments, &segment{code: "", docs: docsPat.ReplaceAllString(lines[0], "")})
-    segments = append(segments, &segment{code: "", docs: ""})
-    lastLine := ""
-    for _, line := range lines[2:] {
-        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.Printf(`
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta http-eqiv="content-type" content="text/html;charset=utf-8">
-    <title>%s</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>`, titlePat.ReplaceAllString(lines[0], ""))
-  
-
-

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 59bb270..ff4da15 100644 --- a/tool/generate.go +++ b/tool/generate.go @@ -1,7 +1,7 @@ // ## golit -// Generate literate-programming style HTML -// documentation form Go source files. +// **golit** generates literate-programming style HTML +// documentation from a Go source files. package main @@ -57,9 +57,9 @@ type segment struct { } func main() { - // Accept exactly 1 argument - the input filename. + // Accept exactly 1 argument - the input filename, less the .go extension. if len(os.Args) != 2 { - fmt.Fprintln(os.Stderr, "Usage: tool/generate input.go > output.html") + fmt.Fprintln(os.Stderr, "Usage: go run tool/generate.go input > output.html") os.Exit(1) } @@ -71,7 +71,7 @@ func main() { check(err) // Read the source file in, split into lines. - sourceBytes, err := ioutil.ReadFile(os.Args[1]) + sourceBytes, err := ioutil.ReadFile(os.Args[1]+".go") check(err) lines := strings.Split(string(sourceBytes), "\n") @@ -117,7 +117,7 @@ func main() { %s - +