starship / starship

☄🌌️ The minimal, blazing-fast, and infinitely customizable prompt for any shell!
https://starship.rs
ISC License
45.13k stars 1.97k forks source link

Activating modules dynamically (if possible, depending on the session history) #840

Open Mekk opened 4 years ago

Mekk commented 4 years ago

This is likely non-trivial, but I decided to raise it as the functionality could be interesting.

I sometimes use kubernetes. Frequently enough to enable kubernetes module, but … by far not always. I would be much happier if kubernetes module was disabled by default, but magically activated (in given terminal) once I issue kubectl, helm, or oc (as it proves my intent to enter my cloudy hat for some time).

Similar theme could be related to other modules. aws comes to mind immediately but even python version starts being interesting once I do anything pythonic (python, pip, conda… – even if current dir doesn't contain any trigger). Memory module could show up if I happen to issue top/htop/free, etc.

I see some possible ways to achieve similar functionality, draft ideas below.

Dynamic per-terminal configuration context

From the user point of view I imagine it as sth like:

starship config-here enable kubernetes
starship config-here disable python

(of course options can be named differently and maybe provided by separate binary). Not exactly sure about best way to implement it, but some ideas:

  1. starship config-here updates /run/starship/«some-id-of-this-sessionl»/config.toml (or sth similar in /tmp if /run doesn't work). During prompt generation starship checks for those settings and uses them. Both sides must somehow agree on what the «this-session-id» is, shell pid could probably serve.

  2. starship-config-here is just a shell function which sets some environment variable(s) (_STARSHIP_CONFIG_…). Actual starship triggers some shell callback asking for their values (maybe calls shell function _give_me_this_session_settings «target» or maybe does brute echo $_STARSHIP_CONFIG > «target», where «target» is pipe/socket/tempfile ready to grab the data)

This functionality lone could be sufficient to achieve my main goal with some scripting around (like aliasing kubectl to starship config-here enable kubernetes && /actual/kubectl). And seems useful in general, even for „play with starship” game (enable this, disable that, contemplate effects without the need to restart shell).

Changing state according to the commands executed

It would be great if I could write in starship.toml

[kubernetes]
disabled = true
enable_after_command = ["kubectl", "oc", "helm"]

I am not quite sure whether this is possible (is starship able to inspect which command user just executed or is to execute - that's mostly q whether prompt callbacks see BASH_COMMAND and similar vars?) but if so, would be great.

Apart from accessing command itself, it also requires keeping some state, preferably sharing the way with commands from pkt 1 (so one could later use explicit command to disable if he or she likes so).

If such mechanism appears, I also imagine extending it to more "switchy" behaviours in the future, so various commands could enable "general flavor" of the current terminal, disabling unrelated modules (I used python or pip - fine, let's see pyver, check for venvs and even signal PYTHONPATH contents, but disable rust-related things; I called kubectl - fine, let's disable most local modules including that python and show mostly things about remote cluster for some time; etc). But this is just a rough idea, which could be more confusing than useful.

romkatv commented 4 years ago

FWIW, powerlevel10k does something like this. See https://www.reddit.com/r/zsh/comments/ep6987/new_powerlevel10k_feature_show_on_command/.

p10k

Mekk commented 4 years ago

I don't ask for so much dynamism, switching since next prompt would be great too. Not that I'd complain for sth this pic shows but I somehow doubt bash would be sufficiently helpful ;-)

lucarin91 commented 4 years ago

Hi, I think that rendering the modules based on the command history can be a quite useful feature. In the past days, I was doing something to achieve this in starship.

My first attempt was trying to read the history file of the shell, to avoid doing extra work if the history is disabled or not used by any modules. But unfortunately, I then realize that this file is updated only after the shell exit (at least in bash and zsh). Shame on me :(

Then I move to another implementation, using the history command. The recent history is passed to starship thought argument. Here there is a simple implementation for bash with the modules python, rust and java. Thus, if for instance you type rustc or cargo you will see in the next terminal the rust module. This eventually goes off when you do not use rust in the next 5 commands.

This is a very early prototype if this is something that you think is worth I will go thought this path and improve my implementation. I understand that this approach will slow down the starship execution, but I did not fund for now another solution.

Any comments are welcome :)

macintacos commented 4 years ago

I must say, coming from powerlevel10k, this is probably the biggest thing that I miss.

pschulten commented 3 years ago

I have a similar use-case. I only want to display the kube ctx and ns if I have valid credentials. It would be possible if the disabled toggle could be switched dynamically.

I worked around it by abusing the env_var module by setting the var with a custom shell function in my ~/.bashrc

# ...
# starship
function _cur_ns {
  kubectl config view -o jsonpath="{.contexts[?(@.name==\"$(kubectl config current-context)\")].context.namespace}"
}
function _kube_prompt {
  if kubectl config current-context > /dev/null 2>&1 && \
      kubectl config view --minify --raw -o jsonpath='{.users[].user.client-certificate-data}' \
      | base64 -d \
      | openssl x509 -noout -checkend 3 > /dev/null 2>&1; then
    export KUBEAUTH=$(printf "%s⍀%s" "$(kubectl config current-context)" "$(_cur_ns)")
  else
    unset KUBEAUTH
  fi
}
function _ss_precmd(){
  # printf "\x1b[240;2;8;8;8m│%s\x1b[0m " $(token-timer)
  _kube_prompt
  ttl=$(token-timer)
  [ -n "$ttl" ] && printf "\x1b[38;2;255;100;0m%s \x1b[0m" $ttl
}
starship_precmd_user_func="_ss_precmd"
. <(starship init bash)

I'm not very happy with it, but it works:

/tmp ❯ echo $KUBEAUTH

/tmp ❯ ctx icecream
Switched to context "icecream".
icecream⍀kube-system /tmp ❯ echo $KUBEAUTH
icecream⍀kube-system
icecream⍀kube-system /tmp ❯
ninadpage commented 3 years ago

My solution to activate modules "when required":

Also define other trigger words than 'kubectl'

sandbox_hook kubectl kubectx sandbox_hook kubectl kubens sandbox_hook kubectl stern sandbox_hook kubectl kustomize


* Clean up in `~/.zlogout`
```zsh
# Cleanup the cloned starship config when exiting the shell
function cleanup_cloned_starship() {
  local current_zsh_id=$(echo $$)
  if [[ ${STARSHIP_CONFIG} =~ "/tmp/starshipconfigs/zsh-${current_zsh_id}-.+" ]];
  then
    rm -f /tmp/starshipconfigs/zsh-${current_zsh_id}-*
  fi
  unset STARSHIP_CONFIG
}

cleanup_cloned_starship
maxbrunet commented 2 years ago

@ninadpage FYI With zsh, you do not need sandboxd, you can use a preexec hook function: https://zsh.sourceforge.io/Doc/Release/Functions.html#Special-Functions

Here is how I run kubeon for kube-ps1 in my .zshrc (came to this issue to see if I would be able to migrate to starship):

# Automatically enable kube-ps1 when certain commands are executed
function _enable_kube-ps1 {
  local -ar KUBE_CMDS=(
    kubectl
    kubens
    kubectx
    kustomize
  )
  if (( $KUBE_CMDS[(I)${2%% *}] )); then
    kubeon
  fi
}

if ! (( $preexec_functions[(I)_enable_kube-ps1] )); then
  preexec_functions+=(_enable_kube-ps1)
fi
WladyX commented 2 years ago

This is also preventing me from trying to switch from p10k to starship. Will be watching this issue. Thank you for your effort!