Skip to content

Commit 527600e

Browse files
committed
Support the prepare rename request
This allows us to return the current compound decl name when renaming a function, which will get populated as the default value for the text field in which the user enters the new symbol name. rdar://118995649
1 parent b381811 commit 527600e

File tree

4 files changed

+74
-1
lines changed

4 files changed

+74
-1
lines changed

Sources/SourceKitLSP/Rename.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,14 @@ extension SourceKitServer {
365365
}
366366
return edits
367367
}
368+
369+
func prepareRename(
370+
_ request: PrepareRenameRequest,
371+
workspace: Workspace,
372+
languageService: ToolchainLanguageServer
373+
) async throws -> PrepareRenameResponse? {
374+
try await languageService.prepareRename(request)
375+
}
368376
}
369377

370378
// MARK: - Swift
@@ -577,6 +585,25 @@ extension SwiftLanguageServer {
577585
}
578586
}
579587
}
588+
589+
public func prepareRename(_ request: PrepareRenameRequest) async throws -> PrepareRenameResponse? {
590+
let snapshot = try self.documentManager.latestSnapshot(request.textDocument.uri)
591+
592+
let response = try await self.relatedIdentifiers(
593+
at: request.position,
594+
in: snapshot,
595+
includeNonEditableBaseNames: true
596+
)
597+
guard let name = response.name,
598+
let range = response.relatedIdentifiers.first(where: { $0.range.contains(request.position) })?.range
599+
else {
600+
return nil
601+
}
602+
return PrepareRenameResponse(
603+
range: range,
604+
placeholder: name
605+
)
606+
}
580607
}
581608

582609
// MARK: - Clang
@@ -595,4 +622,8 @@ extension ClangLanguageServerShim {
595622
) async throws -> [TextEdit] {
596623
throw ResponseError.internalError("Global rename not implemented for clangd")
597624
}
625+
626+
public func prepareRename(_ request: PrepareRenameRequest) async throws -> PrepareRenameResponse? {
627+
return nil
628+
}
598629
}

Sources/SourceKitLSP/SourceKitServer.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,8 @@ extension SourceKitServer: MessageHandler {
911911
await self.handleRequest(for: request, requestHandler: self.inlayHint)
912912
case let request as RequestAndReply<DocumentDiagnosticsRequest>:
913913
await self.handleRequest(for: request, requestHandler: self.documentDiagnostic)
914+
case let request as RequestAndReply<PrepareRenameRequest>:
915+
await self.handleRequest(for: request, requestHandler: self.prepareRename)
914916
// IMPORTANT: When adding a new entry to this switch, also add it to the `TaskMetadata` initializer.
915917
default:
916918
reply(.failure(ResponseError.methodNotFound(R.method)))
@@ -1175,7 +1177,7 @@ extension SourceKitServer {
11751177
supportsCodeActions: true
11761178
)
11771179
),
1178-
renameProvider: .value(RenameOptions()),
1180+
renameProvider: .value(RenameOptions(prepareProvider: true)),
11791181
colorProvider: .bool(true),
11801182
foldingRangeProvider: .bool(!registry.clientHasDynamicFoldingRangeRegistration),
11811183
declarationProvider: .bool(true),

Sources/SourceKitLSP/ToolchainLanguageServer.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ public protocol ToolchainLanguageServer: AnyObject {
161161
newName: String
162162
) async throws -> [TextEdit]
163163

164+
/// Return compound decl name that will be used as a placeholder for a rename request at a specific position.
165+
func prepareRename(_ request: PrepareRenameRequest) async throws -> PrepareRenameResponse?
166+
164167
// MARK: - Other
165168

166169
func executeCommand(_ req: ExecuteCommandRequest) async throws -> LSPAny?

Tests/SourceKitLSPTests/RenameTests.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,4 +640,41 @@ final class RenameTests: XCTestCase {
640640
]
641641
)
642642
}
643+
644+
func testPrepeareRenameOnDefinition() async throws {
645+
let testClient = try await TestSourceKitLSPClient()
646+
let uri = DocumentURI.for(.swift)
647+
let positions = testClient.openDocument(
648+
"""
649+
func 1️⃣foo2️⃣(a: Int) {}
650+
""",
651+
uri: uri
652+
)
653+
let response = try await testClient.send(
654+
PrepareRenameRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
655+
)
656+
let range = try XCTUnwrap(response?.range)
657+
let placeholder = try XCTUnwrap(response?.placeholder)
658+
XCTAssertEqual(range, positions["1️⃣"]..<positions["2️⃣"])
659+
XCTAssertEqual(placeholder, "foo(a:)")
660+
}
661+
662+
func testPrepeareRenameOnReference() async throws {
663+
let testClient = try await TestSourceKitLSPClient()
664+
let uri = DocumentURI.for(.swift)
665+
let positions = testClient.openDocument(
666+
"""
667+
func foo(a: Int, b: Int = 1) {}
668+
1️⃣foo2️⃣(a: 1)
669+
""",
670+
uri: uri
671+
)
672+
let response = try await testClient.send(
673+
PrepareRenameRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
674+
)
675+
let range = try XCTUnwrap(response?.range)
676+
let placeholder = try XCTUnwrap(response?.placeholder)
677+
XCTAssertEqual(range, positions["1️⃣"]..<positions["2️⃣"])
678+
XCTAssertEqual(placeholder, "foo(a:b:)")
679+
}
643680
}

0 commit comments

Comments
 (0)