Powerlevel10k: [feature] Show kubecontext only when the current command in BUFFER is kubectl

Created on 9 Nov 2019  路  30Comments  路  Source: romkatv/powerlevel10k

Most helpful comment

We are live! I've just merged reactive branch into master. Please switch when you get a chance. Announcement on /r/zsh: https://www.reddit.com/r/zsh/comments/ep6987/new_powerlevel10k_feature_show_on_command/.

Thanks to everyone for helping with testing the new feature and coming up with good defaults!

All 30 comments

It would make sense to support helm, helmfile and maybe more commands, which work with Kubernetes API. Meaning this feature shouldn't be tied to single command.

I opened this issue after this feature has already been implemented. It's not tied to a single command. This feature is a reminder for myself to promote the API from experimental to public.

Pinging folks who've expressed interest in this feature (perhaps only indirectly, in which case I apologize for spamming). @Syphdias @maximbaz @rsotnychenko @jordanjennings @JiffsMaverick @jcassee

I've implemented this feature in reactive branch. I would appreciate if you can give it a try and report whether it works for you and/or causes any issues. The API is quite simple:

POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|terraform'

This will make kubecontext hidden unless the command you are typing invokes kubectl or terraform. You can replace KUBECONTEXT in the name of the parameter with any other segment name. The value is a pattern that matches against basename of every word in command position. For example, if your command line contains this code:

() { sudo -u user foo arg && bar arg } always { &>/dev/null baz }

... and baz is an alias for qux, matching is done against foo, bar and qux.

The command line parser is much more precise and much faster than in any syntax highlighting plugin but it's still not perfect. If you notice where it fails to recognize a command word, do let me know.

The parser stops after 64 tokens to avoid slowing zle down if your command line is immense. On my machine this caps parser's latency at about 2ms. Even if your machine is much slower, you aren't supposed to notice any increase in zle latency when using this new feature. Let me know if this is not the case. You can override the limit with POWERLEVEL9K_COMMANDS_MAX_TOKEN_COUNT.


If you want more customization power, read on. Otherwise feel free to stop reading.

The same branch contains the final code for p10k display and p10k-on-* hooks. This is advanced API. p10k display lets you instantly hide and show prompt segments and it can be called from zle. p10k-on-* hooks are user-defined functions that p10k will call if they exist.

Hooks:

  • p10k-on-init -- Called when p10k is being initialized. May be called from zle. This is always the first hook to get called. Next hook: p10k-on-pre-prompt.
  • p10k-on-pre-prompt -- Called before every prompt. May be called from zle. Next hook: p10k-on-post-widget or p10k-on-post-prompt.
  • p10k-on-post-widget -- Called after every zle widget when PS1 is active. Always called from zle. Next hook: p10k-on-post-widget or p10k-on-post-prompt.
  • p10k-on-post-prompt -- Called before a prompt is retired. Always called from zle. Next hook: p10k-on-pre-prompt or p10k-on-init.

Edit: p10k-on-pre-prompt may get called more than once for the same prompt without intervening p10k-on-post-prompt. When p10k-on-pre-prompt is called for the second time, this always happens from zle, and p10k-on-post-widget always follows immediately after.

The following scalar parameters are available in all hooks:

  • P9K_PROMPT -- the kind of prompt that is being rendered: instant or regular.
  • P9K_TTY -- the state of the terminal: new when the terminal has just been created and is empty; old otherwise.

In addition, array parameter P9K_COMMANDS is available in p10k-on-post-widget. It contains all commands from $BUFFER. Each element is a nul-separated list. The last component is the actual command (kubectl, foo/bar, grep, etc.). The previous components are precommands (sudo, nice,nohup, etc.) . For example:

( exec sudo -u user =ls /etc ) && foo/bar

... results in the following P9K_COMMANDS:

P9K_COMMANDS=(
  $'exec\0sudo\0/bin/ls'
  'foo/bar'
)

Hooks don't have any positional parameters.

POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|terraform' is syntax sugar for the following more powerful but at the same time more complex construct:

function p10k-on-pre-prompt() {
  # Hide kubecontext segment when a new prompt is being rendered.
  p10k display '*/kubecontext'=hide
}

function p10k-on-post-widget() {
  # If the command in $BUFFER invokes kubectl or terraform, show
  # kubecontext segment. Otherwise hide it.
  local pattern=$'(|*[/\0])(kubectl|terraform)'
  if (( $P9K_COMMANDS[(I)$pattern] )); then
    p10k display '*/kubecontext'=show
  else
    p10k display '*/kubecontext'=hide
  fi
}

p10k display is documented in p10k help display.

@romkatv I've switched to the branch you mentioned, seems to be working fine :)
I'll update if any issues arise.

@Syphdias @maximbaz @rsotnychenko @jordanjennings @JiffsMaverick @jcassee

I forgot the most important thing. Please share the values of POWERLEVEL9K_*_SHOW_ON_COMMAND parameters you are using. I'd like to enable show-on-command mode by default for several prompt segments but I don't know which command patterns to use.

For example, does POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|terraform' make sense? I know that kubectl should be there but what about terraform? Can the behavior of terraform command be affected by the current kubernetes context? What other common commands can be affected by it? What would be good command patterns for azure and gcloud? What other segments should use this by default? I don't use any of these technologies myself, so I need to rely on your expertise here.

(When I say "by default", I mean that configs produced by p10k configure will make use of POWERLEVEL9K_*_SHOW_ON_COMMAND. The existing configs will behave as before.)

Terraform can be affected by Kubernetes context in-use (see https://www.terraform.io/docs/providers/kubernetes/index.html#file-config), but I am not sure if that's widely used as I personally never saw a use case for it. Maybe someone else can shed some light on this.
Apart from kubectl and terraform I do have helm in the list of the commands for kubecontext prompt.

I think that all cloud provider contexts should be displayed on terraform and, maybe, we should consider adding pulumi (https://github.com/pulumi/pulumi) as well.
For gcloud its also reasonable to add gcs, that's a CLI for interacting with Google Cloud Storage

Will update once I come up with any other ideas.

@rsotnychenko Thanks! That's exactly the kind of info I'm looking for.

@rsotnychenko I've defined these:

POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|terraform|helm|pulumi'
POWERLEVEL9K_AZURE_SHOW_ON_COMMAND='azure|terraform|helm|pulumi'
POWERLEVEL9K_GCLOUD_SHOW_ON_COMMAND='gcloud|terraform|helm|pulumi'

Did I understand your suggestions correctly?

There are a few more segments that are sort of related and perhaps should also have SHOW_ON_COMMAND:

  • terraform -- current terraform workspace (terraform workspace show). This value usually comes from .terraform/environment, so it's probably not spammy.
  • aws_eb_env -- aws elastic beanstalk environment. This value comes from .../.elasticbeanstalk/config.yml, so it's probably not spammy.
  • aws -- current aws profile. This value always comes from an environment variable. Might be spammy? Makes sense to use SHOW_ON_COMMAND? What pattern?
  • google_app_cred -- google application credentials. This value comes from a combination of environment variables and global config files. Might be spammy? Makes sense to use SHOW_ON_COMMAND? What pattern?

Just installed reactive branch, really nice work!

I agree that although terraform does have a k8s provider, I haven't seen seen it being used, so not sure how much value there is in having terraform in POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND _by default_ - I'll keep it out in my personal setup, at least for now.

I agree also that all cloud providers (azure, aws, gcloud) should contain terraform (and pulumi I guess, it seems quite popular) in it. They don't need helm though, that is purely kubernetes specific tool.

For defaults, I therefore recommend to adjust your list to:

POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm'
POWERLEVEL9K_AZURE_SHOW_ON_COMMAND='azure|terraform|pulumi'
POWERLEVEL9K_GCLOUD_SHOW_ON_COMMAND='gcloud|terraform|pulumi'

terraform, aws_eb_env probably not spammy

Agree 馃憤

aws might be spammy?

Think so. Seems their CLI tool is called aws. Therefore I propose to extend defaults above with:

```
POWERLEVEL9K_AWS_SHOW_ON_COMMAND='aws|terraform|pulumi'

> `google_app_cred`

馃し鈥嶁檪 Never used, sounds spammy, but don't know which commands to put in `_ON_COMMAND`.


------

My personal setup as I have right now:

clean historical prompts, ready for copy-paste

function p10k-on-pre-prompt() { p10k display '1'=show }
function p10k-on-post-prompt() { p10k display '1'=hide }

typeset -g POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm'
typeset -g POWERLEVEL9K_AZURE_SHOW_ON_COMMAND='az|terraform'
```

Thanks, @maximbaz. I've updated config templates.

POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm'

Just to clarify, this doesn't need pulumi, right?

google_app_cred

@rsotnychenko Could you help with this? Is this something you need to always see or is it better to have SHOW_ON_COMMAND for it?

Just to clarify, this doesn't need pulumi, right?

Correct, at least let's wait until we hear counter-arguments from other users, right now I just agree with what @rsotnychenko said, although both terraform and pulumi _technically_ can work with kubernetes, it doesn't seem to be widely used yet, so doesn't warrant to be in default setup.

@romkatv I minimized my configuration to what I am using, just:

POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm'
POWERLEVEL9K_GCLOUD_SHOW_ON_COMMAND='gcloud'

It's working great! I have enabled gcloud where I had not before because it is only displayed when I type gcloud.

@rsotnychenko Could you help with this? Is this something you need to always see or is it better to have SHOW_ON_COMMAND for it?

From what was posted here and my own thoughts I've compiled the following list of defaults and added some comments regarding the changes I made:

# Added `kubens` - a helper for switching namespaces (https://github.com/ahmetb/kubectx)
POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm|kubens'
# Added `awless` - a 3-rd party CLI for AWS (https://github.com/wallix/awless)
POWERLEVEL9K_AWS_SHOW_ON_COMMAND='aws|awless|terraform|pulumi'
POWERLEVEL9K_AZURE_SHOW_ON_COMMAND='azure|terraform|pulumi'
# Only Google's CLI tools are able to use credentials that are displayed in `gcloud` prompt
POWERLEVEL9K_GCLOUD_SHOW_ON_COMMAND='gcloud|gcs'
# `google_app_cred` is showing credentials that can be consumed by other apps
POWERLEVEL9K_GOOGLE_APP_CRED_SHOW_ON_COMMAND='terraform|pulumi'

Did I miss something? Should we change something in this list?

This is an amazing feature, thanks!

My two cents regarding kubecontext segment and terraform/pulumi tools: handling K8s resources using Terraform/Pulumi is gaining track recently (either directly or indirectly with Helm provider) but I think that most of users specify credentials using different mechanisms (e.g. inline using AKS resource outputs; that is promoted by MS for example). So, I would say that you don't need to include them in the defaults.

I'm currently using something that is a mix of @maximbaz and @rsotnychenko config:

# I don't use helm that much
typeset -g POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|kubens'
typeset -g POWERLEVEL9K_AZURE_SHOW_ON_COMMAND='az|terraform|pulumi'

kubectx is an interesting tool 馃憤 But then remember that it provides two binaries (to select context and to select namespace), so your config should really be:

POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm|kubens|kubectx'

kubectx has more github stars than pulumi, so I guess it warrants to be included in the default config, like the above.

@romkatv I'm wondering if that's possible to refresh the prompt when unhiding it?

It would be useful in the following scenario with kubectl and any other prompts showing values that are _not_ based on an environment variables:

  1. Multiple terminals are open
  2. In one of the terminals you change the file that is used as source for the prompt (i.e. change Kubernetes context)
  3. You switch to a different terminal, type a command and see the updated prompt

You can simply hit ENTER to refresh prompt. If you don't want to create a new prompt, use this widget:

function redraw-prompt() {
  emulate -L zsh
  local chpwd=${1:-0} f
  if (( chpwd )); then
    for f in chpwd $chpwd_functions; do
      (( $+functions[$f] )) && $f &>/dev/null
    done
  fi
  for f in precmd $precmd_functions; do
    (( $+functions[$f] )) && $f &>/dev/null
  done
  zle .reset-prompt && zle -R
}

We are live! I've just merged reactive branch into master. Please switch when you get a chance. Announcement on /r/zsh: https://www.reddit.com/r/zsh/comments/ep6987/new_powerlevel10k_feature_show_on_command/.

Thanks to everyone for helping with testing the new feature and coming up with good defaults!

Guys, I need your expertise again. I received a PR that adds oc to POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND: https://github.com/romkatv/powerlevel10k/pull/436/files. Good idea?

Yes, oc is OpenStack's version of kubectl.

Yes, oc is OpenStack's version of kubectl.

Thanks, Joost and folks who've upvoted this comment. I've merged the PR.

Hey,

I've disabled POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND in my config to always show the kubecontext. But as I don't need it always I've added this keybinding:

function toggle-k8s-prompt() { p10k display '*/kubecontext'=hide,show; }
zle -N toggle-k8s-prompt
bindkey '^k' toggle-k8s-prompt

Now to my question: Would it be possible to somehow fallback to "show on command" when I disable the "show always" through key stroke?

ctrl-k -> show always kubecontext
ctrl-k -> show on command kubecontext

@spielkind This should do it:

function toggle-k8s-prompt() {
  if (( ${+POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND} )); then
    unset POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND
  else
    typeset -g POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm|kubens|kubectx|oc|istioctl|kogito'
  fi
  p10k reload
  if zle; then
    zle push-input
    zle accept-line
  fi
}
zle -N toggle-k8s-prompt
bindkey '^K' toggle-k8s-prompt

It's much slower because powerlevel10k will fully reinitialize. It'll also wipe all caches. Should probably still work satisfactorily. Let me know if not.

Edit: This is now in the FAQ.

@spielkind FYI: I've updated the command above. Please copy again if you've already copied.

Folks, I need to tap your cloud expertise once again.

Currently gcloud prompt segment shows the output of gcloud config get-value project by default. This command reads local files. At least one user would prefer to see gcloud projects describe "$(gcloud config get-value project)" --format='value(name)' instead.

From gcloud help projects describe:

Shows metadata for a project given a valid project ID.

This command can fail for the following reasons:

  • The project specified does not exist.
  • The active account does not have permission to access the given project.

So this command talks to Google servers, can be very slow, and can fail.

My questions to you:

  1. If powerlevel10k was able to compute both values, which one would you prefer to see in prompt?
  2. If powerlevel10k was able to compute only the project id but failed to compute project name, would you prefer to see the project id, some kind of error indicator, or nothing at all?
  3. If powerlevel10k was able to compute the project id but is still computing project name, would you prefer to see the project id, some kind of loading indicator, or nothing at all?
  4. If you prefer to see project name if it's available, and prefer project id over nothing, do you need some kind of indicator telling you whether prompt is showing project id or project name?

To make it more concrete, I could implement something like this:

  • Powerlevel10k sets P9K_GCLOUD_ACCOUNT, P9K_GCLOUD_PROJECT_ID and P9K_GCLOUD_PROJECT_NAME that can be used in expansions to customize the format of gcloud segment. If P9K_GCLOUD_PROJECT_NAME is unknown, it's not set.
  • gcloud segment has two states: COMPLETE and PARTIAL. P9K_GCLOUD_PROJECT_NAME is set only in COMPLETE state.
  • By default the content in COMPLETE state is ${P9K_GCLOUD_PROJECT_NAME} and in PARTIAL state it's ${P9K_GCLOUD_PROJECT_ID}. Colors and icons are the same.
  • P9K_GCLOUD_PROJECT_NAME can be stale. Sending an RPC to Google on every prompt might get you banned, so this value will be recomputed only once a minute (configurable) and when P9K_GCLOUD_ACCOUNT or P9K_GCLOUD_PROJECT_ID change.

This should provide enough degrees of customization freedom. No matter how you answer the 4 questions above, it'll be possible to configure powerlevel10k to do what you want.

Does this make sense? Is this enough flexibility? Is this overkill?

P.S.

Please ignore the questions of performance. Whatever I'll end up implementing will have no impact on prompt latency.

Note: I don't use gcloud that much, so my answer is based on how I use other connections.

If powerlevel10k was able to compute both values, which one would you prefer to see in prompt?

I agree with the PR, I would like to see the project name instead of the id. Although the project ID is what you need to switch to the project (gcloud --project [...] / gcloud config set project), it's nicer to see the name when it is selected.

If powerlevel10k was able to compute only the project id but failed to compute project name, would you prefer to see the project id, some kind of error indicator, or nothing at all?

I would like to see the project id.

If powerlevel10k was able to compute the project id but is still computing project name, would you prefer to see the project id, some kind of loading indicator, or nothing at all?

Probably nothing, but it's a close call to the project ID. I'm not a fan of a loading indicator.

If you prefer to see project name if it's available, and prefer project id over nothing, do you need some kind of indicator telling you whether prompt is showing project id or project name?

No, I don't think that is necessary.

In general, I think fewer visible "moving parts" is better. Because of the environment variables you propose it is still possible to check the internal state of the gcloud info.

I like your proposal. It might be very general, but this prompt is all about radical customization, right? :smile:

Thanks for the feedback, @jcassee.

I've implemented what I'd described earlier in gcloud branch. Will probably merge it tomorrow unless someone chimes in and stops me.

When that code is merged, the existing p10k configs will be unaffected. New configs generated by p10k configure will display P9K_GCLOUD_PROJECT_NAME if it's available and P9K_GCLOUD_PROJECT_ID otherwise. Icons and colors are the same in both cases by default.

Here's the relevant section from the new configs:

# Google cloud format. Change the value of POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION and/or
# POWERLEVEL9K_GCLOUD_COMPLETE_CONTENT_EXPANSION if the default is too verbose or not informative
# enough. You can use the following parameters in the expansions. Each of them corresponds to the
# output of `gcloud` tool.
#
#   Parameter                | Source
#   -------------------------|--------------------------------------------------------------------
#   P9K_GCLOUD_CONFIGURATION | gcloud config configurations list --format='value(name)'
#   P9K_GCLOUD_ACCOUNT       | gcloud config get-value account
#   P9K_GCLOUD_PROJECT_ID    | gcloud config get-value project
#   P9K_GCLOUD_PROJECT_NAME  | gcloud projects describe $P9K_GCLOUD_PROJECT_ID --format='value(name)'
#
# Note: ${VARIABLE//\%/%%} expands to ${VARIABLE} with all occurences of '%' replaced with '%%'.
#
# Obtaining project name requires sending a request to Google servers. This can take a long time
# and even fail. When project name is unknown, P9K_GCLOUD_PROJECT_NAME is not set and gcloud
# prompt segment is in state PARTIAL. When project name gets known, P9K_GCLOUD_PROJECT_NAME gets
# set and gcloud prompt segment transitions to state COMPLETE.
#
# You can customize the format, icon and colors of gcloud segment separately for states PARTIAL
# and COMPLETE. You can also hide gcloud in state PARTIAL by setting
# POWERLEVEL9K_GCLOUD_PARTIAL_VISUAL_IDENTIFIER_EXPANSION and
# POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION to empty.
typeset -g POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION='${P9K_GCLOUD_PROJECT_ID//\%/%%}'
typeset -g POWERLEVEL9K_GCLOUD_COMPLETE_CONTENT_EXPANSION='${P9K_GCLOUD_PROJECT_NAME//\%/%%}'

# Send a request to Google (by means of `gcloud projects describe ...`) to obtain project name
# this often. Negative value disables periodic polling. In this mode project name is retrieved
# only when the current configuration, account or project id changes.
typeset -g POWERLEVEL9K_GCLOUD_REFRESH_PROJECT_NAME_SECONDS=60

I haven't used gcloud myself but the proposal and feedback sound sensible to me 馃憤

@maximbaz Thanks! Two confirmations that I'm not doing something obviously stupid are enough to inspire confidence.

Cloud experts, please help with https://github.com/romkatv/powerlevel10k/issues/904. It's a proposal to add a bunch of tools to various *_SHOW_ON_COMMAND parameters. I cannot figure out which of these tools it would make sense to add by default.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

georgijd picture georgijd  路  3Comments

ImKifu picture ImKifu  路  3Comments

maximbaz picture maximbaz  路  7Comments

dylanjm picture dylanjm  路  3Comments

fedemengo picture fedemengo  路  7Comments