mirror of
https://github.com/phranck/TUIkit.git
synced 2026-06-20 09:54:37 +00:00
Merge pull request #19 from phranck/rename/tuikit-to-tuikit
Chore: Rename TUIKit to TUIkit
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 248 KiB |
@@ -77,7 +77,7 @@ jobs:
|
||||
run: |
|
||||
swift package --allow-writing-to-directory docs-output \
|
||||
generate-documentation \
|
||||
--target TUIKit \
|
||||
--target TUIkit \
|
||||
--output-path docs-output \
|
||||
--transform-for-static-hosting
|
||||
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
<meta http-equiv="refresh" content="0; url=/documentation/tuikit" />
|
||||
</head>
|
||||
<body>
|
||||
<a href="/documentation/tuikit">Redirecting to TUIKit Documentation...</a>
|
||||
<a href="/documentation/tuikit">Redirecting to TUIkit Documentation...</a>
|
||||
</body>
|
||||
</html>
|
||||
HTMLEOF
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# SwiftLint Configuration for TUIKit
|
||||
# SwiftLint Configuration for TUIkit
|
||||
|
||||
# Only lint project sources (not build artifacts or dependencies)
|
||||
included:
|
||||
|
||||
+11
-11
@@ -17,23 +17,23 @@
|
||||
- **Aspect Ratio**: 16:9 (landscape)
|
||||
- **Recommended Size**: 1000×560px or larger (up to 2000px width for retina)
|
||||
- **Format**: PNG, JPG, or WebP (lossless recommended)
|
||||
- **Content**: Screenshot/demo of TUIKit in action
|
||||
- **Content**: Screenshot/demo of TUIkit in action
|
||||
- Terminal UI showing an interactive application
|
||||
- Nice visualization of TUIKit components
|
||||
- Nice visualization of TUIkit components
|
||||
- Colors: Green (#10b981), dark background (#030712)
|
||||
- Examples: Menu selection, modal dialogs, text input, etc.
|
||||
|
||||
**HTML Location**: `docs/index.html` - Line ~555-591
|
||||
```html
|
||||
<div class="hero-video">
|
||||
<!-- Replace this SVG with: <img src="images/hero-demo.png" alt="TUIKit Demo"> -->
|
||||
<!-- Replace this SVG with: <img src="images/hero-demo.png" alt="TUIkit Demo"> -->
|
||||
<svg>...</svg>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Placeholder Preview**:
|
||||
- Terminal window with green border
|
||||
- Shows TUIKit menu example
|
||||
- Shows TUIkit menu example
|
||||
- Command: `$ swift run MyApp`
|
||||
- Interactive menu selection
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
- **Aspect Ratio**: 16:9 or Square (1:1)
|
||||
- **Recommended Size**: 600×400px (or 600×600px)
|
||||
- **Format**: PNG, JPG, or WebP
|
||||
- **Content**: Professional screenshot of TUIKit features
|
||||
- Shows real TUIKit app with actual components
|
||||
- **Content**: Professional screenshot of TUIkit features
|
||||
- Shows real TUIkit app with actual components
|
||||
- Terminal UI showcase with multiple features
|
||||
- Examples of: Menu, Button, Text, Panel, Dialog, etc.
|
||||
- Color scheme: Green theme with different appearance styles
|
||||
@@ -59,13 +59,13 @@
|
||||
**HTML Location**: `docs/index.html` - Line ~641-685
|
||||
```html
|
||||
<div class="advanced-image">
|
||||
<!-- Replace this SVG with: <img src="images/advanced-demo.png" alt="Advanced TUIKit Features"> -->
|
||||
<!-- Replace this SVG with: <img src="images/advanced-demo.png" alt="Advanced TUIkit Features"> -->
|
||||
<svg>...</svg>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Placeholder Preview**:
|
||||
- Advanced TUIKit Demo terminal window
|
||||
- Advanced TUIkit Demo terminal window
|
||||
- Two feature boxes: "Theme: Green Phosphor" + "Components"
|
||||
- Live example: Interactive menu with selection
|
||||
|
||||
@@ -157,7 +157,7 @@ Find this in `docs/index.html` around line 554:
|
||||
Replace with:
|
||||
```html
|
||||
<div class="hero-video">
|
||||
<img src="images/hero-demo.png" alt="TUIKit Demo Application" style="width: 100%; height: 100%; object-fit: cover; border-radius: 1rem;">
|
||||
<img src="images/hero-demo.png" alt="TUIkit Demo Application" style="width: 100%; height: 100%; object-fit: cover; border-radius: 1rem;">
|
||||
</div>
|
||||
```
|
||||
|
||||
@@ -172,7 +172,7 @@ Find this in `docs/index.html` around line 641:
|
||||
Replace with:
|
||||
```html
|
||||
<div class="advanced-image">
|
||||
<img src="images/advanced-demo.png" alt="Advanced TUIKit Features" style="width: 100%; height: 100%; object-fit: cover; border-radius: 1rem;">
|
||||
<img src="images/advanced-demo.png" alt="Advanced TUIkit Features" style="width: 100%; height: 100%; object-fit: cover; border-radius: 1rem;">
|
||||
</div>
|
||||
```
|
||||
|
||||
@@ -193,7 +193,7 @@ With:
|
||||
|
||||
All current images are high-quality SVG placeholders that:
|
||||
- ✅ Match the dark theme and color scheme
|
||||
- ✅ Show relevant TUIKit UI examples
|
||||
- ✅ Show relevant TUIkit UI examples
|
||||
- ✅ Are vector-based (scale perfectly)
|
||||
- ✅ Look professional on their own
|
||||
- ✅ Are easy to replace
|
||||
|
||||
+10
-10
@@ -14,7 +14,7 @@ let swiftLintPlugin: [Target.PluginUsage] = enableSwiftLint
|
||||
: []
|
||||
|
||||
let package = Package(
|
||||
name: "TUIKit",
|
||||
name: "TUIkit",
|
||||
// Minimum deployment targets for Apple platforms
|
||||
// Linux is automatically supported (no platform specification needed)
|
||||
platforms: [
|
||||
@@ -22,12 +22,12 @@ let package = Package(
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "TUIKit",
|
||||
targets: ["TUIKit"]
|
||||
name: "TUIkit",
|
||||
targets: ["TUIkit"]
|
||||
),
|
||||
.executable(
|
||||
name: "TUIKitExample",
|
||||
targets: ["TUIKitExample"]
|
||||
name: "TUIkitExample",
|
||||
targets: ["TUIkitExample"]
|
||||
),
|
||||
],
|
||||
dependencies: [
|
||||
@@ -36,17 +36,17 @@ let package = Package(
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "TUIKit",
|
||||
name: "TUIkit",
|
||||
plugins: swiftLintPlugin
|
||||
),
|
||||
.executableTarget(
|
||||
name: "TUIKitExample",
|
||||
dependencies: ["TUIKit"],
|
||||
name: "TUIkitExample",
|
||||
dependencies: ["TUIkit"],
|
||||
plugins: swiftLintPlugin
|
||||
),
|
||||
.testTarget(
|
||||
name: "TUIKitTests",
|
||||
dependencies: ["TUIKit"]
|
||||
name: "TUIkitTests",
|
||||
dependencies: ["TUIkit"]
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
[](https://github.com/phranck/TUIKit/actions/workflows/ci.yml)
|
||||
[](https://github.com/phranck/TUIkit/actions/workflows/ci.yml)
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
# TUIKit
|
||||
# TUIkit
|
||||
|
||||
A SwiftUI-like framework for building Terminal User Interfaces in Swift — no ncurses, no C dependencies, just pure Swift.
|
||||
|
||||
## What is this?
|
||||
|
||||
TUIKit lets you build TUI apps using the same declarative syntax you already know from SwiftUI. Define your UI with `View`, compose views with `VStack`, `HStack`, and `ZStack`, style text with modifiers like `.bold()` and `.foregroundColor(.red)`, and run it all in your terminal.
|
||||
TUIkit lets you build TUI apps using the same declarative syntax you already know from SwiftUI. Define your UI with `View`, compose views with `VStack`, `HStack`, and `ZStack`, style text with modifiers like `.bold()` and `.foregroundColor(.red)`, and run it all in your terminal.
|
||||
|
||||
```swift
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
@main
|
||||
struct MyApp: App {
|
||||
@@ -32,7 +31,7 @@ struct ContentView: View {
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
Text("Hello, TUIKit!")
|
||||
Text("Hello, TUIkit!")
|
||||
.bold()
|
||||
.foregroundColor(.cyan)
|
||||
|
||||
@@ -85,18 +84,18 @@ struct ContentView: View {
|
||||
## Run the Example App
|
||||
|
||||
```bash
|
||||
swift run TUIKitExample
|
||||
swift run TUIkitExample
|
||||
```
|
||||
|
||||
Press `q` or `ESC` to exit.
|
||||
|
||||
## Installation
|
||||
|
||||
Add TUIKit to your `Package.swift`:
|
||||
Add TUIkit to your `Package.swift`:
|
||||
|
||||
```swift
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/phranck/TUIKit.git", branch: "main")
|
||||
.package(url: "https://github.com/phranck/TUIkit.git", branch: "main")
|
||||
]
|
||||
```
|
||||
|
||||
@@ -105,13 +104,13 @@ Then add it to your target:
|
||||
```swift
|
||||
.target(
|
||||
name: "YourApp",
|
||||
dependencies: ["TUIKit"]
|
||||
dependencies: ["TUIkit"]
|
||||
)
|
||||
```
|
||||
|
||||
## Theming
|
||||
|
||||
TUIKit includes 8 predefined themes inspired by classic terminals:
|
||||
TUIkit includes 8 predefined themes inspired by classic terminals:
|
||||
|
||||
```swift
|
||||
@main
|
||||
@@ -146,16 +145,16 @@ Available themes:
|
||||
|
||||
```
|
||||
Sources/
|
||||
├── TUIKit/
|
||||
├── TUIkit/
|
||||
│ ├── App/ App, Scene, WindowGroup
|
||||
│ ├── Core/ View, ViewBuilder, State, Environment, Color, Theme
|
||||
│ ├── Modifiers/ Border, Frame, Padding, Overlay, Lifecycle
|
||||
│ ├── Rendering/ Terminal, ANSIRenderer, ViewRenderer, FrameBuffer
|
||||
│ └── Views/ Text, Stacks, Button, Menu, Alert, StatusBar, ...
|
||||
└── TUIKitExample/ Example app (executable target)
|
||||
└── TUIkitExample/ Example app (executable target)
|
||||
|
||||
Tests/
|
||||
└── TUIKitTests/ 181 tests across 27 test suites
|
||||
└── TUIkitTests/ 181 tests across 27 test suites
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
//
|
||||
// App.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// The base protocol for TUIKit applications.
|
||||
// The base protocol for TUIkit applications.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: - App Protocol
|
||||
|
||||
/// The base protocol for TUIKit applications.
|
||||
/// The base protocol for TUIkit applications.
|
||||
///
|
||||
/// `App` is the entry point for every TUIKit application,
|
||||
/// `App` is the entry point for every TUIkit application,
|
||||
/// similar to `App` in SwiftUI.
|
||||
///
|
||||
/// # Example
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// InputHandler.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Dispatches key events through a 3-layer priority chain.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// RenderLoop.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Manages the rendering pipeline: scene rendering, environment
|
||||
// assembly, and status bar output.
|
||||
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// Scene.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Scene types for TUIKit applications.
|
||||
// Scene types for TUIkit applications.
|
||||
//
|
||||
|
||||
/// The base protocol for scenes in TUIKit.
|
||||
/// The base protocol for scenes in TUIkit.
|
||||
///
|
||||
/// A scene represents a part of the app structure,
|
||||
/// typically a window or a group of views.
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// SignalManager.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Manages POSIX signal handlers for terminal resize and graceful shutdown.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// StatusBarState.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Manages the status bar state for the running application.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// AppStorage.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Persistent storage for app settings using @AppStorage property wrapper.
|
||||
//
|
||||
@@ -51,7 +51,7 @@ private func appConfigDirectory() -> URL {
|
||||
|
||||
/// A storage backend that persists data to a JSON file.
|
||||
///
|
||||
/// This is the default storage backend for TUIKit apps.
|
||||
/// This is the default storage backend for TUIkit apps.
|
||||
/// Data is stored in `$XDG_CONFIG_HOME/[appName]/settings.json`
|
||||
/// or `~/.config/[appName]/settings.json` as fallback.
|
||||
public final class JSONFileStorage: StorageBackend, @unchecked Sendable {
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Appearance.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Appearance system for consistent UI control styling.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// BorderStyle.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Border styles and character sets for TUI borders.
|
||||
//
|
||||
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// Color.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Color definitions for terminal output with ANSI escape codes.
|
||||
//
|
||||
|
||||
/// A color for use in TUIKit views.
|
||||
/// A color for use in TUIkit views.
|
||||
///
|
||||
/// `Color` represents standard ANSI colors as well as
|
||||
/// extended 256-color palette and True Color (24-bit RGB).
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Environment.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Environment system for passing values down the view hierarchy.
|
||||
// Similar to SwiftUI's @Environment property wrapper.
|
||||
@@ -209,7 +209,7 @@ extension EnvironmentModifier: Renderable {
|
||||
|
||||
// Render content with modified environment
|
||||
return EnvironmentStorage.shared.withEnvironment(modifiedEnvironment) {
|
||||
TUIKit.renderToBuffer(content, context: modifiedContext)
|
||||
TUIkit.renderToBuffer(content, context: modifiedContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Focus.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Focus management system for interactive views.
|
||||
//
|
||||
@@ -1,8 +1,8 @@
|
||||
//
|
||||
// KeyEvent.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Keyboard event handling for TUIKit.
|
||||
// Keyboard event handling for TUIkit.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Preferences.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Preferences system for bottom-up data flow (child → parent).
|
||||
// Similar to SwiftUI's PreferenceKey system.
|
||||
@@ -214,7 +214,7 @@ extension PreferenceModifier: Renderable {
|
||||
context.tuiContext.preferences.setValue(value, forKey: K.self)
|
||||
|
||||
// Render content
|
||||
return TUIKit.renderToBuffer(content, context: context)
|
||||
return TUIkit.renderToBuffer(content, context: context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ extension OnPreferenceChangeModifier: Renderable {
|
||||
prefs.push()
|
||||
|
||||
// Render content
|
||||
let buffer = TUIKit.renderToBuffer(content, context: context)
|
||||
let buffer = TUIkit.renderToBuffer(content, context: context)
|
||||
|
||||
// Pop and get collected preferences
|
||||
let preferences = prefs.pop()
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// PrimitiveViews.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Primitive view types that serve as leaves in the view tree.
|
||||
//
|
||||
@@ -1,8 +1,8 @@
|
||||
//
|
||||
// State.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// State management for TUIKit views.
|
||||
// State management for TUIkit views.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@@ -11,7 +11,7 @@ import Foundation
|
||||
|
||||
/// Global application state that triggers re-renders when modified.
|
||||
///
|
||||
/// Since TUIKit runs in a single-threaded event loop, we use a simple
|
||||
/// Since TUIkit runs in a single-threaded event loop, we use a simple
|
||||
/// observable pattern. The AppRunner subscribes to state changes and
|
||||
/// re-renders when notified.
|
||||
public final class AppState: @unchecked Sendable {
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// TUIContext.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Central dependency container replacing scattered singletons.
|
||||
// Owned by AppRunner and threaded through RenderContext.
|
||||
@@ -174,7 +174,7 @@ public final class LifecycleManager: @unchecked Sendable {
|
||||
|
||||
// MARK: - TUI Context
|
||||
|
||||
/// Central dependency container for TUIKit runtime services.
|
||||
/// Central dependency container for TUIkit runtime services.
|
||||
///
|
||||
/// `TUIContext` replaces the scattered singleton pattern by bundling all
|
||||
/// framework-internal services into a single object owned by `AppRunner`.
|
||||
@@ -197,7 +197,7 @@ public final class LifecycleManager: @unchecked Sendable {
|
||||
/// context.tuiContext.keyEventDispatcher.addHandler { event in
|
||||
/// // handle key
|
||||
/// }
|
||||
/// return TUIKit.renderToBuffer(content, context: context)
|
||||
/// return TUIkit.renderToBuffer(content, context: context)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Theme.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Palette system with full 16M color support and predefined terminal palettes.
|
||||
//
|
||||
@@ -9,10 +9,10 @@ import Foundation
|
||||
|
||||
// MARK: - Palette Protocol
|
||||
|
||||
/// A palette defines the color scheme for a TUIKit application.
|
||||
/// A palette defines the color scheme for a TUIkit application.
|
||||
///
|
||||
/// Palettes provide semantic colors that views use for consistent styling.
|
||||
/// TUIKit includes several predefined palettes inspired by classic terminals.
|
||||
/// TUIkit includes several predefined palettes inspired by classic terminals.
|
||||
///
|
||||
/// Conforms to ``Cyclable`` so it can be managed by a ``ThemeManager``.
|
||||
///
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ThemeManager.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Generic manager for cycling through items that conform to `Cyclable`.
|
||||
// Replaces the previously duplicated palette manager and appearance manager
|
||||
@@ -43,7 +43,7 @@ public protocol Cyclable: Sendable {
|
||||
/// set a specific item by reference, and apply the current selection to the
|
||||
/// environment so all views pick up the change.
|
||||
///
|
||||
/// TUIKit uses two instances:
|
||||
/// TUIkit uses two instances:
|
||||
/// - A ``PaletteManager`` for color palettes
|
||||
/// - An ``AppearanceManager`` for border-style appearances
|
||||
///
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// TupleViews.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Container type for multiple views in ViewBuilder, using Swift Parameter Packs.
|
||||
//
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// UserDefaultsStorage.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// UserDefaults-compatible storage backend for all platforms.
|
||||
//
|
||||
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// View.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// The base protocol for all TUIKit views.
|
||||
// The base protocol for all TUIkit views.
|
||||
//
|
||||
|
||||
/// The base protocol for all TUIKit views.
|
||||
/// The base protocol for all TUIkit views.
|
||||
///
|
||||
/// `View` is the central protocol in TUIKit and works similarly to `View` in SwiftUI.
|
||||
/// `View` is the central protocol in TUIkit and works similarly to `View` in SwiftUI.
|
||||
/// It defines how components declare their structure and content.
|
||||
///
|
||||
/// Every View defines a `body` composed of other Views.
|
||||
@@ -15,7 +15,7 @@
|
||||
///
|
||||
/// ## Dual Rendering System
|
||||
///
|
||||
/// TUIKit uses two rendering paths:
|
||||
/// TUIkit uses two rendering paths:
|
||||
///
|
||||
/// - **Composite views** implement `body` to compose other views.
|
||||
/// The rendering system recurses into `body` to resolve the tree.
|
||||
@@ -31,7 +31,7 @@
|
||||
/// ```swift
|
||||
/// struct MyView: View {
|
||||
/// var body: some View {
|
||||
/// Text("Hello, TUIKit!")
|
||||
/// Text("Hello, TUIkit!")
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ViewBuilder.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Result builder for declarative view composition.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ViewModifier.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// The view modifier system for transforming views.
|
||||
//
|
||||
@@ -60,7 +60,7 @@ public struct ModifiedView<Content: View, Modifier: ViewModifier>: View {
|
||||
|
||||
extension ModifiedView: Renderable {
|
||||
public func renderToBuffer(context: RenderContext) -> FrameBuffer {
|
||||
let childBuffer = TUIKit.renderToBuffer(content, context: context)
|
||||
let childBuffer = TUIkit.renderToBuffer(content, context: context)
|
||||
return modifier.modify(buffer: childBuffer, context: context)
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// PrimitiveTypes+Extensions.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Protocol conformances for standard types (Never, Optional).
|
||||
//
|
||||
@@ -38,7 +38,7 @@ extension Optional: Renderable where Wrapped: View {
|
||||
public func renderToBuffer(context: RenderContext) -> FrameBuffer {
|
||||
switch self {
|
||||
case .some(let view):
|
||||
return TUIKit.renderToBuffer(view, context: context)
|
||||
return TUIkit.renderToBuffer(view, context: context)
|
||||
case .none:
|
||||
return FrameBuffer()
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// String+ANSI.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// ANSI-aware String helpers for visible-length calculation and padding.
|
||||
//
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// View+Convenience.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Convenience view extensions: modal, asAnyView.
|
||||
//
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// View+Environment.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Environment injection view modifiers: environment, appearance, theme.
|
||||
//
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// View+Events.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Event handling and lifecycle view modifiers: onKeyPress, onAppear, onDisappear, task, statusBarItems.
|
||||
//
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// View+Layout.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Layout and styling view modifiers: border, dimmed, background, frame, overlay, padding.
|
||||
//
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// View+Modifier.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Generic modifier application extension for View.
|
||||
//
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// View+Preferences.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Preference system view modifiers: preference, onPreferenceChange, navigationTitle.
|
||||
//
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// BackgroundModifier.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// The .background() modifier for adding background colors to views.
|
||||
//
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// BorderModifier.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// The .border() modifier for adding borders around views.
|
||||
//
|
||||
@@ -37,7 +37,7 @@ extension BorderedView: Renderable {
|
||||
contentContext.availableWidth = max(1, context.availableWidth - BorderRenderer.borderWidthOverhead)
|
||||
|
||||
// Render content with reduced width
|
||||
let buffer = TUIKit.renderToBuffer(content, context: contentContext)
|
||||
let buffer = TUIkit.renderToBuffer(content, context: contentContext)
|
||||
|
||||
guard !buffer.isEmpty else { return buffer }
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// DimmedModifier.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A modifier that applies a dimming effect to the entire view content.
|
||||
//
|
||||
@@ -22,7 +22,7 @@ public struct DimmedModifier<Content: View>: View {
|
||||
|
||||
extension DimmedModifier: Renderable {
|
||||
public func renderToBuffer(context: RenderContext) -> FrameBuffer {
|
||||
let contentBuffer = TUIKit.renderToBuffer(content, context: context)
|
||||
let contentBuffer = TUIkit.renderToBuffer(content, context: context)
|
||||
|
||||
guard !contentBuffer.isEmpty else {
|
||||
return contentBuffer
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FrameModifier.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// The .frame() modifier for setting explicit size constraints.
|
||||
//
|
||||
@@ -81,7 +81,7 @@ extension FlexibleFrameView: Renderable {
|
||||
}
|
||||
|
||||
// Render content
|
||||
let buffer = TUIKit.renderToBuffer(content, context: contentContext)
|
||||
let buffer = TUIkit.renderToBuffer(content, context: contentContext)
|
||||
|
||||
// Apply minimum constraints
|
||||
var finalWidth = buffer.width
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// KeyPressModifier.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A modifier for handling keyboard events.
|
||||
//
|
||||
@@ -43,6 +43,6 @@ extension KeyPressModifier: Renderable {
|
||||
}
|
||||
|
||||
// Render the content
|
||||
return TUIKit.renderToBuffer(content, context: context)
|
||||
return TUIkit.renderToBuffer(content, context: context)
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// LifecycleModifier.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Lifecycle modifiers: .onAppear(), .onDisappear(), .task()
|
||||
//
|
||||
@@ -117,7 +117,7 @@ extension OnAppearModifier: Renderable {
|
||||
_ = context.tuiContext.lifecycle.recordAppear(token: token, action: action)
|
||||
|
||||
// Render content
|
||||
return TUIKit.renderToBuffer(content, context: context)
|
||||
return TUIkit.renderToBuffer(content, context: context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ extension OnDisappearModifier: Renderable {
|
||||
_ = context.tuiContext.lifecycle.recordAppear(token: token, action: {})
|
||||
|
||||
// Render content
|
||||
return TUIKit.renderToBuffer(content, context: context)
|
||||
return TUIkit.renderToBuffer(content, context: context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,6 +274,6 @@ extension TaskModifier: Renderable {
|
||||
}
|
||||
|
||||
// Render content
|
||||
return TUIKit.renderToBuffer(content, context: context)
|
||||
return TUIkit.renderToBuffer(content, context: context)
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// OverlayModifier.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A modifier that renders an overlay on top of the base view.
|
||||
//
|
||||
@@ -30,8 +30,8 @@ public struct OverlayModifier<Base: View, Overlay: View>: View {
|
||||
extension OverlayModifier: Renderable {
|
||||
public func renderToBuffer(context: RenderContext) -> FrameBuffer {
|
||||
// Render both contents
|
||||
let baseBuffer = TUIKit.renderToBuffer(base, context: context)
|
||||
let overlayBuffer = TUIKit.renderToBuffer(overlay, context: context)
|
||||
let baseBuffer = TUIkit.renderToBuffer(base, context: context)
|
||||
let overlayBuffer = TUIkit.renderToBuffer(overlay, context: context)
|
||||
|
||||
guard !baseBuffer.isEmpty else {
|
||||
return overlayBuffer
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// PaddingModifier.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// The .padding() modifier for adding space around a view.
|
||||
//
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// StatusBarItemsModifier.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A modifier that sets status bar items for a view.
|
||||
//
|
||||
@@ -64,6 +64,6 @@ extension StatusBarItemsModifier: Renderable {
|
||||
}
|
||||
|
||||
// Render the content
|
||||
return TUIKit.renderToBuffer(content, context: renderContext)
|
||||
return TUIkit.renderToBuffer(content, context: renderContext)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ANSIRenderer.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// ANSI escape code generation for terminal output.
|
||||
//
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// BorderRenderer.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Centralized border rendering utilities for standard and block styles.
|
||||
//
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FrameBuffer.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A 2D text buffer for off-screen rendering before terminal output.
|
||||
//
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// Renderable.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Protocol for views that can render themselves directly.
|
||||
//
|
||||
|
||||
/// A protocol for views that produce terminal output directly.
|
||||
///
|
||||
/// TUIKit uses a **dual rendering system** inspired by SwiftUI:
|
||||
/// TUIkit uses a **dual rendering system** inspired by SwiftUI:
|
||||
///
|
||||
/// - **`View.body`** — Compositional path: views declare *what* they
|
||||
/// are made of by composing other `View` types.
|
||||
@@ -123,7 +123,7 @@ public struct RenderContext {
|
||||
|
||||
/// Renders any `View` into a ``FrameBuffer`` using the dual rendering system.
|
||||
///
|
||||
/// This is the **single entry point** for all view rendering in TUIKit.
|
||||
/// This is the **single entry point** for all view rendering in TUIkit.
|
||||
/// Every recursive call in the view tree passes through this function.
|
||||
///
|
||||
/// ## Decision order
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Terminal.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Terminal abstraction for input and output.
|
||||
//
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ViewRenderer.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Renders Views to terminal output via FrameBuffer.
|
||||
//
|
||||
@@ -264,9 +264,9 @@ extension ConditionalView: Renderable {
|
||||
public func renderToBuffer(context: RenderContext) -> FrameBuffer {
|
||||
switch self {
|
||||
case .trueContent(let content):
|
||||
return TUIKit.renderToBuffer(content, context: context)
|
||||
return TUIkit.renderToBuffer(content, context: context)
|
||||
case .falseContent(let content):
|
||||
return TUIKit.renderToBuffer(content, context: context)
|
||||
return TUIkit.renderToBuffer(content, context: context)
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,10 +1,10 @@
|
||||
# Architecture
|
||||
|
||||
Understand the layer model and rendering pipeline of TUIKit.
|
||||
Understand the layer model and rendering pipeline of TUIkit.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit is structured in five layers, each building on the one below. This clean separation makes the framework easy to extend and maintain.
|
||||
TUIkit is structured in five layers, each building on the one below. This clean separation makes the framework easy to extend and maintain.
|
||||
|
||||
## Layer Model
|
||||
|
||||
@@ -55,7 +55,7 @@ The rendering pipeline converts the view tree into terminal output:
|
||||
|
||||
## Event Loop
|
||||
|
||||
TUIKit runs a synchronous event loop:
|
||||
TUIkit runs a synchronous event loop:
|
||||
|
||||
```
|
||||
┌─────────────────────────┐
|
||||
+10
-10
@@ -1,14 +1,14 @@
|
||||
# Getting Started
|
||||
|
||||
Build your first terminal application with TUIKit.
|
||||
Build your first terminal application with TUIkit.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit is a Swift package that lets you create terminal user interfaces with a declarative, SwiftUI-like syntax. This guide walks you through setting up a project and building a simple app.
|
||||
TUIkit is a Swift package that lets you create terminal user interfaces with a declarative, SwiftUI-like syntax. This guide walks you through setting up a project and building a simple app.
|
||||
|
||||
## Adding TUIKit to Your Project
|
||||
## Adding TUIkit to Your Project
|
||||
|
||||
Add TUIKit as a dependency in your `Package.swift`:
|
||||
Add TUIkit as a dependency in your `Package.swift`:
|
||||
|
||||
```swift
|
||||
// swift-tools-version: 6.0
|
||||
@@ -18,12 +18,12 @@ let package = Package(
|
||||
name: "MyTUIApp",
|
||||
platforms: [.macOS(.v10_15)],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/phranck/TUIKit.git", from: "0.1.0"),
|
||||
.package(url: "https://github.com/phranck/TUIkit.git", from: "0.1.0"),
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
name: "MyTUIApp",
|
||||
dependencies: ["TUIKit"]
|
||||
dependencies: ["TUIkit"]
|
||||
),
|
||||
]
|
||||
)
|
||||
@@ -34,7 +34,7 @@ let package = Package(
|
||||
Create a `main.swift` file with the ``App`` protocol as your entry point:
|
||||
|
||||
```swift
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
@main
|
||||
struct MyApp: App {
|
||||
@@ -48,7 +48,7 @@ struct MyApp: App {
|
||||
struct ContentView: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Welcome to TUIKit!")
|
||||
Text("Welcome to TUIkit!")
|
||||
.bold()
|
||||
.foregroundColor(.cyan)
|
||||
|
||||
@@ -86,11 +86,11 @@ struct CounterView: View {
|
||||
For simple scripts that don't need a full app lifecycle, use ``renderOnce(content:)``:
|
||||
|
||||
```swift
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
renderOnce {
|
||||
VStack {
|
||||
Text("Hello, TUIKit!")
|
||||
Text("Hello, TUIkit!")
|
||||
.bold()
|
||||
.foregroundColor(.green)
|
||||
Divider()
|
||||
+3
-3
@@ -1,10 +1,10 @@
|
||||
# State Management
|
||||
|
||||
Manage reactive state in your TUIKit application.
|
||||
Manage reactive state in your TUIkit application.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit provides a state management system modeled after SwiftUI. When state changes, the view tree is automatically re-rendered.
|
||||
TUIkit provides a state management system modeled after SwiftUI. When state changes, the view tree is automatically re-rendered.
|
||||
|
||||
## @State
|
||||
|
||||
@@ -99,7 +99,7 @@ struct SettingsView: View {
|
||||
|
||||
## How Re-Rendering Works
|
||||
|
||||
TUIKit uses a single-threaded event loop. When a ``State`` value changes:
|
||||
TUIkit uses a single-threaded event loop. When a ``State`` value changes:
|
||||
|
||||
1. ``AppState/setNeedsRender()`` is called
|
||||
2. The main loop detects the change
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
# Theming Guide
|
||||
|
||||
Customize the visual appearance of your TUIKit application with themes.
|
||||
Customize the visual appearance of your TUIkit application with themes.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit includes a full theming system with five built-in themes inspired by classic CRT terminals. Themes define semantic colors for backgrounds, foregrounds, accents, and UI elements.
|
||||
TUIkit includes a full theming system with five built-in themes inspired by classic CRT terminals. Themes define semantic colors for backgrounds, foregrounds, accents, and UI elements.
|
||||
|
||||
## Built-in Themes
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# ``TUIKit``
|
||||
# ``TUIkit``
|
||||
|
||||
A declarative, SwiftUI-like framework for building Terminal User Interfaces in Swift.
|
||||
|
||||
@Metadata {
|
||||
@DisplayName("TUIKit")
|
||||
@DisplayName("TUIkit")
|
||||
}
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit lets you build terminal applications using a familiar, declarative syntax inspired by SwiftUI. No ncurses, no C dependencies — pure Swift.
|
||||
TUIkit lets you build terminal applications using a familiar, declarative syntax inspired by SwiftUI. No ncurses, no C dependencies — pure Swift.
|
||||
|
||||
```swift
|
||||
@main
|
||||
@@ -16,7 +16,7 @@ struct MyApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
VStack {
|
||||
Text("Hello, TUIKit!")
|
||||
Text("Hello, TUIkit!")
|
||||
.bold()
|
||||
.foregroundColor(.cyan)
|
||||
Button("Press me") {
|
||||
@@ -1,14 +1,14 @@
|
||||
//
|
||||
// TUIKit.swift
|
||||
// TUIKit
|
||||
// TUIkit.swift
|
||||
// TUIkit
|
||||
//
|
||||
// A SwiftUI-like framework for Terminal User Interfaces.
|
||||
//
|
||||
// TUIKit enables creating TUI applications with a declarative,
|
||||
// TUIkit enables creating TUI applications with a declarative,
|
||||
// SwiftUI-like syntax - without ncurses or other low-level libraries.
|
||||
//
|
||||
|
||||
/// The current version of TUIKit.
|
||||
/// The current version of TUIkit.
|
||||
public let tuiKitVersion = "0.1.0"
|
||||
|
||||
/// Executes a view closure and renders it once.
|
||||
@@ -20,7 +20,7 @@ public let tuiKitVersion = "0.1.0"
|
||||
/// ```swift
|
||||
/// renderOnce {
|
||||
/// VStack {
|
||||
/// Text("Hello, TUIKit!")
|
||||
/// Text("Hello, TUIkit!")
|
||||
/// .bold()
|
||||
/// .foregroundColor(.cyan)
|
||||
/// Divider()
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Alert.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A modal alert view with title, message, and optional action buttons.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Box.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A simple bordered container view.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Button.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// An interactive button view that responds to keyboard input.
|
||||
//
|
||||
@@ -443,7 +443,7 @@ extension ButtonRow: Renderable {
|
||||
// Render each button
|
||||
var buttonBuffers: [FrameBuffer] = []
|
||||
for button in buttons {
|
||||
let buffer = TUIKit.renderToBuffer(button, context: context)
|
||||
let buffer = TUIkit.renderToBuffer(button, context: context)
|
||||
buttonBuffers.append(buffer)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Card.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A styled container view with optional header, content, and footer.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ContainerView.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A unified container component with Header/Body/Footer architecture.
|
||||
//
|
||||
@@ -283,13 +283,13 @@ extension ContainerView: Renderable {
|
||||
|
||||
// Render body content
|
||||
let paddedContent = content.padding(padding)
|
||||
let bodyBuffer = TUIKit.renderToBuffer(paddedContent, context: context)
|
||||
let bodyBuffer = TUIkit.renderToBuffer(paddedContent, context: context)
|
||||
|
||||
// Render footer if present
|
||||
let footerBuffer: FrameBuffer?
|
||||
if let footerView = footer {
|
||||
let paddedFooter = footerView.padding(EdgeInsets(horizontal: 1, vertical: 0))
|
||||
footerBuffer = TUIKit.renderToBuffer(paddedFooter, context: context)
|
||||
footerBuffer = TUIkit.renderToBuffer(paddedFooter, context: context)
|
||||
} else {
|
||||
footerBuffer = nil
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Dialog.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A modal dialog view with title, custom content, and optional footer.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ForEach.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Iteration over data collections for view generation.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Menu.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A menu view that displays a list of selectable items.
|
||||
//
|
||||
@@ -429,7 +429,7 @@ public struct AnyView: View {
|
||||
/// Creates an AnyView wrapping the given view.
|
||||
public init<V: View>(_ view: V) {
|
||||
self._render = { context in
|
||||
TUIKit.renderToBuffer(view, context: context)
|
||||
TUIkit.renderToBuffer(view, context: context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Panel.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A titled container view with optional footer.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Spacer.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Flexible spacing elements for layout.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Stacks.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Layout containers for vertical and horizontal arrangement.
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// StatusBar.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A status bar that displays keyboard shortcuts and context-sensitive actions.
|
||||
// Always rendered at the bottom of the terminal, never dimmed by overlays.
|
||||
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// Text.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// A view for displaying text in the terminal.
|
||||
//
|
||||
|
||||
/// A view that displays text in the terminal.
|
||||
///
|
||||
/// `Text` is one of the most fundamental views in TUIKit. It displays
|
||||
/// `Text` is one of the most fundamental views in TUIkit. It displays
|
||||
/// a string in the terminal and supports various formatting options.
|
||||
///
|
||||
/// # Example
|
||||
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// AppState.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// Global state management for the example app.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
// MARK: - Demo Page Enum
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// DemoSection.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// A reusable section component for organizing demo content.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
/// A section with a styled title and content.
|
||||
///
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// HeaderView.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// A reusable header component for demo pages.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
/// A styled header with title on the left and version on the right.
|
||||
///
|
||||
@@ -36,7 +36,7 @@ struct HeaderView: View {
|
||||
.bold()
|
||||
.foregroundColor(.theme.accent)
|
||||
Spacer()
|
||||
Text("TUIKit v\(tuiKitVersion)")
|
||||
Text("TUIkit v\(tuiKitVersion)")
|
||||
.foregroundColor(.theme.foregroundTertiary)
|
||||
}
|
||||
if let subtitleText = subtitle {
|
||||
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// ContentView.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// The main content view that routes between demo pages.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
// MARK: - Content View (Page Router)
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// ButtonsPage.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// Demonstrates button and focus system capabilities.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
/// Buttons and focus demo page.
|
||||
///
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// ColorsPage.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// Demonstrates color capabilities.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
/// Colors demo page.
|
||||
///
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// ContainersPage.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// Demonstrates container view capabilities.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
/// Container views demo page.
|
||||
///
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// LayoutPage.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// Demonstrates layout system capabilities.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
/// Layout system demo page.
|
||||
///
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// MainMenuPage.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// The main menu page with navigation to all demos.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
/// The main menu page.
|
||||
///
|
||||
@@ -17,7 +17,7 @@ struct MainMenuPage: View {
|
||||
|
||||
VStack(spacing: 1) {
|
||||
HeaderView(
|
||||
title: "TUIKit Example App",
|
||||
title: "TUIkit Example App",
|
||||
subtitle: "A SwiftUI-like framework for Terminal User Interfaces"
|
||||
)
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// OverlaysPage.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// Demonstrates overlay and modal capabilities.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
/// Overlays and modals demo page.
|
||||
///
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// TextStylesPage.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// Demonstrates text styling capabilities.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
/// Text styles demo page.
|
||||
///
|
||||
@@ -1,14 +1,14 @@
|
||||
//
|
||||
// main.swift
|
||||
// TUIKitExample
|
||||
// TUIkitExample
|
||||
//
|
||||
// Entry point for the TUIKit example application.
|
||||
// Entry point for the TUIkit example application.
|
||||
//
|
||||
// This app demonstrates TUIKit capabilities through various demo pages.
|
||||
// This app demonstrates TUIkit capabilities through various demo pages.
|
||||
// Use the menu to navigate between demos.
|
||||
//
|
||||
|
||||
import TUIKit
|
||||
import TUIkit
|
||||
|
||||
// MARK: - Main App
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// AppearanceTests.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Tests for the Appearance system.
|
||||
//
|
||||
|
||||
import Testing
|
||||
|
||||
@testable import TUIKit
|
||||
@testable import TUIkit
|
||||
|
||||
// MARK: - Appearance Tests
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// ButtonTests.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Tests for Button, ButtonStyle, and ButtonRow views.
|
||||
//
|
||||
|
||||
import Testing
|
||||
|
||||
@testable import TUIKit
|
||||
@testable import TUIkit
|
||||
|
||||
// MARK: - Test Helpers
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// ColorTests.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Tests for the Color system and ANSI rendering.
|
||||
//
|
||||
|
||||
import Testing
|
||||
|
||||
@testable import TUIKit
|
||||
@testable import TUIkit
|
||||
|
||||
@Suite("Color Tests")
|
||||
struct ColorTests {
|
||||
+2
-2
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// ContainerViewTests.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Tests for container views: Alert, Dialog, Menu.
|
||||
//
|
||||
|
||||
import Testing
|
||||
|
||||
@testable import TUIKit
|
||||
@testable import TUIkit
|
||||
|
||||
@Suite("Alert Tests")
|
||||
struct AlertTests {
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FocusTests.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Tests for the focus management system.
|
||||
//
|
||||
@@ -8,7 +8,7 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
|
||||
@testable import TUIKit
|
||||
@testable import TUIkit
|
||||
|
||||
// MARK: - Mock Focusable
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// FrameBufferTests.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Tests for FrameBuffer operations and compositing.
|
||||
//
|
||||
|
||||
import Testing
|
||||
|
||||
@testable import TUIKit
|
||||
@testable import TUIkit
|
||||
|
||||
@Suite("FrameBuffer Tests")
|
||||
struct FrameBufferTests {
|
||||
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// RenderingTests.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Tests for view rendering and layout.
|
||||
//
|
||||
|
||||
import Testing
|
||||
|
||||
@testable import TUIKit
|
||||
@testable import TUIkit
|
||||
|
||||
@Suite("Rendering Tests")
|
||||
struct RenderingTests {
|
||||
@@ -1,14 +1,14 @@
|
||||
// swiftlint:disable file_length
|
||||
//
|
||||
// StatusBarTests.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Tests for Shortcut constants, StatusBarItem, StatusBarManager, and StatusBar.
|
||||
//
|
||||
|
||||
import Testing
|
||||
|
||||
@testable import TUIKit
|
||||
@testable import TUIkit
|
||||
|
||||
// MARK: - Shortcut Constants Tests
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// ViewTests.swift
|
||||
// TUIKit
|
||||
// TUIkit
|
||||
//
|
||||
// Tests for the View protocol, ViewBuilder, and basic views.
|
||||
//
|
||||
|
||||
import Testing
|
||||
|
||||
@testable import TUIKit
|
||||
@testable import TUIkit
|
||||
|
||||
@Suite("View Protocol Tests")
|
||||
struct ViewTests {
|
||||
@@ -1,4 +1,4 @@
|
||||
# TUIKit - Comprehensive Project Analysis
|
||||
# TUIkit - Comprehensive Project Analysis
|
||||
|
||||
**Date:** 2026-01-30
|
||||
**Scope:** Full codebase review (66 Swift files)
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
## Executive Summary
|
||||
|
||||
TUIKit is a well-architected declarative Swift framework for building terminal UIs. The SwiftUI-inspired API design is clean, consistent, and idiomatic. Documentation is above average for a personal project. However, the codebase suffers from **significant code duplication** across Views and Modifiers, an **overreliance on singletons** that hinders testability, and several **thread-safety issues** with `@unchecked Sendable` types. The most impactful improvements would be extracting shared rendering logic into utilities, replacing singletons with dependency injection, and expanding test coverage for Views and Modifiers.
|
||||
TUIkit is a well-architected declarative Swift framework for building terminal UIs. The SwiftUI-inspired API design is clean, consistent, and idiomatic. Documentation is above average for a personal project. However, the codebase suffers from **significant code duplication** across Views and Modifiers, an **overreliance on singletons** that hinders testability, and several **thread-safety issues** with `@unchecked Sendable` types. The most impactful improvements would be extracting shared rendering logic into utilities, replacing singletons with dependency injection, and expanding test coverage for Views and Modifiers.
|
||||
|
||||
---
|
||||
|
||||
@@ -319,7 +319,7 @@ Marked as "Fixed Frame Modifier (Legacy)". `FlexibleFrameView` is the active imp
|
||||
|
||||
---
|
||||
|
||||
### C.5 TODO Placeholder — `TUIKit.swift` (Low)
|
||||
### C.5 TODO Placeholder — `TUIkit.swift` (Low)
|
||||
|
||||
```swift
|
||||
return 0 // TODO: Return actual line count
|
||||
@@ -818,14 +818,14 @@ The same bug exists in `AppearanceManager.setAppearance()`.
|
||||
| C.2 | `FrameModifier` legacy code | Dead Code | Medium | FrameModifier.swift |
|
||||
| C.3 | Panel `body` dead code | Dead Code | Medium | Panel.swift |
|
||||
| C.4 | Common Preference Keys likely unused | Dead Code | Low | Preferences.swift |
|
||||
| C.5 | TODO placeholder return 0 | Dead Code | Low | TUIKit.swift |
|
||||
| C.5 | TODO placeholder return 0 | Dead Code | Low | TUIkit.swift |
|
||||
| C.6 | Menu pointless ternary `4 : 4` | Dead Code | Low | Menu.swift |
|
||||
| C.7 | Menu identical if/else branches | Dead Code | Low | Menu.swift |
|
||||
| C.8 | `_ = self` anti-pattern | Dead Code | Low | App.swift |
|
||||
| E.1 | Public types missing doc comments | Documentation | Medium | Multiple |
|
||||
| E.2 | Complex logic without inline comments | Documentation | Medium | KeyEvent, FrameBuffer, ViewRenderer |
|
||||
| E.3 | Missing contributor documentation | Documentation | Medium | Project root |
|
||||
| E.4 | Example app missing demonstrations | Documentation | Low | TUIKitExample |
|
||||
| E.4 | Example app missing demonstrations | Documentation | Low | TUIkitExample |
|
||||
| F.1 | 60+ magic hex values in KeyEvent | Constants | High | KeyEvent.swift |
|
||||
| F.2 | ANSI style codes as magic strings | Constants | Medium | ANSIRenderer.swift |
|
||||
| F.3 | Block characters scattered | Constants | Medium | Multiple |
|
||||
|
||||
Reference in New Issue
Block a user