β οΈ macOS-only library
TerminalKit is a native terminal emulator library built for macOS. Powered by SwiftUI and AppKit, it allows you to easily integrate a VT100/ANSI-compatible terminal into your macOS applications.
- Language: Swift 5.9+
- Frameworks: AppKit (macOS), SwiftUI
- Platform: macOS 13.0+
- Process Management: PTY (Pseudo-Terminal)
- Concurrency: Swift Concurrency (async/await, @MainActor)
- Terminal Standards: VT100, xterm-256color
- β VT100/ANSI Compatible β Supports standard terminal escape sequences
- β Native SwiftUI β Simple to use as a SwiftUI View
- β Full Korean & CJK Support β Proper rendering and input for CJK characters
- β 256-color & True Color β ANSI 256 colors + RGB True Color support
- β Scrollback Buffer β Up to 10,000 lines of history
- β PTY-based β Reliable communication with shell processes
- β Highly Customizable β Fonts, colors, auto-run commands, and more
Add the following to your Package.swift:
dependencies: [
.package(url: "https://github.com/yourusername/TerminalKit.git", from: "1.0.0")
]Or via Xcode:
- File > Add Packages...
- Enter:
https://github.com/heejinnn/TerminalKit.git - Add Package
import SwiftUI
import TerminalKit
struct ContentView: View {
var body: some View {
TerminalView()
.frame(width: 800, height: 600)
}
}TerminalView(
configuration: .init(
workingDirectory: URL(fileURLWithPath: "/Users/yourname/projects")
)
)TerminalView(
configuration: .init(
autoExecuteCommand: "ls -la",
autoExecuteDelay: 500_000_000 // 0.5 seconds
)
)class TerminalHandler: TerminalKitDelegate {
func terminalDidExit(exitCode: Int32?) {
print("Terminal exited with code: \(exitCode ?? -1)")
}
func terminalDidChangeState(isRunning: Bool) {
print("Terminal is \(isRunning ? "running" : "stopped")")
}
}
struct ContentView: View {
let handler = TerminalHandler()
var body: some View {
TerminalView(delegate: handler)
}
}You can customize the terminal using TerminalConfiguration:
let config = TerminalConfiguration(
executable: "/bin/zsh",
args: ["-l"],
workingDirectory: myProjectURL,
autoExecuteCommand: "npm start",
scrollbackLines: 10_000,
fontSize: 14,
defaultForegroundColor: .white,
defaultBackgroundColor: .black
)
TerminalView(configuration: config)TerminalKit/
βββ Core/
β βββ Terminal.swift # VT100/ANSI parser
β βββ Buffer.swift # Terminal buffer
β βββ CharData.swift # Character data structure
β βββ LocalProcess.swift # PTY process management
βββ Views/
β βββ TerminalRendererView.swift # NSView-based renderer
β βββ ProcessTerminalView.swift # Integrated process view
βββ SwiftUI/
βββ TerminalView.swift # SwiftUI interface
TerminalView(
configuration: .init(
defaultForegroundColor: NSColor(white: 0.9, alpha: 1.0),
defaultBackgroundColor: NSColor(red: 0.1, green: 0.1, blue: 0.12, alpha: 1.0)
)
)TerminalView(
configuration: .init(
workingDirectory: projectDirectory,
autoExecuteCommand: "claude --dangerously-skip-permissions"
)
)When you need direct access to NSView:
struct MyTerminalView: NSViewRepresentable {
func makeNSView(context: Context) -> ProcessTerminalView {
let terminal = ProcessTerminalView(frame: .zero)
terminal.startShell(executable: "/bin/zsh", args: ["-l"])
// Send command
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
let command = "echo 'Hello, Terminal!'\n"
terminal.terminal.delegate?.send(Array(command.utf8))
}
return terminal
}
func updateNSView(_ nsView: ProcessTerminalView, context: Context) {}
}Ensure LANG and LC_ALL are set to UTF-8. TerminalKit defaults to en_US.UTF-8.
Check if the environment variable COLORTERM=truecolor is set. TerminalKit sets it automatically.
Make sure the shell path is valid. Default is /bin/zsh.
- Issues: GitHub Issues
- Discussions: GitHub Discussions