From 72f69c81bce52ad970b9d690da7ad6263b24ac8f Mon Sep 17 00:00:00 2001
From: Daniel Tull
Date: Tue, 17 Dec 2024 17:21:43 +0000
Subject: [PATCH 1/4] Ensure Text's x-axis is also 1-based
This is to match the way Color and (the Text y-axis) works.
---
Sources/TerminalUI/Views/Text.swift | 2 +-
Tests/TerminalUITests/AppTests.swift | 4 ++--
Tests/TerminalUITests/EnvironmentTests.swift | 16 ++++++++--------
Tests/TerminalUITests/ViewModifierTests.swift | 2 +-
.../ViewModifiers/BackgroundColor.swift | 2 +-
.../ViewModifiers/BlinkingTests.swift | 2 +-
.../ViewModifiers/BoldTests.swift | 2 +-
.../ViewModifiers/ForegroundColorTests.swift | 2 +-
.../ViewModifiers/HiddenTests.swift | 2 +-
.../ViewModifiers/InverseTests.swift | 2 +-
.../ViewModifiers/ItalicTests.swift | 2 +-
.../ViewModifiers/StrikethroughTests.swift | 2 +-
.../ViewModifiers/UnderlineTests.swift | 2 +-
Tests/TerminalUITests/Views/TextTests.swift | 10 +++++-----
14 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/Sources/TerminalUI/Views/Text.swift b/Sources/TerminalUI/Views/Text.swift
index 3634932..cb16be6 100644
--- a/Sources/TerminalUI/Views/Text.swift
+++ b/Sources/TerminalUI/Views/Text.swift
@@ -21,7 +21,7 @@ public struct Text: Builtin, View {
hidden: environment.hidden,
strikethrough: environment.strikethrough
)
- canvas.draw(pixel, at: Position(x: Horizontal(index), y: 0))
+ canvas.draw(pixel, at: Position(x: Horizontal(index), y: 1))
}
}
}
diff --git a/Tests/TerminalUITests/AppTests.swift b/Tests/TerminalUITests/AppTests.swift
index 0320210..d6d01a4 100644
--- a/Tests/TerminalUITests/AppTests.swift
+++ b/Tests/TerminalUITests/AppTests.swift
@@ -32,7 +32,7 @@ struct AppTests {
"[27m", // Inverse off
"[28m", // Hidden off
"[29m", // Strikethrough off
- "[0;1Ha", // Position + content
+ "[1;1Ha", // Position + content
])
}
@@ -63,7 +63,7 @@ struct AppTests {
"[27m", // Inverse off
"[28m", // Hidden off
"[29m", // Strikethrough off
- "[0;1Ha", // Position + content
+ "[1;1Ha", // Position + content
])
}
}
diff --git a/Tests/TerminalUITests/EnvironmentTests.swift b/Tests/TerminalUITests/EnvironmentTests.swift
index 564a06d..53cfed6 100644
--- a/Tests/TerminalUITests/EnvironmentTests.swift
+++ b/Tests/TerminalUITests/EnvironmentTests.swift
@@ -15,13 +15,13 @@ struct EnvironmentTests {
}
#expect(canvas.pixels == [
- Position(x: 1, y: 0): Pixel("d"),
- Position(x: 2, y: 0): Pixel("e"),
- Position(x: 3, y: 0): Pixel("f"),
- Position(x: 4, y: 0): Pixel("a"),
- Position(x: 5, y: 0): Pixel("u"),
- Position(x: 6, y: 0): Pixel("l"),
- Position(x: 7, y: 0): Pixel("t"),
+ Position(x: 1, y: 1): Pixel("d"),
+ Position(x: 2, y: 1): Pixel("e"),
+ Position(x: 3, y: 1): Pixel("f"),
+ Position(x: 4, y: 1): Pixel("a"),
+ Position(x: 5, y: 1): Pixel("u"),
+ Position(x: 6, y: 1): Pixel("l"),
+ Position(x: 7, y: 1): Pixel("t"),
])
}
@@ -33,7 +33,7 @@ struct EnvironmentTests {
}
#expect(canvas.pixels == [
- Position(x: 1, y: 0): Pixel("b"),
+ Position(x: 1, y: 1): Pixel("b"),
])
}
}
diff --git a/Tests/TerminalUITests/ViewModifierTests.swift b/Tests/TerminalUITests/ViewModifierTests.swift
index c84c194..2d946ee 100644
--- a/Tests/TerminalUITests/ViewModifierTests.swift
+++ b/Tests/TerminalUITests/ViewModifierTests.swift
@@ -33,7 +33,7 @@ struct ViewModifierTests {
"[27m", // Inverse off
"[28m", // Hidden off
"[29m", // Strikethrough off
- "[0;1HA", // Position + content
+ "[1;1HA", // Position + content
])
}
}
diff --git a/Tests/TerminalUITests/ViewModifiers/BackgroundColor.swift b/Tests/TerminalUITests/ViewModifiers/BackgroundColor.swift
index 4f4eb89..90471f2 100644
--- a/Tests/TerminalUITests/ViewModifiers/BackgroundColor.swift
+++ b/Tests/TerminalUITests/ViewModifiers/BackgroundColor.swift
@@ -38,7 +38,7 @@ struct BackgroundColorTests {
"[27m", // Inverse off
"[28m", // Hidden off
"[29m", // Strikethrough off
- "[0;1Ha", // Position + content
+ "[1;1Ha", // Position + content
])
}
}
diff --git a/Tests/TerminalUITests/ViewModifiers/BlinkingTests.swift b/Tests/TerminalUITests/ViewModifiers/BlinkingTests.swift
index 363c67f..819714c 100644
--- a/Tests/TerminalUITests/ViewModifiers/BlinkingTests.swift
+++ b/Tests/TerminalUITests/ViewModifiers/BlinkingTests.swift
@@ -31,7 +31,7 @@ struct BlinkingTests {
"[27m", // Inverse off
"[28m", // Hidden off
"[29m", // Strikethrough off
- "[0;1Ha", // Position + content
+ "[1;1Ha", // Position + content
])
}
}
diff --git a/Tests/TerminalUITests/ViewModifiers/BoldTests.swift b/Tests/TerminalUITests/ViewModifiers/BoldTests.swift
index 42b3aba..7af02d0 100644
--- a/Tests/TerminalUITests/ViewModifiers/BoldTests.swift
+++ b/Tests/TerminalUITests/ViewModifiers/BoldTests.swift
@@ -31,7 +31,7 @@ struct BoldTests {
"[27m", // Inverse off
"[28m", // Hidden off
"[29m", // Strikethrough off
- "[0;1Ha", // Position + content
+ "[1;1Ha", // Position + content
])
}
}
diff --git a/Tests/TerminalUITests/ViewModifiers/ForegroundColorTests.swift b/Tests/TerminalUITests/ViewModifiers/ForegroundColorTests.swift
index c72462e..8fd6634 100644
--- a/Tests/TerminalUITests/ViewModifiers/ForegroundColorTests.swift
+++ b/Tests/TerminalUITests/ViewModifiers/ForegroundColorTests.swift
@@ -38,7 +38,7 @@ struct ForegroundColorTests {
"[27m", // Inverse off
"[28m", // Hidden off
"[29m", // Strikethrough off
- "[0;1Ha", // Position + content
+ "[1;1Ha", // Position + content
])
}
}
diff --git a/Tests/TerminalUITests/ViewModifiers/HiddenTests.swift b/Tests/TerminalUITests/ViewModifiers/HiddenTests.swift
index ade9e75..c5dc163 100644
--- a/Tests/TerminalUITests/ViewModifiers/HiddenTests.swift
+++ b/Tests/TerminalUITests/ViewModifiers/HiddenTests.swift
@@ -31,7 +31,7 @@ struct HiddenTests {
"[27m", // Inverse off
expected, // Hidden
"[29m", // Strikethrough off
- "[0;1Ha", // Position + content
+ "[1;1Ha", // Position + content
])
}
}
diff --git a/Tests/TerminalUITests/ViewModifiers/InverseTests.swift b/Tests/TerminalUITests/ViewModifiers/InverseTests.swift
index bdebd08..0aca36b 100644
--- a/Tests/TerminalUITests/ViewModifiers/InverseTests.swift
+++ b/Tests/TerminalUITests/ViewModifiers/InverseTests.swift
@@ -31,7 +31,7 @@ struct InverseTests {
expected, // Inverse
"[28m", // Hidden off
"[29m", // Strikethrough off
- "[0;1Ha", // Position + content
+ "[1;1Ha", // Position + content
])
}
}
diff --git a/Tests/TerminalUITests/ViewModifiers/ItalicTests.swift b/Tests/TerminalUITests/ViewModifiers/ItalicTests.swift
index 65c715c..57c4af6 100644
--- a/Tests/TerminalUITests/ViewModifiers/ItalicTests.swift
+++ b/Tests/TerminalUITests/ViewModifiers/ItalicTests.swift
@@ -31,7 +31,7 @@ struct ItalicTests {
"[27m", // Inverse off
"[28m", // Hidden off
"[29m", // Strikethrough off
- "[0;1Ha", // Position + content
+ "[1;1Ha", // Position + content
])
}
}
diff --git a/Tests/TerminalUITests/ViewModifiers/StrikethroughTests.swift b/Tests/TerminalUITests/ViewModifiers/StrikethroughTests.swift
index ea1a80b..921f949 100644
--- a/Tests/TerminalUITests/ViewModifiers/StrikethroughTests.swift
+++ b/Tests/TerminalUITests/ViewModifiers/StrikethroughTests.swift
@@ -31,7 +31,7 @@ struct StrikethroughTests {
"[27m", // Inverse off
"[28m", // Hidden off
expected, // Strikethrough
- "[0;1Ha", // Position + content
+ "[1;1Ha", // Position + content
])
}
}
diff --git a/Tests/TerminalUITests/ViewModifiers/UnderlineTests.swift b/Tests/TerminalUITests/ViewModifiers/UnderlineTests.swift
index 0f8ecc1..acd9977 100644
--- a/Tests/TerminalUITests/ViewModifiers/UnderlineTests.swift
+++ b/Tests/TerminalUITests/ViewModifiers/UnderlineTests.swift
@@ -31,7 +31,7 @@ struct UnderlineTests {
"[27m", // Inverse off
"[28m", // Hidden off
"[29m", // Strikethrough off
- "[0;1Ha", // Position + content
+ "[1;1Ha", // Position + content
])
}
}
diff --git a/Tests/TerminalUITests/Views/TextTests.swift b/Tests/TerminalUITests/Views/TextTests.swift
index df87a20..18186c2 100644
--- a/Tests/TerminalUITests/Views/TextTests.swift
+++ b/Tests/TerminalUITests/Views/TextTests.swift
@@ -15,11 +15,11 @@ struct TextTests {
}
#expect(canvas.pixels == [
- Position(x: 1, y: 0): Pixel("H"),
- Position(x: 2, y: 0): Pixel("e"),
- Position(x: 3, y: 0): Pixel("l"),
- Position(x: 4, y: 0): Pixel("l"),
- Position(x: 5, y: 0): Pixel("o"),
+ Position(x: 1, y: 1): Pixel("H"),
+ Position(x: 2, y: 1): Pixel("e"),
+ Position(x: 3, y: 1): Pixel("l"),
+ Position(x: 4, y: 1): Pixel("l"),
+ Position(x: 5, y: 1): Pixel("o"),
])
}
}
From 417c26423d92f160b3744197f52901c80e51c334 Mon Sep 17 00:00:00 2001
From: Daniel Tull
Date: Tue, 17 Dec 2024 17:51:10 +0000
Subject: [PATCH 2/4] Add an origin to Position
---
Sources/TerminalUI/Primitives/Position.swift | 8 ++++++--
Tests/TerminalUITests/Primitives/PositionTests.swift | 11 +++++++++++
2 files changed, 17 insertions(+), 2 deletions(-)
create mode 100644 Tests/TerminalUITests/Primitives/PositionTests.swift
diff --git a/Sources/TerminalUI/Primitives/Position.swift b/Sources/TerminalUI/Primitives/Position.swift
index 01bbe3f..1f21eb6 100644
--- a/Sources/TerminalUI/Primitives/Position.swift
+++ b/Sources/TerminalUI/Primitives/Position.swift
@@ -1,7 +1,7 @@
public struct Position: Equatable, Hashable {
- let x: Horizontal
- let y: Vertical
+ package let x: Horizontal
+ package let y: Vertical
public init(x: Horizontal, y: Vertical) {
self.x = x
@@ -9,6 +9,10 @@ public struct Position: Equatable, Hashable {
}
}
+extension Position {
+ package static var origin: Position { Position(x: 1, y: 1) }
+}
+
extension Position {
var controlSequence: ControlSequence {
"\(y);\(x)H"
diff --git a/Tests/TerminalUITests/Primitives/PositionTests.swift b/Tests/TerminalUITests/Primitives/PositionTests.swift
new file mode 100644
index 0000000..8959a10
--- /dev/null
+++ b/Tests/TerminalUITests/Primitives/PositionTests.swift
@@ -0,0 +1,11 @@
+import TerminalUI
+import Testing
+
+@Suite("Position") struct PositionTests {
+
+ @Test("origin")
+ func origin() async throws {
+ #expect(Position.origin.x == 1)
+ #expect(Position.origin.y == 1)
+ }
+}
From eda9a6915cb184ee6d8feb733688e362683d9fbd Mon Sep 17 00:00:00 2001
From: Daniel Tull
Date: Tue, 17 Dec 2024 17:30:48 +0000
Subject: [PATCH 3/4] Fix implementations of Strideable
---
.../TerminalUI/Primitives/Dimensions.swift | 8 ++++----
.../Primitives/DimensionsTests.swift | 20 +++++++++++++++++++
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/Sources/TerminalUI/Primitives/Dimensions.swift b/Sources/TerminalUI/Primitives/Dimensions.swift
index 570ff33..7200276 100644
--- a/Sources/TerminalUI/Primitives/Dimensions.swift
+++ b/Sources/TerminalUI/Primitives/Dimensions.swift
@@ -36,11 +36,11 @@ extension Horizontal: ExpressibleByIntegerLiteral {
extension Horizontal: Strideable {
public func advanced(by n: Int) -> Horizontal {
- Horizontal(value: value + n)
+ Horizontal(value: value.advanced(by: n))
}
public func distance(to other: Horizontal) -> Int {
- value - other.value
+ value.distance(to: other.value)
}
}
@@ -87,11 +87,11 @@ extension Vertical: ExpressibleByIntegerLiteral {
extension Vertical: Strideable {
public func advanced(by n: Int) -> Vertical {
- Vertical(value: value + n)
+ Vertical(value: value.advanced(by: n))
}
public func distance(to other: Vertical) -> Int {
- value - other.value
+ value.distance(to: other.value)
}
}
diff --git a/Tests/TerminalUITests/Primitives/DimensionsTests.swift b/Tests/TerminalUITests/Primitives/DimensionsTests.swift
index abb55da..b007bd9 100644
--- a/Tests/TerminalUITests/Primitives/DimensionsTests.swift
+++ b/Tests/TerminalUITests/Primitives/DimensionsTests.swift
@@ -40,6 +40,16 @@ import Testing
#expect(horizontals.next() == 3)
#expect(horizontals.next() == nil)
}
+
+ @Test("Strideable: advanced(by:)", arguments: [-1, 0, 1], [-1, 0, 1])
+ func strideable_advancedBy(start: Int, n: Int) {
+ #expect(Horizontal(start).advanced(by: n) == Horizontal(start.advanced(by: n)))
+ }
+
+ @Test("Strideable: distance(to:)", arguments: [-1, 0, 1], [-1, 0, 1])
+ func strideable_distanceTo(x: Int, y: Int) {
+ #expect(Horizontal(x).distance(to: Horizontal(y)) == x.distance(to: y))
+ }
@Test("init(some BinaryInteger)")
func initBinaryInteger() {
@@ -85,6 +95,16 @@ import Testing
#expect(verticals.next() == nil)
}
+ @Test("Strideable: advanced(by:)", arguments: [-1, 0, 1], [-1, 0, 1])
+ func strideable_advancedBy(start: Int, n: Int) {
+ #expect(Vertical(start).advanced(by: n) == Vertical(start.advanced(by: n)))
+ }
+
+ @Test("Strideable: distance(to:)", arguments: [-1, 0, 1], [-1, 0, 1])
+ func strideable_distanceTo(x: Int, y: Int) {
+ #expect(Vertical(x).distance(to: Vertical(y)) == x.distance(to: y))
+ }
+
@Test("init(some BinaryInteger)")
func initBinaryInteger() {
let value: Int = Int.random(in: 0..<1_000_000)
From e7c3421fda4b0ba1479b1f1a34bede7e9d4be768 Mon Sep 17 00:00:00 2001
From: Daniel Tull
Date: Tue, 17 Dec 2024 16:51:55 +0000
Subject: [PATCH 4/4] Add debug output to the test canvas
---
Sources/TerminalUI/Primitives/Pixel.swift | 2 +-
Sources/TerminalUI/Primitives/Size.swift | 4 ++--
Sources/TerminalUITesting/TestCanvas.swift | 23 +++++++++++++++++++
.../Testing/TestCanvasTests.swift | 19 +++++++++++++++
4 files changed, 45 insertions(+), 3 deletions(-)
create mode 100644 Tests/TerminalUITests/Testing/TestCanvasTests.swift
diff --git a/Sources/TerminalUI/Primitives/Pixel.swift b/Sources/TerminalUI/Primitives/Pixel.swift
index f315f86..0b98bd2 100644
--- a/Sources/TerminalUI/Primitives/Pixel.swift
+++ b/Sources/TerminalUI/Primitives/Pixel.swift
@@ -1,7 +1,7 @@
public struct Pixel: Equatable {
- let content: Character
+ package let content: Character
let foreground: Color
let background: Color
let bold: Bold
diff --git a/Sources/TerminalUI/Primitives/Size.swift b/Sources/TerminalUI/Primitives/Size.swift
index 5195103..45771a1 100644
--- a/Sources/TerminalUI/Primitives/Size.swift
+++ b/Sources/TerminalUI/Primitives/Size.swift
@@ -2,8 +2,8 @@ import Foundation
package struct Size {
- let width: Horizontal
- let height: Vertical
+ package let width: Horizontal
+ package let height: Vertical
package init(width: Horizontal, height: Vertical) {
self.width = width
diff --git a/Sources/TerminalUITesting/TestCanvas.swift b/Sources/TerminalUITesting/TestCanvas.swift
index d26b5b6..4b9c804 100644
--- a/Sources/TerminalUITesting/TestCanvas.swift
+++ b/Sources/TerminalUITesting/TestCanvas.swift
@@ -17,3 +17,26 @@ extension TestCanvas {
content()._render(in: self, size: size)
}
}
+
+extension TestCanvas: CustomStringConvertible {
+
+ public var description: String {
+
+ let origin = Position.origin
+ let ys = (origin.y...size.height)
+ let xs = (origin.x...size.width)
+
+ var characters: [[Character]] = ys.map { _ in xs.map { _ in " " } }
+
+ for (position, pixel) in pixels {
+ guard ys.contains(position.y) && xs.contains(position.x) else { continue }
+ let y = origin.y.distance(to: position.y)
+ let x = origin.x.distance(to: position.x)
+ characters[y][x] = pixel.content
+ }
+
+ return characters
+ .map { String($0) }
+ .joined(separator: "\n")
+ }
+}
diff --git a/Tests/TerminalUITests/Testing/TestCanvasTests.swift b/Tests/TerminalUITests/Testing/TestCanvasTests.swift
new file mode 100644
index 0000000..3fec233
--- /dev/null
+++ b/Tests/TerminalUITests/Testing/TestCanvasTests.swift
@@ -0,0 +1,19 @@
+import TerminalUI
+import TerminalUITesting
+import Testing
+
+@Suite("TestCanvas")
+struct TestCanvasTests {
+
+ @Test("CustomStringConvertible")
+ func customStringConvertible() async throws {
+
+ let canvas = TestCanvas(width: 5, height: 1)
+
+ canvas.render {
+ Text("hello")
+ }
+
+ #expect(canvas.description == "hello")
+ }
+}