Skip to content
C.W.K.
Stream
Lesson 03 of 05 · published

SwiftTerm on Both

~10 min · swiftterm, pin, ios, embed, emulator

Level 0Spark
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

One Pin, Two Glasses

The Mac host wraps SwiftTerm in AppKit. The phone wraps SwiftTerm in SwiftUI around a UIKit terminal view. Both attach the same embedded core, the same exact pin. That is not an accident and not a preview of a language course. A glyph bug is one pin, not two forks. A Korean IME composing mark is one core's problem, not a Mac-only patch and an iOS-only hope. Track 1 already refused to rewrite the emulator. This lesson refuses to rewrite it twice.

The pin is exact because a floating range is how Wednesday's phone feels different from Tuesday's Mac with no commit you can point at. Moving the pin is a decision, recorded, applied to both surfaces together. A Mac-only bump that "we will catch iOS up later" is a fork with a calendar. Later, in this family, is how forks get comfortable.

The Core Still Does Not Own the Family

SwiftTerm draws characters. It does not own leases, spectators, arrangements, or the gateway. Those sit above the core, in app code, on both surfaces, talking the shared wire. If a family rule cannot be expressed above the emulator — if you need a local diff against SwiftTerm to make a spectator not resize — you do not have a family rule. You have a core-change decision, and it has to be made in the open, for both glasses at once.

Configure the core: font, scrollback, the standard palette, Option as Meta on the Mac. Do not patch it to know what a spectator is. Observation-must-not-resize, in the next lesson, is a wire and lease rule, not a renderer flag. Putting it in the emulator is how you fork the pin the first time someone watches from a phone.

Language Is a Sibling Quest

Swift the language — actors, isolation, the way a view wraps a UIKit surface — is deferred. There is a sibling quest for that, or there will be. This lesson's product fact is narrower: the emulator dependency is shared, so the daily-driver bar does not grow a second parser. If you came here to learn Swift, you are in the wrong house. If you came here to understand why a pocket Smolder does not ship a second terminal core, you are in the right one.

Identity chrome still sits outside the core. Ember rail, ash title bar, wordmark — those are views around SwiftTerm, on both sizes of glass, not cells the emulator was asked to paint orange. Content colors stay standard on the phone too. A pocket TUI is still a TUI. Painting it ember to "match the icon" is the same fight as on the Mac, in a smaller room.

Same pin, both surfaces. Configure the core. Never patch it. Never fork it by bumping one glass and not the other. Swift the language waits in a sibling quest; this lesson owns the shared emulator, not the compiler book.

Code

One product, one exact pin, two platforms·swift
// swift-tools-version: 6.2
import PackageDescription

let package = Package(
    name: "Smolder",
    platforms: [
        .macOS(.v14), .iOS(.v17)
    ],
    dependencies: [
        .package(
            url: "https://github.com/migueldeicaza/SwiftTerm.git",
            exact: "1.20.0"   // both glasses; bump is one decision
        )
    ],
    targets: [
        .target(name: "SmolderMac",  dependencies: ["SwiftTerm", "SmolderWire"]),
        // iOS is a separate Xcode project with the same exact 1.20.0 pin.
        .target(name: "SmolderWire", dependencies: []) // no AppKit, no SwiftTerm
    ]
)

// Illegal
//   exact pin on Mac, from: "1.20.0" on iOS
//   a local patch against SwiftTerm "just for spectators"
//   teaching Swift actors in this file

External links

Exercise

Name one emulator behavior that must match on Mac and iPhone (a glyph, a paste mode, a composing mark). Write what would drift if each surface floated its own version range. Then write one family feature that must stay above the core (spectator, lease, ember rail) and one sentence for the review comment if someone patched SwiftTerm to implement it.
Hint
If the feature needs to know what a spectator is, it is above the core. If the behavior is "what does ESC do in this mode," it is the core, and it has to be the same pin.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.