mirror of
https://github.com/robbyrussell/oh-my-zsh.git
synced 2026-09-21 18:46:06 +02:00
refactor(cli): group theme browser files
This commit is contained in:
@@ -181,7 +181,7 @@ omz theme preview agnoster # Print one isolated static preview
|
||||
|
||||
In the browser, type to filter, use Up/Down or Ctrl-P/Ctrl-N to navigate, and press Enter
|
||||
for explicit use/save actions. Esc or Ctrl-C cancels without applying a theme.
|
||||
See the [theme browser guide](tools/theme-browser.md) for shortcuts, preview limitations,
|
||||
See the [theme browser guide](tools/theme-browser/README.md) for shortcuts, preview limitations,
|
||||
and local testing instructions.
|
||||
|
||||
We'll admit it. Early in the Oh My Zsh world, we may have gotten a bit too theme-happy. We have over one
|
||||
|
||||
+4
-4
@@ -79,7 +79,7 @@ function _omz {
|
||||
_describe -o 'options' opts ;;
|
||||
theme::(browse|preview))
|
||||
local -a themes
|
||||
themes=("${(@f)$(source "$ZSH/tools/theme-preview.zsh"; _omz_theme_names)}")
|
||||
themes=("${(@f)$(source "$ZSH/tools/theme-browser/preview.zsh"; _omz_theme_names)}")
|
||||
_describe 'theme' themes ;;
|
||||
theme::(set|use))
|
||||
local -aU themes
|
||||
@@ -774,7 +774,7 @@ function _omz::theme::preview {
|
||||
print -u2 -r -- 'Usage: omz theme preview <theme>'
|
||||
return 1
|
||||
fi
|
||||
source "$ZSH/tools/theme-preview.zsh"
|
||||
source "$ZSH/tools/theme-browser/preview.zsh"
|
||||
_omz_theme_preview "$1"
|
||||
}
|
||||
|
||||
@@ -787,8 +787,8 @@ function _omz::theme::browse {
|
||||
print -u2 -r -- 'omz theme browse requires an interactive terminal; use omz theme preview <theme> instead.'
|
||||
return 1
|
||||
fi
|
||||
source "$ZSH/tools/theme-preview.zsh"
|
||||
source "$ZSH/tools/theme-browser.zsh"
|
||||
source "$ZSH/tools/theme-browser/preview.zsh"
|
||||
source "$ZSH/tools/theme-browser/browser.zsh"
|
||||
local selection action name
|
||||
selection=$(_omz_theme_browser "$1") || return $?
|
||||
[[ -n $selection ]] || return 0
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
# Theme Browser
|
||||
|
||||
```zsh
|
||||
omz theme browse
|
||||
omz theme browse agn
|
||||
omz theme preview agnoster
|
||||
```
|
||||
|
||||
The browser renders only the highlighted theme, in your invoking directory with real,
|
||||
synchronous Git information. Filtering is a case-insensitive literal substring match.
|
||||
Names are deduplicated; resolution follows normal Oh My Zsh precedence:
|
||||
`$ZSH_CUSTOM/<name>.zsh-theme`, `$ZSH_CUSTOM/themes/<name>.zsh-theme`, then
|
||||
`$ZSH/themes/<name>.zsh-theme`. Nested custom themes are supported. The `random`
|
||||
selector and names containing traversal components or control characters are excluded.
|
||||
|
||||
## Controls
|
||||
|
||||
| Key | Action |
|
||||
| --- | --- |
|
||||
| Up / Down, Ctrl-P / Ctrl-N | Previous / next theme |
|
||||
| Page Up / Page Down | Move one page |
|
||||
| Printable text | Filter names |
|
||||
| Backspace | Delete the last filter character |
|
||||
| Ctrl-U | Clear the filter |
|
||||
| Enter | Open selection actions |
|
||||
| Esc / Ctrl-C | Cancel without applying or saving |
|
||||
| `u` in selection actions | Use the theme for this session |
|
||||
| `s` in selection actions | Save as default and reload the shell |
|
||||
| `b` or Enter in selection actions | Return to browsing |
|
||||
|
||||
Using a theme calls `omz theme use`: it does **not** remove hooks, widgets, or other
|
||||
state installed by your previous theme. Saving calls `omz theme set`, edits `.zshrc`,
|
||||
and reloads the shell. These actions happen only after leaving the browser and
|
||||
restoring terminal state. Names containing shell punctuation cannot be saved through
|
||||
the browser; configure those manually. No global aliases or keybindings are installed.
|
||||
|
||||
## Preview Limits
|
||||
|
||||
- Each preview runs in a fresh `zsh -df` worker, not your active shell. The worker
|
||||
inherits the directory and exported environment, but not non-exported theme
|
||||
settings, plugins, user `.zshrc`, or custom library overrides. System `zshenv`
|
||||
still runs as required by zsh.
|
||||
- Previews initialize prompt helpers and precmd hooks. They show a successful
|
||||
previous command (status 0). Tests also exercise nonzero status rendering.
|
||||
- Multiline left prompts are supported. Right prompts are deliberately labeled
|
||||
and displayed separately, not positioned as ZLE would position them.
|
||||
- Interactive/async themes, plugin-dependent segments, terminal queries, and
|
||||
widget-driven prompts may be incomplete or unsupported. Themes still require
|
||||
their usual fonts for special glyphs; the browser itself requires no fonts.
|
||||
- Workers have a three-second execution limit and a 32,000-byte output limit.
|
||||
Navigation cancels obsolete work. ANSI colors are retained; other terminal
|
||||
controls are filtered. Long lines and tall previews are clipped in the browser.
|
||||
- The browser requires an interactive terminal with alternate-screen support and
|
||||
at least 40 columns by 16 rows. Smaller windows show a resize message; Esc still
|
||||
exits. `omz theme preview` also works without an interactive terminal.
|
||||
- This is **shell-state isolation, not a security sandbox**. Only preview trusted
|
||||
themes: their code can write files, access the network, or deliberately detach
|
||||
processes. The supervisor cleans up ordinary descendants, not escaped processes.
|
||||
|
||||
No new third-party runtime is required. The implementation uses standard zsh modules
|
||||
(`zpty`, `system`, `datetime`, `zselect`, `terminfo`) and platform utilities including
|
||||
`stty`, `mktemp`, `mkfifo`, and `rm`. Git segments need Git as usual. Private temporary
|
||||
files are removed when previews finish or are cancelled. Full OMZ startup, update
|
||||
checks, and OMZ cache initialization are not invoked by workers. The old
|
||||
`tools/theme_chooser.sh` is unchanged.
|
||||
|
||||
## Local Testing
|
||||
|
||||
From this checkout, launch a disposable interactive shell without reading your `.zshrc`:
|
||||
|
||||
```zsh
|
||||
env ZSH="$PWD" zsh -dfi
|
||||
```
|
||||
|
||||
Inside it, load the CLI and try previews. Change directory to a Git repository to
|
||||
compare clean, dirty, and untracked-file states:
|
||||
|
||||
```zsh
|
||||
source "$ZSH/lib/cli.zsh"
|
||||
omz theme preview robbyrussell
|
||||
omz theme preview agnoster
|
||||
omz theme preview half-life
|
||||
omz theme preview dieter
|
||||
omz theme browse
|
||||
```
|
||||
|
||||
This minimal shell is intended for preview/navigation testing. For a real session-use
|
||||
test, load this checkout's full OMZ configuration in a disposable shell. Do not choose
|
||||
Save unless you intend to edit your actual `.zshrc`; automated browser tests stub both
|
||||
actions and never edit your configuration. Exit the disposable shell when finished.
|
||||
|
||||
Regression suites run without additional test frameworks:
|
||||
|
||||
```zsh
|
||||
zsh -df tools/tests/theme-preview.zsh
|
||||
zsh -df tools/tests/theme-browser.zsh
|
||||
```
|
||||
|
||||
The tests cover resolution, prompt isolation, Git context, hook/status rendering,
|
||||
terminal-control filtering, failures, time/output limits, descendant cleanup,
|
||||
completion candidates, lazy loading, keyboard navigation, resizing, action dispatch,
|
||||
and terminal restoration using real PTYs. Human visual testing in your terminal and
|
||||
font is still required before proposing a PR. Linux/older-zsh testing remains pending.
|
||||
|
||||
## Footprint And Startup
|
||||
|
||||
Runtime code is roughly 18 KiB across the three `tools/theme-*.zsh` files, plus small
|
||||
CLI wrappers and completion/help entries. Tests and this guide are additional text
|
||||
files, not runtime dependencies. Measure the exact current footprint with:
|
||||
|
||||
```zsh
|
||||
wc -c tools/theme-browser.zsh tools/theme-preview.zsh tools/theme-preview-worker.zsh
|
||||
```
|
||||
|
||||
Normal shell startup only defines the CLI wrappers: none of the three tool files is
|
||||
sourced, no browser modules are loaded, and no workers or browser I/O are started.
|
||||
The regression suite verifies lazy loading. Startup timing should be considered
|
||||
noise-sensitive; this prototype does not claim a measurable speed improvement.
|
||||
@@ -0,0 +1,55 @@
|
||||
# Theme Browser
|
||||
|
||||
Preview installed themes without changing your current prompt:
|
||||
|
||||
```zsh
|
||||
omz theme browse
|
||||
omz theme browse agn
|
||||
omz theme preview agnoster
|
||||
```
|
||||
|
||||
The browser filters theme names as you type and renders the highlighted theme using
|
||||
the current directory, including synchronous Git information.
|
||||
|
||||
## Controls
|
||||
|
||||
| Key | Action |
|
||||
| --- | --- |
|
||||
| Up / Down, Ctrl-P / Ctrl-N | Previous / next theme |
|
||||
| Page Up / Page Down | Move one page |
|
||||
| Printable text | Filter names |
|
||||
| Backspace | Delete the last filter character |
|
||||
| Ctrl-U | Clear the filter |
|
||||
| Enter | Open selection actions |
|
||||
| Esc / Ctrl-C | Cancel without applying or saving |
|
||||
| `u` in selection actions | Use the theme for this session |
|
||||
| `s` in selection actions | Save as default and reload the shell |
|
||||
| `b` or Enter in selection actions | Return to browsing |
|
||||
|
||||
Using a theme changes the current session. It does not remove hooks or widgets installed
|
||||
by the previous theme. Saving updates `ZSH_THEME` in `.zshrc` and reloads the shell.
|
||||
|
||||
## Limitations
|
||||
|
||||
- Previews run in a fresh shell, so plugin-dependent and interactive themes may be incomplete.
|
||||
- Right prompts are labeled and shown separately rather than positioned by ZLE.
|
||||
- The browser requires an interactive terminal with alternate-screen support.
|
||||
- Theme code is isolated from your active shell, but it is not sandboxed. Preview only trusted themes.
|
||||
|
||||
## Local Testing
|
||||
|
||||
From this checkout, launch a disposable interactive shell:
|
||||
|
||||
```zsh
|
||||
env ZSH="$PWD" zsh -dfi
|
||||
source "$ZSH/lib/cli.zsh"
|
||||
omz theme preview robbyrussell
|
||||
omz theme browse
|
||||
```
|
||||
|
||||
Run the regression suites with:
|
||||
|
||||
```zsh
|
||||
zsh -df tools/theme-browser/tests/preview_test.zsh
|
||||
zsh -df tools/theme-browser/tests/browser_test.zsh
|
||||
```
|
||||
@@ -1,4 +1,4 @@
|
||||
# Invoked only by theme-preview.zsh in a fresh zsh -df process. Themes and hooks
|
||||
# Invoked only by preview.zsh in a fresh zsh -df process. Themes and hooks
|
||||
# are intentionally sourced/run at top level (not inside a setup function).
|
||||
emulate -R zsh
|
||||
if [[ $1 == --supervise ]]; then
|
||||
@@ -5,7 +5,7 @@ typeset -g _OMZ_THEME_PREVIEW_DIR=${${(%):-%x}:A:h}
|
||||
function _omz_theme_names() (
|
||||
emulate -L zsh
|
||||
setopt extendedglob
|
||||
local root=${ZSH:-${_OMZ_THEME_PREVIEW_DIR:h}}
|
||||
local root=${ZSH:-${_OMZ_THEME_PREVIEW_DIR:h:h}}
|
||||
local custom=${ZSH_CUSTOM:-$root/custom} dir file name
|
||||
local -a names files
|
||||
for dir in "$custom" "$root/themes"; do
|
||||
@@ -28,7 +28,7 @@ function _omz_theme_names() (
|
||||
function _omz_theme_resolve() (
|
||||
emulate -L zsh
|
||||
setopt extendedglob
|
||||
local name=$1 root=${ZSH:-${_OMZ_THEME_PREVIEW_DIR:h}}
|
||||
local name=$1 root=${ZSH:-${_OMZ_THEME_PREVIEW_DIR:h:h}}
|
||||
local custom=${ZSH_CUSTOM:-$root/custom} dir
|
||||
if (( $# != 1 )) || [[ -z $name || $name == random || /$name/ == */(.|..)/* || $name == /* || $name == *//* || $name == *[[:cntrl:]\\]* ]]; then
|
||||
print -u2 -r -- 'theme preview: invalid or non-selectable theme name'
|
||||
@@ -60,7 +60,7 @@ function _omz_theme_preview() (
|
||||
return 1
|
||||
fi
|
||||
local tmp fifo_fd pty=omz-preview-$sysparams[pid] record pgid raw='' chunk error=''
|
||||
local selected=$1 custom=${ZSH_CUSTOM:-${ZSH:-$backend:h}/custom}
|
||||
local selected=$1 custom=${ZSH_CUSTOM:-${ZSH:-${backend:h:h}}/custom}
|
||||
local -i active=0 cancelled=0 bytes=0 count remaining result=1
|
||||
local -F deadline
|
||||
trap 'cancelled=130' INT
|
||||
@@ -73,8 +73,8 @@ function _omz_theme_preview() (
|
||||
|
||||
# Exec immediately: a forked shell function could run inherited EXIT traps
|
||||
# after returning. Both the launcher and theme worker must start fresh.
|
||||
local -a launch=("$commands[zsh]" -df "$backend/theme-preview-worker.zsh" --supervise
|
||||
"$tmp" "$backend:h" "$theme" "$sample" "$selected" "$custom")
|
||||
local -a launch=("$commands[zsh]" -df "$backend/preview-worker.zsh" --supervise
|
||||
"$tmp" "${backend:h:h}" "$theme" "$sample" "$selected" "$custom")
|
||||
deadline=$(( EPOCHREALTIME + 3 ))
|
||||
if ! zpty -b "$pty" exec "${(@q)launch}"; then
|
||||
print -u2 -r -- 'theme preview: could not allocate a private PTY'
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env zsh
|
||||
# Run with: zsh -df tools/tests/theme-browser.zsh
|
||||
# Run with: zsh -df tools/theme-browser/tests/browser_test.zsh
|
||||
# Optionally pass one group, e.g. `slow-interrupt`, to run it alone.
|
||||
# Each browser runs under a real controlling PTY, with no user startup files.
|
||||
emulate -R zsh
|
||||
@@ -85,7 +85,7 @@ setopt err_exit pipe_fail
|
||||
zmodload zsh/zpty
|
||||
zmodload zsh/datetime
|
||||
zmodload zsh/zselect
|
||||
typeset -r repo=${0:A:h:h:h} self=${0:A}
|
||||
typeset -r repo=${0:A:h:h:h:h} self=${0:A}
|
||||
typeset scratch=$(mktemp -d "${TMPDIR:-/tmp}/omz-browser-test.XXXXXXXX")
|
||||
scratch=${scratch:A}
|
||||
trap 'zpty -d 2>/dev/null; command rm -rf -- "$scratch"' EXIT
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env zsh
|
||||
# Run with: zsh -df tools/tests/theme-preview.zsh
|
||||
# Run with: zsh -df tools/theme-browser/tests/preview_test.zsh
|
||||
emulate -R zsh
|
||||
setopt err_exit pipe_fail
|
||||
typeset -r repo=${0:A:h:h:h}
|
||||
source "$repo/tools/theme-preview.zsh"
|
||||
typeset -r repo=${0:A:h:h:h:h}
|
||||
source "$repo/tools/theme-browser/preview.zsh"
|
||||
typeset scratch=$(mktemp -d "${TMPDIR:-/tmp}/omz-preview-test.XXXXXXXX")
|
||||
scratch=${scratch:A}
|
||||
trap 'command rm -rf -- "$scratch"' EXIT
|
||||
@@ -220,7 +220,7 @@ check test -z "${child_state//[ ZN+]/}"
|
||||
# Match the browser's nested-PTY invocation, preserving other owned PTYs.
|
||||
zmodload zsh/zpty
|
||||
zpty -b unrelated 'exec sleep 30'
|
||||
typeset -a nested_command=("$commands[zsh]" -dfc 'source "$1"; _omz_theme_preview status' zsh "$repo/tools/theme-preview.zsh")
|
||||
typeset -a nested_command=("$commands[zsh]" -dfc 'source "$1"; _omz_theme_preview status' zsh "$repo/tools/theme-browser/preview.zsh")
|
||||
zpty -b browser exec "${(@q)nested_command}"
|
||||
output=''
|
||||
for attempt in {1..300}; do
|
||||
@@ -239,7 +239,7 @@ zpty -d browser unrelated
|
||||
# Cancellation by the browser's outer process group must also clean the
|
||||
# backend's separate inner PTY group and private FIFO directory.
|
||||
rm -f "$PREVIEW_PID_FILE"
|
||||
nested_command=("$commands[zsh]" -dfc 'source "$1"; _omz_theme_preview slow' zsh "$repo/tools/theme-preview.zsh")
|
||||
nested_command=("$commands[zsh]" -dfc 'source "$1"; _omz_theme_preview slow' zsh "$repo/tools/theme-browser/preview.zsh")
|
||||
zpty -b browser exec "${(@q)nested_command}"
|
||||
typeset browser_group record
|
||||
for record in "${(@f)$(zpty)}"; do
|
||||
@@ -266,7 +266,7 @@ zpty -d browser
|
||||
export ZSH=$repo
|
||||
git -C "$scratch/work" init -q
|
||||
git -C "$scratch/work" symbolic-ref HEAD refs/heads/preview-branch
|
||||
output=$(zsh -dfc 'builtin cd "$1"; source tools/theme-preview.zsh; builtin cd "$2"; _omz_theme_preview robbyrussell' zsh "$repo" "$scratch/work")
|
||||
output=$(zsh -dfc 'builtin cd "$1"; source tools/theme-browser/preview.zsh; builtin cd "$2"; _omz_theme_preview robbyrussell' zsh "$repo" "$scratch/work")
|
||||
check test "${output#*preview-branch}" != "$output"
|
||||
for name in robbyrussell dieter agnoster bira nicoulaj half-life; do
|
||||
output=$(builtin cd "$scratch/work"; _omz_theme_preview "$name" 7)
|
||||
Reference in New Issue
Block a user