
SwiftTerm
=========

SwiftTerm is a VT100/Xterm terminal emulator library for Swift applications that can be 
embedded into macOS, iOS applications, text-based, headless applications or other 
custom scenarios. It has been used in several commercially available SSH clients, including 
[Secure Shellfish](https://apps.apple.com/us/app/secure-shellfish-ssh-files/id1336634154), 
 [La Terminal](https://apps.apple.com/us/app/la-terminal-ssh-client/id1629902861) and [CodeEdit](https://github.com/CodeEditApp/CodeEdit)

Check the [API Documentation](https://migueldeicaza.github.io/SwiftTerm/documentation/swiftterm/)

This repository contains both a terminal emulator engine that is UI agnostic, as well as
front-ends for this engine for iOS using UIKit, and macOS using AppKit.   A curses-based
terminal emulator (to emulate an xterm inside a console application) is available as
part of the [TermKit](https://github.com/migueldeicaza/TermKit) library. 

**Sample Code** There are a couple of minimal sample apps for Mac and iOS showing how to 
use the library inside the `TerminalApp` directory.   

* The sample Mac app has much of the functionality of MacOS' Terminal.app, but without the configuration UI.   
* The sample iOS application uses an SSH library to connect to a remote system (as there is no native shell
on iOS to run) and includes a login UI to configure the connection. 

## Companion Apps

[SwiftTermApp](https://github.com/migueldeicaza/SwiftTermApp) builds
an actual iOS app that uses this library and is more complete than the
testing apps in this module and provides a proper configuration UI.
It is a proof of concept for what you would need to do.

[Pane](https://github.com/migueldeicaza/pane) is a terminal
multiplexor, similar to tmux.

## History

This is a port of my original
[XtermSharp](https://github.com/migueldeicaza/XtermSharp), which was itself
based on [xterm.js](https://xtermjs.org).  At this point, I consider SwiftTerm
to be a more advanced terminal emulator than both of those (modulo
Selection/Accessibility) as it handles UTF, Unicode and grapheme clusters better
than those and has a more complete coverage of terminal emulation.   XtermSharp
is generally attempting to keep up, but has lagged behind.

Plenty of test cases have been extracted from xterm.js and Ghostty and
this also relies extensively on `esctest` to ensure compatibility.

Features
========

* Pretty decent terminal emulation, on or better than XtermSharp and xterm.js (and more comprehensive in many ways)
* Unicode rendering (including Emoji, and combining characters and emoji)
* Bidirectional text (Arabic, Hebrew) following the [terminal-wg BiDi recommendation](https://terminal-wg.pages.freedesktop.org/bidi/), with Arabic contextual shaping
* Reusable and pluggable engine allows multiple user interfaces to be built on top of it:
   *  Bundled MacOS and iOS
   *  Bundled Headless terminal.
   *  [TermKit](https://github.com/migueldeicaza/TermKit) contains a terminal-over-a-terminal
   *  [Pane](https://github.com/migueldeicaza/pane) implements a terminal multiplexor
* Selection engine (with macOS support in the view)
* Search support with a built-in macOS find bar and programmable search APIs
* Supports colors (ANSI, 256, TrueColor)
* Supports text attributes including bold, italic, underline, strikethrough, and dim/faint (SGR 2)
* Supports mouse events
* Supports terminal resizing operations (controlled by remote host, or locally)
* [Hyperlinks](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda) in terminal output
* Local process and SSH connection support (some assembly required for the last one)
* Proper CoreText rendering can munch through the hardened Unicode test suites.
* Graphics support:
  * Sixel (Use img2sixel to test)
  * iTerm2-style graphic rendering (Use imgcat to test)
  * Kitty graphics (Use kittyimg to test)
* Terminal session recording and playback with termcast
* Thread-safe Terminal instances
* Fuzzed and abused
* Optional GPU-accelerated rendering via Metal (macOS, iOS, visionOS)
* Seems pretty fast to me

### Image formats

SwiftTerm supports these image data formats:

* **Sixel** image streams.
* **PNG** images through the iTerm2 and Kitty graphics protocols.
* **JPEG** images through the iTerm2 graphics protocol.
* **Raw RGB** (24-bit) and **RGBA** (32-bit) pixel data through the Kitty
  graphics protocol.

For iTerm2 images, the Apple views use the system image decoder. Other image
formats that the target platform can decode can also work, but PNG and JPEG
are the tested formats.

# SwiftTerm library

The SwiftTerm library itself contains the source code for both
the engine and the front-ends.  The front-ends are conditionally
compiled based on the target platform.

The engine is in this directory, while code for macOS lives under `Mac`, and
code for iOS, lives under `iOS`.    Given that those two share a lot of common 
traits, the shared code is under `Apple`.

## Using SwiftTerm

SwiftTerm uses the Swift Package Manager for its build, and you can
add the library to your project by using the url for this project or a
fork of it.

## MacOS NSView 
The macOS AppKit NSView implementation [`TerminalView`](https://migueldeicaza.github.io/SwiftTermDocs/documentation/swiftterm/terminalview) is a reusable
NSView control that can be connected to any source by implementing the
[`TerminalViewDelegate`](https://migueldeicaza.github.io/SwiftTermDocs/documentation/swiftterm/terminalviewdelegate).  
I anticipate that a common scenario will be
to host a local Unix command, so I have included
[`LocalProcessTerminalView`](https://migueldeicaza.github.io/SwiftTermDocs/documentation/swiftterm/localprocessterminalview)
 which is an implementation that connects
the `TerminalView` to a Unix pseudo-terminal and runs a command there.

## iOS UIView
There is an equivalent UIKit UIView implementation for
[`TerminalView`](https://migueldeicaza.github.io/SwiftTermDocs/documentation/swiftterm/terminalview)
which like its NSView companion is an embeddable and reusable view
that can be connected to your application by implementing the same
TerminalViewDelegate.  Unlike the NSView case running on a Mac, where
a common scenario will be to run local commands, given that iOS does
not offer access to processes, the most common scenario will be to
wire up this terminal to a remote host.  And the safest way of
connecting to a remote system is with SSH.

## Shared Code between MacOS and iOS

The iOS and UIKit code share a lot of the code, that code lives under the Apple directory.

### Link Reporting in Apple Views

Both AppKit and UIKit `TerminalView` expose `linkReporting`:

* `.none` disables link tracking.
* `.explicit` tracks only explicit OSC 8 hyperlinks.
* `.implicit` (default) tracks explicit links first, then falls back to implicit URL detection from terminal text.

`linkReporting` controls link discovery/tracking. Link activation is additionally gated by `linkHighlightMode`.

When the user activates a link, `TerminalView` calls `TerminalViewDelegate.requestOpenLink(source:link:params:)`.
For explicit OSC 8 hyperlinks, `params` includes parsed key/value metadata (if provided); implicit links use empty `params`.
On macOS, the default delegate implementation opens links via `NSWorkspace`. On iOS/visionOS, handle `requestOpenLink` in your delegate.

* On macOS, tracking is hover-based. The default highlight mode is `.hoverWithModifier`, so Command-hover and Command-click are the default link interaction.
* On iOS/visionOS, tracking is driven by pointer/hover interactions (`UIPointerInteraction` / `UIHoverGestureRecognizer`), and tap activation depends on the active `linkHighlightMode` (including modifier requirements for modifier-based modes).

## Using SSH
The core library currently does not provide a convenient way to connect to SSH, purely
to avoid the additional dependency. The iOS sample app demonstrates how to integrate SSH
using a modern SSH stack with [swift-nio-ssh](https://github.com/apple/swift-nio-ssh). See
[`UIKitSshTerminalView`](https://github.com/migueldeicaza/SwiftTerm/blob/main/TerminalApp/iOSTerminal/UIKitSshTerminalView.swift)
and [`SSHLoginView`](https://github.com/migueldeicaza/SwiftTerm/blob/main/TerminalApp/iOSTerminal/SSHLoginView.swift)
for an example of connecting the `TerminalView` for iOS to an SSH connection.

## Termcast - Terminal Recording and Playback

SwiftTerm includes a `termcast` command-line tool that can record and playback terminal sessions in the [asciinema](https://asciinema.org/) `.cast` format. This tool is built using SwiftTerm's `LocalProcess` functionality.

### Recording Sessions

To record a terminal session:

```bash
swift run termcast record output.cast
```

Options:
- `--command` / `-c`: Specify a command to run (defaults to your shell)
- `--timeout` / `-t`: Set an automatic timeout in seconds

Examples:
```bash
# Record an interactive shell session
swift run termcast record my-session.cast

# Record a specific command
swift run termcast record -c "ls -la && echo 'Done'" command-demo.cast

# Record with a 30-second timeout
swift run termcast record --timeout 30 timed-session.cast
```

### Playing Back Sessions

To playback a recorded session:

```bash
swift run termcast playback my-session.cast
```

The playback will show the recorded terminal session with proper timing, including both input and output as they occurred during recording.

### Features

- **Full input/output capture**: Records both user input and program output with precise timing
- **Raw terminal mode**: Properly handles terminal control sequences and special keys
- **asciinema compatibility**: Uses the standard `.cast` format for interoperability
- **Live display**: Shows the session live while recording
- **Proper terminal handling**: Maintains correct line endings and terminal state  

Working on SwiftTerm
====================

If you are using Xcode, there are two toplevel projects, one for Mac
and one for iOS in the TerminalApp directory, one called "iOSTerminal.xcodeproj"
and one called "MacTerminal.xcodeproj".  

This is needed because Xcode does not provide code completion for iOS if you 
have a Mac project in the project.   So I had to split them up.   Both 
projects reference the same SwiftTerm package.

When working with these projects, if you choose the terminal application
it will run this one.   To run the test suite, select the 'SwiftTerm' target
instead, and you can use 'SwiftTermFuzz' to run the fuzzer.

You can use `swift build` to build the package, and `swift test` to
run the test suite.  For better test coverage, clone the esctest
repository which contains comprehensive terminal emulator tests:

```
make clone-esctest
swift test
```

This clones the [esctest](https://github.com/migueldeicaza/esctest)
repository (Python 3 branch) and enables the full terminal compliance
test suite to run.

If using Xcode, you can select the "SwiftTerm" project, and then use Command-U 
to run the test suite.

## Bidirectional text (BiDi)

SwiftTerm implements the [terminal-wg BiDi
recommendation](https://terminal-wg.pages.freedesktop.org/bidi/) for
right-to-left and mixed-direction text on the Apple views (both the
CoreGraphics and Metal renderers):

* The buffer stays in logical order; each paragraph is reordered at render
  time with the Unicode Bidirectional Algorithm, with Arabic contextual
  shaping, lam-alef ligatures, and bracket mirroring.
* All six presentation modes from the recommendation are supported:
  implicit/explicit, fixed LTR/RTL, and autodetection from the first strong
  character. The default (implicit + autodetect + LTR fallback) renders RTL
  text correctly out of the box and leaves LTR output unchanged.
* Terminal applications control the behavior with the standard sequences:
  BDSM (`CSI 8 h/l`), SCP (`CSI Ps SP k`), and DEC private modes 2501
  (autodetection), 2500 (box-drawing mirroring), and 1243 (arrow-key
  swapping), including DECRQM queries and XTSAVE/XTRESTORE.
* Embedders can set the initial state through `TerminalOptions`
  (`initialBidiState`, `initialBidiArrowKeySwap`, `maximumBidiParagraphRows`),
  inspect it via `Terminal.currentBidiState`, and opt a view out entirely
  with `TerminalView.bidiHostPolicy = .legacyLeftToRight`.

The details are in the [BiDi
documentation](https://migueldeicaza.github.io/SwiftTerm/documentation/swiftterm/bidi).

## BiDi visual test harness

The [SwiftTerm BiDi harness](Tools/BidiHarness/README.md) is an AppKit app for
visual BiDi tests. It shows SwiftTerm beside a WebKit reference. Its scenarios
cover paragraph reflow, terminal modes, reset behavior, box mirroring,
combining marks, selection, cursor movement, and scrollback.

Run it from the repository root:

```sh
Tools/BidiHarness/Scripts/run-harness.sh --artifacts /tmp/bidi-artifacts
```

Use the controls in the app to select a scenario, move through its steps,
resize the terminal, scroll, change the renderer, and save a capture. The app
also has a local control socket for repeatable test runs. See the harness README
for the control commands, Xcode instructions, artifact paths, and the macOS
permission that Metal window capture needs.

Screenshots
===========

24 Bit Color 

<img width="1246" alt="24 bit color" src="https://user-images.githubusercontent.com/36863/79060395-82181400-7c52-11ea-8f48-cd02323a8284.png">

Midnight Commander

<img width="969" alt="Screen Shot 2020-04-12 at 12 17 49 AM" src="https://user-images.githubusercontent.com/36863/79060466-49c50580-7c53-11ea-8514-bb4a31359662.png">

Solid UTF-8 support, excellent rendering:
<img width="799" alt="Screen Shot 2020-04-22 at 11 25 30 PM" src="https://user-images.githubusercontent.com/36863/80055786-95e43580-84f0-11ea-86dd-8dfb7f062b39.png">

<img width="799" alt="Screen Shot 2020-04-22 at 11 25 24 PM" src="https://user-images.githubusercontent.com/36863/80055792-9977bc80-84f0-11ea-8cac-735d4a516a80.png">

Supports hyperlinks emitted by modern apps:

<img width="674" alt="image" src="https://user-images.githubusercontent.com/36863/80055972-0b500600-84f1-11ea-9c57-41cadce67162.png">

iOS support:

<img width="981" alt="image" src="https://user-images.githubusercontent.com/36863/80056069-54a05580-84f1-11ea-8597-5a227c9c64a7.png">

Sixel support:

<img width="770" alt="image" src="https://user-images.githubusercontent.com/36863/115647346-97a62c00-a2f1-11eb-929a-f9d942cc0c09.png">

<img width="568" alt="image" src="https://user-images.githubusercontent.com/36863/115647706-4e0a1100-a2f2-11eb-9bba-2a82503bca33.png">


Resources 
========= 

* [Digital's VT100 User Guide](https://geoffg.net/Downloads/Terminal/VT100_User_Guide.pdf)
* [Terminal Guide](https://terminalguide.namepad.de) - very nice and visual, but not normative
* [Xterm Control Sequences](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking)
* [VT510 Video Terminal Programmer Information](https://vt100.net/docs/vt510-rm/contents.html])

Additional and useful documents:
* [VT330/VT340 Programmer Reference Manual Volume 2: Graphics Programming](https://vt100.net/docs/vt3xx-gp/contents.html)
* [A parser for DEC’s ANSI-compatible video terminals](https://vt100.net/emu/dec_ansi_parser)
* [Codes and Standards](https://vt100.net/emu/)
* [Linux Console Docs](http://man7.org/linux/man-pages/man4/console_codes.4.html) they are a subset of vt100, but often simple to follow.
* [Sixel Graphics](https://github.com/saitoha/libsixel)

Test suites:
* [VTTest](https://invisible-island.net/vttest/) - old, but still good
* [EscTest](https://gitlab.freedesktop.org/terminal-wg/esctest) - fantastic: George Nachman, the author of iTerm, created this test suite, and it became a FreeDesktop standard.  Since then, Thomas E. Dickey, the xterm maintainer and maintainer of many text apps has contributed to this effort.

# Authors

* Thanks go to the [xterm.js](https://xtermjs.org/) developers that originally wrote a terminal emulator
that was licensed under a license that allowed for maximum reuse.   
* [Marcin Krzyzanowski](https://krzyzanowskim.com) who masterfully improved and curated the rendering engine on AppKit/CoreText to be the glorious renderer that it is today - and for his contributions to the rendering engine
* Greg Munn that did a lot of work in XtermSharp to support the needs of Visual Studio for
Mac
* [Anders Borum](https://github.com/palmin) has contributed reliability fixes, the sixel parser and changes required to put SwiftTerm to use in production.
* [Miguel de Icaza](https://tirania.org/) -me- who have been looking for an excuse to write some Swift code.
