summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Sources/bar/Models/Cell.swift47
-rw-r--r--Sources/bar/bar.docc/highlighting.md12
-rw-r--r--Tests/barTests/CellTests.swift38
-rw-r--r--tasks/20261014-191535/TASK.md4
4 files changed, 66 insertions, 35 deletions
diff --git a/Sources/bar/Models/Cell.swift b/Sources/bar/Models/Cell.swift
index b7911b5..0ae324b 100644
--- a/Sources/bar/Models/Cell.swift
+++ b/Sources/bar/Models/Cell.swift
@@ -1,6 +1,4 @@
-import RegexBuilder
import SwiftUI
-import Synchronization
/// A thin wrapper around a single text line captured
/// by a block.
@@ -28,15 +26,6 @@ import Synchronization
/// within a group. For example when you want to show
/// window manager workspaces and which one is active.
struct Cell: RawRepresentable, Identifiable {
- /// Build the parser once rather than on every refresh of every cell.
- private static let pattern = Mutex(Regex {
- Optionally {
- "&!"
- Capture { OneOrMore(.digit) }
- }
- Capture { OneOrMore(.any) }
- })
-
/// A content-derived identifier combining text and highlight.
///
/// Identical cells share this value and content changes change it.
@@ -51,26 +40,26 @@ struct Cell: RawRepresentable, Identifiable {
var background: Color
init(rawValue: String) {
- guard let match = Self.pattern.withLock({ rawValue.firstMatch(of: $0) }) else {
- self.rawValue = rawValue
- self.background = .clear
- self.id = "\(rawValue):0"
- return
- }
+ var text = rawValue
+ var level = 0
- guard let rawHighlight = match.output.1,
- let highlight = Int(String(rawHighlight)),
- highlight > 0,
- highlight <= Config.highlights.count
- else {
- self.rawValue = String(match.output.2)
- self.background = .clear
- self.id = "\(self.rawValue):0"
- return
+ if rawValue.hasPrefix("&!") {
+ let suffix = rawValue.dropFirst(2)
+ // Consume every ASCII digit before interpreting the level.
+ let digits = suffix.prefix { character in
+ character.unicodeScalars.count == 1 && character >= "0" && character <= "9"
+ }
+ let body = suffix.dropFirst(digits.count)
+ if !digits.isEmpty && !body.isEmpty {
+ text = String(body)
+ if let parsed = Int(digits), parsed > 0, parsed <= Config.highlights.count {
+ level = parsed
+ }
+ }
}
- self.rawValue = String(match.output.2)
- self.background = Config.highlights[highlight - 1]
- self.id = "\(self.rawValue):\(highlight)"
+ self.rawValue = text
+ self.background = level > 0 ? Config.highlights[level - 1] : .clear
+ self.id = "\(text):\(level)"
}
}
diff --git a/Sources/bar/bar.docc/highlighting.md b/Sources/bar/bar.docc/highlighting.md
index 8075031..dc318ec 100644
--- a/Sources/bar/bar.docc/highlighting.md
+++ b/Sources/bar/bar.docc/highlighting.md
@@ -34,9 +34,11 @@ echo "&!2 workspace 2" # highlighted with Config.highlights[1]
echo "workspace 3" # no highlight
```
-> Important: A parsed `&!<level>` prefix followed by text is stripped before rendering, so only the text after it is displayed.
-> For example, `&!1 workspace 1` renders as `workspace 1` on a highlighted background.
+> Important: Only a prefix at the start of the line is recognized. Its level uses ASCII digits (`0`–`9`), and the entire digit sequence is consumed. A nonempty body must follow it. Whitespace counts as a body and is preserved exactly: `&!1 workspace 1` renders as ` workspace 1`, including the leading space.
-> Important: The highlight level is a positive integer that indexes into ``Config-swift.enum/highlights`` (1-based).
-> For a parsed prefix followed by text, zero, an out-of-range level, or a number too large to represent as an Int leaves the cell unhighlighted and removes the prefix.
-> Use a level followed by text as shown above: malformed or textless prefixes are not guaranteed to be stripped by the current parser.
+The highlight level is a positive integer that indexes into ``Config-swift.enum/highlights`` (1-based).
+With a nonempty body, zero, an out-of-range level, or an integer overflow removes the prefix but leaves the body unhighlighted.
+Leading zeroes are allowed (`&!01 text` selects level 1).
+
+Empty input, textless prefixes such as `&!1` and `&!12`, and malformed prefixes such as `&!`, `&!-1 text`, or `&!1 text` remain literal and unhighlighted.
+Embedded prefixes also remain literal, as in `text &!1 more`.
diff --git a/Tests/barTests/CellTests.swift b/Tests/barTests/CellTests.swift
new file mode 100644
index 0000000..c7aae13
--- /dev/null
+++ b/Tests/barTests/CellTests.swift
@@ -0,0 +1,38 @@
+import SwiftUI
+import Testing
+@testable import bar
+
+@Test(arguments: [
+ "", "ordinary text", "text &!1 more", " &!1 text",
+ "&!", "&!1", "&!12", "&!0", "&!999999999999999999999999999999",
+ "&! text", "&!-1 text", "&!+1 text", "&!1 text", "&!١ text",
+]) func literalCellText(_ input: String) {
+ let cell = Cell(rawValue: input)
+ #expect(cell.rawValue == input)
+ #expect(cell.background == .clear)
+ #expect(cell.id == "\(input):0")
+}
+
+@Test(arguments: ["0", "12", "999999999999999999999999999999"]) func invalidCellLevels(_ level: String) {
+ let cell = Cell(rawValue: "&!\(level) text")
+ #expect(cell.rawValue == " text")
+ #expect(cell.background == .clear)
+ #expect(cell.id == " text:0")
+}
+
+@Test func configuredCellHighlights() {
+ for level in 1...Config.highlights.count {
+ for body in ["hello", " hello", " ", "\t", "\n", "&!2 nested"] {
+ let cell = Cell(rawValue: "&!\(level)\(body)")
+ #expect(cell.rawValue == body)
+ #expect(cell.background == Config.highlights[level - 1])
+ #expect(cell.id == "\(body):\(level)")
+ }
+ }
+ let cell = Cell(rawValue: "&!01 hello")
+ #expect(cell.background == Config.highlights[0])
+ #expect(cell.rawValue == " hello")
+ let outOfRange = Cell(rawValue: "&!\(Config.highlights.count + 1) text")
+ #expect(outOfRange.rawValue == " text")
+ #expect(outOfRange.background == .clear)
+}
diff --git a/tasks/20261014-191535/TASK.md b/tasks/20261014-191535/TASK.md
index 06556ad..40f9239 100644
--- a/tasks/20261014-191535/TASK.md
+++ b/tasks/20261014-191535/TASK.md
@@ -1,6 +1,6 @@
# Parse highlight prefixes without regex backtracking surprises
-- STATUS: OPEN
+- STATUS: CLOSED
- PRIORITY: 60
- TAGS: review,bug,core
@@ -13,3 +13,5 @@ Approach: Define the contract for a prefix with no body, zero/out-of-range level
Completion checks: Cover ordinary text, valid levels, &!1, &!12, &!0 text, out-of-range and huge levels, malformed prefixes, embedded &!, empty text, and whitespace-only bodies. No partial level interpretation is possible. Preserve the existing one-based Config.highlights convention.
Design constraint: Follow README.md: keep source-based configuration, no dependencies or plugin framework, and use the smallest readable change that makes the existing behavior reliable. This is a suggestion for individual review, not a deadline. Findings were recorded on 2026-10-14; re-check the current code before implementing.
+
+Implemented an explicit leading-prefix parser with ASCII digits and no partial level interpretation. Textless and malformed prefixes remain literal; numeric prefixes with a body are stripped even when the level is invalid. Body whitespace and one-based highlight indexing are preserved. Added parser regression coverage and documented the contract. Validation: `swift test` passed all 22 tests.