Skip to content

An iOS syntax highlighter based on Savanna Kit, Sourceful and originally Highlightr

License

Notifications You must be signed in to change notification settings

ActuallyTaylor/Firefly

Repository files navigation

Firefly logo

Twitter: @LinemanZachary

Firefly

Firefly is a pure swift iOS & macOS syntax highlighter based of off Sourceful, SavannaKit, SyntaxKit, and previously Highlightr. Highlighter has since been remove from the project in favor of a pure swift solution.

Get in contact

If you want to get in contact about Firefly, the Jellycuts Discord is the best place to talk.

Issues

Issues are hosted on both this repo and the Jellycuts Issue Repo. This is done because a lot of issues that occur with Firefly are reported through Jellycuts and it does not make sense to mirror them across to this repo.

How does Firefly Work?

Firefly is written in pure swift, and uses NSRegularExpressions for detecting tokens to highlight. Once tokens are detected they are colored based on the current theme.

Using Firefly in your project

If you are going to use Firefly in your project, I request that you include a link back to this github page somewhere. If you would like to you can also email me and I will add you into the list of apps that use Firefly on this page.

About this project

This project was inspired by Paul Hudson’s (@twostraws) Sourceful syntax highlighter and Highlightr by J.P Illanes (@raspu). Sourceful is a project combining Louis D’hauwe's SavannaKit and Source Editor. Highlightr merges Highlight.js with swift.

Features

  • Line Numbers
  • Changeable Themes
  • Changeable Languages
  • Basic String, Parentheses, and Bracket completion

Supports

  • 2 Languages
  • 61 Themes

How To Use

To start using you can either create a UIView in storyboards and assign it the class SyntaxTextView, or by creating a SyntaxTextView programmatically. You can then assign the editors language inside your View Controller. Firefly also supports setting up with Swift UI.

Sample Code

UI Kit

A basic setup for a Firefly View

import UIKit
import Firefly

class ViewController: UIViewController {

    @IBOutlet weak var fireflyView: FireflySyntaxView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Use the setup function
        fireflyView.setup(theme: themeName, language: "jelly", font: "system", offsetKeyboard: true, keyboardOffset: 10, dynamicGutter: true, gutterWidth: 20, placeholdersAllowed: true, linkPlaceholders: false)
    }
}

Using the .setup function is the same on macOS as it is on iOS.

Set everything at once

This allows you to set almost all ascpets of the view at once so you do not accidently cause extra highlight calls.

fireflyView.setup(theme: themeName, language: "jelly", font: "system", offsetKeyboard: true, keyboardOffset: 10, dynamicGutter: true, gutterWidth: 20, placeholdersAllowed: true, linkPlaceholders: false)

Set individual parts about the view

Set the text in the Firefly View

fireflyView.text = “My code string”

Set the Firefly View's Theme

fireflyView.setTheme(name: "Basic")

Set the Firefly View's Language

fireflyView.setLanguage(nLanguage: "default")

Set the Firefly View's Gutter Width

fireView.setGutterWidth(width: 20)

Set the Firefly View’s Keyboard Offset

The keyboard offset is the space between the bottom of firefly view and the keyboard frame. You should use this to make space for any keyboard input views.

fireflyView.setKeyboardOffset(offset: 85)

Tell the view if it should dynamically adjust for the keyboard

fireView.setShouldOffsetKeyboard(bool: true)

Set the Firefly View’s Font

fireflyView.setFont(font: "Source Code Pro")

Tell the view if it should dynamically update the gutter width

fireflyView.setDynamicGutter(bool: true)

Tell the view if it should show placeholders or not

A placeholder can be used to deeplink to a different part of your app or open a link. Used for documentation in Jellycuts.

fireView.setPlaceholdersAllowed(bool: true)

Tell the view if it placeholders should also be links

fireView.setLinkPlaceholders(bool: true)

Get the current theme set for the Firefly View

This returns the value for the current theme. You can use this to get details about what the View looks like and color other parts of your app accordingly.

let theme = fireflyView.getCurrentTheme()

List all supported languages

fireflyView().availableLanguages()

List all supported themes

fireflyView().availableThemes()

Swift UI

Swift UI is not fully supported but it is still supported. An example view for Swift UI is below. This will set you up with a basic swift UI Fiefly view.

struct ContentView: View {
    @State var text = """
    if(x == 3) {
        quickLook()
    }
    import Shortcuts 1090.2
    #Color: red, #Icon: shortcuts
    Function()
    functionWithParams(test: test)
    // This is a comment
    /*
    This is a multi line comment
    */
    "String"
    \"""
    Multi Line Text
    More Text
    \"""
    """

    @State var theme: String = "Xcode Dark"
    @State var fontName: String = "system"
    
    @State var update: Bool = false
    
    @State var dynamicGutter: Bool = false
    @State var gutterWidth: CGFloat = 40
    @State var placeholdersAllowed: Bool = true
    @State var linkPlaceholders: Bool = false
    @State var lineNumbers: Bool = true
    @State var fontSize: CGFloat = 14

    var body: some View {
        FireflySyntaxEditor(text: $text, language: .constant("Jelly"), theme: $theme, fontName: $fontName, fontSize: $fontSize, dynamicGutter: $dynamicGutter, gutterWidth: $gutterWidth, placeholdersAllowed: $placeholdersAllowed, linkPlaceholders: $linkPlaceholders, lineNumbers: $lineNumbers, cursorPosition: $cursorPosition) { editor in
            print("Did change text")
        } didChangeSelectedRange: { editor, range in
            print("Did change selected range")
        } textViewDidBeginEditing: { editor in
            print("Did begin editing")
        }
    }
}

Adding your own content

Adding your own language

Languages are a dictionary of definitions that tell the syntax highlighter how to detect a token.

Example of a language definition:

let defaultLanguage: [String: Any] = [
    "comment": [
        "regex": "//.*?(\\n|$)", // The regex used for highlighting
        "group": 0, // The regex group that should be highlighted
        "relevance": 5, // The releavance over other tokens
        "options": [], // Regular expression options
        "multiline": false // If the token is multiline
    ],
    "multi_comment": [
        "regex": "/\\*.*?\\*/", // The regex used for highlighting
        "group": 0, // The regex group that should be highlighted
        "relevance": 5, // The releavance over other tokens
        "options": [NSRegularExpression.Options.dotMatchesLineSeparators],  // Regular expression options
        "multiline": true // If the token is multiline
    ],
]

Adding your language

To add your own language to the languages array within the languages dictionary.

let languages: [String: [String: Any]] = [
    "default": defaultLanguage,
    "jelly": jellyLanguage,
    "swift": swiftLanguage
]

Adding a Theme

Themes are a dictionary with color values telling the highlighter what color to highlight different tokens.

Example of a theme definition:

"Basic": [
    "default": "#000000", // The default font color
    "background": "#FFFFFF", // The background color
    "currentLine": "#F3F3F4", // Color of the current line
    "selection": "#A4CDFF", // The selection color of the text view
    "cursor": "#000000", // The cursor color of the text view
    "definitions": [ // These are the definitions that tell the highlighter what color to highlight different types of definitions.
        "function": "#2B839F",
        "keyword": "#0000FF",
        "identifier": "#2B839F",
        "string": "#A31515",
        "mult_string": "#A31515",
        "comment": "#008000",
        "multi_comment": "#008000",
        "numbers": "#000000",
        "url": "#0000FF"
    ]
]

Apps that use Firefly

  1. Jellycuts
  2. App Maker

To-Do

  • Support for Theme Changing

  • Support for Language Changing

  • Dynmaically creating Gutter and Line styles

  • Fix issues with themes not showing the correct colors when the token has a font weight modifier - Not really fixed, just a workaround currently.

  • Modify, update and implement SavannaKit / SyntaxKit LineNumberLayoutManager for better and faster line numbers

  • Speed increasments for loading larger files

  • Multi-line string support

  • Swift UI support

  • Placeholders

  • Collapsable lines

  • More languages

  • Rewrite the NSTextStorage subclass in obj-c. This will bring speed improvments.

  • Support VSCode Themes or a converter for VSCode -> Firefly theme

  • Highlight current line with tinting of line number and line fragmenet

Credits

Sourceful is a project merging together SavannaKit and SourceEditor, and then udpdated too a modern version of Swift. It is maintained by Paul Hudson. This project was used as a starting ground for Firefly but has been largely removed from the working copy. Sourceful is licensed under the MIT license; see Sourceful LICENSE for more information.

Highlightr is a project taking Highlight.js and allowing it to interact with Swift. Highlighter has been removed from the working copy in favor of a full swift approach. Highlightr is licensed under the MIT license; see Highlightr LICENSE for more information.

SyntaxKit is a project created by Palle Klewitz for iOS syntax highlighting. This project was used as a reference for issues in code. SyntaxKit is licensed under the MIT license; see SyntaxKit LICENSE for more information.

SavannaKit is a project created by Louis D'hauwe. Firefly uses a modified version of LineNumberLayoutManager. SavannaKit is licensed under the MIT license; see SavannaKit LICENSE for more information.