diff options
-rwxr-xr-x | src/cmd/godoc/snippet.go | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go new file mode 100755 index 000000000..add85aacb --- /dev/null +++ b/src/cmd/godoc/snippet.go @@ -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; +} |