mirror of
https://github.com/phranck/TUIkit.git
synced 2026-06-20 09:54:37 +00:00
Merge pull request #16 from phranck/feature/add-inline-comments
docs: Add inline comments to complex logic (E.2)
This commit is contained in:
@@ -189,10 +189,15 @@ extension KeyEvent {
|
||||
}
|
||||
|
||||
/// Parses a CSI (Control Sequence Introducer) sequence.
|
||||
///
|
||||
/// CSI format: `ESC [ <params> <final-byte>`.
|
||||
/// The final byte identifies the key (e.g. `A` = up arrow).
|
||||
/// Numeric parameters before the final byte encode extended keys
|
||||
/// like Page Up/Down (`ESC [ 5 ~`).
|
||||
private static func parseCSISequence(_ params: [UInt8]) -> KeyEvent? {
|
||||
guard !params.isEmpty else { return nil }
|
||||
|
||||
// Arrow keys: A=up, B=down, C=right, D=left
|
||||
// The last byte is the CSI function identifier
|
||||
switch params.last {
|
||||
case ASCIIByte.arrowUp:
|
||||
return KeyEvent(key: .up)
|
||||
@@ -213,9 +218,12 @@ extension KeyEvent {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses extended key sequences (ESC [ n ~).
|
||||
/// Parses extended key sequences (`ESC [ n ~`).
|
||||
///
|
||||
/// These are VT-style sequences where `n` is a numeric key identifier:
|
||||
/// 1=Home, 2=Insert, 3=Delete, 4=End, 5=PageUp, 6=PageDown.
|
||||
private static func parseExtendedKey(_ params: [UInt8]) -> KeyEvent? {
|
||||
// Parse the number before '~'
|
||||
// Extract the numeric identifier before the '~' terminator
|
||||
let numberBytes = params.dropLast()
|
||||
guard let string = String(bytes: numberBytes, encoding: .ascii),
|
||||
let number = Int(string)
|
||||
@@ -224,20 +232,13 @@ extension KeyEvent {
|
||||
}
|
||||
|
||||
switch number {
|
||||
case 1:
|
||||
return KeyEvent(key: .home)
|
||||
case 2:
|
||||
return nil // Insert - not commonly used
|
||||
case 3:
|
||||
return KeyEvent(key: .delete)
|
||||
case 4:
|
||||
return KeyEvent(key: .end)
|
||||
case 5:
|
||||
return KeyEvent(key: .pageUp)
|
||||
case 6:
|
||||
return KeyEvent(key: .pageDown)
|
||||
default:
|
||||
return nil
|
||||
case 1: return KeyEvent(key: .home)
|
||||
case 2: return nil // Insert — not commonly used in TUI apps
|
||||
case 3: return KeyEvent(key: .delete)
|
||||
case 4: return KeyEvent(key: .end)
|
||||
case 5: return KeyEvent(key: .pageUp)
|
||||
case 6: return KeyEvent(key: .pageDown)
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,27 +169,28 @@ public struct FrameBuffer {
|
||||
/// - column: The column position (0-based).
|
||||
/// - Returns: The composited line.
|
||||
private func insertOverlay(base: String, overlay: String, atColumn column: Int) -> String {
|
||||
// For ANSI-safe insertion, we work with visible characters
|
||||
// Strip ANSI codes from the base to get accurate column positions.
|
||||
// Without stripping, escape sequences would shift character offsets.
|
||||
// The overlay keeps its ANSI codes intact so its styling is preserved.
|
||||
let baseChars = Array(base.stripped)
|
||||
let overlayStripped = overlay.stripped
|
||||
|
||||
// Build result: characters before overlay position + overlay + characters after
|
||||
// Build: [base prefix] + [overlay with ANSI] + [base suffix]
|
||||
var result = ""
|
||||
|
||||
// Add characters before the overlay position
|
||||
// Base characters before the overlay insertion point
|
||||
if column > 0 {
|
||||
let prefixEnd = min(column, baseChars.count)
|
||||
result += String(baseChars[0..<prefixEnd])
|
||||
// Pad if needed
|
||||
if prefixEnd < column {
|
||||
result += String(repeating: " ", count: column - prefixEnd)
|
||||
}
|
||||
}
|
||||
|
||||
// Add the overlay (with its ANSI codes intact)
|
||||
// Overlay with its ANSI styling intact
|
||||
result += overlay
|
||||
|
||||
// Add characters after the overlay
|
||||
// Remaining base characters after the overlay region
|
||||
let afterOverlayColumn = column + overlayStripped.count
|
||||
if afterOverlayColumn < baseChars.count {
|
||||
result += String(baseChars[afterOverlayColumn...])
|
||||
|
||||
@@ -120,7 +120,8 @@ extension VStack: Renderable {
|
||||
public func renderToBuffer(context: RenderContext) -> FrameBuffer {
|
||||
let infos = resolveChildInfos(from: content, context: context)
|
||||
|
||||
// Count spacers and measure fixed children
|
||||
// Spacer distribution: divide remaining vertical space equally
|
||||
// among all spacers after subtracting fixed children and inter-item spacing.
|
||||
let spacerCount = infos.filter(\.isSpacer).count
|
||||
let fixedHeight = infos.compactMap(\.buffer).reduce(0) { $0 + $1.height }
|
||||
let totalSpacing = max(0, infos.count - 1) * spacing
|
||||
@@ -128,7 +129,7 @@ extension VStack: Renderable {
|
||||
let availableForSpacers = max(0, context.availableHeight - fixedHeight - totalSpacing)
|
||||
let spacerHeight = spacerCount > 0 ? availableForSpacers / spacerCount : 0
|
||||
|
||||
// Calculate max width for alignment
|
||||
// Max width across all children determines alignment reference
|
||||
let maxWidth = infos.compactMap(\.buffer).map(\.width).max() ?? 0
|
||||
|
||||
var result = FrameBuffer()
|
||||
@@ -138,7 +139,6 @@ extension VStack: Renderable {
|
||||
let height = max(info.spacerMinLength ?? 0, spacerHeight)
|
||||
result.appendVertically(FrameBuffer(emptyWithHeight: height), spacing: spacingToApply)
|
||||
} else if let buffer = info.buffer {
|
||||
// Apply horizontal alignment
|
||||
let alignedBuffer = alignBuffer(buffer, toWidth: maxWidth, alignment: alignment)
|
||||
result.appendVertically(alignedBuffer, spacing: spacingToApply)
|
||||
}
|
||||
@@ -181,7 +181,8 @@ extension HStack: Renderable {
|
||||
public func renderToBuffer(context: RenderContext) -> FrameBuffer {
|
||||
let infos = resolveChildInfos(from: content, context: context)
|
||||
|
||||
// Count spacers and measure fixed children
|
||||
// Spacer distribution: divide remaining horizontal space equally
|
||||
// among all spacers after subtracting fixed children and inter-item spacing.
|
||||
let spacerCount = infos.filter(\.isSpacer).count
|
||||
let fixedWidth = infos.compactMap(\.buffer).reduce(0) { $0 + $1.width }
|
||||
let totalSpacing = max(0, infos.count - 1) * spacing
|
||||
|
||||
Reference in New Issue
Block a user