Skip to content

Commit 17d2605

Browse files
authored
Merge pull request #2262 from xedin/adopt-refactoring-actions-to-use-edit-provider
[SwiftLanguageService] Adopt changes to package manifest refactoring …
2 parents 415e807 + 061c7a0 commit 17d2605

File tree

3 files changed

+60
-121
lines changed

3 files changed

+60
-121
lines changed

Sources/SwiftLanguageService/CodeActions/PackageManifestEdits.swift

Lines changed: 27 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,20 @@ struct PackageManifestEdits: SyntaxCodeActionProvider {
5050
type: type
5151
)
5252

53-
let edits = try AddPackageTarget.manifestRefactor(
54-
syntax: scope.file,
55-
in: .init(target: target)
56-
)
53+
guard
54+
let edit = try AddPackageTarget.textRefactor(
55+
syntax: scope.file,
56+
in: .init(target: target)
57+
).asWorkspaceEdit(snapshot: scope.snapshot)
58+
else {
59+
continue
60+
}
5761

5862
actions.append(
5963
CodeAction(
6064
title: "Add \(name) target",
6165
kind: .refactor,
62-
edit: edits.asWorkspaceEdit(snapshot: scope.snapshot)
66+
edit: edit
6367
)
6468
)
6569
}
@@ -98,16 +102,20 @@ struct PackageManifestEdits: SyntaxCodeActionProvider {
98102
dependencies: [.byName(name: targetName)],
99103
)
100104

101-
let edits = try AddPackageTarget.manifestRefactor(
102-
syntax: scope.file,
103-
in: .init(target: target, testHarness: testingLibrary)
104-
)
105+
guard
106+
let edit = try AddPackageTarget.textRefactor(
107+
syntax: scope.file,
108+
in: .init(target: target, testHarness: testingLibrary)
109+
).asWorkspaceEdit(snapshot: scope.snapshot)
110+
else {
111+
continue
112+
}
105113

106114
actions.append(
107115
CodeAction(
108116
title: "Add test target (\(libraryName))",
109117
kind: .refactor,
110-
edit: edits.asWorkspaceEdit(snapshot: scope.snapshot)
118+
edit: edit
111119
)
112120
)
113121
}
@@ -151,16 +159,20 @@ struct PackageManifestEdits: SyntaxCodeActionProvider {
151159
targets: [targetName]
152160
)
153161

154-
let edits = try AddProduct.manifestRefactor(
155-
syntax: scope.file,
156-
in: .init(product: product)
157-
)
162+
guard
163+
let edit = try AddProduct.textRefactor(
164+
syntax: scope.file,
165+
in: .init(product: product)
166+
).asWorkspaceEdit(snapshot: scope.snapshot)
167+
else {
168+
return []
169+
}
158170

159171
return [
160172
CodeAction(
161173
title: "Add product to export this target",
162174
kind: .refactor,
163-
edit: edits.asWorkspaceEdit(snapshot: scope.snapshot)
175+
edit: edit
164176
)
165177
]
166178
} catch {
@@ -175,85 +187,6 @@ struct PackageManifestEdits: SyntaxCodeActionProvider {
175187
]
176188
}
177189

178-
fileprivate extension PackageEdit {
179-
/// Translate package manifest edits into a workspace edit. This can
180-
/// involve both modifications to the manifest file as well as the creation
181-
/// of new files.
182-
/// `snapshot` is the latest snapshot of the `Package.swift` file.
183-
func asWorkspaceEdit(snapshot: DocumentSnapshot) -> WorkspaceEdit {
184-
// The edits to perform on the manifest itself.
185-
let manifestTextEdits = manifestEdits.map { edit in
186-
TextEdit(
187-
range: snapshot.absolutePositionRange(of: edit.range),
188-
newText: edit.replacement
189-
)
190-
}
191-
192-
// If we couldn't figure out the manifest directory, or there are no
193-
// files to add, the only changes are the manifest edits. We're done
194-
// here.
195-
let manifestDirectoryURL = snapshot.uri.fileURL?
196-
.deletingLastPathComponent()
197-
guard let manifestDirectoryURL, !auxiliaryFiles.isEmpty else {
198-
return WorkspaceEdit(
199-
changes: [snapshot.uri: manifestTextEdits]
200-
)
201-
}
202-
203-
// Use the more full-featured documentChanges, which takes precedence
204-
// over the individual changes to documents.
205-
var documentChanges: [WorkspaceEditDocumentChange] = []
206-
207-
// Put the manifest changes into the array.
208-
documentChanges.append(
209-
.textDocumentEdit(
210-
TextDocumentEdit(
211-
textDocument: .init(snapshot.uri, version: snapshot.version),
212-
edits: manifestTextEdits.map { .textEdit($0) }
213-
)
214-
)
215-
)
216-
217-
// Create an populate all of the auxiliary files.
218-
for (relativePath, contents) in auxiliaryFiles {
219-
guard
220-
let url = URL(
221-
string: relativePath,
222-
relativeTo: manifestDirectoryURL
223-
)
224-
else {
225-
continue
226-
}
227-
228-
let documentURI = DocumentURI(url)
229-
let createFile = CreateFile(
230-
uri: documentURI
231-
)
232-
233-
let zeroPosition = Position(line: 0, utf16index: 0)
234-
let edit = TextEdit(
235-
range: zeroPosition..<zeroPosition,
236-
newText: contents.description
237-
)
238-
239-
documentChanges.append(.createFile(createFile))
240-
documentChanges.append(
241-
.textDocumentEdit(
242-
TextDocumentEdit(
243-
textDocument: .init(documentURI, version: snapshot.version),
244-
edits: [.textEdit(edit)]
245-
)
246-
)
247-
)
248-
}
249-
250-
return WorkspaceEdit(
251-
changes: [snapshot.uri: manifestTextEdits],
252-
documentChanges: documentChanges
253-
)
254-
}
255-
}
256-
257190
fileprivate extension SyntaxProtocol {
258191
// Find an enclosing call syntax expression.
259192
func findEnclosingCall() -> FunctionCallExprSyntax? {

Sources/SwiftLanguageService/CodeActions/SyntaxRefactoringCodeActionProvider.swift

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,26 +37,15 @@ extension SyntaxRefactoringCodeActionProvider where Self.Context == Void {
3737
return []
3838
}
3939

40-
let textEdits = sourceEdits.compactMap { (edit) -> TextEdit? in
41-
let edit = TextEdit(
42-
range: scope.snapshot.absolutePositionRange(of: edit.range),
43-
newText: edit.replacement
44-
)
45-
if edit.isNoOp(in: scope.snapshot) {
46-
return nil
47-
}
48-
return edit
49-
}
50-
51-
if textEdits.isEmpty {
40+
guard let workspaceEdit = sourceEdits.asWorkspaceEdit(snapshot: scope.snapshot) else {
5241
return []
5342
}
5443

5544
return [
5645
CodeAction(
5746
title: Self.title,
5847
kind: .refactorInline,
59-
edit: WorkspaceEdit(changes: [scope.snapshot.uri: textEdits])
48+
edit: workspaceEdit
6049
)
6150
]
6251
}
@@ -140,3 +129,30 @@ extension SyntaxProtocol {
140129
return nil
141130
}
142131
}
132+
133+
extension [SourceEdit] {
134+
/// Translate source edits into a workspace edit.
135+
/// `snapshot` is the latest snapshot of the document to which these edits belong.
136+
func asWorkspaceEdit(snapshot: DocumentSnapshot) -> WorkspaceEdit? {
137+
let textEdits = compactMap { edit -> TextEdit? in
138+
let edit = TextEdit(
139+
range: snapshot.absolutePositionRange(of: edit.range),
140+
newText: edit.replacement
141+
)
142+
143+
if edit.isNoOp(in: snapshot) {
144+
return nil
145+
}
146+
147+
return edit
148+
}
149+
150+
if textEdits.isEmpty {
151+
return nil
152+
}
153+
154+
return WorkspaceEdit(
155+
changes: [snapshot.uri: textEdits]
156+
)
157+
}
158+
}

Tests/SourceKitLSPTests/CodeActionTests.swift

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -623,29 +623,19 @@ final class CodeActionTests: XCTestCase {
623623
}
624624
)
625625

626-
guard let addTestChanges = addTestAction?.edit?.documentChanges else {
626+
guard let addTestChanges = addTestAction?.edit?.changes else {
627627
XCTFail("Didn't have changes in the 'Add test target (Swift Testing)' action")
628628
return
629629
}
630630

631-
guard
632-
let addTestEdit = addTestChanges.lazy.compactMap({ change in
633-
switch change {
634-
case .textDocumentEdit(let edit): edit
635-
default: nil
636-
}
637-
}).first
638-
else {
631+
guard let manifestEdits = addTestChanges[uri] else {
639632
XCTFail("Didn't have edits")
640633
return
641634
}
642635

643636
XCTAssertTrue(
644-
addTestEdit.edits.contains { edit in
645-
switch edit {
646-
case .textEdit(let edit): edit.newText.contains("testTarget")
647-
case .annotatedTextEdit(let edit): edit.newText.contains("testTarget")
648-
}
637+
manifestEdits.contains { edit in
638+
edit.newText.contains("testTarget")
649639
}
650640
)
651641

0 commit comments

Comments
 (0)