Skip to content

Commit

Permalink
fix: Resolve issues with graph command and definition provider
Browse files Browse the repository at this point in the history
  • Loading branch information
taichimaeda committed Oct 15, 2023
1 parent 4a59f18 commit 06c1dc8
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 114 deletions.
141 changes: 87 additions & 54 deletions cmd/wireplus/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,8 @@ func (*detailCmd) Synopsis() string {
func (*detailCmd) Usage() string {
return `detail [package] [name]
detail is essentially equivalent to show but you can specify the name
detail is equivalent to show but only shows a provider set with the given name
and does not describe injectors.
`
}
func (cmd *detailCmd) SetFlags(f *flag.FlagSet) {
Expand Down Expand Up @@ -667,7 +668,7 @@ func (cmd *detailCmd) Execute(ctx context.Context, f *flag.FlagSet, args ...inte
sb.WriteString(fmt.Sprintf("\t%s\n", imp))
}
for i := range outGroups {
sb.WriteString(fmt.Sprintf("\tOutputs given %s:\n", outGroups[i].name))
sb.WriteString(fmt.Sprintf("\n\tOutputs given %s:\n", outGroups[i].name))
out := make(map[string]token.Pos, outGroups[i].outputs.Len())
outGroups[i].outputs.Iterate(func(t types.Type, v interface{}) {
switch v := v.(type) {
Expand Down Expand Up @@ -801,12 +802,13 @@ func (cmd *lspCmd) Execute(ctx context.Context, f *flag.FlagSet, args ...interfa
}
if _, ok := msg["id"]; !ok {
// Notification received
// TODO: Sending as error for debugging purposes.
lsp.SendError("received notification: %v\n", string(buf))
switch method {
case "initialized":
case "exit":
return subcommands.ExitFailure
// TODO
// TODO: Support client with autosave disabled.
case "textDocument/didOpen", "textDocument/didSave", "textDocument/didChange":
event := &lsp.DidSaveTextDocumentNotification{}
if ok := lsp.ParseRequest(buf, event); !ok {
Expand All @@ -819,6 +821,8 @@ func (cmd *lspCmd) Execute(ctx context.Context, f *flag.FlagSet, args ...interfa
lsp.SendError("invalid notification: %v\n", string(buf))
}
} else {
// TODO: Sending as error for debugging purposes.
lsp.SendError("received request: %v\n", string(buf))
switch method {
case "initialize":
req := &lsp.InitializeRequest{}
Expand Down Expand Up @@ -904,58 +908,79 @@ func (cmd *lspCmd) processDefinitionRequest(ctx context.Context, req *lsp.Defini
return res
}
if len(pkgs) != 1 {
lsp.SendError("")
lsp.SendError("expected exactly one package")
return res
}
pkg := pkgs[0]
pos := lsp.CalculatePos(pkg.Fset, url.Path, req.Params.Position.Line, req.Params.Position.Character)
file := pkg.Fset.Position(pos).Filename
line := req.Params.Position.Line
char := req.Params.Position.Character
pos := lsp.CalculatePos(pkg.Fset, url.Path, line, char)
for _, f := range pkg.Syntax {
if file != url.Path {
continue
}
path, ok := astutil.PathEnclosingInterval(f, pos, pos)
if !ok {
lsp.SendError("")
return res
}
node := path[0]
if ident, ok := node.(*ast.Ident); ok {
obj := pkg.TypesInfo.ObjectOf(ident)
wd := pkg.Module.Path
pattern := []string{obj.Pkg().Path()}
pkgs, errs := wire.LoadPackages(ctx, wd, os.Environ(), cmd.tags, pattern)
if len(errs) > 0 {
lsp.SendError("")
return res
}
if len(pkgs) != 1 {
lsp.SendError("")
file := pkg.Fset.File(f.Pos())
if base := file.Base(); base <= int(pos) && int(pos) < base+file.Size() {
path, ok := astutil.PathEnclosingInterval(f, pos, pos)
if !ok {
lsp.SendError("invalid position within file")
return res
}
pkg := pkgs[0]
position := pkg.Fset.Position(obj.Pos())
line := position.Line
char := position.Column
res.Result = &lsp.Location{
Uri: obj.Pkg().Path(),
Range: lsp.Range{
Start: lsp.Position{
Line: line,
Character: char,
},
End: lsp.Position{
Line: line,
Character: char,
node := path[0]
if ident, ok := node.(*ast.Ident); ok {
// TODO: Check this works for packages above the wd
tarObj := pkg.TypesInfo.ObjectOf(ident)
tarWd, ok := absolutePath(wd, tarObj.Pkg().Path())
if !ok {
lsp.SendError("unknown import path")
}
tarPattern := []string{"."}
tarPkgs, errs := wire.LoadPackages(ctx, tarWd, os.Environ(), cmd.tags, tarPattern)
if len(errs) > 0 {
lsp.SendErrors(errs)
return res
}
if len(tarPkgs) != 1 {
lsp.SendError("expected exactly one package")
return res
}
tarPkg := tarPkgs[0]
// TODO: Somehow jumps to a random position
tarPosition := tarPkg.Fset.Position(tarObj.Pos())
tarFilename := tarPosition.Filename
tarLine := tarPosition.Line
tarChar := tarPosition.Column
res.Result = &lsp.Location{
Uri: tarFilename,
Range: lsp.Range{
Start: lsp.Position{
Line: tarLine,
Character: tarChar,
},
End: lsp.Position{
Line: tarLine,
Character: tarChar,
},
},
},
}
return res
}
return res
}
}
return res
}

func absolutePath(wd string, importPath string) (string, bool) {
tmp := "go list -f '{{.ImportPath}}:{{.Dir}}' all | grep "
cmd := exec.Command("sh", "-c", tmp+importPath)
cmd.Dir = wd
stdout, err := cmd.CombinedOutput()
if err != nil {
return "", false
}
line := string(stdout)
parts := strings.Split(line, ":")
absPath := strings.TrimSpace(parts[1])
return absPath, true
}

func (cmd *lspCmd) processCodeLensRequest(ctx context.Context, req *lsp.CodeLensRequest) *lsp.CodeLensResponse {
res := &lsp.CodeLensResponse{
Jsonrpc: "2.0",
Expand All @@ -978,27 +1003,35 @@ func (cmd *lspCmd) processCodeLensRequest(ctx context.Context, req *lsp.CodeLens
}
var codeLenses []lsp.CodeLens
for _, inj := range info.Injectors {
file := info.Fset.File(inj.Pos)
if file.Name() != url.Path {
continue
}
codeLenses = append(codeLenses, makeCodeLens(
info,
inj.Pos,
"Show Graph",
"exampleExtension.showGraph",
"wireplus.showGraph",
[]interface{}{wd, inj.FuncName}),
)
}
for _, set := range info.Sets {
file := info.Fset.File(set.Pos)
if file.Name() != url.Path {
continue
}
codeLenses = append(codeLenses, makeCodeLens(
info,
set.Pos,
"Show Graph",
"exampleExtension.showGraph",
"wireplus.showGraph",
[]interface{}{wd, set.VarName}),
)
codeLenses = append(codeLenses, makeCodeLens(
info,
set.Pos,
"Show Details",
"exampleExtension.showDetail",
"Show Detail",
"wireplus.showDetail",
[]interface{}{wd, set.VarName}),
)
}
Expand All @@ -1022,8 +1055,8 @@ func makeCodeLens(info *wire.Info, pos token.Pos, title string, cmd string, args
},
},
Command: lsp.Command{
Title: "Show Graph",
Command: "exampleExtension.showGraph",
Title: title,
Command: cmd,
Arguments: args,
},
}
Expand All @@ -1041,13 +1074,13 @@ func (cmd *lspCmd) createPublishDiagnosticsNotification(ctx context.Context, eve
// to clear existing diagnostics
diags := make([]lsp.Diagnostic, 0)
for _, err := range errs {
werr := err.(*wire.WireErr)
file := werr.Position().Filename
if file != url.Path {
wireErr := err.(*wire.WireErr)
position := wireErr.Position()
if position.Filename != url.Path {
continue
}
line := werr.Position().Line - 1
char := werr.Position().Column - 1
line := wireErr.Position().Line - 1
char := wireErr.Position().Column - 1
diags = append(diags, lsp.Diagnostic{
Range: lsp.Range{
Start: lsp.Position{
Expand All @@ -1059,7 +1092,7 @@ func (cmd *lspCmd) createPublishDiagnosticsNotification(ctx context.Context, eve
Character: 0,
},
},
Message: werr.Message(),
Message: wireErr.Message(),
})
}
notif := &lsp.PublishDiagnosticsNotification{
Expand Down
4 changes: 2 additions & 2 deletions internal/wire/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ type buildSolution struct {
}

func solveForBuild(pkg *packages.Package, name string) (*buildSolution, []error) {
fn := findFuncDeclByName(pkg, name)
fn := findFuncDecl(pkg, name)
if fn == nil {
return nil, []error{fmt.Errorf("no function named %s found", name)}
}
Expand Down Expand Up @@ -695,7 +695,7 @@ type newSetSolution struct {
}

func solveForNewSet(pkg *packages.Package, name string) (*newSetSolution, []error) {
set := findVarExprByName(pkg, name)
set := findVarExpr(pkg, name)
if set == nil {
return nil, []error{fmt.Errorf("no value named %s found", name)}
}
Expand Down
23 changes: 6 additions & 17 deletions internal/wire/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,30 +30,19 @@ func Graph(ctx context.Context, wd string, env []string, pattern []string, name
return nil, []error{fmt.Errorf("expected exactly one package")}
}
pkg := pkgs[0]
fn := findFuncDeclByName(pkg, name)
set := findVarExprByName(pkg, name)

switch {
case set != nil:
sol, errs := solveForNewSet(pkg, name)
if len(errs) > 0 {
return nil, errs
}
if sol, errs := solveForNewSet(pkg, name); len(errs) == 0 {
addInputsForNewSet(gviz, sol.missing)
addOutputs(gviz, sol.calls, sol.pset, pkg.Fset)
addDepsForNewSet(gviz, sol.calls, sol.missing, pkg.Fset)
case fn != nil:
sol, errs := solveForBuild(pkg, name)
if len(errs) > 0 {
return nil, errs
}
return gviz, nil
}
if sol, errs := solveForBuild(pkg, name); len(errs) == 0 {
addInputsForBuild(gviz, sol.ins)
addOutputs(gviz, sol.calls, sol.pset, pkg.Fset)
addDepsForBuild(gviz, sol.calls, sol.ins, pkg.Fset)
default:
return nil, []error{fmt.Errorf("no function or variable named %q found", name)}
return gviz, nil
}
return gviz, nil
return nil, errs
}

func addInputsForNewSet(gviz *Graphviz, missing []*types.Type) {
Expand Down
13 changes: 7 additions & 6 deletions internal/wire/lsp/lsp.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ func ReadBuffer(reader *bufio.Reader) ([]byte, bool) {
fmt.Fprintf(os.Stderr, "error reading header: %v\n", err)
return nil, false
}
if header == "\r\n" {
break
}
// TODO: trim the remaining \r also
header = strings.TrimSpace(header)
if header == "" {
break
}
switch {
case strings.HasPrefix(header, "Content-Length: "):
value := strings.TrimPrefix(header, "Content-Length: ")
Expand Down Expand Up @@ -106,6 +106,7 @@ func ParseDocumentUri(uri string) *url.URL {
return url
}

// line and char must be zero-based
func CalculatePos(fset *token.FileSet, path string, line int, char int) token.Pos {
var file *token.File
fset.Iterate(func(f *token.File) bool {
Expand All @@ -115,7 +116,7 @@ func CalculatePos(fset *token.FileSet, path string, line int, char int) token.Po
}
return true
})
offset := int(file.LineStart(line)) - int(file.Base())
offset += char
return file.Pos(offset)
// LineStart accepts one-based line number
start := file.LineStart(line + 1)
return token.Pos(int(start) + char)
}
2 changes: 1 addition & 1 deletion internal/wire/lsp/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ type InitializeResult struct {
type ServerCapabilities struct {
TextDocumentSync int `json:"textDocumentSync"`
CodeLensProvider bool `json:"codeLensProvider"`
DefinitionProvider bool `json:"definition"`
DefinitionProvider bool `json:"definitionProvider"`
Workspace WorkspaceServerCapabilities `json:"workspace"`
}

Expand Down
Loading

0 comments on commit 06c1dc8

Please sign in to comment.