Files
sourcekit-lsp/Sources/SourceKitLSP/Swift/CodeActions/SyntaxCodeActionProvider.swift
Doug Gregor a8b61a52d3 Introduce new refactoring code actions based on the Swift syntax tree.
This change includes a number of new refactoring code actions that
build on the syntax refactorings for the SwiftRefactor module of swift-syntax:

  * Add digit separators to an integer literal, e.g., `1000000` ->
    `1_000_000`.
  * Remove digit separators from an integer literal, e.g., 1_000_000 ->
    1000000.
  * Format a raw string literal, e.g., `"Hello \#(world)"` ->
    `##"Hello\#(world)"##`
  * Migrate to new if let syntax, e.g., `if let x = x { ... }` ->
    `if let x { ... }`
  * Replace opaque parameters with generic parameters, e.g.,
    `func f(p: some P)` --> `func f<T1: P>(p: T1)`.

This is generally easy to do, requiring one conformance to provide a name for the refactoring:

    extension AddSeparatorsToIntegerLiteral: SyntaxRefactoringCodeActionProvider {
      public static var title: String { "Add digit separators" }
    }
2024-04-16 23:00:20 -07:00

66 lines
2.3 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 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 LSPLogging
import LanguageServerProtocol
import SwiftRefactor
import SwiftSyntax
/// Describes types that provide one or more code actions based on purely
/// syntactic information.
protocol SyntaxCodeActionProvider {
/// Produce code actions within the given scope. Each code action
/// corresponds to one syntactic transformation that can be performed, such
/// as adding or removing separators from an integer literal.
static func codeActions(in scope: SyntaxCodeActionScope) -> [CodeAction]
}
/// Defines the scope in which a syntactic code action occurs.
struct SyntaxCodeActionScope {
/// The snapshot of the document on which the code actions will be evaluated.
var snapshot: DocumentSnapshot
/// The actual code action request, which can specify additional parameters
/// to guide the code actions.
var request: CodeActionRequest
/// The source file in which the syntactic code action will operate.
var file: SourceFileSyntax
/// The UTF-8 byte range in the source file in which code actions should be
/// considered, i.e., where the cursor or selection is.
var range: Range<AbsolutePosition>
init(
snapshot: DocumentSnapshot,
syntaxTree tree: SourceFileSyntax,
request: CodeActionRequest
) throws {
self.snapshot = snapshot
self.request = request
self.file = tree
let start = snapshot.absolutePosition(of: request.range.lowerBound)
let end = snapshot.absolutePosition(of: request.range.upperBound)
let left = file.token(at: start)
let right = file.token(at: end)
let leftOff = left?.position ?? AbsolutePosition(utf8Offset: 0)
let rightOff = right?.endPosition ?? leftOff
self.range = leftOff..<rightOff
}
/// The first token in the
var firstToken: TokenSyntax? {
file.token(at: range.lowerBound)
}
}