]> Cypherpunks repositories - gostls13.git/commitdiff
snippet generator for godoc search results
authorRobert Griesemer <gri@golang.org>
Mon, 26 Oct 2009 22:47:56 +0000 (15:47 -0700)
committerRobert Griesemer <gri@golang.org>
Mon, 26 Oct 2009 22:47:56 +0000 (15:47 -0700)
R=rsc
http://go/go-review/1013014

src/cmd/godoc/snippet.go [new file with mode: 0755]

diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go
new file mode 100755 (executable)
index 0000000..add85aa
--- /dev/null
@@ -0,0 +1,122 @@
+// 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.
+
+// This file contains the infrastructure to create a code
+// snippet for search results.
+//
+// Note: At the moment, this only creates HTML snippets.
+
+package main
+
+import (
+       "bytes";
+       "go/ast";
+       "go/printer";
+       "fmt";
+       "strings";
+)
+
+
+type Snippet struct {
+       Line    int;
+       Text    string;
+}
+
+
+type snippetStyler struct {
+       Styler;                         // defined in godoc.go
+       highlight       *ast.Ident;     // identifier to highlight
+}
+
+
+func (s *snippetStyler) LineTag(line int) (text []uint8, tag printer.HtmlTag) {
+       return; // no LineTag for snippets
+}
+
+
+func (s *snippetStyler) Ident(id *ast.Ident) (text []byte, tag printer.HtmlTag) {
+       text = strings.Bytes(id.Value);
+       if s.highlight == id {
+               tag = printer.HtmlTag{"<span class=highlight>", "</span>"};
+       }
+       return;
+}
+
+
+func newSnippet(decl ast.Decl, id *ast.Ident) *Snippet {
+       var buf bytes.Buffer;
+       writeNode(&buf, decl, true, &snippetStyler{highlight: id});
+       return &Snippet{id.Pos().Line, buf.String()};
+}
+
+
+func findSpec(list []ast.Spec, id *ast.Ident) ast.Spec {
+       for _, spec := range list {
+               switch s := spec.(type) {
+               case *ast.ImportSpec:
+                       if s.Name == id {
+                               return s;
+                       }
+               case *ast.ValueSpec:
+                       for _, n := range s.Names {
+                               if n == id {
+                                       return s;
+                               }
+                       }
+               case *ast.TypeSpec:
+                       if s.Name == id {
+                               return s;
+                       }
+               }
+       }
+       return nil;
+}
+
+
+func genSnippet(d *ast.GenDecl, id *ast.Ident) *Snippet {
+       s := findSpec(d.Specs, id);
+       if s == nil {
+               return nil;     //  declaration doesn't contain id - exit gracefully
+       }
+
+       // only use the spec containing the id for the snippet
+       dd := &ast.GenDecl{d.Doc, d.Position, d.Tok, d.Lparen, []ast.Spec{s}, d.Rparen};
+
+       return newSnippet(dd, id);
+}
+
+
+func funcSnippet(d *ast.FuncDecl, id *ast.Ident) *Snippet {
+       if d.Name != id {
+               return nil;     //  declaration doesn't contain id - exit gracefully
+       }
+
+       // only use the function signature for the snippet
+       dd := &ast.FuncDecl{d.Doc, d.Recv, d.Name, d.Type, nil};
+
+       return newSnippet(dd, id);
+}
+
+
+// NewSnippet creates a text snippet from a declaration decl containing an
+// identifier id. Parts of the declaration not containing the identifier
+// may be removed for a more compact snippet.
+//
+func NewSnippet(decl ast.Decl, id *ast.Ident) (s *Snippet) {
+       switch d := decl.(type) {
+       case *ast.GenDecl:
+               s = genSnippet(d, id);
+       case *ast.FuncDecl:
+               s = funcSnippet(d, id);
+       }
+
+       // handle failure gracefully
+       if s == nil {
+               s = &Snippet{
+                       id.Pos().Line,
+                       fmt.Sprintf(`could not generate a snippet for <span class="highlight">%s</span>`, id.Value),
+               };
+       }
+       return;
+}