VT100/Xterm Terminal emulator in Swift

Overview

Swift

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.

Check the API Documentation

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 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 the sample happens to be hardcoded to my home machine, you can change that in the source code.

Companion App 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.

This is a port of my original XtermSharp, which was itself based on xterm.js. 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.

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)
  • Reusable and pluggable engine allows multiple user interfaces to be built on top of it.
  • Selection engine (with macOS support in the view)
  • Supports colors (ANSI, 256, TrueColor)
  • Supports mouse events
  • Supports terminal resizing operations (controlled by remote host, or locally)
  • Hyperlinks in terminal output
  • AppKit, UIKit front-ends; ncruses front-end provided separately
  • Local process and SSH connection support (some assembly required for the last one)
  • Proper CoreText rendering can munch through the hardened Unicode test suites.
  • Sixel graphics (Use img2sixel to test)
  • iTerm2-style graphic rendering (Use imgcat to test)
  • Fuzzed and abused
  • Seems pretty fast to me

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 is a reusable NSView control that can be connected to any source by implementing the TerminalViewDelegate.
I anticipate that a common scenario will be to host a local Unix command, so I have included 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 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.

Using SSH

The core library currently does not provide a convenient way to connect to SSH, purely to avoid the additional dependency. But this git module references a module that pulls a precompiled SSH client (Frugghi's SwiftSH), along with a UIKitSsshTerminalView in the iOS sample that that connects the TerminalView for iOS to an SSH connection.

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 - but be warned that the test suite expects the directory esctest to be checked out to run. You can see how I run these on GitHub actions in the file .github/workflows/swift.yml if you want to do this locally.

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

Pending Work

GitHub issues has a list of desired features and enhancements

Long Term Plans

In the longer term, I want to also add a tvOS UIView, a SwiftGtk front-end for Linux.

Screenshots

24 Bit Color

24 bit color

Midnight Commander

Screen Shot 2020-04-12 at 12 17 49 AM

Solid UTF-8 support, excellent rendering: Screen Shot 2020-04-22 at 11 25 30 PM

Screen Shot 2020-04-22 at 11 25 24 PM

Supports hyperlinks emitted by modern apps:

image

iOS support:

image

Sixel support:

image

image

Resources

Additional and useful documents:

Test suites:

  • VTTest - old, but still good
  • 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 developers that originally wrote a terminal emulator that was licensed under a license that allowed for maximum reuse.
  • Marcin Krzyzanowski 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 has contributed reliability fixes, the sixel parser and changes required to put SwiftTerm to use in production.
  • Miguel de Icaza -me- who have been looking for an excuse to write some Swift code.
Comments
  • Weird characters when connected to PowerShell via ssh

    Weird characters when connected to PowerShell via ssh

    I am using your iOS terminal to communicate with BASH and Powershell remote servers. When I connect to a BASH session, everything works as expected. But when I connect to a PowerShell session, every time I type something, only garbage characters are displayed. Yet when I press RETURN, the correct command executes. For instance:

    I connect to a macOS 11 machine running PowerShell as its default shell. I get:

    PowerShell 7.1.3
    Copyright © Microsoft Corporation.
    
    https://aka.ms/powershell
    Type 'help' to get help.
    
    PS /Users/frios>
    

    All is good until I start typing. I type d and I get d$<5> then I type i and the d disappears and I get $<$<5> then I type r and I get $<5$<5>

    If I then hit return I get the proper directory output on the screen but if the screen is full, the cursor jumps to mid screen.

    Anyone seen this type of behavior before?

    opened by frios 13
  • changes made for Secure ShellFish

    changes made for Secure ShellFish

    The work in these commits is covered by the MIT license and I hope it can be of some use even if a lot is about extracting lines in a scroll-invariant way.

    opened by palmin 12
  • Multi-threading Terminal

    Multi-threading Terminal

    The UI views could run async from the actual engine.

    While currently the engines already do the sort of frame-based rendering, there are situations where we can still be processing too much data in parse without triggering an update to the UI.

    So I would like to fully move to frame-based rendering to be independent of the parsing happening in the background. For this, it would be important to add a modicum of synchronization, but that can happen entirely within the parse method, as no mutation would take place if that method suspends execution if the UI needs to update the display.

    opened by migueldeicaza 8
  • Incorrect Emacs rendering in horizontal split

    Incorrect Emacs rendering in horizontal split

    I'm having pretty great success with SwiftTerm but there is one app that is not rendered properly: when I run Emacs within SwiftTerm, it's layout is a bit off when I M-x help in a wide terminal so that you get a side by side split.

    I've set the terminal to xterm-256color and xterm but that doesn't seem to make a difference.

    The only hint I have is that SwiftTerm prints

    Info: Unhandled Window command: [22, 0, 0]
    Info: Unhandled Window command: [23, 0, 0]
    

    What is the best place to lookup these codes? Maybe handling these commands is this is an improvement I can contribute?

    Update: Note that the Unhandled Window command may be a red herring - I don't think it is happening during rendering. See comments.

    Screen Shot 2021-04-14 at 4 57 56 PM bug 
    opened by st3fan 7
  • Hack for scrolling

    Hack for scrolling

    I'm not sure this is the correct way to do this but here it is.

    Currently UIScrollView does not work. And I don't think there is a possible way for it to work. The gestureRecognizers added will conflict with those inside UIScrollView, making UIScrollView totally unusable.

    So I just make it plain UIView and put together scrolling logic. This way there'll be no fancy scrollbar or bouncing, but the scrolling will work.

    opened by skyline75489 6
  • terminal view options

    terminal view options

    Refactor terminal view options into single property: options. This property is intended to be modified by the user, and the view should apply the changes.

    Put this snippet in TerminalView.setup() and see how it change colors:

    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) {
        let o = Options(font: Options.default.font, colors: Options.Colors(useSystemColors: true))
        self.options = o
    }
    

    color-change

    opened by krzyzanowskim 6
  • No SPM version numbers?

    No SPM version numbers?

    I am trying to add this dependency through Xcode 11, but when I input the URL, there is no version information for the rules. Where do i get that? Pardon my naivte

    opened by SAPIENTechnologies 5
  • Rework glyphs drawing. Use fixed font size measurements.

    Rework glyphs drawing. Use fixed font size measurements.

    Fixes #67

    • [x] revert to fixed height/width for size, yet still draw glyphs that cross the lines
    • [x] disable selection view (again) and fixes performance issue when updating selection
    • [x] update caret view position along the lines
    • [x] draw underline
    • strikethrough doesn't (never did)
    opened by krzyzanowskim 5
  • Mac: Improve fonts metrics and line drawing

    Mac: Improve fonts metrics and line drawing

    Fixes #54

    In this PR:

    • Selection highlight in pair with displayed glyphs

      • before Screenshot 2020-04-09 at 00 58 04

      • after Screenshot 2020-04-09 at 02 07 06

    • dynamic line-height support

      • before Screenshot 2020-04-10 at 12 53 52

      • after Screenshot 2020-04-11 at 21 19 04

    • Improved support for font metrics. Calculate lines positions based on used font (no more magic offset values)

    • Sharp background frame - fullBackgroundColor attribute

      • before 1
      • after 2
    opened by krzyzanowskim 5
  • Swift runtime failure: Double value cannot be converted to UInt16 because the result would be greater than UInt16.max

    Swift runtime failure: Double value cannot be converted to UInt16 because the result would be greater than UInt16.max

    This line: https://github.com/migueldeicaza/SwiftTerm/blob/main/Sources/SwiftTerm/iOS/iOSExtensions.swift#L15

    causes a crash sometimes on iOS 14 with the error: Swift runtime failure: Double value cannot be converted to UInt16 because the result would be greater than UInt16.max

    It seems to be a precision issue:

    (lldb) p red
    (CoreFoundation.CGFloat) $R3 = (native = 0.99990183115005493)
    (lldb) p green
    (CoreFoundation.CGFloat) $R4 = (native = 1.0000687837600708)
    (lldb) p blue
    (CoreFoundation.CGFloat) $R5 = (native = 0.99987989664077759)
    
    opened by osy 4
  • shared and open are unavailable build 1.0.7

    shared and open are unavailable build 1.0.7

    I just updated to the latest build (I assume its 1.0.7) and am receiving the following error messages when building

    'shared' is unavailable in application extensions for iOS: Use view controller based solutions where appropriate instead.
    
    and 
    
    'open(_:options:completionHandler:)' is unavailable in application extensions for iOS
    

    at the following location

        public func requestOpenLink (source: TerminalView, link: String, params: [String:String])
        {
            if let fixedup = link.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
                if let url = NSURLComponents(string: fixedup) {
                    if let nested = url.url {
                        UIApplication.shared.open (nested)
                    }
                }
            }
        }
    

    at the line UIApplication.shared.open(nested)

    This is an iOS app.

    opened by frios 4
  • Crash on reverseIndex

    Crash on reverseIndex

    I caught the issue in the wild, the crash is:

        frame #3: 0x000000019475f134 libswiftCore.dylib`Swift._assertionFailure(_: Swift.StaticString, _: Swift.String, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 652
        frame #4: 0x0000000102b7f84c LaTerminal`CircularList.shiftElements(start=47, count=3, offset=1, self=0x0000000280bf5680) at CircularList.swift:169:9
      * frame #5: 0x0000000102beebe4 LaTerminal`Terminal.reverseIndex(self=0x00000001043e4ed0) at Terminal.swift:4937:26
        frame #6: 0x0000000102bbeb98 LaTerminal`closure #84 in Terminal.configureParser(collect=0 values, flag=77, self=0x00000001043e4ed0) at Terminal.swift:868:76
    

    The issue is that shiftElements is being called with start=47, but the buffer itself only has 42 lines. The 47 is a combination of buffer.y = 21 and buffer.base = 26. And also notice that buffer.y = buffer.scrollTop which is why this path is triggered at all, originMode=false, usingMargins() = false

    I was running top, and messing up the display with debug output from a background process, and I had refreshed it a few times, and I had just attempted to go to the background with control-z

    The data was: [0] = "\r" [1] = "\u{1b}" [2] = "[" [3] = "3" [4] = "4" [5] = "d" [6] = "\u{1b}" [7] = "[" [8] = "L" [9] = "\u{1b}" [10] = "[" [11] = "2" [12] = "2" [13] = ";" [14] = "2" [15] = "5" [16] = "r" [17] = "\u{1b}" [18] = "[" [19] = "2" [20] = "2" [21] = ";" [22] = "1" [23] = "H" [24] = "\u{1b}" [25] = "M" }

    Cursor Vertical Absolute Position 34 Insert Line Set Top and Bottom Margin to 22;25 (sets buffer.scrollBottom = 24, buffer.scrollTop=21) Set Cursor Position 22;1 Reverse Index

    Most likely, what we have here are two different buffers in action.

    opened by migueldeicaza 0
  • Feature: option-tap to move the cursor to that location

    Feature: option-tap to move the cursor to that location

    This allows option-tap to send cursor arrow movements to reach a destination, like Terminal.app does.

    In application mode, this could send the sequence of cursor movements to get to the target location, in regular mode, it should probably only do left/right, as up/down navigates a command line history.

    opened by migueldeicaza 0
  • Terminal Rendering Defect

    Terminal Rendering Defect

    Hi,

    I work on CodeEdit and there's a terminal rendering defect. We use SwiftTerm as the package for our terminal emulator

    Click here to see the issue and please comment on it as soon as you can.

    opened by ghost 9
Owner
Miguel de Icaza
Miguel de Icaza
NES - NES emulator, written in Swift

Swift NES NES emulator, written in Swift. NESKit: Emulator core. License GPL v3.

Swift Simpers 0 Jan 10, 2022
ZX Spectrum emulator for macOs. Retro Virtual Machine

Retro Virtual Machine 1.1.x This is the code for version 1.1.x of my emulator for the ZX Spectrum, Retro Virtual Machine. The current version (v2.0.7)

Juan Carlos González Amestoy 9 Dec 31, 2022
ActiveGS, Apple 2/2GS emulator for iOS

Activegs IOS Source code for the complete ActiveGS iOS application Installation Process (easier than it sounds!) Download Xcode 7 https://itunes.apple

Olivier Goguel 69 Jan 6, 2023
A Gameboy Emulator for the Apple Watch

A Gameboy Emulator for the Apple Watch. Interested in how this was made? Check out the write-up here Installation Giovanni uses git submodules for it'

Gabriel O'Flaherty-Chan 894 Dec 12, 2022
Terminal TODO application in Swift with ncurses.

stodo Terminal TODO application in Swift with ncurses. Development streamed live

Alejandro Martínez 3 Aug 3, 2022
Mac-asksec - Test Mac Permissions from the Terminal

asksec A simple CLI to test permissions from any macOS terminal app. Building ru

Christian Zangl 1 Jan 18, 2022
Swift Playgrounds desenvolvido para o Swift Student Challenge da WWDC 21

Pile Up Swift Playgrounds desenvolvido para o Swift Student Challenge da WWDC 21 Descrição Pile Up é um quebra cabeça cujo objetivo é empilhar os bloc

Beatriz Sato 3 Jun 5, 2021
Swift Language Weather is an iOS weather app developed in Swift

Swift Language Weather SwiftWeather has renamed to Swift Language Weather. Because this repo is ranked number one in Google when we search "Swift Weat

Jake Lin 5.2k Jan 7, 2023
Todo-app-swift- - A Todo Lists app built using swift

TODO-Lists App Available on the App Store What is this? This is a todo app I mad

Kushal Shingote 3 Feb 20, 2022
Matrix-rust-components-swift - Swift package providing components from the matrix-rust-sdk

Swift package for Matrix Rust components This repository is a Swift Package for

matrix.org 10 Nov 4, 2022
A small SwiftUI based chat client for IRC, using swift-nio-irc

NeoIRC A simple Internet Relay Chat client implemented using SwiftNIO and SwiftUI. Inspired by: For maximum NIO someone (I’m tempted) should adopt NIO

The Noze Consortium 18 Jun 22, 2022
🎮 Favorite your games filter and see the upcoming games and ! Swift + Combine = 💜 Hacktoberfest 🎃 👾

✨ Revill is App to list games and search best games ✨ Design in Swift UI + Combine ✨ The idea is develop this app in Hacktober Fest Expected To Do Des

Vinicius Mangueira 21 Dec 17, 2022
🎲 100% SwiftUI 2.0, classic 2048 game [SwiftUI 2.0, iOS 14.0+, iPadOS 14.0+, macOS 11.0+, Swift 5.3].

swiftui-2048 If you like the project, please give it a star ⭐ It will show the creator your appreciation and help others to discover the repo. ✍️ Abou

Astemir Eleev 174 Dec 17, 2022
My submission for WWDC'21 Swift Student Challenge which was selected.

Double Spending This is my submission for Swift Student Challenge - WWDC2021. This playgrounds aims to teach you basics of Double Spending Attack. Thi

Garima Bothra 18 Jul 7, 2022
My WWDC21 Swift Student Challenge Submission

Swift3D A 3D framework for everyone. I love SwiftUI. I have been using it constantly since it came out in 2019 and its power and ease of use are what

Christian 191 Sep 23, 2022
A swift client library for GoTrue.

gotrue-swift Swift client for the GoTrue API. Using The usage should be the same as gotrue-js except: Oauth2: signIn with oauth2 provider only return

Supabase 23 Jan 7, 2023
My project for WWDC21 Swift Student Challenge!

Art with Times Table An interactive book that shows the figures that are generated when times tables are drawn inside a circle. This project was appro

Lucas Claro 10 Dec 30, 2022
Examples for Swift Algorithms visualized in SwiftUI.

Examples for Swift Algorithms Examples for Swift Algorithms visualized in SwiftUI. There are many more algorithms in the package - feel free to contri

Ralf Ebert 5 Oct 22, 2022
WeChat-like Moments App implemented using Swift 5.5 and SwiftUI

Moments SwiftUI This is a re-implementation of Moments App using Swift 5.5 and SwiftUI. Features: Aysnc/Await Actor AysncImage MVVM BFF Screenshot Als

Jake Lin 46 Jan 5, 2023