Merge pull request #16 from phranck/feature/add-inline-comments

docs: Add inline comments to complex logic (E.2)
This commit is contained in:
phranck
2026-01-30 15:47:34 +01:00
3 changed files with 30 additions and 27 deletions
+18 -17
View File
@@ -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
}
}
}
+7 -6
View File
@@ -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...])
+5 -4
View File
@@ -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