blob: 1b6112e51ea0324a97d7f154497ea405b7387a1e [file] [log] [blame]
// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package web
import (
"bytes"
"html/template"
"log"
"net/url"
"strconv"
"strings"
"github.com/google/zoekt"
)
func (s *Server) formatResults(result *zoekt.SearchResult, query string, localPrint bool) ([]*FileMatch, error) {
var fmatches []*FileMatch
templateMap := map[string]*template.Template{}
fragmentMap := map[string]*template.Template{}
if !localPrint {
for repo, str := range result.RepoURLs {
if str != "" {
templateMap[repo] = s.getTemplate(str)
}
}
for repo, str := range result.LineFragments {
if str != "" {
fragmentMap[repo] = s.getTemplate(str)
}
}
}
getFragment := func(repo string, linenum int) string {
tpl := fragmentMap[repo]
if tpl == nil || localPrint {
return "#l" + strconv.Itoa(linenum)
}
var buf bytes.Buffer
if err := tpl.Execute(&buf, map[string]string{
"LineNumber": strconv.Itoa(linenum),
}); err != nil {
log.Printf("fragment template: %v", err)
return ""
}
return buf.String()
}
getURL := func(repo, filename string, branches []string, version string) string {
tpl := templateMap[repo]
if localPrint || tpl == nil {
v := make(url.Values)
v.Add("r", repo)
v.Add("f", filename)
v.Add("q", query)
if len(branches) > 0 {
v.Add("b", branches[0])
}
return "print?" + v.Encode()
}
var buf bytes.Buffer
b := ""
if len(branches) > 0 {
b = branches[0]
}
err := tpl.Execute(&buf, map[string]string{
"Branch": b,
"Version": version,
"Path": filename,
})
if err != nil {
log.Printf("url template: %v", err)
return ""
}
return buf.String()
}
// hash => result-id
seenFiles := map[string]string{}
for _, f := range result.Files {
fMatch := FileMatch{
FileName: f.FileName,
Repo: f.Repository,
ResultID: f.Repository + ":" + f.FileName,
Branches: f.Branches,
Language: f.Language,
}
if dup, ok := seenFiles[string(f.Checksum)]; ok {
fMatch.DuplicateID = dup
} else {
seenFiles[string(f.Checksum)] = fMatch.ResultID
}
if f.SubRepositoryName != "" {
fn := strings.TrimPrefix(fMatch.FileName[len(f.SubRepositoryPath):], "/")
fMatch.URL = getURL(f.SubRepositoryName, fn, f.Branches, f.Version)
} else {
fMatch.URL = getURL(f.Repository, f.FileName, f.Branches, f.Version)
}
for _, m := range f.LineMatches {
fragment := getFragment(f.Repository, m.LineNumber)
if !strings.HasPrefix(fragment, "#") && !strings.HasPrefix(fragment, ";") {
// TODO - remove this is backward compatibility glue.
fragment = "#" + fragment
}
md := Match{
FileName: f.FileName,
LineNum: m.LineNumber,
URL: fMatch.URL + fragment,
}
lastEnd := 0
line := m.Line
for i, f := range m.LineFragments {
l := f.LineOffset
e := l + f.MatchLength
frag := Fragment{
Pre: string(line[lastEnd:l]),
Match: string(line[l:e]),
}
if i == len(m.LineFragments)-1 {
frag.Post = string(m.Line[e:])
}
md.Fragments = append(md.Fragments, frag)
lastEnd = e
}
fMatch.Matches = append(fMatch.Matches, md)
}
fmatches = append(fmatches, &fMatch)
}
return fmatches, nil
}