Skip to content

Instantly share code, notes, and snippets.

@nickwb
Created April 14, 2020 13:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nickwb/b12edea4152414bf5858c7b66f8171fe to your computer and use it in GitHub Desktop.
Save nickwb/b12edea4152414bf5858c7b66f8171fe to your computer and use it in GitHub Desktop.
Starship Daemon Concept

Starship Daemon Concept

This is a concept for an updated architecture for starship, which I think is worthy of further exploration and testing.

Motivation

Starship is a fast prompt for most users, most of the time. However, some of its modules are inherently I/O intensive, and this can lead to poor prompt performance under some conditions. For example, the git_status module can be slow to compute in very large git repositories.

Starship is also a stateless prompt. All values printed to the prompt are re-calculated every time the prompt is shown. This occurs despite the fact that most modules will produce unchanged output on subsequent prompts. In a rapid-fire terminal session, Starship mostly needs to rely on the operating system to keep recently used files in cache in order to keep performance acceptable.

The contributors to Starship have worked hard, under this stateless model, to make performance as fast as possible. However, we are increasingly approaching a ceiling of what performance is possible under the model.

High-level Concept

Starship should, during starship init, launch a long-running daemon. This daemon would be responsible for generating prompts, and storing caches and other state which allows subsequent prompts to be re-calculated much faster.

Under this new model, each module could:

  • Specify how long it should be cached for (or not at all)
  • Nominate files/directories to be watched for changes. Using OS filesystem watchers (e.g., through the notify-rs crate), we can invalidate those caches so that the prompt remains fresh.

Other possible features could include:

  • Pre-calculating prompts for frequently visited directories.
    • Allow the user to manually pin directories in the starship config file
  • Implement a timeout for prompt rendering, after which stale or incomplete data may be shown.

Ideas on Mechanics

starship daemon

Create a new verb for the starship CLI, daemon, which starts the daemon. Use a lockfile (e.g., starship.lock) in the user's home directory, or adjacent to the starship config file, to ensure the daemon is only run once per user. The lockfile crate may be suitable.

If the daemon is not already running, then starship daemon starts and detaches the daemon, and returns on stdout some socket address which can be used to communicate with the daemon. This is likely to be the address of some simple, platform-specific, high performance socket: such as a unix socket on MacOS and Linux, or a named pipe on Windows.

If the daemon is already running, then starship daemon returns the socket address of the already running daemon. Perhaps this address is written to a file (e.g., starship.socket) after the lockfile is successfully acquired.

starship init

The starship init verb should be similar to the existing implementation, but the shell-specific init scripts should be updated to include the following behaviours:

  1. Invokes starship daemon, and store the socket address returned in some shell variable

  2. Parameterize the shell's prompt function to take the socket address as an argument to starship prompt.

    • e.g., starship prompt --daemon-address=abcd --status=x --cmd-duration=y --jobs=z
    • This prevents us from having to do a fresh lookup of the socket address each time we invoke starship prompt.
    • If --daemon--address is not passed as an argument to starship prompt, we can fall back to loading this from the starship.socket file.
  3. Attaches the current shell to the daemon, by passing the PID of the shell process to the daemon.

    • We might achieve this through an argument to starship daemon. e.g., starship daemon --attach-shell 1234.
    • The daemon can regularly poll the OS to ensure each attached shell process is still running. Shells which exit are removed from the attached shell list. If all shells exit, then the daemon itself can exit.
    • Some users may use screen or tmux for very long-lived terminal sessions, so perhaps we should also have an idle timeout (e.g., no prompts generated in 3 hours) to kill the daemon.

Daemonless Mode

We could support a daemonless mode, equivalent to the existing stateless starship behaviour, by supporting a --daemonless argument to starship init.

starship prompt

The existing prompt verb will defer most of it's current work to the daemon. It captures the last exit code, command duration and job count - and sends these along with the current directory path to the daemon via the socket. The daemon responds with a fully-rendered prompt.

If the prompt detects that the daemon is unavailable, then it should attempt to re-initialize starship. This could involve some special exit code from starship prompt, which is then detected by the shell-specific prompt scripts.

@YourFin
Copy link

YourFin commented Nov 23, 2020

RE: Process tracking - this might be worth looking at: https://natanyellin.com/posts/tracking-running-processes-on-linux/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment