Swift Snippets
Hello everyone,
Continuing the discussion started in Command Line UX Enhancements for swift
, I'd like to introduce some experimental work for a new Swift Package Manager feature for snippets.
We all know that learning by example is great, especially for code. I wanted to create the smallest, simplest method of providing example code for Swift packages, and I've just landed some work in progress in the Swift Package Manager.
First and foremost a teaching tool, snippets are a small, focused, single file of example code that teaches a specific concept or API. Each snippet is a piece of the puzzle for documenting and showing best practices for your packages. They can also stand alone as a series of exercises, examples, or code recipes.
Each snippet file implies an executable target in the package that builds alongside the other targets in a package, ensuring that your examples always build. They can automatically import any library that a package defines, along with those normally available in an SDK, or whatever is the equivalent for your platform.
You can think of this work on snippets as both a new file format for sample code, and an initial implementation of a UX for interacting with those snippets (via SwiftPM.) It is easy to imagine other editors, IDEs, education apps, or documentation tools interacting with snippet files to teach in new and exciting ways.
Writing and organizing snippets in a package
Here's an example snippet file:
//! Does a foo.
import MyModule
func foo() {}
// MARK: Hide
print(...)
// MARK: Show
func bar() {
foo()
}
The //!
comment is presented as a brief explanation for the snippet. This comment does not show inline in the source but at the top or in a listing for searching and browsing. Feel free to use regular comments if you need to explain the flow of a snippet.
The MARK: Hide
comment tells the snippet system that the line and subsequent lines should be hidden but kept for building and running. A MARK: Show
line will toggle that and lines will start showing again. This is how you separate presentation code from demo code, or glue code if you like.
The above snippet would present via SwiftPM like so:
Does a foo.
import MyModule
func foo() {}
func bar() {
foo()
}
To start adding snippets to a package, create a Snippets
directory alongside the familiar Sources
and Tests
directory and start dropping .swift
files into thereโno configuration or manifest changes necessary.
๐ MyPackage
๐ Package.swift
๐ Sources/
๐ Tests/
๐ Snippets/
๐ A.swift
๐ B.swift
๐ C.swift
...
As you can see, the simple case (above) is incredibly simple to get started. As your body of snippets grows, you can create subdirectories to serve as groups, and even add an Explanation.md
file that provides an abstract for the group.
๐ MyPackage
๐ Package.swift
๐ Sources/
๐ Tests/
๐ Snippets/
๐ Fizzing
๐ Explanation.md
๐ Fizz.swift
...
๐ Buzzing
๐ Explanation.md
๐ Buzz.swift
...
Browsing a package's snippets at the command line
Included in the initial code contribution is an interactive command line experience that presents snippets in menus, or cards, along with short explanations. Here's what it looks like.
First, below is the top card. This shows either the snippets you have put into the Snippets
directory or snippet groups, if you have opted to create those.
Here below is the snippet group card. Grouping your snippets is optional, but it can help you organize your snippets by task or concept.
Finally below is the card for a snippet. You can see the abstract, code, and an option to run the snippet.
Try it out!
Snippets are available for testing in the Trunk Development snapshots. To try out the interactive experience at the command line, you first need some snippets. I've created a dummy project for you to see the folder structure, which you can clone and try the command below or start adding them to your own packages.
Once you've got some snippets in your Snippets
directory, set an environment variable SWIFTPM_ENABLE_SNIPPETS
to enable the feature and use the new swift-package
subcommand called learn
.
export SWIFTPM_ENABLE_SNIPPETS=1
swift package learn
Questions?
Here are some answers to potential questions you might have about snippets:
Why single files?
Example code projects are still useful vehicles for explaining complex applications that may pull in many concepts at the same time. However, they can grow to be quite large and difficult to maintain. They also present navigation challenges for beginners and experienced developers alike. SwiftPM already has executable targets in which many source files can take part. Snippets are a short path to creating digestable, searchable chunks of code.
Are snippets just tests?
No, snippets aren't tests. Again, snippets are a teaching tool, and I wanted to provide a tool that lets package authors focus on teaching users how to use their package and not mix in complex concerns about setup, tear-down, and glue code that is not typical of real world use.
Future Development
In the future, here are some aspects I would like to explore with snippets:
-
Add syntax highlighting to code snippets at the command line. This is something that I have already started working on but will require a SwiftSyntax dependency.
-
Presentation order of snippets and groups
-
Export of snippet data for integration into DocC, The Swift Programming Language book, swift.org, and more
-
Search for text and titles at the command line
-
Turning snippets into high-level templates
-
Creating a style guide for teaching with snippets
-
Optional or uncommon features for Package.swift, such as excludes
I hope I've whetted your appetite and I'm curious to hear what you think about this approach.
Thanks!