Skip to content

WIP: Git super status as template string#40

Open
NAR8789 wants to merge 36 commits intostarcraftman:masterfrom
NAR8789:git-super-status-as-template-string
Open

WIP: Git super status as template string#40
NAR8789 wants to merge 36 commits intostarcraftman:masterfrom
NAR8789:git-super-status-as-template-string

Conversation

@NAR8789
Copy link

@NAR8789 NAR8789 commented Dec 28, 2018

NOTE: this builds on top of some unit testing brought in in #39, and that PR is generally less weird than this one, so you should probably read #39 first.

This PR is an attempt (possibly misguided) at allowing "template-string"-like customization of the git prompt.

For example, here is the original theme in template-string form:

'$ZSH_THEME_GIT_PROMPT_PREFIX$branch$merge_or_rebase$upstream${${:-$behind$ahead}:+ }$behind$ahead$ZSH_THEME_GIT_PROMPT_SEPARATOR$staged$conflicts$changed$untracked$stashed$clean$ZSH_THEME_GIT_PROMPT_SUFFIX'

Here is an example retheming involving custom template string (template string is the last line)

ZSH_GIT_PROMPT_SHOW_UPSTREAM=2
ZSH_THEME_GIT_PROMPT_BEHIND="↓"
ZSH_THEME_GIT_PROMPT_AHEAD="↑"
ZSH_THEME_GIT_PROMPT_LOCAL='L'
ZSH_THEME_GIT_PROMPT_UPSTREAM_FRONT="%{$fg_bold[blue]%}"
ZSH_THEME_GIT_PROMPT_UPSTREAM_END="%{${reset_color}%}"
ZSH_THEME_GIT_PROMPT_MERGING="%{$fg_bold[yellow]%}MERGE"
ZSH_THEME_GIT_PROMPT_REBASE="%{$fg_bold[yellow]%}REBASE "

ZSH_THEME_GIT_PROMPT='(${(j:|:)${(s:|:)${:-$branch|$upstream|$merge_or_rebase|$behind$ahead$staged$conflicts$changed$untracked$stashed$clean}}})'

And here are some example prompts under that custom template

clean:                          (master|origin|✔)
basic metrics:                  (master|origin|↓2↑1●3✚5…6⚑7)
local only:                     (master|L|✔)
local only, with metrics:       (master|L|●3✚5…6⚑7)
merging:                        (master|origin|MERGE|✖1)
merging, with metrics:          (master|L|MERGE|●3✖4✚5…6⚑7)
rebasing:                       (:abc1234|origin/master|REBASE 3/10|✔)
rebasing, with metrics:         (:abc1234|origin/master|REBASE 2/7|●3✖4✚5…6⚑7)

Why?

I think template strings potentially provide an easier way to make structural modifications to the git-prompt theme, e.g. omitting or reordering pieces. Reordering by moving variables around in a template string feels a lot lighter weight than overriding git_super_status and reordering the blocks therein.

At the end of the day it's about having varying levels of granularity in configuration. The preexisting theme variables already nicely support fine-grained changes (i.e. tweaking look-and-feel in-place), so I've written this template string implementation to avoid that level of granular detail, and to leave that existing layer of customizability intact.

Template strings fill in a missing level of granularity--providing the ability to work at the level of prebuilt status blocks, e.g. ✖4, or ●3. or REBASE 2/7

In theory this might also be a nicer place to configure separators and margins, rather than using ZSH_THEME_GIT_PROMPT_PREFIX, ZSH_THEME_GIT_PROMPT_SUFFIX, and ZSH_THEME_GIT_PROMPT_SEPARATOR

Why Not?

Template strings sound nice, but in practice I find them headachey in particular for optional separators or spacers (e.g. "omit this spacer if the next section is empty"). Optional Spacers require a tiny bit of logic, and I found zsh expansions an awkward tool for this purpose.

For example, my custom template above contains optional separators logic, but it reads like a code golf solution.

Here is my example custom template string again:

'(${(j:|:)${(s:|:)${:-$branch|$upstream|$merge_or_rebase|$behind$ahead$staged$conflicts$changed$untracked$stashed$clean}}})'

At a high level, the idea I'm implementing above is simple:

  • Take a bunch of segments, in order: $branch, $upstream, $merge_or_rebase, and $behind$ahead$staged$conflicts$changed$untracked$stashed$clean
  • omit the empty segments
  • join the remaining segments with pipes | as separators

Zsh has built-in support for joining arrays: ${(j:|:)array_var} will join the elements of $array_var with pipes |. You can see this at the outermost layer of my expression, just inside the literally-printed parens.

The rest of the expression, ${(s:|:)${:-...}}, is a hack to declare an anonymous array inside of a string.

  • ${(s:|:)string_var} splits a string on pipes
  • ${:-string_expression} is a hack, to shoehorn an arbitrary string expression into the above splitter. Otherwise, the string_var argument above would only take variables, not arbitrary expressions. credit to stackoverflow for this one.
  • omitting empty segments happens automatically, because splitting behaves like argument-splitting.
  • Put everything together, and the result is this weird anonymous array syntax based on string operations.

Note that, though this works for the current purpose, this is not fully general:

  • Since omitting of blanks is built-in, I'm not sure how I'd create an anonymous array that does contain blanks
  • The current solution is also susceptible to oversplitting (e.g. if any of the nonempty segments themselves contain pipes)

Given the weirdness of zsh expansions, it feels like template strings might be hard for most people to write from scratch.

Extra Bits

As part of this, I wrote a previewer tool, to see the git status under various conditions all at once, without needing repositories to produce the correct underlying states. It's invoked as preview_git_super_status, and lives in a separate file so as not to clutter the main logic. It avoids polluting the environment by doing all its work in a subshell.

@NAR8789 NAR8789 force-pushed the git-super-status-as-template-string branch 2 times, most recently from 304a99c to 2c031fa Compare December 28, 2018 23:22
@NAR8789 NAR8789 force-pushed the git-super-status-as-template-string branch from 2c031fa to 151c01a Compare December 28, 2018 23:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant