* Add omarchy-ascii for drawing text in the logo font Renders text as ASCII art in Delta Corps Priest 1, the FIGlet font the Omarchy wordmark itself is drawn in, so branding art can be words rather than a picture. The font is embedded in the script and the layout is done in awk, so the command adds nothing to the default package set. The layout runs on one-byte stand-ins for the five block characters the font draws with. Column arithmetic over the characters themselves counts bytes in one locale and characters in another, and the stand-ins keep length() and substr() counting columns either way. Delta Corps Priest 1 carries letters and spaces only, and every mirror of it ships the same file with the digit and punctuation glyphs empty. Anything else is dropped and named on stderr, and text with nothing drawable at all exits 1 rather than printing silence. 🤖 Generated by Opus 5 in Claude Code. * Correct what the renderer did with input it could not draw The route never ran on piped text. The metadata declared `<text...>` as required, so `omarchy ascii` with nothing on the command line resolved to the router's help while `omarchy-ascii` run directly worked, which is why the tests missed it: they all called the binary. The argument is optional now, and a test goes through the route. Text reached awk as a command-line variable, where awk reads backslash escapes of its own, so `omarchy ascii 'A\nB'` drew two blocks instead of naming the backslash as a character the font lacks. A text longer than the argument list could not be passed at all. It arrives as awk's input now, with the font on a descriptor of its own. A line with nothing drawable printed nothing at all, so a blank line between two words closed the gap up rather than keeping it. Every line draws its block now, blank ones included, which is what figlet does with a newline. Placing a glyph scanned and copied the whole width of the art so far, costing the square of the line's length: four thousand characters took forty-six seconds. A row is now held without its trailing blanks, counted separately instead, so a glyph costs its own width and those four thousand characters take a tenth of a second. A skipped control character was named on stderr by writing it out, which sends it to the terminal as a control character; those are named by code now. An unknown option was drawn as art rather than refused, so a mistyped `--width 40` quietly rendered the word "width". figlet.c trims the column of blanks that every row of an `M` shares when it is the first glyph on a line, and figlet.js keeps it. asciiart.eu runs figlet.js, so the rendering follows figlet.js and a test pins that `M`, because the wordmark alone does not catch the difference and the next reader would have no way to tell the choice from an oversight. 🤖 Generated by Opus 5 in Claude Code. Reviewed by Codex XHigh. Co-Authored-By: Codex XHigh <codex@openai.com> --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Codex XHigh <codex@openai.com>
148 lines
7.1 KiB
Bash
Executable File
148 lines
7.1 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
|
|
|
export PATH="$ROOT/bin:$PATH"
|
|
|
|
columns() {
|
|
awk 'NR == 1 { print length($0) }'
|
|
}
|
|
|
|
# The wordmark FIGlet itself draws for this font, so a change to the embedded
|
|
# font or to the kerning shows up here rather than in someone's terminal.
|
|
expected=$(
|
|
cat <<'WORDMARK'
|
|
▄██████▄ ▄▄▄▄███▄▄▄▄ ▄████████ ▄████████ ▄████████ ▄█ █▄ ▄██ ▄
|
|
███ ███ ▄██▀▀▀███▀▀▀██▄ ███ ███ ███ ███ ███ ███ ███ ███ ███ ██▄
|
|
███ ███ ███ ███ ███ ███ ███ ███ ███ ███ █▀ ███ ███ ███▄▄▄███
|
|
███ ███ ███ ███ ███ ███ ███ ▄███▄▄▄▄██▀ ███ ▄███▄▄▄▄███▄▄ ▀▀▀▀▀▀███
|
|
███ ███ ███ ███ ███ ▀███████████ ▀▀███▀▀▀▀▀ ███ ▀▀███▀▀▀▀███▀ ▄██ ███
|
|
███ ███ ███ ███ ███ ███ ███ ▀███████████ ███ █▄ ███ ███ ███ ███
|
|
███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███
|
|
▀██████▀ ▀█ ███ █▀ ███ █▀ ███ ███ ████████▀ ███ █▀ ▀█████▀
|
|
███ ███
|
|
WORDMARK
|
|
)
|
|
|
|
output=$(omarchy-ascii Omarchy)
|
|
[[ $output == "$expected" ]] || fail "the wordmark matches the reference rendering" "expected:
|
|
$expected
|
|
actual:
|
|
$output"
|
|
pass "the wordmark matches the reference rendering"
|
|
|
|
# figlet.js and figlet.c disagree about a first M: the C one trims the column of
|
|
# blanks every row of that glyph shares, the JavaScript one keeps it. asciiart.eu
|
|
# runs figlet.js, so this pins the leading blanks rather than leaving the next
|
|
# reader to "fix" them.
|
|
expected_m=$(
|
|
cat <<'LETTER_M'
|
|
▄▄▄▄███▄▄▄▄
|
|
▄██▀▀▀███▀▀▀██▄
|
|
███ ███ ███
|
|
███ ███ ███
|
|
███ ███ ███
|
|
███ ███ ███
|
|
███ ███ ███
|
|
▀█ ███ █▀
|
|
|
|
LETTER_M
|
|
)
|
|
|
|
output=$(omarchy-ascii M)
|
|
[[ $output == "$expected_m" ]] || fail "a leading M keeps the blanks figlet.js gives it" "expected:
|
|
$expected_m
|
|
actual:
|
|
$output"
|
|
pass "a leading M keeps the blanks figlet.js gives it"
|
|
|
|
output=$(printf 'Omarchy' | omarchy-ascii)
|
|
[[ $output == "$expected" ]] || fail "text can arrive on stdin"
|
|
pass "text can arrive on stdin"
|
|
|
|
# The route is the way a user reaches this, and it dispatches on whether the
|
|
# metadata says an argument is required -- so a piped run has to be exercised
|
|
# through `omarchy` itself, not just through the binary.
|
|
output=$(printf 'Omarchy' | omarchy ascii)
|
|
[[ $output == "$expected" ]] || fail "piped text renders through the omarchy route" "got:
|
|
$output"
|
|
pass "piped text renders through the omarchy route"
|
|
|
|
# The block characters are three bytes each, so the column arithmetic has to
|
|
# count columns rather than bytes wherever the locale lands.
|
|
output=$(LC_ALL=C omarchy-ascii Omarchy)
|
|
[[ $output == "$expected" ]] || fail "a byte-only locale draws the same wordmark"
|
|
pass "a byte-only locale draws the same wordmark"
|
|
|
|
blanks=$(omarchy-ascii Omarchy | grep -c ' $' || true)
|
|
[[ $blanks == "0" ]] || fail "no line is padded with trailing blanks" "$blanks lines end in a blank"
|
|
pass "no line is padded with trailing blanks"
|
|
|
|
# The space is a glyph of five hardblank columns, so it is worth exactly five
|
|
# columns of art -- not merely more than none.
|
|
tight=$(omarchy-ascii "Hi" | columns)
|
|
spaced=$(omarchy-ascii "H i" | columns)
|
|
(( tight == 18 )) || fail "Hi is 18 columns wide" "got $tight"
|
|
(( spaced == tight + 5 )) || fail "a space between words is five columns" "expected $((tight + 5)), got $spaced"
|
|
pass "a space between words is five columns"
|
|
|
|
rows=$(omarchy-ascii Hi | wc -l)
|
|
(( rows == 9 )) || fail "a block is nine rows" "got $rows"
|
|
pass "a block is nine rows"
|
|
|
|
# An empty line is a block of its own in figlet, and dropping it would silently
|
|
# close up the gap someone put there on purpose.
|
|
rows=$(printf 'A\n\nB\n' | omarchy-ascii | wc -l)
|
|
(( rows == 27 )) || fail "an empty line still draws its block" "expected 27 rows, got $rows"
|
|
pass "an empty line still draws its block"
|
|
|
|
# awk reads escapes in a variable it is given on the command line, so text has
|
|
# to reach it as input instead: a backslash is a character the font lacks, not
|
|
# the start of an escape.
|
|
rows=$(omarchy-ascii 'A\nB' 2>/dev/null | wc -l)
|
|
(( rows == 9 )) || fail "a backslash in the text is not an escape" "expected 9 rows, got $rows"
|
|
pass "a backslash in the text is not an escape"
|
|
|
|
# Delta Corps Priest 1 carries letters and spaces only. Dropping the rest in
|
|
# silence would leave a version number looking like a bug in the renderer.
|
|
status=0
|
|
warning=$(omarchy-ascii "Omarchy 4.0" 2>&1 >/dev/null) || status=$?
|
|
(( status == 0 )) || fail "text with unusable characters still draws" "exited $status"
|
|
[[ $warning == *"Skipped"* && $warning == *"4"* && $warning == *"."* && $warning == *"0"* ]] ||
|
|
fail "skipped characters are named on stderr" "got: $warning"
|
|
pass "skipped characters are named on stderr"
|
|
|
|
output=$(omarchy-ascii "Omarchy 4.0" 2>/dev/null)
|
|
[[ $output == "$expected" ]] || fail "the drawable characters still render"
|
|
pass "the drawable characters still render"
|
|
|
|
# Naming a skipped control character by writing it out would send it to the
|
|
# terminal as a control character.
|
|
warning=$(printf 'A\001B\n' | omarchy-ascii 2>&1 >/dev/null)
|
|
[[ $warning == *'\x01'* ]] || fail "a skipped control character is named by code" "got: $warning"
|
|
[[ $warning != *$'\001'* ]] || fail "a skipped control character is not written out raw"
|
|
pass "a skipped control character is named by code"
|
|
|
|
status=0
|
|
output=$(omarchy-ascii "4.0" 2>/dev/null) || status=$?
|
|
(( status == 1 )) || fail "text the font cannot draw at all fails" "exited $status"
|
|
[[ -z $output ]] || fail "text the font cannot draw at all prints nothing"
|
|
pass "text the font cannot draw at all fails"
|
|
|
|
# A mistyped option would otherwise be drawn as art, silently.
|
|
status=0
|
|
output=$(omarchy-ascii --width 40 2>&1 >/dev/null) || status=$?
|
|
(( status == 1 )) || fail "an unknown option is refused" "exited $status"
|
|
[[ $output == *"Unknown option: --width"* ]] || fail "an unknown option is named" "got: $output"
|
|
pass "an unknown option is refused"
|
|
|
|
output=$(omarchy-ascii -- Hi | columns)
|
|
(( output == 18 )) || fail "text after -- is still text" "got $output columns"
|
|
pass "text after -- is still text"
|
|
|
|
output=$(omarchy-ascii --help)
|
|
[[ $output == *"Usage: omarchy-ascii"* ]] || fail "help renders"
|
|
pass "help renders"
|