OysterKit is a framework that provides a native Swift scanning, lexical analysis, and parsing capabilities. In addition it provides a language that can be used to rapidly define the rules used by OysterKit called STLR

Overview

OysterKit

OysterKit

A Swift Framework for Tokenizing, Parsing, and Interpreting Languages

Swift Platforms BSD Build Status - Master codecov Documentation Coverage
Twitter

OysterKit enables native Swift scanning, lexical analysis, and parsing capabilities as a pure Swift framework. Two additional elements are also provided in this package. The first is a second framework STLR which uses OysterKit to provide a plain text grammar specification language called STLR (Swift Tool for Language Recognition). Finally a command line tool, stlr can be used to automatically generate Swift source code for OysterKit for STLR grammars, as well as dynamically apply STLR grammars to a number of use-cases. The following documentation is available:

Please note all development is now for Swift 5.0 and beyond only. If you wish to use the last Swift 4.1 compatible release please use the swift/4.1 branch

Key Features

  • OysterKit Provides support for scanning strings
    • Fully supports direct and indirect left hand recursion in rules
    • Provides support for parsing strings using defined rules as streams of tokens or constructing Abstract Syntax Trees (ASTs)
    • All of the above provided as implementations of protocols allowing the replacement of any by your own components if you wish
    • Create your own file decoders (using Swift 4's Encoding/Decoding framework Encodable and Decodable)
  • STLR Provides support for defining scanning (terminal) and parsing rules
    • A lexical analysis and parser definition language, STLR, which can be compiled at run-time in memory, or from stored files
    • Complied STLR can be used immediately at run time, or through the generation of a Swift source file

Examples

Creating a rule and tokenizing a String

OysterKit can be used to create and use grammars very quickly and simply directly in Swift. Here are are few simple examples

/// Scanning
let letter = CharacterSet.letters.parse(as:StringToken("letter"))

for token in [letter].tokenize("Hello"){
	print(token)
}

Instances CharacterSet, String, and NSRegularExpression can all be used as rules directly. To make a rule produce a token just use the parse(as:TokenType) function of a rule. A grammar is simply an array of rules, and you can use that grammar to tokenise a string.

Making choices

A choice rule is simply one where any of the rules contained can match to satisfy the choice. In this case the punctuation rule can be one of a number of strings. We can then tokenize

/// Choices
let punctuation = [".",",","!","?"].choice.parse(as: StringToken("punctuation"))

for token in [letter, punctuation].tokenize("Hello!"){
    print(token)
}

Skipping Content

You don't always want to create tokens for everything. You can chain modifications to any rule together as rules have value based semantics... you don't change the original.

/// Skipping
let space = CharacterSet.whitespaces.skip()

for token in [letter, punctuation, space].tokenize("Hello, World!"){
    print(token)
}

We use all three of our different rules to tokenize "Hello, World!", but notice that we call skip() on the space rule. That means no token will be created (and when we get to more complex parsing later... it also means that if this rule forms part of another more complex rule, the skipped rules at the beginning and end won't be included in the matched range. But more on that later). You'll only get letter and punctuation tokens iun this example, but you'll still match spaces.

Repetition

You can also tell a rule how many times it must match before generating a token. Here we create a word token which repeats our letter rule one or more times.

let word = letter.require(.oneOrMore).parse(as: StringToken("word"))

for token in [word, punctuation, space].tokenize("Hello, World!"){
    print(token)
}

There are standard ones for one,noneOrOne, noneOrMore, and oneOrMore but you can also specify a closed or open range (e.g. .require(2...) would match two or more.

Sequences

Rules can be made up of sequences of other rules. In this example we create a properNoun rule which requires an uppercase letter followed by zero or more lowercase letters. Note that we create a new rule from our previous word rule that generates a different token (other). Then we make our new choice generate the word token. We've just created a little hierarchy in our grammar. word will match properNoun or other (our old word rule). You'll see why this is useful later. When you stream you'll just get word (not properNoun or other).

// Sequences
let properNoun = [CharacterSet.uppercaseLetters, CharacterSet.lowercaseLetters.require(.zeroOrMore)].sequence.parse(as: StringToken("properNoun"))
let classifiedWord = [properNoun,word.parse(as: StringToken("other"))].choice.parse(as: StringToken("word"))

print("Word classification")
for token in [classifiedWord, punctuation, space].tokenize("Jon was here!"){
    print(token)
}

Parsing - Beyond Tokenization

Tokenizing is great, and there are many applications where it's enough (syntax highlighting anyone?), but if you are going to attempt anything like building an actual language, or want to parse a more complex data structure you are going to want to build an Abstract Syntax Tree. OysterKit can build HomogenousTree's from any grammar. Wait! Don't go. It's not that bad! Here it is in action.

do {
    print(try [[classifiedWord, punctuation, space].choice].parse("Jon was here!"))

} catch let error as ProcessingError {
    print(error.debugDescription)
}

Here we use parse() instead of tokenize(). We need to wrap it in a do-catch block because whereas with tokenization we just stopped streaming when something went wrong, we can get a lot more information when we parse including errors. This code simply tries to parse (note this time we are creating a single rule grammar, but that single rule is a choice of all our other rules) the same string as before, but this time it produces a tree. Here's what would be printed out

root 
    word 
	    properNoun - 'Jon'
    word 
	    other - 'was'
    word 
	    other - 'here'
    punctuation - '!'

Now we can see our word classification.

Building Complex Heterogenous Abstract Syntax Trees

I know... I did it again... jargon. It's pretty simple though. Homogenous means "of the same kind", so a Homogenous tree is just one where every node in the tree is the same type. That's what the parse function creates. build can create heterogenous (data structures populated with different kinds of data) of data structures, such as Swift types. OysterKit uses the power of Swift make this really quite simple.

Out of the box you can Decode and Decodable type using an OysterKit grammar (and if you think this is powerful, wait until you've had a look at STLR and auto-generated the Swift source code instead of doing all of the typing you are about to see!).

First, let's declare some data structures for words and sentences.

struct Word : Decodable, CustomStringConvertible {
    let properNoun : String?
    let other : String?
    
    var description: String {
        return properNoun != nil ? "properNoun: \(properNoun!)" : "other: \(other!)"
    }
}

struct Sentence : Decodable {
    let words : [Word]
    let punctuation : String
}

Fairly straightforward (if inaccurate... you can normally have more punctuation than just at the end). Now we define a grammar that produces tokens with names that match the properties of our types, and OysterKit (and Swift) will do the rest.

do {
    let words = [classifiedWord, space.require(.zeroOrMore)].sequence.require(.oneOrMore).parse(as:StringToken("words"))
    let sentence = try [ [words, punctuation ].sequence ].build("Jon was here!", as: Sentence.self)

    print(sentence)
} catch let error as ProcessingError {
    print(error.debugDescription)
} catch {
    print(error)
}

Instead of parse() we build(). We need an extra parameter here; you need to tell build what you want to build it as.

.build("Jon was here!", as: Sentence.self)

That tree we saw in the previous example can be exactly matched against our data-structure.

But what if I want a Heterogeneous Tree but don't want to go to all that effort?

Luckily OysterKit comes hand in hand with STLR which is a language for writing grammars. You can either dynamically turn this into Swift in memory (perfect if you just want to parse) or use the final member of the trinity stlrc to generate the Swift not just for the rules, but the Swift data structures too. You can read full documentation for STLR here, but I wanted to leave you with an example of the STLR for the grammar we finished with, and the Swift it generates, but not before showing you the only Swift you'll need to write to use it

The only code you'll have to write

All you need to do is build an instance of the generated type...

do {
    let sentence = Sentence.build("Hello Jon!")
} catch {
    print(error)
}

It's really that simple. OK, here's where it came from

The STLR

grammar Sentence

punctuation = "." | "," | "!" | "?"

properNoun  = .uppercaseLetter .lowercaseLetter*
other       = .letter+

word        = properNoun | other
words       = (word -.whitespace+)+

sentence    = words punctuation

Yup. That's it. Here's the Swift that was generated. There seems to be a lot of it... but remember, you don't even need to look at it if you don't want to! When you do though, you should see all of the things you've learned in there

The Generated Swift

We can now use stlrc to compile the STLR into Swift. This simple command will do that

stlrc generate -g Sentence.stlr -l swiftIR -ot ./

The above command will generate a Sentence.swift file in the current directory. You should see what it does if you change -l swiftIR to -l SwiftPM... but that's another story. Here's what's in Sentence.swift

import Foundation
import OysterKit

/// Intermediate Representation of the grammar
internal enum SentenceTokens : Int, TokenType, CaseIterable, Equatable {
    typealias T = SentenceTokens

    /// The tokens defined by the grammar
    case `punctuation`, `properNoun`, `other`, `word`, `words`, `sentence`

    /// The rule for the token
    var rule : Rule {
	switch self {
	    /// punctuation
	    case .punctuation:
		return [".", ",", "!", "?"].choice.reference(.structural(token: self))

	    /// properNoun
	    case .properNoun:
		return [CharacterSet.uppercaseLetters,    CharacterSet.lowercaseLetters.require(.zeroOrMore)].sequence.reference(.structural(token: self))

	    /// other
	    case .other:
		return CharacterSet.letters.require(.oneOrMore).reference(.structural(token: self))

	    /// word
	    case .word:
		return [T.properNoun.rule,T.other.rule].choice.reference(.structural(token: self))

	    /// words
	    case .words:
		return [T.word.rule, -CharacterSet.whitespaces.require(.oneOrMore)].sequence.require(.oneOrMore).reference(.structural(token: self))

	    /// sentence
	    case .sentence:
		return [T.words.rule,T.punctuation.rule].sequence.reference(.structural(token: self))
	}
    }

    /// Create a language that can be used for parsing etc
    public static var generatedRules: [Rule] {
	return [T.sentence.rule]
    }
}

public struct Sentence : Codable {

    // Punctuation
    public enum Punctuation : Swift.String, Codable, CaseIterable {
	case period = ".",comma = ",",ping = "!",questionMark = "?"
    }

    // Word
    public enum Word : Swift.String, Codable, CaseIterable {
	case properNoun,other
    }

    public typealias Words = [Word] 

    /// Sentence 
    public struct Sentence : Codable {
	public let words: Words
	public let punctuation: Punctuation
    }
    public let sentence : Sentence
    
    /**
     Parses the supplied string using the generated grammar into a new instance of
     the generated data structure

     - Parameter source: The string to parse
     - Returns: A new instance of the data-structure
     */
    public static func build(_ source : Swift.String) throws ->Sentence{
	let root = HomogenousTree(with: StringToken("root"), matching: source, children: [try AbstractSyntaxTreeConstructor().build(source, using: Sentence.generatedLanguage)])
	// print(root.description)
	return try ParsingDecoder().decode(Sentence.self, using: root)
    }

    public static var generatedLanguage : Grammar {return SentenceTokens.generatedRules}
}

There are some interesting (and I think rather clever) things in there. Note that for the Word type STLR has been clever and determined that there are only a couple of possible values and that both of those are just Strings, so it's created an enum instead. It's done that for Punctuation as well, but that's a little easier as it was just a choice of simple strings. It's also determined that it doesn't really need to create a new type for Words, it can just use a typealias.

I mention this because you will be interacting with this data structure, so I've spent a lot of time making sure it genertes easy to use Swift, that's strongly typed. This is going to make it easier for you to work with once building is complete.

Status

You will notice there are some warnings in this build. You should not be concerned by these as they are largely forward references to further clean up that can be done now that STLR is generating the Swift code for both Rules/Tokens as well as the data-structures for itself. Deprication is in full swing now as I start to move closer to 1.0 and want to get old code out.

Comments
  • You must declare the name of the grammar before any other declarations (e.g. grammar <your-grammar-name>) from 47 to 47

    You must declare the name of the grammar before any other declarations (e.g. grammar ) from 47 to 47

    I'm trying to build an stlr file for swift comments (taken from "The Swift Programming Language" book).

    This is my grammar file: swift.stlr

    grammar SwiftComments
    
    whitespace = whitespace-item whitespace?
    
    whitespaceItem = lineBreak | comment | multiline-comment |
    				  "\u0000" | "\u0009" | "\u000B" | "\u000C" | "\u0020"
    
    lineBreak = "\u000A" | "\u000D" | "\u000D\u000A"
    
    comment = "//" commentText lineBreak
    multilineComment = "/*" multilineCommentText "*/"
    
    commentText = commentTextItem commentText?
    commentTextItem = /[^\r\n]/
    
    multilineCommentText = multitlineCommentTextItem multitlineCommentText?
    multilineCommentTextItem = (>> !"/*" | !"*/") (multilineComment | commentTextItem)
    

    When I run stlrc -g swift.stlr I get the error in issue title. Any pointers to where I got this wrong?

    question 
    opened by eimantas 17
  • Add tests for `RuleAnnotations+Description.swift`

    Add tests for `RuleAnnotations+Description.swift`

    These tests check for a generated string for a single token (each token with each value type - 7x4). What needs to be done more is check for proper generation of multiple tokens from a single dinct. This is hard since dict keys are unsorted. To do this properly we'd need to sort the keys in description method (which would be solely for the purpose of the tests).

    opened by eimantas 6
  • Bork example errors with preposition

    Bork example errors with preposition

    I pulled the Bork repo, as well as my own, and when I run the example: "ATTACK SNAKE WITH SWORD" im getting the following error:

    keyNotFound(CodingKeys(stringValue: "noun", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "secondSubject", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"noun\", intValue: nil) (\"noun\").", underlyingError: nil))
    
    // Lexer
    
    @pin verb         = "INVENTORY" | "GO" | "PICKUP" | "DROP" | "ATTACK"
    @pin noun         = "NORTH" | "SOUTH" | "KITTEN" | "SNAKE" | "CLUB" | "SWORD"
    @pin adjective    = "FLUFFY" | "ANGRY" | "DEAD"
    @pin preposition  = "WITH" | "USING"
    
    // Commands
    subject = (adjective .whitespace)? noun
    command = verb (.whitespace subject (.whitespace preposition .whitespace @token("secondSubject") subject)? )?
    
    

    Just like your tutorial.

    Thanks!

    opened by wess 3
  • OysterKit.swift missing

    OysterKit.swift missing

    I converted the code to use Swift 1.2, and also fixed the absolute path in the project to get things compiling.

    One thing I'm not sure I can work around though, the iOS version of the OysterKit framework includes the file "OysterKit.swift", which is not in the project anywhere. I note that the Mac version of the framework has OKStandard.swift - is that a new name for the same file?

    opened by KiGi 3
  • Fixed ParseCommand.parseInput not using language argument

    Fixed ParseCommand.parseInput not using language argument

    Turns out, when using parse command with a supplied grammar, parseInput function tried to parse the grammar itself, not the passed input with supplied language. This is fixed in this PR, also fully fixes #47.

    I wasn't able to add tests for ParseCommand due to inscrutable linking errors when trying to import stlrc module in tests code, might be some configuration issue. Happy to write those test if we figure out how to link them correctly to stlrc module.

    opened by MaxDesiatov 2
  • Bork tutorial example always fails with obscure error

    Bork tutorial example always fails with obscure error

    Hi, thanks for the great library!

    When I go through the tutorial, I copy the example grammar exactly as given:

    //
    // A grammar for the Bork text-adventure
    //
    
    
    // Vocabulary
    //
    @pin verb        = "INVENTORY" | "GO" | "PICKUP" | "DROP" | "ATTACK"
    @pin noun        = "NORTH" | "SOUTH" | "KITTEN" | "SNAKE" | "CLUB" | "SWORD"
    @pin adjective   = "FLUFFY" | "ANGRY" | "DEAD"
    @pin preposition = "WITH" | "USING"
    
    // Commands
    //
    subject     = (adjective .whitespaces)? noun
    command     = verb (.whitespaces subject (.whitespaces preposition .whitespaces subject)? )?
    

    to a file Bork.stlr

    After I test this grammar with swift run stlrc -g Bork.stlr I always get this error with any of the tutorial test strings:

    Parsing failed: 
    constructionFailed([])
    

    The error doesn't give any info on what exactly failed. OysterKit code is from master branch.

    bug 
    opened by MaxDesiatov 2
  • Using OysterKit for syntax highlight

    Using OysterKit for syntax highlight

    I'm pretty new to this language creation thing using tools like STLR. I was wondering if OysterKit and STLR would be of any help in creating a simple editor with rudimentary syntax highlight (by recognizing language node types and providing location information in source string).

    question 
    opened by eimantas 1
  • Rework error handling

    Rework error handling

    The new stack and rule system enables far more simple error handling, but the code is still littered with old special cases that are no longer required.

    Before release of v1 this should be cleaned up to use simple hierarchical errors and all error handling removed from IRs and parsing strategies.

    enhancement 
    opened by SwiftStudies 1
  • Offer a brew install option for command line tool

    Offer a brew install option for command line tool

    Following how Swiftenv (https://swiftenv.fuller.li/en/latest/installation.html) does the brew install setup, I would love to be able to install the command line interface via brew instead of having to worry about cloning or using it on some variance of a path.

    enhancement 
    opened by wess 1
  • Nested expression matching

    Nested expression matching

    One awesome thing would be ability to nest pattern matches/calls within your grammar, like a PEG, Antlr, or even a Flex/Bison:

    Example:

    statement = [a-zA-Z0-9]+
    statements = statement + statements
    

    It might do this, just didn't see anything in the docs about it.

    ps. awesome work on regex support!

    opened by wess 1
  • Suggestion to rename .whitespaces to .whitespace or .whitespaceOrTab or to change their behaviour

    Suggestion to rename .whitespaces to .whitespace or .whitespaceOrTab or to change their behaviour

    When reviewing #47 I realised that .whitespaces naming doesn't play well with .whitespaces*, .whitespaces+ or .whitespace?. It implies that many whitespaces may be matched, while only one is matched.

    It could be better for library user experience to either rename it or make it match multiple symbols. Possible naming: .whitespace, .whitespaceChar, .whitespaceCharacter, .whitespaceOrTab.

    Same actually could be applied to .newlines, which I think matches only one newline character.

    Overall, looking at character sets, singular/plural naming is inconsistent at a first glance. I understand that it applies to the number of characters in a character set, but users of STLR might not understand it this way (like it happened to me). I think that communicating how many characters will be matched is more important than how many characters are in a set.

    enhancement 
    opened by MaxDesiatov 1
  • Support parsing a plain byte stream

    Support parsing a plain byte stream

    Based on the examples and the definition of a parse() function it looks like it's only possible to parse strings, not the more generic Data. I think it would be a nice feature if it would be possible to run the parser over a generic Data as this would allow to parse more complex grammars where some rules may define a blob array or something like that.

    opened by daniel-abramov 0
  • Update stlrc to use TerminalKit

    Update stlrc to use TerminalKit

    CommandKit is heavy and fundamentally hard to understand. TerminalKit is simpler (and somewhat less powerful) but is more than enough and will enable easier extension.

    https://github.com/SwiftStudies/TerminalKit

    enhancement 
    opened by SwiftStudies 2
  • Finalize changes to STLR language

    Finalize changes to STLR language

    Remove some of the old transient tokens that are no longer needed, and make the new ones that can be used for error propagation and handling standard instead of custom.

    enhancement 
    opened by SwiftStudies 0
Releases(0.6.2)
  • 0.6.2(Aug 12, 2019)

  • 0.6.1(Aug 12, 2019)

  • 0.6.0(Sep 2, 2018)

    The New API Release

    OysterKit

    There has been a significant amount of refactoring in this release, and a lot of old code disposed of. Only the fully automatically generated (by `stlrc`) `STLR` compiler is now in use (and in the code base). I recommend if you are moving from pre 0.5 you move through 0.5.1, fix depreciation warnings, then move to this release and again fix depreciation warnings as I'll be removing the code from them as I push towards API stability which this release should largely achieve. I've updated the API documentation and added some examples of the new API to the readme. I hope you like it, it was certainly easier to write about than the old one! Source code(tar.gz)
    Source code(zip)
  • 0.5.1(Aug 25, 2018)

    Swift 4.2 and new API transition release

    In this release I have added significant new capabilities to not only auto-generate the rules for parsing but also the Abstract Syntax Tree implemented as Swift types, and using the Decoding framework of standard Swift to automatically populate that based on the results of parsing with the rules.

    In addition I have begun the work of refactoring the rule/token API to make significant optimisation available in the future and to dramatically simplify developing rules directly in Swift.

    In this release old API is marked as deprecated, and the next release (0.6) will remove them completely to free me to start to benefit from the new architecture from now on.

    This release requires at least Swift 4.2. Please use the swift/4.1 branch if you wish to continue with Swift 4.1 for now, but note only bug-fix pull requests from others will be applied from now on.

    Source code(tar.gz)
    Source code(zip)
  • 0.5.0(Jul 17, 2018)

    Some fairly major changes as we progress towards version 1.0. No changes required by any consumers but Swift IntermediateRepresentation autogeneration has been added. There are some issues at this stage, but for the first time you can parse STLR itself and generate the parsing rules and the IR automatically which can then be used to parse STLR.

    The new flatter rule system is also included in this release and is thoroughly tested but is not yet consumed by anything. Existing rule implementers don't need to change anything (and may never need to), but internally ParserRules and ScannerRules will be replaced by this new architecture.

    Furthermore creating custom (and therefore potentially highly optimised) rules in Swift is now very easy (see ClosureRule).

    If any future changes are required they will be minimal.

    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Jul 10, 2018)

  • 0.3.2(Jun 17, 2018)

  • 0.3.1(May 9, 2018)

  • 0.3.0(Feb 6, 2018)

    This is a significant release. The API and underlying implementation have been replaced significantly simplifying both.

    The remainder of the releases up to v1.0 will now focus on stabilising the STLR language itself (not bugs, but ensuring there is a solid base to build on in future releases, and that any grammar breaking changes are minimised (I am not aware of any that are required at this point, but I will leave the door open)

    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(Feb 4, 2018)

    The overly complex API for streams, homogenous, and heterogenous abstract syntax trees are replaced by a much simpler & smaller yet equally configurable set of classes.

    You should refer to TokenStream and AbstractSyntaxTreeConstructor for more information.

    Deprecation warnings will be issued for use of the previous classes, and support for these will be removed most likely by 0.3 when internal dependencies on the legacy types has been resolved.

    In addition there are numerous fixes, although all of these are available only in the new APIs and have not been applied to the legacy ones.

    Source code(tar.gz)
    Source code(zip)
  • 0.1.4(Jan 26, 2018)

  • 0.1.3(Jan 19, 2018)

    The focus of this release has been getting the API documentation off the ground. I have also added a substantial tutorial demonstrating many of the standard OysterKit features including STLR, Swift Code Generation, automatic Parser Decoding (Using the Swift 4.0 Decoding features), stlr command line processing, and off course some standard Swift.

    In the next interim release there will be some code breaking changes as I break out STLR and it attendant parsing from OysterKit itself. I also intend to remerge the stlr command line product back into this package as well as integrating the tutorial repositories to make it easier to get up and running with OysterKit.

    Source code(tar.gz)
    Source code(zip)
  • 0.1.2(Jan 15, 2018)

  • v0.1.1(Dec 7, 2017)

  • 0.1.0(Sep 11, 2017)

    Beta Release 1: OysterKit v2 (0.1.0)

    There is a lot of work that needs to be done to tidy up the code base, and changes should be expected to STLR (although I believe it is largely syntacticly complete). From this point onwards I will create issues for any code breaking changes I'm intending to make (including both Swift and STLR)

    Source code(tar.gz)
    Source code(zip)
Owner
Swift Studies
Swift Studies
A Swift framework for parsing, formatting and validating international phone numbers. Inspired by Google's libphonenumber.

PhoneNumberKit Swift 5.3 framework for parsing, formatting and validating international phone numbers. Inspired by Google's libphonenumber. Features F

Roy Marmelstein 4.7k Jan 8, 2023
Markdown parsing and rendering for iOS and OS X

CocoaMarkdown Markdown parsing and rendering for iOS and macOS CocoaMarkdown is a cross-platform framework for parsing and rendering Markdown, built o

Indragie Karunaratne 1.2k Dec 12, 2022
Croc is a swift emoji string parsing library

Croc is a library for parsing emojis on iOS. It provides a simple and lightweight interface for detecting, generating, categorizing and managing emoji characters, making emoji-powered features an easy task for developers.

Joe Kalash 127 Nov 20, 2022
Swift emoji string parsing library

Croc is a library for parsing emojis on iOS. It provides a simple and lightweight interface for detecting, generating, categorizing and managing emoji

Joe Kalash 125 Sep 27, 2021
A Pure Swift implementation of the markdown mark-up language

SmarkDown A pure Swift markdown implementation consistent with Gruber's 1.0.1 version. It is released under the BSD license so please feel free to use

Swift Studies 67 Jan 24, 2022
A set of libraries to help users find and replace native system emojis with EmojiOne in their app or website.

This repository is now maintained as JoyPixels/emoji-toolkit. You'll find the latest version of our resources at emoji-toolkit. Please see the UPGRADE

JoyPixels Inc. 4.5k Dec 24, 2022
Marky Mark is a parser written in Swift that converts markdown into native views.

Marky Mark is a parser written in Swift that converts markdown into native views. The way it looks it highly customizable and the supported markdown syntax is easy to extend.

M2mobi 287 Nov 29, 2022
A lightning fast, native SwiftUI scratchpad/text editor.

Sedit A lightning fast, native SwiftUI scratchpad/text editor. Sedit (Swift Edit, as in the language and as in fast) is a lightning fast basic text ed

null 5 Jan 28, 2022
AttributedText is a Swift µpackage that provides NSAttributedString rendering in SwiftUI by wrapping either an NSTextView or a UITextView depending on the platform.

AttributedText AttributedText is a Swift µpackage that provides NSAttributedString rendering in SwiftUI by wrapping either an NSTextView or a UITextVi

null 1 Jul 18, 2022
A TextView that provides easy to use tagging feature for Mention or Hashtag

Tagging A TextView that provides easy to use tagging feature for Mention or Hashtag. Introduction Tagging is a UIView that encloses a TextView that co

DongHee Kang 110 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 simple library that provides standard Unicode emoji support across all platforms

Twitter Emoji (Twemoji) A simple library that provides standard Unicode emoji support across all platforms. Twemoji v13.1 adheres to the Unicode 13.0

Twitter 15k Jan 8, 2023
Powerful text framework for iOS to display and edit rich text.

YYText Powerful text framework for iOS to display and edit rich text. (It's a component of YYKit) Features UILabel and UITextView API compatible High

null 8.8k Jan 4, 2023
A Swift framework for using custom emoji in strings.

Emojica – a Swift framework for using custom emoji in strings. What does it do? Emojica allows you to replace the standard emoji in your iOS apps with

Dan 101 Nov 7, 2022
The iOS framework that grows only as fast as its documentation

Nimbus is an iOS framework whose feature set grows only as fast as its documentation. Support status Nimbus is in a supported maintenance mode, meanin

featherless 6.5k Nov 30, 2022
An Objective-C framework for converting Markdown to HTML.

MMMarkdown MMMarkdown is an Objective-C framework for converting Markdown to HTML. It is compatible with OS X 10.7+, iOS 8.0+, tvOS, and watchOS. Unli

Matt Diephouse 1.2k Dec 14, 2022
Heimdall is a wrapper around the Security framework for simple encryption/decryption operations.

Heimdall In Norse mythology, Heimdall is the gatekeeper of Bifröst, the rainbow road connecting Midgard, realm of the humans, to Asgard, the realm of

Henri Normak 393 Nov 23, 2022
A simple and customizable Markdown Parser for Swift

MarkdownKit MarkdownKit is a customizable and extensible Markdown parser for iOS and macOS. It supports many of the standard Markdown elements through

Bruno Oliveira 687 Dec 18, 2022
An NSPredicate DSL for iOS, OSX, tvOS, & watchOS. Inspired by SnapKit and lovingly written in Swift.

PrediKit A Swift NSPredicate DSL for iOS & OS X inspired by SnapKit, lovingly written in Swift, and created by that weird dude at KrakenDev. If you're

Hector Matos 542 Sep 24, 2022