mirror of
https://github.com/golang/go
synced 2024-11-22 06:04:39 -07:00
use grouping instead of colors to show non-global search hits:
- introduced a new run per file containing all spots belonging to the same kind (e.g. var decl, const decl, etc.) - more comments, better index.go file organization R=rsc http://go/go-review/1026028
This commit is contained in:
parent
e8b580c9aa
commit
7837dbfcb8
@ -181,6 +181,11 @@ a.noline {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.info {
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #D8D8D8;
|
||||||
|
}
|
||||||
|
|
||||||
table.layout {
|
table.layout {
|
||||||
border-width: 0px;
|
border-width: 0px;
|
||||||
border-spacing: 0px;
|
border-spacing: 0px;
|
||||||
@ -196,50 +201,6 @@ span.highlight {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
|
||||||
/* Styles used by infoClassFmt */
|
|
||||||
|
|
||||||
a.package {
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: #FFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.import {
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: #D8D8D8;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.const {
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: #F5A9A9;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.type {
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: #F2F5A9;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.var {
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: #A9F5A9;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.func {
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: #A9D0F5;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.method {
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: #D0A9F5;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.use {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #FFFFFF;
|
|
||||||
background-color: #5858FA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* Styles for the frontpage */
|
/* Styles for the frontpage */
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
{.repeated section @}
|
{.repeated section @}
|
||||||
<h3>package {Pak.Name|html}</h3>
|
<h3>package {Pak.Name|html}</h3>
|
||||||
{.repeated section Files}
|
{.repeated section Files}
|
||||||
|
{.repeated section Groups}
|
||||||
{.repeated section Infos}
|
{.repeated section Infos}
|
||||||
<a href="{File.Path|html}?h={Query|html}#L{@|infoLine}" class="noline">{File.Path|html}:{@|infoLine}</a>
|
<a href="{File.Path|html}?h={Query|html}#L{@|infoLine}" class="noline">{File.Path|html}:{@|infoLine}</a>
|
||||||
<pre>{@|infoSnippet}</pre>
|
<pre>{@|infoSnippet}</pre>
|
||||||
@ -31,25 +32,22 @@
|
|||||||
{.end}
|
{.end}
|
||||||
{.end}
|
{.end}
|
||||||
{.end}
|
{.end}
|
||||||
|
{.end}
|
||||||
{.section Others}
|
{.section Others}
|
||||||
<h2>Local declarations and uses</h2>
|
<h2>Local declarations and uses</h2>
|
||||||
<p>
|
|
||||||
Legend:
|
|
||||||
{.repeated section Legend}
|
|
||||||
<a class="{@|html}">{@|html}</a>
|
|
||||||
{.end}
|
|
||||||
</p>
|
|
||||||
{.repeated section @}
|
{.repeated section @}
|
||||||
<h3>package {Pak.Name|html}</h3>
|
<h3>package {Pak.Name|html}</h3>
|
||||||
<table border="0" cellspacing="2">
|
|
||||||
{.repeated section Files}
|
{.repeated section Files}
|
||||||
|
<a href="{File.Path|html}?h={Query|html}" class="noline">{File.Path|html}</a>
|
||||||
|
<table class="layout">
|
||||||
|
{.repeated section Groups}
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top">
|
<td width="25"></td>
|
||||||
<a href="{File.Path|html}?h={Query|html}" class="noline">{File.Path|html}:</a>
|
<th align="left" valign="top">{Kind|infoKind}</th>
|
||||||
</td>
|
<td align="left" width="4"></td>
|
||||||
<td>
|
<td>
|
||||||
{.repeated section Infos}
|
{.repeated section Infos}
|
||||||
<a href="{File.Path|html}?h={Query|html}#L{@|infoLine}" class="{@|infoClass}">{@|infoLine}</a>
|
<a href="{File.Path|html}?h={Query|html}#L{@|infoLine}" class="info">{@|infoLine}</a>
|
||||||
{.end}
|
{.end}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -57,6 +55,7 @@
|
|||||||
</table>
|
</table>
|
||||||
{.end}
|
{.end}
|
||||||
{.end}
|
{.end}
|
||||||
|
{.end}
|
||||||
{.or}
|
{.or}
|
||||||
<p>
|
<p>
|
||||||
A legal query is a single identifier (such as <a href="search?q=ToLower">ToLower</a>)
|
A legal query is a single identifier (such as <a href="search?q=ToLower">ToLower</a>)
|
||||||
|
@ -595,22 +595,22 @@ func linkFmt(w io.Writer, x interface{}, format string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The strings in infoClasses must be properly html-escaped.
|
// The strings in infoKinds must be properly html-escaped.
|
||||||
var infoClasses = [nKinds]string{
|
var infoKinds = [nKinds]string{
|
||||||
"package", // PackageClause
|
PackageClause: "package clause",
|
||||||
"import", // ImportDecl
|
ImportDecl: "import decl",
|
||||||
"const", // ConstDecl
|
ConstDecl: "const decl",
|
||||||
"type", // TypeDecl
|
TypeDecl: "type decl",
|
||||||
"var", // VarDecl
|
VarDecl: "var decl",
|
||||||
"func", // FuncDecl
|
FuncDecl: "func decl",
|
||||||
"method", // MethodDecl
|
MethodDecl: "method decl",
|
||||||
"use", // Use
|
Use: "use",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Template formatter for "infoClass" format.
|
// Template formatter for "infoKind" format.
|
||||||
func infoClassFmt(w io.Writer, x interface{}, format string) {
|
func infoKindFmt(w io.Writer, x interface{}, format string) {
|
||||||
fmt.Fprintf(w, infoClasses[x.(SpotInfo).Kind()]); // no html escaping needed
|
fmt.Fprintf(w, infoKinds[x.(SpotKind)]); // infoKind entries are html-escaped
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -661,7 +661,7 @@ var fmap = template.FormatterMap{
|
|||||||
"html-comment": htmlCommentFmt,
|
"html-comment": htmlCommentFmt,
|
||||||
"path": pathFmt,
|
"path": pathFmt,
|
||||||
"link": linkFmt,
|
"link": linkFmt,
|
||||||
"infoClass": infoClassFmt,
|
"infoKind": infoKindFmt,
|
||||||
"infoLine": infoLineFmt,
|
"infoLine": infoLineFmt,
|
||||||
"infoSnippet": infoSnippetFmt,
|
"infoSnippet": infoSnippetFmt,
|
||||||
"padding": paddingFmt,
|
"padding": paddingFmt,
|
||||||
@ -1071,7 +1071,6 @@ type SearchResult struct {
|
|||||||
Hit *LookupResult;
|
Hit *LookupResult;
|
||||||
Alt *AltWords;
|
Alt *AltWords;
|
||||||
Accurate bool;
|
Accurate bool;
|
||||||
Legend []string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func search(c *http.Conn, r *http.Request) {
|
func search(c *http.Conn, r *http.Request) {
|
||||||
@ -1083,7 +1082,6 @@ func search(c *http.Conn, r *http.Request) {
|
|||||||
result.Hit, result.Alt = index.(*Index).Lookup(query);
|
result.Hit, result.Alt = index.(*Index).Lookup(query);
|
||||||
_, ts := fsTree.get();
|
_, ts := fsTree.get();
|
||||||
result.Accurate = timestamp >= ts;
|
result.Accurate = timestamp >= ts;
|
||||||
result.Legend = &infoClasses;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer;
|
var buf bytes.Buffer;
|
||||||
|
@ -37,7 +37,7 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Data structures used during indexing
|
// RunList
|
||||||
|
|
||||||
// A RunList is a vector of entries that can be sorted according to some
|
// A RunList is a vector of entries that can be sorted according to some
|
||||||
// criteria. A RunList may be compressed by grouping "runs" of entries
|
// criteria. A RunList may be compressed by grouping "runs" of entries
|
||||||
@ -83,6 +83,9 @@ func (h *RunList) reduce(less func(x, y interface{}) bool, newRun func(h *RunLis
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// SpotInfo
|
||||||
|
|
||||||
// A SpotInfo value describes a particular identifier spot in a given file;
|
// A SpotInfo value describes a particular identifier spot in a given file;
|
||||||
// It encodes three values: the SpotKind (declaration or use), a line or
|
// It encodes three values: the SpotKind (declaration or use), a line or
|
||||||
// snippet index "lori", and whether it's a line or index.
|
// snippet index "lori", and whether it's a line or index.
|
||||||
@ -140,25 +143,80 @@ func makeSpotInfo(kind SpotKind, lori int, isIndex bool) SpotInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (x SpotInfo) less(y SpotInfo) bool { return x.Lori() < y.Lori() }
|
|
||||||
|
|
||||||
|
|
||||||
func (x SpotInfo) Kind() SpotKind { return SpotKind(x>>1&7) }
|
func (x SpotInfo) Kind() SpotKind { return SpotKind(x>>1&7) }
|
||||||
|
|
||||||
|
|
||||||
func (x SpotInfo) Lori() int { return int(x>>4) }
|
func (x SpotInfo) Lori() int { return int(x>>4) }
|
||||||
|
|
||||||
|
|
||||||
func (x SpotInfo) IsIndex() bool { return x&1 != 0 }
|
func (x SpotInfo) IsIndex() bool { return x&1 != 0 }
|
||||||
|
|
||||||
|
|
||||||
// A Pak describes a Go package.
|
// ----------------------------------------------------------------------------
|
||||||
type Pak struct {
|
// KindRun
|
||||||
Path string; // directory name containing the package
|
|
||||||
Name string; // package name as declared by package clause
|
// Debugging support. Disable to see multiple entries per line.
|
||||||
|
const removeDuplicates = true
|
||||||
|
|
||||||
|
// A KindRun is a run of SpotInfos of the same kind in a given file.
|
||||||
|
type KindRun struct {
|
||||||
|
Kind SpotKind;
|
||||||
|
Infos []SpotInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// KindRuns are sorted by line number or index. Since the isIndex bit
|
||||||
|
// is always the same for all infos in one list we can compare lori's.
|
||||||
|
func (f *KindRun) Len() int { return len(f.Infos) }
|
||||||
|
func (f *KindRun) Less(i, j int) bool { return f.Infos[i].Lori() < f.Infos[j].Lori() }
|
||||||
|
func (f *KindRun) Swap(i, j int) { f.Infos[i], f.Infos[j] = f.Infos[j], f.Infos[i] }
|
||||||
|
|
||||||
|
|
||||||
|
// FileRun contents are sorted by Kind for the reduction into KindRuns.
|
||||||
|
func lessKind(x, y interface{}) bool { return x.(SpotInfo).Kind() < y.(SpotInfo).Kind() }
|
||||||
|
|
||||||
|
|
||||||
|
// newKindRun allocates a new KindRun from the SpotInfo run [i, j) in h.
|
||||||
|
func newKindRun(h *RunList, i, j int) interface{} {
|
||||||
|
kind := h.At(i).(SpotInfo).Kind();
|
||||||
|
infos := make([]SpotInfo, j-i);
|
||||||
|
k := 0;
|
||||||
|
for ; i < j; i++ {
|
||||||
|
infos[k] = h.At(i).(SpotInfo);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
run := &KindRun{kind, infos};
|
||||||
|
|
||||||
|
// Spots were sorted by file and kind to create this run.
|
||||||
|
// Within this run, sort them by line number or index.
|
||||||
|
sort.Sort(run);
|
||||||
|
|
||||||
|
if removeDuplicates {
|
||||||
|
// Since both the lori and kind field must be
|
||||||
|
// same for duplicates, and since the isIndex
|
||||||
|
// bit is always the same for all infos in one
|
||||||
|
// list we can simply compare the entire info.
|
||||||
|
k := 0;
|
||||||
|
var prev SpotInfo;
|
||||||
|
for i, x := range infos {
|
||||||
|
if x != prev || i == 0 {
|
||||||
|
infos[k] = x;
|
||||||
|
k++;
|
||||||
|
prev = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
run.Infos = infos[0:k];
|
||||||
|
}
|
||||||
|
|
||||||
|
return run;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// FileRun
|
||||||
|
|
||||||
|
// A Pak describes a Go package.
|
||||||
|
type Pak struct {
|
||||||
|
Path string; // path of directory containing the package
|
||||||
|
Name string; // package name as declared by package clause
|
||||||
|
}
|
||||||
|
|
||||||
// Paks are sorted by name (primary key) and by import path (secondary key).
|
// Paks are sorted by name (primary key) and by import path (secondary key).
|
||||||
func (p *Pak) less(q *Pak) bool {
|
func (p *Pak) less(q *Pak) bool {
|
||||||
return p.Name < q.Name || p.Name == q.Name && p.Path < q.Path;
|
return p.Name < q.Name || p.Name == q.Name && p.Path < q.Path;
|
||||||
@ -172,9 +230,6 @@ type File struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (f *File) less(g *File) bool { return f.Path < g.Path }
|
|
||||||
|
|
||||||
|
|
||||||
// A Spot describes a single occurence of a word.
|
// A Spot describes a single occurence of a word.
|
||||||
type Spot struct {
|
type Spot struct {
|
||||||
File *File;
|
File *File;
|
||||||
@ -182,59 +237,42 @@ type Spot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Spots are sorted by filename.
|
// A FileRun is a list of KindRuns belonging to the same file.
|
||||||
func lessSpot(x, y interface{}) bool { return x.(Spot).File.less(y.(Spot).File) }
|
|
||||||
|
|
||||||
|
|
||||||
// A FileRun describes a run of Spots of a word in a single file.
|
|
||||||
type FileRun struct {
|
type FileRun struct {
|
||||||
File *File;
|
File *File;
|
||||||
Infos []SpotInfo;
|
Groups []*KindRun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (f *FileRun) Len() int { return len(f.Infos) }
|
// Spots are sorted by path for the reduction into FileRuns.
|
||||||
func (f *FileRun) Less(i, j int) bool { return f.Infos[i].less(f.Infos[j]) }
|
func lessSpot(x, y interface{}) bool { return x.(Spot).File.Path < y.(Spot).File.Path }
|
||||||
func (f *FileRun) Swap(i, j int) { f.Infos[i], f.Infos[j] = f.Infos[j], f.Infos[i] }
|
|
||||||
|
|
||||||
|
|
||||||
// newFileRun allocates a new *FileRun from the Spot run [i, j) in h.
|
// newFileRun allocates a new FileRun from the Spot run [i, j) in h.
|
||||||
func newFileRun(h *RunList, i, j int) interface{} {
|
func newFileRun(h0 *RunList, i, j int) interface{} {
|
||||||
file := h.At(i).(Spot).File;
|
file := h0.At(i).(Spot).File;
|
||||||
infos := make([]SpotInfo, j-i);
|
|
||||||
|
// reduce the list of Spots into a list of KindRuns
|
||||||
|
var h1 RunList;
|
||||||
|
h1.Vector.Init(j-i);
|
||||||
k := 0;
|
k := 0;
|
||||||
for ; i < j; i++ {
|
for ; i < j; i++ {
|
||||||
infos[k] = h.At(i).(Spot).Info;
|
h1.Set(k, h0.At(i).(Spot).Info);
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
run := &FileRun{file, infos};
|
h2 := h1.reduce(lessKind, newKindRun);
|
||||||
// Spots were sorted by file to create this run.
|
|
||||||
// Within this run, sort them by line number.
|
// create the FileRun
|
||||||
sort.Sort(run);
|
groups := make([]*KindRun, h2.Len());
|
||||||
// Remove duplicates: Both the lori and kind field
|
for i := 0; i < h2.Len(); i++ {
|
||||||
// must be the same for duplicate, and since the
|
groups[i] = h2.At(i).(*KindRun);
|
||||||
// isIndex field is always the same for all infos
|
|
||||||
// in one list we can simply compare the entire
|
|
||||||
// info.
|
|
||||||
k = 0;
|
|
||||||
var prev SpotInfo;
|
|
||||||
for i, x := range infos {
|
|
||||||
if x != prev || i == 0 {
|
|
||||||
infos[k] = x;
|
|
||||||
k++;
|
|
||||||
prev = x;
|
|
||||||
}
|
}
|
||||||
}
|
return &FileRun{file, groups};
|
||||||
run.Infos = infos[0:k];
|
|
||||||
return run;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// FileRuns are sorted by package.
|
// ----------------------------------------------------------------------------
|
||||||
func lessFileRun(x, y interface{}) bool {
|
// PakRun
|
||||||
return x.(*FileRun).File.Pak.less(&y.(*FileRun).File.Pak);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// A PakRun describes a run of *FileRuns of a package.
|
// A PakRun describes a run of *FileRuns of a package.
|
||||||
type PakRun struct {
|
type PakRun struct {
|
||||||
@ -244,11 +282,17 @@ type PakRun struct {
|
|||||||
|
|
||||||
// Sorting support for files within a PakRun.
|
// Sorting support for files within a PakRun.
|
||||||
func (p *PakRun) Len() int { return len(p.Files) }
|
func (p *PakRun) Len() int { return len(p.Files) }
|
||||||
func (p *PakRun) Less(i, j int) bool { return p.Files[i].File.less(p.Files[j].File) }
|
func (p *PakRun) Less(i, j int) bool { return p.Files[i].File.Path < p.Files[j].File.Path }
|
||||||
func (p *PakRun) Swap(i, j int) { p.Files[i], p.Files[j] = p.Files[j], p.Files[i] }
|
func (p *PakRun) Swap(i, j int) { p.Files[i], p.Files[j] = p.Files[j], p.Files[i] }
|
||||||
|
|
||||||
|
|
||||||
// newPakRun allocates a new *PakRun from the *FileRun run [i, j) in h.
|
// FileRuns are sorted by package for the reduction into PakRuns.
|
||||||
|
func lessFileRun(x, y interface{}) bool {
|
||||||
|
return x.(*FileRun).File.Pak.less(&y.(*FileRun).File.Pak);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// newPakRun allocates a new PakRun from the *FileRun run [i, j) in h.
|
||||||
func newPakRun(h *RunList, i, j int) interface{} {
|
func newPakRun(h *RunList, i, j int) interface{} {
|
||||||
pak := h.At(i).(*FileRun).File.Pak;
|
pak := h.At(i).(*FileRun).File.Pak;
|
||||||
files := make([]*FileRun, j-i);
|
files := make([]*FileRun, j-i);
|
||||||
@ -263,14 +307,17 @@ func newPakRun(h *RunList, i, j int) interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// PakRuns are sorted by package.
|
// ----------------------------------------------------------------------------
|
||||||
func lessPakRun(x, y interface{}) bool { return x.(*PakRun).Pak.less(&y.(*PakRun).Pak) }
|
// HitList
|
||||||
|
|
||||||
|
|
||||||
// A HitList describes a list of PakRuns.
|
// A HitList describes a list of PakRuns.
|
||||||
type HitList []*PakRun
|
type HitList []*PakRun
|
||||||
|
|
||||||
|
|
||||||
|
// PakRuns are sorted by package.
|
||||||
|
func lessPakRun(x, y interface{}) bool { return x.(*PakRun).Pak.less(&y.(*PakRun).Pak) }
|
||||||
|
|
||||||
|
|
||||||
func reduce(h0 *RunList) HitList {
|
func reduce(h0 *RunList) HitList {
|
||||||
// reduce a list of Spots into a list of FileRuns
|
// reduce a list of Spots into a list of FileRuns
|
||||||
h1 := h0.reduce(lessSpot, newFileRun);
|
h1 := h0.reduce(lessSpot, newFileRun);
|
||||||
@ -308,6 +355,9 @@ func (h HitList) filter(pakname string) HitList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// AltWords
|
||||||
|
|
||||||
type wordPair struct {
|
type wordPair struct {
|
||||||
canon string; // canonical word spelling (all lowercase)
|
canon string; // canonical word spelling (all lowercase)
|
||||||
alt string; // alternative spelling
|
alt string; // alternative spelling
|
||||||
@ -322,10 +372,11 @@ type AltWords struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// wordPairs are sorted by their canonical spelling.
|
||||||
func lessWordPair(x, y interface{}) bool { return x.(*wordPair).canon < y.(*wordPair).canon }
|
func lessWordPair(x, y interface{}) bool { return x.(*wordPair).canon < y.(*wordPair).canon }
|
||||||
|
|
||||||
|
|
||||||
// newAltWords allocates a new *AltWords from the *wordPair run [i, j) in h.
|
// newAltWords allocates a new AltWords from the *wordPair run [i, j) in h.
|
||||||
func newAltWords(h *RunList, i, j int) interface{} {
|
func newAltWords(h *RunList, i, j int) interface{} {
|
||||||
canon := h.At(i).(*wordPair).canon;
|
canon := h.At(i).(*wordPair).canon;
|
||||||
alts := make([]string, j-i);
|
alts := make([]string, j-i);
|
||||||
|
Loading…
Reference in New Issue
Block a user