一个 Swift 包,为你的命令行应用程序带来 Vim 风格的导航和强大的终端 UI 功能。轻松创建交互式终端 UI,支持单列布局(如文件浏览器)和多列布局(如菜单)。
将 VimTerminalKit 添加到你的 Package.swift
dependencies: [
.package(url: "https://github.com/marcusziade/VimTerminalKit.git", from: "1.0.0")
]
然后在你的源文件中导入它
import VimTerminalKit
最佳应用场景
必要设置
let navigator = VimTerminalKit.Navigator(
itemCount: items.count,
columnsCount: 1 // Must be 1 for vertical lists
)
最佳应用场景
必要设置
let navigator = VimTerminalKit.Navigator(
itemCount: items.count,
columnsCount: 2 // 2 or more for grid layouts
)
正确的初始化模式对于避免编译器错误和运行时问题至关重要。
final class MyApp {
private let navigator: VimTerminalKit.Navigator
private let stateManager: VimTerminalKit.StateManager
private var items: [String] = []
init() {
// 1. Initialize basic properties first
self.items = []
// 2. Set up navigator with initial state
self.navigator = .init(itemCount: 1, columnsCount: 1)
// 3. Initialize stateManager with empty closure
self.stateManager = .init { }
// 4. Set up callbacks after initialization
setupStateManager()
}
private func setupStateManager() {
stateManager = .init { [weak self] in
self?.updateUI()
}
}
}
StateManager 处理 UI 更新和加载状态。
// Initialize with UI update callback
let stateManager = VimTerminalKit.StateManager {
// Update UI here
}
// Show loading state
await stateManager.withLoading(message: "Loading...") {
try await someAsyncWork()
}
处理导航输入
switch VimTerminalKit.InputReader.getInput() {
case .vim(let direction), .arrow(let direction):
navigator.navigate(.arrow(direction))
case .enter:
// Handle selection
case .quit:
isRunning = false
default:
break
}
final class Explorer {
private let fileManager = FileManager.default
private var currentPath: String
private var items: [FileItem] = []
private var navigator: VimTerminalKit.Navigator
private var stateManager: VimTerminalKit.StateManager
private var isRunning = true
private var pathHistory: [String] = []
init() {
// IMPORTANT: Order matters for initialization
self.currentPath = fileManager.currentDirectoryPath
self.navigator = .init(itemCount: 1, columnsCount: 1)
self.stateManager = .init { }
setupStateManager()
}
private func setupStateManager() {
stateManager = .init { [weak self] in
self?.clearScreen()
self?.printInterface()
}
}
private func loadCurrentDirectory() {
Task { [weak self] in
guard let self else { return }
try await self.stateManager.withLoading(message: "Loading...") {
let contents = try self.fileManager.contentsOfDirectory(atPath: self.currentPath)
self.items = // ... process contents ...
let totalItems = self.currentPath == "/" ? items.count : items.count + 1
self.navigator = .init(itemCount: totalItems, columnsCount: 1)
}
}
}
func start() {
VimTerminalKit.setup()
defer { VimTerminalKit.cleanup() }
loadCurrentDirectory()
while isRunning {
clearScreen()
printInterface()
handleInput()
}
}
}
struct MenuApp {
private let navigator: VimTerminalKit.Navigator
private let stateManager: VimTerminalKit.StateManager
private var isRunning = true
private let menuItems = ["Option 1", "Option 2", "Option 3", "Option 4"]
init() {
self.navigator = .init(itemCount: menuItems.count, columnsCount: 2)
self.stateManager = .init { }
setupStateManager()
}
private func setupStateManager() {
stateManager = .init { [weak self] in
self?.redrawInterface()
}
}
func start() {
VimTerminalKit.setup()
defer { VimTerminalKit.cleanup() }
while isRunning {
redrawInterface()
handleInput()
}
}
private func redrawInterface() {
// ... draw menu interface ...
}
}
self
columnsCount: 1
columnsCount: 2+
// Screen control
print(VimTerminalKit.Terminal.Control.clearScreen)
// Cursor control
print(VimTerminalKit.Terminal.Control.hideCursor)
print(VimTerminalKit.Terminal.Control.showCursor)
// Movement
print(VimTerminalKit.Terminal.Control.up)
print(VimTerminalKit.Terminal.Control.down)
// Progress indication
stateManager.startLoading(message: "Step 1")
// ... work ...
stateManager.updateLoadingMessage("Step 2")
// ... work ...
stateManager.stopLoading()
// Async operations
await stateManager.withLoading(message: "Processing...") {
try await someAsyncWork()
}
设置和清理
VimTerminalKit.setup()
defer { VimTerminalKit.cleanup() }
内存管理
[weak self]
错误处理
欢迎贡献!请按照以下步骤
git checkout -b feature/AmazingFeature
)git commit -m 'Add some AmazingFeature'
)git push origin feature/AmazingFeature
)在提交拉取请求之前,请阅读我们的 贡献指南。
本项目根据 MIT 许可证获得许可 - 有关详细信息,请参阅 LICENSE 文件。