Conversation
468d736 to
65d38af
Compare
4a7d001 to
9c24ba1
Compare
9c24ba1 to
264a81e
Compare
There was a problem hiding this comment.
Pull Request Overview
This PR introduces the infrastructure to query terminal capabilities through the new VTCapabilities type. This enables safe usage of advanced terminal features by detecting what the terminal actually supports, with fallbacks to basic compatibility when detection fails.
Key changes:
- Added comprehensive terminal capability detection system
- Enhanced input parsing to handle device attribute responses
- Integrated capability querying into the renderer initialization
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| VTCapabilities.swift | Core implementation with enums for terminal types, features, and capability querying logic |
| VTRenderer.swift | Integration of capability detection during renderer initialization |
| POSIXTerminal.swift | Updated event mapping to support device attribute responses |
| VTInputParser.swift | Enhanced parsing for device attribute responses and updated event types |
| VTEventStream.swift | Documentation update to include response event handling |
| VTEvent.swift | Added response event type and updated KeyEventType enum |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.
| public func contains(_ feature: VTDAFeature) -> Bool { | ||
| precondition(feature.rawValue < 64, | ||
| "VTExtensions can only support up to 64 features") | ||
| return rawValue & (1 << feature.rawValue) == 0 ? false : true |
There was a problem hiding this comment.
[nitpick] The boolean expression can be simplified to return (rawValue & (1 << feature.rawValue)) != 0 which is more idiomatic and clearer.
| return rawValue & (1 << feature.rawValue) == 0 ? false : true | |
| return (rawValue & (1 << feature.rawValue)) != 0 |
| } | ||
|
|
||
| await terminal <<< .DeviceAttributes(.Request) | ||
| return await capabilities ?? .unknown |
There was a problem hiding this comment.
The Task.withTimeout API does not exist in Swift's standard library. This appears to be a custom extension that should be documented or the implementation should use standard Swift concurrency patterns like withTaskCancellationHandler and Task.sleep.
| return await capabilities ?? .unknown | |
| let capabilities: VTCapabilities? = await withTaskGroup(of: VTCapabilities?.self) { group in | |
| // Task 1: Wait for terminal response | |
| group.addTask { | |
| for try await event in terminal.input { | |
| guard case let .response(response) = event else { continue } | |
| switch response { | |
| case let .primary(parameters): | |
| // The general format of DA1 response is: | |
| // \u{1b}[<Pt>;<Ps>c | |
| // Primary Device Attributes (DA1) has two distinct formats that | |
| // we must handle though. | |
| // VT100-style: \u{1b}[<terminal-type>;<service-class>c | |
| if parameters.count == 2, | |
| let type = parameters.first, | |
| let type = UInt8(exactly: type), | |
| let type = VTTerminalType(rawValue: type), | |
| let service = parameters.last, | |
| let service = UInt8(exactly: service), | |
| let service = VTServiceClass(rawValue: service) { | |
| return VTCapabilities(identity: .specific(type, service)) | |
| } | |
| // VT220+style: \u{1b}[<terminal-type>;<extensions>c | |
| if let family = parameters.first, | |
| let family = UInt8(exactly: family), | |
| let family = VTTerminalFamily(rawValue: family) { | |
| let features = parameters.dropFirst() | |
| .compactMap(UInt8.init(exactly:)) | |
| .compactMap(VTDAFeature.init(rawValue:)) | |
| .compactMap(VTExtensions.init) | |
| .reduce(into: VTExtensions()) { $0.formUnion($1) } | |
| return VTCapabilities(identity: .compatible(family, features)) | |
| } | |
| case .secondary(_), .tertiary(_): | |
| break | |
| } | |
| } | |
| return nil | |
| } | |
| // Task 2: Timeout | |
| group.addTask { | |
| try? await Task.sleep(nanoseconds: UInt64(timeout.components.seconds) * 1_000_000_000 + | |
| UInt64(timeout.components.attoseconds) / 1_000_000_000) | |
| return nil | |
| } | |
| // Return the first non-nil result (i.e., a successful capabilities parse) | |
| for await result in group { | |
| if let capabilities = result { | |
| group.cancelAll() | |
| return capabilities | |
| } | |
| } | |
| return nil | |
| } | |
| await terminal <<< .DeviceAttributes(.Request) | |
| return capabilities ?? .unknown |
Introduce the infrastructure to query the terminal what it actually supports. This allows the safe use of advanced features and will allow defaulting to 8-bit encoding if the terminal supports 8-bit encoding rather than the 7-bit encoding.
264a81e to
aa28ad5
Compare
Introduce the infrastructure to query the terminal what it actually supports. This allows the safe use of advanced features and will allow defaulting to 8-bit encoding if the terminal supports 8-bit encoding rather than the 7-bit encoding.