用于构建 Chime 扩展的框架

许可证

编钟套件

用于构建 Chime 扩展的框架。

概述

Chime的扩展基于ExtensionKit。它们是用 Swift 和 SwiftUI 编写的。ChimeKit 还包括一个用于将语言服务器协议服务器与扩展 API 集成的系统。

在大多数情况下,ChimeKit抽象出所有扩展工具包的详细信息。您针对 ChimeKit API 而不是 ExtensionKit 基元进行编程。但是,ExtensionKit 确实施加了一些与您必须注意的安全性和分发相关的要求。ChimeKit 开发需要 Xcode 14、Swift 5.7 和 macOS Ventura(13.0)。

⚠️ ChimeKit 包含一些尚未完成的较低级别的私有 API。这些不会影响支持的扩展 API,但会影响二进制兼容性。

Chime 2.0 的早期测试版可供测试

沙盒

扩展工具包扩展必须沙盒化。ChimeKit透明地管理用户打开的文档和目录的所有权限。但是,在沙盒中运行可能会导致无法托管 LSP 服务器,这是 Chime 扩展的核心用例之一。ChimeKit 包含一个用于在沙盒之外运行可执行文件的系统。它基于ProcessService

分配

扩展工具包扩展必须在包装器应用程序中提供。您绝对可以自己构建它,甚至可以在现有应用程序中托管 Chime 扩展。您甚至可以将这些放在App Store上并收取费用!

但是,如果您不想为此烦恼,我们有一个解决方案正在开发中。

编钟扩展图库

这是一个第一方扩展托管应用程序,由我们的开发者 ID 签名。它将处理发现和更新,所有开源扩展都有资格申请收录。这个应用程序将是开源的,但它即将推出。如何整合您的资源的实际细节尚未确定,因此如果您有想法,请与我们联系。

我们的理念

我们希望为扩展提供简单的用户体验,尤其是语言支持。我们认为为一种语言提供四种不同的扩展并不好。因此,虽然我们不会把关,但我们对每种语言的一个扩展会有非常强烈的偏见。

LSP 在语言支持扩展中很普遍。许多 IDE 使用每个语言服务器一个扩展的模型。ChimeKit允许每个扩展使用多个服务器。我们将 LSP 服务器视为语言支持的实现细节。协调多个服务器的行为是扩展的工作,而不是用户的工作。

Chime’s core Go and Ruby support aren’t open source, yet. But, we will be publishing them. And, going forward, we will always begin work on new language support as open source projects.

Integration

ChimeKit supports two different integration options, both available via SPM.

dependencies: [
    .package(url: "https://github.com/ChimeHQ/ChimeKit")
]

This package includes the modules , which you can use directly. These do not provide out-of-sandbox-executable support without work from you.ChimeExtensionInterfaceChimeLSPAdapter

You can also use the bundled , which provides the same API and does include the ability to transparently run executables. However, due to an SPM limitation, your extension Xcode target must depend on but link against the framework. The framework must also be copied into your extension/wrapper app to be found at runtime.ChimeKit.xcframeworkChimeKitWrapper

Chime uses the ChimeKit binary xcframework as its own interface to extensions. This means that there could be drift between the app and the extension. We’ll do our best to minimize ABI- and API-incompatible changes, and use deprecations, but these kinds of changes are inevitable. Chime cannot make its own copy of ChimeKit available to extensions for runtime linking, but that would help reduce issues here. If you’d like to see that, please file feedback with Apple asking for the feature.

Documentation

This is an area of active work. Right now, autocomplete is your friend 🥴. We’re putting this out there extra-early to try to get some feedback and thoughts on API.

Please don’t be shy to reach out to us – we’ll help!

New Languages

Adding support for a new languages has multiple components. Source interactions, like highlighting and indenting, are low-latency operations that must happen within the Chime main application. These things cannot be done by an extension today.

If Chime does not support a language you’d like to use, the first step is to let us know! Our process will look like this:

  • Create an SPM-based tree-sitter parser tree-sitter
  • Ensure that parser has the needed queries defined
  • Encorporate the parser and queries into a new Chime build

Your process will depend on what kind of support you need to build. If you are using an LSP server, at a minimum, you’ll need to ensure that LanguageServerProtocol has a language identifier constant defined. After that, your extension does the rest, most likely by making use of the API within the module of ChimeKit.LSPServiceChimeLSPAdapter

Non-UI Extension

Extension point identifier: com.chimehq.Edit.extension

import Foundation

import ChimeKit

@main
class NoUIExtension: ChimeExtension {
    var hostApp: HostProtocol?

    required init() {
    }

    func documentService(for context: DocumentContext) async throws -> DocumentService? {
        return self
    }
}

extension NoUIExtension: DocumentService {
    var completionService: CompletionService? {
        get async throws { return self }
    }
}

extension NoUIExtension: CompletionService {
    func completions(at position: CombinedTextPosition, trigger: CompletionTrigger) async throws -> [Completion] {
        let range = TextRange.range(NSRange(location: position.location, length: 0))
        let completion = Completion(displayString: "hello!", range: range, fragments: [])

        return [completion]
    }
}

Fixed Sidebar Extension

Extension point identifier: com.chimehq.Edit.extension.ui.sidebar

import Foundation
import SwiftUI

import ChimeKit

@main
class SidebarExtension: SidebarChimeUIExtension {
    var hostApp: HostProtocol?

    required init() {
    }
    
    var body: some View {
        VStack {
            Rectangle().frame(width: nil, height: 4).foregroundColor(.red)
            Spacer()
            Text("Hello, app extension!")
            Spacer()
            Rectangle().frame(width: nil, height: 4).foregroundColor(.blue)
        }
    }
}

Document-Synced Extension

Extension point identifier: com.chimehq.Edit.extension.ui.document-synced

import Foundation
import SwiftUI

import ChimeKit

@main
class SidebarExtension: DocumentSyncedChimeUIExtension {
    var hostApp: HostProtocol?

    required init() {
    }
    
    var body: some View {
        VStack {
            Rectangle().frame(width: nil, height: 4).foregroundColor(.red)
            Spacer()
            Text("Hello, doc-synced extension!")
            Spacer()
            Rectangle().frame(width: nil, height: 4).foregroundColor(.blue)
        }
    }
}

Suggestions or Feedback

We’d love to hear from you! Get in touch via twitter, an issue, or a pull request.

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

GitHub

点击跳转