A faster-than-light (FTL) drive for Starship Zsh prompts
Warning
This is experimental. Prompt drawing is full of edge cases we haven't seen yet, and some we may not be able to solve for. If it works for your prompt, awesome! If it doesn't, file a bug report and include the starship.toml that isn't working. We may not be able to address every edge case, but we'll give it a shot.
Starship renders a prompt in milliseconds, but you still stare at
an empty screen while the rest of your .zshrc loads. Starship-FTL draws your
prompt before the rest of your config runs, then swaps in the real one when
loading finishes. Startup does the same work as before, it just stops making
you wait to see something. It also adds a clean up for your old prompts after
you run a command (aka: a transient prompt).
The technique comes from romkatv's instant-zsh gist, the same idea behind powerlevel10k's instant prompt.
- FTL Prompt:
- Enable by calling
ftl-prompt starship - Prompt appears immediately, before plugins and completions load
- Anything printed during startup, stdout and stderr, is captured and replayed above the real prompt instead of being erased
- Hopefully no flickering: the swap happens in a single write bracketed by synchronized update marks, and the stray partial-line mark is suppressed while loading
- Allows you to also set your cursor style up front instead of waiting for your config to load
- Works with starship out of the box, or with any
promptinittheme you build - The prompt drawn up front can come from your
starship.toml, so there is no second prompt definition to keep in sync
- Enable by calling
- FTL Transient:
- Enable by calling
ftl-transient on - Finished commands collapse to a short prompt
- Zsh ships with a transient right prompt, enabled with
setopt TRANSIENT_RPROMPT
- Enable by calling
All features are optional, and require you to enable the ones you want.
With antidote, add to the top of your .zsh_plugins.txt:
mattmc3/starship-ftl post:"ftl-prompt starship"
If you want to enable the transient prompt as well, use this:
mattmc3/starship-ftl post:"ftl-prompt starship; ftl-transient on"
If you don't use a plugin manager, you can clone and source this manually:
git clone https://github.com/mattmc3/starship-ftl ${ZDOTDIR:-$HOME}/.starship-ftl
source ${ZDOTDIR:-$HOME}/.starship-ftl/starship-ftl.plugin.zshThen, at the very top of your .zshrc, after making sure starship is in your path:
# .zshrc
path=(/path/to/starship/bin $path)
source /path/to/starship-ftl/starship-ftl.plugin.zsh
ftl-prompt starship # show your starship prompt instantly
ftl-transient on # optional: enable transient promptThe starship theme takes an optional config argument:
ftl-prompt starship mythemeThe config resolves to the first of these that exists:
- The argument itself, as a path to a
.tomlfile $ZDOTDIR/themes/mytheme.toml${XDG_CONFIG_HOME:-$HOME/.config}/starship/mytheme.toml
By default the theme loads first and its own prompt is drawn, so what you see
is your real prompt. That's normally what you want and costs a few milliseconds,
which is the right thing for most themes. For a very slow theme however, -p
allows you to draw an approximation immediately and loads the theme behind it:
ftl-prompt -p '%~ %# ' starshipFor best results, make the approximation resemble your real prompt.
With starship, the approximation can come out of starship.toml instead of a
string, so there is only one prompt definition to keep in sync. -P draws the
ftl-prompt profile:
ftl-prompt -P starship[profiles]
# Drawn by starship-ftl before the real prompt is ready. Same shape as `format`,
# minus anything that has to shell out, git especially, so the cost stays flat
# no matter how big the repo is.
ftl-prompt = """\
$directory\
$python$character\
"""-P is for the starship theme only, and it's an alternative to -p, not an
addition. A config with no ftl-prompt profile gets a message and the real
prompt, the same as leaving the flag off.
Only the left prompt is drawn. A right prompt appears when the real one does.
This costs one starship call before anything is on screen, which -p does not,
and both are far cheaper than loading the theme first.
A cursor style set by a plugin or editor config only takes effect once it
loads. To apply it up front, set the style before calling ftl-prompt:
zstyle ':ftl-prompt:' cursor barStyles are block, underline, or bar, with an optional blinking-
prefix, or a raw DECSCUSR number 0-6.
This covers the gap until your own config loads. It doesn't replace a plugin that manages cursor shape, like one that changes the cursor per vi mode.
Themes are ordinary promptinit themes, loaded from a
prompt_<name>_setup file on fpath. ftl-prompt runs that setup function,
applies the prompt_opts it asks for and records prompt_theme, which is the
part of the prompt system that matters for setting one theme once.
It does not run promptinit, which globs every fpath entry for every theme on
the system to build a list only prompt -l and prompt -p read. Nor does it
tear down a theme that was already set: this runs at the top of your .zshrc,
where there is never one to tear down.
If you want prompt -l, prompt -p or prompt -r, or you're switching themes
in a running shell, run promptinit yourself. After your prompt is set it costs
nothing, because the prompt is already on screen:
ftl-prompt starship
autoload -Uz promptinit && promptinitEvery question this asks starship is a process spawn, and those spawns are most
of what it costs at startup. The answers are cached under
${XDG_CACHE_HOME:-~/.cache}/starship-ftl, keyed on the size and modification
time of the starship binary and your config, so editing starship.toml
invalidates the cache on your next shell.
Two edits slip past that key: a config restored from a backup or copied with
cp -p, which keeps its old timestamp, and one landing in the same timestamp
tick as the previous edit. If your prompt ever disagrees with your config, rule
that out first:
rm -rf ${XDG_CACHE_HOME:-~/.cache}/starship-ftlTo ask starship every time instead, before calling ftl-prompt:
zstyle ':starship-ftl:' cache noReplace the prompt on a finished command with a short one, so scrollback reads as a list of commands instead of a wall of prompts. Opt in, off by default.
Add a profile to your starship.toml:
[profiles]
transient = "[❯](bold purple) "Then, once your prompt is set up:
ftl-transient onftl-transient off turns it back off. The profile name defaults to transient;
pass another to use it instead:
ftl-transient on my-short-promptOnly the left prompt is touched, so a finished command keeps whatever its right prompt showed. To drop that too, use zsh's own option:
setopt transient_rprompt- starship: the minimal, blazing-fast, customizable prompt
- instant-zsh: romkatv's proof of concept
- powerlevel10k: P10k's famously fast instant prompt