Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1405)

Side by Side Diff: doc/tmpltohtml.go

Issue 4699041: code review 4699041: go_tutorial: change the way it's generated. (Closed)
Patch Set: diff -r a5b801874645 https://go.googlecode.com/hg/ Created 13 years, 8 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « doc/makehtml ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5
6 // The template uses the function "code" to inject program
7 // source into the output by extracting code from files and
8 // injecting them as HTML-escaped <pre> blocks.
9 //
10 // The syntax is simple: 1, 2, or 3 space-separated arguments:
11 //
12 // Whole file:
13 // {{code "foo.go"}}
14 // One line (here the signature of main):
15 // {{code "foo.go" `/^func.main/`}}
16 // Block of text, determined by start and end (here the body of main):
17 // {{code "foo.go" `/^func.main/` `/^}/`
18 //
19 // Patterns can be `/regular expression/`, a decimal number, or "$"
20 // to signify the end of the file.
21 package main
22
23 import (
24 "exp/template"
25 "flag"
26 "fmt"
27 "io/ioutil"
28 "log"
29 "os"
30 "regexp"
31 "strings"
32 )
33
34 func Usage() {
35 fmt.Fprintf(os.Stderr, "usage: tmpltohtml file\n")
36 os.Exit(2)
37 }
38
39 func main() {
40 flag.Usage = Usage
41 flag.Parse()
42 if len(flag.Args()) != 1 {
43 Usage()
44 }
45
46 // Read and parse the input.
47 name := flag.Args()[0]
48 input := contents(name)
adg 2011/07/13 00:05:56 Just use ParseFile instead.
49 tmpl := template.New(name).Funcs(template.FuncMap{"code": code})
50 if err := tmpl.Parse(input); err != nil {
51 log.Fatal(err)
52 }
53
54 // Execute the template.
55 if err := tmpl.Execute(os.Stdout, 0); err != nil {
56 log.Fatal(err)
57 }
58 }
59
60 // contents reads a file by name and returns its contents as a string.
61 func contents(name string) string {
62 file, err := ioutil.ReadFile(name)
63 if err != nil {
64 log.Fatal(err)
65 }
66 return string(file)
67 }
68
69 // format returns a textual representation of the arg, formatted according to it s nature.
70 func format(arg interface{}) string {
71 switch arg := arg.(type) {
72 case int:
73 return fmt.Sprintf("%d", arg)
74 case string:
75 if len(arg) > 2 && arg[0] == '/' && arg[len(arg)-1] == '/' {
76 return fmt.Sprintf("%#q", arg)
77 }
78 return fmt.Sprintf("%q", arg)
79 default:
80 log.Fatalf("unrecognized argument: %v type %T", arg, arg)
81 }
82 return ""
83 }
84
85 func code(file string, arg ...interface{}) (string, os.Error) {
86 text := contents(file)
87 var command string
88 switch len(arg) {
89 case 0:
90 // text is already whole file.
91 command = fmt.Sprintf("code %q", file)
92 case 1:
93 command = fmt.Sprintf("code %q %s", file, format(arg[0]))
94 text = oneLine(file, text, arg[0])
95 case 2:
96 command = fmt.Sprintf("code %q %s %s", file, format(arg[0]), for mat(arg[1]))
97 text = multipleLines(file, text, arg[0], arg[1])
98 default:
99 return "", fmt.Errorf("incorrect code invocation: code %q %q", f ile, arg)
100 }
101 // Replace tabs by spaces, which work better in HTML.
102 text = strings.Replace(text, "\t", " ", -1)
103 // Escape the program text for HTML.
104 text = template.HTMLEscapeString(text)
105 // Include the command as a comment.
106 text = fmt.Sprintf("<pre><!--{{%s}}\n-->%s</pre>", command, text)
107 return text, nil
108 }
109
110 // parseArg returns the integer or string value of the argument and tells which it is.
111 func parseArg(arg interface{}, file string, max int) (ival int, sval string, isI nt bool) {
112 switch n := arg.(type) {
113 case int:
114 if n <= 0 || n > max {
115 log.Fatalf("%q:%d is out of range", file, n)
116 }
117 return n, "", true
118 case string:
119 return 0, n, false
120 }
121 log.Fatalf("unrecognized argument %v type %T", arg, arg)
122 return
123 }
124
125 // oneLine returns the single line generated by a two-argument code invocation.
126 func oneLine(file, text string, arg interface{}) string {
127 lines := strings.SplitAfter(contents(file), "\n")
128 line, pattern, isInt := parseArg(arg, file, len(lines))
129 if isInt {
130 return lines[line-1]
131 }
132 return lines[match(file, 0, lines, pattern)-1]
133 }
134
135 // multipleLines returns the text generated by a three-argument code invocation.
136 func multipleLines(file, text string, arg1, arg2 interface{}) string {
137 lines := strings.SplitAfter(contents(file), "\n")
138 line1, pattern1, isInt1 := parseArg(arg1, file, len(lines))
139 line2, pattern2, isInt2 := parseArg(arg2, file, len(lines))
140 if !isInt1 {
141 line1 = match(file, 0, lines, pattern1)
142 }
143 if isInt2 {
adg 2011/07/13 00:05:56 This might be more readable as if !isInt2 { li
144 if line2 < line1 {
145 log.Fatal("lines out of order for %q: %d %d", line1, lin e2)
146 }
147 } else {
148 line2 = match(file, line1, lines, pattern2)
149 }
150 return strings.Join(lines[line1-1:line2], "")
151 }
152
153 // match identifies the input line that matches the pattern in a code invocation .
154 // If start>0, match lines starting there rather than at the beginning.
155 // The return value is 1-indexed.
156 func match(file string, start int, lines []string, pattern string) int {
157 // $ matches the end of the file.
158 if pattern == "$" {
159 if len(lines) == 0 {
160 log.Fatal("%q: empty file", file)
161 }
162 return len(lines)
163 }
164 // /regexp/ matches the line that matches the regexp.
165 if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == ' /' {
166 re, err := regexp.Compile(pattern[1 : len(pattern)-1])
167 if err != nil {
168 log.Fatal(err)
169 }
170 for i := start; i < len(lines); i++ {
171 if re.MatchString(lines[i]) {
172 return i + 1
173 }
174 }
175 log.Fatalf("%s: no match for %#q", file, pattern)
176 }
177 log.Fatalf("unrecognized pattern: %q", pattern)
178 return 0
179 }
OLDNEW
« no previous file with comments | « doc/makehtml ('k') | no next file » | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b