func (s *localImpl) Search(ctx context.Context, req *CodeSearchRequest) (*CodeSearchReply, error) { reply := CodeSearchReply{} if req.Regexp == nil { return nil, errors.New("No search regexp provided.") } re, err := req.Regexp.Compile() if err != nil { return nil, fmt.Errorf("Search regexp compilation error: %v", err) } q := index.RegexpQuery(re.Syntax) for _, fileid := range s.ix.PostingQuery(q) { // TODO(delroth): Apply pagination. // TODO(delroth): Sort the filenames by relevance. // TODO(delroth): File RE should be applied here. fn := s.ix.Name(fileid) data, err := s.ReadFileContents(ctx, fn) if err != nil { return nil, fmt.Errorf("Search in file contents failed: %v", err) } m := &Match{ Filename: fn, Snippet: GetSnippets(data, re, 5), } if len(m.Snippet) > 0 { reply.Match = append(reply.Match, m) } } return &reply, nil }
func Main() { g := regexp.Grep{ Stdout: os.Stdout, Stderr: os.Stderr, } g.AddFlags() flag.Usage = usage flag.Parse() args := flag.Args() if len(args) != 1 { usage() } if *cpuProfile != "" { f, err := os.Create(*cpuProfile) if err != nil { log.Fatal(err) } defer f.Close() pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } pat := "(?m)" + args[0] if *iFlag { pat = "(?i)" + pat } re, err := regexp.Compile(pat) if err != nil { log.Fatal(err) } g.Regexp = re var fre *regexp.Regexp if *fFlag != "" { fre, err = regexp.Compile(*fFlag) if err != nil { log.Fatal(err) } } q := index.RegexpQuery(re.Syntax) if *verboseFlag { log.Printf("query: %s\n", q) } ix := index.Open(index.File()) ix.Verbose = *verboseFlag var post []uint32 if *bruteFlag { post = ix.PostingQuery(&index.Query{Op: index.QAll}) } else { post = ix.PostingQuery(q) } if *verboseFlag { log.Printf("post query identified %d possible files\n", len(post)) } if fre != nil { fnames := make([]uint32, 0, len(post)) for _, fileid := range post { name := ix.Name(fileid) if fre.MatchString(name, true, true) < 0 { continue } fnames = append(fnames, fileid) } if *verboseFlag { log.Printf("filename regexp matched %d files\n", len(fnames)) } post = fnames } for _, fileid := range post { name := ix.Name(fileid) g.File(name) } matches = g.Match }
// Search returns matches for the given regexp. // The results are unordered. func (s *Searcher) Search(opts Options) ([]Result, error) { // Package index needs a regexp from the syntax package. syntaxRe, err := syntax.Parse(opts.Regexp, syntax.POSIX) if err != nil { return nil, err } // While package grep wants us to use the regex package. re, err := regexp.Compile(opts.Regexp) if err != nil { return nil, err } // Find candidate files. fileids := s.idx.PostingQuery(index.RegexpQuery(syntaxRe)) // Grep all the files. rChan := make(chan Result, 10) var wg sync.WaitGroup for _, id := range fileids { path := s.idx.Name(id) wg.Add(1) go func() { defer wg.Done() f, err := os.Open(path) if err != nil { return } g, err := grep.New(f) if err != nil { return } // Copy the regexp to avoid lock contention. m := g.Search(re.Copy(), opts.Context) if len(m) > 0 { p := strings.TrimPrefix(path, s.prefix) rChan <- MakeResult(p, re, m) } }() } // Collect the results. var results []Result var wg2 sync.WaitGroup wg2.Add(1) go func() { defer wg2.Done() for { r, ok := <-rChan if !ok { return } results = append(results, r) } }() wg.Wait() close(rChan) wg2.Wait() return results, nil }