Add omarchy-capture-code for themed code screenshots - #6479
Open
ryuhzk wants to merge 1 commit into
Open
Conversation
Author
Contributor
There was a problem hiding this comment.
Pull request overview
Adds themed clipboard-to-code-image capture to Omarchy.
Changes:
- Adds Silicon-based rendering, language detection, theme caching, and image processing.
- Integrates capture into packages, shortcuts, and menus.
- Adds comprehensive shell tests.
Tip
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
bin/omarchy-capture-code |
Implements code-image capture. |
default/silicon/omarchy.tmTheme.tpl |
Defines syntax highlighting colors. |
default/hypr/bindings/utilities.lua |
Adds the keyboard shortcut. |
default/omarchy/omarchy-menu.jsonc |
Adds the capture menu entry. |
install/omarchy-base.packages |
Adds Silicon to installations. |
test/shell.d/capture-code-test.sh |
Tests capture behavior and theming. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| rust | ||
| tensaku | ||
| sddm | ||
| silicon |
Turns the clipboard into a shareable code image rendered with silicon, styled from the active Omarchy theme rather than a bundled palette. The theme is generated from the same colors.toml the rest of the desktop reads, into a tmTheme cached under XDG_CACHE_HOME and re-rendered when the theme changes. A theme may ship its own silicon.tmTheme to override it. Corners are rounded and stroked in the theme's accent colour by a masked ImageMagick pass, which degrades to silicon's plain image if it fails. The font family follows fc-match monospace, so `omarchy font set` changes the output the same way `omarchy theme set` does. OMARCHY_CODE_FONT, OMARCHY_CODE_FONT_SIZE, OMARCHY_CODE_PADDING and OMARCHY_CODE_CORNER_RADIUS override the defaults. Language comes from the focused window title, then from content markers that are proof rather than inference — shebangs, <?php, package+func. Anything ambiguous asks with gum instead of guessing, because a miss costs one keypress while a wrong guess silently renders the wrong highlighting. Without a controlling terminal the command relaunches itself in a floating terminal to run that picker, carrying its settings across explicitly: uwsm-app passes only argv to the app daemon, so the environment is otherwise lost.
Author
|
BTW, this code syntax highlighting theme follows Omarchy's theme. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




Adds
omarchy-capture-code, which turns code on the clipboard into a PNG matching the active Omarchy theme — saved to the screenshot directory and copied to the clipboard, ready to paste into a chat or a post.Bound to
SUPER + SHIFT + PRINT, and added toTrigger → Capturealongside Screenshot / Screenrecord / Text / Color.siliconis added toinstall/omarchy-base.packagesfor fresh installs, and a migration installs it for existing users — the update path ispacman -Syuplus migrations, and does not read that manifest.Rendering is done by
silicon, which is in the official repos, works offline, and depends only onfontconfig freetype2 harfbuzz oniguruma— so it brings no browser or network round-trip into the capture path, and harfbuzz already handles ligatures, CJK mixing and monospace alignment.Theming
The theme is rendered on demand from
default/silicon/omarchy.tmTheme.tpland cached at~/.cache/omarchy/silicon.tmTheme, invalidated by an mtime comparison against the active theme'scolors.toml. A theme may ship its ownsilicon.tmThemeto override it entirely.It is deliberately not in the
default/themed/pipeline. Everything there is config for an application the user lives in, regenerated on every theme switch.siliconis a one-shot renderer that exists for a few hundred milliseconds; putting it there would make every user pay a render on every theme switch for a feature most never invoke.The template carries the full
tokenColorsset from the existingdefault/themed/vscode-theme.json.tpl— same TextMate scope vocabulary, includingfontStyle— so a capture matches the highlighting the user already sees in their editor rather than a reduced subset.silicon --themeaccepts a filesystem path, so no syntect cache build is involved.The font family follows
fc-match monospacerather than being hardcoded, soomarchy font setchanges captures the same wayomarchy theme setdoes.OMARCHY_CODE_FONT,OMARCHY_CODE_FONT_SIZE,OMARCHY_CODE_PADDINGandOMARCHY_CODE_CORNER_RADIUSoverride the defaults.Language detection
siliconneeds--languagefor clipboard input, and its own fallback only matches shebang-style first lines — with no default, so detection failure is a hard error. That is the common case for a mid-file snippet, so detection runs first, in three stages:hyprctl activewindow. Editors put the filename there, and so does GitHub in a browser.<?php,package+func,<!DOCTYPE html.gum filterpicker.Stage 2 only accepts markers that are proof, never inference. Rules keyed on type annotations,
def, or::were written and then removed: across 15 sample files they read C++ as TypeScript and Ruby as Python. A miss costs one keypress in the picker; a wrong guess silently renders the snippet highlighted as the wrong language, and nothing in the result tells the user it happened. The two snippets that were mislabelled are pinned as test cases.Two details worth calling out:
The value passed to
-lis a file extension, not a language name, because syntect'sfind_syntax_by_tokenmatches extensions first.bat --list-languagesis tempting as a name source but ships syntaxes absent from syntect's default set, which would produceUnsupported language.An extension taken from a window title is accepted only if it is in a known list. Window titles are full of dots that are not filenames — domains, version numbers, sentence ends — and without the list a browser tab yields a nonsense language.
The picker needs a terminal, and neither the keybinding nor the menu entry has one, so the command hands itself off to a floating terminal when it needs to prompt — by resolved absolute path, not by name. Naming it bare leaves the user looking at an empty terminal reporting the executable as missing, with no notification, because the terminal spawn itself succeeded.
That handoff also carries the resolved appearance settings across as explicit assignments.
uwsm-appwrites only argv to the app daemon's fifo, so the relaunched process starts from the systemd user manager's environment; without this everyOMARCHY_CODE_*the user set is silently dropped the moment the picker is needed.Error handling
siliconexits 0 even when it fails — unsupported language, unloadable theme, unwritable output — and simply writes no file. The artifact is checked rather than the exit code; otherwise the user gets a success notification while the clipboard still holds the old contents.ImageMagick post-processing rounds the corners and strokes only the four corner arcs in the theme's
accent, the same value Hyprland uses for the active window border. A full outline read as a generic wrapped frame. Post-processing is cosmetic, so ifmagickfails the unbordered image is kept rather than losing the capture; the result is written to a temp file and moved into place only on success.Scope coverage
Transliterating vscode's
tokenColorsturned out not to be enough. That vocabulary and syntect's Sublime grammars disagree, and TextMate matching is prefix-based — a rule formeta.function-call.genericnever matches a scope ofmeta.function-call. Method calls stayed unstyled in every language as a result.Probing each candidate scope with a unique colour showed what the grammars actually emit, which added
variable.function,meta.function-call,variable.other.member,entity.name.class,constant.other,meta.annotationandsupport.other.Verified across 15 languages — TypeScript, JavaScript, Python, Rust, Go, Java, C, C++, Ruby, PHP, shell, JSON, YAML, SQL, Lua — every scope the grammars emit is now styled, bar the outermost
source, which every token carries and which would flatten the whole image to one colour.Tests
test/shell.d/capture-code-test.sh— 92 assertions, using the PATH-stub and command-log pattern fromchannel-test.sh. No network, no clipboard, no compositor:silicon,magick,hyprctl,wl-paste,wl-copy,gumandomarchy-font-currentare stubbed against a throwawayHOMEandXDG_CACHE_HOME, so the run never depends on the developer's real theme or font state.Coverage includes the three-stage cascade and its cancel paths, the no-tty handoff and the settings it carries,
copy/save/default output modes, theme cache generation and invalidation, the theme-provided override, the font/padding/corner-radius knobs and their defaults, silicon's exit-0-on-failure path, and the magick degrade path.Every assertion was mutation-tested — the behaviour was deliberately broken and the matching assertion confirmed to fail — before this was considered done.