CodeEditor

SwiftUI Swift5 macOS iOS visionOS Build and Test

一个使用 SwiftUI 构建的 TextEditor 视图,支持使用 Highlight.js 进行语法高亮。

它构建于 Highlightr 之上,Highlightr 封装了 Highlight.js。 CodeEditor 然后将这些内容打包以便在 SwiftUI 中使用。

用于 SwiftUI 的 SVG Shaper 中的使用示例 (用于编辑 SVG 和 Swift 源代码)

SVG Shaper Screenshot

(Shaper 实际上没有使用 Highlightr,但在其他方面非常相似)。

Highlightr 示例

Highlight Example

用法

添加包

Swift 包 URL 是: https://github.com/ZeeZide/CodeEditor.git

在 SwiftUI 应用程序中使用

要将 CodeEditor 用作源代码查看器,只需将源代码作为字符串传递即可

struct ContentView: View {

    var body: some View {
        CodeEditor(source: "let a = 42")
    }
}

如果它应该充当实际的编辑器,请传入一个字符串 Binding

struct ContentView: View {

    @State private var source = "let a = 42\n"
    
    var body: some View {
        CodeEditor(source: $source, language: .swift, theme: .ocean)
    }
}

语言和主题

Highlight.js 支持超过 180 种语言和 80 多种不同的主题。

可以使用以下方式访问可用的语言和主题

CodeEditor.availableLanguages
CodeEditor.availableThemes

它们可以在 SwiftUI Picker 中使用,如下所示

struct MyEditor: View {
  
    @State private var source   = "let it = be"
    @State private var language = CodeEditor.Language.swift

    var body: some View {
        Picker("Language", selection: $language) {
            ForEach(CodeEditor.availableLanguages) { language in
                Text("\(language.rawValue.capitalized)")
                    .tag(language)
            }
        }
    
        CodeEditor(source: $source, language: language)
    }
}

注意:如果外观发生更改,CodeEditor 不会自动进行主题更改。

智能缩进和开/关配对

NTYSmartTextView 的启发,CodeEditor 现在还支持(在 macOS 上):

要启用智能缩进,请添加 smartIndent 标志,例如

CodeEditor(source: $source, language: language, 
           flags: [ .selectable, .editable, .smartIndent ])

默认情况下,编辑器已启用此功能。

要配置软缩进,请使用 indentStyle 参数,例如

CodeEditor(source: $source, language: language,
           indentStyle: .softTab(width: 2))

默认设置为制表符,与系统设置一致。

自动字符配对是根据语言自动进行的。 例如,对于类似 C 的语言(例如 Swift)、Python 或 XML 有一组默认值。 可以使用 CodeEditor 中相应的静态变量覆盖默认值,或者可以显式设置所需的配对

CodeEditor(source: $source, language: language,
           autoPairs: [ "{": "}", "<": ">", "'": "'" ])

字体大小

在 macOS 上,编辑器支持字体大小调整(使用 Cmd +/Cmd - 和字体面板)。 要启用大小调整命令,WindowScene 需要应用正确的命令,例如

WindowGroup {
    ContentView()
}
.commands {
    TextFormattingCommands()
}

要持久化大小,可以使用 fontSize binding。

选择和滚动

可以通过另一个 Binding 观察和修改所选文本

 struct ContentView: View {
    static private let initialSource = "let a = 42\n"

    @State private var source = Self.initialSource
    @State private var selection = Self.initialSource.endIndex..<Self.initialSource.endIndex

    var body: some View {
        CodeEditor(source: $source,
                   selection: $selection,
                   language: .swift,
                   theme: .ocean,
                   autoscroll: false)
        Button("Select All") {
            selection = source.startIndex..<source.endIndex
        }
    }
}

autoscrolltrue 时,当从外部(即通过编程方式)修改 selection 时,编辑器会自动滚动到相应的光标位置。

Highlightr 和 Shaper

基于出色的 Highlightr。 这意味着它使用 JavaScriptCore 作为实际的驱动程序。 正如 Highlightr 所说

它永远不会像原生解决方案那样快,但它足够快,可以在实时编辑器上使用。

该编辑器与 用于 SwiftUI 的 SVG Shaper(用于其 SVG 和 Swift 编辑器部分)使用的编辑器类似(但不完全相同)。

完整示例

import SwiftUI
import CodeEditor

struct ContentView: View {
  
  #if os(macOS)
    @AppStorage("fontsize") var fontSize = Int(NSFont.systemFontSize)
  #endif
  @State private var source = "let a = 42"
  @State private var language = CodeEditor.Language.swift
  @State private var theme    = CodeEditor.ThemeName.pojoaque

  var body: some View {
    VStack(spacing: 0) {
      HStack {
        Picker("Language", selection: $language) {
          ForEach(CodeEditor.availableLanguages) { language in
            Text("\(language.rawValue.capitalized)")
              .tag(language)
          }
        }
        Picker("Theme", selection: $theme) {
          ForEach(CodeEditor.availableThemes) { theme in
            Text("\(theme.rawValue.capitalized)")
              .tag(theme)
          }
        }
      }
      .padding()
    
      Divider()
    
      #if os(macOS)
        CodeEditor(source: $source, language: language, theme: theme,
                   fontSize: .init(get: { CGFloat(fontSize)  },
                                   set: { fontSize = Int($0) }))
          .frame(minWidth: 640, minHeight: 480)
      #else
        CodeEditor(source: $source, language: language, theme: theme)
      #endif
    }
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

关于

CodeEditor 由 ZeeZide 提供。 我们喜欢反馈、GitHub 星标、酷炫的合同工作,大概是您能想到的任何形式的赞美。