Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit d6e9e93

Browse files
Cosmin Cojocarkeegancsmith
Cosmin Cojocar
authored andcommitted
Implement the 'textDocument/rename' command (#337)
1 parent e01bf53 commit d6e9e93

File tree

3 files changed

+123
-0
lines changed

3 files changed

+123
-0
lines changed

langserver/handler.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,15 @@ func (h *LangHandler) Handle(ctx context.Context, conn jsonrpc2.JSONRPC2, req *j
446446
}
447447
return h.handleWorkspaceReferences(ctx, conn, req, params)
448448

449+
case "textDocument/rename":
450+
if req.Params == nil {
451+
return nil, &jsonrpc2.Error{Code: jsonrpc2.CodeInvalidParams}
452+
}
453+
var params lsp.RenameParams
454+
if err := json.Unmarshal(*req.Params, &params); err != nil {
455+
return nil, err
456+
}
457+
return h.handleRename(ctx, conn, req, params)
449458
default:
450459
if isFileSystemRequest(req.Method) {
451460
uri, fileChanged, err := h.handleFileSystemRequest(ctx, req)

langserver/langserver_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,35 @@ func main() {
11811181
},
11821182
},
11831183
},
1184+
"renaming": {
1185+
rootURI: "file:///src/test/pkg",
1186+
fs: map[string]string{
1187+
"a.go": `package p
1188+
import "fmt"
1189+
1190+
func main() {
1191+
str := A()
1192+
fmt.Println(str)
1193+
}
1194+
1195+
func A() string {
1196+
return "test"
1197+
}
1198+
`,
1199+
},
1200+
cases: lspTestCases{
1201+
wantRenames: map[string]map[string]string{
1202+
"a.go:5:5": map[string]string{
1203+
"4:4-4:7": "/src/test/pkg/a.go",
1204+
"5:16-5:19": "/src/test/pkg/a.go",
1205+
},
1206+
"a.go:9:6": map[string]string{
1207+
"4:11-4:12": "/src/test/pkg/a.go",
1208+
"8:5-8:6": "/src/test/pkg/a.go",
1209+
},
1210+
},
1211+
},
1212+
},
11841213
}
11851214

11861215
func TestServer(t *testing.T) {
@@ -1314,6 +1343,7 @@ type lspTestCases struct {
13141343
wantSignatures map[string]string
13151344
wantWorkspaceReferences map[*lspext.WorkspaceReferencesParams][]string
13161345
wantFormatting map[string]map[string]string
1346+
wantRenames map[string]map[string]string
13171347
}
13181348

13191349
func copyFileToOS(ctx context.Context, fs *AtomicFS, targetFile, srcFile string) error {
@@ -1495,6 +1525,12 @@ func lspTests(t testing.TB, ctx context.Context, h *LangHandler, c *jsonrpc2.Con
14951525
formattingTest(t, ctx, c, rootURI, file, want)
14961526
})
14971527
}
1528+
1529+
for pos, want := range cases.wantRenames {
1530+
tbRun(t, fmt.Sprintf("renaming-%s", strings.Replace(pos, "/", "-", -1)), func(t testing.TB) {
1531+
renamingTest(t, ctx, c, rootURI, pos, want)
1532+
})
1533+
}
14981534
}
14991535

15001536
// tbRun calls (testing.T).Run or (testing.B).Run.
@@ -1716,6 +1752,29 @@ func formattingTest(t testing.TB, ctx context.Context, c *jsonrpc2.Conn, rootURI
17161752
}
17171753
}
17181754

1755+
func renamingTest(t testing.TB, ctx context.Context, c *jsonrpc2.Conn, rootURI lsp.DocumentURI, pos string, want map[string]string) {
1756+
file, line, char, err := parsePos(pos)
1757+
if err != nil {
1758+
t.Fatal(err)
1759+
}
1760+
1761+
workspaceEdit, err := callRenaming(ctx, c, uriJoin(rootURI, file), line, char, "")
1762+
if err != nil {
1763+
t.Fatal(err)
1764+
}
1765+
1766+
got := map[string]string{}
1767+
for file, edits := range workspaceEdit.Changes {
1768+
for _, edit := range edits {
1769+
got[edit.Range.String()] = util.UriToPath(lsp.DocumentURI(file))
1770+
}
1771+
}
1772+
1773+
if !reflect.DeepEqual(got, want) {
1774+
t.Errorf("got %v, want: %v", got, want)
1775+
}
1776+
}
1777+
17191778
func parsePos(s string) (file string, line, char int, err error) {
17201779
parts := strings.Split(s, ":")
17211780
if len(parts) != 3 {
@@ -1970,6 +2029,16 @@ func callFormatting(ctx context.Context, c *jsonrpc2.Conn, uri lsp.DocumentURI)
19702029
return edits, err
19712030
}
19722031

2032+
func callRenaming(ctx context.Context, c *jsonrpc2.Conn, uri lsp.DocumentURI, line, char int, newName string) (lsp.WorkspaceEdit, error) {
2033+
var edit lsp.WorkspaceEdit
2034+
err := c.Call(ctx, "textDocument/rename", lsp.RenameParams{
2035+
TextDocument: lsp.TextDocumentIdentifier{URI: uri},
2036+
Position: lsp.Position{Line: line, Character: char},
2037+
NewName: newName,
2038+
}, &edit)
2039+
return edit, err
2040+
}
2041+
19732042
type markedStrings []lsp.MarkedString
19742043

19752044
func (v *markedStrings) UnmarshalJSON(data []byte) error {

langserver/rename.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package langserver
2+
3+
import (
4+
"context"
5+
6+
lsp "github.com/sourcegraph/go-lsp"
7+
"github.com/sourcegraph/jsonrpc2"
8+
)
9+
10+
func (h *LangHandler) handleRename(ctx context.Context, conn jsonrpc2.JSONRPC2,
11+
req *jsonrpc2.Request, params lsp.RenameParams) (lsp.WorkspaceEdit, error) {
12+
rp := lsp.ReferenceParams{
13+
TextDocumentPositionParams: lsp.TextDocumentPositionParams{
14+
TextDocument: params.TextDocument,
15+
Position: params.Position,
16+
},
17+
Context: lsp.ReferenceContext{
18+
IncludeDeclaration: true,
19+
XLimit: 0,
20+
},
21+
}
22+
23+
references, err := h.handleTextDocumentReferences(ctx, conn, req, rp)
24+
if err != nil {
25+
return lsp.WorkspaceEdit{}, err
26+
}
27+
28+
result := lsp.WorkspaceEdit{}
29+
if result.Changes == nil {
30+
result.Changes = make(map[string][]lsp.TextEdit)
31+
}
32+
for _, ref := range references {
33+
edit := lsp.TextEdit{
34+
Range: ref.Range,
35+
NewText: params.NewName,
36+
}
37+
edits := result.Changes[string(ref.URI)]
38+
if edits == nil {
39+
edits = []lsp.TextEdit{}
40+
}
41+
edits = append(edits, edit)
42+
result.Changes[string(ref.URI)] = edits
43+
}
44+
return result, nil
45+
}

0 commit comments

Comments
 (0)