CodeEditor - A SwiftUI TextEditor with syntax highlighting using Highlight.js

Overview

CodeEditor

SwiftUI Swift5.3 macOS iOS Build and Test

A SwiftUI TextEditor View with syntax highlighting using Highlight.js.

It builds on top of Highlightr which does the wrapping of Highlight.js. CodeEditor then packages things up for SwiftUI.

Example usage in SVG Shaper for SwiftUI (used for editing SVG and Swift source):

SVG Shaper Screenshot

(Shaper is not actually using Highlightr, but is otherwise quite similar).

Highlightr example:

Highlight Example

Usage

Adding the Package

The Swift package URL is: https://github.com/ZeeZide/CodeEditor.git

Using it in a SwiftUI App

To use CodeEditor as a source code viewer, simply pass the source code as a string:

struct ContentView: View {

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

If it should act as an actual editor, pass in a string Binding:

struct ContentView: View {

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

Languages and Themes

Highlight.js. supports more than 180 languages and over 80 different themes.

The available languages and themes can be accessed using:

CodeEditor.availableLanguages
CodeEditor.availableThemes

They can be used in a SwiftUI Picker like so:

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)
    }
}

Note: The CodeEditor doesn't do automatic theme changes if the appearance changes.

Smart Indent and Open/Close Pairing

Inspired by NTYSmartTextView, CodeEditor now also supports (on macOS):

  • smarter indents (preserving the indent of the previous line)
  • soft indents (insert a configurable amount of spaces if the user presses tabs)
  • auto character pairing, e.g. when entering {, the matching } will be auto-added

To enable smart indents, add the smartIndent flag, e.g.:

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

It is enabled for editors by default.

To configure soft indents, use the indentStyle parameter, e.g.

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

It defaults to tabs, as per system settings.

Auto character pairing is automatic based on the language. E.g. there is a set of defaults for C like languages (e.g. Swift), Python or XML. The defaults can be overridden using the respective static variable in CodeEditor, or the desired pairing can be set explicitly:

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

Font Sizing

On macOS the editor supports sizing of the font (using Cmd +/Cmd - and the font panel). To enable sizing commands, the WindowScene needs to have the proper commands applied, e.g.:

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

To persist the size, the fontSize binding is available.

Highlightr and Shaper

Based on the excellent Highlightr. This means that it is using JavaScriptCore as the actual driver. As Highlightr says:

It will never be as fast as a native solution, but it's fast enough to be used on a real time editor.

The editor is similar to (but not exactly the same) the one used by SVG Shaper for SwiftUI, for its SVG and Swift editor parts.

Complete Example

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) { theme in
          ForEach(CodeEditor.availableThemes) {
            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()
  }
}

Who

SVGWebView is brought to you by ZeeZide. We like feedback, GitHub stars, cool contract work, presumably any form of praise you can think of.

Comments
  • Add support for observing and modifying the selected text range.

    Add support for observing and modifying the selected text range.

    This PR addresses #2.

    The selected text range can be observed and modified via another Binding now:

     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
            }
        }
    }
    

    When autoscroll is true, the editor automatically scrolls to the respective cursor position when selection is modfied from the outside, i.e. programatically.

    opened by theMomax 5
  • [BUG] - CodeEditor is affected by ColorPicker

    [BUG] - CodeEditor is affected by ColorPicker

    When CodeEditor and ColorPicker are used at the same time, the color of CodeEditor changes

    import SwiftUI
    import CodeEditor
    
    struct ContentView: View {
        @State private var source = """
    struct ContentView: View {
        @State private var source = "let a = 42\n"
        @State var color: Color = Color.white
        var body: some View {
            HStack {
                ColorPicker("Color Picker", selection: $color)
                CodeEditor(source: $source, language: .swift, theme: .ocean)
            }
        }
    }
    """
        @State var color: Color = Color.white
        var body: some View {
            HStack {
                ColorPicker("Color Picker", selection: $color)
                CodeEditor(source: $source, language: .swift, theme: .ocean)
            }
        }
    }
    

    https://user-images.githubusercontent.com/84154073/164365639-cad35ec1-ac9e-4ce4-82b8-66e1c7b589e7.mov

    bug 
    opened by SNQ-2001 3
  • How to turn off smart dash

    How to turn off smart dash

    If using lua, then double dash aka -- is comment character. iOS has the feature to merge -- into a longer single dash..... Any idea, how to turn this off in CodeEditor ? I could not find any solution

    opened by gin66 2
  • Keyboard shortcuts

    Keyboard shortcuts

    Hello, Thanks for this great library!

    A beginner's question: what's the easiest way to add keyboard shortcuts? I'd like to execute a closure upon receiving a specific keyboard combination, ex. Cmd-R.

    Thanks!

    opened by iliasaz 2
  • How to use a customized font in IOS?

    How to use a customized font in IOS?

    I switched from SwiftUI's TextEditor to this CodeEditor. it really amazed me. However, I found I cannot specify the font and font size as I did in the TextEditor. The code is as follow,

    CodeEditor(source: $formulaInput, language: .python, theme: .default,
                           autoPairs: ["(" : ")", "{" : "}", "[" : "]"])
                    .font(.custom("SF Mono Bold", size: fontSize))
    

    Can you teach me how to use a customized font? Thank you so much

    opened by InkosiZhong 1
  • Add a Binding to report the currently selected range

    Add a Binding to report the currently selected range

    I want to insert some text in the code editor. Markdown example: Select some text, press Cmd-B for Bold, and have two asterisks inserted before and after the selection. But to do this, I need to get the code editor's selection range. How do I get the selection range?

    enhancement 
    opened by SwiftDevJournal 1
  • Correction of README

    Correction of README

    I noticed that the README was wrong, so I fixed it.

    Picker("Theme", selection: $theme) { theme in
      ForEach(CodeEditor.availableThemes) {
        Text("\(theme.rawValue.capitalized)")
          .tag(theme)
      }
    }
    

    ↓ Change ↓

    Picker("Theme", selection: $theme) {
      ForEach(CodeEditor.availableThemes) { theme in
        Text("\(theme.rawValue.capitalized)")
          .tag(theme)
      }
    }
    
    opened by SNQ-2001 0
  • Add missing delegate function (iOS)

    Add missing delegate function (iOS)

    Summary

    This PR adds missing UITextViewDelegate's function, which fixes #6.

    What was done

    • [x] Implement textViewDidChange(_ textView: UITextView) function in UXCodeTextViewRepresentable.Coordinator class.
    opened by darrarski 0
  • Binding does not work on iOS 15.2

    Binding does not work on iOS 15.2

    Description

    When a user enters text into CodeEditor, the binding is not called. This happens only on iOS. When using CodeEditor in a macOS app, there are no issues.

    Environment

    • Xcode v13.2.1
    • iOS 15.2 Simulator

    Steps to reproduce

    1. Embed CodeEditor in SwiftUI iOS application

      struct ContentView: View {
        @State var text = "TEST"
      
        var body: some View {
          VStack {
            CodeEditor(source: $text)
              .frame(height: 100)
      
            Divider()
      
            Text(text)
              .frame(maxWidth: .infinity, alignment: .leading)
              .multilineTextAlignment(.leading)
      
            Spacer()
          }
        }
      }
      
    2. Run the app in iOS Simulator

    3. Enter some text into CodeEditor

    4. Notice that the text property is not updated.

    opened by darrarski 0
  • Themes don’t work in Swift Playgrounds 4 on iPad

    Themes don’t work in Swift Playgrounds 4 on iPad

    When trying to use a CodeEditor view in my SP4 app, the editor always shows a clear background with a black letter font, no matter what theme I chose.

    opened by LeonardoXUI 0
  • Multiple instances in custom views are messing up the text state on macOS

    Multiple instances in custom views are messing up the text state on macOS

    Hello and first of all thank you for this great library :)

    I'm trying to replicate something similar to Xcode tabs, with some kind of top "tab bar" selecting each code file I want to edit.

    Since SwiftUI's TabView doesn't (currently) allow for tab bar customization, I've created my own using buttons in a HStack. When I click a button, the "main view" (containing the CodeEditor for selected file) changes and shows me file contents.

    The bug I've found is very strange, after changing one of two tabs the global "state" starts to mixup, showing up either wrong file content (the previous one) or resetting contents after window loses focus or when my tab changes.

    System's TextEditor seems to work fine.

    I have a strong suspect this is somehow related to SwiftUI.

    I hope attached video is "self explaining" (window always has focus, but something strange also happens when you focus any other application).

    you can find it here https://github.com/stefanomondino/CodeEditor in the Demo folder.

    https://user-images.githubusercontent.com/1691903/168474027-aedb3b73-5bcb-4183-b755-d745c11941cc.mov

    Also, it's worth nothing that also CodeEditorView (a very similar project) has the same issue.

    Let me know if you have any idea, thanks!

    bug help wanted 
    opened by stefanomondino 8
  • Problems using ColorPicker and CodeEditor at the same time

    Problems using ColorPicker and CodeEditor at the same time

    I found a new issue regarding the relationship between ColorPicker and CodeEditor

    (1) Start ColorPicker (2) Double-tap Text in CodeEditor

    ↓ Result ↓

    The color of the Text is reflected in the ColorPicker

    import SwiftUI
    import CodeEditor
    
    struct ContentView: View {
        @State var source: String = """
    import SwiftUI
    import CodeEditor
    
    struct ContentView: View {
        @State var source: String = ""
        @State var color: Color = Color.white
        var body: some View {
            HStack {
                ColorPicker("", selection: $color)
                CodeEditor(source: $source)
            }
        }
    }
    """
        @State var color: Color = Color.white
        var body: some View {
            ZStack {
                color
                    .edgesIgnoringSafeArea(.all)
                HStack {
                    ColorPicker("ColorPicker", selection: $color)
                    CodeEditor(source: $source, language: .swift, theme: .pojoaque)
                }
            }
        }
    }
    

    https://user-images.githubusercontent.com/84154073/164490460-6978fbbb-2afc-4e30-973b-87aae9435ae5.mp4

    opened by SNQ-2001 5
  • Problems with integrating CodeView into an Action Extension

    Problems with integrating CodeView into an Action Extension

    I am using this to build an App for reading codes on iOS. This package works fine for building SwiftUI Views. However, when I am using it to build an Action Extension, this error below occurs. Can you help me with that? Thanks a lot!

    Undefined symbols for architecture x86_64: "nominal type descriptor for CodeViewer.CodeViewer", referenced from: _symbolic ____y___________y_____y_____GGACy_____y__________y_____SgGGGQo 7SwiftUI4ViewPAAE18navigationBarItems7leading8trailingQrqd___qd_0_tAaBRd__AaBRd_0_r0_lFQO 10CodeViewerAGV AA6HStackV AA6ButtonV AA4TextV AA15ModifiedContentV AA5ImageV AA30_EnvironmentKeyWritingModifierV AA4FontV in EditorView.o _symbolic ____y_____y___________y_____y_____GGACy_____y__________y_____SgGGGQo_______Qo 7SwiftUI4ViewPAAE5sheet11isPresented9onDismiss7contentQrAA7BindingVySbG_yycSgqd__yctAaBRd__lFQO AcAE18navigationBarItems7leading8trailingQrqd___qd_0_tAaBRd__AaBRd_0_r0_lFQO 10CodeViewerAOV AA6HStackV AA6ButtonV AA4TextV AA15ModifiedContentV AA5ImageV AA30_EnvironmentKeyWritingModifierV AA4FontV 15ActionExtension05ThemeC0V in EditorView.o "nominal type descriptor for CodeViewer.CodeWebView.Theme", referenced from: _symbolic _____y_____G 7SwiftUI5StateV 10CodeViewer0D7WebViewC5ThemeO in EditorView.o "CodeViewer.CodeViewer.init(content: SwiftUI.Binding<Swift.String>, mode: CodeViewer.CodeWebView.Mode, darkTheme: CodeViewer.CodeWebView.Theme, lightTheme: CodeViewer.CodeWebView.Theme, isReadOnly: Swift.Bool, fontSize: Swift.Int, textDidChanged: ((Swift.String) -> ())?) -> CodeViewer.CodeViewer", referenced from: ActionExtension.EditorView.body.getter : some in EditorView.o "protocol conformance descriptor for CodeViewer.CodeViewer : SwiftUI.View in CodeViewer", referenced from: lazy protocol witness table accessor for type CodeViewer.CodeViewer and conformance CodeViewer.CodeViewer : SwiftUI.View in CodeViewer in EditorView.o "type metadata accessor for CodeViewer.CodeViewer", referenced from: ActionExtension.EditorView.body.getter : some in EditorView.o lazy protocol witness table accessor for type CodeViewer.CodeViewer and conformance CodeViewer.CodeViewer : SwiftUI.View in CodeViewer in EditorView.o outlined destroy of CodeViewer.CodeViewer in EditorView.o l_get_witness_table qd0__7SwiftUI4ViewHD3_AaBPAAE5sheet11isPresented9onDismiss7contentQrAA7BindingVySbG_yycSgqd__yctAaBRd__lFQOyAcAE18navigationBarItems7leading8trailingQrqd___qd_0_tAaBRd__AaBRd_0_r0_lFQOy10CodeViewerAOV_AA6HStackVyAA6ButtonVyAA4TextVGGATyAA15ModifiedContentVyAA5ImageVAA30_EnvironmentKeyWritingModifierVyAA4FontVSgGGGQo__15ActionExtension05ThemeC0VQo_HO in EditorView.o "type metadata for CodeViewer.CodeWebView.Theme", referenced from: property wrapper backing initializer of ActionExtension.EditorView.(theme in _1FD4E17BFA9D43C14FDD2767A1577070) : CodeViewer.CodeWebView.Theme in EditorView.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)

    opened by TangZhongham 1
Releases(1.2.2)
  • 1.2.2(Jul 16, 2022)

  • 1.2.1(Apr 21, 2022)

    Bug fixes:

    • block NSColorPanel from changing the text color
    • iOS: disable autocorrection, spellchecking and smart quotes (thanks @gin66!)
    • iOS: fix a bug where the text binding wasn't updated (thanks @darrarski!)

    New features:

    • monitor and set the text selection (thanks @theMomax!)
    • CocoaPods support (thanks @mcblooder!)
    Source code(tar.gz)
    Source code(zip)
  • 1.2.0(May 13, 2021)

    Added the set of "smart" editing features demonstrated by NTYSmartTextView, i.e.:

    • smarter indents (preserving the indent of the previous line when pressing enter)
    • soft indents (insert a configurable amount of spaces if the user presses tabs)
    • auto character pairing, e.g. when entering {, the matching } will be auto-added
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(May 12, 2021)

Owner
ZeeZide
ZeeZide GmbH ★ Software Consulting and Development
ZeeZide
A modern Swift (5.6) syntax definition for Sublime Text 4

Swift for Sublime This is a WIP version of a modern Swift (5.6) syntax for Sublime Text 4. It uses the latest features of the Sublime Text syntax engi

Will Bond 13 Dec 5, 2022
a custom Lisp REPL using Swifties

Swifties REPL intro This projects aims to demonstrate how to implement a custom Lisp REPL using Swifties. Swifties v5 Return evaluates completed form

Andreas Nilsson 12 Apr 11, 2022
SwiftUI Implementation of RichEditorView (WYSIWYG Editor)

A Rich Text Editor (WYSIWYG Editor) for your application by combining UIKit and SwiftUI.

Formaloo 36 Jan 7, 2023
Notepad - A fully themeable iOS markdown editor with live syntax highlighting.

Notepad is just like any other UITextView, but you need to use the convenience initializer in order to use the themes. To create a new theme, copy one of the existing themes and edit the JSON.

Rudd Fawcett 802 Dec 31, 2022
Simple Application that registers Vapor Leaf's .leaf file type to LaunchServices as html enabling automatic syntax highlighting in Xcode.

Vapor Leaf Extension Update: The Vapor Leaf Extension is now meant to be used with the Xcode Plugin I designed to provide Xcode language support for t

Omran Khoja 12 Jun 18, 2022
TextMate-style syntax highlighting

SyntaxKit SyntaxKit makes TextMate-style syntax highlighting easy. It works on iOS, watchOS, and OS X. SyntaxKit was abstracted from Whiskey. Building

Sam Soffes 466 Sep 9, 2022
A Swift library for efficient highlighting, indenting, and querying the structure of language syntax.

Neon A Swift library for efficient highlighting, indenting, and querying the structure of language syntax. It features: Minimal text invalidation Supp

Chime 214 Dec 28, 2022
A Collection of Tree-Sitter Parsers for Syntax Highlighting

CodeEditLanguages A collection of tree-sitter languages for syntax highlighting. Overview This package includes a binary framework CodeLanguagesContai

CodeEdit 16 Dec 30, 2022
null 1 Jan 24, 2022
MarkdownView is a WKWebView based UI element, and internally use bootstrap, highlight.js, markdown-it.

MarkdownView is a WKWebView based UI element, and internally use bootstrap, highlight.js, markdown-it.

Keita Oouchi 1.8k Dec 21, 2022
UISlider clone with multiple thumbs and values, range highlight, optional snap intervals, optional value labels, either vertical or horizontal.

MultiSlider UISlider clone with multiple thumbs and values, range highlight, optional snap intervals, optional value labels, either vertical or horizo

Yonat Sharon 326 Dec 29, 2022
iOS Chart. Support animation, click, scroll, area highlight.

XJYChart XJYChart - A High-performance, Elegant, Easy-to-integrate Charting Framework. The Best iOS Objc Charts. chart more beautiful support chart sc

junyixie 868 Nov 16, 2022
Weather Forecast Assigment is an iOS application built to highlight MVP and Clean Architecture concepts

Weather Forecast Assigment - iOS - MVP + Clean Architecture Description Weather Forecast Assigment is an iOS application built to highlight MVP (Model

Khôi Việt 2 Oct 30, 2021
🖍 Highlight whatever you want!

Highlighter Updates See CHANGELOG for details Intoduction ?? Highlight whatever you want! Highlighter will magically find UI objects such as UILabel,

Kyle Yi 933 Dec 29, 2022
UISlider clone with multiple thumbs and values, range highlight, optional snap intervals, optional value labels, either vertical or horizontal.

MultiSlider UISlider clone with multiple thumbs and values, range highlight, optional snap intervals, optional value labels, either vertical or horizo

Yonat Sharon 326 Dec 29, 2022
WVWalkthroughView is an objective C based utility to highlight certain parts for iOS apps.

WVWalkthroughView A simple utility written in Objective C to help developers walk a user through their app. It allows a message to be displayed, a par

Praagya Joshi 29 Mar 25, 2021
swift-highlight a pure-Swift data structure library designed for server applications that need to store a lot of styled text

swift-highlight is a pure-Swift data structure library designed for server applications that need to store a lot of styled text. The Highlight module is memory-efficient and uses slab allocations and small-string optimizations to pack large amounts of styled text into a small amount of memory, while still supporting efficient traversal through the Sequence protocol.

kelvin 4 Aug 14, 2022
A Xcode plugin to add highlight to the instances of selected symbol.

Auto Highlight Symbol About Xcode 8 Xcode 8 does't support plugins anymore, but there is a workaround, use at your own risk. Xcode can highlight insta

Nelson 83 Jan 3, 2023
Fluid - Use a declarative syntax to build your user interface using UIKit like SwiftUI

Fluid Fluid is powered by ResultBuilder and a custom layout engine. You can uses

HZ.Liu 13 Dec 9, 2022