Skip to content

Instantly share code, notes, and snippets.

@martinpi
Created October 13, 2018 14:27

Revisions

  1. martinpi created this gist Oct 13, 2018.
    73 changes: 73 additions & 0 deletions SyntaxHighlighter.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,73 @@
    //
    // SyntaxHighlighter.swift
    // CardsCardsCards
    //
    // Created by Martin Pichlmair on 12/10/2018.
    //

    // Based on https://raw.githubusercontent.com/kuyawa/Macaw/master/Macaw/Macaw.swift

    import Cocoa
    import Foundation

    class SyntaxHighlighter {

    struct color {
    static let normal = [NSAttributedString.Key.foregroundColor: NSColor(red: 0.95, green: 0.95, blue: 0.95, alpha: 1.0)] // light grey
    static let ruleName = [NSAttributedString.Key.foregroundColor: NSColor(red: 0.40, green: 0.60, blue: 0.90, alpha: 1.0)] // cyan
    static let number = [NSAttributedString.Key.foregroundColor: NSColor(red: 0.60, green: 0.60, blue: 0.90, alpha: 1.0)] // blue
    static let keyword = [NSAttributedString.Key.foregroundColor: NSColor(red: 0.75, green: 0.20, blue: 0.75, alpha: 1.0)] // magenta
    static let expression = [NSAttributedString.Key.foregroundColor: NSColor(red: 0.95, green: 0.75, blue: 0.10, alpha: 1.0)] // yellow
    static let modifier = [NSAttributedString.Key.foregroundColor: NSColor(red: 0.95, green: 0.50, blue: 0.20, alpha: 1.0)] // orange
    static let comment = [NSAttributedString.Key.foregroundColor: NSColor(red: 0.20, green: 0.60, blue: 0.20, alpha: 1.0)] // green
    }

    struct regex {
    static let keywords = "\\b(origin)\\b"
    static let ruleName = "(\\[.*\\])"
    static let expression = "(\\#[a-zA-Z][a-zA-Z0-9,\\.\\(\\)]*\\#)"
    static let modifier = "\\#.*\\.([a-zA-Z][a-zA-Z0-9,]*\\(.*\\))\\#"
    static let numberLiteral = "\\b([0-9]*(\\.[0-9]*)?)\\b"
    static let symbols = "(\\+|-|\\*|/|=|\\{|\\}|\\[|\\]|\\(|\\))"
    static let commentLine = "(^\\\\.*)"
    }

    let patterns = [
    regex.commentLine : color.comment,
    regex.ruleName : color.keyword,
    regex.numberLiteral : color.number,
    regex.keywords : color.keyword,
    regex.expression : color.expression,
    regex.modifier : color.modifier
    ]

    init() {
    }

    // Colorize all
    func colorize(_ textView: NSTextView) {
    let all = textView.string
    let range = NSString(string: textView.string).range(of: all)
    colorize(textView, range: range)
    }

    // Colorize range
    func colorize(_ textView: NSTextView, range: NSRange) {
    var extended = NSUnionRange(range, NSString(string: textView.string).lineRange(for: NSMakeRange(range.location, 0)))
    extended = NSUnionRange(range, NSString(string: textView.string).lineRange(for: NSMakeRange(NSMaxRange(range), 0)))

    for (pattern, attribute) in patterns {
    applyStyles(textView, range: extended, pattern: pattern, attribute: attribute)
    }
    }

    func applyStyles(_ textView: NSTextView, range: NSRange, pattern: String, attribute: [NSAttributedString.Key: Any]) {
    let regex = try? NSRegularExpression(pattern: pattern, options: [NSRegularExpression.Options.anchorsMatchLines])
    regex?.enumerateMatches(in: textView.string, options: [], range: range) {
    match, flags, stop in

    let matchRange = match?.range(at: 1)
    textView.textStorage?.addAttributes(attribute, range: matchRange!)
    }
    }
    }