-
Notifications
You must be signed in to change notification settings - Fork 947
Add Async Functionality per Segment #1176
base: next
Are you sure you want to change the base?
Conversation
The cache key (array key) must exactly match, otherwise we create two cache items. Creating an array key like left::1 differs from "left::1" (quotes matter).
The __p9k_left|right_prompt_segment functions now write directly into `__p9k_unsafe`. This was necessary, because it is not possible to write global variables from subshells. On the good side, this means that we removed a lot of subshells.
This means that all segments should print their metadata always.
The last prompt may be removed if too many async segments are enabled and newlines are added by P9K_PROMPT_ADD_NEWLINE='true'
P9K_PROMPT_ON_NEWLINE='true' In my test, I enabled as many async segments as possible, and entered a directory supporting many segment features. It turned out the last prompt may be removed/overwritten by the new prompt once you press Is there a competition among prompt redrawing activated by async segments? Update: Another problem is that, the |
generator/default.p9k
Outdated
# About .reset-promt see: | ||
# https://github.com/sorin-ionescu/prezto/issues/1026 | ||
# https://github.com/zsh-users/zsh-autosuggestions/issues/107#issuecomment-183824034 | ||
[[ "${1}" == "true" ]] && zle .reset-prompt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zle -R
(force redisplay) should be added at the end. Otherwise, the current prompt may be moved one line up and overwrite previous prompt.
[[ "${1}" == "true" ]] && zle .reset-prompt && zle -R
Good findings @laggardkernel . I'll have a look at that in the next couple of days. |
It turns out the async worker should be restarted in # restarts just the worker - in order to update worker with current shell values
function zinc_worker_restart () {
# _ZINC_DBG_OUT "restarting worker..."
# async_worker_eval zinc_segment_worker "zinc_reload"
async_stop_worker zinc_segment_worker
async_start_worker zinc_segment_worker
async_register_callback zinc_segment_worker _zinc_segment_async_callback
} |
3d3a106
to
5e72735
Compare
This has to be done, so that the worker has knowledge of all the variables set that might be used by segments.
5e72735
to
c6c1c38
Compare
@laggardkernel Thanks for pointing me to this. I changed the code, so that the worker gets restarted in the precmd hook. It still seems odd to me, that we have to restart the whole worker just to update the variables. Maybe a better approach would be to use |
@dritter I think one of the benefits of this "conditional-async" is to make the segment functions work without any change of the code. Anyone could continue to contribute to the sections without realizing the existence of the async worker. |
generator/default.p9k
Outdated
typeset -gAh __p9k_unsafe=() | ||
|
||
# Process Cache | ||
for data in "${(Oa@v)__p9k_segment_cache}"; do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another finding.
The use of expansion flag (Oa@v)
couldn't ensure an iteration based on the array index.
Here's what I find with setting many segments on the left prompt.
# example conf
# 12 segments on the left, and 0 on the right
P9K_LEFT_PROMPT_ELEMENTS=(context dir vcs::async node_version::async nvm::async rbenv::async anaconda::async pyenv::async status command_execution_time background_jobs time)
P9K_RIGHT_PROMPT_ELEMENTS=()
# result
for data in "${(Oa@v)__p9k_segment_cache}"; do echo "$data"; done
CONTEXT_DEFAULT·|·left·|·1·|·false·|··|··|·false
DIR_HOME_SUBFOLDER·|·left·|·2·|·false·|·…/dritter---powerlevel9k·|··|·true
VCS_CLEAN·|·left·|·3·|·false·|· conditional_async·|· ·|·true
NODE_VERSION·|·left·|·4·|·false·|··|··|·false
NVM·|·left·|·5·|·false·|··|··|·false
COMMAND_EXECUTION_TIME·|·left·|·10·|·false·|··|··|·false
RBENV·|·left·|·6·|·false·|·2.6.3·|··|·false
BACKGROUND_JOBS·|·left·|·11·|·false·|·0·|··|·false
ANACONDA·|·left·|·7·|·false·|·()·|··|·false
TIME·|·left·|·12·|·false·|·%D{%H:%M:%S}·|··|·true
PYENV·|·left·|·8·|·false·|·3.6.8:2.7.16·|··|·false
STATUS_OK·|·left·|·9·|·false·|··|· ·|·true
The sequence of BACKGROUND_JOBS
is not based on its index from array P9K_LEFT_PROMPT_ELEMENTS
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A pr is opened for this problem in your fork. dritter#41
The current implementation requires the segment functions pass out an additional conditional string to decide whether render the segment or not. Another function I have some idea to avoid this and make the async work with segment functions untouched. I'd like to make a pr to achieve this once you make a decision on my current pr. Update: new pr is opened under your fork to implement the idea above. |
Disable segment to be disabled in `async_wrapper` to remove the placeholder in case an segment function exits early. This change will ensure no additional step is needed in segment func for an early exit.
Set the display flag as `false` to avoid additional steps taken before an early exit in segment functions.
Fix iteration in render
Async with segment untouched
Btw. @laggardkernel I was thinking of a general approach to transport the current env into the worker (might use a temp file for transport, like here). This could be done in the precmd hook, so you don't have to worry about that when writing new segments. |
Recalling precmd_functions is only needed when cwd is changed, which means when `jump` is called. `.reset-prompt`: bypass the zsh-syntax-highlighting wrapper<Paste> - sorin-ionescu/prezto#1026 - zsh-users/zsh-autosuggestions#107 (comment) `-R`: redisplay the prompt to avoid old prompts being eaten up - Powerlevel9k/powerlevel9k#1176 (comment)
This is my fourth iteration on async functionality and adds such (currently based solely on ZSH-Async) to every segment that is tagged as
async
. So, opposed to our earlier approaches, we don't render the whole prompt asynchronously, but we can render a mixture.There is a major change how the segments work internally. Instead of printing each segment directly in
p9k::prepare_segment
this outputs now just the metadata of the segment. Additionally we build up a segment cache (in__p9k_build_segment_cache
) that holds these metadata. When we are finished with building up the cache, we trigger rendering the prompt (__p9k_render
is called), which stitches together all cached segments.With async segments, we wait for the callback (
__p9k_async_callback
), update the cache and re-render the prompt.Preconditions
This branch is based on the
segment_tags
branch (#1171 ).Caveat
This is still in a pretty raw stage. So don't expect everything to be working. I drafted this at an early stage, to get feedback as early as possible.
Todo
These things are still open:
async_flush_jobs
andasync_worker_eval
are always called.vi_mode
segment. This contains old code based ongenerators/async.p9k
..generator/default.p9k
could be improved..So
p9k::prepare_segment
must always be called (we have to look on conditions enclosingp9k::prepare_segment
and earlyreturn
statements). This is already done for most of the segments, but not for all: