Skip to content

Emoji: OpenEmoji built in and on by default, plus the font installer and inline art - #96

Merged
ralyodio merged 2 commits into
mainfrom
openemoji-pack
Sep 24, 2026
Merged

ralyodio merged 2 commits into
mainfrom
openemoji-pack

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Stacked on #95 (OpenIcon), so the two land together. Retarget to main once #95 merges.

The pack. OpenEmoji (every standard emoji, 3,963 in Emoji 18.0) is built in and on by default, next to OpenIcon.

  • scripts/generate-emoji.ts writes one table for TypeScript, Go, Python and Rust, about 270 KB each (skin-tone variants stored as key plus base, shortcodes only where they differ from the name, the ten rarest CLDR keywords).
  • TypeScript API: emoji(), emojify(":tada:"), emojiSearch("lol"), emojiInfo(), emojiText(), setEmojiMode(), HQTUI_EMOJI=emoji|text.
  • Ports: Go Emoji/EmojiIn/Emojify/EmojiSearch, Python emoji/emojify/emoji_search, Rust emoji/emoji_in/emojify/emoji_search.
  • Text fallback: an emoticon where one fits (:), <3), otherwise [name]. The Linux console gets text.

Width, in every port. An emoji is now one two-column cell in TS, Go, Rust, Python, Zig and C:

  • skin tones join their base (👍🏽 was 4 columns);
  • flags pair, and a third regional indicator stands alone;
  • subdivision-flag tags join (🏴󠁧󠁢󠁥󠁮󠁧󠁿);
  • U+FE0F, keycaps and a skin tone make a text-default pictograph 2 wide (❤️, #️⃣, ☝🏽).

Cell width and measured width share one rule, including when the cluster table is full. The conformance fixtures gain these cases. screen.json/input.json already drift from the generator on openicon-pack itself; that drift is left alone.

hqtui fonts install | status | remove (TypeScript; runs only on that explicit command):

  • Downloads the OpenEmoji colour font from the set's release (falling back to the repository, with a clear error if neither has it): CBDT into ~/.local/share/fonts on Linux, sbix into ~/Library/Fonts on macOS.
  • Linux fontconfig: OpenEmoji is the emoji family, the other emoji families alias to it, and it is appended to monospace/sans/serif so digits stay text. Then fc-cache.
  • Prints the Kitty symbol_map and WezTerm font_with_fallback lines, and on macOS the iTerm2 setting and the Terminal.app caveat.
  • Backs up any file it edits as <name>.bak-001.<ext> in ~/.config/hqtui/backups, outside conf.d. remove undoes everything and restores those files.

emojiImage() draws the artwork inline (Kitty graphics in Kitty/Ghostty, iTerm2 images in iTerm2/WezTerm).

  • Off unless HQTUI_EMOJI_ART=1; tmux and every other terminal get the character.
  • PNG size is 2× the cell's pixel height (from CSI 16 t or HQTUI_CELL_PX), chosen from 128/256/512, cached under XDG_CACHE_HOME.
  • Node modules load lazily, so importing hqtui stays side-effect free.

Docs: an Emoji section on hqtui.com/docs and in the package README, including the xterm.js openemoji.css note.

Tests run locally:

  • TypeScript: 357 pass under Bun, and emoji plus unicode pass under Node. The one demo failure is this worktree's demo resolving hqtui to an older build; CI installs fresh.
  • Go -race, Rust (46 + 17 demo), Python (45), Zig (16), and C ctest with conformance all pass.
  • Typecheck and web typecheck are clean.

What was actually verified:

  • fonts install ran with real fontconfig in a sandbox home: fc-match gave OpenEmoji for emoji and U+1F525, while the digit 7 stayed DejaVu Sans Mono. remove restored the original.
  • No terminal emulator was driven. The Kitty and iTerm2 escape sequences are tested byte by byte, not on screen.

🤖 Generated with Claude Code

@ralyodio
ralyodio marked this pull request as ready for review September 24, 2026 07:04
@ralyodio
ralyodio added this pull request to stack #97 September 24, 2026 07:18
Base automatically changed from openicon-pack to main September 24, 2026 07:30
ralyodio and others added 2 commits September 24, 2026 00:30
…best it can

The OpenEmoji pack (every standard emoji, 3,963 in Emoji 18.0) ships beside
OpenIcon, generated by scripts/generate-emoji.ts into one table for the
TypeScript library and the Go, Python and Rust ports (about 270 KB each):
emoji(), emojify(":tada:"), emojiSearch("lol"), emojiInfo(), setEmojiMode()
and HQTUI_EMOJI=emoji|text. Text is an emoticon where one fits and the name in
brackets elsewhere; the Linux console gets text.

Width: emoji are one two-column cell in every port (TS, Go, Rust, Python, Zig,
C): skin tones join their base, regional indicators pair into flags, tag
sequences join, and U+FE0F, keycaps and a skin tone make a text-default
pictograph two columns (❤️, #️⃣, ☝🏽). Cell width and measured width share one
rule, including when the cluster table is full. Conformance fixtures gain the
emoji cases; unrelated pre-existing drift in screen.json/input.json is left.

TypeScript also gets:
- hqtui fonts install|status|remove and installEmojiFont(): the OpenEmoji
  colour font (CBDT on Linux, sbix on macOS) from the set's release, falling
  back to the repository, wired through fontconfig (emoji family, other emoji
  families aliased, appended to text families so digits stay text), with
  Kitty/WezTerm/iTerm2 snippets, backups as <name>.bak-001.<ext> outside
  conf.d, and a record that remove undoes. Only on the explicit command.
- emojiImage(): the artwork inline via the Kitty graphics protocol (Kitty,
  Ghostty) or iTerm2 images (iTerm2, WezTerm), off unless HQTUI_EMOJI_ART=1,
  PNG size from the cell's pixel height x2 (128/256/512, CSI 16 t or
  HQTUI_CELL_PX), cached under XDG_CACHE_HOME. Node modules load lazily, so
  importing hqtui stays side-effect free.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ay the code does

Windows CI caught both: the fallback used the process's emoji mode (text on
the runner) instead of the env passed in, and the tests expected path.join's
backslashes where the code joins with /.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ralyodio
ralyodio merged commit cb0d8f6 into main Sep 24, 2026
18 checks passed
@ralyodio
ralyodio deleted the openemoji-pack branch September 24, 2026 07:41
ralyodio added a commit to profullstack/cli-tools that referenced this pull request Sep 24, 2026
…nt (0.45.2) (#87)

`gh pr merge` calls the GraphQL mergePullRequest mutation, and GitHub refuses
that mutation outright for a pull request that belongs to a stack, naming the
asynchronous merge REST API instead. Nothing is wrong with such a PR: it reads
MERGEABLE and CLEAN with every check green, so no repair applies and the sweep
just reported FAILED and merged nothing.

`Gh.squashMerge` now falls back to PUT /repos/{owner}/{repo}/pulls/{n}/merge-async
and polls the uuid it returns until the merge settles. The fallback is narrow
on purpose: it fires only on that one refusal message, still pins the head
commit, still asks for a squash, and still passes no --admin, so a PR is held
to exactly the rules it was held to before. A PR the endpoint hands to a merge
queue reports enqueued, which counts as merged because nothing further is ours
to do.

The refusal is matched on the message rather than on the base branch: GitHub
still calls a PR stacked after it has retargeted it onto the default branch,
which is how profullstack/hqtui#96 behaved in practice.

The shell original in profullstack/scripts got the same fix (v0.3.2) and is
being retired in favour of this one.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
ralyodio added a commit that referenced this pull request Sep 24, 2026
The version sites that no build step touches, moved together: the library
and demo package.json, the CLI's VERSION, the demo's --version string, the
site badge, and the workspace ranges in bun.lock.

A minor rather than a patch because the public API grew: icon() and emoji()
landed in #95 and #96, along with `hqtui fonts install`.

The three ^0.6.2 ranges in apps/web, apps/benchmark and examples move too.
A caret below 1.0.0 stops at <0.7.0, so left alone they would declare a
range the library in this tree no longer satisfies.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant