func (c *APIDescribeCmd) Execute(args []string) error { context, err := prepareCommandContext(c.File) if err != nil { return err } file := context.relativeFile units, err := getSourceUnitsWithFile(context.buildStore, context.repo, file) if err != nil { return err } if GlobalOpt.Verbose { if len(units) > 0 { ids := make([]string, len(units)) for i, u := range units { ids[i] = string(u.ID()) } log.Printf("Position %s:%d is in %d source units %v.", file, c.StartByte, len(units), ids) } else { log.Printf("Position %s:%d is not in any source units.", file, c.StartByte) } } // Find the ref(s) at the character position. var ref *graph.Ref var nearbyRefs []*graph.Ref // Find nearby refs to help with debugging. OuterLoop: for _, u := range units { var g graph.Output graphFile := plan.SourceUnitDataFilename("graph", u) f, err := context.commitFS.Open(graphFile) if err != nil { return err } defer f.Close() if err := json.NewDecoder(f).Decode(&g); err != nil { return fmt.Errorf("%s: %s", graphFile, err) } for _, ref2 := range g.Refs { if file == ref2.File { if c.StartByte >= ref2.Start && c.StartByte <= ref2.End { ref = ref2 if ref.DefUnit == "" { ref.DefUnit = u.Name } if ref.DefUnitType == "" { ref.DefUnitType = u.Type } break OuterLoop } else if GlobalOpt.Verbose && abs(int(ref2.Start)-int(c.StartByte)) < 25 { nearbyRefs = append(nearbyRefs, ref2) } } } } if ref == nil { if GlobalOpt.Verbose { log.Printf("No ref found at %s:%d.", file, c.StartByte) if len(nearbyRefs) > 0 { log.Printf("However, nearby refs were found in the same file:") for _, nref := range nearbyRefs { log.Printf("Ref at bytes %d-%d to %v", nref.Start, nref.End, nref.DefKey()) } } f, err := os.Open(file) if err == nil { defer f.Close() b, err := ioutil.ReadAll(f) if err != nil { log.Fatalf("Error reading source file: %s.", err) } start := c.StartByte if start < 0 || int(start) > len(b)-1 { log.Fatalf("Start byte %d is out of file bounds.", c.StartByte) } end := c.StartByte + 50 if int(end) > len(b)-1 { end = uint32(len(b) - 1) } log.Printf("Surrounding source is:\n\n%s", b[start:end]) } else { log.Printf("Error opening source file to show surrounding source: %s.", err) } } fmt.Println(`{}`) return nil } // ref.DefRepo is *not* guaranteed to be non-empty, as // repo.URI() will return the empty string if the repo's // CloneURL is empty or malformed. if ref.DefRepo == "" { ref.DefRepo = context.repo.URI() } var resp apiDescribeCmdOutput // Now find the def for this ref. defInCurrentRepo := ref.DefRepo == context.repo.URI() if defInCurrentRepo { // Def is in the current repo. var g graph.Output graphFile := plan.SourceUnitDataFilename("graph", &unit.SourceUnit{Name: ref.DefUnit, Type: ref.DefUnitType}) f, err := context.commitFS.Open(graphFile) if err != nil { return err } defer f.Close() if err := json.NewDecoder(f).Decode(&g); err != nil { return fmt.Errorf("%s: %s", graphFile, err) } for _, def2 := range g.Defs { if def2.Path == ref.DefPath { resp.Def = &sourcegraph.Def{Def: *def2} break } } if resp.Def != nil { for _, doc := range g.Docs { if doc.Path == ref.DefPath { resp.Def.DocHTML = doc.Data } } // If Def is in the current Repo, transform that path to be an absolute path resp.Def.File = filepath.Join(context.repo.RootDir, resp.Def.File) } if resp.Def == nil && GlobalOpt.Verbose { log.Printf("No definition found with path %q in unit %q type %q.", ref.DefPath, ref.DefUnit, ref.DefUnitType) } } // spec is only valid for remote requests if ref.DefRepo is // non-empty. var spec sourcegraph.DefSpec var specValid bool if ref.DefRepo != "" { specValid = true spec = sourcegraph.DefSpec{ Repo: string(ref.DefRepo), UnitType: ref.DefUnitType, Unit: ref.DefUnit, Path: string(ref.DefPath), } } if specValid { apiclient := NewAPIClientWithAuthIfPresent() var wg sync.WaitGroup if resp.Def == nil { // Def is not in the current repo. Try looking it up using the // Sourcegraph API. wg.Add(1) go func() { defer wg.Done() var err error resp.Def, _, err = apiclient.Defs.Get(spec, &sourcegraph.DefGetOptions{Doc: true}) if err != nil && GlobalOpt.Verbose { log.Printf("Couldn't fetch definition %v: %s.", spec, err) } }() } if !c.NoExamples { wg.Add(1) go func() { defer wg.Done() var err error resp.Examples, _, err = apiclient.Defs.ListExamples(spec, &sourcegraph.DefListExamplesOptions{ Formatted: true, ListOptions: sourcegraph.ListOptions{PerPage: 4}, }) if err != nil && GlobalOpt.Verbose { log.Printf("Couldn't fetch examples for %v: %s.", spec, err) } }() } wg.Wait() } if err := json.NewEncoder(os.Stdout).Encode(resp); err != nil { return err } return nil }
func (c *APIDescribeCmd) Execute(args []string) error { context, err := prepareCommandContext(c.File) if err != nil { return err } file := context.relativeFile units, err := getSourceUnitsWithFile(context.buildStore, context.repo, file) if err != nil { return err } if GlobalOpt.Verbose { if len(units) > 0 { ids := make([]string, len(units)) for i, u := range units { ids[i] = string(u.ID()) } log.Printf("Position %s:%d is in %d source units %v.", file, c.StartByte, len(units), ids) } else { log.Printf("Position %s:%d is not in any source units.", file, c.StartByte) } } // Find the ref(s) at the character position. var ref *graph.Ref var nearbyRefs []*graph.Ref // Find nearby refs to help with debugging. OuterLoop: for _, u := range units { var g graph.Output graphFile := plan.SourceUnitDataFilename("graph", u) f, err := context.commitFS.Open(graphFile) if err != nil { return err } defer f.Close() if err := json.NewDecoder(f).Decode(&g); err != nil { return fmt.Errorf("%s: %s", graphFile, err) } for _, ref2 := range g.Refs { if file == ref2.File { if c.StartByte >= ref2.Start && c.StartByte <= ref2.End { ref = ref2 if ref.DefUnit == "" { ref.DefUnit = u.Name } if ref.DefUnitType == "" { ref.DefUnitType = u.Type } break OuterLoop } else if GlobalOpt.Verbose && abs(int(ref2.Start)-int(c.StartByte)) < 25 { nearbyRefs = append(nearbyRefs, ref2) } } } } if ref == nil { if GlobalOpt.Verbose { log.Printf("No ref found at %s:%d.", file, c.StartByte) if len(nearbyRefs) > 0 { log.Printf("However, nearby refs were found in the same file:") for _, nref := range nearbyRefs { log.Printf("Ref at bytes %d-%d to %v", nref.Start, nref.End, nref.DefKey()) } } f, err := os.Open(file) if err == nil { defer f.Close() b, err := ioutil.ReadAll(f) if err != nil { log.Fatalf("Error reading source file: %s.", err) } start := c.StartByte if start < 0 || int(start) > len(b)-1 { log.Fatalf("Start byte %d is out of file bounds.", c.StartByte) } end := c.StartByte + 50 if int(end) > len(b)-1 { end = uint32(len(b) - 1) } log.Printf("Surrounding source is:\n\n%s", b[start:end]) } else { log.Printf("Error opening source file to show surrounding source: %s.", err) } } colorable.Println(`{}`) return nil } // ref.DefRepo is *not* guaranteed to be non-empty, as // repo.URI() will return the empty string if the repo's // CloneURL is empty or malformed. if ref.DefRepo == "" { ref.DefRepo = context.repo.URI() } var resp apiDescribeCmdOutput // Now find the def for this ref. defInCurrentRepo := ref.DefRepo == context.repo.URI() if defInCurrentRepo { // Def is in the current repo. var g graph.Output graphFile := plan.SourceUnitDataFilename("graph", &unit.SourceUnit{Name: ref.DefUnit, Type: ref.DefUnitType}) f, err := context.commitFS.Open(graphFile) if err != nil { return err } defer f.Close() if err := json.NewDecoder(f).Decode(&g); err != nil { return fmt.Errorf("%s: %s", graphFile, err) } for _, def := range g.Defs { if def.Path == ref.DefPath { resp.Def = def break } } if resp.Def != nil { // If Def is in the current Repo, transform that path to be an absolute path resp.Def.File = filepath.ToSlash(filepath.Join(context.repo.RootDir, resp.Def.File)) } if resp.Def == nil && GlobalOpt.Verbose { log.Printf("No definition found with path %q in unit %q type %q.", ref.DefPath, ref.DefUnit, ref.DefUnitType) } } if err := json.NewEncoder(os.Stdout).Encode(resp); err != nil { return err } return nil }