Awesome
Sylvester πΌ
<p align="center"> <a href="https://github.com/Carthage/Carthage" style="text-decoration:none" target="_blank"> <img alt="Carthage compatible" src ="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat"/> </a> <a href="https://cocoapods.org/pods/Sylvester" style="text-decoration:none" target="_blank"> <img alt="Pod Version" src ="https://img.shields.io/cocoapods/v/Sylvester.svg?style=flat"/> </a> <a href="https://travis-ci.org/chriszielinski/Sylvester" style="text-decoration:none" target="_blank"> <img src="https://travis-ci.org/chriszielinski/Sylvester.svg?branch=master"> </a> <a href="https://sonarcloud.io/dashboard?id=chriszielinski_Sylvester" style="text-decoration:none" target="_blank"> <img src="https://sonarcloud.io/api/project_badges/measure?project=chriszielinski_Sylvester&metric=alert_status"> </a> <a href="https://sonarcloud.io/component_measures?id=chriszielinski_Sylvester&metric=Coverage" style="text-decoration:none" target="_blank"> <img src="https://sonarcloud.io/api/project_badges/measure?project=chriszielinski_Sylvester&metric=coverage"> </a> <a href="https://codebeat.co/projects/github-com-chriszielinski-sylvester-master" style="text-decoration:none" target="_blank"> <img alt="codebeat badge" src="https://codebeat.co/badges/94e83fa7-6299-4c3c-a364-5c3aa958cf8e" /> </a> <a href="https://developer.apple.com/swift" style="text-decoration:none" target="_blank"> <img alt="Swift Version" src ="https://img.shields.io/badge/language-swift%204.2-brightgreen.svg"/> </a> <a href="https://github.com/chriszielinski/Sylvester/blob/master/LICENSE" style="text-decoration:none" target="_blank"> <img alt="GitHub license" src ="https://img.shields.io/badge/license-MIT-blue.svg"/> </a> <img alt="PRs Welcome" src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" /> <br> <br> <img src="https://github.com/chriszielinski/Sylvester/blob/master/.readme-assets/header.png?raw=true" alt="Header"> <br> <br> <b>A type-safe, XPC-available <a href="https://github.com/jpsim/SourceKitten"> SourceKitten</a> (SourceKit) interface with some sugar.</b> <br> </p>Looking for...
- A Floating Action Button for macOS? Check out Fab. ποΈ.
- An Expanding Bubble Text Field for macOS? Check out BubbleTextField π¬.
- An integrated spotlight-based onboarding and help library for macOS? Check out Enlighten π‘.
Features
- Type-safe, no more dictionaries and
SourceKitRepresentable
s. - Optional XPC service, sandbox-friendly.
- Subclassable interface.
- Comprehensive test suite.
Requirements
- macOS 10.12+
Modules
The Sylvester
framework has two build configurations that differ in their method of communicating with SourceKit
:
Sylvester
β Communicates directly from within the embedding application or process. This module is not sandbox-friendly.SylvesterXPC
β Communicates through a XPC service. This module provides privilege separation, enhanced stability, and is sandbox-friendly.
π Note: The XPC service itself cannot be sandboxed (due to inherent dependencies: xcrun, xcodebuild, sourcekitd), and requires an additional code signing step.
Installation
Sylvester
is available for installation using Carthage or CocoaPods.
Using CocoaPods
π Bug: Requires CocoaPods version >= 1.6.0 (Current pre-release, 1.6.0.rc.2)
π£ Important: The XPC service (and/or the
SylvesterXPC
module) is currently unavailable for CocoaPods installations.
pod "Sylvester"
Using Carthage
github "chriszielinski/Sylvester"
Dependencies
Sylvester
/SylvesterXPC
depends on the following frameworks/libraries, so ensure they are also embedded in the Embed Frameworks phase:
SylvesterCommon.framework
SourceKittenFramework.framework
SWXMLHash.framework
Yams.framework
Code Signing
If you decide to use the SylvesterXPC
module, you will need to add a Run Script phase before embedding the SylvesterXPC.framework (i.e. before the Embed Frameworks phase). Ensure the shell launch path is /bin/sh
(default). Then for Carthage installations, execute the code_sign_carthage.sh
shell script in the repository's Scripts directory.
"$SRCROOT/Carthage/Checkouts/Sylvester/Scripts/code_sign_carthage.sh"
<p align="center">
<img src="https://github.com/chriszielinski/Sylvester/blob/master/.readme-assets/code-sign.png?raw=true" alt="Code Sign Phase">
</p>
For other installations, modify the script's paths as neccessary.
Supported Requests
Request | Class |
---|---|
Code Completion | SKCodeCompletion |
Code Completion Session | SKCodeCompletionSession |
Cursor Info | SKCursorInfo |
Documentation Info | SKDocInfo |
Editor Open | SKEditorOpen |
Editor Extract Text From Comment | SKEditorExtractTextFromComment |
Convert Markup To XML | SKConvertMarkupToXML |
Module Info | SKModule |
Swift Documentation | SKSwiftDocs |
Syntax Map | SKSyntaxMap |
Custom YAML | SKYAMLRequest |
Other Fun Things
Subclassing
Most of the standard requests are concrete subclasses of beautiful generic classes. Fancy your own subclass? No problem, it might be possible.
SKSubstructure
, SKEntity
Also known as SKBaseSubstructure
(or SKBaseEntity
), a common culprit.
π Note: Subclassing
SKBaseEntity
uses similar syntax.
final class BetterSubstructureSubclass: SKBaseSubstructure, SKFinalSubclass {
var iAmAnImportantProperty: String = "πΆββοΈ"
public override func decodeChildren(from container: DecodingContainer) throws -> [SKBaseSubstructure]? {
return try decodeChildren(BetterSubstructureSubclass.self, from: container)
}
/// The default iterator for `SKChildren` does a pre-order (NLR) depth-first search (DFS) traversal; however, if you want something else, for instance:
class FunctionSubstructureIterator<Substructure: BetterSubstructureSubclass>: SKPreOrderDFSIterator<Substructure> {
override func next() -> Substructure? {
guard let nextSubstructure = super.next()
else { return nil }
if nextSubstructure.isFunction {
return nextSubstructure
} else {
return next()
}
}
}
override class func iteratorClass<Substructure: BetterSubstructureSubclass>() -> SKPreOrderDFSIterator<Substructure>.Type {
return FunctionSubstructureIterator.self
}
}
SKEditorOpen
, SKSwiftDocs
An example of a SKSwiftDocs
subclass utilizing the BetterSubstructureSubclass
declared above:
π Note: Subclassing
SKEditorOpen
uses identical syntax, except it inherits fromSKGenericEditorOpen
.
class BetterSwiftDocs: SKGenericSwiftDocs<BetterSubstructureSubclass> {
var mySuperCoolProperty: String = "π"
}
SKModule
An example of a SKModule
subclass utilizing the BetterSwiftDocs
and BetterSubstructureSubclass
classes declared above:
class BetterModule: SKGenericModule<BetterSubstructureSubclass, BetterSwiftDocs> {}
Documentation
You can explore the docs here.
// ToDo:
- Add support for other requests.
Community
- Found a bug? Open an issue.
- Feature idea?
Open an issue.Do it yourself & PR when done π (or you can open an issue π). - Want to contribute? Submit a pull request.
Contributors
- Chris Zielinski β Original author.
Frameworks & Libraries
Sylvester
depends on the wonderful contributions of the Swift community, namely:
- jpsim/SourceKitten β An adorable little framework and command line tool for interacting with SourceKit.
- macmade/AtomicKit β Concurrency made simple in Swift.
- groue/GRMustache.swift β Flexible Mustache templates for Swift.
- realm/jazzy β Soulful docs for Swift & Objective-C.
- realm/SwiftLint β A tool to enforce Swift style and conventions.
License
Sylvester
is available under the MIT license, see the LICENSE file for more information.