aboutsummaryrefslogtreecommitdiff
path: root/Sources
diff options
context:
space:
mode:
authorTommaso Negri <me@tommasongr.com>2026-10-14 22:13:55 +0200
committerTommaso Negri <me@tommasongr.com>2026-10-14 22:13:55 +0200
commited506be5076c500f19e8a39e89867ee54007577e (patch)
tree1e9f8471ef5186f57e1a41080a7d66dd47aec4be /Sources
parent8aacd1f753c7ef21a7e1173cc08c5b0a85a94c6b (diff)
downloadbar-ed506be5076c500f19e8a39e89867ee54007577e.tar.gz
bar-ed506be5076c500f19e8a39e89867ee54007577e.zip
improve and clarify documentation
Diffstat (limited to 'Sources')
-rw-r--r--Sources/bar/Config.swift6
-rw-r--r--Sources/bar/Models/Block.swift5
-rw-r--r--Sources/bar/Models/Cell.swift13
-rw-r--r--Sources/bar/Models/HEX.swift11
-rw-r--r--Sources/bar/Models/Runner.swift18
-rw-r--r--Sources/bar/bar.docc/command.md11
-rw-r--r--Sources/bar/bar.docc/customisation.md2
-rw-r--r--Sources/bar/bar.docc/highlighting.md5
-rw-r--r--Sources/bar/bar.docc/how-it-works.md3
9 files changed, 47 insertions, 27 deletions
diff --git a/Sources/bar/Config.swift b/Sources/bar/Config.swift
index f1edf01..565459b 100644
--- a/Sources/bar/Config.swift
+++ b/Sources/bar/Config.swift
@@ -30,7 +30,8 @@ enum Config {
//
// You can use system default colors and the standard SwiftUI
// methods to define them. However, for convenience we added
- // support for hex colors too (see ``HEX``).
+ // support for hex colors too (see ``HEX``). These strings are parsed
+ // at runtime, so the compiler does not check their format.
//
// E.g: `.hex("#000000")`
@@ -110,7 +111,8 @@ extension Config {
/// The interval, in seconds, at which the command is executed.
///
/// If set to `nil`, the block will be evaluated just once
- /// at launch. You can of course trigger a manual update via
+ /// at launch. Zero and negative intervals also disable repeating updates.
+ /// You can of course trigger a manual update via
/// a notification later on.
let interval: Double?
diff --git a/Sources/bar/Models/Block.swift b/Sources/bar/Models/Block.swift
index cb09a4b..a9881f7 100644
--- a/Sources/bar/Models/Block.swift
+++ b/Sources/bar/Models/Block.swift
@@ -9,7 +9,8 @@ import Foundation
/// notifications (see ``Notifier``).
@MainActor
final class Block: ObservableObject, Identifiable {
- /// Stable identity for SwiftUI diffing.
+ /// Distinguishes this block instance in SwiftUI, even when names match.
+ /// Content updates are published separately through ``cells``.
let id = UUID()
/// Identifier used for manual updates via Darwin
@@ -70,7 +71,7 @@ final class Block: ObservableObject, Identifiable {
}
}
- /// Stop the interval timer.
+ /// Cancel future interval refreshes. Already-running commands continue.
func stop() {
tick?.cancel()
}
diff --git a/Sources/bar/Models/Cell.swift b/Sources/bar/Models/Cell.swift
index a09d1f9..d715fc2 100644
--- a/Sources/bar/Models/Cell.swift
+++ b/Sources/bar/Models/Cell.swift
@@ -9,9 +9,8 @@ import SwiftUI
/// is then laid out horizontally respecting the order.
///
/// ### Highlight
-/// Besides the underlying text value, a cell holds an
-/// highlight level (as Int) that, if true, applies the
-/// special background color defined in ``Config``.
+/// Besides the underlying text value, a cell holds a background
+/// color selected by a highlight level from ``Config``.
/// You can set the highlight at runtime by prefixing the
/// text line with the special notation `&!<level>`, where
/// `<level>` is a positive integer that can be used as an
@@ -28,11 +27,11 @@ import SwiftUI
/// within a group. For example when you want to show
/// window manager workspaces and which one is active.
struct Cell: RawRepresentable, Identifiable {
- /// Stable identity for SwiftUI diffing.
+ /// A content-derived identifier combining text and highlight.
///
- /// The id is constructed by the rawValue + highlight
- /// so that SwiftUI redraws the cell only on content
- /// change and not every time the cell is computed.
+ /// Identical cells share this value and content changes change it.
+ /// ``BlockView`` uses line positions to distinguish rendered cells;
+ /// view identity does not prevent updates to their displayed content.
let id: String
/// The represented text content.
diff --git a/Sources/bar/Models/HEX.swift b/Sources/bar/Models/HEX.swift
index a262630..5ceb393 100644
--- a/Sources/bar/Models/HEX.swift
+++ b/Sources/bar/Models/HEX.swift
@@ -14,7 +14,9 @@ import SwiftUI
///
/// Single-digit components are expanded by repeating the digit; for example,
/// `#3aF` is read as `#33AAFF`. When present, the trailing digits encode alpha
-/// (opacity); otherwise opacity defaults to `1`.
+/// (opacity); otherwise opacity defaults to `1`. Surrounding whitespace is
+/// trimmed during conversion. Unsupported lengths resolve to opaque black;
+/// characters are not fully validated, so use one of the formats above.
struct HEX {
/// The raw hex code, exactly as supplied. It is not validated or normalized;
/// parsing is performed lazily by `Color.hex(_:)`.
@@ -40,8 +42,11 @@ extension SwiftUI.Color {
/// Supported formats (the leading `#` is optional): `#RGB`, `#RGBA`,
/// `#RRGGBB`, and `#RRGGBBAA`. Single-digit components are expanded by
/// repeating the digit. When present, the trailing digits encode alpha
- /// (opacity); otherwise opacity defaults to `1`. Malformed input resolves
- /// to opaque black.
+ /// (opacity); otherwise opacity defaults to `1`. Surrounding whitespace is
+ /// trimmed. Unsupported lengths resolve to opaque black. At supported
+ /// lengths, Scanner may parse only a leading hexadecimal portion; its
+ /// success result is not checked. Invalid characters therefore do not
+ /// reliably produce opaque black (alpha formats can be transparent).
///
/// - Parameter code: A hex color code.
static func hex(_ code: String) -> SwiftUI.Color {
diff --git a/Sources/bar/Models/Runner.swift b/Sources/bar/Models/Runner.swift
index dc88049..1fb88ad 100644
--- a/Sources/bar/Models/Runner.swift
+++ b/Sources/bar/Models/Runner.swift
@@ -3,12 +3,12 @@ import Foundation
/// Runs a shell command and returns its stdout as separate lines.
///
/// Blocking — always call from a background context (e.g. `Task.detached`).
-/// A 30-second timeout prevents hanging processes from consuming
-/// cooperative pool threads indefinitely.
+/// After 30 seconds, requests termination of the shell process. This is
+/// not a hard execution limit: the shell can ignore termination, and child
+/// processes can keep output pipes open. Pipe reads and waiting can still block.
enum Runner {
- /// The maximum time (in seconds) a command is allowed to run before
- /// being killed. This prevents a single hung process from consuming
- /// a cooperative thread indefinitely.
+ /// Delay in seconds before requesting shell termination with SIGTERM.
+ /// Does not forcibly kill the shell or terminate its descendants.
private static let timeout: Double = 30
/// Run a command and returns stdout as an array of separated lines.
@@ -17,7 +17,9 @@ enum Runner {
/// - env: An optional dictionary of strings to merge into
/// the process environment.
///
- /// - Returns: An array of the text lines printed to stdout.
+ /// - Returns: Parsed stdout on success; ["ERROR"] on launch failure or
+ /// nonzero exit, or [""] if successful output cannot be decoded as UTF-8.
+ /// Captured stderr is forwarded only after a nonzero exit.
static func run(_ command: String, env: [String: String] = [:]) -> [String] {
let process = Process()
process.executableURL = URL(fileURLWithPath: "/bin/sh")
@@ -36,8 +38,8 @@ enum Runner {
return ["ERROR"]
}
- // Schedule a kill after the timeout expires.
- // If the process finishes before that, the timer is cancelled.
+ // Request shell termination after the timeout expires.
+ // Cancel the timer after pipe reads and process waiting finish.
let timer = DispatchSource.makeTimerSource()
timer.schedule(deadline: .now() + timeout)
timer.setEventHandler { [weak process] in
diff --git a/Sources/bar/bar.docc/command.md b/Sources/bar/bar.docc/command.md
index da1a71f..3196011 100644
--- a/Sources/bar/bar.docc/command.md
+++ b/Sources/bar/bar.docc/command.md
@@ -5,6 +5,9 @@ How the block's command is executed.
Each block runs its ``Config-swift.enum/Block/command`` as a shell script via `/bin/sh -c`.
The standard output is captured and **each line becomes one ``Cell``** in the bar.
Cells are laid out horizontally in the order they appear.
+One final newline is removed; other blank lines and spaces are preserved.
+A successful command with empty stdout produces no cells, hiding the block.
+Printing a newline produces a blank cell rather than hiding it.
```shell
# A single-line command produces one cell
@@ -26,7 +29,13 @@ On the contrary, if you run `bar` from a launch agent, you'll probably not have
## Error handling
If the command exits with a non-zero status or cannot be launched, the block displays a single cell containing the text `ERROR`.
-The command's stderr is forwarded to the `bar` process stderr, which you can inspect for the actual failure.
+After a non-zero exit, captured stderr is forwarded to the `bar` process stderr.
+Stderr from a successful command is discarded, and launch failures do not forward a diagnostic.
+Successful stdout that cannot be decoded as UTF-8 produces a blank cell.
+
+After 30 seconds, *bar* requests termination of the shell with SIGTERM.
+This is not a hard deadline: a shell can ignore the signal, and child processes can keep the output pipes open.
+The current runner reads stdout and then stderr before waiting for exit, so commands with enough stderr output can also block while stdout is being read.
```shell
# Example: simulate a command failure
diff --git a/Sources/bar/bar.docc/customisation.md b/Sources/bar/bar.docc/customisation.md
index 602f29a..e006fa3 100644
--- a/Sources/bar/bar.docc/customisation.md
+++ b/Sources/bar/bar.docc/customisation.md
@@ -29,7 +29,7 @@ enum Config {
## HEX Colors
-You can use any standard SwiftUI color. For convenience, we also provide the ``HEX`` type for defining colors by hex code directly in source:
+You can use any standard SwiftUI color. For convenience, `Color.hex(_:)` parses hex strings directly in source, and ``HEX`` wraps a stored hex code:
```swift
static let foreground: Color = .hex("#CDD6F4")
diff --git a/Sources/bar/bar.docc/highlighting.md b/Sources/bar/bar.docc/highlighting.md
index aa2ad0d..8075031 100644
--- a/Sources/bar/bar.docc/highlighting.md
+++ b/Sources/bar/bar.docc/highlighting.md
@@ -34,8 +34,9 @@ echo "&!2 workspace 2" # highlighted with Config.highlights[1]
echo "workspace 3" # no highlight
```
-> Important: The `&!<level>` notation is stripped before rendering, so only the text after it is displayed.
+> 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: The highlight level is a positive integer that indexes into ``Config-swift.enum/highlights`` (1-based).
-> If the level exceeds the number of defined highlights, the cell is treated as unhighlighted.
+> 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.
diff --git a/Sources/bar/bar.docc/how-it-works.md b/Sources/bar/bar.docc/how-it-works.md
index ab8216a..d9c4bd4 100644
--- a/Sources/bar/bar.docc/how-it-works.md
+++ b/Sources/bar/bar.docc/how-it-works.md
@@ -15,7 +15,8 @@ You're supposed to fully understand how it works, make it yours, and ultimately
*bar* does not read a configuration file somewhere on your system.
Instead, configuration happens directly in the source code by editing ``Config`` and rebuilding the software.
-This approach allows us to keep the software extremely minimal and reliable, since all the possible errors are caught at build time.
+This keeps configuration simple and lets the Swift compiler catch syntax and type errors when you build.
+Shell commands and string values, such as hex color codes, are interpreted at runtime, so you still need to check their output and behavior.
## No pre-built binaries