Commit 4873bb21 authored by Robert Griesemer's avatar Robert Griesemer

Snapshot:

- fixed html tag generation
- simplified html escaping machinery
  (not 100% correct for strings yet)
- can now produce the first mostly correct formatted html pages from source
  with (fake) links: e.g. pretty -html srcfile.go > srcfile.html
  R=r

OCL=20915
CL=20915
parent e9564291
...@@ -37,7 +37,7 @@ parser.6: scanner.6 ast.6 ...@@ -37,7 +37,7 @@ parser.6: scanner.6 ast.6
platform.6: utils.6 platform.6: utils.6
printer.6: scanner.6 ast.6 htmlwriter.6 printer.6: scanner.6 ast.6
%.6: %.go %.6: %.go
$(G) $(F) $< $(G) $(F) $<
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package htmlwriter
import (
"os";
"io";
"fmt";
)
// Writer is a filter implementing the io.Write interface.
// It provides facilities to generate HTML tags and does
// HTML-escaping for text written through Write. Incoming
// text is assumed to be UTF-8 encoded.
export type Writer struct {
// TODO should not export any of the fields
writer io.Write;
}
func (b *Writer) Init(writer io.Write) *Writer {
b.writer = writer;
return b;
}
/* export */ func (p *Writer) Write(buf *[]byte) (written int, err *os.Error) {
i0 := 0;
for i := i0; i < len(buf); i++ {
var s string;
switch buf[i] {
case '<': s = "&lt;";
case '&': s = "&amp;";
default: continue;
}
// write HTML escape instead of buf[i]
w1, e1 := p.writer.Write(buf[i0 : i]);
if e1 != nil {
return i0 + w1, e1;
}
w2, e2 := io.WriteString(p.writer, s);
if e2 != nil {
return i0 + w1 /* not w2! */, e2;
}
i0 = i + 1;
}
written, err = p.writer.Write(buf[i0 : len(buf)]);
return len(buf), err;
}
// ----------------------------------------------------------------------------
// HTML-specific interface
/* export */ func (p *Writer) Tag(s string) {
// TODO proper error handling
io.WriteString(p.writer, s);
}
// ----------------------------------------------------------------------------
//
export func New(writer io.Write) *Writer {
return new(Writer).Init(writer);
}
...@@ -11,7 +11,6 @@ import ( ...@@ -11,7 +11,6 @@ import (
"tabwriter"; "tabwriter";
"flag"; "flag";
"fmt"; "fmt";
"htmlwriter";
Scanner "scanner"; Scanner "scanner";
AST "ast"; AST "ast";
) )
...@@ -57,7 +56,6 @@ const ( ...@@ -57,7 +56,6 @@ const (
type Printer struct { type Printer struct {
// output // output
text io.Write; text io.Write;
tags *htmlwriter.Writer;
// comments // comments
comments *array.Array; // the list of all comments comments *array.Array; // the list of all comments
...@@ -94,10 +92,9 @@ func (P *Printer) NextComment() { ...@@ -94,10 +92,9 @@ func (P *Printer) NextComment() {
} }
func (P *Printer) Init(text io.Write, tags *htmlwriter.Writer, comments *array.Array) { func (P *Printer) Init(text io.Write, comments *array.Array) {
// writers // writers
P.text = text; P.text = text;
P.tags = tags;
// comments // comments
P.comments = comments; P.comments = comments;
...@@ -111,6 +108,22 @@ func (P *Printer) Init(text io.Write, tags *htmlwriter.Writer, comments *array.A ...@@ -111,6 +108,22 @@ func (P *Printer) Init(text io.Write, tags *htmlwriter.Writer, comments *array.A
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Printing support // Printing support
func HtmlEscape(s string) string {
if html.BVal() {
var esc string;
for i := 0; i < len(s); i++ {
switch s[i] {
case '<': esc = "&lt";
case '&': esc = "&amp";
default: continue;
}
return s[0 : i] + esc + HtmlEscape(s[i+1 : len(s)]);
}
}
return s;
}
func (P *Printer) Printf(format string, s ...) { func (P *Printer) Printf(format string, s ...) {
n, err := fmt.fprintf(P.text, format, s); n, err := fmt.fprintf(P.text, format, s);
if err != nil { if err != nil {
...@@ -135,7 +148,7 @@ func (P *Printer) Newline(n int) { ...@@ -135,7 +148,7 @@ func (P *Printer) Newline(n int) {
} }
func (P *Printer) String(pos int, s string) { func (P *Printer) TaggedString(pos int, tag, s, endtag string) {
// use estimate for pos if we don't have one // use estimate for pos if we don't have one
if pos == 0 { if pos == 0 {
pos = P.lastpos; pos = P.lastpos;
...@@ -230,7 +243,7 @@ func (P *Printer) String(pos int, s string) { ...@@ -230,7 +243,7 @@ func (P *Printer) String(pos int, s string) {
if debug.BVal() { if debug.BVal() {
P.Printf("[%d]", P.cpos); P.Printf("[%d]", P.cpos);
} }
P.Printf("%s", ctext); P.Printf("%s", HtmlEscape(ctext));
if ctext[1] == '/' { if ctext[1] == '/' {
//-style comments must end in newline //-style comments must end in newline
...@@ -276,7 +289,7 @@ func (P *Printer) String(pos int, s string) { ...@@ -276,7 +289,7 @@ func (P *Printer) String(pos int, s string) {
if debug.BVal() { if debug.BVal() {
P.Printf("[%d]", pos); P.Printf("[%d]", pos);
} }
P.Printf("%s", s); P.Printf("%s%s%s", tag, HtmlEscape(s), endtag);
// -------------------------------- // --------------------------------
// interpret state // interpret state
...@@ -300,6 +313,11 @@ func (P *Printer) String(pos int, s string) { ...@@ -300,6 +313,11 @@ func (P *Printer) String(pos int, s string) {
} }
func (P *Printer) String(pos int, s string) {
P.TaggedString(pos, "", s, "");
}
func (P *Printer) Token(pos int, tok int) { func (P *Printer) Token(pos int, tok int) {
P.String(pos, Scanner.TokenString(tok)); P.String(pos, Scanner.TokenString(tok));
} }
...@@ -316,36 +334,39 @@ func (P *Printer) Error(pos int, tok int, msg string) { ...@@ -316,36 +334,39 @@ func (P *Printer) Error(pos int, tok int, msg string) {
// HTML support // HTML support
func (P *Printer) HtmlPrologue(title string) { func (P *Printer) HtmlPrologue(title string) {
if P.tags != nil { if html.BVal() {
P.tags.Tag( P.TaggedString(0,
"<html>\n" "<html>\n"
"<head>\n" "<head>\n"
" <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">\n" " <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">\n"
" <title>" + title + "</title>\n" " <title>" + HtmlEscape(title) + "</title>\n"
" <style type=\"text/css\">\n" " <style type=\"text/css\">\n"
" </style>\n" " </style>\n"
"</head>\n" "</head>\n"
"<body>\n" "<body>\n"
"<pre>\n" "<pre>\n",
"", ""
) )
} }
} }
func (P *Printer) HtmlEpilogue() { func (P *Printer) HtmlEpilogue() {
if P.tags != nil { if html.BVal() {
P.tags.Tag( P.TaggedString(0,
"</pre>\n" "</pre>\n"
"</body>\n" "</body>\n"
"<html>\n" "<html>\n",
"", ""
) )
} }
} }
func (P *Printer) HtmlIdentifier(pos int, ident string) { func (P *Printer) HtmlIdentifier(pos int, ident string) {
if false && P.tags != nil { if html.BVal() {
P.tags.Tag(`<a href="#` + ident + `">` + ident + `</a>`); // no need to HtmlEscape ident
P.TaggedString(pos, `<a href="#` + ident + `">`, ident, `</a>`);
} else { } else {
P.String(pos, ident); P.String(pos, ident);
} }
...@@ -632,14 +653,14 @@ func (P *Printer) ControlClause(s *AST.Stat) { ...@@ -632,14 +653,14 @@ func (P *Printer) ControlClause(s *AST.Stat) {
P.Stat(s.init); P.Stat(s.init);
P.separator = none; P.separator = none;
} }
P.Printf(";"); P.String(0, ";");
P.separator = blank; P.separator = blank;
if s.expr != nil { if s.expr != nil {
P.Expr(s.expr); P.Expr(s.expr);
P.separator = none; P.separator = none;
} }
if s.tok == Scanner.FOR { if s.tok == Scanner.FOR {
P.Printf(";"); P.String(0, ";");
P.separator = blank; P.separator = blank;
if has_post { if has_post {
P.Stat(s.post); P.Stat(s.post);
...@@ -838,14 +859,8 @@ export func Print(prog *AST.Program) { ...@@ -838,14 +859,8 @@ export func Print(prog *AST.Program) {
if usetabs.BVal() { if usetabs.BVal() {
padchar = '\t'; padchar = '\t';
} }
var ( text := tabwriter.New(os.Stdout, int(tabwidth.IVal()), 1, padchar, true, html.BVal());
text = tabwriter.New(os.Stdout, int(tabwidth.IVal()), 1, padchar, true, html.BVal()); P.Init(text, prog.comments);
tags *htmlwriter.Writer;
)
if html.BVal() {
tags = htmlwriter.New(text);
}
P.Init(text, tags, prog.comments);
P.HtmlPrologue("<the source>"); P.HtmlPrologue("<the source>");
P.Program(prog); P.Program(prog);
......
...@@ -23,7 +23,7 @@ apply1() { ...@@ -23,7 +23,7 @@ apply1() {
#echo $1 $2 #echo $1 $2
case `basename $F` in case `basename $F` in
# these files don't pass the idempotency test yet # these files don't pass the idempotency test yet
log.go | type.go | \ log.go | type.go | types_amd64_darwin.go | \
\ \
selftest1.go | func3.go | bug014.go | bug029.go | bug032.go | bug050.go | \ selftest1.go | func3.go | bug014.go | bug029.go | bug032.go | bug050.go | \
bug068.go | bug088.go | bug083.go | bug106.go | bug125.go ) ;; # skip - files contain syntax errors bug068.go | bug088.go | bug083.go | bug106.go | bug125.go ) ;; # skip - files contain syntax errors
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment