Powerlevel9k: Current directory doesn't update in a function called by a bindkey

Created on 13 Mar 2017  路  26Comments  路  Source: Powerlevel9k/powerlevel9k

I have the following in ~/.zshrc

cdUndoKey() {
  popd      > /dev/null
  zle       reset-prompt
  echo
}

cdParentKey() {
  pushd .. > /dev/null
  zle      reset-prompt
  echo
}

zle -N                 cdParentKey
zle -N                 cdUndoKey
bindkey '^[[1;3A'      cdParentKey
bindkey '^[[1;3D'      cdUndoKey

This makes Alt+Left cd "back" in history, and Alt+Up move up a directory. The prompt is then updated in both cases to show the new directory. This works fine with a few other prompts I tested (steeef and minimal). However, in powerlevel9k 0.6.1, the prompt stays the same, with the old directory still shown. I can manually echo, which updates the prompt correctly. I tried putting in sleep 1 before the echo in the functions, but that made no difference.

I also tried reverting to powerline9k 0.5.0, which updates the current directory fine. I did notice a slight problem with the vcs part not being updated, though. i.e. if I start in a vcs directory, then move out, the current directory updates, but not the vcs part.

/tmp/zsh-theme-powerlevel9k | b183342... $
/tmp | b183342... $
/ | b183342... $

Finally, back with the most recent powerlevel9k 0.6.1, if I manually call the function, both current directory and vcs status appear to work fine, albeit with a warning. pushd alone works too.

/tmp/zsh-theme-powerlevel9k | b183342... $ cdParentKey
cdParentKey:zle:2: widgets can only be called when ZLE is active

cdParentKey:zle:4: widgets can only be called when ZLE is active
/tmp $ pushd .. > /dev/null
/ $
bug question

All 26 comments

So this is a result of us not re-drawing the prompt on line entry / endings, which we turned off due to slowness in ZSH's VCS_INFO module. My bet is if you pull this PR onto v0.6.1 it will work for you: https://github.com/bhilburn/powerlevel9k/pull/320

Can you give that a go and let us know if it does indeed fix the problem?

I tried the apply the patch, but it failed. It looks like the file had changed too much? I tried manually applying it as below. I might have got it wrong, but it fails after this patch. (I don't need to recompile or remove caches, etc. do I?)

--- /usr/share/zsh-theme-powerlevel9k/powerlevel9k.zsh-theme.orig   2017-03-15 11:47:57.184276955 +1100
+++ /usr/share/zsh-theme-powerlevel9k/powerlevel9k.zsh-theme    2017-03-15 11:48:56.964156562 +1100
@@ -1297,6 +1297,30 @@
   [[ $POWERLEVEL9K_PROMPT_ADD_NEWLINE == true ]] && PROMPT="$NEWLINE$PROMPT"
 }

+function zle-line-init {
+  powerlevel9k_prepare_prompts
+  if (( ${+terminfo[smkx]} )); then
+    printf '%s' ${terminfo[smkx]}
+  fi
+  zle reset-prompt
+  zle -R
+}
+
+function zle-line-finish {
+  powerlevel9k_prepare_prompts
+  if (( ${+terminfo[rmkx]} )); then
+    printf '%s' ${terminfo[rmkx]}
+  fi
+  zle reset-prompt
+  zle -R
+}
+
+function zle-keymap-select {
+  powerlevel9k_prepare_prompts
+  zle reset-prompt
+  zle -R
+}
+
 prompt_powerlevel9k_setup() {
   # Disable false display of command execution time
   _P9K_TIMER_START=99999999999
@@ -1357,6 +1381,10 @@
   # prepare prompts
   add-zsh-hook precmd powerlevel9k_prepare_prompts
   add-zsh-hook preexec powerlevel9k_preexec
+
+  zle -N zle-line-init
+  zle -N zle-line-finish
+  zle -N zle-keymap-select
 }

 prompt_powerlevel9k_setup "$@"

It looks like you translated the patch correctly. Well, I'm completely baffled. Will need to spin on this one a bit.

Anyone else have thoughts?

So, after spinning on this, I wonder if redefining your bindkeys using terminfo might work better. That said, I tried to read a bit about how terminfo works, and my head nearly imploded.

Summoning @apjanke to the thread, as the resident P9k master of all things in this area: How can we figure out what Alt+Left and Alt+Up are in terminfo so that we can give that a go, and do you think that might help?

Hi @bhilburn!

I'm afraid you can't do this with terminfo: the terminfo database does not supply information on the effect of modifier keys like this. You're stuck coding up that behavior from scratch or hardcoding it the way @protist did.

The xterm documentation fully specifies how it behaves with modifier keys; you can use that as a reference and hope other terminals behave the same. (Unfortunately, there's some variation between terminal emulators here, so it won't work everywhere.) This PR has an example of how I coded it up in a somewhat user-friendly way myself when faced with the issue.

But it seems unlikely that key bindings are the issue here: if the behavior is being invoked at all, that indicates the key bindings are behaving correctly.

Thanks so much for your response, @apjanke! (and sorry for the delay in my response!)

Okay, so per @apjanke, the key bindings are behaving correctly, and there isn't much that can be improved there, anyway. @protist already tried the patch that I thought almost assuredly was causing this, and it did nothing.

I'm drawing blanks at this point. Anyone else have thoughts?

I don't really understand most of this conversation, but would it help if I tested shortcuts that don't use modifier keys (is that even possible?), so that I can at least troubleshoot with terminfo (would that even work)? If so, you'd probably have to walk me through it veeeery slowly.

Also, were you able to reproduce this issue locally at all?

Okay, I tracked it down. The error is caused by 268c3247c95eb11c92054465404e37d8877c0f5d, specifically, this change:

-  local current_path='%~'
+  local current_path="$(print -P "%~")"

If you revert that change, it works. @dritter - Can you give a bit of background as to why that piece of the change is important?

This change comes from #394
We need to evaluate the path at the start because these 3 conditions are optionnal

whereas before there was only the first one, which would do the evaluation if needed.
I don't know how we could fix it, we need that evaluation :/

@V1rgul - Thanks for the background!

Okay, so, the issue then is that previously we weren't actually doing the prompt expansion, but then we changed to do the prompt expansion because we needed it for the shortening strategies.

The aspect of this that is most confusing to me, I think, is why isn't the prompt expansion yielding the new directory? The directory change, trigged by the keybinding, is taking effect - it just isn't reflected in the segment.

@V1rgul is right. I did this because if the user did not choose to truncate the path, but changes the dir separator (or one of the things @V1rgul mentioned), the path needs to be expanded at that point.

In dritter/rework_dir_truncation branch the code gets completely rewritten, btw.

Thanks for the insight, @V1rgul and @dritter!

Any thoughts as to why the change isn't being reflected in the segment with this change? The directory change actually is taking place, it just isn't updated in the segment with the current code which is really bizarre to me. It seems to me that there should be an easy way for us to resolve this, but I can't seem to spot it.

Hi, sorry for the delay in replying. I just got back from holidays.

@bhilburn, I attempted applying the modification that you mentioned above, but this did not fix the problem for me. i.e. after Alt+Left or Alt+Up, the prompt is still not updated. Potentially it's something else in my ~/.zshrc, I'm happy to try slimming it down if you think it might help.

@protist - I don't think it's anything in your .zshrc. I still don't understand why not expanding the prompt string at that point breaks this, but it seems like that logic is going to fundamentally have to change. The answer might be duplicating the prompt string for the shortening logic. I'm going to try and play with it a bit more this week.

I don't think it's anything in your .zshrc.

But weren't you able to reproduce this, then fix it with that modification on your system, @bhilburn? Or do I misunderstand?

@protist - No, that's correct, I was - the issue is that that modification breaks the path shortening strategies (which I didn't notice because I don't personally use them), so it's not a merge-able fix. So, I need to figure out how to fix it without breaking everything else :)

Sorry, I still don't understand entirely. I understand that the modification breaks other things, but isn't there still an inconsistency between us? In your case, the modification did cause the prompt to be redrawn. In my case it did not.

@protist - Oh, wow, yeah, I totally did not understand that.

Well, crap. Hah.

Okay, well, need to do more digging, then. Can you share your entire zshrc?

@bhilburn No worries, sorry for being vague in the first place!

My zshrc is also a (verbose) pile of crap, so I found a minimal failing example. I've isolated it to the following line.

POWERLEVEL9K_SHORTEN_DIR_LENGTH=4

To replicate, I patch powerlevel9k.zsh-theme as you mention above. If I then remove this line from ~/.zshrc, the prompt updates as expected. If I put this line back in, the prompt fails to update.

FWIW, I also tested permutations with and without your modifications to powerlevel9k.zsh-theme, and with and without this line in ~/.zshrc.


Hence, with powerlevel9k.zsh-theme as the default from 0.6.2, the prompt always fails to update. With powerlevel9k.zsh-theme modified as per your post above, the prompt updates fine, unless POWERLEVEL9K_SHORTEN_DIR_LENGTH=4 is set.

So, the fix is relatively easy...

First we define a function to be called

p9k_chpwd() {
  powerlevel9k_prepare_prompts
  powerlevel9k_preexec
}

Then we hook it into the zsh-chpwd by adding these 2 lines to the end of prompt_powerlevel9k_setup:

  # hook into chpwd for bindkey support
  chpwd_functions=(${chpwd_functions[@]} "p9k_chpwd")

We define it this way so that it chains into chpwd instead of overwriting it, in case there are previous functions there.

I made the two set of changes to powerlevel9k.zsh-theme. I then redefined my functions as you suggest. However, this didn't work. After pressing Alt+Up or Alt+Left, nothing happened.

However, after I redefined my functions, putting zle reset-prompt back in, the prompt updated fine. (I could also put echo back in, if I wanted an additional, new prompt drawn). So it seems to work! Thank you!

I'm glad you have it working now.

There's a similar omz plugin that does push/pop if you're interested https://github.com/robbyrussell/oh-my-zsh/blob/master/plugins/dirhistory/dirhistory.plugin.zsh :)

Thanks @V1rgul. TBH I'm unclear on how much extra functionality it provides, apart from moving forward in history, which I'd never use, so I'll just stick with the simpler version for now. BTW I got the code snippet from the ArchWiki zsh page.

I had left this open, because I thought we might be able to spin something out of it for p9k. After reviewing it again, though, I'm not sure I can identify anything that makes sense.

@protist - I'm glad you've got it working. Thanks for your input, @V1rgul, and for providing the fix, @onaforeignshore! Excellent work, all =)

Thank you @bhilburn.

Just as a slight update to this, I've since updated to master instead of the stable release, because of issue #511. I'm not sure if it's because of this update or some other change, but I've had to modify my code slightly. It seems that my original code now changes the displayed directory in the initial prompt, echos to the next line, then leaves my cursor on an empty, prompt-less line. To get the original behaviour back (leave the current prompt as is, create and move to another prompt, which will show the new directory), I had to swap around two commands, hence:

cdUndoKey() {
  popd      > /dev/null
  echo
  zle       reset-prompt
}

cdParentKey() {
  pushd .. > /dev/null
  echo
  zle      reset-prompt
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

edwardsmit picture edwardsmit  路  3Comments

agungsetiawan picture agungsetiawan  路  6Comments

DanielChabrowski picture DanielChabrowski  路  3Comments

gipert picture gipert  路  5Comments

yoyoys picture yoyoys  路  3Comments