Skip to content

heejinnn/TerminalKit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

13 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

TerminalKit

Swift Platform License

⚠️ 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.

πŸ›  Tech Stack

  • 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

✨ Features

  • βœ… 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

πŸ“¦ Installation

Swift Package Manager

Add the following to your Package.swift:

dependencies: [
    .package(url: "https://github.com/yourusername/TerminalKit.git", from: "1.0.0")
]

Or via Xcode:

  1. File > Add Packages...
  2. Enter: https://github.com/heejinnn/TerminalKit.git
  3. Add Package

πŸš€ Quick Start

Basic Usage

import SwiftUI
import TerminalKit

struct ContentView: View {
    var body: some View {
        TerminalView()
            .frame(width: 800, height: 600)
    }
}

Set Working Directory

TerminalView(
    configuration: .init(
        workingDirectory: URL(fileURLWithPath: "/Users/yourname/projects")
    )
)

Auto-Execute Command

TerminalView(
    configuration: .init(
        autoExecuteCommand: "ls -la",
        autoExecuteDelay: 500_000_000 // 0.5 seconds
    )
)

Handle Process Events

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)
    }
}

βš™οΈ Configuration

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)

πŸ“š Architecture

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

🎨 Customization Examples

Dark Theme

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)
    )
)

Running Claude Code

TerminalView(
    configuration: .init(
        workingDirectory: projectDirectory,
        autoExecuteCommand: "claude --dangerously-skip-permissions"
    )
)

πŸ“– Advanced Usage

Sending Commands Programmatically

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) {}
}

πŸ› Troubleshooting

Korean/CJK characters render incorrectly

Ensure LANG and LC_ALL are set to UTF-8. TerminalKit defaults to en_US.UTF-8.

Colors not displaying correctly

Check if the environment variable COLORTERM=truecolor is set. TerminalKit sets it automatically.

Process won't start

Make sure the shell path is valid. Default is /bin/zsh.

πŸ“§ Contact

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages