1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import Foundation
import SwiftParser
import SwiftRefactor
import SwiftSyntax
import XcodeKit
enum ExtensionError: Error {
case unsupportedContentType
case unknownRefactoring(String)
}
final class SourceEditorCommand: NSObject, XCSourceEditorCommand {
func perform(with invocation: XCSourceEditorCommandInvocation) async throws {
guard invocation.buffer.contentUTI == "public.swift-source" else {
throw ExtensionError.unsupportedContentType
}
guard let provider = RefactoringRegistry.shared[invocation.commandIdentifier] else {
throw ExtensionError.unknownRefactoring(invocation.commandIdentifier)
}
class Rewriter: SyntaxRewriter {
private let provider: any SyntaxRefactoringProvider.Type
init(provider: any SyntaxRefactoringProvider.Type) {
self.provider = provider
super.init(viewMode: .sourceAccurate)
}
override func visitAny(_ node: Syntax) -> Syntax? {
func withOpenedRefactoringProvider<T: SyntaxRefactoringProvider>(_ providerType: T.Type) -> Syntax? {
guard
let input = node.as(providerType.Input.self),
providerType.Context.self == Void.self
else {
return nil
}
let context = unsafeBitCast(Void(), to: providerType.Context.self)
return providerType.refactor(syntax: input, in: context).map { Syntax($0) }
}
return _openExistential(self.provider, do: withOpenedRefactoringProvider)
}
}
let source = Parser.parse(source: invocation.buffer.completeBuffer)
let transformedSource = Rewriter(provider: provider).visit(source)
invocation.buffer.completeBuffer = transformedSource.description
}
}
|