CodeEditorView Swift package provides a SwiftUI view implementing a rich code editor for iOS and macOS

Overview

SwiftUI code editor view for iOS and macOS

The CodeEditorView Swift package provides a SwiftUI view implementing a rich code editor for iOS and macOS whose visual style is inspired by Xcode. The currently supported functionality includes syntax highlighting with configurable themes, inline message (warnings, errors, etc) reporting, bracket matching, matching bracket insertion, current line highlighting, and a minimap (only on macOS).

Screenshots of the demo app

This is the default dark theme on macOS. Like in Xcode, messages have got an inline view on the right hand side of the screen, which pops up into a larger overlay to display more information. The minimap on the right provides an outline of the edited text.

The following is the default light theme on iOS. Both line highlighting and the minimap are currently not supported on iOS due to limitations in the iOS version of TextKit. Instead of the line highlight, both the current line (or the current selection range) and lines with messages are indicated with differently coloured line numbers in the gutter.

How to use it

Typical usage of the view is as follows.

> = Set () @Environment(\.colorScheme) private var colorScheme: ColorScheme var body: some View { CodeEditor(text: $text, messages: $messages, language: .swift) .environment(\.codeEditorTheme, colorScheme == .dark ? Theme.defaultDark : Theme.defaultLight) } } ">
struct ContentView: View {
  @State private var text:     String                = "My awesome code..."
  @State private var messages: Set> = Set ()

  @Environment(\.colorScheme) private var colorScheme: ColorScheme

  var body: some View {
    CodeEditor(text: $text, messages: $messages, language: .swift)
      .environment(\.codeEditorTheme,
                   colorScheme == .dark ? Theme.defaultDark : Theme.defaultLight)
  }
}

Demo app

To see the CodeEditorView in action, have a look at the repo with a cross-platform demo app.

Documentation

For more information, see the package documentation.

Status

I consider this to be pre-release quality. It is sufficient to start building something on it, but it is not yet ready for production. While the CodeEditor view already supports quite a bit of advanced functionality (such as the inline messages and minimap), other components are still quite simple, such as the range of tokens covered by the language configuration. Moreover, performance is still an issue that needs to be addressed. The core archtecture, such as the incremental tokenisation for syntax highlighting, is designed to handle larger files smoothly, but the overall implementation still needs some performance debugging.

License

Copyright 2021 Manuel M. T. Chakravarty.

Distributed under the Apache-2.0 license — see the license file for details.

Comments
  • Questions

    Questions

    Hi,

    thank you very much for this. A good code editor is urgently needed for SwiftUI! This really fills a void. Would be so cool not to have to use Ace in a WebView anymore.

    Some questions:

    1. Will it be possible to have sessions, i.e. when you have several source files to switch between source sessions which restores the cursor / scroll location for that session (and the messages if possible) ?
    2. Will it be possible to to provide custom syntax highlighting for custom languages from the outside ? I have my own scripting language.

    IMHO focus on making the core usable for a v1 and add all the options / features later ...

    Thanks

    opened by markusmoenig 8
  • New Language Support

    New Language Support

    Is there an easy way of adding new language support? I am really interested in using this library to support another language. Right now, it looks like the only way to do so is to change the LanguageConfiguration file. If that is true, it would be nice to be able to create an external file for my own language support that gets added to the existing language support. That way, anybody can create and submit language configurations to the project.

    opened by frios 8
  • Eager location reading in some cases

    Eager location reading in some cases

    Using the exact sample code as shown in the readme:

    struct ContentView: View {
      @State private var text:     String                = "My awesome code..."
      @State private var messages: Set<Located<Message>> = Set ()
    
      @Environment(\.colorScheme) private var colorScheme: ColorScheme
    
      var body: some View {
        CodeEditor(text: $text, messages: $messages, language: .swift)
          .environment(\.codeEditorTheme,
                       colorScheme == .dark ? Theme.defaultDark : Theme.defaultLight)
      }
    }
    

    Pressing the backspace key to delete one character causes an immediate crash. Inputting more text is not affected, crash seems to only occur when deleting any character.

    Here's a screen recording of the crash (window does not close since Xcode is attached to the app). Xcode printed out the stack trace (which is included below) immediately after I backspaced the 'd' character.

    Here's the stack trace of the crash:

    022-02-04 13:59:11.334073+0800 CPEdit[90289:4724934] [General] An uncaught exception was raised
    2022-02-04 13:59:11.334204+0800 CPEdit[90289:4724934] [General] -[__NSCFString getLineStart:end:contentsEnd:forRange:]: Range {60, 0} out of bounds; string length 59
    2022-02-04 13:59:11.339149+0800 CPEdit[90289:4724934] [General] (
    	0   CoreFoundation                      0x00000001bccd01cc __exceptionPreprocess + 240
    	1   libobjc.A.dylib                     0x00000001bca217b8 objc_exception_throw + 60
    	2   CoreFoundation                      0x00000001bcda0488 -[__NSCFString characterAtIndex:].cold.1 + 0
    	3   CoreFoundation                      0x00000001bccb4750 CFStringGetLineBounds + 0
    	4   Foundation                          0x00000001bdcef0cc -[NSString lineRangeForRange:] + 64
    	5   CPEdit                              0x0000000100f329d8 $s14CodeEditorView0aC0C17setSelectedRanges_8affinity14stillSelectingySaySo7NSValueCG_So19NSSelectionAffinityVSbtFSo8_NSRangeVSgSiXEfU_ + 392
    	6   CPEdit                              0x0000000100f32a54 $sSiSo8_NSRangeVSgs5Error_pIgydzo_SiACsAD_pIegnrzo_TR + 32
    	7   CPEdit                              0x0000000100f3da80 $sSiSo8_NSRangeVSgs5Error_pIgydzo_SiACsAD_pIegnrzo_TRTA + 28
    	8   libswiftCore.dylib                  0x00000001c9c02c44 $sSq7flatMapyqd__SgABxKXEKlF + 448
    	9   CPEdit                              0x0000000100f32210 $s14CodeEditorView0aC0C17setSelectedRanges_8affinity14stillSelectingySaySo7NSValueCG_So19NSSelectionAffinityVSbtF + 1016
    	10  CPEdit                              0x0000000100f33aa0 $s14CodeEditorView0aC0C17setSelectedRanges_8affinity14stillSelectingySaySo7NSValueCG_So19NSSelectionAffinityVSbtFTo + 108
    	11  UIFoundation                        0x00000001c063ba6c -[NSLayoutManager textStorage:edited:range:changeInLength:invalidatedRange:] + 372
    	12  CPEdit                              0x0000000100f3c510 $s14CodeEditorView0A13LayoutManagerC14processEditing3for6edited5range14changeInLength16invalidatedRangeySo13NSTextStorageC_So0pQ11EditActionsVSo8_NSRangeVSiAOtF + 544
    	13  CPEdit                              0x0000000100f3cad4 $s14CodeEditorView0A13LayoutManagerC14processEditing3for6edited5range14changeInLength16invalidatedRangeySo13NSTextStorageC_So0pQ11EditActionsVSo8_NSRangeVSiAOtFTo + 140
    	14  UIFoundation                        0x00000001c0662934 -[NSTextStorage _notifyEdited:range:changeInLength:invalidatedRange:] + 188
    	15  UIFoundation                        0x00000001c066e3b4 -[NSTextStorage endEditing] + 116
    	16  CPEdit                              0x0000000100f18374 $s14CodeEditorView0A7StorageC17replaceCharacters2in4withySo8_NSRangeV_SStF + 3220
    	17  CPEdit                              0x0000000100f18ec4 $s14CodeEditorView0A7StorageC17replaceCharacters2in4withySo8_NSRangeV_SStFTo + 100
    	18  AppKit                              0x00000001bfb19fbc -[NSTextView(NSPrivate) _userReplaceRange:withString:] + 260
    	19  AppKit                              0x00000001bfb19a40 _NSDoUserReplaceForCharRange + 480
    	20  AppKit                              0x00000001bfb6511c -[NSTextView(NSKeyBindingCommands) deleteBackward:] + 824
    	21  AppKit                              0x00000001bfa86e60 -[NSTextView doCommandBySelector:] + 216
    	22  AppKit                              0x00000001bfa86d48 -[NSTextInputContext(NSInputContext_WithCompletion) doCommandBySelector:completionHandler:] + 264
    	23  AppKit                              0x00000001bf9b0f6c -[NSKeyBindingManager(NSKeyBindingManager_MultiClients) interpretEventAsCommand:forClient:] + 2008
    	24  AppKit                              0x00000001bf9b9c9c __84-[NSTextInputContext _handleEvent:options:allowingSyntheticEvent:completionHandler:]_block_invoke_5 + 376
    	25  AppKit                              0x00000001c01845d8 __84-[NSTextInputContext _handleEvent:options:allowingSyntheticEvent:completionHandler:]_block_invoke_3.1027 + 108
    	26  AppKit                              0x00000001bf9b9ae0 -[NSTextInputContext tryHandleEvent_HasMarkedText_withDispatchCondition:dispatchWork:continuation:] + 148
    	27  AppKit                              0x00000001c0184530 __84-[NSTextInputContext _handleEvent:options:allowingSyntheticEvent:completionHandler:]_block_invoke.1024 + 324
    	28  HIToolbox                           0x00000001c58207dc __TSMProcessRawKeyEventWithOptionsAndCompletionHandler_block_invoke_5 + 96
    	29  HIToolbox                           0x00000001c5831c3c ___ZL23DispatchEventToHandlersP14EventTargetRecP14OpaqueEventRefP14HandlerCallRec_block_invoke + 148
    	30  AppKit                              0x00000001c017f11c __55-[NSTextInputContext handleTSMEvent:completionHandler:]_block_invoke.341 + 592
    	31  AppKit                              0x00000001bf9b2fb0 __55-[NSTextInputContext handleTSMEvent:completionHandler:]_block_invoke_2 + 108
    	32  AppKit                              0x00000001bf9b2ef4 -[NSTextInputContext tryHandleTSMEvent_HasMarkedText_withDispatchCondition:dispatchWork:continuation:] + 148
    	33  AppKit                              0x00000001bf9b23a0 -[NSTextInputContext handleTSMEvent:completionHandler:] + 2004
    	34  AppKit                              0x00000001bf9b1b50 _NSTSMEventHandler + 340
    	35  HIToolbox                           0x00000001c57bf418 _ZL23DispatchEventToHandlersP14EventTargetRecP14OpaqueEventRefP14HandlerCallRec + 1116
    	36  HIToolbox                           0x00000001c57be884 _ZL30SendEventToEventTargetInternalP14OpaqueEventRefP20OpaqueEventTargetRefP14HandlerCallRec + 356
    	37  HIToolbox                           0x00000001c57be714 SendEventToEventTargetWithOptions + 44
    	38  HIToolbox                           0x00000001c581cd54 SendTSMEvent_WithCompletionHandler + 432
    	39  HIToolbox                           0x00000001c581d298 __SendUnicodeTextAEToUnicodeDoc_WithCompletionHandler_block_invoke + 440
    	40  HIToolbox                           0x00000001c581d0b4 __SendFilterTextEvent_WithCompletionHandler_block_invoke + 224
    	41  HIToolbox                           0x00000001c581cdac SendTSMEvent_WithCompletionHandler + 520
    	42  HIToolbox                           0x00000001c581cb5c SendFilterTextEvent_WithCompletionHandler + 256
    	43  HIToolbox                           0x00000001c581c788 SendUnicodeTextAEToUnicodeDoc_WithCompletionHandler + 292
    	44  HIToolbox                           0x00000001c581c524 __utDeliverTSMEvent_WithCompletionHandler_block_invoke_2 + 320
    	45  HIToolbox                           0x00000001c581c2a8 __utDeliverTSMEvent_WithCompletionHandler_block_invoke + 284
    	46  HIToolbox                           0x00000001c581c10c TSMKeyEvent_WithCompletionHandler + 600
    	47  HIToolbox                           0x00000001c581be94 __TSMProcessRawKeyEventWithOptionsAndCompletionHandler_block_invoke_4 + 320
    	48  HIToolbox                           0x00000001c581bca4 __TSMProcessRawKeyEventWithOptionsAndCompletionHandler_block_invoke_3 + 352
    	49  HIToolbox                           0x00000001c581b9a0 __TSMProcessRawKeyEventWithOptionsAndCompletionHandler_block_invoke_2 + 352
    	50  HIToolbox                           0x00000001c581b69c __TSMProcessRawKeyEventWithOptionsAndCompletionHandler_block_invoke + 344
    	51  HIToolbox                           0x00000001c5809b84 TSMProcessRawKeyEventWithOptionsAndCompletionHandler + 3372
    	52  AppKit                              0x00000001c01843dc __84-[NSTextInputContext _handleEvent:options:allowingSyntheticEvent:completionHandler:]_block_invoke_3.1020 + 148
    	53  AppKit                              0x00000001c018408c __204-[NSTextInputContext tryTSMProcessRawKeyEvent_orSubstitution:dispatchCondition:setupForDispatch:furtherCondition:doubleSpaceSubstitutionCondition:doubleSpaceSubstitutionWork:dispatchTSMWork:continuation:]_block_invoke.971 + 192
    	54  AppKit                              0x00000001bf9b0620 -[NSTextInputContext tryTSMProcessRawKeyEvent_orSubstitution:dispatchCondition:setupForDispatch:furtherCondition:doubleSpaceSubstitutionCondition:doubleSpaceSubstitutionWork:dispatchTSMWork:continuation:] + 344
    	55  AppKit                              0x00000001bf9aff20 -[NSTextInputContext _handleEvent:options:allowingSyntheticEvent:completionHandler:] + 1528
    	56  AppKit                              0x00000001bf9af8e8 -[NSTextInputContext _handleEvent:allowingSyntheticEvent:] + 136
    	57  AppKit                              0x00000001bf9af708 -[NSView interpretKeyEvents:] + 196
    	58  AppKit                              0x00000001bf9af518 -[NSTextView keyDown:] + 712
    	59  AppKit                              0x00000001bf916d98 -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 5920
    	60  AppKit                              0x00000001bf91540c -[NSWindow(NSEventRouting) sendEvent:] + 348
    	61  AppKit                              0x00000001bf914878 -[NSApplication(NSEvent) sendEvent:] + 4064
    	62  AppKit                              0x00000001bfbcd010 -[NSApplication _handleEvent:] + 76
    	63  AppKit                              0x00000001bf7959dc -[NSApplication run] + 636
    	64  AppKit                              0x00000001bf767088 NSApplicationMain + 1064
    	65  SwiftUI                             0x00000001e16b14c4 $s7SwiftUI6runAppys5NeverOSo21NSApplicationDelegate_So11NSResponderCXcFTf4e_nAA07TestingdG0C_Tg5 + 148
    	66  SwiftUI                             0x00000001e21dba40 $s7SwiftUI6runAppys5NeverOxAA0D0RzlF + 260
    	67  SwiftUI                             0x00000001e1c6b658 $s7SwiftUI3AppPAAE4mainyyFZ + 128
    	68  CPEdit                              0x0000000100f0f6c0 $s6CPEdit0A3AppV5$mainyyFZ + 40
    	69  CPEdit                              0x0000000100f0f778 main + 12
    	70  dyld                                0x00000001014590f4 start + 520
    )
    

    If relevant, I'm including some information about my machine and environment:

    • Model: 2021 14" MBP
    • macOS version: 12.2 RC
    • Xcode version: 13.2.1
    • Swift version: 5
    • App was running in debug mode and Xcode was attached to it
    • CodeEditorView version 0.9.0 was installed thru SPM
    bug iOS macOS 
    opened by cryptoAlgorithm 5
  • LanguageConfiguration: expose most helpers

    LanguageConfiguration: expose most helpers

    They get scoped and slightly more expressive names. (The names are still partially abbreviated; otherwise, the regular expressions just get too big, negatively affecting readability.)

    opened by mchakravarty 5
  • Fix warnings for access of theme from environment

    Fix warnings for access of theme from environment

    I've changed the accessor used to get the editor theme to EnvironmentValues.codeEditorTheme, which vends the same value. This avoids the warnings for not using CodeEditorTheme.self when accessing with the EnvironmentKey subscript on EnvironmentValues

    opened by christopherweems 1
  • Changing font size

    Changing font size

    If I want to change the default font size, what is the best way to do that? I tried to create a new theme with a different font size to pass into the CodeEditor call, but I get

    'Theme' initializer is inaccessible due to 'internal' protection level

    I don't see any other obvious way to make that change.

    Thanks

    opened by frios 1
  • Gutter invalidation is too generous

    Gutter invalidation is too generous

    Just moving the cursor one character seems to invalidate the entire visible gutter.

    There is also an interaction with gutter invalidation and change management or similar that can lead to an endless loop (or at least, extreme slowness) during start up if there is a window with a large file open. Gutter invalidation happens async on the main thread, but on a large file that may run too early after all. In any case, it is fragile.

    performance 
    opened by mchakravarty 0
  • Crash in GutterView.swift

    Crash in GutterView.swift

    I'm seeing a crash when emptying all text, when accessing message[0].

    Worked around here:

    https://github.com/mchakravarty/CodeEditorView/compare/main...ronyfadel:CodeEditorView:main

    opened by ronyfadel 1
  • Code Review (Diff)

    Code Review (Diff)

    In CodeEdit, our goal is to reach editor feature parity with Xcode. We'd like to use CodeEditorView as opposed to rolling our own editor view. That considered the question arises, what is the responsibility of the editor and what is the responsibility of the application built around it?

    01-macOS-code-edit-source-control

    I am thinking the Code Review might be the responsibility of the editor as it is the editor that draws the new lines, line highlights etc. What are your thoughts here? If it is not the responsibility of the editor, without looking into it too much, is CodeEditor extensible enough to build this on top of it outside the editor?

    enhancement advanced 
    opened by austincondiff 8
  • More Overall Visual Consistency with Xcode

    More Overall Visual Consistency with Xcode

    We seem to generally be following the editor visual style of Xcode. There are a few things that need to be addressed to get be more visually consistent. (left - Xcode, right - CodeEditorView)

    image
    • Better syntax highlighting
    • Increased line height
    • Smaller and more narrow line number font.
    • General editor font styling is off (maybe smaller font size by 1px and increased font weight?).
    image image
    • General message styling (typography, iconography, colors, animation, dismiss popover button, etc) needs work
    enhancement 
    opened by austincondiff 1
  • Layer backed gutter view

    Layer backed gutter view

    Currently the redrawing of the gutter view lacks behind resizing operations because it needs to wait until the layout manager has finished laying out the text. This can be clearly observed when switching between fullscreen and windowed mode.

    It should be possible to avoid this by using a CALayer appropriately. By continuing to use the last layer (in GutterView) until the recomputed layout allows us to draw a new layer, the gutter view ought to be able to handle animations, such as going into fullscreen, more elegantly.

    enhancement design 
    opened by mchakravarty 0
Releases(0.10.0)
  • 0.10.0(Feb 21, 2022)

    What's Changed

    • Added layout configuration
    • LanguageConfiguration exposes most helpers
    • Added support for tracking and restoring edit positions (selections and scroll position)
    • Various bug fixes and performance improvements
    Source code(tar.gz)
    Source code(zip)
  • 0.9.0(Jun 3, 2021)

    This is the initial release of this new package. It is not production ready yet, but already includes a substantial amount of advanced and solid functionality.

    Source code(tar.gz)
    Source code(zip)
Owner
Manuel M T Chakravarty
Lambda Scientist
Manuel M T Chakravarty
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
A Xcode Source Editor Extension to sort your header imports and remove duplicates, similar to iSort.

CleanHeaders An Xcode plug-in to format your import headers in a systematic manner. It simply removes duplicates, spaces and sorts them alphabetically

Karthikeya Udupa 93 Oct 9, 2021
WIP document editor for iOS

¶ Pilcrow This is an work-in-progress experiment on building a document editor similar to Bear, Notion, Notes.app, Craft, Dropbox Paper, and others. I

Zach Waugh 54 Dec 30, 2022
Finite Automata iPad Editor

Automata Editor This is a repository of Automata Editor which is an iPad app for editing finite automata. It uses CoreML to recognize your strokes and

Marek Fořt 56 Dec 13, 2022
📱 A simple wallpaper editor application for iPhone. Create your own wallpapers with a beautiful shelves.

iShelf A simple wallpaper editor application for iPhone. Create your own wallpapers with a beautiful shelves. ?? Demo ?? Screenshots ✨ Features Lots o

Daniel Tvorun 5 Nov 3, 2022
CodeEditor - A SwiftUI TextEditor with syntax highlighting using Highlight.js

CodeEditor A SwiftUI TextEditor View with syntax highlighting using Highlight.js. It builds on top of Highlightr which does the wrapping of Highlight.

ZeeZide 269 Dec 30, 2022
null 1 Jan 24, 2022
Emacs support for Apple's Swift programming language.

swift-mode Major-mode for Apple's Swift programming language. Installation Install swift-mode package from MELPA. To install without MELPA, download l

null 347 Dec 17, 2022
Vim runtime files for Swift

Swift.vim Syntax and indent files for Swift If you don't have a preferred installation method check out vim-plug. Examples Syntastic Integration swift

Keith Smiley 787 Dec 1, 2022
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
🪞 Swift wrapper for CodeMirror 6

?? Swift wrapper for CodeMirror 6

khoi 4 Jan 3, 2023
A standalone, flexible API that provides a full-featured rich text editor for iOS applications.

Twitter Text Editor A standalone, flexible API that provides a full featured rich text editor for iOS applications. This provides a robust text attrib

Twitter 2.8k Dec 29, 2022
A beautiful rich text WYSIWYG editor for iOS with a syntax highlighted source view

ZSSRichTextEditor The Editor ZSSRichTextEditor is a beautiful Rich Text WYSIWYG Editor for iOS. It includes all of the standard editor tools one would

Nic Hubbard 3.7k Dec 31, 2022
A rich-text editor for iOS

DTRichTextEditor This project aims to provide a replacement for Apple's severely limited UITextView and to allow for editing attributed strings. It co

Cocoanetics 346 Oct 8, 2022
RichTexture is a rich text editor for iOS.

RichTexture About RichTexture is a rich text editor for iOS. Running Open RichTexture.xcworkspace, change the bundle identifier to an identifier linke

Steve Moser 45 Dec 23, 2022
React-native-photo-editor - Photo editor using native modules for iOS and Android

?? Image editor using native modules for iOS and Android. Inherit from 2 available libraries, ZLImageEditor (iOS) and PhotoEditor (Android)

Baron Ha. 244 Jan 5, 2023
A fully fledged syscfg editor. Just the editor. Written in pure swift.

MagicCFG Reloaded The SysCFG Writing Utility - UPDATED, OSV Report Bug Table of Contents About MagicCFG Reloaded Getting Started Roadmap Contact Credi

Jan Fabel 47 Dec 31, 2022
IGStoryButtonKit provides an easy-to-use button with rich animation and multiple way inspired by instagram story/stories.

Introduction Have you ever seen UI like instagram story, haven't you? Actually, features like instagram story have been implemented in many applicatio

mutation 34 Nov 8, 2022
CodeEditTextView - An Xcode-inspired code editor view written in Swift powered by tree-sitter for CodeEdit

An Xcode-inspired code editor view written in Swift powered by tree-sitter for CodeEdit. Features include syntax highlighting (based

CodeEdit 243 Jan 8, 2023
Make your table view expandable just by implementing one method.

ExpyTableView About ExpyTableView is a re-write based on SLExpandableTableView. Takes some ideas, concepts and codes and regenerates them in Swift. Le

Okhan Okbay 359 Dec 27, 2022